为什么在 DllImport 返回值中用 IntPtr 或 StringBuilder 替换 char[] 会导致我的程序不再找到正确的入口点?

发布于 2024-08-11 21:39:08 字数 859 浏览 6 评论 0原文

编辑:我刚刚意识到这是定义为宏,而不是函数。我到底如何将宏从 DLL 导入到 C# 中? (这可能是一个新问题)。

这与我刚刚问的一个问题有关:

我该怎么办正确地将字符从非托管 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

放血 2024-08-18 21:39:08

编写 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++.

不爱素颜 2024-08-18 21:39:08

编辑:更新以反映导入宏:

你不能。

现在,你可以做的是查看宏的作用,然后使用 P/Invoke 实现它。以下建议也适用于此。


使用 Platform Invoke (P/Invoke) 时,最好尽可能明确:

internal static class NativeMethods
{
    private static string DllName = @"api.dll";

    // This uses 'string' assuming you do not have to free the memory.
    [DllImport(DllName, EntryPoint = "errMessage",
         CharSet = YourCharacterSet,              // CharSet.Ansi? .Unicode?
         CallingConvention = DllCallingConvention // .StdCall? .Cdecl?
    )]
    public static string errMessage(int errorCode);
}

此外,最好提供一个托管入口点,使该方法更加“.Net”。您可以在此处确保调用者分配的内存保持适当的时间(您可能必须实现 SafeHandle) 或其他挥手动作得到处理。

假设 errMessage 返回一个字符串,我们不负责释放:

public static class ManagedMethods
{
    public static string ErrorMessage(ErrorCode errorCode)
    {
        return NativeMethods.errMessage((int)errorCode);
    }
}

EDIT: updated to reflect importing a macro:

You can't.

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:

internal static class NativeMethods
{
    private static string DllName = @"api.dll";

    // This uses 'string' assuming you do not have to free the memory.
    [DllImport(DllName, EntryPoint = "errMessage",
         CharSet = YourCharacterSet,              // CharSet.Ansi? .Unicode?
         CallingConvention = DllCallingConvention // .StdCall? .Cdecl?
    )]
    public static string errMessage(int errorCode);
}

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:

public static class ManagedMethods
{
    public static string ErrorMessage(ErrorCode errorCode)
    {
        return NativeMethods.errMessage((int)errorCode);
    }
}
岁月染过的梦 2024-08-18 21:39:08

您可能需要更改 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.

呢古 2024-08-18 21:39:08

看起来调用约定不是 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文