// 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);
}