[英]How to pass IntPtr to method from unmanaged C++ CLR hosting code?
我使用本教程作為我的32位非托管DLL代碼的基礎https://code.msdn.microsoft.com/CppHostCLR-e6581ee0
假設我想調用TestIntPtr
public class IntPtrTester
{
public static void TestIntPtr(IntPtr p)
{
MessageBox.Show("TestIntPtr Method was Called");
}
public static void TestInt(int p)
{
MessageBox.Show("TestInt Method was Called");
}
}
如果在C ++端它代表句柄,我如何傳遞IntPtr參數? TestInt有效,但對於TestIntPtr,我得到的錯誤是找不到該方法。 這是因為參數類型錯誤。
在我使用的TestInt教程的代碼中
// HDC dc;
// The static method in the .NET class to invoke.
bstr_t bstrStaticMethodName(L"TestInt");
SAFEARRAY *psaStaticMethodArgs = NULL;
variant_t vtIntArg((INT) dc);
variant_t vtLengthRet;
...
psaStaticMethodArgs = SafeArrayCreateVector(VT_VARIANT, 0, 1);
LONG index = 0;
hr = SafeArrayPutElement(psaStaticMethodArgs, &index, &vtIntArg);
if (FAILED(hr))
{
wprintf(L"SafeArrayPutElement failed w/hr 0x%08lx\n", hr);
goto Cleanup;
}
問題是什么是TestIntPtr的正確代碼
// The static method in the .NET class to invoke.
// HDC dc;
bstr_t bstrStaticMethodName(L"TestIntPtr");
SAFEARRAY *psaStaticMethodArgs = NULL;
variant_t vtIntArg((INT) dc); // what do I have to write here?
variant_t vtLengthRet;
我試過了:
variant_t vtIntArg((INT) dc);
variant_t vtIntArg((UINT) dc);
variant_t vtIntArg((long) dc);
variant_t vtIntArg((UINT32) dc);
variant_t vtIntArg((INT32) dc);
也許CLR期待IntPtr的IUNKNOWN? 但是如何構建這樣的實例呢? 我試圖用這個API調用IntPtr構造函數,但它返回V_INTEGER類型的變體,所以這是閉環。
我知道我可以使用COM公開C#庫以及如何使用DllExports hack,我也可以將C#部分改為接受int或uint。 但所有這些方式與問題無關。
目前它適用於我的C#helper
public class Helper
{
public static void help(int hdc)
{
IntPtrTester.TestIntPtr(new IntPtr(hdc));
}
}
和
variant_t vtIntArg((INT32) dc);
在c ++中。 但這很丑陋,因為我需要這個幫手,我無法影響你的庫。
此處記錄了自動化兼容類型列表: 2.2.49.3自動兼容類型
如你所見,沒有任何“指針”,句柄或任何聞起來“本機”(低級別)的概念。 這是因為自動化最初是為VB(不是.NET,VB / VBA / VBScript等)而設計的,它是一種語言和IDE,設計易於使用,而不是指針處理的樂趣,在64位Windows時還沒有。
因此,IntPtr是一個原始且不透明的指針(不是句柄),它根據執行的進程位數而具有可變存儲大小的特性,它不是COM自動化兼容類型,因此它不能按原樣放置,如一個指針,在VARIANT中,因為在您想要在互操作代碼中使用的VARIANT中,您只能放置自動化兼容的東西。
然而,有許多解決方案/解決方法,因為VARIANT可以傳輸64位大小的東西,如果你問得好。 所以,您可以像這樣定義方法:
public static void Test(object input)
{
// check for int (Int32) or long (Int64) here
}
在C ++代碼中執行以下操作:
variant_t vtIntArg;
if (64-bit mode)
{
vtIntArg = (__int64)dc; // force VT_I8, this overload available only if _WIN32_WINNT >= 0x0501
}
else
{
vtIntArg = (long)dc; // force VT_I4
}
另一個解決方案是在C#中定義它
public static void Test32(int ptr)
{
}
public static void Test64(long ptr)
{
}
並調用正確的函數,仍然使用Test64方法的__int64重載。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.