Home > DELPHI & EMBARCADERO > [DELPHI] – Start e Stop del MySQL Server da un’applicazione Delphi su Pendrive

[DELPHI] – Start e Stop del MySQL Server da un’applicazione Delphi su Pendrive

Scenario…

Abbiamo un’applicazione Delphi (desktop) con Data Base MySQL. Vogliamo che l’applicazione possa essere avviata da una pendrive e che i dati (le Tabelle) siano anch’essi memorizzati su pendrive. Ma vogliamo anche che lo stesso MySQL Server sia sulla pendrive e che la nostra applicazione lo avvii alla partenza e lo arresti all’uscita.

… in poche parole vogliamo che tutto (La nostra applicazione, le Tabelle del DataBase  e l’engine del MySQL Server) sia presente sulla pendrive … e che l’utilizzatore della nostra applicazione non debba installare alcun software sul proprio computer! 

 

 Il MySQL Server sulla Pendrive.

Prepariamo l’ambiente sulla pendrive :

1. Creamo un directory nella pendrive (es. \contab) in cui copieremo la nostra applicazione Delphi, l’eseguibile (es. coge.exe)

2. Nella stessa direcotory ( \contab ), copiamo l’intera cartella ( \mysql ) con tutte le sue sottocarelle : \bin, \data, \share e \Docs (possiamo anche, se preferiamo, rinominarla)

3. Nel file di configurazione del MySQL (my.ini), modifichiamo i percorsi assegnati a basedir e datadir

File di Configurazione del MySQL :  my.ini (presente nella cartella \mysql)

...
# CLIENT SECTION
# ----------------------------------------------------------------------
#
# The following options will be read by MySQL client applications.
# Note that only client applications shipped by MySQL are guaranteed
# to read this section. If you want your own MySQL client program to
# honor these values, you need to specify it as an option during the
# MySQL client library initialization.
#
[client]

port=3306

default-character-set=latin1

# SERVER SECTION
# ----------------------------------------------------------------------
#
# The following options will be read by the MySQL Server. Make sure that
# you have installed the server correctly (see above) so it reads this
# file.
#
[mysqld]

# The TCP/IP Port the MySQL Server will listen on
port=3306

#Path to installation directory. All paths are usually resolved relative to this.
basedir="\mysql\"

#Path to the database root
datadir="\mysql\data\"
...

Le Funzioni per lo Start e Stop del MySQL Sever.

Di seguito sono riportate le quattro funzioni per la gestione dell’avvio e l’arresto del MySQL Server.
Le funzioni SP_MySQLStart() e SP_MySQLStop() effettuano rispettivamente l’avvio e l’arresto del MySQL Server, la funzione SP_ExecProcess() avvia un processo richiamando a sua volta l’API di Windows CreateProcess(), ed infine la funzione SP_CheckProcess() controlla se un processo è in esecuzione o meno.

… le funzioni sono state raccolte in una unit : MySQLServer_Lib.pas, così da poter essere facilmente incluse ed utilizzate nei propri progetti…


unit MYSQLServer_Lib;

interface

Uses Forms,SysUtils, DBTables, Classes, DB, Dialogs, StdCtrls,
        WinTypes, WinProcs;

   // ... funzioni per lo Start e Stop del servizio MySQL Server
   function  SP_MySQLStart(var pHandle_Server:THandle):Integer;
   function  SP_MySQLStop(pHandle_Server:THandle) :Integer;

   function  SP_ExecProcess(pApplication, pCommandLine, pDirectory : string): THandle;
   function  SP_CheckProcess(pHandle: THandle): Boolean;

const

   // ... costanti relative ai valori di ritorno delle funzioni
   //     di Strat e Stop.
   ENGINE_STARTED             = 9001;
   ENGINE_RUNNING             = 9002;
   ENGINE_START_ERROR         = 9003;

   ENGINE_STOPPED             = 9004;
   ENGINE_NOT_RUNNING         = 9005;
   ENGINE_STOP_ERROR          = 9006;

