调用 Delphi DLL 并将 C# Stream 传递给它
Call a Delphi DLL and pass a C# Stream to it
我有一个用 Delphi 编写的 DLL,从那里我只知道他的签名,例如:
function GeResultToStream(Param1: PChar; Param2: PChar; Param3:PChar; Param4: integer; out Param5: DWord; ParamStream: IStream; Error: PChar; ErrorSize: integer):BOOL;stdcall; external 'MYDLL.dll';
我在从 C# 调用此 DLL 方法时遇到了一些问题。如果一切顺利,该方法还应该在 ParamStream
和 return true
中传输一些数据。
我尝试了以下方法(以及 DLL 方法参数中的其他各种更改)但没有成功(每次我使用引用或输出参数调用此函数时都出现错误):
public class TestDLL
{
internal class DLLInternal
{
const string _dllLocation = "MYDLL.dll";
[DllImport(_dllLocation,
CallingConvention = CallingConvention.StdCall,
CharSet = CharSet.Ansi,
EntryPoint = "GeResultToStream")]
public static extern bool GeResultToStream(string Param1, string Param2, string Param3, int Param4, char[] Param5, ref Stream ParamStream, string Error, int ErrorSize);
}
public TestDLL()
{
}
~TestDLL()
{
}
public Stream GetStream(string Param1, string Param2, string Param3, int Param4, char[] Param5, string Error, int ErrorSize)
{
try
{
Stream stream = new MemoryStream();
bool x = DLLInternal.GeResultToStream(Param1, Param2, Param3, Param4, Param5, ref stream, Error, ErrorSize);
//here i think i might need to use somehow the Marshal class
return stream;
}
catch (Exception ex)
{
Console.WriteLine("Exception GetStream:" + ex.ToString());
return null;
}
}
}
我的猜测是我不明白如何以正确的方式翻译签名以在 C# 中使用它。如果需要,我可以提供更多信息(比如我得到的错误,但大多数是损坏的内存)。
你的翻译有误。我不确定您如何将 DWORD
类型的 out
参数转换为 char[]
。那应该是out uint
。而且Stream
不应该是ref
,而且需要是IStream
接口而不是Stream
class.
p/invoke应该是这样的:
[DllImport(_dllLocation, CallingConvention = CallingConvention.StdCall,
CharSet = CharSet.Ansi, EntryPoint = "GeResultToStream")]
public static extern bool GeResultToStream(
string Param1,
string Param2,
string Param3,
int Param4,
out uint Param5,
ComTypes.IStream ParamStream,
string Error,
int ErrorSize
);
请注意,这假定 Delphi 版本为 2007 或更早版本,其中 PChar
映射到 PAnsiChar
。如果Delphi版本比那个晚,而PChar
是PWideChar
,那么就用CharSet.Unicode
.
我还假设所有的字符串参数都用于将数据从调用者传递给被调用者。但可能最后的字符串参数 Error
没有那些语义。这可能是为了传递错误文本。因此应该用 StringBuilder
代替 string
.
来实现
当然,您需要从某处获得 IStream
的实现。例如:Creating IStream object in C#。我很难就此向您提出建议,因为您没有提供有关如何调用该函数的任何重要细节。而且您更改了所有参数的名称,因此我们无法猜测其语义。
随着调试的进行,我可以看出这个问题变成了火车残骸。我希望我被证明是错误的。
我有一个用 Delphi 编写的 DLL,从那里我只知道他的签名,例如:
function GeResultToStream(Param1: PChar; Param2: PChar; Param3:PChar; Param4: integer; out Param5: DWord; ParamStream: IStream; Error: PChar; ErrorSize: integer):BOOL;stdcall; external 'MYDLL.dll';
我在从 C# 调用此 DLL 方法时遇到了一些问题。如果一切顺利,该方法还应该在 ParamStream
和 return true
中传输一些数据。
我尝试了以下方法(以及 DLL 方法参数中的其他各种更改)但没有成功(每次我使用引用或输出参数调用此函数时都出现错误):
public class TestDLL
{
internal class DLLInternal
{
const string _dllLocation = "MYDLL.dll";
[DllImport(_dllLocation,
CallingConvention = CallingConvention.StdCall,
CharSet = CharSet.Ansi,
EntryPoint = "GeResultToStream")]
public static extern bool GeResultToStream(string Param1, string Param2, string Param3, int Param4, char[] Param5, ref Stream ParamStream, string Error, int ErrorSize);
}
public TestDLL()
{
}
~TestDLL()
{
}
public Stream GetStream(string Param1, string Param2, string Param3, int Param4, char[] Param5, string Error, int ErrorSize)
{
try
{
Stream stream = new MemoryStream();
bool x = DLLInternal.GeResultToStream(Param1, Param2, Param3, Param4, Param5, ref stream, Error, ErrorSize);
//here i think i might need to use somehow the Marshal class
return stream;
}
catch (Exception ex)
{
Console.WriteLine("Exception GetStream:" + ex.ToString());
return null;
}
}
}
我的猜测是我不明白如何以正确的方式翻译签名以在 C# 中使用它。如果需要,我可以提供更多信息(比如我得到的错误,但大多数是损坏的内存)。
你的翻译有误。我不确定您如何将 DWORD
类型的 out
参数转换为 char[]
。那应该是out uint
。而且Stream
不应该是ref
,而且需要是IStream
接口而不是Stream
class.
p/invoke应该是这样的:
[DllImport(_dllLocation, CallingConvention = CallingConvention.StdCall,
CharSet = CharSet.Ansi, EntryPoint = "GeResultToStream")]
public static extern bool GeResultToStream(
string Param1,
string Param2,
string Param3,
int Param4,
out uint Param5,
ComTypes.IStream ParamStream,
string Error,
int ErrorSize
);
请注意,这假定 Delphi 版本为 2007 或更早版本,其中 PChar
映射到 PAnsiChar
。如果Delphi版本比那个晚,而PChar
是PWideChar
,那么就用CharSet.Unicode
.
我还假设所有的字符串参数都用于将数据从调用者传递给被调用者。但可能最后的字符串参数 Error
没有那些语义。这可能是为了传递错误文本。因此应该用 StringBuilder
代替 string
.
当然,您需要从某处获得 IStream
的实现。例如:Creating IStream object in C#。我很难就此向您提出建议,因为您没有提供有关如何调用该函数的任何重要细节。而且您更改了所有参数的名称,因此我们无法猜测其语义。
随着调试的进行,我可以看出这个问题变成了火车残骸。我希望我被证明是错误的。