Logo Search packages:      
Sourcecode: firebird1.5 version File versions

fbdialog.cpp

/*
 *    PROGRAM:    Firebird 1.5 control panel applet
 *    MODULE:           fbdialog.cpp
 *    DESCRIPTION:      Main file to provide GUI based server control functions
 *                            for Firebird 1.5 Super Server
 *
 *  The contents of this file are subject to the Initial Developer's 
 *  Public License Version 1.0 (the "License"); you may not use this 
 *  file except in compliance with the License. You may obtain a copy 
 *  of the License here:
 *
 *    http://www.ibphoenix.com?a=ibphoenix&page=ibp_idpl.
 *
 *  Software distributed under the License is distributed on an "AS 
 *  IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or 
 *  implied. See the License for the specific language governing rights
 *  and limitations under the License.
 *  
 *  The Initial Developer of the Original Code is Paul Reeves.
 *
 *  The Original Code is (C) 2003 Paul Reeves .
 *
 *  All Rights Reserved.
 *  
 *  Contributor(s): ______________________________________. 
 *
 *    History:
 *          This current version is derived from the Fb 1.0 control panel applet
 *          It was adapted to support management of a dual Super Server and
 *          Classic Server install, allowing easy switching between the two server 
 *          types. Unfortunately it became obvious too late in the development 
 *          cycle that such support was not feasible without delaying release 
 *          further. Consequently the applet has been converted back to manage 
 *          Super Server only. The relevant code for Classic has been ifdef'ed out.
 *
 *
 */


#include "stdafx.h"
#include "FBDialog.h"

#include "../../common/config/config.h"

#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif


/////////////////////////////////////////////////////////////////////////////
// CFBDialog 


CFBDialog::CFBDialog(CWnd* pParent /*=NULL*/)
      :     CDialog(CFBDialog::IDD, pParent)
{
      //{{AFX_DATA_INIT(CFBDialog)
      m_FB_Version = _T("");
      m_Firebird_Status = _T("");
      //}}AFX_DATA_INIT

      m_uiTimer = 0;
    hScManager = 0;
      initialised = false;

      m_Guardian_Name         = ISCGUARD_EXECUTABLE;
      m_SS_Server_Name  = REMOTE_SS_EXECUTABLE; 
#ifdef MANAGE_CLASSIC
      m_CS_Server_Name  = REMOTE_CS_EXECUTABLE; 
#endif

      fb_status.AutoStart = 0;
      fb_status.ServicesAvailable = 0;
      fb_status.ServerStatus = 0;
      fb_status.UseGuardian = 0;
      fb_status.UseService = 0;
      fb_status.WasRunning  = 0;
#ifdef MANAGE_CLASSIC
      fb_status.UseClassic = 0;
#endif
      fb_status.SystemLogin = 1;
      fb_status.SufficientUserRights = 1;
      fb_status.ServerName = "";

      new_settings = fb_status;
}


