Click here to Skip to main content
15,897,704 members
Articles / Desktop Programming / MFC

A service that displays an icon in the system tray

Rate me:
Please Sign up or sign in to vote.
4.00/5 (8 votes)
17 Jan 2000 196.4K   5.2K   49  
This article demonstrates a service that uses the system tray to interact with the user.
// IconService.cpp : Defines the entry point for the console application.
//

//// Copyright (c) 2000 Bruno Vais
//
// Distribute and use freely, except:
// a) Don't alter or remove this notice.
// b) Mark the changes you make.
//
// This file is provided "as is" with no expressed or implied warranty.
// Use at your own risk. Expect bugs.
//
// Send bug reports, bug fixes, enhancements, request, etc. to:
//
//  bvais@usa.net
//


#include "stdafx.h"
#include <winsvc.h>
#include "IconService.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// The one and only application object

CWinApp theApp;

using namespace std;

#define WM_ICON_NOTIFY	WM_USER+1

VOID WINAPI service_ctrl(DWORD dwCtrlCode);
VOID WINAPI service_main(DWORD dwArgc, LPTSTR *lpszArgv);
VOID CmdInstallService();
VOID CmdRemoveService();


SERVICE_STATUS          ssStatus;       // current status of the service
SERVICE_STATUS_HANDLE   sshStatusHandle;
DWORD                   dwErr = 0;
BOOL                    bDebug = FALSE;
TCHAR                   szErr[256];
HWND					hwnd;


int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
	int nRetCode = 0;

	// initialize MFC and print and error on failure
	if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
	{
		// TODO: change error code to suit your needs
		cerr << _T("Fatal Error: MFC initialization failed") << endl;
		nRetCode = 1;
	}
	else
	{
		SERVICE_TABLE_ENTRY dispatchTable[] =
		{
			{ TEXT(SZSERVICENAME), (LPSERVICE_MAIN_FUNCTION)service_main },
			{ NULL, NULL }
		};
		
		if ( (argc > 1) &&
			((*argv[1] == '-') || (*argv[1] == '/')) )
		{
			if ( _stricmp( "install", argv[1]+1 ) == 0 )
			{
				CmdInstallService();
			}
			else if ( _stricmp( "remove", argv[1]+1 ) == 0 )
			{
				CmdRemoveService();
			}
			return nRetCode;
		}
		
		StartServiceCtrlDispatcher(dispatchTable);
	}

	return nRetCode;
}


BOOL CALLBACK DialogProc(  HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
	switch (uMsg)
	{
	case WM_INITDIALOG:
		
		NOTIFYICONDATA ndata;
		
		ndata.cbSize=sizeof(NOTIFYICONDATA);
		ndata.hWnd=hwndDlg;
		ndata.uID=2000;
		ndata.uFlags=NIF_ICON|NIF_MESSAGE|NIF_TIP;
		ndata.uCallbackMessage=WM_ICON_NOTIFY;
		ndata.hIcon=::LoadIcon(GetModuleHandle("IconService.exe"),MAKEINTRESOURCE(IDI_STANDBY));
		strcpy(ndata.szTip,"Aloha");			
		Shell_NotifyIcon(NIM_ADD,&ndata);
		
		SetWindowPos(hwndDlg,NULL,-10,-10,0,0,SWP_NOZORDER|SWP_NOMOVE);
		hwnd=hwndDlg;
		break;
	
	case WM_ICON_NOTIFY:
		
		if (lParam==WM_RBUTTONDOWN)
		{
			Beep(200,200);
			CMenu menu;
			menu.LoadMenu(IDR_POPUP);
			CMenu* popup=menu.GetSubMenu(0);
			CPoint pt;
			GetCursorPos(&pt);
			popup->TrackPopupMenu(TPM_LEFTALIGN,pt.x,pt.y,CWnd::FromHandle(hwndDlg),CRect(0,0,0,0));
		}
		break;
	case WM_COMMAND:
		if (LOWORD(wParam) == ID_POPUP_CLOSE)
			ServiceStop();
		break;
	}
	return FALSE;
}


