Now that you know how to export a simple function from a DLL and use it in an application, let's look into how to export an entire class.
By modifying the SimpleDll project slightly, we'll use a class to provide equivalent functionality to external applications. This example can be found in the SimpleClassDLL folder within the simple.bpr project on the accompanying CD-ROM. The code declarations associated to the header file for our new simple.dll is provided in Listing 16.9.
#ifndef __SIMPLE_H #define __SIMPLE_H enum Tlast_set { meters=0, feet }; __declspec(dllexport) class TDistance { private: double FVersion; double FMeters; double FFeet; void __fastcall SetMeters(double value); void __fastcall SetFeet(double value); double __fastcall feet_to_meters(); double __fastcall meters_to_feet(); Tlast_set last_set; public : __fastcall TDistance(); __fastcall ~TDistance(); double GetLibVersion(); __property double Version = {read = FVersion}; __property double Meters = {read = feet_to_meters, write = SetMeters}; __property double Feet = {read = meters_to_feet, write = SetFeet}; }; #endif // __SIMPLE_H
Notice that we're using the same export technique used to export the functions earlier, except we're not using the extern C clause. Also notice how our class within our DLL looks much like a class used in a standard executable.
The code to our source file, which now has a .cpp extension, that is associated to this class is provided in Listing 16.10.
__fastcall TDistance::TDistance() { FVersion = 1.1; FFeet = 0.0; FMeters = 0.0; } // - __fastcall TDistance::~TDistance() { } // - double TDistance::GetLibVersion() //current library version of the DLL. { return FVersion; } // - void __fastcall TDistance::SetMeters(double value) { FMeters = value; last_set = meters; } // - void __fastcall TDistance::SetFeet(double value) { FFeet = value; last_set = feet; } // - double __fastcall TDistance::feet_to_meters() { if (last_set == meters) return FMeters; else return (FFeet * 0.3048); } // - double __fastcall TDistance::meters_to_feet() { if (last_set == feet) return FFeet; else return (FMeters * 3.2808); }
Note that although it's not provided in the listing, we still use the same DLL Entry Point function as the previous example.
This is all we need to save and build the DLL. Let's now test it out with a new application that statically loads the DLL. The header file for this application is provided in Listing 16.11 and can be found under the SimpleClass folder and AppStatic.bpr project on the accompanying CD-ROM.
#ifndef AppStaticFormH #define AppStaticFormH // - #include <Classes.hpp> #include <Controls.hpp> #include <StdCtrls.hpp> #include <Forms.hpp> #include "simple.h" // - class TForm1 : public TForm { __published: // IDE-managed Components TButton *ButtonGetVersion; TEdit *EditVersion; TButton *ButtonGetVersion2; void __fastcall ButtonGetVersionClick(TObject *Sender); void __fastcall ButtonGetVersion2Click(TObject *Sender); private: // User declarations TDistance *distance; public: // User declarations __fastcall TForm1(TComponent* Owner); }; // - extern PACKAGE TForm1 *Form1; // - #endif
Because our header file now has a property that is defined by the class contained within the DLL, we need to be sure to include the DLL header file inside the application header file.
#include "simple.h"
The property we declare can be found in the private section of our form's class.
TDistance *distance;
The application source file is provided in Listing 16.12.
#include <vcl.h> #pragma hdrstop #include "AppStaticForm.h" // - #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; // - __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { distance = new TDistance(); } // - void __fastcall TForm1::ButtonGetVersionClick(TObject *Sender) { EditVersion->Text = AnsiString(distance->GetLibVersion()); } // - void __fastcall TForm1::ButtonGetVersion2Click(TObject *Sender) { EditVersion->Text = AnsiString(distance->Version); } // - void __fastcall TForm1::EditMetersChange(TObject *Sender) { double meters = EditMeters->Text.ToDouble(); distance->Meters = meters; } // - void __fastcall TForm1::EditFeetChange(TObject *Sender) { double feet = EditFeet->Text.ToDouble(); distance->Feet = feet; } // - void __fastcall TForm1::ButtonConvertToMetersClick(TObject *Sender) { EditMeters->Text = AnsiString(distance->Meters); } // - void __fastcall TForm1::ButtonConvertToFeetClick(TObject *Sender) { EditFeet->Text = AnsiString(distance->Feet); }
In this example, the form constructor class initializes the simple property to the TDistance class declared within the DLL header file. This class provides two mechanisms to retrieve the version number: the function GetLibVersion() and the class property Version . To retrieve the distance in meters or feet, we simply examine the Meters or Feet property within the TDistance class. The class will perform the appropriate conversion if required. Within the application, we use button event-handlers to demonstrate the capability to access the class members (function and properties), as illustrated in Figure 16.10.
The example illustrated in Figure 16.10 demonstrates how to use properties and methods contained within a DLL class. You may notice the coding style is very similar to how we would use a VCL class contained within a VCL Package. In fact, Packages used by C++Builder and Delphi are actually DLLs; there are just a few subtle differences.
Top |