implementation

//--------------------------------------------------------------------------
// FUNCTION  : SP_MySQLStart()
//             La Funzione effettua lo Start del MySQL Server (mysql-nt.exe)
//
// PARAMETRI : Nessuno
//
// RETURN    : La funzione ritorna uno dei valori interi dichiarati
//             come const :
//              ENGINE_STARTED      = 9001 - MySQL Server avviato.
//              ENGINE_RUNNING      = 9002 - MySQL Server gia' in esecuzione.
//              ENGINE_START_ERROR  = 9003 - Errore durante l'avvio.
//--------------------------------------------------------------------------
function SP_MySQLStart(var pHandle_Server:THandle):Integer;
var
  Start_Code        : Integer;

  PathEngine        : string;

  ApplicationName   : string;
  CommandLine       : string;
  CurrentDirectory  : string;
begin

  // ... directory corrente dell'Applicazione Delphi
  //     ( da dove l'applicazione è stata avviata)
  PathEngine        := GetCurrentDir;

  // ... assegna : Nome Applicazione, Linea di Comando e Directory di lavore
  ApplicationName   := PathEngine + '\DataBase\bin\mysqld-nt.exe';
  CommandLine       := '--defaults-file="\DataBase\my.ini"';
  CurrentDirectory  := PathEngine + '\DataBase';

  // ... controlla se il Processo ( il MySQL Engine è già in esecuzione )
  if SP_CheckProcess(pHandle_Server) = true then begin
     // ... il processo MySQL Server è gia' in esecuzione
     Start_Code := ENGINE_RUNNING;
     // ShowMessage('MYSQL Server gia'' in esecuzione');
  end
  else begin
     // ShowMessage('MYSQL Server non in esecuzione, START...');

     // ... Start dell'MSQL Engine!
     pHandle_Server := SP_ExecProcess(ApplicationName, CommandLine, CurrentDirectory);
     // ... Sleep ( attendi un po' )
     sleep(3000);
     if pHandle_Server <> 0 then begin
        // ... Ok, avviato !
        Start_Code := ENGINE_STARTED;
     end
     else begin
        // ... errore durante l'avvio del servizio MySQL Server
        Start_Code := ENGINE_START_ERROR;
        // ShowMessage('Errore durante lo START!');
     end;
  end;
  // ... ritorna lo Start Code relativo
  Result := Start_Code;
end;
//--------------------------------------------------------------------------

//--------------------------------------------------------------------------
//
// FUNCTION  : SP_MySQLStop()
//             La Funzione effettua lo Stop del servizion MySQL Server
//
// PARAMETRI : Nessuno
//
// RETURN    : La funzione ritorna uno dei valori interi dichiarati
//             come const :
//              ENGINE_STOPPED      = 9004 - MySQL Server arrestato.
//              ENGINE_NOT_RUNNING  = 9005 - MySQL Server non in esecuzione.
//              ENGINE_STOP_ERROR   = 9005 - Errore durante l'arresto.
//
//--------------------------------------------------------------------------
function SP_MySQLStop(pHandle_Server:THandle):Integer;
var
  Stop_Code         : Integer;

  Handle_Admin      : THandle;

  PathEngine        : string;

  ApplicationName   : string;
  CommandLine       : string;
  CurrentDirectory  : string;

  contatore         : Integer;