DWORD WINAPI Thread(  LPVOID lpParameter)
{
	HWND hwnd=CreateDialog(NULL,MAKEINTRESOURCE(IDD_DIALOG1),NULL,NULL);
	DialogBox(NULL,MAKEINTRESOURCE(IDD_DIALOG1),hwnd,DialogProc);
	return 0;
}


void WINAPI service_main(DWORD dwArgc, LPTSTR *lpszArgv)
{

    // register our service control handler:
    //
	sshStatusHandle = RegisterServiceCtrlHandler( TEXT(SZSERVICENAME), service_ctrl);


    // SERVICE_STATUS members that don't change in example
    //
    ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
    ssStatus.dwServiceSpecificExitCode = 0;


    // report the status to the service control manager.
    //
    if (!ReportStatusToSCMgr(SERVICE_START_PENDING,NO_ERROR,3000))
    {
		if (sshStatusHandle)
			(VOID)ReportStatusToSCMgr(SERVICE_STOPPED,dwErr,0);
	}


    ServiceStart( dwArgc, lpszArgv );


    // try to report the stopped status to the service control manager.
    //
    if (sshStatusHandle)
        (VOID)ReportStatusToSCMgr(SERVICE_STOPPED,dwErr,0);

    return;
}


VOID WINAPI service_ctrl(DWORD dwCtrlCode)
{
    // Handle the requested control code.
    //
    switch(dwCtrlCode)
    {
        // Stop the service.
        //
        // SERVICE_STOP_PENDING should be reported before
        // setting the Stop Event - hServerStopEvent - in
        // ServiceStop().  This avoids a race condition
        // which may result in a 1053 - The Service did not respond...
        // error.
        case SERVICE_CONTROL_STOP:
            ReportStatusToSCMgr(SERVICE_STOP_PENDING, NO_ERROR, 0);
            ServiceStop();
            return;

        // Update the service status.
        //
        case SERVICE_CONTROL_INTERROGATE:
            break;

        // invalid control code
        //
        default:
            break;

    }

    ReportStatusToSCMgr(ssStatus.dwCurrentState, NO_ERROR, 0);
}



//
//  FUNCTION: ReportStatusToSCMgr()
//
//  PURPOSE: Sets the current status of the service and
//           reports it to the Service Control Manager
//

BOOL ReportStatusToSCMgr(DWORD dwCurrentState,
                         DWORD dwWin32ExitCode,
                         DWORD dwWaitHint)
{
    static DWORD dwCheckPoint = 1;
    BOOL fResult = TRUE;


    if ( !bDebug ) // when debugging we don't report to the SCM
    {
        if (dwCurrentState == SERVICE_START_PENDING)
            ssStatus.dwControlsAccepted = 0;
        else
            ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;

        ssStatus.dwCurrentState = dwCurrentState;
        ssStatus.dwWin32ExitCode = dwWin32ExitCode;
        ssStatus.dwWaitHint = dwWaitHint;

        if ( ( dwCurrentState == SERVICE_RUNNING ) ||
             ( dwCurrentState == SERVICE_STOPPED ) )
            ssStatus.dwCheckPoint = 0;
        else
            ssStatus.dwCheckPoint = dwCheckPoint++;


        // Report the status of the service to the service control manager.
        //

		fResult = SetServiceStatus( sshStatusHandle, &ssStatus);
    }
    return fResult;
}



//
//  FUNCTION: CmdInstallService()
//
//  PURPOSE: Installs the service

