What to pass for pinned string in P/Invoke?

℡╲_俬逩灬. 提交于 2019-12-10 15:07:30

问题


Assume this C function:

void do_something(const char* str)

It stores the string somewhere for later reference.

Furthermore, I have this signature in C# to call this function:

[DllImport("NativeLib")]
static extern void do_something(string str);

Now, what do I need to do when passing a string to this method:

  • Do I need to pin the string (with GCHandle.Alloc()) (or is the marshaller creating a copy)?
  • If I do need to pin it, do I pass the "original" string (i.e. the string I passed to GCHandle.Alloc())? Or do I need to pass the return value of GCHandle.AddrOfPinnedObject()?
  • Is string the correct data type (for do_something) in this case? Or should I use IntPtr instead?

回答1:


Storing pointers through an interop boundary is a Really Bad Idea, do everything you can to modify the C code to make a copy of the string instead.

Pinning the string as suggested in the upvoted answer isn't going to work, the pinvoke marshaller must convert the string to char* and releases that converted string after making the native call, invalidating the pointer. You must marshal the string yourself. Declare the argument as IntPtr and use Marshal.StringToHGlobalAnsi() to create the pointer value.

Or use Marshal.StringToCoTaskMemAnsi(), it allocates from the COM heap. Which is your real problem, there is no great scenario to release the string. The C code cannot release the string because it doesn't know how it was allocated. Your C# code cannot release the string because it doesn't know when the C code is done with the pointer. This is why copying the string is so important. You can live with the memory leak if you make this call only a few times.




回答2:


Given that the unmanaged code will be storing a pointer rather than copying the string, I recommend that you use GCHandle.Alloc() to manually create a copy of the string and pass it as an IntPtr.

You will then be able to manage the lifetime of the passed block of memory, only releasing it (via the GCHandle) when you are done with it.



来源:https://stackoverflow.com/questions/10977231/what-to-pass-for-pinned-string-in-p-invoke

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!