为什么在 DllImport 返回值中用 IntPtr 或 StringBuilder 替换 char[] 会导致我的程序不再找到正确的入口点?
编辑:我刚刚意识到这是定义为宏,而不是函数。我到底如何将宏从 DLL 导入到 C# 中? (这可能是一个新问题)。
这与我刚刚问的一个问题有关:
一些答案建议我将函数签名更改为 IntPtr 或 StringBuilder。我还在谷歌搜索的一些网站上看到了这些解决方案,最值得注意的是这里。 (还有其他的,但我没有时间寻找链接)。
函数签名:
[DllImport("api.dll")] internal static extern char[] errMessage(int err);
如果我更改返回类型,我的调用将引发以下异常:
“无法在 DLL 中找到名为“errMessage”的入口点”
如果它不起作用,我无法想象人们会建议这样做。我在这里做错了什么吗?是不是少了点什么?遗憾的是,我的 C/C++ 技能很糟糕,所以我可能会错过一些非常简单的东西。感谢您的任何帮助。
编辑:文档中的函数签名:
char * errMessage(int err);
EDIT: I just realized this is defined as a MACRO, not a function. How the heck would I import a macro from a DLL to C#? (this may have to be a new question).
This is related to a question I just asked:
How Do I Properly Return A Char From An Unmanaged Dll To C#?
Some of the answers suggested I change the function signature to IntPtr or StringBuilder. I also saw these solutions on a few sites in my googling, most notably here. (There were others, but I don't have time to hunt down the links).
Function signature:
[DllImport("api.dll")] internal static extern char[] errMessage(int err);
If I change the return type, my call throws the following exception:
"Unable to find an entry point named 'errMessage' in DLL"
I can't imagine people would suggest this if it didn't work. Am I doing something wrong here? Is there something missing? Sad to say, but my C/C++ skills are terrible, so I could be missing something really simple. Thanks for any help.
EDIT: Function signature from documentation:
char * errMessage(int err);
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
编写 C++/CLI 包装器。这是一种弥合 C# 和非托管(旧)C/C++ 之间差距的极其简单且强大的方法。
Write a C++/CLI wrapper. It is an amazingly easy and powerful way to bridge the gap between C# and unmanaged (old) C/C++.
编辑:更新以反映导入宏:
现在,你可以做的是查看宏的作用,然后使用 P/Invoke 实现它。以下建议也适用于此。
使用 Platform Invoke (P/Invoke) 时,最好尽可能明确:
此外,最好提供一个托管入口点,使该方法更加“.Net”。您可以在此处确保调用者分配的内存保持适当的时间(您可能必须实现 SafeHandle) 或其他挥手动作得到处理。
假设 errMessage 返回一个字符串,我们不负责释放:
EDIT: updated to reflect importing a macro:
Now, what you can do is look at what the macro does, then implement that with P/Invoke. The below advice holds for that as well.
When working with Platform Invoke (P/Invoke) it is best to be as explicit as possible:
Moreover, it is best to provide a managed entry-point that makes the method more ".Net". This is where you would ensure that Caller allocated memory gets held the appropriate amount of time (you may have to implement a SafeHandle) or that other hand-waving gets handled.
Assuming
errMessage
returns a string we aren't responsible for deallocating:您可能需要更改 C/C++ 方法以返回指针,据我所知,我还没有看到 DllImport 从函数返回字符数组。我建议您更改 errMessage 函数中的 API 代码,也许您可以返回 api.dll 库中指向 char 的指针,而不是返回 char[]...即
void errMessage(int err, char *ptr );
第二点......您是否使用它返回标准 Win API 错误代码,有一个 Marshal.Win32Error 类可以为您完成这项工作?
你怎么认为?
汤姆.
You may need to change your C/C++ method to return a pointer, AFAIK I have not seen a DllImport returning back an array of characters from a function. I would suggest you change around your API code within the function errMessage, perhaps instead of returning back char[], you could return back a pointer to char in your api.dll library...i.e.
void errMessage(int err, char *ptr);
On second note...are you using this to return back a standard Win API error code, there is a Marshal.Win32Error class that would do just the job for you?
What do you think?
Tom.
看起来调用约定不是 stdcall(这是 DllImport 使用的默认调用约定)。
如果没有另外声明,C/C++ 使用 CDECL 调用约定。因此,您必须将此调用约定添加到 DllImport 调用中。
Looks like the calling convention is not stdcall (which is the default one used by DllImport).
C/C++ use the CDECL calling convention if not declared otherwise. So you have to add this calling convention to the DllImport call.