我希望将.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或本地世界之外的其他方法。
答案 0 :(得分:2)
.Label
属性是一个实例属性,但您没有将创建的实例传递给ReadDotNetClass函数 - 只是Label Type
的句柄。请注意,如果您从托管代码调用本机函数,则无需初始化CLR - 它已经初始化,运行托管代码。因此,在本机函数签名中包含指向托管对象的指针,在调用本机函数时将其传递给指向托管对象Type
的指针,并在本机函数内部调用InvokeMember
。 Type
实例,将托管对象作为target
参数传递 - 删除所有CLR初始化内容。