我被迫使用非托管delphi dll。我没有访问源代码的权限。只有模糊的文档:
type
TServiceData = packed record
DBAlias: PChar;
LicKey: PChar;
Pass: PChar;
end;
PServiceData = ^TServiceData;
function CreateRole(SrvData: PServiceData; var UserName: PChar): byte; stdcall;
UserName
应该是out
参数。
我的C#代码:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct SERVICE_DATA
{
public string DBALias;
public string LicKey;
public string Pass;
}
[DllImport(dllname, CallingConvention = CallingConvention.StdCall)]
public static extern byte CreateRole(SERVICE_DATA data, out string str);
我不知道是什么导致堆栈不平衡(除了调用约定似乎是正确的)。我不知道我的结构中的字符串是否正确编组,但根据其他线程,这不会导致PStackImbalanceException。任何帮助将不胜感激:)
EDIT。 我已经实施了David的建议,现在我遇到了访问冲突异常:
“未处理的异常:System.AccessViolationException:尝试读取或写入受保护的内存。这通常表示其他内存已损坏”
我的结构和方法声明只是从答案中复制粘贴,我称之为没有什么花哨的方式:
string str;
var data = new SERVICE_DATA();
data.DBALias = "test";
data.LicKey = "test";
data.Pass = "test";
var result = CreateRole(ref data, out str);
答案 0 :(得分:2)
翻译有一些问题:
CoTaskMemAlloc
在COM堆上分配。我猜你没有这样做,所以当编组人员试图通过调用CoTaskMemFree
来解除分配指针时,你会遇到问题。我可能会对字符串使用COM字符串类型。我也会避免打包记录,因为这是一般规则的不良做法。
我这样写:
<强>的Delphi 强>
type
TServiceData = record
DBAlias: WideString;
LicKey: WideString;
Pass: WideString;
end;
function CreateRole(const SrvData: TServiceData; out UserName: WideString): Byte;
stdcall;
<强> C#强>
[StructLayout(LayoutKind.Sequential)]
public struct SERVICE_DATA
{
[MarshalAs(UnmanagedType.BStr)]
public string DBALias;
[MarshalAs(UnmanagedType.BStr)]
public string LicKey;
[MarshalAs(UnmanagedType.BStr)]
public string Pass;
}
[DllImport(dllname, CallingConvention = CallingConvention.StdCall)]
public static extern byte CreateRole(
[In] ref SERVICE_DATA data,
[MarshalAs(UnmanagedType.BStr)] out string str
);
这是一个完整的测试项目,表明它按预期工作:
<强>的Delphi 强>
library Project1;
type
TServiceData = record
DBAlias: WideString;
LicKey: WideString;
Pass: WideString;
end;
function CreateRole(const SrvData: TServiceData; out UserName: WideString): Byte;
stdcall;
begin
UserName := SrvData.DBAlias + SrvData.LicKey + SrvData.Pass;
Result := Length(UserName);
end;
exports
CreateRole;
begin
end.
<强> C#强>
using System;
using System.Runtime.InteropServices;
namespace ConsoleApplication1
{
class Program
{
const string dllname = @"...";
[StructLayout(LayoutKind.Sequential)]
public struct SERVICE_DATA
{
[MarshalAs(UnmanagedType.BStr)]
public string DBALias;
[MarshalAs(UnmanagedType.BStr)]
public string LicKey;
[MarshalAs(UnmanagedType.BStr)]
public string Pass;
}
[DllImport(dllname, CallingConvention = CallingConvention.StdCall)]
public static extern byte CreateRole(
[In] ref SERVICE_DATA data,
[MarshalAs(UnmanagedType.BStr)] out string str
);
static void Main(string[] args)
{
SERVICE_DATA data;
data.DBALias = "DBALias";
data.LicKey = "LicKey";
data.Pass = "Pass";
string str;
var result = CreateRole(ref data, out str);
Console.WriteLine(result);
Console.WriteLine(str);
}
}
}
<强>输出强>
17 DBALiasLicKeyPass