[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1314
  • Last Modified:

How can I run a Windows Service sucessfully with ODBC connectivity and already installed third party DLL's?

Dear,
This is for the first time I am running my application as a Windows-Service using Visual Studio 6.0 (VC++). I have a separate workspace for installing, uninstalling and running the service. I am able to start multiple processes through CreateProcess() from the service. These processes as a standalone applications run correctly as they are using a third party SDK and ODBC driver. But when I start them through the service, then the application is unable to find the ODBC driver as I provide the "DSN" name for database connectivity.
I have all the third party DLL's and supported files present in a directory, say, "C:\Program Files\ThirdPartyTool\Bin" which is set in PATH environment variable. Similarly, I have a customized ODBC DLL, say, DynamicODBC.dll which is used by the application, say, "X" to connect to any database through a "DSN" name.

Now, "X" is called through "CreateProcess" through the service on start. When the initiated application complained about the third party DLL's, I copied all the required DLL's to the path of the same application. Then, it started throwing exception as it could not load ODBC driver and so could not connect to the database.

Now, I feel I am missing something for which it is searching for the DLL's/drivers. Do I need to register the DLL's? Do I need to change something in the service so that it can run with all environmental variables exported? Now, the service is running with following parameters to "CreateService":
=====================================================================
SC_HANDLE schService = CreateService
(
schSCManager,
pName,
pName,
SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS ,
SERVICE_AUTO_START,
SERVICE_ERROR_NORMAL,
pAppPathName,
NULL,
NULL,
NULL,
NULL,
NULL
);
======================================================

I start application inside the service with following series of statements:

====================================================================
LPTSTR ProcessNames[MAX_NUM_OF_PROCESS];

BOOL StartProcess(int ProcessIndex)
{
  STARTUPINFO startUpInfo = { sizeof(STARTUPINFO),NULL,"",NULL,0,0,0,0,0,0,0,
                                                   STARTF_USESHOWWINDOW,0,0,NULL,0,0,0};  
  startUpInfo.wShowWindow = SW_SHOW;
  startUpInfo.lpDesktop = NULL;
  WriteLog (pLogFile, "Creating process\n");
  if(CreateProcess(NULL, ProcessNames
                                   [ProcessIndex],NULL,NULL,FALSE,NORMAL_PRIORITY_CLASS,\
                                   NULL,NULL,&startUpInfo,&pProcInfo[ProcessIndex]))
  {
    WriteLog (pLogFile, ProcessNames[ProcessIndex]);
    WriteLog (pLogFile, "Process created\n");
    Sleep(1000);
    return TRUE;
  }
  else
  {
    long nError = GetLastError();
    char pTemp[256];
    sprintf(pTemp,"Failed to start program '%s', error code = %d\n", ProcessNames
                                                                                                       [ProcessIndex], nError);
    WriteLog(pLogFile, pTemp);
    return FALSE;
  }
}
==========================================================================

I need expert comments from you on the changes to be made to my service or my application so that I no need to copy the requried DLL's to the excutable path of the service. Why the DNS-based ODBC connectivity is failing when the service starts running?

Please help.

Thanks,
Rao
//  Service.cpp : Defines the entry point for the console application.
//
 
#include "stdafx.h"
 
#define    MAX_NUM_OF_PROCESS    2
/** Window Service **/
VOID ServiceMainProc();
VOID Install(char* pPath, char* pName);
VOID UnInstall(char* pName);
VOID WriteLog(char* pFile, char* pMsg);
BOOL KillService(char* pName);
BOOL RunService(char* pName);
VOID ExecuteSubProcess();
VOID ProcMonitorThread(VOID *);
BOOL StartProcess(int ProcessIndex);
VOID EndProcess(int ProcessIndex);
VOID AttachProcessNames();
 
VOID WINAPI ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv);
VOID WINAPI ServiceHandler(DWORD fdwControl);
 
 
/** Window Service **/
const int nBufferSize = 500;
CHAR pServiceName[nBufferSize+1];
CHAR pExeFile[nBufferSize+1];
CHAR lpCmdLineData[nBufferSize+1];
CHAR pLogFile[nBufferSize+1];
BOOL ProcessStarted = TRUE;
 
CRITICAL_SECTION    myCS;
SERVICE_TABLE_ENTRY    lpServiceStartTable[] = 
{
  {pServiceName, ServiceMain},
  {NULL, NULL}
};
 
