Delphi - Program fordítás a Delphi elindítása nélkül

forráskód letöltése
Ebben a példában egy olyan programot készítünk, amely egy adott könyvtárban található összes Delphi project-et automatikusan lefordítja anélkül, hogy elindítanánk a Delphi-t. A könyvtárak gyorsmenüjét kiegészíti a "Compile all Delphi projects" menüponttal, aminek segítségével akár az Intézőből is könnyedén elindíthatjuk.
Ezen kívül még a DPR fájlok gyorsmenüjét is kiegészíti egy "Compile" menüponttal, aminek kiválasztásával rögtön le is fordíthatjuk az adott project-et. Először is ahhoz, hogy Delphi project-et tudjunk fordítani a Delphi elindítása nélkül, szükségünk lesz a parancssori fordítóra. Ez nem más, mint a dcc32.exe, amely a Delphi könyvtár Bin alkönyvtárában található.

Két gyorsmenüt is létre szeretnénk hozni, ehhez viszont a Registry adatbázisban kell néhány módosítást megtenni. A Registry-t többféleképpen is el tudjuk érni Delphi-ből, mi jelenleg a TRegistry osztályt használtuk erre a célra. A változtatásokat mindjárt el is végezzük a Form1 OnCreate eseményénél.
procedure TForm1.FormCreate(Sender: TObject);
var Reg:TRegistry;
    s:string;
begin
    reg:=TRegistry.Create;
    reg.RootKey:=HKEY_CLASSES_ROOT;
Szükségünk lesz a dcc32.exe elérési útjára, amit szintén a Registry-ből tudhatunk meg. Mivel több Delphi verzió is lehet egyidejűleg telepítve, ezért megnézzük, hogy a DPR fájlokhoz melyik DELPHI.EXE van hozzárendelve. Ennek elérési útját használjuk a dcc32.exe eléréséhez.
    reg.OpenKey('\DelphiProject\Shell\Open\Command', FALSE);
    DelphiDir:=ExtractFilePath(reg.ReadString(''));
Ha megvan a dcc32.exe elérési útvonala, akkor létrehozunk a DelphiProject fájlokhoz egy új gyorsmenüt. Mivel itt azonnal a dcc32.exe-t regisztráljuk, ezért ezzel a továbbiakban semmi gondunk nem lesz, vagyis ezt "kézzel" is megtehettük volna, és akkor is működne a dolog.
    reg.RootKey:=HKEY_CLASSES_ROOT;
    reg.OpenKey('\DelphiProject\Shell\Compile\Command', TRUE);
    reg.WriteString('', 'dcc32.exe %1');
Ezután a könyvtárakhoz is hozzárendelünk egy gyorsmenüt, ami viszont már a saját programunkat fogja indítani.
    reg.RootKey:=HKEY_CLASSES_ROOT;
    reg.OpenKey('\Folder\Shell\Compile all Delphi projects\
       Command', TRUE);
    reg.WriteString('', Application.ExeName+' %L');
Megnézzük, hogy a programunkat paraméterezve indították-e, és ha igen, akkor a paramétert beírjuk az Edit1-be. Ez általában akkor fordul elő, ha a program a gyorsmenüből lett indítva. Ilyenkor paraméterként annak a könyvtárnak az elérési útvonalát kapjuk meg, amin a gyorsmenüt aktivizálták. Ha nem volt paraméter, akkor a Delphi\Bin könyvtárat adjuk meg.
    s:=CmdLine;
    if s[1]='"' then s:=Copy(s, 2, length(s)-3);

    Delete(s, 1, length(Application.ExeName));

    if s='' then s:=DelphiDir;
    Edit1.Text:=s;

A projectek keresése és fordítása a Button1Click eljárásban indul. Ebben beállítjuk az egér kurzort homokórára (nem tudván, hogy mennyi ideig tart a fordítás), és a ScanDir eljárást indítjuk.

A ScanDir eljárás paraméterként egy könyvtárnevet vár. A könyvtárban található fájlok és könyvtárak nevét sorban beolvassa. Ha könyvtárat talált és a CheckBox1 Checked property-je True, akkor rekurzívan meghívja önmagát a beolvasott könyvtárnévvel. Ezzel elérhető, hogy a kiinduló könyvtár összes alkönyvtára is beolvasásra kerüljön. Ha .DPR kiterjesztésű fájlt talál, akkor a CompileDPR eljárást meghívja paraméterként átadva neki a beolvasott fájlnevet. Mire az összes fájlt beolvastuk, addigra az összes project le lesz fordítva!

A CompileDPR végzi a paraméterként megkapott nevű és elérési útvonalú fájl fordítását.
procedure TForm1.CompileDpr;
var ok:boolean;
    si:TStartupInfo;
    pi:TProcessInformation;
    cline:string;
    cdir:string;
begin
A Label2 Caption property-jébe beírjuk az éppen fordítandó fájl nevét.
    Label2.Caption:=FileName;
    Label2.Refresh;
A cline változóban a parancssort állítjuk elő. A dcc32.exe nagyon sok kapcsolóval rendelkezik, amelyekről a dcc32.exe "/?" paraméterrel történő futtatásával szerezhetünk információkat. Mi jelenesetben egyetlen kapcsolót sem használunk.
    cline:=DelphiDir+'dcc32.exe '+ExtractFileName(FileName);
    cdir:=ExtractFilePath(FileName);
Ahhoz, hogy futtatni tudjuk a parancssorunkat, létrehozunk egy új processzt. Erre azért van szükség, mert addig nem kívánjuk folytatni a program futását, amíg a fordítás meg nem történt. Új processzt a CreateProcess függvénnyel hozhatunk létre. Ennek van egy StartupInfo paramétere, amiben megadhatjuk, hogy a processz hogyan jelenjen meg. A wShowWindow változóban SW_HIDE-t adunk meg, hogy az ablak ne jelenjen meg, míg a dwFlags változóban a STARTF_USESHOWWINDOW flag-et állítjuk be, hogy a processz használja is ezt a beállítást.
    si.dwFlags:=STARTF_USESHOWWINDOW;
    si.wShowWindow:=SW_HIDE;
Létrehozzuk a processzt, és ha sikerült, akkor addig várunk, amíg az le nem fut.
    ok:=CreateProcess(nil, PChar(cline), nil, nil, false, 
       NORMAL_PRIORITY_CLASS, nil, PChar(cdir), si, pi);
    if ok then
    begin
        WaitForInputIdle(pi.hProcess, INFINITE);
        WaitForSingleObject(pi.hProcess, INFINITE);
    end;
end;