我想将 .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/