EDIT: I've posted a better implementation of this, below. I left this here so the responses would make sense.
I've done numerous searches for the correct method for writing a DLL in Delphi, and being able to call it from C#, passing and returning strings. A lot of the information was incomplete or incorrect. After much trial and error, I found the solution.
This was compiled using Delphi 2007 and VS 2010. I suspect it will work fine in other versions as well.
Here's the Delphi code. Remember to include version information in the project.
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.
Here's the C# code:
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();
}
}
}
I hope this information helps someone else to not have to pull their hair out as much as I did.
COM
its easy to use it in c#, I made a little search and find some resource which is about delphi and COM relation here: delphi.about.com/library/weekly/aa122804a.htm – Saeed Amiris
inDelphiFunction
will be zero at the end of the function, so the memory that is used bys
will be returned to the memory allocator, and potentially be used (and overwritten) by something else after DelphiFunction returns before the C# caller can fetch the content. When that happens, all sorts of havoc will occur. In a multi-threaded situation (especially on multi-core systems) that can be really soon. – Jeroen Wiert Pluimers