Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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 = [email protected];
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.

like image 846
butterwaach Avatar asked Aug 09 '12 08:08

butterwaach


1 Answers

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 = "[email protected]";
        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.

like image 161
logicnp Avatar answered Sep 21 '22 01:09

logicnp