void CmdInstallService()
{
    SC_HANDLE   schService;
    SC_HANDLE   schSCManager;

    TCHAR szPath[512];

    
	if ( GetModuleFileName( NULL, szPath, 512 ) == 0 )
    {
        printf("Unable to install IconService\n");
        return;
    }

	

    schSCManager = OpenSCManager(
                        NULL,                   // machine (NULL == local)
                        NULL,                   // database (NULL == default)
                        SC_MANAGER_ALL_ACCESS   // access required
                        );
    if ( schSCManager )
    {
        schService = CreateService(
            schSCManager,               // SCManager database
            TEXT(SZSERVICENAME),        // name of service
            TEXT(SZSERVICEDISPLAYNAME), // name to display
            SERVICE_ALL_ACCESS,         // desired access
            SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS ,  // service type
            SERVICE_DEMAND_START,       // start type
            SERVICE_ERROR_NORMAL,       // error control type
            szPath,                     // service's binary
            NULL,                       // no load ordering group
            NULL,                       // no tag identifier
            TEXT(SZDEPENDENCIES),       // dependencies
            NULL,                       // LocalSystem account
            NULL);                      // no password

        if ( schService )
        {
            printf("IconService installed.\n");
            CloseServiceHandle(schService);
		}
        else
        {
            printf("CreateService failed");
        }

        CloseServiceHandle(schSCManager);
    }
    else
        printf("OpenSCManager failed");

	
}



//
//  FUNCTION: CmdRemoveService()
//
//  PURPOSE: Stops and removes the service
//

void CmdRemoveService()
{
    SC_HANDLE   schService;
    SC_HANDLE   schSCManager;

    schSCManager = OpenSCManager(
                        NULL,                   // machine (NULL == local)
                        NULL,                   // database (NULL == default)
                        SC_MANAGER_ALL_ACCESS   // access required
                        );
    if ( schSCManager )
    {
        schService = OpenService(schSCManager, TEXT(SZSERVICENAME), SERVICE_ALL_ACCESS);

        if (schService)
        {
            // try to stop the service
            if ( ControlService( schService, SERVICE_CONTROL_STOP, &ssStatus ) )
            {
                printf("Stopping IconService.");
                Sleep( 1000 );

                while( QueryServiceStatus( schService, &ssStatus ) )
                {
                    if ( ssStatus.dwCurrentState == SERVICE_STOP_PENDING )
                    {
                        printf(".");
                        Sleep( 1000 );
                    }
                    else
                        break;
                }

                if ( ssStatus.dwCurrentState == SERVICE_STOPPED )
                    printf("\nIconService stopped.\n");
                else
                    printf("\nFailed to stop IconService.\n");

            }

            // now remove the service
            if( DeleteService(schService) )
				printf("IconService removed.\n");
			else
				printf("DeleteService failed.\n");
			
            CloseServiceHandle(schService);
        }
        else
            printf("OpenService failed.\n");

        CloseServiceHandle(schSCManager);
    }
    else
        printf("OpenSCManager failed.\n");

}





HANDLE  hServerStopEvent = NULL;


//
//  FUNCTION: ServiceStart
//
//  PURPOSE: Actual code of the service
//           that does the work.
//

VOID ServiceStart (DWORD dwArgc, LPTSTR *lpszArgv)
{
    
    // create the event object. The control handler function signals
    // this event when it receives the "stop" control code.
    //
    hServerStopEvent = CreateEvent(
        NULL,    // no security attributes
        TRUE,    // manual reset event
        FALSE,   // not-signalled
        NULL);   // no name

    // report the status to the service control manager.
    //
    if (!ReportStatusToSCMgr(SERVICE_RUNNING,NO_ERROR,0))
    {
		if (hServerStopEvent)
			CloseHandle(hServerStopEvent);
		
		return;
	}

    CreateThread(NULL,0,Thread,NULL,0,NULL);
	
    WaitForSingleObject( hServerStopEvent,INFINITE );

  //cleanup:

    if (hServerStopEvent)
        CloseHandle(hServerStopEvent);

}



//  FUNCTION: ServiceStop
//
//  PURPOSE: Stops the service

VOID ServiceStop()
{
    if ( hServerStopEvent )
        SetEvent(hServerStopEvent);
	NOTIFYICONDATA ndata;
	ndata.hWnd=hwnd;
	ndata.uID=2000;
	Shell_NotifyIcon(NIM_DELETE,&ndata);
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions