1

How can i use this dll function in c#? I tried the following but i get error. "External component has thrown an exception."

First time i am doing this PInvoke stuff with C# and Delphi.

function HTTPGET(location:string):string; stdcall;
var
HTTP:TIdHttp;
begin
  HTTP := TidHttp.Create(nil);
  try
    result := HTTP.Get(location);
  finally
  FreeAndNil(HTTP);
  end;
end;


exports
  HTTPGET;

begin
end.


namespace Test
{
    class Program
    {
        [DllImport("project1.dll")]
        public static extern string HTTPGET(string location);

        static void Main(string[] args)
        {
           Console.WriteLine(HTTPGET("http://www.reuters.com/"));
        }
    }
}
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490

4 Answers4

7

You cannot call that function from C#. That's because you cannot use Delphi string for interop. You can use PAnsiChar for strings passed from managed to unmanaged, but in the other direction it's more complex. You'd need to allocate the memory at the caller, or use a shared heap. I prefer the latter approach which is easiest done with the COM BSTR. This is WideString in Delphi.

As has been discussed before, you cannot use WideString as a return value for interop, since Delphi uses a different ABI from MS tools for return values.

The Delphi code needs to look like this:

procedure HTTPGET(URL: PAnsiChar; out result: WideString); stdcall;

On the C# side you write it like this:

[DllImport("project1.dll")] 
public static extern void HTTPGET(
    string URL,
    [MarshalAs(UnmanagedType.BStr)]
    out string result
);     

If you want Unicode for the URL then use PWideChar and CharSet.Unicode.

procedure HTTPGET(URL: PWideChar; out result: WideString); stdcall;
....
[DllImport("project1.dll", CharSet=CharSet.Unicode)] 
public static extern void HTTPGET(
    string URL,
    [MarshalAs(UnmanagedType.BStr)]
    out string result
);     
Community
  • 1
  • 1
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • How would it differ from a function? –  May 19 '13 at 18:02
  • 1
    I added a link to the answer. It's quite complex. – David Heffernan May 19 '13 at 18:04
  • Much easier and does the same thing. Fantastic. –  May 19 '13 at 18:10
  • @DavidHeffernan, could you explain when and where the memory allocated for the widestring is freed? Thanks. – AJ. Jul 19 '13 at 09:56
  • 2
    @AJ. It is allocated in the Delphi code, and deallocated in the C# code. You don't need to worry about it at all because the frameworks do it for you. Since it is a `BSTR` then the memory is from the shared COM heap, which is why you can allocate and deallocate in different modules. – David Heffernan Jul 19 '13 at 09:58
0

Do not use string type: strings require memory management, and C# and Delphi modules obviously use different memory managers (leave alone that C# passes char* and Delphi expects String). Try changing location type to PChar in your DLL, and also change your result type so it's either PChar (the buffer should be allocated explicitly) or something else, but not string.

nullptr
  • 11,008
  • 1
  • 23
  • 18
  • 1
    You've glossed right over the issue of heap deallocation. Use PChar return value, and then what? And on the C# side? You can have C# `string` return value if the native code returns `PChar` allocated with `CoTaskMemAlloc`. But you've really got to cover all bases in detail in a question like this. It's interop. It only works when both sides of the interop divide are aligned. – David Heffernan May 19 '13 at 18:18
  • @DavidHeffernan Is there some guide for more complex interop between Delphi and C# ? Or is Hydra the solution for more complex stuff. –  May 19 '13 at 18:33
  • 1
    @t0xic There's not actually a single really good guide for p/invoke and very little if anything on p/invoke with Delphi. Personally I do interop by writing my own p/invokes. Once you know what you are doing it's not hard. – David Heffernan May 19 '13 at 18:47
  • @t0xic I don't doubt that. I like to do this kind of stuff myself, but I can see that others would be right to choose a different way. – David Heffernan May 22 '13 at 04:00
-1

As i remember, you can't marshall delphi strings with C#... you have to use a workaround with PChar and manage the memory yourself, or use something like the workaround provided in the last answer here:

Using Delphi's stuct arrays and strings in C#

Community
  • 1
  • 1
thalm
  • 2,738
  • 2
  • 35
  • 49
-1

Try Unmanaged Exports for c# by Robert Giesecke

https://sites.google.com/site/robertgiesecke/Home/uploads/unmanagedexports

we are using encrypting engine from c# in Delphi App due compatibility with php and works well (so, the mentioned strings problem do not exists).

our earlier solution (worse) : register c# dll as com component and use it. with above solution output library have to be placed in exe directory and without registration works well :)

Lightning3
  • 375
  • 7
  • 18