begin

  // ... directory dell'Applicazione Delphi ( da dove è stata avviata )
  PathEngine        := GetCurrentDir;

  // ... avviamo il msqladmin.exe che ci consentirà di arretsare il MySQL Engine
  //     (mysqld-nt.exe)

  // ... assegna : Nome Applicazione, Linea di Comando e Directory di lavoro
  ApplicationName   := PathEngine + '\DataBase\bin\mysqladmin.exe';

  // ... User e Password (sono impostate a root root ...impostare le proprie)
  CommandLine       := '-u root -proot shutdown';

  // ... direcoty di lavoro
  CurrentDirectory  := PathEngine + '\DataBase';

  // ... controlla se il Processo ( il MySQL Engine è in esecuzione )
  if SP_CheckProcess(pHandle_Server) = FALSE then begin
     // ... esci!
     Stop_Code := ENGINE_NOT_RUNNING;
     // ShowMessage('MySQL NON E'' IN ESECUZIONE');
  end
  else begin
     // ShowMessage('MySQL E'' IN ESECUZIONE, STOP...');

     // ... per fermare il servizio MySQL Server, dobbiamo avviare il servizio
     // mysqladmin.exe indicando, nella riga di comando ( CommandLine ),
     // ... lo shutdown del servizio con la relativa utenza e password
     Handle_Admin := SP_ExecProcess(ApplicationName, CommandLine, CurrentDirectory);

     if Handle_Admin <> 0 then begin
        // ... il servizio myqladmin.exe e' avviato,
        // ... ora attendi che il mysqladmin arresti il MySQL Engine (msqld-nt.exe)
        contatore := 10;
        repeat
            // ... decrementa il contatore
            dec(contatore);
            // ... controlla se il Processo è ancora attivo
            if SP_CheckProcess(pHandle_Server) = TRUE then begin
               // ... si, ancora attivo ... attendi un po'
               Sleep(3000);
            end;
        until (contatore < 1) or (Handle_Admin = 0);

        // ... chiudi l'Handle del msqladmin.exe
        CloseHandle(Handle_Admin);
        // ShowMessage('MySQl Server stopped');
        Stop_Code := ENGINE_STOPPED;
        // ShowMessage('STOPPED OK !');
     end
     else begin
        // ... errore durante l'avvio del servizio msqadmin.exe...
        //     (che avrebbe dovuto fermare il mysqld-nt.exe)
        Stop_Code := ENGINE_STOP_ERROR;
        // ShowMessage('ERRORE DURANTE LO STOP !');
     end;
  end;

  // ... ritorna lo Stop Code relativo
  Result := Stop_Code;
end;
//--------------------------------------------------------------------------

//--------------------------------------------------------------------------
//
// FUNCTION  :  SP_ExecProcess()
//              La Funzione avvia un'applicazione creandone il
//              processo relativo.
//              Richiama l'API di Windows CreateProcess().
//
// PARAMS    :  Sono previsti tre parametri in ingresso :
//
//              pApplication = Nome del l'applicazione che
//                             da avviare.
//
//              pCommandLine = Linea di comando.
//                             (eventuali parametri e flags
//                              da passare all'applicazione
//                              da avviare).
//
//              pDirectory   = Directory di lavoro
//                             dell'applicazione.
//
// RETURN    :  La funzione ritorna l'handle relativo al processo
//              avviato.
//
//--------------------------------------------------------------------------
function SP_ExecProcess(pApplication, pCommandLine,
                        pDirectory : string): THandle;
var
  // ... struttura contenete le Info di StartUp dell'applicazione
  //     da avviare.
  //     (vedere la documentazione Windows SDK Developer's Reference)
  sInfo          : TStartupInfo;

  // ... struttura contenete le Info del processo avviato.
  //     (vedere la documentazione Windows SDK Developer's Reference)
  pInfo          : TProcessInformation;

  // ... handle del processo
  Handle_Process : THandle;

  // ... flag che indica se il processo e' stato creato o meno
  CreatedOK      : Boolean;

