Blorgbeard
Blorgbeard

Reputation: 103525

How should I call this native dll function from C#?

Here's the native (Delphi 7) function:

function Foo(const PAnsiChar input) : PAnsiChar; stdcall; export;
var
  s : string;
begin
    s := SomeInternalMethod(input);
    Result := PAnsiChar(s);
end;

I need to call this from C#, but the name of the dll is not known at compile time - so I must use LoadLibrary to get to it.

This is what my C# code looks like so far:

[DllImport("kernel32.dll")]
public extern static IntPtr LoadLibrary(String lpFileName);

[DllImport("kernel32.dll")]
public extern static IntPtr GetProcAddress(IntPtr handle, string funcName);

[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private delegate string FooFunction(string input);

...

IntPtr dllHandle = LoadLibrary(dllName);
IntPtr fooProcAddr = GetProcAddress(dllHandle, "Foo");

FooFunction foo = (FooFunction)Marshal.GetDelegateForFunctionPointer(
    fooProcAddr, typeof(FooFuncion)
);

string output = foo(myInputString);

Now, this actually works - at least, the delphi code receives the string correctly, and the C# code receives the output string.

However, I've noticed some weirdness when debugging the delphi code when it's called from the C# code - the debugger skips lines when it shouldn't..

And I'm concerned that I'm leaking memory - is anyone cleaning up those PChars?

Can anyone give me some feedback / advice on how this should be done?

Upvotes: 1

Views: 1208

Answers (2)

mjn
mjn

Reputation: 36664

For memory leak detection you can use the open source FastMM4 memory manager for Delphi.

"FastMM is a lightning fast replacement memory manager for Embarcadero Delphi Win32 applications that scales well in multi-threaded applications, is not prone to memory fragmentation, and supports shared memory without the use of external .DLL files."

It is great for speed, leak checking and memory sharing between dll's.

Also very useful is the FastMM4 Options Interface which helps to configure FastMM4.

Upvotes: 2

mghie
mghie

Reputation: 32334

The only reasonable thing that you can do is trash this function and rewrite it. There is no way this is ever going to work. s is a local string variable of the Foo() function, so the memory the string occupies will be freed when you leave Foo(). The pointer you return points to an invalid memory location, which by chance still contains the string data. If you use a memory manager that clears the memory when pointers to it are freed it won't even contain the data any more. If memory is reused it will contain something else, if the block containing that chunk of memory is released you will get an AV.

There are more questions here on StackOverflow how to return character sequence data from a DLL. Either use a string type that is compatible with the way the Windows API does business, a COM string, or pass a preallocated buffer to your function and fill that with data. In the latter case you can use the same way of using your function like with every similar API function.

Upvotes: 3

Related Questions