可以在CLR和本机C ++之间传递对象指针吗?

时间:2016-07-20 08:59:09

标签: visual-c++ dll c++-cli marshalling void-pointers

我一直在尝试将类指针从本机DLL传递给CLR。我不是那么成功。我发现它使用void *返回指针,然后使用IntrPtr和ToPointer()将其转换为ClassType *。但是,当我尝试访问其成员方法时,它无法获取旧的属性值。我得到0和一些随机值。

我甚至尝试将VC100用作CLR和本机dll的工具集。我仍然得到值"读取字符串"的错误。

我试图google并且无法找到有关将原始对象指针从CLR传递到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)&#34; public:__ thishisall Obj1 :: Obj1(int,char const *,char const *)&#34;函数&#34; int __cdecl main(void)&#34;中引用了(?? 0Obj1 @@ $$ FQAE @ HPBD0 @ Z) (?主@@ $$ HYAHXZ)

错误LNK2028:未解析的令牌(0A00035B)&#34; void __cdecl SomeMethod2(int,char const *,char const *,class Obj1 *)&#34; (?SomeMethod2 @@ $$ FYAXHPBD0PAVObj1 @@@ Z)在函数&#34; int __cdecl main(void)&#34;中引用(?主@@ $$ HYAHXZ)

错误LNK2019:未解析的外部符号&#34; public:__ thishisall Obj1 :: Obj1(int,char const *,char const *)&#34;函数&#34; int __cdecl main(void)&#34;中引用了(?? 0Obj1 @@ $$ FQAE @ HPBD0 @ Z) (?主@@ $$ HYAHXZ)

错误LNK2019:未解析的外部符号&#34; void __cdecl SomeMethod2(int,char const *,char const *,class Obj1 *)&#34; (?SomeMethod2 @@ $$ FYAXHPBD0PAVObj1 @@@ Z)在函数&#34; int __cdecl main(void)&#34;中引用(?主@@ $$ HYAHXZ)

enter image description here

1 个答案:

答案 0 :(得分:1)

您不以这种方式使用C ++ / CLI!

C ++ / CLI的整个是.NET世界和本地世界之间的粘合剂。

你要做的是:

  • 在C ++ / CLI源文件中包含SomeMethodclass Obj1的C ++标头,
  • 让C ++ / CLI程序集引用Native.dll项目

然后,您可以像在C ++中一样使用它 - convert any CLR types to native representation first(如果包含MFC,则可以通过MFC CString转换System :: String):

String^ str1 = gcnew String("1223568");
String^ str2 = gcnew String("1.2.3.5");
Obj1 *objptr = SomeMethod(1, CString(str1), CString(str2));

至于为什么你在调试器中看到垃圾:可能是因为你返回一个本地对象的地址

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
}

在这种情况下,obj一旦从SomeMethod返回,就会清除new(它的D&#39被调用并且其堆栈内存被回收)。

  • 按值返回对象
  • Shared向上对象并返回指针。 (虽然这是泄密风险代码)