begin

  // ... inizializza la Struttura sInfo
  FillChar(sInfo, SizeOf(sInfo), 0);

  // ... ora inizializza la Struttura pInfo
  FillChar(pInfo, SizeOf(pInfo), 0);

  // ... l'elemento .cb (della struttura TStartupInfo) indica
  //     la taglia, in bytes, della struttura...
  // ... assegnagli il valore!
  sInfo.cb := SizeOf(TStartupInfo);

  // ... l'elemento .wShowWindow indica SE e COME deve apparire
  //     la Window relativa al processo che stiamo avviando.
  // ... voglio che il MySQL Sever parta senza che appaia
  //     la finestra del prompt dei comandi.
  sInfo.wShowWindow := SW_HIDE;
  sInfo.dwFlags     := STARTF_USESHOWWINDOW;

  // ... inizializza a FALSE il Flag di creazione del processo
  CreatedOK := FALSE;

  // ... richiama l'API di Windows CreateProcess()
  CreatedOK := CreateProcess(nil, PChar(pApplication + ' ' +
                                        pCommandLine),
                                        nil,
                                        nil,
                                        False,
                                        CREATE_NEW_PROCESS_GROUP +
                                        HIGH_PRIORITY_CLASS,
                                        nil,
                                        PChar(pDirectory),
                                        sInfo,
                                        pInfo);

  // ... test del valore di ritorno della funzione CreateProcess()
  if (createdOK = TRUE) then begin
     // ... ok! il processo e' stato creato...
     // ... ritorna l'id del processo
     Handle_Process := pInfo.hProcess;
  end
  else begin
     // ... il processo non e' stato creato !
     // ... ritorna 0 !
     Handle_Process := 0;
  end;
  //
  Result := Handle_Process;
end;
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
//
// FUNCTION  : SP_CheckProcess()
//             La Funzione controlla se un processo è attivo o meno
//
// PARAMETRI : E' previsto un unico parametro in ingresso :
//             pHandle  =  L'identificativo (Handle) del processo
//                         ...il valore dell'Handle è quello ritornato dalla
//                         funzione SP_ExecProcess()
//
// RETURN    : La funzione ritorna un valore Booleano :
//             True  = se il processo è attivo
//             False = se il processo non è attivo
//
//--------------------------------------------------------------------------
function SP_CheckProcess(pHandle: THandle): Boolean;
var
  Check_Flag : Boolean;
  ExitCode   : Cardinal;
begin

  // ... assegna FALSE al valore di ritorno
  Check_Flag := FALSE;

  // ... test sull'Handle del processo
  if (pHandle <> 0) then begin
     // ... è diverso da ZERO... allora :
     // ... richiamo dell'API di Windows GetExitCode() che valorizzerà
     //     ExitCode e ritornerà TRUE se la funzione ha successo.
     if (GetExitCodeProcess(pHandle, ExitCode) = TRUE) then begin
        // ... analisi dell'ExitCode
        if (ExitCode = STILL_ACTIVE) then begin
           // ... il processo è ancora attivo
           // showmessage('ancora attivo');
           Check_Flag := TRUE;
        end
        else begin
           // ... il processo non e' attivo
           // showmessage('non attivo');
           CloseHandle(pHandle);
           pHandle    := 0;
           // ... il processo non e' attivo
           Check_Flag := FALSE;
        end;
     end
     else begin
        // ShowMessage('Valore della ExitCodeProcess = FALSE (insuccesso) ');
     end;
  end
  else begin
     // ShowMessage('Halndle da controllare e'' ZERO');
  end;

  // ... ritorna il Check Flag
  Result := Check_Flag;
end;
//--------------------------------------------------------------------------

end.

La Form per il test delle Funzioni…

Una semplice Form per effettuare il test delle funzioni di Start e Stop del MySQL Server.
La Form prevede solo due bottoni, uno per l’avvio e l’altro per l’arresto del MySQL Server, ed una Label in cui sarà visualizzato il messaggio relativo…


unit UMySQLServer_Test;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, Buttons,

  MySQLServer_Lib;

