Search code examples
c#cstringunmanagedmanaged

How can I pass an empty string buffer that can be written to from native to c#?


I'm trying to get a string from my managed code into my unmanaged code:

unmanaged dll:

typedef int (__stdcall * GetNameFromDictionaryCallback)(ULONGLONG id, WCHAR * name);

declspec(dllexport) void __stdcall UnmanagedSetNameLookupCallback(GetNameFromDictionaryCallback fn)
{
     GetNameFromDictionaryCallback GetNameFromDictionary = fn;

     WCHAR * value = new WCHAR[256];
     ULONGLONG key = 0x250000000DA44785;
     GetNameFromDictionary(key, value); // reverse P/Invoke call to C# function
     wprintf_s("%ls", value); // just to display the result for simplicity
     delete value;
}

managed dll:

public class ProgramInterop
{
    private delegate int GetNameFromDictionaryCallback(UInt64 key, string value);
    private static GetNameFromDictionaryCallback mGetNameInstance;
    private Dictionary<UInt64, string> dict;

    private ProgramInterop()
    {
        mGetNameInstance = new GetNameFromDictionaryCallback(GetNameFromDictionary);
        UnmanagedSetNameLookupCallback(mGetNameInstance);
    }

    public bool GetNameFromDictionary(UInt64 key, string value)
    {
        return dict.TryGetValue(key, out value);
    }

    [DllImport("Unmanaged.dll")]
    private static extern void UnmanagedSetNameLookupCallback(GetNameFromDictionaryCallback fn);
}

Within my managed program my string looks fine but it turns into garbage on the unmanaged side. I didn't copy all the code but I think this makes the point of what I'm trying to accomplish. If I'm going about this the wrong way or I made mistakes, please let me know. Thanks.


Solution

  • Try this:

    delegate int GetNameFromDictionaryCallback(
        UInt64 key, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder value);
    
    public bool GetNameFromDictionary(UInt64 key, StringBuilder value)
    {
        string s;
        if (dict.TryGetValue(key, out s))
        {
            value.Append(s);
            return true;
        }
        return false;
    }