hakan648
شنبه 04 مرداد 1393, 16:27 عصر
روش کار با کلاس های .net در C++ ( مدیریت نشده - Native ) به چه صورت است؟ ( بدون استفاده از COM و تنها توسط C++ )
فرض کنید از کلاسی در .net، در C# نمونه سازی کردیم و میخواهیم مقداری از آن کلاس را در C++ بخوانیم.
روشی که من امتحان کردم، ارسال پوینتری از نوع Type از کلاس Label به C++ و استفاده از آن در CLR لود شده بود.
کدهای زیر حاصل روش فوق است که با خطای 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.
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);
}
در صورتی که روشی برای انجام این کار سراغ دارید، در اختیار بنده قرار دهید.
با تشکر
فرض کنید از کلاسی در .net، در C# نمونه سازی کردیم و میخواهیم مقداری از آن کلاس را در C++ بخوانیم.
روشی که من امتحان کردم، ارسال پوینتری از نوع Type از کلاس Label به C++ و استفاده از آن در CLR لود شده بود.
کدهای زیر حاصل روش فوق است که با خطای 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.
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);
}
در صورتی که روشی برای انجام این کار سراغ دارید، در اختیار بنده قرار دهید.
با تشکر