////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// File: MAPIService.cpp
// Description: Example of using CMAPIEx in a windows service
//
// Copyright (C) 2005-2011, Noel Dillabough
//
// This source code is free to use and modify provided this notice remains intact and that any enhancements
// or bug fixes are posted to the CodeProject page hosting this class for the community to benefit.
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include "MAPIService.h"

// To make deploying the service easier, I'm linking MAPIEx as a library; to use the DLL instead comment out the following lines 
// and change the dependency to MAPIEx
#undef AFX_EXT_CLASS
#define AFX_EXT_CLASS

#include "../../MAPIEx.h"

// Service globals
#define SERVICE_NAME _T("MAPIExService")
SERVICE_STATUS status; 
SERVICE_STATUS_HANDLE hStatus;
CMAPIEx mapi;

#ifdef UNICODE
#define PRINTF wprintf
#else
#define PRINTF printf
#endif

void SetStatus(DWORD dwStatus, DWORD dwExitCode=0)
{
	status.dwCurrentState=dwStatus;
	status.dwWin32ExitCode=dwExitCode;
	SetServiceStatus(hStatus, &status);
}

void ControlHandler(DWORD dwControl) 
{ 
	if(dwControl==SERVICE_CONTROL_STOP || dwControl==SERVICE_CONTROL_SHUTDOWN) 
	{
		SetStatus(SERVICE_STOPPED);
		mapi.Logout();
		CMAPIEx::Term();
	}
} 

BOOL InstallService(SC_HANDLE hManager)
{
	TCHAR szPath[_MAX_PATH];
	GetModuleFileName(GetModuleHandle(NULL), szPath, _MAX_PATH);

	SC_HANDLE hService=CreateService(hManager, SERVICE_NAME, SERVICE_NAME, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, szPath, NULL, NULL, NULL, NULL, NULL);
	if(!hService) return FALSE;

	SERVICE_DESCRIPTION desc;
	desc.lpDescription=_T("MAPIEx sample service");
	ChangeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, &desc);
	CloseServiceHandle(hService);
	return TRUE;
}

long CALLBACK OnNewMessage(LPVOID lpvContext, ULONG cNotification, LPNOTIFICATION lpNotifications)
{
	// I'm just doing a beep here when a new mail arrives 
	MessageBeep(-1);
	return 0;
}

void ServiceMain(int argc, char** argv) 
{ 
	memset(&status, 0, sizeof(SERVICE_STATUS));
	status.dwServiceType=SERVICE_WIN32;
	status.dwCurrentState=SERVICE_START_PENDING;
	status.dwControlsAccepted=SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;

	hStatus=RegisterServiceCtrlHandler(SERVICE_NAME, (LPHANDLER_FUNCTION)ControlHandler);
	if(!hStatus) return;

	// initialize MAPI, and turn on notifications for new mail
	if(!CMAPIEx::Init(0, TRUE) || !mapi.Login(NULL, 0, TRUE) || !mapi.OpenMessageStore() || !mapi.Notify(OnNewMessage, NULL, fnevNewMail)) 
	{
		SetStatus(SERVICE_STOPPED, -1);
		return;
	}

	// sleep while running, checking every few seconds
	SetStatus(SERVICE_RUNNING);
	while(status.dwCurrentState==SERVICE_RUNNING) 
	{
		Sleep(4000);
	}
	ControlHandler(SERVICE_CONTROL_SHUTDOWN);
}

void main(int argc, char* argv[]) 
{ 
	if(argc>1)
	{
		SC_HANDLE hManager=OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
		if(hManager) 
		{
			SC_HANDLE hService=OpenService(hManager, SERVICE_NAME, SERVICE_ALL_ACCESS);

			if(!_tcscmp(argv[1], _T("-i"))) 
			{
				if(InstallService(hManager)) PRINTF("Installed %s successfully.\n", SERVICE_NAME);
				else PRINTF("Failed to install %s.\n", SERVICE_NAME);
			} else if(!_tcscmp(argv[1], _T("-u"))) 
			{
				if(hService && DeleteService(hService)) PRINTF("Uninstalled %s successfully.\n", SERVICE_NAME);
				else PRINTF("Failed to uninstall %s.\n", SERVICE_NAME);
			} else {
				PRINTF(_T("Usage:\n"));
				PRINTF(_T("\t-i\tInstall Service\n"));
				PRINTF(_T("\t-u\tUninstall Service\n"));
			}
			if(hService) CloseServiceHandle(hService);
			CloseServiceHandle(hManager);
		}
		return;
	}

	SERVICE_TABLE_ENTRY table[]={
		{ SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION)ServiceMain },
		{ NULL, NULL }
	};
	StartServiceCtrlDispatcher(table);  
}
