|
|
#include "shsrvice.h"
#include "mischlpr.h"
#include "dbg.h"
#include "tfids.h"
#define ARRAYSIZE(a) (sizeof((a))/sizeof((a)[0]))
#define SC_PAUSE 0
#define SC_CONTINUE 1
#define SC_STOP 2
#define SC_SHUTDOWN 3
#define SC_INTERROGATE 4
DWORD rgdwControlCodes[] = { SERVICE_CONTROL_PAUSE, // 0x00000002
SERVICE_CONTROL_CONTINUE, // 0x00000003
SERVICE_CONTROL_STOP, // 0x00000001
SERVICE_CONTROL_SHUTDOWN, // 0x00000005
SERVICE_CONTROL_INTERROGATE, // 0x00000004
};
static SERVICEENTRY* g_pseWantsDeviceEvents = NULL; static SERVICEENTRY** g_ppse = NULL; static HWND g_hwnd = NULL; static HANDLE* g_phEvent = NULL;
LRESULT _FakeWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
DWORD WINAPI _ServiceMainCaller(PVOID pvParam) { LPWSTR* ppsz = (LPWSTR*)pvParam;
TRACE(TF_SERVICEASPROCESS, TEXT("%s: _ServiceMainCaller called"), (LPWSTR)*ppsz); CGenericServiceManager::_ServiceMain(1, (LPWSTR*)pvParam);
return 0; }
DWORD _ServiceIndexFromServiceName(SERVICE_TABLE_ENTRY* pste, LPCWSTR pszServiceName) { DWORD dw = 0;
while (pste[dw].lpServiceName) { if (!lstrcmp(pste[dw].lpServiceName, pszServiceName)) { break; } else { ++dw; } }
return dw; }
//static
HRESULT CGenericServiceManager::_RegisterServiceCtrlHandler( LPCWSTR pszServiceName, SERVICEENTRY* pse) { ASSERT(pse);
TRACE(TF_SERVICEASPROCESS, TEXT("%s: _RegisterServiceCtrlHandler called"), pszServiceName);
g_ppse[_ServiceIndexFromServiceName(_rgste, pszServiceName)] = pse;
#ifdef DEBUG
lstrcpy(pse->_szServiceName, pszServiceName); #endif
return S_OK; }
// static
HRESULT CGenericServiceManager::_HandleWantsDeviceEvents( LPCWSTR pszServiceName, BOOL UNREF_PARAM(fWantsDeviceEvents)) { HRESULT hres = E_FAIL; DWORD dwWait; DWORD dwService = _ServiceIndexFromServiceName(_rgste, pszServiceName);
TRACE(TF_SERVICEASPROCESS, TEXT("%s: _HandleWantsDeviceEvents (1)"), pszServiceName);
// We need to release the main service thread, so that it can create
// the fake wnd that will receive the WM_DEVICECHANGE msgs to fake
// the SERVICE_CONTROL_DEVICEEVENT.
SetEvent(g_phEvent[dwService]);
TRACE(TF_SERVICEASPROCESS, TEXT("%s: _HandleWantsDeviceEvents (2)"), pszServiceName); // Let's relinquish our remaining time slice. Or else we won't wait on
// the following line.
// That's not fool proof (might not work) but this is test code...
Sleep(0);
TRACE(TF_SERVICEASPROCESS, TEXT("%s: _HandleWantsDeviceEvents (3)"), pszServiceName); // We wait until the main service thread is done with the window creation.
// Then g_hwnd wil lbe set and we'll be able to use it to register for
// notif.
dwWait = WaitForSingleObject(g_phEvent[dwService], INFINITE);
TRACE(TF_SERVICEASPROCESS, TEXT("%s: _HandleWantsDeviceEvents (4)"), pszServiceName); if (WAIT_OBJECT_0 == dwWait) { hres = S_OK; }
CloseHandle(g_phEvent[dwService]);
g_phEvent[dwService] = NULL;
return hres; }
// static
HRESULT CGenericServiceManager::StartServiceCtrlDispatcher() { HRESULT hres = E_FAIL; HANDLE* phEvents; g_ppse = (SERVICEENTRY**)LocalAlloc(LPTR, sizeof(SERVICEENTRY*) * _cste);
phEvents = (HANDLE*)LocalAlloc(LPTR, sizeof(HANDLE) * _cste * 5);
g_phEvent = (HANDLE*)LocalAlloc(LPTR, sizeof(HANDLE) * _cste);
if (g_ppse && phEvents && g_phEvent) { for (DWORD dwService = 0; dwService < _cste; ++dwService) { WCHAR szEventName[256]; LPWSTR pszServiceName = _rgste[dwService].lpServiceName;
hres = S_OK;
lstrcpy(szEventName, _rgste[dwService].lpServiceName); lstrcat(szEventName, TEXT(".SC_PAUSE"));
phEvents[dwService * 5 + SC_PAUSE] = CreateEvent(NULL, TRUE, FALSE, szEventName);
lstrcpy(szEventName, _rgste[dwService].lpServiceName); lstrcat(szEventName, TEXT(".SC_CONTINUE"));
phEvents[dwService * 5 + SC_CONTINUE] = CreateEvent(NULL, TRUE, FALSE, szEventName);
lstrcpy(szEventName, _rgste[dwService].lpServiceName); lstrcat(szEventName, TEXT(".SC_STOP"));
phEvents[dwService * 5 + SC_STOP] = CreateEvent(NULL, TRUE, FALSE, szEventName);
lstrcpy(szEventName, _rgste[dwService].lpServiceName); lstrcat(szEventName, TEXT(".SC_SHUTDOWN"));
phEvents[dwService * 5 + SC_SHUTDOWN] = CreateEvent(NULL, TRUE, FALSE, szEventName);
lstrcpy(szEventName, _rgste[dwService].lpServiceName); lstrcat(szEventName, TEXT(".SC_INTERROGATE"));
phEvents[dwService * 5 + SC_INTERROGATE] = CreateEvent(NULL, TRUE, FALSE, szEventName);
for (DWORD dwEvent = SC_PAUSE; SUCCEEDED(hres) && (dwEvent <= SC_INTERROGATE); ++dwEvent) { if (!phEvents[(dwService * 5) + dwEvent]) { hres = E_FAIL; } }
if (SUCCEEDED(hres)) { g_phEvent[dwService] = CreateEvent(NULL, FALSE, FALSE, NULL);
if (g_phEvent[dwService]) { CreateThread(NULL, 0, _ServiceMainCaller, (LPWSTR*)&(_rgste[dwService].lpServiceName), 0, NULL);
// We have to wait for the IService impl to be CoCreated and
// queried for fWantsDeviceEvents. So we block here.
// _HandleWantsDeviceEvents will unblock us when
// fWantsDeviceEvents will be known.
TRACE(TF_SERVICEASPROCESS, TEXT("%s: StartServiceCtrlDispatcher (1)"), pszServiceName);
DWORD dwWait = WaitForSingleObject(g_phEvent[dwService], INFINITE);
TRACE(TF_SERVICEASPROCESS, TEXT("%s: StartServiceCtrlDispatcher (2)"), pszServiceName);
if (WAIT_OBJECT_0 == dwWait) { if (g_ppse[dwService]->_fWantsDeviceEvents) { WNDCLASSEX wndclass; HINSTANCE hinst = GetModuleHandle(NULL);
g_pseWantsDeviceEvents = g_ppse[dwService];
if (hinst) { wndclass.cbSize = sizeof(wndclass); wndclass.style = NULL; wndclass.lpfnWndProc = _FakeWndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hinst; wndclass.hIcon = NULL; wndclass.hCursor = NULL; wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = TEXT("FakeWnd"); wndclass.hIconSm = NULL;
if (RegisterClassEx(&wndclass)) { g_hwnd = CreateWindow(TEXT("FakeWnd"), TEXT("FakeWnd"), WS_POPUPWINDOW, 0, 0, 100, 200, NULL, NULL, hinst, NULL);
if (g_hwnd) { g_pseWantsDeviceEvents->_ssh = (SERVICE_STATUS_HANDLE)g_hwnd; } } } }
// We're done with the window creation, release the IService
// impl thread.
SetEvent(g_phEvent[dwService]); } } } TRACE(TF_SERVICEASPROCESS, TEXT("%s: StartServiceCtrlDispatcher (3)"), pszServiceName); }
while (SUCCEEDED(hres)) { DWORD dw = MsgWaitForMultipleObjects(_cste * 5, phEvents, FALSE, INFINITE, QS_ALLINPUT);
if (WAIT_FAILED != dw) { if ((_cste * 5) == (dw - WAIT_OBJECT_0)) { MSG msg;
if (GetMessage(&msg, NULL, 0, 0)) { if (WM_DEVICECHANGE != msg.message) { DispatchMessage(&msg); } else { // To mimic the true service behavior, deliver
// these messages only if the "service" is
// running
if (SERVICE_RUNNING == g_pseWantsDeviceEvents->_servicestatus.dwCurrentState) { DispatchMessage(&msg); } } } } else { DWORD dwService2 = ((dw - WAIT_OBJECT_0 + 1) / 5);
if (NO_ERROR != _ServiceHandler( rgdwControlCodes[(dw - WAIT_OBJECT_0) - (dwService2 * 5)], 0, NULL, (PVOID)g_ppse[dwService2])) { hres = E_FAIL; } } } else { hres = E_FAIL; } } } else { hres = E_OUTOFMEMORY; } return hres; }
#ifdef DEBUG
BOOL CGenericServiceManager::_SetServiceStatus(SERVICEENTRY* pse) { WCHAR sz[256];
lstrcpy(sz, pse->_szServiceName);
switch (pse->_servicestatus.dwCurrentState) { case SERVICE_STOPPED: lstrcat(sz, TEXT(": SERVICE_STOPPED")); break; case SERVICE_START_PENDING: lstrcat(sz, TEXT(": SERVICE_START_PENDING")); break; case SERVICE_STOP_PENDING: lstrcat(sz, TEXT(": SERVICE_STOP_PENDING")); break; case SERVICE_RUNNING: lstrcat(sz, TEXT(": SERVICE_RUNNING")); break; case SERVICE_CONTINUE_PENDING: lstrcat(sz, TEXT(": SERVICE_CONTINUE_PENDING")); break; case SERVICE_PAUSE_PENDING: lstrcat(sz, TEXT(": SERVICE_PAUSE_PENDING")); break; case SERVICE_PAUSED: lstrcat(sz, TEXT(": SERVICE_PAUSED")); break; default: lstrcat(sz, TEXT(": Unknown state")); break; }
TRACE(TF_SERVICE, sz);
return TRUE; } #else
BOOL CGenericServiceManager::_SetServiceStatus(SERVICEENTRY*) { return TRUE; } #endif
///////////////////////////////////////////////////////////////////////////////
// Wnd stuff
LRESULT _FakeWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { LRESULT lRes = 0; BOOL fProcessed = FALSE;
switch (uMsg) { case WM_DEVICECHANGE: { fProcessed = TRUE;
lRes = CGenericServiceManager::_ServiceHandler( SERVICE_CONTROL_DEVICEEVENT, (DWORD)wParam, (PVOID)lParam, (PVOID)g_pseWantsDeviceEvents);
if ((NO_ERROR != lRes) && (TRUE != lRes)) { ASSERT(FALSE); }
break; } case WM_DESTROY:
// Should cleanup here
fProcessed = FALSE;
break;
default:
fProcessed = FALSE; break;
}
if (!fProcessed) { lRes = DefWindowProc(hWnd, uMsg, wParam, lParam); }
return lRes; }
|