我是编程新手,有人可以帮我调用delphi dll中的指针函数到Visual C#函数 .
这是存储在DLL中的Delphi函数 . // Delphi代码存储在DLL中
function DeviceName(Size : Integer; Msg : Pointer) : Integer stdcall;
var
i: Integer;
TempByte : PByte;
TempName : string;
begin
if DLLClass.DevList.HidDevices.Count > 0 then
begin
TempName := (DLLClass.DevList.HidDevices.Name[DLLClass.HIDTool.CurrentDeviceIndex]);
if Length(TempName) <= Size then
begin
try
TempByte := Msg;
for i := 0 to Length(TempName) - 1 do
begin
TempByte^ := Ord(TempName[i+1]);
Inc(TempByte)
end;
Result := Length(TempName);
except
Result := -2;
end;
end
else
begin
Result := -3;
end;
end
else
begin
Result := -1;
end;
end;
// C#Code` //导入功能指针
[DllImport("HID_DLL.dll", CallingConvention= CallingConvention.StdCall, CharSet = CharSet.Ansi)]
public unsafe static extern int DeviceName(IntPtr Size, [MarshalAs(UnmanagedType.LPStr)] string Msg);
unsafe static void Main()
{
byte[] buffer = new byte[32768];
DeviceName(255, &**buffer);
Console.WriteLine("%s\n" + buffer);
}
`
1 回答
这个Delphi函数有点乱 . 它的工作是将字符串复制到调用者提供的缓冲区中 . 通常使用以null结尾的字符串来完成,但Delphi代码不会这样做 .
假设无法修改Delphi代码,这里是如何从C#调用它 . 请注意,这里不需要不安全的代码,我建议您停止使用不安全的代码 .
首先是p / invoke声明:
Size
参数在Delphi中的类型为Integer
. 这是C#中的32位整数 . 所以使用int
,就像你对返回值所做的那样 . 不要使用IntPtr
这是一个大小等于指针大小的整数 . 这在64位进程中是不正确的 .Msg
参数应该作为字节数组分配,因为您没有添加空终止符 . 而这反过来意味着没有必要指定CharSet
.现在来电:
你的Delphi功能设计很差 . 如前所述,在这种情况下习惯使用以null结尾的字符串 . 这样做允许你让p / invoke marshaller处理锅炉板代码 . 您的错误代码也很差 . 如果用户传递的大小不足以存储字符串,则应让他们知道需要多少空间 .
Delphi函数的实现也是次优的 . 您应该一次性复制整个缓冲区,而不是逐字节复制 .
最后一条建议 . 您的函数返回指示是否成功的值 . 您的C#代码只是忽略那些返回值 . 作为一个广泛的规则,如果一个函数返回一个值,你应该注意它 . 特别是在执行互操作时,返回值表示成功或失败 .