簡體   English   中英

如何從非托管C ++ CLR托管代碼傳遞IntPtr方法?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM