尝试从VS2013 C#程序调用DELPHI XE2 DLL时出错

时间:2013-12-16 13:27:10

标签: c# delphi pinvoke delphi-xe2

我正在尝试使用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 +'参数。');   结束; 端;

1 个答案:

答案 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层反对并说:

  

外部组件抛出异常

跨越此互操作边界抛出异常是绝对禁止的。别那样做。你必须使用错误代码处理老派的错误。