how to call a C function from C# with a WCHAR* out

2019-04-08 23:09发布

I'm having a bit of problem with marshaling and I just can't figure it out by myself. I've searched for this topic, but hadn't have any luck yet, so basically I'm trying to call an unmanaged C function from my managed C# application. The signature of the C function looks like this:

long MyFunction(WCHAR* upn, long upnSize, WCHAR* guid, long* guidSize);

I don't access to the .dll file, I just know that the function is being exposed for usage and I know what the function is supposed to do, but I don't know what happening inside, so the function receives a WCHAR* upn holding a UserPricipalName and a long with the length of the supplied UPN. Also a WCHAR pointer is passed along, where the function writes back a corresponding GUID which is associated with the passed UPN. The guidSize pointer supplies the size of the pointer, if it's too small the written GUID is not fully written. If everything goes fine the function should return 0 (it never happened yet, when called from c#)

Now my efforts to invoke and call this function look like this:

[DllImport(@"MyDll.dll", EntryPoint = "MyFunction", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
public static extern long MyFunction(IntPtr upnPtr, long upnSize, [Out, MarshalAsAttribute(UnmanagedType.LPWStr) ] StringBuilder guidPtr, IntPtr guidSizePtr);


//my attempt to call the Dll's exposed function
string upn = foo@bar.com;
long upnSize = upn.Length;
IntPtr upnPtr = Marshal.StringToHGlobalUni(upn);

IntPtr guidSizePtr = Marshal.AllocHGlobal(sizeof(long));
Marshal.WriteInt32(GuidSizePtr, 128);
var guidSB = new StringBuilder(128);

result = MyFunction(upnPtr, upnSize, guidSB, guidSizePtr);

as a result I receive an AccessViolationException. I've played around with many variations to call the function, but I never managed to receive a 0 as return value and I was never able to read out the GUID as I'm supposed to do.

Any help with this would be appreciated.

1条回答
Ridiculous、
2楼-- · 2019-04-08 23:59

Declare the function as:

    [DllImport(@"MyDll.dll", EntryPoint = "MyFunction", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
    public static extern int MyFunction([MarshalAsAttribute(UnmanagedType.LPWStr)] string upnPtr, int upnSize, [MarshalAsAttribute(UnmanagedType.LPWStr)] StringBuilder guidPtr, ref int guidSizePtr);

Call it as follows:

        string upn = "foo@bar.com";
        var guidSB = new StringBuilder(128);
        int guidSizePtr =guidSB.Capacity;
        MyFunction(upn, upn.Length, guidSB, ref guidSizePtr);

Note that long in C++ is 32-bit, so you should define all such instances as int in your C# code.

查看更多
登录 后发表回答