type
  TFMySQLServer_Test = class(TForm)
    B_START : TBitBtn;
    B_STOP  : TBitBtn;

    MSG     : TLabel;

    procedure B_STARTClick(Sender: TObject);
    procedure B_STOPClick(Sender: TObject);

    procedure FormCreate(Sender: TObject);
    procedure FormShow(Sender: TObject);

  private
    { Private declarations }
  public
    { Public declarations }

  end;

var
  FMySQLServer_Test    : TFMySQLServer_Test;

  //  ... identificativo del processo relativo al MySQL Server
  MySQL_Server_Handle : THandle;

implementation

{$R *.DFM}

//--------------------------------------------------------------------------
//   EVENTO : FormCreate
//--------------------------------------------------------------------------
procedure TFMySQLServer_Test.FormCreate(Sender: TObject);
begin
  // ... inizializza a 0
  MySQL_Server_Handle := 0;
end;
//--------------------------------------------------------------------------

//--------------------------------------------------------------------------
//   EVENTO : FormShow
//--------------------------------------------------------------------------
procedure TFMySQLServer_Test.FormShow(Sender: TObject);
begin
  // ... messaggio a video
  MSG.Caption := '';
end;
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
//   EVENTO : Click sul BOTTONE START_ENGINE
//--------------------------------------------------------------------------
procedure TFMySQLServer_Test.B_STARTClick(Sender: TObject);
var
  Start_Code : Integer;
begin

  // Start MySQL Server

  // ... imposta il Cursore a clessidra
  Screen.Cursor := crHourglass;

  // ... eventuale messaggio di attesa
  MSG.Caption := 'Start MySQL Server ...please wait';

  // ... forza la visualizzazione del messaggio
  Application.ProcessMessages;

  // ... richiamo della Funzione di Start del MySQL Server
  Start_Code := SP_MySQLStart(MySQL_Server_Handle);

  // ... analisi del Codice di ritorno :
  case Start_Code of
           ENGINE_STARTED : begin
                               MSG.Caption := 'MySQL Server started!';
                            end;

           ENGINE_RUNNING : begin
                               MSG.Caption := 'MySQL Server running';
                            end;

       ENGINE_START_ERROR : begin
                               MSG.Caption := 'MySQL Server Start Error!';
                            end;
  end;

  // ... ripristina il Cursore
  Screen.Cursor := crDefault;
end;
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
//   EVENTO : Click sul BOTTONE STOP_ENGINE
//--------------------------------------------------------------------------
procedure TFMySQLServer_Test.B_STOPClick(Sender: TObject);
var
  Stop_Code : Integer;
begin

  // ... Stop MYSQL Server :

  // ... imposta il Cursore a clessidra
  Screen.Cursor := crHourglass;

  // ... eventuale messaggio di attesa
  MSG.Caption := 'Stop MySQL Server ...please wait';

  // ... forza la visualizzazione del messaggio
  Application.ProcessMessages;

  // ... richiamo della Funzione di Start del MySQL Server
  Stop_Code   := SP_MySQLStop(MySQL_Server_Handle);

  // ... analisi del Codice di ritorno :
  case Stop_Code of
          ENGINE_STOPPED : begin
                               MSG.Caption := 'MySQL Server stopped!';
                           end;

      ENGINE_NOT_RUNNING : begin
                               MSG.Caption := 'MySQL Server not running';
                           end;

       ENGINE_STOP_ERROR : begin
                               MSG.Caption := 'MySQL Server Stop Error!';
                           end;
  end;

  // ... ripristina il Cursore
  Screen.Cursor := crDefault;
end;
//--------------------------------------------------------------------------

end.

Annunci
  1. Daniele
    27 giugno 2012 alle 14:25

    Io utilizzo i comandi NET START e NET STOP da riga di comando aspettando la fine dell’esecuzione però questo è più pulito. Grazie !

  1. No trackbacks yet.

Rispondi

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione / Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione / Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione / Modifica )

Google+ photo

Stai commentando usando il tuo account Google+. Chiudi sessione / Modifica )

Connessione a %s...