从C++调用 dotnet 程序集方法将返回错误COR_E_SAFEARRAYTYPEMISMATCH

Invoking dotnet assembly method from C++ returns error COR_E_SAFEARRAYTYPEMISMATCH

本文关键字:COR 错误 SAFEARRAYTYPEMISMATCH 返回 调用 C++ dotnet 程序集 方法      更新时间:2023-10-16

我正在尝试从C++程序内的内存缓冲区加载和执行dotnet可执行文件。

为此,我正在尝试调用我在C++项目中加载的 dotnet 程序集的 Main 函数。

首先,我加载 CRL 运行时,加载正常。

然后我从内存缓冲区加载 dotnet.exe它加载正常。

然后我想通过调用它的 Main 函数来启动它。

此时,Invoke_3函数返回COR_E_SAFEARRAYTYPEMISMATCH。我不明白为什么,因为我使用 GetParameters 函数检索参数,该函数填充 SAFEARRAY 以传递给 Invoke 函数。有人知道这个参数有什么问题吗?提前谢谢你!

// Up here we correctly load the CRL runtime
// Load up our dotnet file inside a std::string
string sFileData = FileToString("C:\dotnet.exe");
// Copy our file data inside a SAFEARRAY
SAFEARRAYBOUND bounds = { sFileData.size(), 0 };
SAFEARRAY *pSA = SafeArrayCreate(VT_UI1, 1, &bounds);
void* data;
HRESULT hr = SafeArrayAccessData(pSA, &data);
CopyMemory(data, sFileData.c_str(), sFileData.size());
hr = SafeArrayUnaccessData(pSA);
if (pSA)
{ 
    // Load our managed assembly:
    _AssemblyPtr spAssembly = nullptr;
    hr = spAppDomain->Load_3(pSA, &spAssembly);
    // Get the entrypoint of the assembly, which should be the "Main" function
    _MethodInfoPtr entryp;
    hr = spAssembly->get_EntryPoint(&entryp);
    // Get the parameters of the entrypoint function and save them in a SAFEARRAY
    SAFEARRAY *pArrParams;
    hr = entryp->GetParameters(&pArrParams);
    // Call the entrypoint passing parameters in the SAFEARRAY.
    // Returns error COR_E_SAFEARRAYTYPEMISMATCH
    VARIANT retval;
    hr = entryp->Invoke_3(_variant_t(), pArrParams, &retval);
}

根据 SafeArrayTypeMismatchException 的框架源代码(映射到 COR_E_SAFEARRAYTYPEMISMATCH

):

当数组的运行时类型与元数据中指定的安全数组子类型不同时,将引发此异常。

因此,我很确定这就是问题所在:

SafeArrayCreate(VT_UI1, 1, &bounds);

VT_UI1 是一个 1 字节的无符号整数。但 C# 应用程序中的标准 Main() 方法采用 4 字节有符号整数数组。这些是不同的类型,因此存在错误。因此,您需要将代码更改为以下内容:

SafeArrayCreate(VT_I4, 1, &bounds);
VARIANT ret;
VARIANT obj;
SAFEARRAY *args = SafeArrayCreateVector(VT_VARIANT, 0, 1);
ZeroMemory(&ret, sizeof(VARIANT));
ZeroMemory(&obj, sizeof(VARIANT));
obj.vt = VT_NULL;
hr = entryp->Invoke_3(obj, args, &ret);

将类型从"VT_UI1"更改为"VT_VARIANT"。