如何从非托管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");
}
}
我怎么能传递IntPtr参数如果在c++端它代表句柄?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%08lxn", 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;
I have try:
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和如何使用DllExports hack暴露c#库,我也可以改变c#部分接受int或int。但所有这些方法都与问题无关。
目前它为我工作与以下c#帮助
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重载
相关文章:
- 如何在 c++ 非托管代码中反序列化 byte[] 的 json 字符串?
- 如何使用指针直接从托管代码中的非托管代码中读取矢量数据
- 异步接口托管 - > 非托管代码
- 从C++(非托管代码)检索数组到 C 尖锐形式(托管)
- 从本机代码返回到托管代码会损坏返回的对象
- 将C++非托管代码转换为 C#
- 将托管事件处理程序传递给 Linux 中的非托管代码
- 访问在托管代码创建的事件上对WaitforsingLeoBject拒绝
- 使用 P/Invoke 时存储非托管代码的数据
- Windows 服务导入C++非托管代码
- 将字符串数组从托管代码编组到本机代码
- P/从获取"tried to access protected memory error"调用非托管C++代码
- 将数据从非托管代码传递到托管代码
- 为使用C# /托管代码的无注册COM Interop设置DLL
- 从无操纵项目(C/C VS2005)调用托管代码(C#/Visual Basic VS2010)
- 从 VB.NET 调用非托管代码C++ dll
- 当C#中的字节数组传递给结构中的非托管代码时,会发生什么情况
- 在托管代码和非托管代码之间传递非托管结构的安全数组
- 如何调试C++非托管代码中的较低级别文件访问异常/崩溃
- 如何从非托管c++ CLR托管代码传递IntPtr到方法