在本机C ++中处理.NET类

时间:2014-07-26 12:08:53

标签: c# c++ .net

我希望将.net类传递给本机函数并使用该类(即获取属性的值)。请注意,我不想使用C ++ / CLI。

例如,我的Web应用程序中有一个Label,我想在我的本机C ++代码中获取Text属性。

我的尝试

我尝试在C ++中加载CLR并读取在C#中实例化的标签的Text属性,但我遇到了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 ++代码是此code sample from microsoft的简化版。

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

1 个答案:

答案 0 :(得分:2)

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