我正在尝试使用C#VS2013程序中的Pinvoke来访问现有的DelphiXE2 dll程序。 Delphi程序获取xml文件和IB数据库文件,并根据xmlfile更新数据库。从另一个Delphi程序成功调用DelphiXE2 dll程序。在C#中我试图调用GETxml程序。我得到一个{“外部组件抛出异常。”}错误。
我需要对我要做的事情进行语法检查,因为我是C#和DELPHI的新手。
C#
[DllImport("MSA.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, EntryPoint = "GetXML")]
extern static int GetXML([MarshalAs(UnmanagedType.LPStr)] string a, [MarshalAs(UnmanagedType.LPStr)] string b, Boolean c);
int retval = 0;
retval = GetXML(txtPath.Text.ToString().Trim(), txtCabFile.Text.ToString().Trim(), false);
现有的Delphi程序:(我注意到这个dll函数没有发生数据库打开。实际上它是在调用GetXML之前在调用Delphi程序中发生的。不确定这是否是一个问题,因为我是从C#程序调用。)
function GetXML(DatabasePath: pChar; OFileName: pChar; Silent: Boolean = True): Integer; stdcall;
var
xmlDatabase: TIBDatabase;
xmlTransaction: TIBTransaction;
objXML: TXML;
begin
Result := -1;
if FileExists(oFilename) then
begin
objXML := nil;
xmlDatabase := nil;
try
xmlDatabase := TIBDatabase.Create(nil);
xmlTransaction := TIBTransaction.Create(xmlDatabase);
xmlTransaction.DefaultDatabase := xmlDatabase;
xmlDatabase.DatabaseName := DatabasePath;
xmlDatabase.Params.Add('user_name=SYSTASS');
xmlDatabase.Params.Add('password=pswdf88');
xmlDatabase.LoginPrompt := False;
xmlDatabase.DefaultTransaction := xmlTransaction;
xmlDatabase.Connected := True;
xmlTransaction.StartTransaction;
try
objXML := TXML.Create(XMLDatabase, IsSecGDB(XMLDatabase)); //uses IBQUERY to start transaction
objXML.XMLIntoDB(oFilename, Silent);
xmlTransaction.Commit;
result := 1;
except
on e: Exception do
begin
xmlTransaction.Rollback;
raise Exception.Create('GetXML Exception: ' + e.Message);
end;
end;
finally
FreeAndNil(objXML);
if xmlDatabase <> nil then
xmlDatabase.Close;
FreeAndNil(xmlDatabase);
end;
端 其他 开始 提出Exception.Create(找不到'Filename'+ oFilename +'参数。'); 结束; 端;
答案 0 :(得分:2)
首先,让我们看一下互操作边界两侧的不匹配。您从C#传递ANSI字符串,但Delphi代码需要UTF-16。
[DllImport("MSA.dll", CallingConvention = CallingConvention.StdCall,
CharSet = CharSet.Unicode, EntryPoint = "GetXML")]
extern static int GetXML(
[MarshalAs(UnmanagedType.LPStr)]
string a,
[MarshalAs(UnmanagedType.LPStr)]
string b,
Boolean c
);
虽然你指定了CharSet.Unicode
,然后继续使用PAnsiChar
明确告诉编组人员编组为UnmanagedType.LPStr
。对于UTF-16,您可以使用UnmanagedType.LPWStr
但是,你的p / invoke是不必要的复杂。我会写这样的p / invoke:
[DllImport("MSA.dll", CharSet = CharSet.Unicode)]
extern static int GetXML(string a, string b, bool c);
请注意,CallingConvention.StdCall
是默认值。这里不需要指定EntryPoint
因为它只重复了函数名称。自您指定MarshalAs
以来,您不需要CharSet.Unicode
属性。
现在,您遇到的一个更大的问题是您在互操作边界上抛出本机Delphi异常。这就是为什么p / invoke层反对并说:
外部组件抛出异常
跨越此互操作边界抛出异常是绝对禁止的。别那样做。你必须使用错误代码处理老派的错误。