void CFBDialog::DoDataExchange(CDataExchange* pDX)
{
      CDialog::DoDataExchange(pDX);
      //{{AFX_DATA_MAP(CFBDialog)
      DDX_Control(pDX, IDC_SERVER_ARCH, m_Server_Arch);
      DDX_Control(pDX, IDAPPLY, m_Apply);
      DDX_Control(pDX, IDC_USE_GUARDIAN, m_Use_Guardian);
      DDX_Control(pDX, IDC_MANUAL_START, m_Manual_Start);
      DDX_Control(pDX, IDC_APPLICATION, m_Run_As_Application);
      DDX_Control(pDX, IDC_SERVICE, m_Run_As_Service);
      DDX_Control(pDX, IDC_AUTO_START, m_Auto_Start);
      DDX_Control(pDX, IDC_RUN_TYPE, m_Run_Type);
      DDX_Control(pDX, IDC_BUTTON_STOP, m_Button_Stop);
      DDX_Control(pDX, IDC_STATUS_ICON, m_Icon);
      DDX_Text(pDX, IDC_FB_VERSION, m_FB_Version);
      DDV_MaxChars(pDX, m_FB_Version, 128);
      DDX_Text(pDX, IDC_FIREBIRD_STATUS, m_Firebird_Status);
      //}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CFBDialog, CDialog)
      //{{AFX_MSG_MAP(CFBDialog)
      ON_BN_CLICKED(IDC_BUTTON_STOP, OnButtonStop)
      ON_WM_TIMER()
      ON_WM_DESTROY()
      ON_BN_CLICKED(IDC_SERVICE, OnService)
      ON_BN_CLICKED(IDC_MANUAL_START, OnManualStart)
      ON_BN_CLICKED(IDC_APPLICATION, OnApplication)
      ON_BN_CLICKED(IDC_AUTO_START, OnAutoStart)
      ON_BN_CLICKED(IDC_USE_GUARDIAN, OnUseGuardian)
      ON_BN_CLICKED(IDAPPLY, OnApply)
      ON_BN_CLICKED(IDC_CLASSIC_SERVER, OnClassicServer)
      ON_BN_CLICKED(IDC_SUPER_SERVER, OnSuperServer)
      //}}AFX_MSG_MAP
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CFBDialog message handlers


BOOL CFBDialog::OnInitDialog() 
// This method is meant to do the minimum, one-time setup stuff
// UpdateServerStatus does most of the work, and is called on 
// a timer, so we don't need to repeat that work here.
{
      CDialog::OnInitDialog();
      
      m_Reset_Display_To_Existing_Values = TRUE;

      fb_status.ServicesAvailable = ServiceSupportAvailable();
      if ( fb_status.ServicesAvailable )
      {
            m_Run_Type.EnableWindow(TRUE);
            m_Run_As_Service.EnableWindow(TRUE);
            m_Run_As_Application.EnableWindow(TRUE);
      }
      else
      {
            m_Run_As_Service.EnableWindow(FALSE);
      }

      if (fb_status.ServicesAvailable)
      {
            if (!ValidateInstalledServices())
            {
                  if (ServerStop())
                        ServiceRemove();
                  ValidateInstalledServices();
            }
      }
      ViewRegistryEntries();

      fb_status.SufficientUserRights = UserHasSufficientRights();

      m_Auto_Start.EnableWindow( fb_status.SufficientUserRights );
      m_Manual_Start.EnableWindow( fb_status.SufficientUserRights );
      m_Run_As_Application.EnableWindow( fb_status.SufficientUserRights );
      m_Run_As_Service.EnableWindow( fb_status.SufficientUserRights );
      m_Use_Guardian.EnableWindow( fb_status.SufficientUserRights );
      m_Button_Stop.EnableWindow( fb_status.SufficientUserRights );

      m_uiTimer = SetTimer(1, 500, NULL);
      
      return TRUE;  // return TRUE unless you set the focus to a control
}


void CFBDialog::UpdateServerStatus() 
// This is one of the key functions. It is called
// from the timer and sets the display.
// It is in three sections
//    a) Evaluate current status of the Firebird install
//    b) Update internal variables
//    c) Update display
{

      //These two methods more or less tell us everything
      //about the current state of the server.
      ViewRegistryEntries();
      fb_status.ServerStatus = GetServerStatus();


#ifdef MANAGE_CLASSIC
      if ((fb_status.WasRunning) && (!fb_status.UseService))
      { 
            fb_status.UseClassic = (bool) GetClassicServerHandle();
      }
      else
      {
            fb_status.UseClassic = (bool) GetPreferredArchitecture();
      }
#endif

//========Update other internal variables ==============

      m_Firebird_Status.Format(fb_status.ServerStatus);

#ifdef MANAGE_CLASSIC
      if (fb_status.UseClassic) 
      {
            fb_status.ServiceExecutable = m_CS_Server_Name; 
      }
      else
#endif
      {
            fb_status.ServiceExecutable = m_SS_Server_Name; 
      }

//========Start of code that updates GUI================
      if ( fb_status.WasRunning )
      {
            m_Icon.SetIcon(AfxGetApp()->LoadIcon(IDI_ICON1)); 
            m_Button_Stop.SetWindowText("&Stop");
      }
      else
      {
            m_Icon.SetIcon(AfxGetApp()->LoadIcon(IDI_ICON4));
            m_Button_Stop.SetWindowText("&Start");
      }

      //Reset check boxes 
      if (m_Reset_Display_To_Existing_Values)
      {
            // This is always called on startup. This method 
            // is also called if an attempt to install
            // the service fails.
            ResetCheckBoxes( fb_status );
            if ( m_Apply.IsWindowEnabled() )
                  ApplyChanges();
      }

      m_Reset_Display_To_Existing_Values = false;
      
      UpdateData(false);            

      // This will be false the first time round.
      // It is needed because the Config class doesn't 
      // refresh after the conf file has been updated.
      initialised = true;

      // The only time new_settings differs from fb_status is 
      // during the ApplyChanges method. 
      new_settings = fb_status;
}


bool CFBDialog::CheckServiceInstalled( LPCTSTR service )
{
      SC_HANDLE hService = NULL;
      bool result;
      
      OpenServiceManager( GENERIC_READ );
      hService = OpenService (hScManager, service, GENERIC_READ );
      result = hService;
      if (hService)
            CloseServiceHandle( hService );
      CloseServiceManager();
      return result;
}


bool CFBDialog::ValidateInstalledServices()
// Check if services are installed.
// If Guardian installed but not Server service 
// then return false;
{
      fb_status.UseService = CheckServiceInstalled(REMOTE_SERVICE);
      fb_status.UseGuardian = CheckServiceInstalled(ISCGUARD_SERVICE);  

      if ((!fb_status.UseService) && (fb_status.UseGuardian))
            return false;
      else
            return true;
}


int CFBDialog::GetServerStatus()
// This is called by UpdateServerStatus, 
// which is called on the timer, so our status 
// should always be 'up-to-date'.
// Returns:
//          fb_status.ServerStatus
// Also sets:
//          fb_status.UseService
//          fb_status.WasRunning

{
      int result = IDS_APPLICATION_STOPPED;

      fb_status.UseService = CheckServiceInstalled(REMOTE_SERVICE);

      if ( fb_status.UseService )
      {
            SC_HANDLE hService = NULL;
            OpenServiceManager( GENERIC_READ );
            hService = OpenService (hScManager, REMOTE_SERVICE, GENERIC_READ );
            QueryServiceStatus( hService, &service_status ); 
            CloseServiceHandle ( hService );
            CloseServiceManager();
            switch ( service_status.dwCurrentState )
            {
                  case SERVICE_STOPPED :
                  {
                        result = IDS_SERVICE_STOPPED;
                        break;
                  }
                  case SERVICE_START_PENDING :
                  {
                        result = IDS_SERVICE_START_PENDING;
                        break;
                  }
                  case SERVICE_STOP_PENDING : 
                  {
                        result = IDS_SERVICE_STOP_PENDING;
                        break;
                  }
                  case SERVICE_RUNNING : 
                  {
                        result = IDS_SERVICE_RUNNING;
                        break;
                  }
                  case SERVICE_CONTINUE_PENDING :
                  {
                        result = IDS_SERVICE_CONTINUE_PENDING;
                        break;
                  }
                  case SERVICE_PAUSE_PENDING : 
                  {
                        result = IDS_SERVICE_PAUSE_PENDING;
                        break;
                  }
                  case SERVICE_PAUSED :
                  {
                        result = IDS_SERVICE_PAUSED;
                        break;
                  }
            }
      }
      else
      {
            //Is Firebird running as an application...
            if ( FirebirdRunning() ) 
            {
                  result = IDS_APPLICATION_RUNNING;
            }
            else
            {
                  result = IDS_APPLICATION_STOPPED;
            }
      }

      fb_status.WasRunning = ( (fb_status.ServerStatus == IDS_SERVICE_RUNNING) 
                                          || (fb_status.ServerStatus == IDS_APPLICATION_RUNNING) );

      // If running as an application and not set to run automatically on start up 
      // we still don't  know if we the guardian is running.
      if ((fb_status.WasRunning) && (!fb_status.UseService) )
      { 
            fb_status.UseGuardian = (bool) GetGuardianHandle();
      }

      return result;
}


void CFBDialog::ViewRegistryEntries()
// Find out what we have in the non-Firebird section of the 
// registry ie, in Services or Application Run
//
// The following variables will be set on return:
//    fb_status.UseGuardian 
//    fb_status.AutoStart
//    fb_status.SystemLogin
//    fb_status.UseClassic
//    fb_status.ServerName
{
      
      fb_status.AutoStart = 0;

      fb_status.UseService = CheckServiceInstalled(REMOTE_SERVICE);
      if ( fb_status.UseService )
      {
          LPQUERY_SERVICE_CONFIG status_info;
            SC_HANDLE hService = 0;
            DWORD dwBytesNeeded; 
            OpenServiceManager( GENERIC_READ );

            char * service = "";
            char * display_name = "";
            service = ISCGUARD_SERVICE;
            display_name = ISCGUARD_DISPLAY_NAME;
            hService = OpenService (hScManager, service, SERVICE_QUERY_CONFIG);
            fb_status.UseGuardian = hService;
            if (hService != NULL) // then we are running as a Service
            {
                  status_info = (LPQUERY_SERVICE_CONFIG) LocalAlloc(LPTR, 4096); 
                  if (!QueryServiceConfig(hService,status_info,4096,&dwBytesNeeded))
                  {     
                        LocalFree( status_info );
                        HandleError(0, "ViewRegistryEntries - Cannot query Guardian service.");
                  }
                  else
                  {
                        if (status_info->dwStartType == SERVICE_AUTO_START )
                        {
                              fb_status.AutoStart = 1;
                        }
                  }
                  CloseServiceHandle (hService);
                  LocalFree( status_info );

            }

            //Now do the same again, but this time only look at the server itself
            service = REMOTE_SERVICE;
            display_name = REMOTE_DISPLAY_NAME;
            hService = OpenService (hScManager, service, SERVICE_QUERY_CONFIG);
            CloseServiceManager();
            if (hService != NULL) // then we are running as a Service
            {
                  status_info = (LPQUERY_SERVICE_CONFIG) LocalAlloc(LPTR, 4096); 
                  if (!QueryServiceConfig(hService,status_info,4096,&dwBytesNeeded))
                  {
                        LocalFree( status_info );
                        HandleError(0, "ViewRegistryEntries - Cannot query server service.");
                  }
                  else
                  {
                        fb_status.ServerName = status_info->lpBinaryPathName;
                  }

                  CString LoginAccount = status_info->lpServiceStartName;
                  if (  LoginAccount == "LocalSystem" )
                  {
                        fb_status.SystemLogin = true;
                  }
                  else
                  {
                        fb_status.SystemLogin = false;
                  }
                  LocalFree( status_info );
                  CloseServiceHandle (hService);
            }
      }
      else //Installed as Application, so look for an entry in registry
      {
          HKEY hkey;
            if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, 
                  "Software\\Microsoft\\Windows\\CurrentVersion\\Run", 0, 
                  KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS)
            {
                  DWORD dwType;
                  DWORD dwSize = MAX_PATH;
                  fb_status.AutoStart = (RegQueryValueEx(hkey, "Firebird", NULL, 
                        &dwType, (LPBYTE) fb_status.ServerName.GetBuffer(dwSize/sizeof(TCHAR)), 
                        &dwSize) == ERROR_SUCCESS );
                  if (fb_status.AutoStart)
                        fb_status.UseGuardian = ( fb_status.ServerName.Find("fbguard") == ERROR_SUCCESS );
                        
                RegCloseKey (hkey);
            }
      }

#ifdef MANAGE_CLASSIC
      //Our look in the registry has probably given us 
      //the filename of the installed server
      if ( fb_status.ServerName.Find("fb_inet_server") == ERROR_SUCCESS )
      {
            fb_status.UseClassic = true;
      }
      if ( fb_status.ServerName.Find("fbserver") == ERROR_SUCCESS )
      {
            fb_status.UseClassic = false;
      }
      if ( fb_status.ServerName == "" ) 
      {
            // Nothing is stored in the registry so we must look to see if 
            // Firebird.conf has a preference
            fb_status.UseClassic = GetPreferredArchitecture();
      }
#endif
}


