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



我正试图使用C#VS2013程序中的Pinvoke来访问现有的DelphiXE2 dll程序。Delphi程序获取一个xml文件和一个IB数据库文件,并根据xml文件更新数据库。从另一个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;

完其他的开始引发异常。Create(找不到"Filename"+oFilename+"参数。");终止终止

首先,让我们看看interop边界两侧的不匹配。您正在从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,但随后继续并明确告诉编组器使用UnmanagedType.LPStr编组为PAnsiChar。对于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,因为它只是重复函数名称。并且由于指定了CharSet.Unicode,因此不需要MarshalAs属性。


现在,您面临的一个更大的问题是,在interop边界上抛出一个本地Delphi异常。这就是为什么p/invoke层反对并说:

外部组件引发异常

在这个互操作边界上抛出异常是绝对不允许的。别那样做了。你将不得不用老式的错误代码来处理错误。

最新更新