在本地c++中处理.net类

本文关键字:处理 net c++ | 更新日期: 2023-09-27 18:15:12

我想传递一个。net类到一个本机函数和工作与该类(即获得一个属性的值)。注意,我不想使用c++/CLI。

例如,我有一个标签在我的web应用程序,我想在我的本地c++代码中获得文本属性。

我的尝试

我试图在c++中加载CLR并读取在c#中实例化的标签的文本属性,但我遇到了System。AccessViolationException例外。

下面是我的代码:

c#

static void Main(string[] args)
{
    var label = new Label { Text = "Some Text" };
    //Send Type because CLR Invocation is defined on object's Type
    var labelType = label.GetType();
    GCHandle gch = GCHandle.Alloc(labelType);
    IntPtr labelTypeIntPtr = GCHandle.ToIntPtr(gch);
    ReadDotNetClass(labelTypeIntPtr);
}
//native function definition
[DllImport("Unmanaged.dll")]
private static extern void ReadDotNetClass(IntPtr labelTypeIntPtr);

C + +

extern "C" __declspec(dllexport) void ReadDotNetClass(_TypePtr labelTypePtr)
{
    PCWSTR pszVersion = L"v4.0.30319";
    PCWSTR pszAssemblyName= L"System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
    PCWSTR pszClassName=L"System.Web.UI.WebControls.Label";
    ICLRMetaHost *pMetaHost = NULL;
    ICLRRuntimeInfo *pRuntimeInfo = NULL;
    ICorRuntimeHost *pCorRuntimeHost = NULL;
    IUnknownPtr spAppDomainThunk = NULL;
    _AppDomainPtr spDefaultAppDomain = NULL;
    // The .NET assembly to load.
    bstr_t bstrAssemblyName(pszAssemblyName);
    _AssemblyPtr spAssembly = NULL;
    // The .NET class to instantiate.
    bstr_t bstrClassName(pszClassName);
    variant_t vtObject;
    // The instance method in the .NET class to invoke.
    bstr_t bstrMethodName(L"Text");
    SAFEARRAY *psaMethodArgs = NULL;
    variant_t vtStringRet;
    CLRCreateInstance(CLSID_CLRMetaHost, IID_PPV_ARGS(&pMetaHost));
    pMetaHost->GetRuntime(pszVersion, IID_PPV_ARGS(&pRuntimeInfo));
    BOOL fLoadable;
    pRuntimeInfo->IsLoadable(&fLoadable);
    pRuntimeInfo->GetInterface(CLSID_CorRuntimeHost, IID_PPV_ARGS(&pCorRuntimeHost));
    pCorRuntimeHost->Start();
    pCorRuntimeHost->GetDefaultDomain(&spAppDomainThunk);
    spAppDomainThunk->QueryInterface(IID_PPV_ARGS(&spDefaultAppDomain));
    spDefaultAppDomain->Load_2(bstrAssemblyName, &spAssembly);
    psaMethodArgs = SafeArrayCreateVector(VT_VARIANT, 0, 0);
    //Invoke method from the Type interface.
    //System.AccessViolationException occurred here
    HRESULT hr = labelTypePtr->InvokeMember_3(bstrMethodName, static_cast<BindingFlags>(
        BindingFlags_Instance | BindingFlags_Public | BindingFlags_GetProperty),
        NULL, vtObject, psaMethodArgs, &vtStringRet);
    if (FAILED(hr))
        wprintf(L"Failed to invoke Method w/hr 0x%08lx'n", hr);
}

c++代码是微软代码示例的简化版本。

请注意,我只需要在本地c++中处理。net类(不是我自己的类),我不想使用COM或其他发生在本地世界之外的方法。

在本地c++中处理.net类

.Label属性是一个实例属性,但是您没有将创建的实例传递给ReadDotNetClass函数-只是将句柄传递给Label的Type。注意,如果您从托管代码中调用本机函数,则不需要初始化CLR——它已经初始化,运行托管代码。因此,在本机函数签名中包含一个指向托管对象的指针,在调用本机函数时与指向托管对象的Type的指针一起传递它,并且在本机函数内部仅在Type实例上调用InvokeMember,将托管对象作为target参数传递-删除所有CLR初始化的东西。