線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:3158
推到 Plurk!
推到 Facebook!

有關C#呼叫Delphi DLL傳遞Array of record型態的問題

答題得分者是:syntax
minjiu
中階會員


發表:27
回覆:119
積分:69
註冊:2002-06-26

發送簡訊給我
#1 引用回覆 回覆 發表時間:2010-03-24 19:42:25 IP:220.130.xxx.xxx 訂閱
以下是我測試的大概程式碼... 

每次在C#呼叫Delphi的DLL函式都會出錯,請問各位高手,我這樣寫是否有錯,要如何修改,謝謝!!
以下是Delphi DLL的型態宣告: [code delphi]

type TRecDetail = packed record
DetailID : Integer;
DetailNO : PAnsiChar;
end;
PRecDetailArray = ^TRecDetailArray;
TRecDetailArray = array of TRecDetail;

type TRecMain = packed record
MainID : Integer;
MainNO : PAnsiChar;
Detail : PRecDetailArray;
end;
PRecMainArray = ^TRecMainArray;
TRecMainArray = packed array of TRecMain;

....

// 給C#呼叫的函式
procedure SendData(var Data : PRecMainArray); stdcall;
begin
.....
end;

[/code]

以下是C#型態宣告:

[code c#]

public struct TRecDetail
{
public int DetailID;
public String DetailNO;
}

public struct TRecMain
{
public int MainID;
public String MainNo;
public TRecDetail[] Detail;
}

// 外部DLL函式
[DllImport(DllFile)]
public static extern void SendData(ref TRecMain[] RecMain);

...

// 實際呼叫
private void button4_Click(object sender, EventArgs e)
{
int iMainCount = 5, iDetailCount = 3;
int iCount = 0;

TRecMain[] RecMain = new TRecMain[iMainCount];
for (int i = 0; i < iMainCount; i )
{
RecMain[i].MainID = i;
RecMain[i].MainNo = "M00" i.ToString();
RecMain[i].Detail = new TRecDetail[iDetailCount];
for (int j = 0; j < iDetailCount; j )
{
iCount ;
RecMain[i].Detail[j].DetailID = iCount;
RecMain[i].Detail[j].DetailNO = "D00" iCount.ToString();
}
}
SendData(ref RecMain);
}

[/code]
編輯記錄
minjiu 重新編輯於 2010-03-24 19:44:33, 註解 無‧
minjiu 重新編輯於 2010-03-24 19:46:10, 註解 無‧
minjiu 重新編輯於 2010-03-24 19:47:16, 註解 無‧
minjiu 重新編輯於 2010-03-24 19:53:47, 註解 無‧
minjiu 重新編輯於 2010-03-24 19:54:06, 註解 無‧
minjiu 重新編輯於 2010-03-24 19:54:35, 註解 無‧
minjiu 重新編輯於 2010-03-24 19:56:00, 註解 無‧
minjiu 重新編輯於 2010-03-24 19:57:30, 註解 無‧
syntax
尊榮會員


發表:26
回覆:1139
積分:1258
註冊:2002-04-23

發送簡訊給我
#2 引用回覆 回覆 發表時間:2010-03-25 07:59:04 IP:59.125.xxx.xxx 訂閱
拿掉 packed
===================引 用 minjiu 文 章===================
以下是我測試的大概程式碼...

每次在C#呼叫Delphi的DLL函式都會出錯,請問各位高手,我這樣寫是否有錯,要如何修改,謝謝!!
以下是Delphi DLL的型態宣告: [code delphi]

type TRecDetail = packed record
DetailID : Integer;
DetailNO : PAnsiChar;
end;
PRecDetailArray = ^TRecDetailArray;
TRecDetailArray = array of TRecDetail;

type TRecMain = packed record
MainID : Integer;
MainNO : PAnsiChar;
Detail : PRecDetailArray;
end;
PRecMainArray = ^TRecMainArray;
TRecMainArray = packed array of TRecMain;

....

// 給C#呼叫的函式
procedure SendData(var Data : PRecMainArray); stdcall;
begin
.....
end;

[/code]

以下是C#型態宣告:

[code c#]

public struct TRecDetail
{
public int DetailID;
public String DetailNO;
}

public struct TRecMain
{
public int MainID;
public String MainNo;
public TRecDetail[] Detail;
}

// 外部DLL函式
[DllImport(DllFile)]
public static extern void SendData(ref TRecMain[] RecMain);

...

// 實際呼叫
private void button4_Click(object sender, EventArgs e)
{
int iMainCount = 5, iDetailCount = 3;
int iCount = 0;

TRecMain[] RecMain = new TRecMain[iMainCount];
for (int i = 0; i < iMainCount; i )
{
RecMain[i].MainID = i;
RecMain[i].MainNo = "M00" i.ToString();
RecMain[i].Detail = new TRecDetail[iDetailCount];
for (int j = 0; j < iDetailCount; j )
{
iCount ;
RecMain[i].Detail[j].DetailID = iCount;
RecMain[i].Detail[j].DetailNO = "D00" iCount.ToString();
}
}
SendData(ref RecMain);
}

[/code]
minjiu
中階會員


發表:27
回覆:119
積分:69
註冊:2002-06-26

發送簡訊給我
#3 引用回覆 回覆 發表時間:2010-03-25 10:43:29 IP:220.130.xxx.xxx 訂閱
感謝 syntax 的回答,可是我不管有沒有加上packed,
在C#執行到SendData(ref RecMain);
就會出現"參數錯誤。 (發生例外狀況於 HRESULT: 0x80070057 (E_INVALIDARG))"的錯誤訊息,
請問還有哪裡可能會有問題,謝謝!!
syntax
尊榮會員


發表:26
回覆:1139
積分:1258
註冊:2002-04-23

發送簡訊給我
#4 引用回覆 回覆 發表時間:2010-03-26 13:27:28 IP:59.125.xxx.xxx 訂閱
1. DLL 不應使用編譯器相依的程式碼, no packed, no dy array
2. 過於複雜的 結構,要 port 到 .Net 必須外加一層處理,即是將原來複雜結構的資料取出,另外組合成簡單結構
3. 觀念請看 http://msdn.microsoft.com/en-us/library/z6cfh6e6.aspx

===================引 用 minjiu 文 章===================
感謝 syntax 的回答,可是我不管有沒有加上packed,
在C#執行到SendData(ref RecMain);
就會出現"參數錯誤。 (發生例外狀況於 HRESULT: 0x80070057 (E_INVALIDARG))"的錯誤訊息,
請問還有哪裡可能會有問題,謝謝!!
minjiu
中階會員


發表:27
回覆:119
積分:69
註冊:2002-06-26

發送簡訊給我
#5 引用回覆 回覆 發表時間:2010-03-26 19:15:28 IP:220.130.xxx.xxx 訂閱
再次感謝syntax 的回答...

看來目前只能將 RecMain 裡的 RecDetail 拆開另外傳遞了,改成傳2個參數就沒問題了...

不過參數內容可正確的傳至Delphi DLL中後,在Delphi中確無法使用Length(), Low() 或 High()函式正確的 RecMain array 及 RecDetail array的大小,真是奇怪...

[code delphi]
type TRecDetail = packed record
MainID : Integer;
DetailID : Integer;
DetailNO : PAnsiChar;
end;
PRecDetailArray = ^TRecDetailArray;
TRecDetailArray = array of TRecDetail;

type TRecMain = packed record
MainID : Integer;
MainNO : PAnsiChar;
end;
PRecMainArray = ^TRecMainArray;
TRecMainArray = packed array of TRecMain;

....

// 給C#呼叫的函式
procedure SendData(var PMain : PRecMainArray;var PDetail : PRecDetailArray); stdcall;
var
Main : TRecMainArray;
Detail : TRecDetailArray;
begin
Main := PRecMainArray(PMain)^;
Detail := PRecDetailArray(PDetail)^;

Length(Main); >> 取出的大小不正確 (不管由C#傳過來的array大小為何,這裡取出來的值都固定不變)
Length(Detail); >> 取出的大小不正確 (不管由C#傳過來的array大小為何,這裡取出來的值都固定不變)

Main[0].MainID; >> 傳過來的值都正確
Main[0].MainNo; >> 傳過來的值都正確
Main[1].MainID; >> 傳過來的值都正確
Main[1].MainNo; >> 傳過來的值都正確
Main[2].MainID; >> 傳過來的值都正確
Main[2].MainNo; >> 傳過來的值都正確


Detail[0].DetailID; >> 傳過來的值都正確
Detail[0].DetailNo; >> 傳過來的值都正確
Detail[1].DetailID; >> 傳過來的值都正確
Detail[1].DetailNo; >> 傳過來的值都正確
Detail[2].DetailID; >> 傳過來的值都正確
Detail[2].DetailNo; >> 傳過來的值都正確
....
end;
[/code]


===================引 用 syntax 文 章===================
1. DLL 不應使用編譯器相依的程式碼, no packed, no dy array
2. 過於複雜的 結構,要 port 到 .Net 必須外加一層處理,即是將原來複雜結構的資料取出,另外組合成簡單結構
3. 觀念請看 http://msdn.microsoft.com/en-us/library/z6cfh6e6.aspx

===================引 用 minjiu 文 章===================
感謝 syntax 的回答,可是我不管有沒有加上packed,
在C#執行到SendData(ref RecMain);
就會出現"參數錯誤。 (發生例外狀況於 HRESULT: 0x80070057 (E_INVALIDARG))"的錯誤訊息,
請問還有哪裡可能會有問題,謝謝!!
編輯記錄
minjiu 重新編輯於 2010-03-26 19:17:47, 註解 無‧
syntax
尊榮會員


發表:26
回覆:1139
積分:1258
註冊:2002-04-23

發送簡訊給我
#6 引用回覆 回覆 發表時間:2010-03-30 08:57:51 IP:59.125.xxx.xxx 訂閱
Delphi 的 Array 是 Delphi 自己的格式
所以當然 Length Low High 無法使用,這很正常
所以你還必須傳陣列長度,這是不可以偷懶的
===================引 用 minjiu 文 章===================
再次感謝syntax 的回答...

看來目前只能將 RecMain 裡的 RecDetail 拆開另外傳遞了,改成傳2個參數就沒問題了...

不過參數內容可正確的傳至Delphi DLL中後,在Delphi中確無法使用Length(), Low() 或 High()函式正確的RecMain array 及RecDetailarray的大小,真是奇怪...

[code delphi]
type TRecDetail = packed record
MainID : Integer;
DetailID : Integer;
DetailNO : PAnsiChar;
end;
PRecDetailArray = ^TRecDetailArray;
TRecDetailArray = array of TRecDetail;

type TRecMain = packed record
MainID : Integer;
MainNO : PAnsiChar;
end;
PRecMainArray = ^TRecMainArray;
TRecMainArray = packed array of TRecMain;

....

// 給C#呼叫的函式
procedure SendData(var PMain : PRecMainArray;var PDetail : PRecDetailArray); stdcall;
var
Main : TRecMainArray;
Detail : TRecDetailArray;
begin
Main := PRecMainArray(PMain)^;
Detail := PRecDetailArray(PDetail)^;

Length(Main); >> 取出的大小不正確 (不管由C#傳過來的array大小為何,這裡取出來的值都固定不變)
Length(Detail); >> 取出的大小不正確 (不管由C#傳過來的array大小為何,這裡取出來的值都固定不變)

Main[0].MainID; >> 傳過來的值都正確
Main[0].MainNo; >> 傳過來的值都正確
Main[1].MainID; >> 傳過來的值都正確
Main[1].MainNo; >> 傳過來的值都正確
Main[2].MainID; >> 傳過來的值都正確
Main[2].MainNo; >> 傳過來的值都正確


Detail[0].DetailID; >> 傳過來的值都正確
Detail[0].DetailNo; >> 傳過來的值都正確
Detail[1].DetailID; >> 傳過來的值都正確
Detail[1].DetailNo; >> 傳過來的值都正確
Detail[2].DetailID; >> 傳過來的值都正確
Detail[2].DetailNo; >> 傳過來的值都正確
....
end;
[/code]


===================引 用 syntax 文 章===================
1. DLL 不應使用編譯器相依的程式碼, no packed, no dy array
2. 過於複雜的 結構,要 port 到 .Net 必須外加一層處理,即是將原來複雜結構的資料取出,另外組合成簡單結構
3. 觀念請看 http://msdn.microsoft.com/en-us/library/z6cfh6e6.aspx

===================引 用 minjiu 文 章===================
感謝 syntax 的回答,可是我不管有沒有加上packed,
在C#執行到SendData(ref RecMain);
就會出現"參數錯誤。 (發生例外狀況於 HRESULT: 0x80070057 (E_INVALIDARG))"的錯誤訊息,
請問還有哪裡可能會有問題,謝謝!!
系統時間:2017-10-24 4:45:33
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!