简体   繁体   中英

C# wrapper class for c++ lib dll

I am trying to create a class in c# to access the function in a c++ lib. The function in the c++ dll :
bool WriteReply(const unsigned char *reply, const unsigned long reply_length) .

A sample of how its used in c++:-

unsigned short msg_id = 0x0000;                      
byte msg_body[] = {(byte)(GetTickCount()/0x100)};    // a random value for loopback data

    // combine the message id and message body into an big msg
    unsigned long msg_length = sizeof(msg_id)+sizeof(msg_body);
    byte* big_msg = new byte[msg_length];
    big_msg[0] = LOBYTE(msg_id);
    big_msg[1] = HIBYTE(msg_id);
    memcpy((void*)&big_msg[2], (void*)msg_body, sizeof(msg_body));

    // send the big message
    if (!big_dev.WriteReply(big_msg, msg_length))
    {
        //do something here
    }

I can't seem to pass the function from c# to the dll ( AccessViolationException ). This is the command i've tried:-

byte[] bytearray = new byte[3] { 0x01, 0x02, 0x03 };
IntPtr unmanagedPointer = Marshal.AllocHGlobal(bytearray.Length);
Marshal.Copy(bytearray, 0, unmanagedPointer, bytearray.Length);

bool writestatus = (bool)NativeMethods.WriteReply(unmanagedPointer, (uint)bytearray.Length);

and on the import side:-

[DllImport("dllname.dll", EntryPoint = "WriteReply")]
[return: MarshalAs(UnmanagedType.U1)]
internal static extern bool WriteReply(IntPtr msg, uint reply_length);

Please let me know where have i gone wrong?Thanks!

Assuming your C++ method uses the string and does not modify it...

Try this

__declspec(dllexport) bool __cdecl WriteReply(const unsigned char *reply, const unsigned long reply_length);


[DllImport("libfile.dll", EntryPoint = "WriteReply")]
private static extern bool WriteReplyExternal(
    [MarshalAs(UnmanagedType.LPStr)] [Out] string replyString,
    [Out] UInt32 replyLength);

Or better yet (since C strings are null-terminated and the buffer is readonly, so you don't have to worry about buffer overflow, the length parameter is redudant):

__declspec(dllexport) bool __cdecl WriteReply(const unsigned char *reply);


[DllImport("libfile.dll", EntryPoint = "WriteReply")]
private static extern bool WriteReplyExternal(
    [MarshalAs(UnmanagedType.LPStr)] [Out] string replyString);

These will work if the method is not within a class, otherwise you will need to use the C++ mangled name as the entry point .

If your string contains characters outside the 1...127 ASCII range (eg non-English letters), you should use wchar_t instead of char in the C++ and LPWStr instead of LPStr in the marshalling.

Edit:

You need to wrap the private method with another method with a signature that is more appropriate for .NET eg

public void WriteReply(string message)
{
    var result = WriteReplyExternal(message, message.Length);
    if (result == false)
        throw new ApplicationException("WriteReplay failed ...");
}

I think the latest addition of code provides a clue as to the real problem:

if (!big_dev.WriteReply(big_msg, msg_length))

This cannot work because WriteReply is an member function. You need to be calling a C style function rather than a C++ member function. The latter requires an instance ( big_dev in the code sample).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM