Thread: Changing a program into a Win Service

  1. #1
    Registered User
    Join Date
    May 2007
    Posts
    17

    Changing a program into a Win Service

    Hi,

    I've finished coding a program a few days before. It has a WinMain function, a window procedure function and a couple of more. Now the problem is I have decided to run it as a service. But before attempting to change the code I wanted to ask you for easy ways of doing it.

    It can install it's service fine, but starting it gives an 1053 error, as it lacks necessary functions for the service to work. It would be appreciated if you show me a simple way of running the program as a service, with minimal amount of modifications.

    Thanks...

  2. #2
    Malum in se abachler's Avatar
    Join Date
    Apr 2007
    Posts
    3,195
    You have to start a project intending it to be a service. There is no way to convert a windows application into a service. They are completely different project types. Services are actually closer to console applications. What exactly do you want the service to do for you, and why do you need it to run as a service, as apposed to a regular application?

    Writing a system service is not trivial, so im just trying to help you figure out whether you truly need to do so.

  3. #3
    Registered User
    Join Date
    May 2007
    Posts
    17
    It already has no visible windows. It runs completely in the background. I use it for HTTP tunneling and it needs to be running all the time. So I thought setting it up as a service would be a good idea.

    It may not be the only choice but I want to try it, at least.

  4. #4
    Registered User
    Join Date
    Apr 2007
    Posts
    137
    Quote Originally Posted by abachler View Post
    There is no way to convert a windows application into a service.
    Of course, there is.
    And for > 10 years !

  5. #5
    Registered User
    Join Date
    Mar 2005
    Location
    Mountaintop, Pa
    Posts
    1,058

  6. #6
    Registered User
    Join Date
    May 2007
    Posts
    17
    Well, I made some progress today and set program's WinMain as the service's main function. I was able to start the service and it was working OK, but now I made some changes and StartServiceCtrlDispatcher(); returns ERROR_FAILED_SERVICE_CONTROLLER_CONNECT.

    I call this function in the main() and just after a few calls and initializations. I will try to undo those changes now, and hopefully find where it fails.

    Note: Are there things that I shouldn't do before calling StartServiceCtrlDispatcher();, except waiting for 30 seconds?
    Last edited by phal; 07-26-2008 at 06:28 AM.

  7. #7
    Registered User
    Join Date
    May 2007
    Posts
    17
    I got it working today. SERVICE_INTERACTIVE_PROCESS was used with SERVICE_WIN32_OWN_PROCESS while installing the service with CreateService(). I could even create a visible window this way.

    Now the only problem is, not a big one though, I can't start the service by starting the executable. It needs to be started from the Service Manager. I will need to figure out how to fix this.

    Thanks to all who have answered...

  8. #8
    Registered User
    Join Date
    Apr 2007
    Posts
    137
    As I said, you don't need at all to convert it to a service.
    Use the MS Tool which does all the job, for any Win32 app.
    Done in 2 minutes.

  9. #9
    Registered User
    Join Date
    Mar 2005
    Location
    Mountaintop, Pa
    Posts
    1,058
    It needs to be started from the Service Manager. I will need to figure out how to fix this.
    Code:
    #pragma comment( lib, "advapi32.lib" ) 
    #include <stdio.h>
    #include <windows.h>
    #include <winsvc.h>
    #include <lmerr.h>
    
    VOID DisplayErrorText(DWORD dwLastError )
    {
        HMODULE hModule = NULL; // default to system source
        LPSTR MessageBuffer;
        DWORD dwBufferLength;
    
        DWORD dwFormatFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER |
            FORMAT_MESSAGE_IGNORE_INSERTS |
            FORMAT_MESSAGE_FROM_SYSTEM ;
    
        if(dwLastError >= NERR_BASE && dwLastError <= MAX_NERR) {
            hModule = LoadLibraryEx(
                TEXT("netmsg.dll"),
                NULL,
                LOAD_LIBRARY_AS_DATAFILE
                );
            if(hModule != NULL)
                dwFormatFlags |= FORMAT_MESSAGE_FROM_HMODULE;
        }
        if(dwBufferLength = FormatMessageA(
            dwFormatFlags,
            hModule, // module to get message from (NULL == system)
            dwLastError,
            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // default language
            (LPSTR) &MessageBuffer,
            0,
            NULL
            ))
        {
            DWORD dwBytesWritten;
            WriteFile(
                GetStdHandle(STD_ERROR_HANDLE),
                MessageBuffer,
                dwBufferLength,
                &dwBytesWritten,
                NULL
                );
            LocalFree(MessageBuffer);
        }
        if(hModule != NULL)
            FreeLibrary(hModule);
    }
    
    BOOL LaterOSVersion(void)
    {
        OSVERSIONINFOEX osvi;
        BOOL bOsVersionInfoEx;
        // Try calling GetVersionEx using the OSVERSIONINFOEX structure.
        // If that fails, try using the OSVERSIONINFO structure.
        ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
        osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
        if( !(bOsVersionInfoEx = GetVersionEx ((OSVERSIONINFO *) &osvi)) )
        {
            osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
            if (! GetVersionEx ( (OSVERSIONINFO *) &osvi) ) 
                return FALSE;
        }
        if ( osvi.dwMajorVersion <= 4 )
            return FALSE;
        else
            return TRUE; 
    }
    
    
    VOID Install(char* pPath, char* pName, char *pComputerName) 
    {  
        SERVICE_DESCRIPTION sdBuf;
        SC_HANDLE schService;
    
        SC_HANDLE schSCManager = OpenSCManager( pComputerName, NULL, SC_MANAGER_CREATE_SERVICE); 
        if (schSCManager==0) 
        {
            DWORD dwError = GetLastError();
            DisplayErrorText(dwError );
        }
        else
        {
            schService = CreateService
                ( 
                schSCManager,   /* SCManager database      */ 
                pName,          /* name of service         */ 
                pName,          /* service name to display */ 
                SERVICE_ALL_ACCESS,        /* desired access          */ 
                SERVICE_WIN32_OWN_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) 
            {
                DWORD dwError = GetLastError();
                DisplayErrorText(dwError );
            }
            else
            {
                printf("Service %s installed\n", pName);
                sdBuf.lpDescription = "MyService  It does what it's supposed to";
                if( LaterOSVersion() == TRUE)
                {
                    if( !ChangeServiceConfig2
                        (
                        schService,                 // handle to service
                        SERVICE_CONFIG_DESCRIPTION, // change: description
                        &sdBuf) )                   // value: new description
                    {
                        DWORD dwError =  GetLastError();
                        DisplayErrorText(dwError );
                    }
                }
            }
            CloseServiceHandle(schService); 
            CloseServiceHandle(schSCManager);
        }   
    }
    
    VOID UnInstall(char* pName,char *pComputerName)
    {
        DWORD dwError;
        SC_HANDLE schSCManager = OpenSCManager( pComputerName, NULL, SC_MANAGER_ALL_ACCESS); 
        if (schSCManager == 0) 
        {
            dwError = GetLastError();
            DisplayErrorText(dwError );
        }
        else
        {
            SC_HANDLE schService = OpenService( schSCManager, pName, SERVICE_ALL_ACCESS);
            if (schService==0) 
            {
                dwError = GetLastError();
                DisplayErrorText(dwError );
            }
            else
            {
                if(!DeleteService(schService)) 
                {
                    dwError = GetLastError();
                    DisplayErrorText(dwError );
                }
                else 
                {
                    printf("Service %s removed\n",pName);   
                }
                CloseServiceHandle(schService); 
            }
            CloseServiceHandle(schSCManager);   
        }
    }
    
    BOOL KillService(char* pName, char *pComputerName) 
    { 
        DWORD dwError, dwTimeout= 0;
        SERVICE_STATUS ss;
        DWORD dwStartTime = GetTickCount();
        DWORD dwBytesNeeded;
    
        SC_HANDLE schSCManager = OpenSCManager( pComputerName, NULL, SC_MANAGER_ALL_ACCESS); 
        if (schSCManager==0) 
        {
            dwError = GetLastError();
            DisplayErrorText(dwError );
        }
        else
        {
            SC_HANDLE schService = OpenService( schSCManager, pName, SERVICE_ALL_ACCESS);
            if (schService==0) 
            {
                dwError = GetLastError();
                DisplayErrorText(dwError );
            }
            else
            {
                // Make sure the service is not already stopped
                QueryServiceStatusEx( 
                    schService, 
                    SC_STATUS_PROCESS_INFO,
                    (LPBYTE)&ss, 
                    sizeof(SC_STATUS_PROCESS_INFO),
                    &dwBytesNeeded );
                if ( ss.dwCurrentState == SERVICE_STOPPED ) 
                    return TRUE;
                // If a stop is pending, just wait for it
                while ( ss.dwCurrentState == SERVICE_STOP_PENDING ) 
                {
                    Sleep( ss.dwWaitHint );
                    if ( !QueryServiceStatusEx( 
                        schService, 
                        SC_STATUS_PROCESS_INFO,
                        (LPBYTE)&ss, 
                        sizeof(SC_STATUS_PROCESS_INFO),
                        &dwBytesNeeded ) )
                        return FALSE;
                    if ( ss.dwCurrentState == SERVICE_STOPPED )
                        return TRUE;
                    if ( GetTickCount() - dwStartTime > dwTimeout )
                        return FALSE;
                }
                // call ControlService to kill the given service
                SERVICE_STATUS status;
                if(ControlService(schService,SERVICE_CONTROL_STOP,&status))
                {
                    CloseServiceHandle(schService); 
                    CloseServiceHandle(schSCManager); 
                    printf("%s killed\n",pName);  
                    return TRUE;
                }
                else
                {
                    dwError = GetLastError();
                    DisplayErrorText(dwError );
                }
                CloseServiceHandle(schService); 
            }
            CloseServiceHandle(schSCManager); 
        }
        return FALSE;
    }
    
    BOOL RunService(char* pName, int nArg, char** pArg, char *pComputerName) 
    { 
        DWORD  dwError = 0l;
    
        SC_HANDLE schSCManager = OpenSCManager( pComputerName, NULL, SC_MANAGER_ALL_ACCESS); 
        if (schSCManager==0) 
        {
            dwError = GetLastError();
            DisplayErrorText(dwError );
        }
        else
        {
            // open the service
            SC_HANDLE schService = OpenService( schSCManager, pName, SERVICE_ALL_ACCESS);
            if (schService==0) 
            {
                dwError = GetLastError();
                DisplayErrorText(dwError );
            }
            else
            {
                // call StartService to run the service
                if(StartService(schService,nArg,(const char**)pArg))
                {
                    CloseServiceHandle(schService); 
                    CloseServiceHandle(schSCManager); 
                    printf("%s has succesfully started", pName);
                    return TRUE;
                }
                else
                {
                    dwError = GetLastError();
                    DisplayErrorText(dwError );
                }
                CloseServiceHandle(schService); 
            }
            CloseServiceHandle(schSCManager); 
        }
        return FALSE;
    }
    
    INT main(VOID)
    {
        char ServiceName[] = {"MyService"};
        char ServiceExecutable[] = {"C:\\Temp\\MyService.exe"};
        Install(ServiceExecutable, ServiceName,   NULL);
        RunService(ServiceName,0,NULL,  NULL);
        //   KillService(ServiceName,    NULL);
        //   UnInstall(ServiceName,  NULL);      
        return 0;
    }

  10. #10
    Registered User
    Join Date
    May 2007
    Posts
    17
    Thank you BobS0327. But I didn't understand how i can start the service from it's own PE file. This code is for starting a service that has another executable, isn't it? Correct me if I got it wrong.

  11. #11
    Registered User
    Join Date
    Mar 2005
    Location
    Mountaintop, Pa
    Posts
    1,058
    This code is for starting a service that has another executable, isn't it? Correct me if I got it wrong.
    The code above is just a binary that installs and starts a service. Thus, MyService.exe is the actual service which has an entry point entitled ServiceMain as opposed to the typical main or WinMain entry point.

    I don't think it's possible to start a service from within itself. Primarily because it would need two entry points. WinMain or main which is needed to install and start the service and ServiceMain which is the actual service entry point. Maybe there is a trick to doing this. But I'm just not aware of it.

  12. #12
    Registered User
    Join Date
    May 2007
    Posts
    17
    OK, thank you again. That didn't seem easily possible to me, too.

  13. #13
    Malum in se abachler's Avatar
    Join Date
    Apr 2007
    Posts
    3,195
    Quote Originally Posted by BobS0327 View Post
    The code above is just a binary that installs and starts a service. Thus, MyService.exe is the actual service which has an entry point entitled ServiceMain as opposed to the typical main or WinMain entry point.

    I don't think it's possible to start a service from within itself. Primarily because it would need two entry points. WinMain or main which is needed to install and start the service and ServiceMain which is the actual service entry point. Maybe there is a trick to doing this. But I'm just not aware of it.
    You can have a service that installs itself. I do it all teh time. Ill dig up my nonproprietary version and post it.

  14. #14
    Registered User
    Join Date
    May 2007
    Posts
    17
    Quote Originally Posted by abachler View Post
    You can have a service that installs itself. I do it all teh time. Ill dig up my nonproprietary version and post it.
    Well, I can install it within itself, but the thing is, it can't start itself from it's own process.

  15. #15
    Registered User
    Join Date
    Mar 2005
    Location
    Mountaintop, Pa
    Posts
    1,058
    My approach to installing and starting a service from one binary is to embed the service binary in the installation binary by using a resource file. The installation binary would be a self deleting binary. So, after the the installation binary extracts the service binary and installs/starts the service binary, it would self delete.

    Having a service binary install and start itself is a very interesting concept. I'd like to see a example of how this works.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. program run as service
    By statquos in forum C++ Programming
    Replies: 2
    Last Post: 06-02-2008, 11:43 AM
  2. Re-running program! displayed unreadable charactes.. HELP PLS
    By rzr.copperhead in forum C++ Programming
    Replies: 3
    Last Post: 04-03-2008, 03:39 AM
  3. Win Console program environment variable
    By C3Pnuts in forum C Programming
    Replies: 2
    Last Post: 05-23-2005, 02:08 PM
  4. I need some help with my program please.
    By agentxx04 in forum C Programming
    Replies: 9
    Last Post: 09-26-2004, 07:51 AM