2012-05-24 37 views
1

我有一個C++結構,它具有下面的char [20],並且它被打包。在c#中的char []數組相當於#

#pragma pack(push, temp_aion_packed, 1) 
struct temp 
{ 
    char x[20]; 
    char y[20]; 
}; 
#pragma pack(pop, temp_aion_packed) 

現在我怎麼能在c#中寫這個結構,以便兩者都是相同的。我在C#這樣寫的

[DataContract] 
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1),Serializable] 
public class temp 
{ 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)] 
    public string x; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)] 
    public string y; 
} 
下面

是在C#中進行pinvoke聲明

[DllImport("rmsCAPI.dll", CallingConvention = CallingConvention.StdCall, ExactSpelling = true, EntryPoint = "OrderRequirement")] 
    public static extern int OrderRequirement(ref temp tmp); 

C++函數調用此結構作爲參數

long __stdcall OrderRequirement(struct temp *tmp) 
{ 
    string p=""; 
    string q=""; 
    p=temp->x; 
    q=temp->y; 
    char buff[2048]; 
    sprintf(buff,"p: %s\n q: %s\n x: %s\n y: %s\n",p,q,temp->x,temp->y); 
} 

但是當我做這樣的c#它給我的C++垃圾數據,當我在c#中爲他們分配值。任何人都可以協助。

謝謝大家對上述問題的幫助,但現在我得到了一個新的問題,這是一個擴展,我在下面詳細提供了一切。

我在C++

#pragma pack(push, temp_aion_packed, 1) 
struct temp 
{ 
    long req; 
    struct type m_type; 
    short id; 
    char x[20]; 
    char y[20]; 
}; 
#pragma pack(pop, temp_aion_packed) 

#pragma pack(push, type_aion_packed, 1) 
struct type 
{ 
    short i; 
}; 
#pragma pack(pop, type_aion_packed) 

結構我寫等價的C#結構像這樣

[DataContract] 
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1),Serializable] 
public struct temp 
{ 
    [DataMember] 
    public long req; 
    [DataMember] 
    [MarshalAs(UnmanagedType.Struct)] 
    public type m_type; 
    [DataMember] 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)] 
    public string x; 
    [DataMember] 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)] 
    public string y; 
} 

[DataContract] 
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1),Serializable] 
public struct type 
{ 
    [DataMember] 
    public short i; 
} 

下面是我的C#的PInvoke

[DllImport("rmsCAPI.dll", CallingConvention = CallingConvention.StdCall, ExactSpelling = true, EntryPoint = "OrderRequirement")] 
    public static extern int OrderRequirement(ref temp tmp); 
下面

是我的C++方法調用結構作爲參數

long __stdcall OrderRequirement(struct temp *tmp) 
{ 
    char buff[2048]; 
    sprintf(buff,"req: %ld \n id: %d \n x: %s\n",tmp->req,tmp->id,tmp->x); 
} 

現在我得到的問題是我在struct temp中聲明的結構變量m_type(struct「type」),在C++程序中正確打印的聲明之前聲明的變量(long req)在那之後沒有給我任何輸出。所以我認爲在c#中的結構聲明搞亂了,我無法弄清楚,所以任何人都可以幫助。

+3

我想你想要byte [20]。 – Ben

+0

@Ben'byte [20]'不能在C#中編譯。 –

+0

@DavidHeffernan - 我現在詳細提供了一切 – krishna555

回答

1

您將結構聲明爲C#中的類。這很好,但它意味着任何這種類型的變量已經是一個參考。所以你不需要通過ref。當你通過ref傳遞一個類時,你最終會傳遞一個指向該對象的指針。這是一個間接太多的層面。

的P /調用在C#代碼因此應該是這樣的:

public static extern int OrderRequirement(temp tmp); 

的另一種方法來解決它是離開ref在函數聲明,但聲明temp類型作爲struct而不是class。這是因爲struct是一個值類型。類型是struct的變量是一個值而不是引用。

這兩種解決方案的工作,這取決於你選擇。


您的C++代碼還有另一個問題。

sprintf(buff,"p: %s\n q: %s\n x: %s\n y: %s\n",p,q,temp->x,temp->y); 

你傳入pq,這是std::string型到printf和期待%s格式字符串打印出來。這是一個錯誤。你需要在字符串上調用c_str()。就像這樣:

sprintf(
    buff, 
    "p: %s\n q: %s\n x: %s\n y: %s\n", 
    p.c_str(),q.c_str(),temp->x,temp->y 
); 

的問題,您的更新是長是Windows C++ 32位,並在C#64位。你需要在C#中聲明它爲int。你錯過了id字段。

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1),Serializable] 
public struct temp 
{ 
    [DataMember] 
    public int req; 

    [DataMember] 
    public type m_type; 

    [DataMember] 
    public short id; 

    [DataMember] 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)] 
    public string x; 

    [DataMember] 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)] 
    public string y; 
} 
+0

我試過你最初提到的我認爲它工作但它不工作。 – krishna555

+1

是的,它確實有效。我建立了一個DLL來證明它的工作原理。也許你可以展示你現在有什麼,我可以幫忙,但我相信這是有效的。當你說「它不工作」時,我們不能做太多事情。你需要提供細節。正是你的代碼失敗的方式。 –

+0

好吧,我再次檢查它,它的工作,我通過添加另一個結構來驗證它,並且我看到原始問題。在另一個結構中的結構是導致問題的原因,我不知道如何解決它。我已經編輯了新的問題,你可以看看它的代碼。 – krishna555