Export functions and methods from DLL (Views: 30)
Problem/Question/Abstract: Some time ago I have created a program using Delphi3. Now I want to adapt it to Delphi7. The problem is that creating the program I have used component (TComponent descendent) without source files and I can not install it into Delphi7. Actually I use only one function and one method (event) which returns the progress. I thought maybe I could add that component into DLL using D3 and use this DLL with D7. The function of the component exports successfully from DLL but how to export the Method (Event) of it? Answer: Well, if there is no D7 version of this component a DLL build with D3 is indeed the best solution to your problem. It would have helped if you had posted the declarations of the function you need to call and the event you want to handle, though. Without that at hand i can only give you some general guidance. What you need to do is to build a set of exported functions for the DLL that gives you access to the components functionality. Since DLL and host EXE are build with different Delphi versions they cannot safely share a memory manager via the ShareMem unit, so you cannot pass data types like AnsiString to the DLL functions or receive such parameters in the event handler. You have to write the DLL interface like a set of Windows API methods, using only types that do not require a shared memory manager. Since the original component may not fit this requirements you need a layer of insulation between the DLLs exported functions and the component, best implemented as a class since you will need an object method to handle the components event anyway. There is also the question of how to manage the lifetime of the DLL component.You can create it easily the first time the DLLs exported function is called to get the component do some work. But where to destroy it again? The usage pattern your post implies is not synchronous, the component seems to be doing something in a secondary thread after its mystery method has been called, delivering progress events while at work. The best option seems to be to provide another exported function the host EXE can call to get the DLL to destroy the component when it is no longer needed. OK, let's try to code a DLL interface as a wrapper for this hypothetical component: type TProgressEvent = procedure(PercentDone: Integer) of object; TMysteryComponent = class(TComponent) {....} public function ProcessData(const Data: string): Boolean; published property OnProgress: TProgressEvent read FProgressEvent write FProgressEvent; end; The import unit for the DLL used in your D7 program would then look like this: unit MysteryComponentWrapper; interface type TWrapperProgressEvent = procedure(PercentDone: Integer) of object; function WrapperProcessData(Data: Pchar; ProgressCallback: TWrapperProgressEvent): Boolean; function DestroyWrapper: Boolean; implementation function WrapperProcessData(Data: Pchar; ProgressCallback: TWrapperProgressEvent): Boolean; external 'MystComp.DLL'; function DestroyWrapper: Boolean; external 'MystComp.DLL'; end. The DLL project file would look like this: library MystComp; uses WrapperU; exports WrapperProcessData, DestroyWrapper; begin end. The meat is in the WrapperU unit: unit WrapperU; interface type TWrapperProgressEvent = procedure(PercentDone: Integer) of object; function WrapperProcessData(Data: Pchar; ProgressCallback: TWrapperProgressEvent): Boolean; function DestroyWrapper: Boolean; implementation uses Sysutils, MysteryComponentU; type TWrapper = class private FProgressEvent: TWrapperProgressEvent; FMysteryComponent: TMysteryComponent; procedure ProgressHandler(PercentDone: Integer); public constructor Create; destructor Destroy; override; function ProcessData(Data: Pchar; ProgressCallback: TWrapperProgressEvent): Boolean; end; var Wrapper: TWrapper; //starts out as Nil function WrapperProcessData(Data: Pchar; ProgressCallback: TWrapperProgressEvent): Boolean; begin try if not Assigned(Wrapper) then Wrapper := TWrapper.Create; Result := Wrapper.ProcessData(Data, ProgressCallback); except Result := false; end; end; function DestroyWrapper: Boolean; begin Wrapper.Free; Wrapper := nil; end; procedure TWrapper.ProgressHandler(PercentDone: Integer); begin if Assigned(FProgressEvent) then FProgressEvent(PercentDone); end. constructor TWrapper.Create; begin inherited; FMysteryComponent := TMysteryComponent.Create(nil); FMysteryComponent.OnProgress := ProgressHandler; end; destructor TWrapper.Destroy; begin FMysteryComponent.Free; inherited; end; function TWrapper.ProcessData(Data: Pchar; ProgressCallback: TWrapperProgressEvent): Boolean; begin FProgressEvent := ProgressCallback; Result := FMysteryComponent.ProcessData(Data); end; end. |