ReactOS 0.4.16-dev-197-g92996da
service.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS Local Spooler API Tests
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Functions needed to run our code as a service. This is needed to run in SYSTEM security context.
5 * COPYRIGHT: Copyright 2015 Colin Finck (colin@reactos.org)
6 */
7
8#include <apitest.h>
9
10#define WIN32_NO_STATUS
11#include <windef.h>
12#include <winbase.h>
13#include <wingdi.h>
14#include <winreg.h>
15#include <winsvc.h>
16#include <winspool.h>
17#include <winsplp.h>
18#include <tlhelp32.h>
19
20#include "localspl_apitest.h"
21
22//#define NDEBUG
23#include <debug.h>
24
25
26static void
28{
29 DWORD cbDLLPath;
31 HANDLE hSnapshot;
34 PVOID pLoadLibraryAddress;
35 PVOID pLoadLibraryArgument;
36 PWSTR p;
37 WCHAR wszFilePath[MAX_PATH];
38
39 // Get the full path to our EXE file.
40 if (!GetModuleFileNameW(NULL, wszFilePath, _countof(wszFilePath)))
41 {
42 DPRINT("GetModuleFileNameW failed with error %lu!\n", GetLastError());
43 return;
44 }
45
46 // Replace the extension.
47 p = wcsrchr(wszFilePath, L'.');
48 if (!p)
49 {
50 DPRINT("File path has no file extension: %S\n", wszFilePath);
51 return;
52 }
53
54 wcscpy(p, L".dll");
55 cbDLLPath = (lstrlenW(wszFilePath) + 1) * sizeof(WCHAR);
56
57 // Create a snapshot of the currently running processes.
59 if (hSnapshot == INVALID_HANDLE_VALUE)
60 {
61 DPRINT("CreateToolhelp32Snapshot failed with error %lu!\n", GetLastError());
62 return;
63 }
64
65 // Enumerate through all running processes.
66 pe.dwSize = sizeof(pe);
67 if (!Process32FirstW(hSnapshot, &pe))
68 {
69 DPRINT("Process32FirstW failed with error %lu!\n", GetLastError());
70 return;
71 }
72
73 do
74 {
75 // Check if this is the spooler server process.
76 if (_wcsicmp(pe.szExeFile, L"spoolsv.exe") != 0)
77 continue;
78
79 // Open a handle to the process.
81 if (!hProcess)
82 {
83 DPRINT("OpenProcess failed with error %lu!\n", GetLastError());
84 return;
85 }
86
87 // Get the address of LoadLibraryW.
88 pLoadLibraryAddress = (PVOID)GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "LoadLibraryW");
89 if (!pLoadLibraryAddress)
90 {
91 DPRINT("GetProcAddress failed with error %lu!\n", GetLastError());
92 return;
93 }
94
95 // Allocate memory for the DLL path in the spooler process.
96 pLoadLibraryArgument = VirtualAllocEx(hProcess, NULL, cbDLLPath, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
97 if (!pLoadLibraryArgument)
98 {
99 DPRINT("VirtualAllocEx failed with error %lu!\n", GetLastError());
100 return;
101 }
102
103 // Write the DLL path to the process memory.
104 if (!WriteProcessMemory(hProcess, pLoadLibraryArgument, wszFilePath, cbDLLPath, NULL))
105 {
106 DPRINT("WriteProcessMemory failed with error %lu!\n", GetLastError());
107 return;
108 }
109
110 // Create a new thread in the spooler process that calls LoadLibraryW as the start routine with our DLL as the argument.
111 // This effectively injects our DLL into the spooler process and we can inspect localspl.dll there just like the spooler.
112 hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pLoadLibraryAddress, pLoadLibraryArgument, 0, NULL);
113 if (!hThread)
114 {
115 DPRINT("CreateRemoteThread failed with error %lu!\n", GetLastError());
116 return;
117 }
118
120 break;
121 }
122 while (Process32NextW(hSnapshot, &pe));
123}
124
125static DWORD WINAPI
126_ServiceControlHandlerEx(DWORD dwControl, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext)
127{
128 return NO_ERROR;
129}
130
131static void WINAPI
132_ServiceMain(DWORD dwArgc, LPWSTR* lpszArgv)
133{
136
138 UNREFERENCED_PARAMETER(lpszArgv);
139
140 // Register our service for control.
142
143 // Report SERVICE_RUNNING status.
151
152 // Do our funky crazy stuff.
154
155 // Our work is done.
158}
159
161{
162 int argc;
163 char** argv;
164
165#if defined(_M_AMD64)
167 {
168 skip("ROSTESTS-366: Skipping localspl_apitest:service because it hangs on Windows Server 2003 x64-Testbot. Set winetest_interactive to run it anyway.\n");
169 return;
170 }
171#endif
172
174 {
176 { NULL, NULL }
177 };
178
179 // This is no real test, but an easy way to integrate the service handler routines into the API-Test executable.
180 // Therefore, bail out if someone tries to run "service" as a usual test.
182 if (argc != 3)
183 return;
184
185 // If we have exactly 3 arguments, we're run as a service, so initialize the corresponding service handler functions.
187
188 // Prevent the testing framework from outputting a "0 tests executed" line here.
189 ExitProcess(0);
190}
static SERVICE_STATUS_HANDLE(WINAPI *pRegisterServiceCtrlHandlerExA)(LPCSTR
static int argc
Definition: ServiceArgs.c:12
#define skip(...)
Definition: atltest.h:64
#define START_TEST(x)
Definition: atltest.h:75
static SERVICE_STATUS ServiceStatus
Definition: browser.c:22
#define NO_ERROR
Definition: dderror.h:5
#define NULL
Definition: types.h:112
#define FALSE
Definition: types.h:117
#define CloseHandle
Definition: compat.h:739
#define wcsrchr
Definition: compat.h:16
#define GetProcAddress(x, y)
Definition: compat.h:753
#define INVALID_HANDLE_VALUE
Definition: compat.h:731
#define MAX_PATH
Definition: compat.h:34
#define lstrlenW
Definition: compat.h:750
DWORD WINAPI GetModuleFileNameW(HINSTANCE hModule, LPWSTR lpFilename, DWORD nSize)
Definition: loader.c:600
HMODULE WINAPI GetModuleHandleW(LPCWSTR lpModuleName)
Definition: loader.c:838
BOOL NTAPI WriteProcessMemory(IN HANDLE hProcess, IN LPVOID lpBaseAddress, IN LPCVOID lpBuffer, IN SIZE_T nSize, OUT SIZE_T *lpNumberOfBytesWritten)
Definition: proc.c:2062
VOID WINAPI ExitProcess(IN UINT uExitCode)
Definition: proc.c:1487
HANDLE WINAPI OpenProcess(IN DWORD dwDesiredAccess, IN BOOL bInheritHandle, IN DWORD dwProcessId)
Definition: proc.c:1227
HANDLE WINAPI CreateRemoteThread(IN HANDLE hProcess, IN LPSECURITY_ATTRIBUTES lpThreadAttributes, IN DWORD dwStackSize, IN LPTHREAD_START_ROUTINE lpStartAddress, IN LPVOID lpParameter, IN DWORD dwCreationFlags, OUT LPDWORD lpThreadId)
Definition: thread.c:159
BOOL WINAPI Process32NextW(HANDLE hSnapshot, LPPROCESSENTRY32W lppe)
Definition: toolhelp.c:1073
HANDLE WINAPI CreateToolhelp32Snapshot(DWORD dwFlags, DWORD th32ProcessID)
Definition: toolhelp.c:1255
BOOL WINAPI Process32FirstW(HANDLE hSnapshot, LPPROCESSENTRY32W lppe)
Definition: toolhelp.c:984
SERVICE_TABLE_ENTRYW ServiceTable[]
Definition: service.c:21
unsigned long DWORD
Definition: ntddk_ex.h:95
GLfloat GLfloat p
Definition: glext.h:8902
_In_ BOOL _In_ HANDLE hProcess
Definition: mapping.h:71
static void _DoDLLInjection()
Definition: service.c:27
static DWORD WINAPI _ServiceControlHandlerEx(DWORD dwControl, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext)
Definition: service.c:126
static void WINAPI _ServiceMain(DWORD dwArgc, LPWSTR *lpszArgv)
Definition: service.c:132
#define argv
Definition: mplay32.c:18
HANDLE hThread
Definition: wizard.c:28
#define PAGE_READWRITE
Definition: nt_native.h:1304
#define PROCESS_ALL_ACCESS
Definition: nt_native.h:1324
#define MEM_RESERVE
Definition: nt_native.h:1314
#define MEM_COMMIT
Definition: nt_native.h:1313
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:317
#define L(x)
Definition: ntvdm.h:50
SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW(LPCWSTR lpServiceName, LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext)
Definition: sctrl.c:812
BOOL WINAPI StartServiceCtrlDispatcherW(const SERVICE_TABLE_ENTRYW *lpServiceStartTable)
Definition: sctrl.c:1134
BOOL WINAPI SetServiceStatus(SERVICE_STATUS_HANDLE hServiceStatus, LPSERVICE_STATUS lpServiceStatus)
Definition: sctrl.c:997
_Check_return_ _CRTIMP int __cdecl _wcsicmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
_CRTIMP wchar_t *__cdecl wcscpy(_Out_writes_z_(_String_length_(_Source)+1) wchar_t *_Dest, _In_z_ const wchar_t *_Source)
int winetest_interactive
int winetest_get_mainargs(char ***pargv)
#define DPRINT
Definition: sndvol32.h:73
#define _countof(array)
Definition: sndvol32.h:70
DWORD dwServiceType
Definition: winsvc.h:99
DWORD dwWin32ExitCode
Definition: winsvc.h:102
DWORD dwControlsAccepted
Definition: winsvc.h:101
DWORD dwWaitHint
Definition: winsvc.h:105
DWORD dwCurrentState
Definition: winsvc.h:100
DWORD dwServiceSpecificExitCode
Definition: winsvc.h:103
WCHAR szExeFile[MAX_PATH]
Definition: tlhelp32.h:58
DWORD th32ProcessID
Definition: tlhelp32.h:51
#define TH32CS_SNAPPROCESS
Definition: tlhelp32.h:26
uint16_t * PWSTR
Definition: typedefs.h:56
void * PVOID
Definition: typedefs.h:50
LPVOID NTAPI VirtualAllocEx(IN HANDLE hProcess, IN LPVOID lpAddress, IN SIZE_T dwSize, IN DWORD flAllocationType, IN DWORD flProtect)
Definition: virtmem.c:23
SERVICE_STATUS_HANDLE hServiceStatus
Definition: main.c:10
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
DWORD(WINAPI * LPTHREAD_START_ROUTINE)(LPVOID)
Definition: winbase.h:753
#define WINAPI
Definition: msvc.h:6
#define SERVICE_STOPPED
Definition: winsvc.h:21
#define SERVICE_ACCEPT_STOP
Definition: winsvc.h:28
#define SERVICE_RUNNING
Definition: winsvc.h:24
#define SERVICE_ACCEPT_SHUTDOWN
Definition: winsvc.h:30
#define SERVICE_NAME
Definition: wlansvc.c:18
#define SERVICE_WIN32_OWN_PROCESS
Definition: cmtypes.h:962
__wchar_t WCHAR
Definition: xmlstorage.h:180
WCHAR * LPWSTR
Definition: xmlstorage.h:184