void CFBDialog::ApplyChanges()
/*
 *
 *    It all happens here.
 *
 *    With the addition of support for classic we now need to 
 *  evaluate 16 possible states.
 *
 */
{
      // Stop the update timer before doing anything else
      if (m_uiTimer) KillTimer(m_uiTimer);

      //find out what has changed and implement the changes
      try
      {     
      //Stage 1
            // Stop the Server 
            // We don't try to restart unless we were running
            // and we successfully stopped the server.
            if ( fb_status.WasRunning )
            {
                  if ( ServerStop() )
                  {
#if defined(_DEBUG)
                        // If we are in debug mode it is useful to 
                        // reset the display - but UpdateServerStatus
                        // resyncs new_settings with fb_status, so 
                        // it must never be called in ApplyChanges() 
                        // after this point.
                        UpdateServerStatus();
                        ProcessMessages();
#endif
                        new_settings.WasRunning = true;
                  }
                  else
                  {
                  //If we can't stop the server we should give up.
                        HandleError(0,"Failed to stop server. New settings will not be applied.");
                        throw;
                  }
            }


      //Stage 2 - Gather details of changes to make

            //Manage change to startup - from/to manual or auto
            bool ChangeStartType = false;
            ChangeStartType = (     ( (bool) fb_status.AutoStart &&  m_Manual_Start.GetCheck() ) || 
                  ((bool)  !fb_status.AutoStart &&  m_Auto_Start.GetCheck() ) );
            
            if ( ChangeStartType )
                  new_settings.AutoStart = !fb_status.AutoStart;
            else 
                  new_settings.AutoStart = fb_status.AutoStart;
            
#ifdef MANAGE_CLASSIC
            //Do we use Super Server or Classic
            bool ChangeServerArchitecture = false;
            ChangeServerArchitecture = ( ( (bool) !fb_status.UseClassic && m_Classic_Server.GetCheck() ) || 
                  ( (bool) fb_status.UseClassic && m_Super_Server.GetCheck() ) );
            if ( ChangeServerArchitecture )
                  new_settings.UseClassic = !fb_status.UseClassic;
            else
                  new_settings.UseClassic = fb_status.UseClassic;

            if (new_settings.UseClassic) 
            {
                  new_settings.ServiceExecutable = m_CS_Server_Name;
            }
            else
            {
                  new_settings.ServiceExecutable = m_SS_Server_Name;
            }
#endif

            //Do we change Guardian Usage?
            bool ChangeGuardianUse = false;
            ChangeGuardianUse = ( ( (bool) !fb_status.UseGuardian && m_Use_Guardian.GetCheck() ) || 
                  ( (bool) fb_status.UseGuardian && !m_Use_Guardian.GetCheck() ) );
            if ( ChangeGuardianUse )
                  new_settings.UseGuardian = !fb_status.UseGuardian;
            else
                  new_settings.UseGuardian = fb_status.UseGuardian;

            //Finally, test for change between service and application usage.
            bool ChangeRunStyle = false;
            ChangeRunStyle = ( ( (bool) fb_status.UseService && m_Run_As_Application.GetCheck() )  ||
                  ( !(bool) fb_status.UseService && m_Run_As_Service.GetCheck() ) );
            if (ChangeRunStyle)
                  new_settings.UseService = !fb_status.UseService;
            else
                  new_settings.UseService = fb_status.UseService;

            
      //Stage 3 - implement changes

#if !defined(_DEBUG)
            BeginWaitCursor();
#endif

            //Three things to do
            // a) First pull down what is already there
            if ( ChangeRunStyle || ChangeGuardianUse /* || ChangeServerArchitecture */)
            {
                  if ( fb_status.UseService )
                  {
                        ServiceRemove();
                  }
                  else
                        AppRemove();
            }

            
#ifdef FBCPL_UPDATE_CONF
            // b) update firebird.conf
            if ( ChangeGuardianUse )
            {
                  SetGuardianUseInConf( new_settings.UseGuardian );
            }
#endif
#ifdef MANAGE_CLASSIC
            if ( ChangeServerArchitecture )
            {
                  SetPreferredArchitectureInConf( new_settings.UseClassic );
            }
#endif

            // c) install the new configuration
            if ( ChangeRunStyle || ChangeGuardianUse 
#ifdef MANAGE_CLASSIC

                   || ChangeServerArchitecture 
#endif
                  )
            {
                  if ( new_settings.UseService )
                  {
                        ServiceInstall( new_settings );
                  }
                  else
                  {
                        AppInstall( new_settings );
                  }
            }
            else
            {
                  // We are not changing the run style and not changing guardian usage
                  // and we are not changing the server architecture so
                  // we only have the autostart setting left to change
                  SetAutoStart( new_settings );
            }

            if ( new_settings.WasRunning )
            {
                  ProcessMessages();
                  ServerStart( new_settings );
            }

            // If we haven't had a failure then we disable the apply button
            if ( m_Reset_Display_To_Existing_Values == false )
                  DisableApplyButton();

            // Update fb_status if we are running as an application
            if (( !new_settings.UseService ) && (ChangeGuardianUse))
                  fb_status.UseGuardian = !fb_status.UseGuardian;

            //And finally reset the m_error_status to zero;
            m_Error_Status = 0;

      }
      catch ( ... )
      {
            // Oops, something bad happened. Which 
            // means the apply button is still enabled.
            // We should probably do a reset here.

            m_Reset_Display_To_Existing_Values = true;
      }

#if !defined(_DEBUG)
    EndWaitCursor();
#endif

      //Whatever the outcome of ApplyChanges we need to refresh the dialog
      m_uiTimer = SetTimer( 1, 500, NULL );
}


