0

我正在尝试将一组接口从 C# 传递到 C++/CLI。这是代码:

// *** SafeArrayTesting_PlusPlus.cpp  ***
#include "stdafx.h"  
#include <comdef.h>

using namespace System;    
using namespace System::Runtime::InteropServices;

namespace SafeArrayTesting_PlusPlus {

public ref class MyCppClass
{       
    public:
    MyCppClass();
    ~MyCppClass();
    void SetMyInterfaces(
        array<SafeArrayTesting_Sharp::MyInterface^>^ myInterfaces);
};

MyCppClass::MyCppClass(){}
MyCppClass::~MyCppClass(){}

void MyCppClass::SetMyInterfaces(array<SafeArrayTesting_Sharp::MyInterface^>^ 
     myInterfaces)
{
    // Create safearray
    SAFEARRAY  *safeArrayPointer;
    SAFEARRAYBOUND arrayDim[1];    // one dimensional array
    arrayDim[0].lLbound= 0;
    arrayDim[0].cElements= myInterfaces->Length;

    safeArrayPointer = SafeArrayCreate(VT_UNKNOWN,1,arrayDim);

    // copy ints to safearray
    for (long lo= 0;lo<myInterfaces->Length;lo++)
    {           
        IntPtr myIntPtr = Marshal::GetIUnknkownForObject(myInterfaces[lo]);
        SafeArrayPutElement(
            safeArrayPointer, 
            &lo, 
            static_cast<void*>(myIntPtr)
            ); 
    }

    // do something with the safearray here - area XX
}}

// *** SafeArrayTesting_Main.cs ***
using SafeArrayTesting_PlusPlus;
using SafeArrayTesting_Sharp;

namespace SafeArrayTesting_Main
{

class SafeArrayTesting_Main
{
    static void Main()
    {
        var myCppClass = new MyCppClass();
        MyInterface myInterface = new MyClass();
        myCppClass.SetMyInterfaces(new[]{ myInterface });
    }
}}  

// *** SafeArrayTesting_Sharp.cs ***
using System;
using System.Runtime.InteropServices;

namespace SafeArrayTesting_Sharp
{
    [ComVisible(true)]
    public interface MyInterface
    {
        int MyInt { get; set; }
        string MyString { get; set; }
        DateTime MyDateTime { get; set; }
    }

    [ComVisible(true)]
    public class MyClass : MyInterface
    {
        public int MyInt{get;set;}
        public string MyString{get;set;}
        public DateTime MyDateTime{get; set;}
    }

// Just to please the compiler; bear with me. 
class DummyClass { static void Main() { } }
}

如此处所写,代码可以干净地运行和编译。但是,在运行“区域 XX”部分时,我得到一个System.Runtime.InteropServices.SEHException.

XX 代码只是调用自动生成的方法并接受 SAFEARRAY 指针的单行代码。这是此方法的声明(来自 .tlh 文件):

virtual HRESULT __stdcall put_SafeArray (
        /*[in]*/ SAFEARRAY * pRetVal ) = 0;

实际上,我认为这种方法将 SAFEARRAY 转换回 .NET 数组——这都是我公司当时正在运行的转换项目的一部分。因此,除了使用 SAFEARRAY,别无选择。

无论如何,如果没有 XX 部分的代码没有错误,我真的会感到惊讶;当谈到 C++ 时,我是个新手。你能帮我找出一些问题吗?如果有人可以提出一种更好的方法来测试 SAFEARRAY 的有效性,那也会有所帮助。

(顺便说一句,这是SafeArrayPutElement method throws System.AccessViolationException问题的一个更复杂的变体,其中我只是将一个整数数组从 C# 传递到 C++/CLI。)

4

1 回答 1

3

几个问题。一方面,您实际上并没有在数组中存储 VARIANT。这最终不会去任何地方,SafeArray 不能存储对托管对象的引用。垃圾收集器四处移动对象,它看不到非托管代码持有的引用,因此它无法更新引用。

充其量,您可以创建一个 VT_UNKNOWN 或 VT_DISPATCH 数组。但是您无法获取这些托管对象的 COM 接口指针,它们不是 [ComVisible]。当您修复该问题时,您将使用 Marshal.GetIDispatchForObject() 或 Marshal.GetIUnknownForObject() 来获取要存储在数组中的接口指针。

于 2010-08-12T07:08:17.657 回答