导航

Inno Setup设置NT服务

Posted on 2015-04-09 15:53  eastson  阅读(457)  评论(0编辑  收藏  举报

原文地址:http://stackoverflow.com/questions/16922272/unknown-identifier-and-wpselectdir

// Variables Globales
var
    TimeZone: String;
    type
        SERVICE_STATUS = record
            dwServiceType               : cardinal;
            dwCurrentState              : cardinal;
            dwControlsAccepted          : cardinal;
            dwWin32ExitCode             : cardinal;
            dwServiceSpecificExitCode   : cardinal;
            dwCheckPoint                : cardinal;
            dwWaitHint                  : cardinal;
    end;
    HANDLE = cardinal;

const
    SERVICE_QUERY_CONFIG        = $1;
    SERVICE_CHANGE_CONFIG       = $2;
    SERVICE_QUERY_STATUS        = $4;
    SERVICE_START               = $10;
    SERVICE_STOP                = $20;
    SERVICE_ALL_ACCESS          = $f01ff;
    SC_MANAGER_ALL_ACCESS       = $f003f;
    SERVICE_WIN32_OWN_PROCESS   = $10;
    SERVICE_WIN32_SHARE_PROCESS = $20;
    SERVICE_WIN32               = $30;
    SERVICE_INTERACTIVE_PROCESS = $100;
    SERVICE_BOOT_START          = $0;
    SERVICE_SYSTEM_START        = $1;
    SERVICE_AUTO_START          = $2;
    SERVICE_DEMAND_START        = $3;
    SERVICE_DISABLED            = $4;
    SERVICE_DELETE              = $10000;
    SERVICE_CONTROL_STOP        = $1;
    SERVICE_CONTROL_PAUSE       = $2;
    SERVICE_CONTROL_CONTINUE    = $3;
    SERVICE_CONTROL_INTERROGATE = $4;
    SERVICE_STOPPED             = $1;
    SERVICE_START_PENDING       = $2;
    SERVICE_STOP_PENDING        = $3;
    SERVICE_RUNNING             = $4;
    SERVICE_CONTINUE_PENDING    = $5;
    SERVICE_PAUSE_PENDING       = $6;
    SERVICE_PAUSED              = $7;

// #######################################################################################
// nt based service utilities
// #######################################################################################

function OpenSCManager(lpMachineName, lpDatabaseName: string; dwDesiredAccess :cardinal): HANDLE;
external 'OpenSCManagerA@advapi32.dll stdcall';

function OpenService(hSCManager :HANDLE;lpServiceName: string; dwDesiredAccess :cardinal): HANDLE;
external 'OpenServiceA@advapi32.dll stdcall';

function CloseServiceHandle(hSCObject :HANDLE): boolean;
external 'CloseServiceHandle@advapi32.dll stdcall';

function CreateService(hSCManager :HANDLE;lpServiceName, lpDisplayName: string;dwDesiredAccess,dwServiceType,dwStartType,dwErrorControl: cardinal;lpBinaryPathName,lpLoadOrderGroup: String; lpdwTagId : cardinal;lpDependencies,lpServiceStartName,lpPassword :string): cardinal;
external 'CreateServiceA@advapi32.dll stdcall';

function DeleteService(hService :HANDLE): boolean;
external 'DeleteService@advapi32.dll stdcall';

function StartNTService(hService :HANDLE;dwNumServiceArgs : cardinal;lpServiceArgVectors : cardinal) : boolean;
external 'StartServiceA@advapi32.dll stdcall';

function ControlService(hService :HANDLE; dwControl :cardinal;var ServiceStatus :SERVICE_STATUS) : boolean;
external 'ControlService@advapi32.dll stdcall';

function QueryServiceStatus(hService :HANDLE;var ServiceStatus :SERVICE_STATUS) : boolean;
external 'QueryServiceStatus@advapi32.dll stdcall';

function QueryServiceStatusEx(hService :HANDLE;ServiceStatus :SERVICE_STATUS) : boolean;
external 'QueryServiceStatus@advapi32.dll stdcall';

function OpenServiceManager() : HANDLE;
begin
    if UsingWinNT() = true then
    begin
        Result := OpenSCManager('','ServicesActive',SC_MANAGER_ALL_ACCESS);
        if Result = 0 then
            MsgBox('the servicemanager is not available', mbError, MB_OK)
    end
    else
    begin
        MsgBox('only nt based systems support services', mbError, MB_OK)
        Result := 0;
    end
end;

function IsServiceInstalled(ServiceName: string) : boolean;
var
    hSCM    : HANDLE;
    hService: HANDLE;
begin
    hSCM := OpenServiceManager();
    Result := false;
    if hSCM <> 0 then begin
        hService := OpenService(hSCM,ServiceName,SERVICE_QUERY_CONFIG);
        if hService <> 0 then begin
            Result := true;
            CloseServiceHandle(hService)
        end;
        CloseServiceHandle(hSCM)
    end
end;

function InstallService(FileName, ServiceName, DisplayName, Description : string;ServiceType,StartType :cardinal) : boolean;
var
    hSCM    : HANDLE;
    hService: HANDLE;
begin
    hSCM := OpenServiceManager();
    Result := false;
    if hSCM <> 0 then begin
        hService := CreateService(hSCM,ServiceName,DisplayName,SERVICE_ALL_ACCESS,ServiceType,StartType,0,FileName,'',0,'','','');
        if hService <> 0 then begin
            Result := true;
            // Win2K & WinXP supports aditional description text for services
            if Description<> '' then
                RegWriteStringValue(HKLM,'System\CurrentControlSet\Services' + ServiceName,'Description',Description);
            CloseServiceHandle(hService)
        end;
        CloseServiceHandle(hSCM)
    end
end;

function RemoveService(ServiceName: string) : boolean;
var
    hSCM    : HANDLE;
    hService: HANDLE;
begin
    hSCM := OpenServiceManager();
    Result := false;
    if hSCM <> 0 then begin
        hService := OpenService(hSCM,ServiceName,SERVICE_DELETE);
        if hService <> 0 then begin
            Result := DeleteService(hService);
            CloseServiceHandle(hService)
        end;
        CloseServiceHandle(hSCM)
    end
end;

function StartService(ServiceName: string) : boolean;
var
    hSCM    : HANDLE;
    hService: HANDLE;
begin
    hSCM := OpenServiceManager();
    Result := false;
    if hSCM <> 0 then begin
        hService := OpenService(hSCM,ServiceName,SERVICE_START);
        if hService <> 0 then begin
            Result := StartNTService(hService,0,0);
            CloseServiceHandle(hService)
        end;
        CloseServiceHandle(hSCM)
    end;
end;

function StopService(ServiceName: string) : boolean;
var
    hSCM    : HANDLE;
    hService: HANDLE;
    Status  : SERVICE_STATUS;
begin
    hSCM := OpenServiceManager();
    Result := false;
    if hSCM <> 0 then begin
        hService := OpenService(hSCM,ServiceName,SERVICE_STOP);
        if hService <> 0 then begin
            Result := ControlService(hService,SERVICE_CONTROL_STOP,Status);
            CloseServiceHandle(hService)
        end;
        CloseServiceHandle(hSCM)
    end;
end;

function IsServiceRunning(ServiceName: string) : boolean;
var
    hSCM    : HANDLE;
    hService: HANDLE;
    Status  : SERVICE_STATUS;
begin
    hSCM := OpenServiceManager();
    Result := false;
    if hSCM <> 0 then begin
        hService := OpenService(hSCM,ServiceName,SERVICE_QUERY_STATUS);
        if hService <> 0 then begin
            if QueryServiceStatus(hService,Status) then begin
                Result :=(Status.dwCurrentState = SERVICE_RUNNING)
            end;
            CloseServiceHandle(hService)
            end;
        CloseServiceHandle(hSCM)
    end
end;

// #######################################################################################
// create an entry in the services file
// #######################################################################################
function SetupService(service, port, comment: string) : boolean;
var
    filename    : string;
    s           : string;
    lines       : TArrayOfString;
    n           : longint;
    i           : longint;
    errcode     : integer;
    servnamlen  : integer;
    error       : boolean;
begin
    if UsingWinNT() = true then
        filename := ExpandConstant('{sys}\drivers\etc\services')
    else
        filename := ExpandConstant('{win}\services');

    if LoadStringsFromFile(filename,lines) = true then begin
        Result      := true;
        n           := GetArrayLength(lines) - 1;
        servnamlen  := Length(service);
        error       := false;

        for i:=0 to n do begin
            if Copy(lines[i],1,1) <> '#' then begin
                s := Copy(lines[i],1,servnamlen);
                if CompareText(s,service) = 0 then
                    exit; // found service-entry

                if Pos(port,lines[i]) > 0 then begin
                    error := true;
                    lines[i] := '#' + lines[i] + '   # disabled because collision with  ' + service + ' service';
                end;
            end
            else if CompareText(Copy(lines[i],2,servnamlen),service) = 0 then begin
                // service-entry was disabled
                Delete(lines[i],1,1);
                Result := SaveStringsToFile(filename,lines,false);
                exit;
            end;
        end;

        if error = true then begin
            // save disabled entries
            if SaveStringsToFile(filename,lines,false) = false then begin
                Result := false;
                exit;
            end;
        end;

        // create new service entry
        s := service + '       ' + port + '           # ' + comment + #13#10;
        if SaveStringToFile(filename,s,true) = false then begin
            Result := false;
            exit;
        end;

        if error = true then begin
            MsgBox('the ' + service + ' port was already used. The old service is disabled now. You should check the services file manually now.',mbInformation,MB_OK);
            //InstExec('notepad.exe',filename,GetCurrentDir(),true,false,SW_SHOWNORMAL,errcode);
        end;
    end
    else
        Result := false;
end;

// #######################################################################################
// version functions
// #######################################################################################
function CheckVersion(Filename : string;hh,hl,lh,ll : integer) : boolean;
var
    VersionMS   : cardinal;
    VersionLS   : cardinal;
    CheckMS     : cardinal;
    CheckLS     : cardinal;
begin
    if GetVersionNumbers(Filename,VersionMS,VersionLS) = false then
        Result := false
    else begin
        CheckMS := (hh shl $10) or hl;
        CheckLS := (lh shl $10) or ll;
        Result := (VersionMS > CheckMS) or ((VersionMS = CheckMS) and (VersionLS >= CheckLS));
    end;
end;

// Some examples for version checking
function NeedShellFolderUpdate() : boolean;
begin
    Result := CheckVersion('ShFolder.dll',5,50,4027,300) = false;
end;

function NeedVCRedistUpdate() : boolean;
begin
    Result := (CheckVersion('mfc42.dll',6,0,8665,0) = false)
        or (CheckVersion('msvcrt.dll',6,0,8797,0) = false)
        or (CheckVersion('comctl32.dll',5,80,2614,3600) = false);
end;

function NeedHTMLHelpUpdate() : boolean;
begin
    Result := CheckVersion('hh.exe',4,72,0,0) = false;
end;

function NeedWinsockUpdate() : boolean;
begin
    Result := (UsingWinNT() = false) and (CheckVersion('mswsock.dll',4,10,0,1656) = false);
end;

function NeedDCOMUpdate() : boolean;
begin
    Result := (UsingWinNT() = false) and (CheckVersion('oleaut32.dll',2,30,0,0) = false);
end;

// #######################################################################################
// Replace substring in a string functions
// #######################################################################################
procedure FileReplace(SrcFile, sFrom, sTo: String);
var
    FileContent: String;
begin
    //Load srcfile to a string
    LoadStringFromFile(SrcFile, FileContent);
    //Replace Fraomstring by toString in file string content
    StringChange (sTo,'/', '\');
    StringChange (FileContent, sFrom, sTo);
    //Replace old content srcfile by the new content
    DeleteFile(SrcFile);
    SaveStringToFile(SrcFile,FileContent, True);
end;

// #######################################################################################
// Replace in file functions
// #######################################################################################
procedure FileWrite(SrcFile, sFrom, sTo: String);
var
    FileContent: String;
begin
    //Load srcfile to a string
    LoadStringFromFile(SrcFile, FileContent);
    //Replace Fraomstring by toString in file string content
    //StringChange (sTo,'/', '\');
    StringChange (FileContent, sFrom, sTo);
    //Replace old content srcfile by the new content
    DeleteFile(SrcFile);
    SaveStringToFile(SrcFile,FileContent, True);
end;

// #######################################################################################
// Custumized page for apache config
// #######################################################################################
procedure CreateTheWizardPages;
// variables locales
var
    Lbl: TLabel;
    Page: TWizardPage;
    Edit: TEdit;
    PortNbr: String;
// boites
begin
    Page := CreateCustomPage(wpSelectComponents, 'Apache configuration', 'Please enter your parameter for the apache server (Default is 80)');
    Lbl := TLabel.Create(Page);
    Lbl.Top := ScaleY(11);
    Lbl.Caption := 'Apache server port :';
    Lbl.AutoSize := True;
    Lbl.Parent := Page.Surface;

    Edit := TEdit.Create(Page);
    Edit.Top := ScaleY(8);
    Edit.Left := Lbl.Left + ScaleX(70);
    Edit.Width := Page.SurfaceWidth div 2 - ScaleX(8);
    Edit.Text := PortNbr;
    Edit.Text := '80';
    Edit.Parent := Page.Surface;
end;

// #######################################################################################
// Custumized page for Password enter
// #######################################################################################
procedure CreateTheWizardPagesPwd;
// variables locales
var
    PasWd: TLabel;
    PagePwd: TWizardPage;
    EditPw: TEdit;
    //MailHostName: String;
// boites
begin
    PagePwd := CreateCustomPage(wpSelectComponents, 'Password for the data base user', 'Please enter the password for the data base');
    PasWd := TLabel.Create(PagePwd);
    PasWd.Top := ScaleY(11);
    PasWd.Caption := 'PassWord : ';
    PasWd.AutoSize := True;
    PasWd.Parent := PagePwd.Surface;

    EditPw := TEdit.Create(PagePwd);
    EditPw.Top := ScaleY(8);
    EditPw.Left := PasWd.Left + ScaleX(70);
    EditPw.Width := PagePwd.SurfaceWidth div 2 - ScaleX(8);
    EditPw.Parent := PagePwd.Surface;
end;

// #######################################################################################
// Custumized page for Enter the path of the backup file
// #######################################################################################
procedure CreateTheWizardPagesBkpDir;
var
    PageBkpDir: TInputDirWizardPage;
// boites
begin
    PageBkpDir := CreateInputDirPage(wpSelectDir,'Select Backup Data Directory','Where should Backup data files be installed?','Select the folder in which Setup should copy backup data files, then click Next.', False, '');
    PageBkpDir.Add('');
    PageBkpDir.Values[0] := ExpandConstant('{userdesktop}\dbBackup');
end;

// #######################################################################################
// Custumized page for Time zone enter
// #######################################################################################
procedure CreateTheWizardPagesTimeZone;
// variables locales
var
    Panel: TPanel;
    PageTimeZone: TWizardPage;
    ListBTimeZone: TNewListBox;
// boites
begin
    PageTimeZone := CreateCustomPage(wpWelcome, 'Time zone of your location', 'Please choose your time zone');
    Panel := TPanel.Create(PageTimeZone);
    Panel.Width := PageTimeZone.SurfaceWidth div 2 - ScaleX(8);
    Panel.Left :=  PageTimeZone.SurfaceWidth - Panel.Width;
    Panel.Caption := 'TPanel';
    Panel.Color := clWindow;
    Panel.ParentBackground := False;
    Panel.Parent := PageTimeZone.Surface;

    ListBTimeZone := TNewListBox.Create(PageTimeZone);
    ListBTimeZone.Width := PageTimeZone.SurfaceWidth;
    ListBTimeZone.Height := ScaleY(200);
    ListBTimeZone.Parent := PageTimeZone.Surface;
    ListBTimeZone.Items.Add('Etc/UTC');
    ListBTimeZone.Items.Add('Europe/Paris');
    ListBTimeZone.ItemIndex := 2;
end;

// Initialisation
procedure InitializeWizard();
begin
    CreateTheWizardPages;
    CreateTheWizardPagesTimeZone;
    CreateTheWizardPagesPwd;
    CreateTheWizardPagesBkpDir;
end;

// #######################################################################################
// Function to stop and delete de service by uninstallation procedur
// #######################################################################################
procedure CurUninstallStepChanged(CurStep: TUninstallStep);
var
    ErrorCode: Integer;
begin
    if CurStep = usUninstall then
    begin
        //Uninstall process
        ShellExec('open','taskkill.exe','/f /im MyApplicationService.exe','',SW_HIDE,ewNoWait,ErrorCode);
        ShellExec('open','taskkill.exe','/f /im httpd.exe','',SW_HIDE,ewNoWait,ErrorCode);
        ShellExec('open','taskkill.exe','/f /im mysqld.exe','',SW_HIDE,ewNoWait,ErrorCode);

        // stop all affected services
        StopService('MyApplicationService');
        StopService('MySqld');
        StopService('Apache');

        // remove all affected services
        RemoveService('MyApplicationService');
        RemoveService('MySqld');
        RemoveService('Apache');
    end;
end;

// #######################################################################################
// Function to check and replace the string in the file at the end of the installation
// #######################################################################################
procedure CurStepChanged(CurStep: TSetupStep);
var
    ErrorCode: Integer;
    WorkingDir:   String;
    PathOfDir: String;
begin
    //juste aprés installation
    if CurStep = ssPostInstall then
    begin
        PathOfDir := GetShortName(PathOfDir2);
        FileReplace(ExpandConstant('{app}\create_db.sql'), '@@Pwd@@', EditPw.Text);

        FileReplace(ExpandConstant('{app}\webserver\bin\apache\Apache2.2.22\conf\httpd.conf'), '@@Port@@', PortNbr);
        FileReplace(ExpandConstant('{app}\webserver\bin\apache\Apache2.2.22\conf\httpd.conf'), '@@Path@@', PathOfDir+'\webserver');
        FileReplace(ExpandConstant('{app}\webserver\bin\apache\Apache2.2.22\bin\php.ini'), '@@Path@@', PathOfDir+'\webserver');
        FileWrite(ExpandConstant('{app}\webserver\bin\apache\Apache2.2.22\bin\php.ini'), '@@TimeZone@@', TimeZone);

        FileReplace(ExpandConstant('{app}\webserver\bin\mysql\mysql5.5.24\my.ini'), '@@Path@@', PathOfDir+'\webserver');
        FileReplace(ExpandConstant('{app}\webserver\bin\mysql\mysql5.5.24\bin\dbexport.bat'), '@@Path@@', PathOfBackupDir);
        FileReplace(ExpandConstant('{app}\webserver\bin\mysql\mysql5.5.24\bin\create_db.bat'), '@@Path@@', PathOfDir + '\webserver\bin\mysql\mysql5.5.24');
        FileReplace(ExpandConstant('{app}\webserver\bin\mysql\mysql5.5.24\bin\create_db.bat'), '@@PathOfDir@@', PathOfDir);

        FileReplace(ExpandConstant('{app}\webserver\bin\php\php5.4.3\php.ini'), '@@Path@@', PathOfDir+'\webserver');
        FileReplace(ExpandConstant('{app}\webserver\bin\php\php5.4.3\phpForApache.ini'), '@@Path@@', PathOfDir+'\webserver');

        if InstallService(ExpandConstant('"{app}\webserver\bin\mysql\mysql5.5.24\bin\mysqld.exe" MySqld'),'MySqld','MySqld','The mysql service',SERVICE_WIN32_OWN_PROCESS,SERVICE_AUTO_START) = true then
        begin
            StartService('MySqld');
            Sleep(8000);
        end
        else
            MsgBox('MySqld service could not be installed',mbInformation, MB_OK);

        if InstallService(ExpandConstant('"{app}\webserver\bin\apache\apache2.2.22\bin\httpd.exe" -k runservice'),'Apache','Apache','The apache service',SERVICE_WIN32_OWN_PROCESS,SERVICE_AUTO_START) = true then
        begin
            StartService('Apache');
            Sleep(5000);
        end
        else
            MsgBox('Apache service could not be installed',mbInformation, MB_OK);

        if InstallService(ExpandConstant('"{app}\MyApplicationService.exe"'),'MyApplicationService','MyApplicationService','The server',SERVICE_WIN32_OWN_PROCESS,SERVICE_AUTO_START) = true then
        begin
            StartService('MyApplicationService');
            Sleep(5000);
        end
        else
            MsgBox('The MyApplicationService service could not be installed',mbInformation, MB_OK);

    end;

    if CurStep = ssInstall then
    begin
        //Uninstall process
        ShellExec('open','taskkill.exe','/f /im MyApplicationService.exe','',SW_HIDE,ewNoWait,ErrorCode);
        ShellExec('open','taskkill.exe','/f /im httpd.exe','',SW_HIDE,ewNoWait,ErrorCode);
        ShellExec('open','taskkill.exe','/f /im mysqld.exe','',SW_HIDE,ewNoWait,ErrorCode);

        // stop all affected services
        StopService('MyApplicationService');
        StopService('MySqld');
        StopService('Apache');  

        // remove all affected services
        RemoveService('MyApplicationService');
        RemoveService('MySqld');
        RemoveService('Apache');
    end;

    if CurStep = ssDone then
    begin
        Exec(ExpandConstant('{app}\webserver\bin\mysql\mysql5.5.24\bin\create_db.bat'),'','', SW_SHOW, ewWaitUntilTerminated, ErrorCode);
    end;
end;

// #######################################################################################
// Function to check the values entered
// #######################################################################################
function NextButtonClick(CurPageID: Integer): Boolean;
var
    ErrorCode: Integer;
begin
    Result := True;
    case CurPageID of
        Page.ID:
        begin
            if (Edit.Text = '') then
            begin
                MsgBox('Port number check:'#13#13 'The port number is empty. The default port << 80 >> will be applied. Please click on the back button to change if needed ', mbError, MB_OK);
                Edit.Text := '80';
            end
            else
            begin
                Result := True;
                PortNbr := Edit.Text;
            end
        end;
        //End page.id

        PagesEmailSt.ID:
        begin
            if (EditPwd.Text = EditPwd2.Text) then
            begin
                MailHostName := EditMailHostName.Text;
                MailUserName := EditUserName.Text;
                MailPwd := EditPwd.Text;
                MailFrom := EditFromMail.Text;
                MailSmtpPort := EditSmtpPort.Text;
            end
            else
            begin
                MsgBox('Password check:'#13#13 'The password entered is not the same. Please click on back and check ', mbError, MB_OK);
                Result := false;
            end
        end;
        //End PagesEmailSt.id

        //Time zone add beginn
        PageTimeZone.ID:
        begin
            Result := false;
            TimeZone := ListBTimeZone.Items.Strings[ListBTimeZone.ItemIndex];
        end;
        //End time zone add

        //Beginn dir selector
        PageBkpDir.ID:
        begin
            //PageBkpDir.Values[0] := ExpandConstant('{userdesktop}\dbBackup');
            PathOfBackupDir := PageBkpDir.Values[0];
        end;

        wpSelectDir:
        begin
            PathOfDir2 := WizardDirValue;
            //MsgBox('NextButtonClick:' #13#13 'You selected: ''' + PathOfDir + '''.', mbInformation, MB_OK);
        end;
        //End dir selector
    end; //End case
    Result := True;
end;

function GetDataDir(Param: String): String;
begin
    //Return the selected DataDir
    Result := PageBkpDir.Values[0];
end;