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.