You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
251 lines
6.9 KiB
251 lines
6.9 KiB
/*
|
|
Copyright (c) Microsoft Corporation
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#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);
|
|
}
|