LPTSTR ProcessNames[MAX_NUM_OF_PROCESS];
 
SERVICE_STATUS_HANDLE   hServiceStatusHandle; 
SERVICE_STATUS          ServiceStatus; 
PROCESS_INFORMATION  pProcInfo[MAX_NUM_OF_PROCESS];
 
int _tmain(int argc, _TCHAR* argv[])
{
  if(argc >= 2)
    strcpy(lpCmdLineData, argv[1]);
  ServiceMainProc();
  return 0;
}
 
VOID ServiceMainProc()
{
  ::InitializeCriticalSection(&myCS);
  // initialize variables for .exe and .log file names
  char pModuleFile[nBufferSize+1];
  DWORD dwSize = GetModuleFileName(NULL, pModuleFile, nBufferSize);
  pModuleFile[dwSize] = 0;
  if(dwSize>4 && pModuleFile[dwSize-4] == '.')
  {
    sprintf(pExeFile,"%s",pModuleFile);
    pModuleFile[dwSize-4] = 0;
    sprintf(pLogFile,"%s.log",pModuleFile);
  }
  strcpy(pServiceName,"SampleService");
 
  if(_stricmp("-i",lpCmdLineData) == 0 || _stricmp("-I",lpCmdLineData) == 0)
    Install(pExeFile, pServiceName);
  else if(_stricmp("-k",lpCmdLineData) == 0 || _stricmp("-K",lpCmdLineData) == 0)
    KillService(pServiceName);
  else if(_stricmp("-u",lpCmdLineData) == 0 || _stricmp("-U",lpCmdLineData) == 0)
    UnInstall(pServiceName);
  else if(_stricmp("-s",lpCmdLineData) == 0 || _stricmp("-S",lpCmdLineData) == 0)
    RunService(pServiceName);
  else
    ExecuteSubProcess();
}
 
VOID Install(char* pPath, char* pName)
{  
  SC_HANDLE schSCManager = OpenSCManager( NULL, NULL, SC_MANAGER_CREATE_SERVICE); 
  if (schSCManager==0) 
  {
    long nError = GetLastError();
    char pTemp[121];
    sprintf(pTemp, "OpenSCManager failed, error code = %d\n", nError);
    WriteLog(pLogFile, pTemp);
  }
  else
  {
    SC_HANDLE schService = CreateService
    ( 
      schSCManager,  /* SCManager database      */ 
      pName,      /* name of service         */ 
      pName,      /* service name to display */ 
      SERVICE_ALL_ACCESS,        /* desired access          */ 
      SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS , /* service type            */ 
      SERVICE_AUTO_START,      /* start type              */ 
      SERVICE_ERROR_NORMAL,      /* error control type      */ 
      pPath,      /* service's binary        */ 
      NULL,                      /* no load ordering group  */ 
      NULL,                      /* no tag identifier       */ 
      NULL,                      /* no dependencies         */ 
      NULL,                      /* LocalSystem account     */ 
      NULL
    );                     /* no password             */ 
    if (schService==0) 
    {
      long nError =  GetLastError();
      char pTemp[121];
      sprintf(pTemp, "Failed to create service %s, error code = %d\n", pName, nError);
      WriteLog(pLogFile, pTemp);
    }
    else
    {
      char pTemp[121];
      sprintf(pTemp, "Service %s installed\n", pName);
      WriteLog(pLogFile, pTemp);
      CloseServiceHandle(schService); 
    }
    CloseServiceHandle(schSCManager);
  }  
}
 
VOID UnInstall(char* pName)
{
  SC_HANDLE schSCManager = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS); 
  if (schSCManager==0) 
  {
    long nError = GetLastError();
    char pTemp[121];
    sprintf(pTemp, "OpenSCManager failed, error code = %d\n", nError);
    WriteLog(pLogFile, pTemp);
  }
  else
  {
    SC_HANDLE schService = OpenService( schSCManager, pName, SERVICE_ALL_ACCESS);
    if (schService==0) 
    {
      long nError = GetLastError();
      char pTemp[121];
      sprintf(pTemp, "OpenService failed, error code = %d\n", nError);
      WriteLog(pLogFile, pTemp);
    }
    else
    {
      if(!DeleteService(schService)) 
      {
        char pTemp[121];
        sprintf(pTemp, "Failed to delete service %s\n", pName);
        WriteLog(pLogFile, pTemp);
      }
      else 
      {
        char pTemp[121];
        sprintf(pTemp, "Service %s removed\n",pName);
        WriteLog(pLogFile, pTemp);
      }
      CloseServiceHandle(schService); 
    }
    CloseServiceHandle(schSCManager);  
  }
  DeleteFile(pLogFile);
}
 
