0

I have been given a C++ Library with a function that takes a parameter of list< pair< tstring, tstring>>. I need to create a C# shim for other developers to be able to use this library.

I understand that marshaling generic types is not allowed, so I wanted to know if I can pass in an array of structs which mimics the list of pairs in C++.

In order to test if this works, I made a simple C++ DLL which mimics the DLL I was given. I created the following function in my C++ Test DLL:

//In my C++ Test DLL
int MyFunction(list<pair<tstring, tstring>> &listParams)

In C#, I created the following Structure to mimic the pair of tstrings:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 1)]
struct myPair
{
    [MarshalAs(UnmanagedType.LPTStr)]
    public string Key;
    [MarshalAs(UnmanagedType.LPTStr)]
    public string Value;

    public myPair(string key, string val)
    {
        Key = key;
        Value = val;
    }
}

Here is also the PInvoke definition to my C++ function:

[System.Runtime.InteropServices.DllImport("MyTestLib.dll",  
CharSet = CharSet.Unicode, EntryPoint = "MyFunction")]
[return: MarshalAs(UnmanagedType.I4)]
public static extern Int32 MyFunction(
        [param:  MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)]
        ref myPair[] listParams);

Here is the code in my C# Test Shim:

    public Int32 MyFunctionTest(Dictionary<string, string> testData)
    {
        Int32 retCode = 0;

        try
        {
            List<myPair> transfer = new List<myPair>();

            foreach (var entry in testData)
            {
                transfer.Add(new myPair(entry.Key, entry.Value));
            }

            myPair[] transferArray = transfer.ToArray();

            retCode = NativeMethods.MyFunction(ref transferArray);

        }
        catch (Exception ex)
        {
        }
        return retCode;
    }

Although the call is successful (does not crash), in my C++ method, the data is garbled and invalid.

Does anyone know if this sort of mapping is even possible?

Russell Gantman
  • 269
  • 4
  • 7
  • The answers to [this question](http://stackoverflow.com/q/30998810/33499) suggests to use a C++/CLI layer between C++ and C# when you use STL classes. See also [this example](http://stackoverflow.com/a/31418911/33499) and [this answer](http://stackoverflow.com/a/15467270/33499) – wimh Feb 01 '16 at 21:20

1 Answers1

1

Thanks to Wimmel I was able to find the answer. It was to create a "CLR based Shim" which is a bridge between my C# and the C++ library.

Here is the code:

//This is a method in a shim class which takes the C# objects
//and translates them to the C++ types required in the C++ dll 
Int32 myClass::Method(Dictionary<System::String^, System::String^> ^args)
{
    Int32 retCode = 0;
    list<pair<wstring, wstring>> listParams;

    for each (KeyValuePair<String^, String^>^ kvp in args)
    {
        listParams.insert(listParams.end(), 
            make_pair(msclr::interop::marshal_as<wstring>(kvp->Key),
            msclr::interop::marshal_as<wstring>(kvp->Value))
                          );
    }

    //My C++ Method
    MyFunction(listParams);

    return retCode;
}

I tested this in my C++ libary and the passed in data went through correctly and ungarbled

Russell Gantman
  • 269
  • 4
  • 7