【发布时间】:2010-11-12 09:49:20
【问题描述】:
编辑:我在下面发布了一个更好的实现。我把它留在这里,这样回复才有意义。
我已经为在 Delphi 中编写 DLL 并能够从 C# 调用它、传递和返回字符串的正确方法进行了大量搜索。很多信息不完整或不正确。经过多次尝试和错误,我找到了解决方案。
这是使用 Delphi 2007 和 VS 2010 编译的。我怀疑它在其他版本中也可以正常工作。
这是德尔福代码。记得在项目中包含版本信息。
library DelphiLibrary;
uses SysUtils;
// Compiled using Delphi 2007.
// NOTE: If your project doesn't have version information included, you may
// receive the error "The "ResolveManifestFiles" task failed unexpectedly"
// when compiling the C# application.
{$R *.res}
// Example function takes an input integer and input string, and returns
// inputInt + 1, and inputString + ' ' + IntToStr(outputInt) as output
// parameters. If successful, the return result is nil (null), otherwise it is
// the exception message string.
// NOTE: I've posted a better version of this below. You should use that instead.
function DelphiFunction(inputInt : integer; inputString : PAnsiChar;
out outputInt : integer; out outputString : PAnsiChar)
: PAnsiChar; stdcall; export;
var s : string;
begin
outputInt := 0;
outputString := nil;
try
outputInt := inputInt + 1;
s := inputString + ' ' + IntToStr(outputInt);
outputString := PAnsiChar(s);
Result := nil;
except
on e : exception do Result := PAnsiChar(e.Message);
end;
end;
// I would have thought having "export" at the end of the function declartion
// (above) would have been enough to export the function, but I couldn't get it
// to work without this line also.
exports DelphiFunction;
begin
end.
这是 C# 代码:
using System;
using System.Runtime.InteropServices;
namespace CsharpApp
{
class Program
{
// I added DelphiLibrary.dll to my project (NOT in References, but
// "Add existing file"). In Properties for the dll, I set "BuildAction"
// to None, and "Copy to Output Directory" to "Copy always".
// Make sure your Delphi dll has version information included.
[DllImport("DelphiLibrary.dll",
CallingConvention = CallingConvention.StdCall,
CharSet = CharSet.Ansi)]
public static extern
string DelphiFunction(int inputInt, string inputString,
out int outputInt, out string outputString);
static void Main(string[] args)
{
int inputInt = 1;
string inputString = "This is a test";
int outputInt;
string outputString;
// NOTE: I've posted a better version of this below. You should use that instead.
Console.WriteLine("inputInt = {0}, intputString = \"{1}\"",
inputInt, inputString);
var errorString = DelphiFunction(inputInt, inputString,
out outputInt, out outputString);
if (errorString != null)
Console.WriteLine("Error = \"{0}\"", errorString);
else
Console.WriteLine("outputInt = {0}, outputString = \"{1}\"",
outputInt, outputString);
Console.Write("Press Enter:");
Console.ReadLine();
}
}
}
我希望这些信息可以帮助其他人不必像我那样拔头发。
【问题讨论】:
-
不是真正的问题,而是 +1 :)。
-
我不熟悉delphi,但知道是否可以将其转换为
COM,它在c#中易于使用,我进行了一些搜索并找到了一些关于delphi和COM的资源这里的关系:delphi.about.com/library/weekly/aa122804a.htm -
您应该将您的问题改写为“从 C# .NET 应用程序中使用 Delphi DLL 的正确方法是什么?”然后用其余的帖子回答自己。见stackoverflow.com/faq(你可以回答你自己的问题)和这里:meta.stackexchange.com/questions/12513/…
-
这里需要非常小心。 Delphi 字符串是引用计数的;
DelphiFunction中s的引用计数将在函数结束时为零,因此s使用的内存将返回给内存分配器,并可能在之后被其他东西使用(和覆盖) DelphiFunction 在 C# 调用者获取内容之前返回。当这种情况发生时,就会发生各种破坏。在多线程情况下(尤其是在多核系统上)可能很快。 -
詹斯 - 感谢您提供信息。我想知道我这样做是否正确。 -丹