2015-09-15 41 views
1

我在這個問題之前已經問過。在C++中使用C#嵌套Structs

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

現在我試圖嵌套結構元帥。

我已經替換了那樣的結構。

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

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

調用DLL函數

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#側

[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; 
    } 

當我編譯我的項目並運行,它訪問TKeyValue重點領域一樣,aMyStruct.KeyValue[0]->Key

後引發訪問衝突錯誤

我的錯誤是什麼?

謝謝。

+0

刪除除嵌套結構以外的所有內容。確保工作。然後添加struct的嵌套數組。檢查工作。等等。這是調試的本質。首先分離問題。 –

+0

'myStruct.KeyValues = new KeyValue [2]'看起來很奇怪。編組人員沒有分配嗎?無論如何,直到你減少了這個問題並隔離了問題並在兩邊顯示完整的代碼之後,我纔會再看看。[mcve]。 –

+0

我修改了我的問題 –

回答

0

這裏的問題是你的Arrays字段。 C++的聲明是:

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

這意味着一個3個指針的數組。停一會兒,考慮離字符串有多遠 - 它不是一個連續的記憶塊,你傳遞的是字符,你通過號碼。如果你想通過3個C字符串,你聲明它是這樣,而不是(不是你的方式發送,您需要在C#側不同的屬性):

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

你發送垃圾在這些指針中,當C代碼試圖解引用它們時,它會得到訪問衝突。

+0

他沒有將該字段聲明爲字符串。他宣佈它爲'[MarshalAs(UnmanagedType.ByValArray,SizeConst = 3)] public string [] Array;' –

+0

正確,這是什麼數組? – Blindy

+1

'string'的默認編組是'const char *' –