首先:我閱讀了很多類似的問題,嘗試了很多不同的解決方案,但我無法使用 Delphi DLL。
Delphi DLL 提供以下方法:
procedure FetchData(var infoIn: INParameter; var infoOut: OUTParameter; var details: OUTDetails); stdcall; external DLL_Name;
型別定義如下:
type
Info1 = record
Param1: Byte;
Param2: Byte;
Param3: Byte;
Param4: Byte;
Param5: integer;
end;
PInfo1 = ^Info1;
Info2 = record
Param1: Byte;
Param2: integer;
Param3: integer;
Param4: integer;
Param5: long;
Param6: string;
Param7: integer;
Param8: array [0 .. 8] of integer;
Param9: string;
end;
PInfo2 = ^Info2;
INParameter = record
Param1: integer;
Param2: integer;
Param3: integer;
Param4: Byte;
Param5: Byte;
Param6: Byte;
Param7: Byte;
Param8: Byte;
Param9: Byte;
Param10: Byte;
Param11: Byte;
Param12: Byte;
Param13: Byte;
Param14: Byte;
Param15: Byte;
Param16: Byte;
Param17: Byte;
Param18: Byte;
Param19: Byte;
Param20: Byte;
Param21: Byte;
Param22: Byte;
Param23: integer;
Param24: integer;
Param25: Byte;
Param26: Byte;
Param27: Byte;
Param28: Byte;
Param29: Byte;
Param30: Byte;
Param31: Byte;
Param32: Byte;
Param33: integer;
Param34: PInfo1;
Param35: PInfo2;
end;
OUTParameter = record
Param1: integer;
Param2: integer;
Param3: integer;
Param4: integer;
Param5: bool;
Param6: bool;
Param7: integer;
Param8: integer;
Param9: bool;
Param10: bool;
Param11: bool;
Param12: bool;
Param13: bool;
Param14: bool;
Param15: integer;
Param16: integer;
Param17: integer;
Param18: bool;
Param19: bool;
Param20: integer;
end;
Pos = record
Param1: integer;
Param2: integer;
Param3: Byte;
Param4: Byte;
end;
OUTDetails = record
Poss: array [0 .. 3, 0 .. 20] of Pos;
end;
我已經將型別翻譯為 C#,如下所示:
public structure Info1
{
public Byte Param1;
public Byte Param2;
public Byte Param3;
public Byte Param4;
public int Param5;
}
public structure Info2
{
public Byte Param1;
public int Param2;
public int Param3;
public int Param4;
public long Param5;
public string Param6;
public int Param7;
public int[] Param8;
public string Param9;
}
public structure INParameter
{
public int Param1;
public int Param2;
public int Param3;
public Byte Param4;
public Byte Param5;
public Byte Param6;
public Byte Param7;
public Byte Param8;
public Byte Param9;
public Byte Param10;
public Byte Param11;
public Byte Param12;
public Byte Param13;
public Byte Param14;
public Byte Param15;
public Byte Param16;
public Byte Param17;
public Byte Param18;
public Byte Param19;
public Byte Param20;
public Byte Param21;
public Byte Param22;
public int Param23;
public int Param24;
public Byte Param25;
public Byte Param26;
public Byte Param27;
public Byte Param28;
public Byte Param29;
public Byte Param30;
public Byte Param31;
public Byte Param32;
public int Param33;
public PInfo1 Param34;
public PInfo2 Param35;
}
public structure OUTParameter
{
public int Param1;
public int Param2;
public int Param3;
public int Param4;
public bool Param5;
public bool Param6;
public int Param7;
public int Param8;
public bool Param9;
public bool Param10;
public bool Param11;
public bool Param12;
public bool Param13;
public bool Param14;
public int Param15;
public int Param16;
public int Param17;
public bool Param18;
public bool Param19;
public int Param20;
}
public structure Pos
{
public int Param1;
public int Param2;
public Byte Param3;
public Byte Param4;
}
public structure Details
{
public Pos[] Poss;
}
然后,在控制臺應用程式中,我添加了 DLL extern 方法定義:
[DllImport("DelphiDLL.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
public static extern void FetchData(IntPtr paramIn,
IntPtr paramOut,
IntPtr detailsOut);
我嘗試了不同的定義,使用:
ref INParameter, ref OUTParameterout OUTParameter[Out, MarshalAs(UnmanagedType.Struct)] out OUTParameter
我最后說 Delphi 需要一個指標,并將在其中寫入資料。所以我給了IntPtr。
對于輸入/輸出引數指標,我這樣做了:
IntPtr pnt = Marshal.AllocHGlobal(Marshal.SizeOf(oneOUTParameter));
Marshal.StructureToPtr(oneOUTParameter, pntForOneOUTParameter, false);
并叫FetchData(pntForINParameter, pntForOUTParameter, pntForOUTDetailParameter);
每次我遇到錯誤時:
在 DelphiDLLTest.exe 中的 0x004F0928 (DelphiDLL.dll) 處引發例外:0xC0000005:訪問沖突讀取位置 0x00002EE0。
你能幫助我嗎?
編輯:替換ShortString為String, 和 C# 中的其他型別。
uj5u.com熱心網友回復:
我在您的代碼中看到了一些互操作問題:
PInfo1C# 中不使用和類似的原始指標PInfo2,因此將它們替換為IntPtr.stringstring在 Delphi 中與在 C#中非常不同。在 Delphi 中,astring是指向字符資料的指標,因此您必須IntPtr在 C# 端使用。如果您需要從stringDelphi 分配的欄位中讀取,您可以簡單地使用Marshal.PtrToStringAnsi()(Delphi 2007 或更早版本) 或Marshal.PtrToStringUni()(Delphi 2009 或更高版本)。但是,如果你需要傳遞一個stringDelphi 會讀的,祝你好運。您不僅要為字符資料手動分配記憶體,還要為StrRec字符資料之前的記錄手動分配記憶體(該記錄的內容可能因 Delphi 版本而異)。因此,string越過 DLL 邊界在互操作中是一個壞主意。您應該改用平面Char[]陣列(或 aShortString)或空終止PChar指標。C# 陣列是動態分配的,因此當 a 中包含固定大小的陣列時
struct,需要MarshalAs在 C# 端使用來指定陣列的大小。Delphi 中的 a
bool大小為 1 位元組,但在 C# 互操作中,默認情況下將 abool編組為 4 位元組整數(LongBool在 Delphi 中為 a )。你需要使用MarshalAs來改變它。a Windows
LONG是一個 4 位元組整數。Delphi 中的ALongint在大多數平臺上為 4 位元組,但在 Posix 64 位系統上為 8 位元組。C# 中的along始終為 8 個位元組。
話雖如此,您顯示的 Delphi 代碼將在 C# 中轉換為更像以下內容:
[StructLayout(LayoutKind.Sequential, Pack=8)]
public struct Info1
{
public byte Param1;
public byte Param2;
public byte Param3;
public byte Param4;
public int Param5;
}
[StructLayout(LayoutKind.Sequential, Pack=8)]
public struct Info2
{
public byte Param1;
public int Param2;
public int Param3;
public int Param4;
public int Param5; // long; use IntPtr or nint instead, if needed
public IntPtr Param6; // string
public int Param7;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=9)]
public int[] Param8;
public IntPtr Param9; // string
}
[StructLayout(LayoutKind.Sequential, Pack=8)]
public struct INParameter
{
public int Param1;
public int Param2;
public int Param3;
public byte Param4;
public byte Param5;
public byte Param6;
public byte Param7;
public byte Param8;
public byte Param9;
public byte Param10;
public byte Param11;
public byte Param12;
public byte Param13;
public byte Param14;
public byte Param15;
public byte Param16;
public byte Param17;
public byte Param18;
public byte Param19;
public byte Param20;
public byte Param21;
public byte Param22;
public int Param23;
public int Param24;
public byte Param25;
public byte Param26;
public byte Param27;
public byte Param28;
public byte Param29;
public byte Param30;
public byte Param31;
public byte Param32;
public int Param33;
public IntPtr Param34; //PInfo1
public IntPtr Param35; //PInfo2
}
[StructLayout(LayoutKind.Sequential, Pack=8)]
public struct OUTParameter
{
public int Param1;
public int Param2;
public int Param3;
public int Param4;
[MarshalAs(UnmanagedType.U1)]
public bool Param5;
[MarshalAs(UnmanagedType.U1)]
public bool Param6;
public int Param7;
public int Param8;
[MarshalAs(UnmanagedType.U1)]
public bool Param9;
[MarshalAs(UnmanagedType.U1)]
public bool Param10;
[MarshalAs(UnmanagedType.U1)]
public bool Param11;
[MarshalAs(UnmanagedType.U1)]
public bool Param12;
[MarshalAs(UnmanagedType.U1)]
public bool Param13;
[MarshalAs(UnmanagedType.U1)]
public bool Param14;
public int Param15;
public int Param16;
public int Param17;
[MarshalAs(UnmanagedType.U1)]
public bool Param18;
[MarshalAs(UnmanagedType.U1)]
public bool Param19;
public int Param20;
}
[StructLayout(LayoutKind.Sequential, Pack=8)]
public struct Pos
{
public int Param1;
public int Param2;
public byte Param3;
public byte Param4;
}
[StructLayout(LayoutKind.Sequential, Pack=8)]
public struct OUTDetails
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst=84)]
public Pos[] Poss;
}
[DLLImport("DLL_Name", CallingConvention = CallingConvention.StdCall)]
void FetchData(ref INParameter infoIn, ref OUTParameter infoOut, ref OUTDetails details);
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/516717.html
