c# - 在 native C++ 中处理 .NET 类

标签 c# c++ .net

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

例如,我的 Web 应用程序中有一个标签,我想在我的 native 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 或发生在原生世界之外的其他方法。

最佳答案

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

关于c# - 在 native C++ 中处理 .NET 类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24970859/

相关文章:

c# - 如何为单个项目返回 IEnumerable<T>

c# - 线程安全方法?

c# - 为什么 Entity Framework 中的子实体包含引用父实体的虚拟属性?

c++ - 可插入私有(private) DICOM 标签的数据是否有任何限制?

c# - 无法创建对象上下文

c# - 从被调用函数中获取调用函数名

.net - 如何解决 VS2010 Windows 窗体设计器问题(无法加载基类)

c# - 如何获取静态类注入(inject)的ILogger?

c++ - 在 Android 下删除 C++ 代码中的 C 样式转换

c++ - 从 'int' 到 'time_t*' 的无效转换和另一个错误