Jannik
Jannik

Reputation: 2429

Writing a .NET (C#) dll for a Delphi App

A friend asked me about writing a dll in C# for a delphi app. He wants to communicate with it using this function decleration:

function OpenAddOnFile(const mafCode: PWideChar; const mafFilePath: PWideChar;
                   const mafVersion: PWideChar): Pointer; stdcall;

The problem I have is translating it to C#. PWideChar isnt available etc... I've tried it like that:

public Pointer OpenAddOnFile(
    [MarshalAs(UnmanagedType.LPWStr)]string mafcode,     
    [MarshalAs(UnmanagedType.LPWStr)]string maffilepath,  
    [MarshalAs(UnmanagedType.LPWStr)]string mafversion
)

But its not working for now :)

Further more how can I return a Pointer to my form in C#?

Can someone help me please? Thanks in advance!

Edit:\

He gave me this additional code: I asked him for the function call, he gave me this info:

unit unAddOn;

interface

uses
   Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
   System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
   Vcl.ComCtrls;

function LoadAddOnFile(aPath: String; aVersion: String; var aFilePath: String;
                       var aCode: String): Boolean;

const
    AddOnExt: String = '.maf';

implementation

function LoadAddOnFile(aPath: String; aVersion: String; var aFilePath: String;
                   var aCode: String): Boolean;
type
   TOpenAddOnFile = function(const mafCode: PWideChar; const mafFilePath: PWideChar;
                        const mafVersion: PWideChar): Pointer; stdcall;
   TCloseAddOnFile = procedure(var mafCode: PWideChar; var mafFilePath: PWideChar;
                          var mafQuitPopUp: PWideChar); stdcall;
var
   CloseAddOnFile: TCloseAddOnFile;
   OpenAddOnFile: TOpenAddOnFile;
   AddOnMainForm: TForm;
   AddOnHandle: THandle;
   mafQuitPopUp: PWideChar;
   mafFilePath: PWideChar;
   mafVersion: PWideChar;
   mafCode: PWideChar;
begin
   Result := True;
   mafQuitPopUp := PWideChar(EmptyStr);
   mafFilePath  := PWideChar(aFilePath);
   mafCode      := PWideChar(aCode);
   mafVersion   := PWideChar(aVersion);

   try
   AddOnHandle := LoadLibrary(PWideChar(aPath));
if (AddOnHandle <> 0) then
begin
  @OpenAddOnFile  := GetProcAddress(AddOnHandle, 'OpenAddOnFile');
  @CloseAddOnFile := GetProcAddress(AddOnHandle, 'CloseAddOnFile');

  if (@OpenAddOnFile <> nil) then
  begin
    AddOnMainForm := OpenAddOnFile(mafCode, mafFilePath, mafVersion);
    AddOnMainForm.Position := poScreenCenter;
    AddOnMainForm.ShowModal;
    if (@CloseAddOnFile <> nil) then
    begin
      CloseAddOnFile(mafCode, mafFilePath, mafQuitPopUp);
    end;
    FreeAndNil(AddOnMainForm);
    Application.ProcessMessages;
  end;
end;

if not (mafQuitPopUp = PWideChar(EmptyStr)) then
begin
  ShowMessage(mafQuitPopUp);
end;
aFilePath := String(mafFilePath);
aCode := String(mafCode);
except
Result := False;
end;
end;

end.

Upvotes: 1

Views: 1329

Answers (2)

shunty
shunty

Reputation: 3768

You could, perhaps, implement it slightly differently with a smallish change to the calling routines in Delphi.

If you were to use the UnmanagedExports (availabe as a Nuget package) as mentioned by David you could get the OpenAddonFile call to return an interface rather than a form. The interface could implement ShowModal and Position.
CloseAddonFile could return an appropriate value as normal. Doesn't matter then whether it's a form a console app or anything else so long as you can call ShowModal on it.

I have found the UnmanagedExports to be very good so long as you remember to only return int / void types from the methods and any strings are returned as var / out parameters.

Upvotes: 1

David Heffernan
David Heffernan

Reputation: 613461

What you are attempting is impossible. You cannot implement a Delphi form in C#. The code that you posted treats the pointer returned by the DLL function as a Delphi form. The only thing that can implement a Delphi form is code compiled by Delphi.

What's more, your code is not even valid if the DLL is implemented in Delphi. That's because the TForm class in the host executable is not the same as the TForm class in the DLL. In order to do what you are attempting to do, with a Delphi DLL, you'd need to pass interfaces across the module boundary.

The bottom line is that your current design for this add-on architecture can never work. You need to go right back to the drawing board and start again.

Upvotes: 4

Related Questions