简体   繁体   中英

Using C# Nested Structs In C++

I've asked before that question.

How to pass C++ Struct To C# DLL ?

Now I'm trying to nested struct marshal.

I've replaced structs like that.

typedef struct TKeyValue
{
  char Key[15];
  char Value[15];
} TKeyValue;

typedef struct MyStruct
{
  TKeyValue *KeyValues[1];
} TMyStruct;
typedef int (__stdcall *DoSomething)(char [],char[],TMyStruct *);

calling DLL function

void __fastcall TForm1::btnInvokeMethodClick(TObject *Sender)
{
  wchar_t buf[256];
  String DLL_FILENAME = "ClassLibrary1.dll";
  HINSTANCE dllHandle = NULL;

  dllHandle = LoadLibrary(DLL_FILENAME.c_str());

  FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, 256, NULL);
  OutputDebugStringW(buf);

  if(dllHandle == NULL) return;

  DoSomething xDoSomething = (DoSomething)GetProcAddress(dllHandle, "DoSomething");
  FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, 256, NULL);
  OutputDebugStringW(buf);

  if (xDoSomething == NULL) return;

  try
  {
      TMyStruct aMyStruct;

      char parameter1[15];
      char parameter2[15];
      strcpy(parameter1,"value1");
      strcpy(parameter2,"value2");

      int result = xDoSomething(parameter1,parameter2,&aMyStruct);

      FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, 256, NULL);
      OutputDebugStringW(buf);

      //access violation at this line
      ShowMessage(aMyStruct.KeyValue[0]->Key);
  }
  catch(EAccessViolation &err)
  {
    ShowMessage(err.Message);
  }

  FreeLibrary(dllHandle);

C# Side

    [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    public struct KeyValue
    {
        [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 15)]
        public string Key;

        [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 15)]
        public string Value;
    }



    [ComVisible(true)]
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    public struct MyStruct
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
        public KeyValue[] KeyValues;
    }

        [DllExport("DoSomething", CallingConvention = CallingConvention.StdCall)]
    public static int DoSomething(string tcKnVkn, string sifre, ref MyStruct myStruct)
    {
        try
        {
            MyStruct.KeyValues[0].Key = "key 1";
            MyStruct.KeyValues[0].Value = "value 1";
        }
        catch (Exception e)
        {
            System.Windows.Forms.MessageBox.Show(e.Message);
        }

        return 2;
    }

When i compile my project and run, it throws access violation error after accessing Key field of TKeyValue like that aMyStruct.KeyValue[0]->Key

What's my mistaken ?

Thanks.

The problem here is your Arrays field. The C++ declaration is:

char *Array[3];           // 3 pointers, uses up 12 bytes (32bit system)

Which means an array of 3 pointers. Stop for a second and consider how far off that is from a string -- it's not a contiguous block of memory with characters that you're passing, you're passing a number . If you wanted to pass 3 C strings, you'd declare it like this instead (not what you're sending by the way, you need different attributes on the C# side):

char Array[15][3];        // 3 strings, uses up 45 bytes

You're sending garbage in those pointers, and when the C code is trying to dereference them it gets an access violation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM