-
Dynamicky sestavitelnΘ knihovny (DLL) umo₧≥ujφ modularizovat aplikace a
tak usnad≥ujφ aktualizovßnφ a op∞tovnΘ pou₧φvßnφ jejich funkΦnosti. TakΘ
pomßhajφ redukovat pam∞¥ovΘ nßroky, pokud n∞kolik aplikacφ pou₧φvß ve stejnou
dobu stejnΘ funkce, nebo¥ ka₧dß aplikace zφskß svou vlastnφ kopii dat,
ale k≤d je sdφlen. Ve Windows, DLL jsou moduly, kterΘ obsahujφ funkce a
data. DLL jsou zavedeny za b∞hu volajφcφm modulem. Kdy₧ DLL je zavedena,
je mapovßna do adresovΘho prostoru volajφcφho procesu.
DLL mohou definovat dva typy funkcφ: exportovanΘ a internφ. ExportovanΘ
funkce mohou b²t volßny ostatnφmi moduly. Internφ funkce mohou b²t volßny
pouze uvnit° DLL, ve kterΘ jsou definovßny. Vytvß°enφ a pou₧φvßnφ DLL je
podrobn∞ popsßno v SDK Win32.
DLL Windows mohou b²t pou₧ity v aplikacφch C++ Builderu stejn∞ jako
v libovoln²ch jin²ch aplikacφch C++. Ke statickΘmu zavedenφ DLL p°i zavßd∞nφ
naÜφ aplikace C++ Builderu, sestavφme importnφ knihovnφ soubor pro tuto
DLL do naÜφ aplikace C++ Builderu b∞hem sestavovßnφ. Pro p°idßnφ importnφ
knihovny k aplikaci C++ Builderu, otev°eme vytvß°ecφ soubor (BPR) pro aplikaci
a p°idßme jmΘno importnφ knihovny do seznamu knihovnφch soubor∙ p°i°azen²ch
k prom∞nnΘ ALLLIB. Je-li to nutnΘ, p°idßme cestu k importnφ knihovn∞ k
cestßm uveden²m ve volb∞ -L prom∞nnΘ LFLAGS.
ExportovanΘ funkce z DLL potom budou dostupnΘ pro pou₧itφ naÜφ aplikacφ.
Prototypy funkcφ DLL naÜe aplikace pou₧φvß s modifikßtorem __declspec(dllimport):
extern
"C" __declspec(dllimport) nßvratov²_typ jmΘno_importovanΘ_funkce(parametry);
K dynamickΘmu zavßd∞nφ DLL za b∞hu aplikace C++ Builderu, pou₧ijeme
funkci Windows API LoadLibrary k zavedenφ DLL a potom pou₧φvßme
funkci API GetProcAddress k zφskßnφ ukazatele na funkci, kterou
chceme pou₧φt. Pozor: na zaΦßtek identifikßtor∙ jazyk C p°idßvß
znak podtr₧enφ. DalÜφ informace m∙₧eme nalΘzt v SDK Win32.
Vytvß°enφ DLL v C++ Builderu je stejnΘ jako ve standardnφm C++. ImportovanΘ
funkce v k≤du musφ b²t identifikovßny modifikßtorem __declspec(dllimport)
stejn∞
jako musφ b²t oznaΦeny i v jin²ch p°ekladaΦφch. Nap°. nßsledujφcφ k≤d je
p°φpustn² v C++ Builderu a v ostatnφch p°ekladaΦφch C++:
double dblValue(double);
double halfValue(double);
extern "C" __declspec(dllexport)
double changeValue(double, bool);
double dblValue(double
value)
{
return value
* value;
};
double halfValue(double
value)
{
return value
/ 2.0;
}
double changeValue(double
value, bool whichOp)
{
return whichOp
? dblValue(value) : halfValue(value);
}
Ve v²Üe uvedenΘm k≤du, funkce changeValue je exportovßna a tedy
je dostupnß z volajφcφch aplikacφ. Funkce dblValue a halfValue
jsou internφ a nemohou b²t volßny z vn∞jÜku DLL.
V IDE C++ Builderu, m∙₧eme vytvo°it projekt novΘ DLL volbou File
| New a na strßnce New vybereme ikonu DLL. Je otev°eno editaΦnφ
okno a projektovΘ volby jsou nastaveny na vytvß°enφ DLL (namφsto EXE).
PovÜimn∞te si, ₧e do zdrojovΘho souboru DLL je vlo₧en hlaviΦkov² soubor
VCL.H. Pokud naÜe DLL nebude pou₧φvat komponenty VCL, pak tento °ßdek m∙₧eme
odstranit.
-
Jednou z v²hod DLL je to, ₧e DLL vytvo°enß v jednom v²vojovΘm prost°edφ
m∙₧e b²t nabφdnuta k pou₧φvßnφ aplikacφm vytvo°en²m v jin²ch v²vojov²ch
nßstrojφch. Kdy₧ naÜe DLL obsahuje komponenty VCL pou₧φvanΘ volajφcφ aplikacφ,
pak je nutno poskytnout exportovanΘ rozhranφ, kterΘ pou₧φvß standardnφ
volacφ konvence a nevy₧aduje aby volajφcφ aplikace po₧adovala pro svou
prßci knihovnu VCL. K vytvo°enφ komponent VCL, kterΘ mohou b²t exportovßny
pou₧φvßme b∞hovΘ balφΦky.
Nap°. p°edpoklßdejme, ₧e chceme vytvo°it DLL zobrazujφcφ nßsledujφcφ
jednoduchΘ dialogovΘ okno:
HlaviΦkov² soubor tohoto formulß°e je:
// DLLMAIN.H
//---------------------------------------------------------------
#ifndef dllMainH
#define dllMainH
//---------------------------------------------------------------
#include <vcl\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();
};
// exportovanß funkce
rozhranφ
extern "C" __declspec(dllexport)
bool InvokeYesNoDialog();
//---------------------------------------------------------------
extern TYesNoDialog
*YesNoDialog;
//---------------------------------------------------------------
#endif
Nßsleduje v²pis zdrojovΘho souboru dialogovΘho okna:
// 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;
}
//---------------------------------------------------------------
// exportovanß funkce
rozhranφ, kterß volß VCL
bool InvokeYesNoDialog()
{
bool returnValue;
TYesNoDialog
*YesNoDialog = new TYesNoDialog(NULL);
YesNoDialog->ShowModal();
returnValue
= YesNoDialog->GetReturnValue();
delete YesNoDialog;
return returnValue;
}
K≤d v tomto p°φklad∞ zobrazφ dialogovΘ okno a v soukromΘ slo₧ce returnValue
ulo₧φ, kter²m tlaΦφtkem okno bylo uzav°eno. Ve°ejnß funkce GetReturnValue
vracφ souΦasnou hodnotu returnValue.
K vyvolßnφ dialogu a urΦenφ, kterΘ tlaΦφtko bylo stisknuto, volajφcφ
aplikace volß exportovanou funkci InvokeYesNoDialog. Tato funkce
je deklarovßna v hlaviΦkovΘm souboru jako exportovanß funkce pou₧φvajφcφ
sestavenφ C (k zabrßn∞nφ komolenφ jmen a pou₧φvßnφ standardnφch volacφch
konvencφ C). Funkce je definovßna ve zdrojovΘm souboru. Tφm dosßhneme to,
₧e DLL m∙₧e b²t volßna z libovolnΘ aplikace (nemusφ b²t vytvo°ena v C++
Builderu). FunkΦnost VCL vy₧adovanß DLL je sestavena do samotnΘ DLL a volajφcφ
aplikace o VCL nepot°ebuje nic znßt. Kdy₧ vytvß°φme DLL, kterΘ pou₧φvajφ
VCL, pak vy₧adovanΘ komponenty VCL jsou sestaveny do DLL. To zv∞tÜuje DLL
a je tedy vhodnΘ do jednΘ DLL ulo₧it vφce komponent. Vytvo°te DLL s dialogov²m
oknem popsan²m v tomto zadßnφ.
-
M∙₧eme nastavit volby sestavovacφho programu pro naÜi DLL na strßnce Linker
dialogovΘho
okna Project Options. Na tΘto strßnce je takΘ znaΦkou mo₧no urΦit,
zda bude pro naÜi DLL vytvß°ena importnφ knihovna. Pokud p°eklßdßme z p°φkazovΘho
°ßdku, pak sestavovacφ program vyvolßvßme s volbou -Tpd. Nap°.
ilink32 /c /aa /Tpd
c0d32.obj mydll.obj, mydll.dll, mdll.map,
import32.lib
cw32mt.lib
Pokud importnφ knihovnu nemßme, pak pou₧ijeme takΘ volbu -Gi
k jejφmu vygenerovßnφ.
Importnφ knihovnu lze takΘ vytvo°it programem IMPLIB. Nap°.
implib mydll.lib
mydll.dll
Vφce informacφ o r∙zn²ch volbßch pro sestavovßnφ DLL a jejich pou₧φvßnφ
s r∙zn²mi moduly, kterΘ jsou staticky nebo dynamicky sestavovßny s knihovnou
b∞hu programu nalezneme v nßpov∞d∞.
-
Vytvo°te aplikaci, kterß pou₧ije DLL vytvo°enou v zadßnφ 2. DLL sestavte
staticky.
-
Vytvo°te aplikaci, kterß pou₧ije DLL vytvo°enou v zadßnφ 2. Tentokrßt DLL
zavßd∞jte dynamicky za b∞hu aplikace.
-
Pro podporu VCL, C++ Builder implementuje, p°eklßdß nebo
p°episuje mapovßnφ mnoha datov²ch typ∙ Object Pascalu, konstrukcφ a jazykov²ch
koncepcφ do jazyka C++. Mnoho zajφmav²ch datov²ch typ∙ Object Pascalu je
implementovßno v C++ Builderu pomocφ typedef na p°irozen² typ C++.
Tyto definice nalezneme v sysdefs.h. Je ale vhodn∞jÜφ pou₧φvat p°irozen²
typ C++ namφsto typu Object Pascalu (nap°. je sice mo₧no pou₧φvat datov²
typ Integer, ale je vhodn∞jÜφ pou₧φvat int).
N∞kterΘ datovΘ typy Object Pascalu a jazykovΘ konstrukce,
kterΘ nejsou v C++, jsou implementovßny jako t°φdy nebo struktury. N∞kdy
jsou takΘ pou₧ity Üablony t°φd (nap°. Üablona set pro implementaci
datovΘho typu mno₧ina). Tyto deklarace nalezneme v hlaviΦkov²ch souborech:
dstring.h,
sysdefs.h,
variant.hpp a wstring.h.
Parametry volanΘ odkazem a netypovΘ parametry Object
Pascalu nejsou p°irozenΘ v C++. C++ i Object Pascal majφ koncepci p°edßvßnφ
parametru odkazem. Jsou to modifikovatelnΘ parametry. Syntaxe v Object
Pascalu je:
procedure
myFunc(var x : integer);
V C++ lze p°edßvat tento typ parametr∙ odkazem:
void
myFunc(int& x);
Parametry p°edßvanΘ odkazem a ukazatelem v C++ mohou
b²t pou₧ity k modifikaci objektu. Odkaz C++ neodpovφdß p°esn∞ parametru
p°edßvanΘmu odkazem Object Pascalu, ale oboje umo₧≥uje m∞nit hodnotu odkazu.
Object Pascal mß takΘ parametry nespecifikovanΘho typu.
Tyto parametry jsou p°edßny funkci s nedefinovan²m typem. Funkce musφ p°etypovat
parametr na znßm² typ p°ed pou₧itφm parametru. C++ Builder interpretuje
netypovΘ parametry jako ukazatel na void. Funkce musφ p°etypovat
ukazatel na void na ukazatel na po₧adovan² typ. Nap°.
int
myfunc(void* MyName)
{
//
P°etypovßnφ ukazatele na po₧adovan² typ; potom jeho dereference
int*
pi = static_cast<int*>(MyName);
return
1 + *pi;
}
-
Object Pascal mß konstrukci "otev°enΘ pole", kterß umo₧≥uje
p°edßvat funkcφm pole nespecifikovanΘ velikosti. V C++ toto m∙₧e b²t vy°eÜeno
p°edßnφm ukazatele na prvnφ prvek pole a hodnotou poslednφho indexu pole
(poΦet prvk∙ pole mφnus jedna). Nap°. funkce Mean v math.hpp
mß v Object Pascalu deklaraci:
function
Mean(Data: array of Double): Extended;
Deklarace C++ je:
Extended
__fastcall Mean(const double * Data, const int Data_Size);
Nßsledujφcφ k≤d ilustruje volßnφ tΘto funkce v C++.
double
d[] = { 3.1, 4.4, 5.6 };
//
explicitnφ specifikace poslednφho indexu
long
double x = Mean(d, 2);
//
lepÜφ: pou₧itφ sizeof pro v²poΦet poΦtu prvk∙ pole
long
double y = Mean(d, (sizeof(d) / sizeof(d[0])) - 1);
//
pou₧itφ makra z sysdefs.h
long
double z = Mean(d, ARRAYSIZE(d) - 1);
Kdy₧ pou₧φvßme sizeof, makro ARRAYSIZE nebo makro
EXISTINGARRAY k v²poΦtu poΦtu prvk∙ v poli, pak nesmφme pou₧φt ukazatel
na prvnφ prvek pole, ale je nutno p°edat jmΘno pole:
double
d[] = { 3.1, 4.4, 5.6 };
ARRAYSIZE(d)
== 3;
double
*pd = d;
ARRAYSIZE(pd)
== 0; // Chyba!
sizeof pole neodpovφdß sizeof ukazatele.
Nap°. p°i deklaraci:
double
d[3];
double
*p = d;
zφskßme velikost pole v²razem:
sizeof(d)/sizeof
d[0]
ale pou₧itφ nßsledujφcφho v²razu je chybnΘ
sizeof(p)/sizeof(p[0])
Object Pascal umo₧≥uje funkcφm p°edßvat nepojmenovanß
doΦasnß otev°enß pole. V C++ pro toto neexistuje syntaxe (je mo₧no to vy°eÜit
n∞kolika p°φkazy a pojmenovßnφm pole). Zßpis v Object Pascalu
Result
:= Mean([3.1, 4.4, 5.6]);
lze v C++ zapsat jako
double
d[] = { 3.1, 4.4, 5.6 };
return
Mean(d, ARRAYSIZE(d) - 1);
K omezenφ rozsahu pojmenovanΘho doΦasnΘho pole je mo₧no
pou₧φt zßpis:
long
double x;
{
double
d[] = { 4.4, 333.1, 0.0 };
x
= Mean(d, ARRAYSIZE(d) - 1);
}
Object Pascal podporuje jazykovou koncepci nazvanou array
of const. Tento typ parametru je stejn² jako p°edßvßnφ otev°enΘho pole
TVarRec
hodnotou.
Nap°. segment k≤du Object Pascalu:
function
Format(const Format: string; Args: array of const): string;
V C++ se jednß o nßsledujφcφ prototyp:
AnsiString
__fastcall Format(const AnsiString Format;
TVarRec const *Args, const int Args_Size);
Funkce je volßna jako libovolnß jinß funkce, kterß p°ebφrß
otev°enΘ pole:
void
show_error(int error_code, AnsiString const &error_msg)
{
TVarRec v[] = { error_code, error_msg };
ShowMessage(Format("%d: %s", v, ARRAYSIZE(v) - 1));
}
Makro OPENARRAY definovanΘ v sysdefs.h m∙₧e b²t
pou₧ito jako alternativa k pou₧itφ pojmenovanΘ prom∞nnΘ pro p°edßnφ doΦasnΘho
otev°enΘho pole funkci, kterß p°ebφrß otev°enΘ pole hodnotou. Pou₧itφ makra
vypadß takto:
OPENARRAY(T,
(value1, value2, value3)) // a₧ 19 hodnot
kde T je typ vytvß°enΘho otev°enΘho pole. Nap°.
void
show_error(int error_code, AnsiString const &error_msg)
{
ShowMessage(Format("%d:
%s",OPENARRAY(TVarRec,error_code,error_msg)));
}
Makro OPENARRAY m∙₧e b²t pou₧ito pro p°edßnφ a₧ 19 hodnot.
Pro v∞tÜφ pole musφ b²t definovßna explicitnφ prom∞nnß.
Makro EXISTINGARRAY definovanΘ v sysdefs.h m∙₧e
b²t pou₧ito k p°edßnφ existujφcφho pole, kdy₧ je oΦekßvßno otev°enΘ pole.
Pou₧itφ makra vypadß takto:
long
double Mean(const double *Data, const int Data_Size);
double
d[] = { 3.1, 3.14159, 2.17128 };
Mean(EXISTINGARRAY
(d));
-
N∞kterΘ typy jsou v Object Pascalu a v C++ definovßny r∙zn∞.
Jednß se o logickΘ datovΘ typy a typ char. S odchylkami v t∞chto
typech se nynφ seznßmφme.
True pro datovΘ typy ByteBool, WordBool
a LongBool Object Pascalu je reprezentovßno hodnotou -1 a False
hodnotou 0. Ostatnφ logickΘ datovΘ typy majφ pro True hodnotu 1
(False je v₧dy 0). C++ p°evßdφ tyto typy sprßvn∞, ale problΘmy mohou
nastat p°i pou₧φvßnφ funkcφ Win API.
Typ char je v C++ znamΘnkov² typ, zatφmco v Object
Pascalu se jednß o bezznamΘnkov² typ. Tato odchylka m∙₧e n∞kdy zp∙sobit
problΘmy p°i sdφlenφ k≤du.
-
Jestli₧e mßme k≤d v jednotce Pascalu, kter² pou₧φvß zdroje
°et∞zc∙, pak p°ekladaΦ Pascalu (DCC32) generuje globßlnφ prom∞nnou a odpovφdajφcφ
makro preprocesoru pro ka₧d² zdroj °et∞zce p°i generovßnφ hlaviΦkovΘho
souboru. Makra jsou pou₧φvßny k automatickΘmu zavßd∞nφ zdroj∙ °et∞zc∙ a
jsou urΦena pro pou₧itφ v naÜem C++ k≤du na mφstech, kde se odkazujeme
na zdroje °et∞zc∙. Nap°. sekce resourcestring v k≤du Object Pascalu
m∙₧e obsahovat:
unit
borrowed;
interfaceS
resourcestring
Warning
= 'Be careful when accessing string resources.';
implementation
begin
end.
Odpovφdajφcφ k≤d generovan² p°ekladaΦem Pascalu pro C++
Builder bude:
extern
System::Resource ResourceString _Warning;
#define
Borrowed_Warning System::LoadResourceString(&Borrowed::_Warning)
To umo₧≥uje pou₧φt exportovanΘ zdroje °et∞zc∙ Object
Pascalu bez nutnosti explicitnφho volßnφ LoadResourceString.
-
P°ekladaΦ Pascalu nynφ akceptuje implicitnφ parametry pro
kompatibilitu s rozliÜovßnφm konstruktor∙ C++. Na rozdφl od C++, konstruktory
Object Pascalu majφ stejn² poΦet a typy parametr∙. K rozliÜenφ konstruktor∙
v Object Pascalu jsou pou₧ity prßzdnΘ parametry (p°i generovßnφ hlaviΦkov²ch
soubor∙ C++). Nap°. pro t°φdu TInCompatible, jsou v Object Pascalu
konstruktory:
constructor
Create(AOwner: TComponent);
constructor
CreateNew(AOwner: TComponent);
kterΘ jsou nesprßvn∞ (nelze je rozliÜit) p°elo₧eny na
tyto konstruktory v C++:
__fastcall
TInCompatible(Classes::TComponent* Owner); // Create
__fastcall
TInCompatible(Classes::TComponent* Owner); // CreateNew
P°i pou₧itφ implicitnφch parametr∙ v Object Pascalu lze
nap°. vytvo°it konstruktory:
constructor
Create(AOwner: TComponent);
constructor
CreateNew(AOwner: TComponent; Dummy: Integer = 0);
kterΘ je mo₧no ji₧ sprßvn∞ p°elo₧it na:
__fastcall
TCompatible(Classes::TComponent* Owner); // Create
__fastcall
TCompatible(Classes::TComponent* Owner, int Dummy); // CreateNew
-
Object Pascal mß jazykovΘ konstrukce pracujφcφ s RTTI (identifikace
typu za b∞hu). N∞co obdobnΘho je i v C++. Nap°. konstrukce Object Pascalu
if
Sender is TButton...
je mapovßna v C++ na
if
(dynamic_cast <TButton*> (Sender))...
Obdob∞
b :=
Sender as TButton;
je mapovßno na
TButton&
ref_b = dynamic_cast <TButton&> (*Sender);
DalÜφ metody t²kajφcφ se RTTI jsou zaobaleny v TObject,
nap°. metody ClassNameIs, ClassName, ClassParent apod.
-
Star² 6-ti slabikov² formßt pohyblivΘ °ßdovΘ Φßrky Object
Pascalu se nynφ naz²vß Real48. V C++ nenφ ekvivalent pro tento typ.
Nelze tedy pou₧φt k≤d Object Pascalu s tφmto k≤dem v k≤du C++.
V Object Pascalu funkce mohou vracet pole. Nap°. syntaxe
pro funkci
GetLine vracejφcφ 80 znak∙ je:
type
Line_Data = array[0..79] of char;
function
GetLine: Line_Data;
V C++ funkce nemohou vracet pole. VCL nemß ₧ßdnou vlastnost,
kterß je polem, i kdy₧ to Object Pascel umo₧≥uje. Proto₧e vlastnosti mohou
pou₧φvat Φtecφ metody, kterΘ vracejφ hodnoty typu vlastnosti, nenφ v C++
Builderu vlastnost typu pole.