在 C# 中使用 Delphi DLL
Using Delphi DLL in C#
我有一个用 Delphi(未知版本)编写的第三方 "mystery dll",在 delphi(2009 年过去)中的工作示例,迫切需要在我的 C# 代码中使用所述 dll , 几乎没有相关知识如何去做。
以下是使用此 dll 的 Delpi 示例:
type
TD_Query = function(host: WideString; port : Word;pud,query : WideString):WideString; stdcall;
procedure TForm11.Button6Click(Sender: TObject);
var
Handle : LongWord;
D_Query : TD_Query;
sss : WideString;
begin
Handle := LoadLibrary('kobrasdk.dll');
sss:='';
if Handle <> 0 then
begin
@D_Query := GetProcAddress(Handle, 'D_Query');
sss:=D_Query('host',8201,'pud','query');
FreeLibrary(Handle);
end;
end;
下面是我用 C# 解释它的尝试:
class Program
{
[DllImport("C:\Games\kobrasdk.dll", CallingConvention = CallingConvention.StdCall,
CharSet = CharSet.Ansi)]
[return: MarshalAs(UnmanagedType.LPStr)]
public static extern string D_Query(string host, ushort port, string pud, string query);
static void Main(string[] args)
{
D_Query("test", 8201, "test", "test");
}
}
不幸的是,我得到的是一个错误:试图读取或写入受保护的内存。这通常表示其他内存已损坏。
根据我白天阅读的内容,我可能弄错了 return 类型或参数类型。帮忙?
我基本上明白了。由于某些我不清楚的原因,C# 无法处理 WideString return 值。如果您可以访问 delphi 源代码,则可能适合将函数与过程交换,并将 return 值作为 "out" 参数传递。在我的例子中,我无法访问源代码,所以我被迫编写一个代理 DLL 来这样做。
例如上面,"proxy" dll代码:
type
TD_Query = function(host : WideString;port : Word;pud,query : WideString):WideString; stdcall;
procedure My_D_Query(host: WideString; port: Word; pud, query: WideString; out return : WideString); stdcall;
var
Handle: LongWord;
D_Query : TD_Query;
sss : WideString;
begin
Handle := LoadLibrary('kobrasdk.dll');
sss:='';
if Handle <> 0 then
begin
@D_Query:=GetProcAddress(Handle, 'D_Query');
sss:=D_Query(host,port,pud,query);
FreeLibrary(Handle);
end;
return := sss;
end;
然后用 C# 代码访问它:
[DllImport("C:\MyDll.dll", CallingConvention = CallingConvention.StdCall,
CharSet = CharSet.Ansi)]
public static extern void My_D_Query(
[MarshalAs(UnmanagedType.BStr)]
string host,
int port,
[MarshalAs(UnmanagedType.BStr)]
string pud,
[MarshalAs(UnmanagedType.BStr)]
string query,
[MarshalAs(UnmanagedType.BStr)]
out string result
);
它不漂亮,但对我来说,它就是答案。
Delphi ABI 在某些类型上不同于 Microsoft ABI。 Delphi WideString
是托管类型(在 Delphi 术语中),并且 return 类型使用与 Microsoft 工具不兼容的 ABI。
Delphi ABI 将托管的 return 类型转换为隐藏的 var
参数。所以编译器转换:
function(host: WideString; port: Word; pud, query: WideString): WideString; stdcall;
进入
procedure(var result: WideString; host: WideString; port: Word; pud, query: WideString);
stdcall;
因此,您可以通过以转换后的形式导入函数,从 C# 访问原始 Delphi 函数。
[DllImport(@"...", CallingConvention = CallingConvention.StdCall)]
public static extern void My_D_Query(
[MarshalAs(UnmanagedType.BStr)]
out string result,
[MarshalAs(UnmanagedType.BStr)]
string host,
ushort port,
[MarshalAs(UnmanagedType.BStr)]
string pud,
[MarshalAs(UnmanagedType.BStr)]
string query
);
我有一个用 Delphi(未知版本)编写的第三方 "mystery dll",在 delphi(2009 年过去)中的工作示例,迫切需要在我的 C# 代码中使用所述 dll , 几乎没有相关知识如何去做。
以下是使用此 dll 的 Delpi 示例:
type
TD_Query = function(host: WideString; port : Word;pud,query : WideString):WideString; stdcall;
procedure TForm11.Button6Click(Sender: TObject);
var
Handle : LongWord;
D_Query : TD_Query;
sss : WideString;
begin
Handle := LoadLibrary('kobrasdk.dll');
sss:='';
if Handle <> 0 then
begin
@D_Query := GetProcAddress(Handle, 'D_Query');
sss:=D_Query('host',8201,'pud','query');
FreeLibrary(Handle);
end;
end;
下面是我用 C# 解释它的尝试:
class Program
{
[DllImport("C:\Games\kobrasdk.dll", CallingConvention = CallingConvention.StdCall,
CharSet = CharSet.Ansi)]
[return: MarshalAs(UnmanagedType.LPStr)]
public static extern string D_Query(string host, ushort port, string pud, string query);
static void Main(string[] args)
{
D_Query("test", 8201, "test", "test");
}
}
不幸的是,我得到的是一个错误:试图读取或写入受保护的内存。这通常表示其他内存已损坏。
根据我白天阅读的内容,我可能弄错了 return 类型或参数类型。帮忙?
我基本上明白了。由于某些我不清楚的原因,C# 无法处理 WideString return 值。如果您可以访问 delphi 源代码,则可能适合将函数与过程交换,并将 return 值作为 "out" 参数传递。在我的例子中,我无法访问源代码,所以我被迫编写一个代理 DLL 来这样做。 例如上面,"proxy" dll代码:
type
TD_Query = function(host : WideString;port : Word;pud,query : WideString):WideString; stdcall;
procedure My_D_Query(host: WideString; port: Word; pud, query: WideString; out return : WideString); stdcall;
var
Handle: LongWord;
D_Query : TD_Query;
sss : WideString;
begin
Handle := LoadLibrary('kobrasdk.dll');
sss:='';
if Handle <> 0 then
begin
@D_Query:=GetProcAddress(Handle, 'D_Query');
sss:=D_Query(host,port,pud,query);
FreeLibrary(Handle);
end;
return := sss;
end;
然后用 C# 代码访问它:
[DllImport("C:\MyDll.dll", CallingConvention = CallingConvention.StdCall,
CharSet = CharSet.Ansi)]
public static extern void My_D_Query(
[MarshalAs(UnmanagedType.BStr)]
string host,
int port,
[MarshalAs(UnmanagedType.BStr)]
string pud,
[MarshalAs(UnmanagedType.BStr)]
string query,
[MarshalAs(UnmanagedType.BStr)]
out string result
);
它不漂亮,但对我来说,它就是答案。
Delphi ABI 在某些类型上不同于 Microsoft ABI。 Delphi WideString
是托管类型(在 Delphi 术语中),并且 return 类型使用与 Microsoft 工具不兼容的 ABI。
Delphi ABI 将托管的 return 类型转换为隐藏的 var
参数。所以编译器转换:
function(host: WideString; port: Word; pud, query: WideString): WideString; stdcall;
进入
procedure(var result: WideString; host: WideString; port: Word; pud, query: WideString);
stdcall;
因此,您可以通过以转换后的形式导入函数,从 C# 访问原始 Delphi 函数。
[DllImport(@"...", CallingConvention = CallingConvention.StdCall)]
public static extern void My_D_Query(
[MarshalAs(UnmanagedType.BStr)]
out string result,
[MarshalAs(UnmanagedType.BStr)]
string host,
ushort port,
[MarshalAs(UnmanagedType.BStr)]
string pud,
[MarshalAs(UnmanagedType.BStr)]
string query
);