void CFBDialog::ResetCheckBoxes(CFBDialog::STATUS status)
{
      if (( status.ServerStatus == IDS_APPLICATION_RUNNING ) ||
            ( status.ServerStatus == IDS_APPLICATION_STOPPED ))
      {
            m_Run_As_Application.SetCheck(1);
            m_Run_As_Service.SetCheck(0);
      }
      else
      {
            m_Run_As_Application.SetCheck(0);
            m_Run_As_Service.SetCheck(1);
      }
      
      //Now are we starting automatically or not?
      if (status.AutoStart)
      {
            m_Auto_Start.SetCheck(1);
            m_Manual_Start.SetCheck(0);
      }
      else
      {
            m_Auto_Start.SetCheck(0);
            m_Manual_Start.SetCheck(1);
      }
      
      m_Use_Guardian.SetCheck(status.UseGuardian);

#ifdef MANAGE_CLASSIC
      if ((status.UseClassic) )
      {
            m_Classic_Server.SetCheck(1);
            m_Super_Server.SetCheck(0);
      }
      else
      {
            m_Classic_Server.SetCheck(0);
            m_Super_Server.SetCheck(1);
      }
#endif

      // The server can now be controlled by a specific 
      // username/password. If it is set then for now we 
      // will disable all config options and add 
      // support at a later date.
/*    m_Classic_Server.EnableWindow( status.SystemLogin );
      m_Super_Server.EnableWindow( status.SystemLogin );
*/
      m_Auto_Start.EnableWindow( status.SystemLogin && fb_status.SufficientUserRights );
      m_Manual_Start.EnableWindow( status.SystemLogin && fb_status.SufficientUserRights );
      m_Run_As_Application.EnableWindow( status.SystemLogin && fb_status.SufficientUserRights );
      m_Run_As_Service.EnableWindow( status.SystemLogin && fb_status.SufficientUserRights );
      m_Use_Guardian.EnableWindow( status.SystemLogin && fb_status.SufficientUserRights );
      m_Button_Stop.EnableWindow( status.SystemLogin && fb_status.SufficientUserRights );
}


int CFBDialog::DatabasesConnected()
// Check if any databases are open on the server.
//**
//** Note: We really need a way of getting number of attachments
//** without having to enter a username / password.
//** This could be done by reading the LOCK_Header
//**
{
      int nDatabases = 0;
      return nDatabases;
}


bool CFBDialog::ServerStart( CFBDialog::STATUS status )
{
      bool result = false;

#if !defined(_DEBUG)
      BeginWaitCursor();
#endif

      if ( status.UseService ) 
      {
            char * service = "";
            char * display_name = "";
            if (status.UseGuardian)
            {
                  service = ISCGUARD_SERVICE;
                  display_name = ISCGUARD_DISPLAY_NAME;
            }
            else
            {
                  service = REMOTE_SERVICE;
                  display_name = REMOTE_DISPLAY_NAME;
            }

            OpenServiceManager(GENERIC_READ | GENERIC_EXECUTE | GENERIC_WRITE);
            if (hScManager)
            {
                  try
                  {
                        m_Error_Status = SERVICES_start (hScManager, service, display_name, 0, svc_error);
                        if (m_Error_Status == FB_SUCCESS)
                              result = true;
                  }
                  catch( ... ) 
                  {
                  }
            }
            CloseServiceManager();
      }
      else
      {
            try
            {
                  STARTUPINFO si;
                  SECURITY_ATTRIBUTES sa;
                  PROCESS_INFORMATION pi;
                  ZeroMemory (&si, sizeof(si));
                  si.cb = sizeof (si);
                  sa.nLength = sizeof (sa);
                  sa.lpSecurityDescriptor = NULL;
                  sa.bInheritHandle = TRUE;
                  
                  char full_name[MAX_PATH] = "";
                  GetFullAppPath( status, full_name );
                  
                  if (!CreateProcess (NULL, full_name, &sa, NULL, FALSE, 0, NULL, NULL, &si, &pi))
                        HandleError(0,"Application Start");
                  else
                        result = true;
            }
            catch( ... )
            {
            }
      }

#if !defined(_DEBUG)
    EndWaitCursor();
#endif

return result;
}


bool CFBDialog::ServerStop()
{
      bool result = false;

      if (!DatabasesConnected())
      {
            if ( fb_status.UseService )
            {
                  try
                  {
#if !defined(_DEBUG)
                        BeginWaitCursor();
#endif
                        OpenServiceManager( GENERIC_READ | GENERIC_EXECUTE | GENERIC_WRITE );

                        if (fb_status.UseGuardian)
                              m_Error_Status = SERVICES_stop(hScManager, ISCGUARD_SERVICE, ISCGUARD_DISPLAY_NAME, svc_error);
                        else
                              m_Error_Status = SERVICES_stop(hScManager, REMOTE_SERVICE, REMOTE_DISPLAY_NAME, svc_error);

                        result = !m_Error_Status;
            
                  }
                  catch (...) 
                  {
                        MessageBeep(-1);
                  }

                  CloseServiceManager();
#if !defined(_DEBUG)
                EndWaitCursor();
#endif
            }
            else
            {
                  try
                  {
#if !defined(_DEBUG)
                        BeginWaitCursor();
#endif
                        KillApp();
                        result = true;
                  }
                  catch (...) 
                  {
                  }
#if !defined(_DEBUG)
                EndWaitCursor();
#endif
            }
      }

      return result;
}


void CFBDialog::KillApp()
{
      // Under Win2K3 and WinXP there seem to be timing issues that don't 
      // exist in earlier platforms. Killing the server will kill the 
      // Guardian, but it won't always do it quickly enough for the CPL 
      // applet, so we try and do that before killing the server.
      LRESULT result;
      HWND hTmpWnd = GetGuardianHandle();
      if (hTmpWnd != NULL)
      {
            result = ::SendMessage(hTmpWnd, WM_CLOSE, 0, 0);
            ProcessMessages();
            hTmpWnd = NULL;
      }

      hTmpWnd = GetFirebirdHandle();
      if (hTmpWnd != NULL)
      {
            result = ::SendMessage(hTmpWnd, WM_CLOSE, 0, 0);
            ProcessMessages();
            hTmpWnd = NULL;
      }
}


bool CFBDialog::ServiceInstall( CFBDialog::STATUS status )
{                          
      char * ServerPath = const_cast<char *> ((LPCTSTR)m_Root_Path);

      OpenServiceManager( GENERIC_READ | GENERIC_EXECUTE | GENERIC_WRITE );

      if (hScManager)
      {
            if (new_settings.UseGuardian) 
            {
                  m_Error_Status = SERVICES_install (hScManager, ISCGUARD_SERVICE,
                        ISCGUARD_DISPLAY_NAME, ISCGUARD_DISPLAY_DESCR,
                        ISCGUARD_EXECUTABLE, ServerPath, NULL, status.AutoStart,
                        NULL, NULL, svc_error);
                  if (m_Error_Status != FB_SUCCESS)
                  {
                        CloseServiceManager();
                        return false;
                  }
                  
                  /* Set AutoStart to manual in preparation for installing the ib_server service */
                  status.AutoStart = false;
                  
            }
            /* do the install of server */
            m_Error_Status = SERVICES_install (hScManager, REMOTE_SERVICE,
                  REMOTE_DISPLAY_NAME, REMOTE_DISPLAY_DESCR,
                  const_cast<char *> ((LPCTSTR) status.ServiceExecutable), 
                  ServerPath, NULL, status.AutoStart, 
                  NULL, NULL, svc_error);
            if (m_Error_Status != FB_SUCCESS)
            {
                  CloseServiceManager();
                  try
                  {
                        ServiceRemove();
                        m_Reset_Display_To_Existing_Values = true;
                        EnableApplyButton();
                  }
                  catch ( ... )
                  {
                  }
                  
                  return false;
            }
            
            CloseServiceManager();
            return true;
      }
      else
            return false;
}


bool CFBDialog::ServiceRemove()
{
      OpenServiceManager( GENERIC_READ | GENERIC_EXECUTE | GENERIC_WRITE );
      if (hScManager)
      {
            m_Error_Status = SERVICES_remove (hScManager, ISCGUARD_SERVICE, 
                  ISCGUARD_DISPLAY_NAME, svc_error);
            if (m_Error_Status == IB_SERVICE_RUNNING)
            {
                  CloseServiceManager();
                  return false;
            }
            
            m_Error_Status = SERVICES_remove (hScManager, REMOTE_SERVICE, 
                  REMOTE_DISPLAY_NAME, svc_error);
            if (m_Error_Status == IB_SERVICE_RUNNING)
            {
                  CloseServiceManager();
                  return false;
            }
            CloseServiceManager();
            return true;
      }
      else
            return false;
}


bool CFBDialog::AppInstall( CFBDialog::STATUS status)
// This method is supplied as a corollary to ServiceInstall, 
// but doesn't do very much as there isn't much to do. 
{
      return ConfigureRegistryForApp( status );
}


bool CFBDialog::ConfigureRegistryForApp(CFBDialog::STATUS status)
{
      // The calling procedure will have already removed the 
      // service. All we need to do now
      // is configure the registry if AutoStart has been set.
      if ( status.AutoStart )
      {
            //Add line to registry 
            HKEY hkey;
            if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, 
                  "Software\\Microsoft\\Windows\\CurrentVersion\\Run", 
                  0, KEY_WRITE, &hkey) == ERROR_SUCCESS)
            {
                  
                  char full_name[MAX_PATH] = "";
                  GetFullAppPath( status, full_name);
                  if (!RegSetValueEx (hkey, "Firebird", 0,REG_SZ, (unsigned char *) full_name, sizeof(full_name) )  == ERROR_SUCCESS)
                  {
                        HandleError(0, "AppInstall");
                        return false;
                  }
            }
            else
            {
                  HandleError(0, "AppInstall");
                  return false;
            }
      }
      else
      {
            //Remove registry entry if set to start automatically on boot.
            HKEY hkey;
            if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, 
                  "Software\\Microsoft\\Windows\\CurrentVersion\\Run", 
                  0, KEY_QUERY_VALUE | KEY_WRITE, &hkey) == ERROR_SUCCESS)
                  
            {
                  if (RegQueryValueEx(hkey, "Firebird", NULL, NULL, NULL, NULL) 
                        == ERROR_SUCCESS)
                  {
                        if (RegDeleteValue(hkey, "Firebird") == ERROR_SUCCESS)
                              return true;
                        else
                        {
                              HandleError(0, "Removing registry entry to stop autorun failed.");
                              return false;
                        }
                  }
                  else
                  {
                        // If an error is thrown it must be because there is no
                        // entry in the registry so we shouldn't need to show an error.
                        return true;
                  }
            }
            else
            {
                  //Things are really bad - perhaps user has screwed up their registry?
                  HandleError(0, "Could not find HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Run in the registry.");
                  return false;
            }
      }

      return true;
}


bool CFBDialog::AppRemove()
{
      return ConfigureRegistryForApp( fb_status );
}


static USHORT svc_error (SLONG      error_status, TEXT *string, SC_HANDLE service)
//This code is for use with the SERVICES_ functions
{
      bool RaiseError = true;

      // process the kinds of errors we may be need to deal with quietly
      switch ( error_status )
      {
            case ERROR_SERVICE_CANNOT_ACCEPT_CTRL:
                  RaiseError = false;

            case ERROR_SERVICE_ALREADY_RUNNING:
                  RaiseError = false;

            case ERROR_SERVICE_DOES_NOT_EXIST:
                  RaiseError = false;
      }

      if (RaiseError)
             CFBDialog::HandleSvcError(error_status, string);
      
      if (service != NULL)
            CloseServiceHandle (service);

      return error_status;
}


void CFBDialog::ProcessMessages()
{
      MSG Msg;
      
      while (::PeekMessage(&Msg, NULL, 0, 0, PM_NOREMOVE))
      {
            if (!AfxGetApp()->PumpMessage())
            {
                  ::PostQuitMessage(0); 
                  return;
            }
      }

      LONG lIdle = 0;
      while (AfxGetApp()->OnIdle(lIdle++));
      return;
}


void CFBDialog::HandleSvcError(SLONG error_status, TEXT *string )
// This method supports the static svc_error() function
// and essentially duplicates HandleError. Oh to be rid of the 
// legacy code.
{
      if (!error_status)
            error_status = GetLastError();

      LPTSTR lpMsgBuf;
      DWORD Size;
      CString error_title = "";
      
      Size = FormatMessage( 
            FORMAT_MESSAGE_ALLOCATE_BUFFER | 
            FORMAT_MESSAGE_FROM_SYSTEM | 
            FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL,
            error_status,
            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
            (LPTSTR) &lpMsgBuf,     0, NULL );
      
      error_title.Format("Error Code %d raised in %s",error_status, (LPCTSTR) string );
      ::MessageBox( NULL, lpMsgBuf, (LPCTSTR) error_title, MB_OK | MB_ICONINFORMATION );
      LocalFree( lpMsgBuf );
}


void CFBDialog::HandleError(bool silent, TEXT *string )
{
      DWORD error_code = GetLastError();
      if (error_code == m_Error_Status)
      {
            //Always be silent if error has not already been thrown.
            silent = true;
      }
      else
      {
            m_Error_Status = error_code;
      }

      if (silent)
      {
            //And do what
      }
      else
      {
            LPTSTR lpMsgBuf;
            DWORD Size;
            CString error_title = "";

            Size = FormatMessage( 
                  FORMAT_MESSAGE_ALLOCATE_BUFFER | 
                  FORMAT_MESSAGE_FROM_SYSTEM | 
                  FORMAT_MESSAGE_IGNORE_INSERTS,
                  NULL,
                  error_code,
                  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
                  (LPTSTR) &lpMsgBuf,     0, NULL );
      
            error_title.Format("Error Code %d raised in %s",error_code, (LPCTSTR) string );

            ShowError(lpMsgBuf, error_title);

            LocalFree( lpMsgBuf );
      }
}


void CFBDialog::ShowError( LPTSTR lpMsgBuf, CString error_title )
{
      CFBDialog::MessageBox( lpMsgBuf, (LPCTSTR) error_title, MB_OK | MB_ICONINFORMATION );
}


void CFBDialog::OnButtonStop() 
{
      if ( fb_status.WasRunning )
            ServerStop();
      else  
            ServerStart( fb_status );
}


void CFBDialog::OnOK() 
{
      // Extra validation can be added here

      //if IDAPPLY is enabled then click IDAPPLY to apply changes before we close
      if (m_Apply.IsWindowEnabled())
      {
            OnApply();
      }
      
      CDialog::OnOK();
}


void CFBDialog::EnableApplyButton()
{
      m_Apply.EnableWindow(TRUE);
      m_Button_Stop.EnableWindow(FALSE);
}


void CFBDialog::DisableApplyButton()
{
      m_Apply.EnableWindow(FALSE);
      m_Button_Stop.EnableWindow(TRUE);
}


void CFBDialog::OnTimer(UINT nIDEvent) 
{
      UpdateServerStatus();
}


void CFBDialog::OnDestroy() 
{
      // Kill the update timer
      if (m_uiTimer) KillTimer(m_uiTimer);

      CDialog::OnDestroy();
}


void CFBDialog::OnService() 
{
      EnableApplyButton();
}


void CFBDialog::OnManualStart() 
{
      EnableApplyButton();
}


void CFBDialog::OnApplication() 
{
      EnableApplyButton();
}


void CFBDialog::OnAutoStart() 
{
      EnableApplyButton();
}


void CFBDialog::OnUseGuardian() 
{
      EnableApplyButton();
}


void CFBDialog::OnSuperServer() 
{
      EnableApplyButton();
}


void CFBDialog::OnClassicServer() 
{
      EnableApplyButton();
}


void CFBDialog::OnApply() 
{
      ApplyChanges();
}


#ifdef FBCPL_UPDATE_CONF
// Currently (Fb 1.5.1) there is no longer any 
// need to change the .conf file
void CFBDialog::SetGuardianUseInConf( bool UseGuardian )
{
      CString newvalue = "";
      if (UseGuardian)
            newvalue = "1";
      else
            newvalue = "0";

// One day the Config class will have set methods...
/*
      if (Config::setGuardianOption( UseGuardian ))
*/
      if (UpdateFirebirdConf("GuardianOption", newvalue ) )
      {
            // Do we assign here? or wait for the 
            // update status routine to pick this up?
            fb_status.UseGuardian = UseGuardian;
      }
      else
      {
            HandleError(0,"SetGuardianUseInConf");
            return;
      }
}

#ifdef MANAGE_CLASSIC
void CFBDialog::SetPreferredArchitectureInConf( bool UseClassic )
{
      CString newvalue = "";
      if ( UseClassic )
            newvalue = "1";
      else
            newvalue = "0";


// One day the Config class will have set methods...
/*
      if (Config::setPreferClassicServer( UseClassic ))
*/
      if ( UpdateFirebirdConf("PreferClassicServer", newvalue ) )
      {
            // Do we assign here? or wait for the 
            // update status routine to pick this up?
            fb_status.UseClassic = UseClassic;
      }
      else
      {
            HandleError(0,"SetPreferredArchitectureInConf");
            return;
      }
}
#endif

bool CFBDialog::UpdateFirebirdConf(CString option, CString value)
{
      bool result = false;
      
      CStdioFile FbConfFile, FbConfFileNew;
      CString FirebirdConfFilename = m_Root_Path + "firebird.conf";
      CString FirebirdConfNewname = FirebirdConfFilename + ".new";
      CString FirebirdConfOldname = FirebirdConfFilename + ".old";
      CString FirebirdConfLine = "";

      bool res;

      res = FbConfFile.Open(FirebirdConfFilename, CFile::modeReadWrite); 
      res = FbConfFileNew.Open(FirebirdConfNewname, CFile::modeCreate | 
                                          CFile::shareExclusive | CFile::modeWrite); 
      try
      {

            bool Found = false;
            int i = 0;

            while (FbConfFile.ReadString(FirebirdConfLine) != NULL)
            {

                  if (FirebirdConfLine.Find( option ) > -1 )
                  {
                        FirebirdConfLine = option + " = " + value;
                  }
      
                  FbConfFileNew.WriteString( FirebirdConfLine + '\n');
            
            }
      }
       catch (CFileException *e)
      {
    #ifdef _DEBUG
        afxDump << "Problem updating " << e->m_strFileName << ".\n \
                              cause = " << e->m_cause << "\n";
    #endif
      }
      

      FbConfFile.Close();
      FbConfFileNew.Close();

      CFile::Rename(FirebirdConfFilename, FirebirdConfFilename + ".old");
      
      try
      {
            CFile::Rename(FirebirdConfNewname, FirebirdConfFilename );
            
            //If we get this far then all is well and we can return good news
            result = true;
      }
      catch (CFileException*)
      {
            CFile::Rename(FirebirdConfOldname, FirebirdConfFilename);
      }

      //always try to delete the temporary old conf file.
      CFile::Remove(FirebirdConfOldname);

      return result;
}
#endif //#ifdef FBCPL_UPDATE_CONF


void CFBDialog::SetAutoStart( CFBDialog::STATUS status )
{
      if (status.UseService)
      {
            SC_LOCK sclLock; 
            DWORD dwStartType; 
            SC_HANDLE hService;
            
            OpenServiceManager( GENERIC_READ | GENERIC_EXECUTE | GENERIC_WRITE );
            // Need to acquire database lock before reconfiguring. 
            if (hScManager)
            {
                  sclLock = LockServiceDatabase(hScManager); 
                  
                  // If the database cannot be locked, report the details. 
                  if (sclLock == NULL) 
                  {
                        HandleError(NULL,"SetAutoStart - Could not lock service database"); 
                        return;
                  }
                  
                  // The database is locked, so it is safe to make changes. 
                  
                  char * service = "";
                  char * display_name = "";
                  
                  if ( status.UseGuardian )
                  {
                        service = ISCGUARD_SERVICE;
                        display_name = ISCGUARD_DISPLAY_NAME;
                  }
                  else
                  {
                        service = REMOTE_SERVICE;
                        display_name = REMOTE_DISPLAY_NAME;
                  }
                  
                  // Open a handle to the service. 
                  hService = OpenService( 
                        hScManager,                   // SCManager database 
                        service,                      // name of service 
                        SERVICE_CHANGE_CONFIG); // need CHANGE access 
                  if (hService) 
                  {           
                        dwStartType = ( status.AutoStart ) ? SERVICE_AUTO_START : SERVICE_DEMAND_START; 
                        
                        if (! ChangeServiceConfig( 
                              hService,               // handle of service 
                              SERVICE_NO_CHANGE,      // service type: no change 
                              dwStartType,            // change service start type 
                              SERVICE_NO_CHANGE,      // error control: no change 
                              NULL,                   // binary path: no change 
                              NULL,                   // load order group: no change 
                              NULL,                   // tag ID: no change 
                              NULL,                   // dependencies: no change 
                              NULL,                   // account name: no change 
                              NULL,                   // password: no change 
                              display_name ) )
                        {
                              HandleError(0,"ChangeServiceConfig in SetAutoStart"); 
                        }
                  }
                  else
                        HandleError(0,"OpenService in SetAutoStart"); 
                  
                  // Release the database lock. 
                  UnlockServiceDatabase(sclLock); 
                  
                  // Close the handle to the service. 
                  CloseServiceHandle(hService); 
            }

            CloseServiceManager();
      
      }
      else
      {
            ConfigureRegistryForApp( status );
      }
}


bool CFBDialog::FirebirdRunning()
/*
 * Check to see if Firebird is running as an application.
 */
{
      bool result = (bool) GetFirebirdHandle();
      bool guardian_running = (bool) GetGuardianHandle();;

      if ((result) && ( guardian_running ))
            fb_status.UseGuardian = guardian_running;

      return result;
}


HWND CFBDialog::GetFirebirdHandle()
{
      HWND result = NULL;
      result = GetSuperServerHandle();
#ifdef MANAGE_CLASSIC
      if ( !result )
      {
            result = GetClassicServerHandle();
      }
#endif
      return result;
}


HWND CFBDialog::GetSuperServerHandle()
{
      return ::FindWindow(szClassName, szWindowName);
}


#ifdef MANAGE_CLASSIC
HWND CFBDialog::GetClassicServerHandle()
{
      // oops - hard-coded string that is liable to change
      // Plus, the original definition is hidden locally
      // within a function in remote/windows (or whatever).
      return ::FindWindow( "FB_Disabled", szWindowName);
}
#endif

HWND CFBDialog::GetGuardianHandle()
{
      return ::FindWindow(GUARDIAN_CLASS_NAME, GUARDIAN_APP_LABEL);
}


bool CFBDialog::ServiceSupportAvailable()
{
      OSVERSIONINFO   OsVersionInfo;

      /* need to set the sizeof this structure for NT to work */
      OsVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);

      GetVersionEx ((LPOSVERSIONINFO) &OsVersionInfo);

      /* true for NT family, false for 95 family */
      return (OsVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT);
}


bool CFBDialog::OpenServiceManager( DWORD DesiredAccess )
{
      if (!fb_status.ServicesAvailable)
            return false;

      if (DesiredAccess == NULL)
            DesiredAccess = GENERIC_READ | GENERIC_EXECUTE | GENERIC_WRITE;

      if (hScManager == NULL)
            hScManager = OpenSCManager (NULL, SERVICES_ACTIVE_DATABASE, DesiredAccess );

      if (hScManager)
            return true;
      else
            return false;
}


void CFBDialog::CloseServiceManager()
{
      if (hScManager == NULL)
            return;

      try
      {
            CloseServiceHandle (hScManager);
      }
      catch (...)
      {
            // Err... what do we do now?
      }

      hScManager = NULL;
}


void CFBDialog::GetFullAppPath( CFBDialog::STATUS status, char * app)
// This returns the fully qualified path and name of the application 
// to start along with parameters -a and -c .
{
      CString AppName = m_Root_Path;

      if ( status.UseGuardian )
      {
            AppName += m_Guardian_Name;

#ifdef MANAGE_CLASSIC
            if (status.UseClassic) 
            {
                  AppName += ".exe -c -a";
            }
            else
#endif
            {
                  AppName += ".exe -a";
            }
      }
      else
      {
            GetServerName( status, AppName );
      }

      ::strcat(app,AppName);
}


void CFBDialog::GetServerName( CFBDialog::STATUS status, CString& AppName)
{
#ifdef MANAGE_CLASSIC
      if ( status.UseClassic )
      {
            AppName += m_CS_Server_Name;
      }
      else
#endif
      {
            AppName += m_SS_Server_Name;
      }

      AppName += ".exe -a";
}


#ifdef MANAGE_CLASSIC
bool CFBDialog::GetPreferredArchitecture()
{
      int option;
      if (!initialised)
            option = Config::getPreferredArchitecture();
      else
            if ((new_settings.UseClassic) != (fb_status.UseClassic))
                  option = new_settings.UseClassic;
            else
                  option = fb_status.UseClassic;

      return (bool) option;
}
#endif


bool CFBDialog::UserHasSufficientRights()
{
      bool HasRights = OpenServiceManager( NULL );
      CloseServiceManager();
      return HasRights;
}


Generated by  Doxygen 1.6.0   Back to index