VOID WriteLog(char* pFile, char* pMsg)
{
  // write error or other information into log file
  ::EnterCriticalSection(&myCS);
  try
  {
    SYSTEMTIME oT;
    ::GetLocalTime(&oT);
    FILE* pLog = fopen(pFile,"a");
    fprintf(pLog,"%02d/%02d/%04d, %02d:%02d:%02d\n    %s",oT.wMonth,oT.wDay,oT.wYear,oT.wHour,oT.wMinute,oT.wSecond,pMsg); 
    fclose(pLog);
  } catch(...) {}
  ::LeaveCriticalSection(&myCS);
}
 
BOOL KillService(char* pName) 
{ 
  // kill service with given name
  SC_HANDLE schSCManager = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS); 
  if (schSCManager==0) 
  {
    long nError = GetLastError();
    char pTemp[121];
    sprintf(pTemp, "OpenSCManager failed, error code = %d\n", nError);
    WriteLog(pLogFile, pTemp);
  }
  else
  {
    // open the service
    SC_HANDLE schService = OpenService( schSCManager, pName, SERVICE_ALL_ACCESS);
    if (schService==0) 
    {
      long nError = GetLastError();
      char pTemp[121];
      sprintf(pTemp, "OpenService failed, error code = %d\n", nError);
      WriteLog(pLogFile, pTemp);
    }
    else
    {
      // call ControlService to kill the given service
      SERVICE_STATUS status;
      if(ControlService(schService,SERVICE_CONTROL_STOP,&status))
      {
        CloseServiceHandle(schService); 
        CloseServiceHandle(schSCManager); 
        return TRUE;
      }
      else
      {
        long nError = GetLastError();
        char pTemp[121];
        sprintf(pTemp, "ControlService failed, error code = %d\n", nError);
        WriteLog(pLogFile, pTemp);
      }
      CloseServiceHandle(schService); 
    }
    CloseServiceHandle(schSCManager); 
  }
  return FALSE;
}
 
BOOL RunService(char* pName) 
{ 
  // run service with given name
  SC_HANDLE schSCManager = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS); 
  if (schSCManager==0) 
  {
    long nError = GetLastError();
    char pTemp[121];
    sprintf(pTemp, "OpenSCManager failed, error code = %d\n", nError);
    WriteLog(pLogFile, pTemp);
  }
  else
  {
    // open the service
    SC_HANDLE schService = OpenService( schSCManager, pName, SERVICE_ALL_ACCESS);
    if (schService==0) 
    {
      long nError = GetLastError();
      char pTemp[121];
      sprintf(pTemp, "OpenService failed, error code = %d\n", nError);
      WriteLog(pLogFile, pTemp);
    }
    else
    {
      // call StartService to run the service
      if(StartService(schService, 0, (const char**)NULL))
      {
        CloseServiceHandle(schService); 
        CloseServiceHandle(schSCManager); 
        return TRUE;
      }
      else
      {
        long nError = GetLastError();
        char pTemp[121];
        sprintf(pTemp, "StartService failed, error code = %d\n", nError);
        WriteLog(pLogFile, pTemp);
      }
      CloseServiceHandle(schService); 
    }
    CloseServiceHandle(schSCManager); 
  }
  return FALSE;
}
 
 
VOID ExecuteSubProcess()
{
  if(_beginthread(ProcMonitorThread, 0, NULL) == -1)
  {
    long nError = GetLastError();
    char pTemp[121];
    sprintf(pTemp, "StartService failed, error code = %d\n", nError);
    WriteLog(pLogFile, pTemp);
  }
  if(!StartServiceCtrlDispatcher(lpServiceStartTable))
  {
    long nError = GetLastError();
    char pTemp[121];
    sprintf(pTemp, "StartServiceCtrlDispatcher failed, error code = %d\n", nError);
    WriteLog(pLogFile, pTemp);
  }
  ::DeleteCriticalSection(&myCS);
}
 
VOID WINAPI ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv)
{
  DWORD   status = 0; 
    DWORD   specificError = 0xfffffff; 
 
    ServiceStatus.dwServiceType        = SERVICE_WIN32; 
    ServiceStatus.dwCurrentState       = SERVICE_START_PENDING; 
    ServiceStatus.dwControlsAccepted   = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_PAUSE_CONTINUE; 
    ServiceStatus.dwWin32ExitCode      = 0; 
    ServiceStatus.dwServiceSpecificExitCode = 0; 
    ServiceStatus.dwCheckPoint         = 0; 
    ServiceStatus.dwWaitHint           = 0; 
 
    hServiceStatusHandle = RegisterServiceCtrlHandler(pServiceName, ServiceHandler); 
    if (hServiceStatusHandle==0) 
    {
      long nError = GetLastError();
      char pTemp[121];
      sprintf(pTemp, "RegisterServiceCtrlHandler failed, error code = %d\n", nError);
      WriteLog(pLogFile, pTemp);
      return; 
    } 
 
    // Initialization complete - report running status 
    ServiceStatus.dwCurrentState       = SERVICE_RUNNING; 
    ServiceStatus.dwCheckPoint         = 0; 
    ServiceStatus.dwWaitHint           = 0;  
    if(!SetServiceStatus(hServiceStatusHandle, &ServiceStatus)) 
    { 
      long nError = GetLastError();
      char pTemp[121];
      sprintf(pTemp, "SetServiceStatus failed, error code = %d\n", nError);
      WriteLog(pLogFile, pTemp);
    } 
 
  AttachProcessNames();
  for(int iLoop = 0; iLoop < MAX_NUM_OF_PROCESS; iLoop++)
  {
    pProcInfo[iLoop].hProcess = 0;
    StartProcess(iLoop);
  }
}
 
VOID AttachProcessNames()
{
  LPTSTR lpszpath;
  lpszpath = new char[nBufferSize];
  memset(lpszpath,0x00,sizeof(lpszpath));
  DWORD dwSize = GetModuleFileName(NULL, lpszpath, nBufferSize);
  lpszpath[dwSize] = 0;
  while(lpszpath[dwSize] != '\\' && dwSize != 0)
  {
    lpszpath[dwSize] = 0; dwSize--;
  }
  for(int iLoop = 0; iLoop < MAX_NUM_OF_PROCESS; iLoop++)
  {
    ProcessNames[iLoop] = (char*) malloc(nBufferSize);
    memset(ProcessNames[iLoop], 0x00, nBufferSize);
    strcpy(ProcessNames[iLoop],lpszpath); 
  }
  WriteLog (pLogFile, "ProcessNames to be written\n");
  strcat(ProcessNames[0], "ODBC_ConsoleApp_PgPCM_High.exe -dsn 195ServerDb -d V: -duser mysql");
  strcat(ProcessNames[1], "ODBC_ConsoleApp_PgPCM_High.exe -dsn 195ServerDb -d V: -duser mysql");
 
}
 
VOID WINAPI ServiceHandler(DWORD fdwControl)
{
  switch(fdwControl) 
  {
    case SERVICE_CONTROL_STOP:
    case SERVICE_CONTROL_SHUTDOWN:
      ProcessStarted = FALSE;
      ServiceStatus.dwWin32ExitCode = 0; 
      ServiceStatus.dwCurrentState  = SERVICE_STOPPED; 
      ServiceStatus.dwCheckPoint    = 0; 
      ServiceStatus.dwWaitHint      = 0;
      // terminate all processes started by this service before shutdown
      {
        for(int i = MAX_NUM_OF_PROCESS - 1 ; i >= 0; i--)
        {
          EndProcess(i);
          delete ProcessNames[i];
        }      
      }
      break; 
    case SERVICE_CONTROL_PAUSE:
      ServiceStatus.dwCurrentState = SERVICE_PAUSED; 
      break;
    case SERVICE_CONTROL_CONTINUE:
      ServiceStatus.dwCurrentState = SERVICE_RUNNING; 
      break;
    case SERVICE_CONTROL_INTERROGATE:
      break;
    default:
      if(fdwControl>=128&&fdwControl<256)
      {
        int nIndex = fdwControl&0x7F;
        // bounce a single process
        if(nIndex >= 0 && nIndex < MAX_NUM_OF_PROCESS)
        {
          EndProcess(nIndex);
          StartProcess(nIndex);
        }
        // bounce all processes
        else if(nIndex==127)
        {
          for(int i = MAX_NUM_OF_PROCESS-1; i >= 0; i--)
          {
            EndProcess(i);
          }
          for(i = 0; i < MAX_NUM_OF_PROCESS; i++)
          {
            StartProcess(i);
          }
        }
      }
      else
      {
        char pTemp[121];
        sprintf(pTemp,  "Unrecognized opcode %d\n", fdwControl);
        WriteLog(pLogFile, pTemp);
      }
  };
  if (!SetServiceStatus(hServiceStatusHandle,  &ServiceStatus)) 
  { 
    long nError = GetLastError();
    char pTemp[121];
    sprintf(pTemp, "SetServiceStatus failed, error code = %d\n", nError);
    WriteLog(pLogFile, pTemp);
  } 
}
BOOL StartProcess(int ProcessIndex)
{
  STARTUPINFO startUpInfo = { sizeof(STARTUPINFO),NULL,"",NULL,0,0,0,0,0,0,0,STARTF_USESHOWWINDOW,0,0,NULL,0,0,0};  
  startUpInfo.wShowWindow = SW_SHOW;
  startUpInfo.lpDesktop = NULL;
  WriteLog (pLogFile, "Creating process\n");
  if(CreateProcess(NULL, ProcessNames[ProcessIndex],NULL,NULL,FALSE,NORMAL_PRIORITY_CLASS,\
           NULL,NULL,&startUpInfo,&pProcInfo[ProcessIndex]))
  {
    WriteLog (pLogFile, ProcessNames[ProcessIndex]);
    WriteLog (pLogFile, "Process created\n");
    Sleep(1000);
    return TRUE;
  }
  else
  {
    long nError = GetLastError();
    char pTemp[256];
    sprintf(pTemp,"Failed to start program '%s', error code = %d\n", ProcessNames[ProcessIndex], nError); 
    WriteLog(pLogFile, pTemp);
    return FALSE;
  }
}
 
 
VOID EndProcess(int ProcessIndex)
{
  if(ProcessIndex >=0 && ProcessIndex <= MAX_NUM_OF_PROCESS)
  {
    if(pProcInfo[ProcessIndex].hProcess)
    {
      // post a WM_QUIT message first
      PostThreadMessage(pProcInfo[ProcessIndex].dwThreadId, WM_QUIT, 0, 0);
      Sleep(1000);
      // terminate the process by force
      TerminateProcess(pProcInfo[ProcessIndex].hProcess, 0);
    }
  }
}
VOID ProcMonitorThread(VOID *)
{
  while(ProcessStarted == TRUE)
  {
    DWORD dwCode;
    for(int iLoop = 0; iLoop < MAX_NUM_OF_PROCESS; iLoop++)
    {
      if(::GetExitCodeProcess(pProcInfo[iLoop].hProcess, &dwCode) && pProcInfo[iLoop].hProcess != NULL)
      {
        if(dwCode != STILL_ACTIVE)
        {
          if(StartProcess(iLoop))
          {
            char pTemp[121];
            sprintf(pTemp, "Restarted process %d\n", iLoop);
            WriteLog(pLogFile, pTemp);
          }
        }
      }
    }
  }
}

Open in new window

0
rrajeshekhar
Asked:
rrajeshekhar
1 Solution
 
StefanKittelCommented:
Hello,

think about the enviroment when running.
A dervice does not run in your security context. So everthing configured to your user does not exists. Maybe the DSN is a user-DSN or the security conext from your service does not allow to run this.

the dlls should be registerd during install.
You can register it using regsvr32 or better using the api function.
Have a look at innosetup for installing with dll register.

Stefan
0
 
jkrCommented:
>>Why the DNS-based ODBC connectivity is failing when the service starts
>>running?

Your problem is that services running under the 'LocalSystem' account have almost OS privileges, but are not allowed to use _any_ networking facilities. To overcome this, make sure to assign your service to run under a predefined user account (preferrably one belonging to the admin group) which does have network access (this is usually done by specifying an account name&password in the call to 'CreateService()', but you're also able to change this from the 'services' control panel applet).
0

Featured Post

Visualize your virtual and backup environments

Create well-organized and polished visualizations of your virtual and backup environments when planning VMware vSphere, Microsoft Hyper-V or Veeam deployments. It helps you to gain better visibility and valuable business insights.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now