【发布时间】:2016-11-23 10:11:19
【问题描述】:
我一直在尝试将类指针从本机 DLL 传递给 CLR。我没有那么成功。我明白了,它使用 void * 返回指针,然后使用 IntrPtr 和 ToPointer() 将其转换为 ClassType *。但是在我尝试访问其成员方法的那一刻,它无法获取旧的属性值。我得到的是 0 和一些随机值。
我什至尝试使用 VC100 作为 CLR 和本机 dll 的工具集。我仍然得到值“读取字符串字符时出错”。
我尝试 google 并找不到太多关于将对象指针从本机传递到 CLR 的信息。我甚至提到了代码项目中可用的step-by-step。
编辑添加:
我有一个本地 dll,其中有一个返回对象指针的函数
Native.dll:
#if defined EXPORTDLL // inside DLL
#define DLL_EXPORT __declspec(dllexport)
#else // outside DLL
#define DLL_EXPORT __declspec(dllimport)
#endif
.....
DLL_EXPORT void* SomeMethod(uint16_t num1, const char * str1, const char * str2)
{
Obj1 obj(...);
...
return (void*)&obj; // <- at this point it is still correct
}
....
class DLL_EXPORT Obj1{
....
const std::string var1;
const std::string var2;
const std::string var3;
....
DLL_EXPORT strct1 memberFunction1()
{
// do something with the variables
// here when its called by managed code, the var1, var2, var3 shows random values and bad ptr..
}
...
}
稍后在托管代码 clr 中,我使用返回指针调用 memberFunct1。
[DllImport("Native.dll", EntryPoint = "?SomeMethod@@YAPAVstruct1@someSpace@@GV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@0@Z", CallingConvention = CallingConvention::Cdecl)]
IntPtr * SomeMethod(uint16_t num1, [In, MarshalAs(UnmanagedType::LPStr)]String^ str1, [In, MarshalAs(UnmanagedType::LPStr)] String^ str2);
.....
String^ str1 = gcnew String("1223568");
String^ str2 = gcnew String("1.2.3.5");
Obj1 *objptr = (Obj1*)(SomeMethod(1,str1, str2)).ToPointer();
// <- at this point the objptr properties are showing garbage
objptr->memberFunction1();
我使用这个 obj1 指针来调用成员方法,但在成员方法中,成员值显示为错误的 ptr。
有人能指点我正确的方向吗?
提前致谢。
我在我的 Native dll 中添加了一个额外的方法。
void DLL_EXPORT SomeMethod2(int i1, const char* var1, const char* var2, Obj1* retval);
并从我的 CLR 项目中调用它
[DllImport("Native.dll", EntryPoint = "?SomeMethod2@@YAXHPBD0PAVObj1@@@Z", CallingConvention = CallingConvention::Cdecl)]
void SomeMethod2(int i1, [MarshalAs(UnmanagedType::LPStr)]String^ var1, [MarshalAs(UnmanagedType::LPStr)]String^ var2, Obj1* retval);
....
Obj1 * testPtr3;
SomeMethod2(1, (char*)(void*)Marshal::StringToHGlobalAnsi(str1), (char*)(void*)Marshal::StringToHGlobalAnsi(str2), testPtr3);
SomeMethod2(1, str1, str2, testPtr3);
Obj1 testPtr2 = Obj1(1, (char*)(void*)Marshal::StringToHGlobalAnsi(str1), (char*)(void*)Marshal::StringToHGlobalAnsi(str2));
但我收到链接错误?我已经链接了??!!??
错误 LNK2028: 未解析的令牌 (0A000356) "public: __thiscall Obj1::Obj1(int,char const *,char const *)" (??0Obj1@@$$FQAE@HPBD0@Z) 在函数 "int __cdecl main(void)" (?main@@$$HYAHXZ)
错误 LNK2028:在函数“int __cdecl main(void)" (?main@@$$HYAHXZ)
错误 LNK2019:在函数“int __cdecl main (void)" (?main@@$$HYAHXZ)
错误 LNK2019:函数“int __cdecl main( void)" (?main@@$$HYAHXZ)
【问题讨论】:
-
@Martin 抱歉,我已经编辑了我的帖子并添加了一些代码。
-
这是一个沼泽标准dangling pointer bug。 C 或 C++ 程序中非常常见的错误,通常很难诊断。但是,当您使用 pinvoke 时,pinvoke 编组器所需的堆栈空间可确保
obj被可靠地覆盖。您必须将其存储在其他地方,最好的位置几乎总是调用者的堆栈帧。将返回类型更改为 void 并添加Obj1* retval参数。 -
@HansPassant 我也试过你的。但我仍然收到链接错误。我已经编辑了我的帖子以包含您提到的内容,并添加了显示链接的图片。
-
@ras - 从屏幕截图中 - 删除 ClrDLLWrapper 项目中的
Native.dll -
@MartinBa - 我已将其删除。还是有链接错误。
标签: visual-c++ dll c++-cli marshalling void-pointers