tags:

views:

139

answers:

2

I have embedded a form in a DLL and can call the DLL and show the form and return various functions from the DLL back to the main app, however I cannot figure out how to get the DLL to trigger events in the main applications form.

For example in the main app I have a dataset and I want to have a button on the form in the DLL to goto a certain record in the dataset but cannot see how this is done.

Can anybody could point me to an example or give me some pointers on how to to this?

+1  A: 

Because DLL's code being executed in the same address space of main application there are a plenty ways of doing communications.

  1. Define a callback function in the main app and give its address to the DLL.
  2. Define a message handler in the main app and send a message from DLL in response to some event.
  3. etc.
Andrei K.
+7  A: 

If a DLL needs to invoke behavior in the host application, then the host should provide a callback function to the DLL that the DLL stores and calls when appropriate.

Your DLL exports a function that tells it to display the form, right? Add a couple of parameters to that function for the EXE to provide a pointer to a callback function. The callback function should accept at least one parameter, which should be of type Pointer. The caller (the EXE) will use that parameter as a context parameter, some way for it to be reminded why the DLL is calling the EXE's function. Your DLL will store the function pointer and the context pointer, and when it's time for the DLL to tell the EXE something, it will call that function and pass the context value back. The DLL won't do anything with the context value; it's just something to store and pass back to the EXE verbatim.

The DLL's interface will look like this:

type
  TDllCallback = function(Context: Pointer): DWord; stdcall;

function DisplayForm(Parent: HWnd; Callback: TDllCallback; Context: Pointer): DWord; stdcall; external Dll;

The EXE will define a callback function like this:

function CallbackFunction(Context: Pointer): DWord; stdcall;
begin
  TMainForm(Context).DoSomething;
  Result := 0;
end;

It will call the DLL function like this:

procedure TMainForm.DoDllTaskClick(Sender: TObject);
begin
  DisplayForm(Handle, CallbackFunction, Pointer(Self));
end;

Notice how the signature of CallbackFunction matches the TDllcallback type defined earlier. Tey both use the stdcall calling convention, and they're both standalone functions, not methods. Avoid methods since method pointers are particular to Delphi, and you shouldn't require your DLL to be used only by Delphi hosts, if possible.

Rob Kennedy
And avoid code that could contain IS, since IS in the DLL's context might yield other results than in the mainprogram's.
Marco van de Voort
Code that uses the `is` operator is fine, as long as you're using it on objects that came from the same module. It's not just `is` that shouldn't cross module boundaries. Ultimately, each module should be written as though no other module will have any idea what a Delphi data type is — don't share objects of any class. Pretend that everything else in the project is written in C.
Rob Kennedy
An alternative is to use a BPL. This will let your form use the global Application object, too, which helps with some form behaviour.
David M
Reading through the above does this mean I can only add 1 function to the DLL using the callback meothod?
Of course not, @User. You can have as many as you want. You can pass them all in as distinct parameters, or you could pass them in serially, one at a time. You could even make a record structure and pass them all in together. Once you have a record, you're getting closer to using an interface.
Rob Kennedy