/* Copyright (c) Microsoft Corporation */ #include #include #include "nt.h" #include "ntrtl.h" #include "nturtl.h" #include "windows.h" #include "delayimp.h" #include "strsafe.h" #include "sxsvc2.h" #define SERVICE_NAME L"sxsvc2" extern const WCHAR ServiceName[] = SERVICE_NAME L"\0"; // extra nul terminal for REG_MULTI_SZ typedef struct _SERVICE_CONTEXT { HANDLE ServiceHandle; SERVICE_STATUS ServiceStatus; } SERVICE_CONTEXT, *PSERVICE_CONTEXT; PVOID MemAlloc(SIZE_T n) { return HeapAlloc(GetProcessHeap(), 0, n); } VOID MemFree(PVOID p) { HeapFree(GetProcessHeap(), 0, p); } BOOL WINAPI DllEntry( HINSTANCE hInst, DWORD dwReason, PVOID pvReserved ) { switch (dwReason) { case DLL_PROCESS_ATTACH: DisableThreadLibraryCalls(hInst); break; } return TRUE; } HMODULE GetMyModule(VOID) { return (HMODULE)&__ImageBase; } void GetMyFullPathW(PWSTR Buffer, DWORD BufferSize) { // NOTE: Do not put this is in the registry. Buffer[0] = 0; GetModuleFileNameW(GetMyModule(), Buffer, BufferSize); } void strcatfW(PWSTR Buffer, SIZE_T n, PCWSTR Format, ...) { va_list Args; va_start(Args, Format); if (n != 0 && Buffer != NULL && Format != NULL) { SIZE_T i = wcslen(Buffer); if (i < n) { SIZE_T j = n - i; StringCchVPrintfW(Buffer + i, j, Format, Args); } Buffer[n - 1] = 0; } va_end(Args); } const STRING EmptyString = RTL_CONSTANT_STRING(""); const STRING * DbgServiceControlToString( DWORD dw ) { const STRING * String = &EmptyString; switch (dw) { #define CASE(x) case x: { const static STRING y = RTL_CONSTANT_STRING(#x); String = &y; } break; CASE(SERVICE_CONTROL_CONTINUE) CASE(SERVICE_CONTROL_INTERROGATE) CASE(SERVICE_CONTROL_NETBINDADD) CASE(SERVICE_CONTROL_NETBINDDISABLE) CASE(SERVICE_CONTROL_NETBINDENABLE) CASE(SERVICE_CONTROL_NETBINDREMOVE) CASE(SERVICE_CONTROL_PARAMCHANGE) CASE(SERVICE_CONTROL_PAUSE) CASE(SERVICE_CONTROL_SHUTDOWN) CASE(SERVICE_CONTROL_STOP) CASE(SERVICE_CONTROL_DEVICEEVENT) CASE(SERVICE_CONTROL_HARDWAREPROFILECHANGE) CASE(SERVICE_CONTROL_POWEREVENT) CASE(SERVICE_CONTROL_SESSIONCHANGE) #undef CASE } return String; } DWORD WINAPI ServiceHandlerEx( DWORD dwControl, // requested control code DWORD dwEventType, // event type LPVOID lpEventData, // event data LPVOID lpContext // user-defined context data ) { BOOL CallSetStatus = FALSE; PSERVICE_CONTEXT ServiceContext = (PSERVICE_CONTEXT)lpContext; DbgPrint("sxsvc2: %Z\n", DbgServiceControlToString(dwControl)); if (ServiceContext == NULL) { DbgPrint("sxsvc2: got null context\n"); return (DWORD)-1; } switch (dwControl) { case SERVICE_CONTROL_CONTINUE: ServiceContext->ServiceStatus.dwCurrentState = SERVICE_RUNNING; CallSetStatus = TRUE; break; case SERVICE_CONTROL_INTERROGATE: CallSetStatus = TRUE; break; case SERVICE_CONTROL_NETBINDADD: break; case SERVICE_CONTROL_NETBINDDISABLE: break; case SERVICE_CONTROL_NETBINDENABLE: break; case SERVICE_CONTROL_NETBINDREMOVE: break; case SERVICE_CONTROL_PARAMCHANGE: break; case SERVICE_CONTROL_PAUSE: ServiceContext->ServiceStatus.dwCurrentState = SERVICE_PAUSED; CallSetStatus = TRUE; break; case SERVICE_CONTROL_SHUTDOWN: ServiceContext->ServiceStatus.dwCurrentState = SERVICE_STOPPED; CallSetStatus = TRUE; break; case SERVICE_CONTROL_STOP: ServiceContext->ServiceStatus.dwCurrentState = SERVICE_STOPPED; CallSetStatus = TRUE; break; case SERVICE_CONTROL_DEVICEEVENT: break; case SERVICE_CONTROL_HARDWAREPROFILECHANGE: break; case SERVICE_CONTROL_POWEREVENT: break; case SERVICE_CONTROL_SESSIONCHANGE: break; } if (CallSetStatus) { SetServiceStatus(ServiceContext->ServiceHandle, &ServiceContext->ServiceStatus); } return NO_ERROR; } VOID WINAPI ServiceMain( DWORD argc, PWSTR argv[] ) { const static WCHAR MyFullPathFormat[] = L"MyFullPath: %ls: "; HANDLE FileHandle = 0; SIZE_T Length = 0; SIZE_T i = 0; PWSTR MyFullPath = 0; PWSTR Buffer = 0; HANDLE CurrentActCtx = 0; DWORD BytesWritten = 0; PSERVICE_CONTEXT ServiceContext = 0; MyFullPath = (PWSTR)MemAlloc(MAX_PATH); if (MyFullPath == NULL) goto Exit; MyFullPath[0] = 0; GetMyFullPathW(MyFullPath, MAX_PATH); Length = 0; if (argc != 0 && argv != NULL) { for (i = 0 ; i < argc ; i++ ) { Length += wcslen(argv[i]) + 1; } } Length += wcslen(MyFullPath) + NUMBER_OF(MyFullPathFormat); Length += 1; Buffer = (PWSTR)MemAlloc(Length * sizeof(WCHAR)); if (Buffer == NULL) { goto Exit; } Buffer[0] = 0; strcatfW(Buffer, Length, MyFullPathFormat, MyFullPath); if (argc != 0 && argv != NULL) { for (i = 0 ; i < argc ; i++ ) { strcatfW(Buffer, Length, L"%ls ", argv[i]); } } GetCurrentActCtx(&CurrentActCtx); #if DBG DbgPrint("sxsvc2: %ls\n", Buffer); #endif ServiceContext = (PSERVICE_CONTEXT)MemAlloc(sizeof(*ServiceContext)); if (ServiceContext == NULL) { DbgPrint("sxsvc2: out of memory line %ld\n", (ULONG)__LINE__); } RtlZeroMemory(ServiceContext, sizeof(*ServiceContext)); ServiceContext->ServiceHandle = RegisterServiceCtrlHandlerExW(ServiceName, ServiceHandlerEx, ServiceContext); if (ServiceContext->ServiceHandle == 0) { DbgPrint("sxsvc2: RegisterServiceCtrlHandlerExW failed 0x%lx\n", (ULONG)GetLastError()); goto Exit; } ServiceContext->ServiceStatus.dwServiceType = ServiceTypeValue; ServiceContext->ServiceStatus.dwCurrentState = SERVICE_RUNNING; ServiceContext->ServiceStatus.dwControlsAccepted |= SERVICE_ACCEPT_STOP; ServiceContext->ServiceStatus.dwControlsAccepted |= SERVICE_ACCEPT_SHUTDOWN; ServiceContext->ServiceStatus.dwControlsAccepted |= SERVICE_ACCEPT_PAUSE_CONTINUE; ServiceContext->ServiceStatus.dwControlsAccepted |= SERVICE_ACCEPT_PARAMCHANGE; ServiceContext->ServiceStatus.dwControlsAccepted |= SERVICE_ACCEPT_SESSIONCHANGE; ServiceContext->ServiceStatus.dwWin32ExitCode = NO_ERROR; SetServiceStatus(ServiceContext->ServiceHandle, &ServiceContext->ServiceStatus); ServiceContext = NULL; Exit: MemFree(Buffer); MemFree(MyFullPath); MemFree(ServiceContext); }