我想在C#中使用interop調用一些遺留的C代碼。 我不太熟悉C#如何互操作,但必須處理一些令人困惑的結構。 我得到了一部分工作,但當我嘗試將結構體置入C層時,地址混亂了。Interop C#到C++結構
我試圖傳遞結構爲C代碼,它會做一些事情,而我需要得到一個結果返回
我在C#這些結構
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct RETURNBUFFER
public IntPtr records; //this is the struct RECORD
public IntPtr infoA; // this is the struct INFO
public IntPtr infoB;
public int number;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct INFO
{
public IntPtr doc; //this is a handle in C code
public int cpFirst;
public int cpLim;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct RECORD
{
public int size;
}
記錄實際的指針在C#這樣定義的另一結構STATS,
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct STATS
{
public int size;
public int a;
public int b;
public int c;
public int d;
public int e;
public int f;
public int g;
}
在C#層
,我創建像下面
0的結構 RETURNBUFFER returnBuffer = new RETURNBUFFER();
returnBuffer.infoA = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(INFO)));
returnBuffer.infoB = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(INFO)));
returnBuffer.records = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(STATS)));
當我運行我的代碼,我只能檢索returnBuffer的第一個項目是returnBuffer.records, 所有包括returnBuffer int值的其他項目搞砸了。
我試圖通過它來調試,並期待到地址值, 我發現,當從C#代碼的代碼 - > C中的地址轉移
我不知道爲什麼地址是關閉的,
下面是64位環境下所發生的事情爲例
C#
&ReturnBuffer
0x00000000046f05f8
&ReturnBuffer.records
0x00000000046f05f8
&ReturnBuffer.infoA
0x00000000046f0600
&ReturnBuffer.infoB
0x00000000046f0608
&ReturnBuffer.number
0x00000000046f0610
用C
,讓說,我呼籲正在參數RETURNBUFFER * pReturnBuffer功能,
我得到這些地址,
pReturnBuffer
0x00000000046F05F8
&pReturnBuffer->records
0x00000000046F05F8
&pReturnBuffer->infoA
0x00000000046F0600
&pReturnBuffer->infoB
0x00000000046F0610 **This address is off by 8**
&pReturnBuffer->number
0x00000000046F0620 **this is off by 16**
所以,作爲一個結果, 當代碼移動回C#的功能,
我可以正確地構建returnBuffer.records, 但沒能構建既不infoA也不infoB也得到正確的值returnBuffer.number
不知道我在這裏錯過了什麼。
============================================== =
我修改了代碼的幫助下,樂門Pieng
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)]
public struct CRB
{
[FieldOffset(0)]
public IntPtr pcstat;//CSTAT
[FieldOffset(8)]
public IntPtr caProc;//NLCA
[FieldOffset(24)]
public IntPtr caSent;//NLCA
[FieldOffset(40)]
public int cnlch;
}
現在,地址相匹配時,它進入C# - > C++ - > C# 但是我仍然得到一些垃圾數據備份。
我做了一些調查,這裏是我發現的不規律行爲。
在C#代碼我作出這樣
IntPtr的文本=元帥呼叫。StringToCoTaskMemUni(「我在這裏」);
legacyFunction(文字,裁判returnBuffer)
在這裏,當我打電話的GetHashCode的功能,我在從函數返回得到以下值
returnBuffer.records.GetHashCode() 473881344
returnBuffer.infoA.GetHashCode() 473898944
returnBuffer.infoB.GetHashCode() 473898784
text.GetHashCode() 468770816
,這些散列值的變化,
returnBuffer.records.GetHashCode() 543431240
returnBuffer.infoA.GetHashCode() 473799988
returnBuffer.infoB.GetHashCode() 473799988
text.GetHashCode() 473799988
現在,我其實可以做, Marshal.PtrToStringUni(checkReturnBuffer.infoA),我得到 「我在這裏」
C#現在認爲,infoA和infoB都與文本相同。
============================================== ====== 第二編輯
C++的結構實際上是在
typedef struct RETURNBUFFER
{
RECORD *precord;
INFO infoA;
INFO infoB;
UINT number;
} CRB;
感謝您的答覆,這的確是我的問題。
我是莫名其妙的印象, 在C++ 每一個結構/類/對象我必須做出同等的IntPtr在C#
最後一個問題,而我在這裏,所以我不必須重新定義所有結構在一個新的問題中,
intPtr in struct INFO。 在C++中,它是類型的手柄
我在這裏糾正它定義爲IntPtr?它只是一個句柄,但它不是一個*處理思想,或者我應該讓它成爲一個uint值?
這是我從MSDN站點寫道:「記着,返回或接受手柄真的不透明指針工作的任何API函數。您的代碼應該在Windows元帥手柄爲System.IntPtr值」
如果我將它定義爲IntPtr,
我該如何爲它分配內存?以下是否正確?
returnBuffer.infoA.doc = Marshal.AllocCoTaskMem(System.IntPtr.Size);
解組
Marshal.PtrToStructure(returnBuffer.infoA.doc的typeof(IntPtr的));
這是正確的做法嗎?
謝謝你這麼多
in C#IntPtr.Size是8,在C++ sizeof(pReturnBuffer)= 8,而sizeof(pReturnBUffer-> infoA)= 16和sizeof(pReturnBuffer-> records)= 8。可以告訴我你是什麼意思使用Int64? – freshWoWer 2011-03-24 03:00:01
@freshWoWer,很抱歉,Int64部分是來自其他地方的失控文本。不應該在這篇文章中。懷疑,你的infoA不是一個64位的指針。我想你應該在你的問題中包含你的C++結構聲明。顯然,它與C#版本不匹配。 – 2011-03-24 03:17:52