1

I have the following types in C++:

typedef void* keychain_handle;

typedef struct {
  const char* keyHolderName;
  unsigned int numKeys;
  key* keys;
} key_holder;

typedef struct {
  const char* keyName;
  unsigned int keySize;
} key;

And I have the following methos:

int createKeyChain(
  int id, 
  key_holder* keyHolders,
  keychain_handle* handle);

I need my C# to create key holders with keys, send it to the C++ code and receive a handle.

This is my C# code:

    /* Structs */
    [StructLayout(LayoutKind.Sequential)]
    public struct Key
    {
          public string key;
          public uint size;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct KeyHolder
    {
          public string name;
          public uint keys;
          public IntPtr keys;
    }


    /* Sync API */
    [DllImport("keys.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
    public static extern uint createKeyChain(uint id, KeyHolder[] keyHolders, ref IntPtr handle);


        Key[] myKeys = new Key[1];
        myKeys[0] = new Key { key = "tst", size = 5 };

        KeyHolder keyHolder = new DllWrapper.KeyHolder
        {
            name = "tst123",
            items = 1,
            keys = Marshal.AllocHGlobal(Marshal.SizeOf(typeof (Key))*myKeys.Length)
        };

        IntPtr c = new IntPtr(keyHolder.keys.ToInt32());

        for (int i = 0; i < myKeys.Length; i++)
        {
            Marshal.StructureToPtr(myKeys[i], c, false);
            c = new IntPtr(c.ToInt32() + Marshal.SizeOf(typeof(Key)));
        }

        Marshal.StructureToPtr(c, keyHolder.keys, false);

        IntPtr handle = IntPtr.Zero;

        var ret = createKeyChain(111, new []{keyHolder}, ref handle);

Everything is working well except for the internal string inside the Key object, which is corrupt. I suspect it is the StructureToPtr that is corrupting it. How can I make the string show on the C++ side?

Thanks.

10
  • can you please show what have you tried in C#? Commented Mar 18, 2015 at 16:03
  • please add Key and KeyHolder definitions Commented Mar 18, 2015 at 16:20
  • @nikis, sorry I forgot to add it, added now. Commented Mar 18, 2015 at 16:23
  • 1
    That's quite a nasty one. Going to require quite a bit of manual marshalling. I think you'll need to marshal the array of keys as IntPtr, and then marshal each key individually. Going to need one call to Marshal.StringToHGlobalAnsi for each element of the array. Is C++/CLI an option? Commented Mar 18, 2015 at 16:34
  • Yeah I guess it is an option. Commented Mar 18, 2015 at 16:37

2 Answers 2

1

Without making changes to the unmanaged code, you have no option but to marshal this all yourself. Which looks something like this:

[StructLayout(LayoutKind.Sequential)]
public struct _Key
{
    public IntPtr keyName;
    public uint keySize;
}

[StructLayout(LayoutKind.Sequential)]
public struct _KeyHolder
{
    public string name;
    public uint numKeys;
    public IntPtr keys;
}

public struct Key
{
    public string keyName;
    public uint keySize;
}

public static _KeyHolder CreateKeyHolder(string name, Key[] keys)
{
    _KeyHolder result;
    result.name = name;
    result.numKeys = (uint)keys.Length;
    result.keys = Marshal.AllocHGlobal(keys.Length * Marshal.SizeOf(typeof(_Key)));
    IntPtr ptr = result.keys;
    for (int i = 0; i < result.numKeys; i++)
    {
        _Key key;
        key.keyName = Marshal.StringToHGlobalAnsi(keys[i].keyName);
        key.keySize = keys[i].keySize;
        Marshal.StructureToPtr(key, ptr, false);
        ptr += Marshal.SizeOf(typeof(_Key));
    }
    return result;
}

public static void DestroyKeyHolder(_KeyHolder keyHolder)
{
    IntPtr ptr = keyHolder.keys;
    for (int i = 0; i < keyHolder.numKeys; i++)
    {
        _Key key = (_Key)Marshal.PtrToStructure(ptr, typeof(_Key));
        Marshal.FreeHGlobal(key.keyName);
        ptr += Marshal.SizeOf(typeof(_Key));
    }
    Marshal.FreeHGlobal(keyHolder.keys);
}
Sign up to request clarification or add additional context in comments.

6 Comments

The function actually takes an array of key holders, but that's not actually the issue. The only issue I have left is the key string not making it to the C++ side. Can you give an example to what you have just explained?
I've updated my post to contain my latest code, where I iterate over all the keys and marshal them.
What you suggested regarding the Key array is not working: Cannot marshal field 'keys' of type 'KeyHolder': Invalid managed/unmanaged type combination (Arrays fields must be paired with ByValArray or SafeArray).
Ok. I deleted that. I can't write any more code right now. If you are still stuck later, I'll have time.
Well I am officially stuck. I even tried to change the string to one(!) char, and it comes out corrupt.
|
-1

You still need to tell .NET to marshal the strings as PChars:

[StructLayout(LayoutKind.Sequential)]
public struct Key
{
      [MarshalAs(UnmanagedType.LPStr)]
      public string key;
      public uint size;
}

[StructLayout(LayoutKind.Sequential)]
public struct KeyHolder
{
      [MarshalAs(UnmanagedType.LPStr)]
      public string name;
      public uint keyCount;

      public Key[] keys;
}

4 Comments

Even if I add that attribute, the key string is corrupt. I think the Marshal.StructureToPtr for the entire Key object corrupts it.
@Tsury Aaah, of course, you can't do that when you're using Marshal.StructureToPtr. Either make the invoke work all the way through (e.g. Key[] instead of IntPtr), or handle the strings manually as well - IntPtr key, and Marshal.PtrToStringAnsi.
Isn't PtrToStringAnsi the opposite? I need to convert a string to IntPtr, right?
@Tsury: Oh, I thought you want to read those. If you want to pass some, Marshal.StringToHGlobalAnsi is your man. Do make sure either you (usually you, right after the method call) or the library free up the memory, though.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.