开发者

How come replacing char[] with IntPtr or StringBuilder in a DllImport return value causes my program to no longer find the correct entry point?

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:

c开发者_运维问答har * errMessage(int err);


Write a C++/CLI wrapper. It is an amazingly easy and powerful way to bridge the gap between C# and unmanaged (old) C/C++.


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);
    }
}


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.


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