One of the strengths of DLLs is that a DLL created with one development tool can often be used by application written using a different development tool. When your DLL contains VCL components (such as forms) that are to be used by the calling application, you need to provide exported interface routines that use standard calling conventions, avoid C++ name mangling, and do not require the calling application to support the VCL libraries in order to work. To create VCL components that can be exported, use runtime packages.
For example, suppose you want to create a DLL to display the following simple dialog box:
The code for the dialog box DLL is as follows:
// DLLMAIN.H //--------------------------------------------------------------------- #ifndef dllMainH #define dllMainH //--------------------------------------------------------------------- #include <Classes.hpp> #include <vcl\Controls.hpp> #include <vcl\StdCtrls.hpp> #include <vcl\Forms.hpp> //--------------------------------------------------------------------- class TYesNoDialog : public TForm { __published: // IDE-managed Components TLabel *LabelText; TButton *YesButton; TButton *NoButton; void __fastcall YesButtonClick(TObject *Sender); void __fastcall NoButtonClick(TObject *Sender); private: // User declarations bool returnValue; public: // User declarations virtual __fastcall TYesNoDialog(TComponent *Owner); bool __fastcall GetReturnValue(); }; // exported interface function extern "C" __declspec(dllexport) bool InvokeYesNoDialog(); //--------------------------------------------------------------------- extern TYesNoDialog *YesNoDialog; //--------------------------------------------------------------------- #endif // DLLMAIN.CPP //--------------------------------------------------------------------- #include <vcl\vcl.h> #pragma hdrstop #include "dllMain.h" //--------------------------------------------------------------------- #pragma resource "*.dfm" TYesNoDialog *YesNoDialog; //--------------------------------------------------------------------- __fastcall TYesNoDialog::TYesNoDialog(TComponent *Owner) : TForm(Owner) { returnValue = false; } //--------------------------------------------------------------------- void __fastcall TYesNoDialog::YesButtonClick(TObject *Sender) { returnValue = true; Close(); } //--------------------------------------------------------------------- void __fastcall TYesNoDialog::NoButtonClick(TObject *Sender) { returnValue = false; Close(); } //--------------------------------------------------------------------- bool __fastcall TYesNoDialog::GetReturnValue() { return returnValue; } //--------------------------------------------------------------------- // exported standard C++ interface function that calls into VCL bool InvokeYesNoDialog() { bool returnValue; TYesNoDialog *YesNoDialog = new TYesNoDialog(NULL); YesNoDialog->ShowModal(); returnValue = YesNoDialog->GetReturnValue(); delete YesNoDialog; return returnValue; } //---------------------------------------------------------------------
The code in this example displays the dialog and stores the value true in the private data member returnValue if the "Yes" button is pressed. Otherwise, returnValue is false. The public GetReturnValue() function retrieves the current value of returnValue.
To invoke the dialog and determine which button was pressed, the calling application calls the exported function InvokeYesNoDialog(). This function is declared in DLLMAIN.H as an exported function using C linkage (to avoid C++ name mangling) and the standard C calling convention. The function is defined in DLLMAIN.CPP.
By using a standard C function as the interface into the DLL, any calling application, whether or not it was created with RAD Studio, can use the DLL. The VCL functionality required to support the dialog is linked into the DLL itself, and the calling application does not need to know anything about it.
Copyright(C) 2009 Embarcadero Technologies, Inc. All Rights Reserved.
|
What do you think about this topic? Send feedback!
|