ReactOS 0.4.15-dev-7994-gb388cb6
svchlp.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS api tests
3 * LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory
4 * PURPOSE: Support helpers for embedded services inside api tests.
5 * PROGRAMMERS: Jacek Caban for CodeWeavers
6 * Thomas Faber <thomas.faber@reactos.org>
7 * Hermes Belusca-Maito
8 *
9 * NOTE: Room for improvements:
10 * - One test_runner managing 1 pipe for 1 service process that is shared
11 * by multiple services of type SERVICE_WIN32_SHARE_PROCESS.
12 * - Find a way to elegantly determine the registered service name inside
13 * the service process, without really passing it
14 */
15
16#include "precomp.h"
17
19static WCHAR named_pipe_name[100]; // Shared: FIXME!
20
21static CHAR service_nameA[100];
22static WCHAR service_nameW[100];
23
24
25/********** S E R V I C E ( C L I E N T ) M O D U L E S I D E *********/
26
27void send_msg(const char *type, const char *msg)
28{
29 DWORD written = 0;
30 char buf[512];
31
32 StringCbPrintfA(buf, sizeof(buf), "%s:%s", type, msg);
33 WriteFile(hClientPipe, buf, lstrlenA(buf)+1, &written, NULL);
34}
35
36void service_trace(const char *msg, ...)
37{
39 char buf[512];
40
42 StringCbVPrintfA(buf, sizeof(buf), msg, valist);
44
45 send_msg("TRACE", buf);
46}
47
48void service_ok(int cnd, const char *msg, ...)
49{
51 char buf[512];
52
54 StringCbVPrintfA(buf, sizeof(buf), msg, valist);
56
57 send_msg(cnd ? "OK" : "FAIL", buf);
58}
59
61{
62 BOOL res;
63
66 StringCbPrintfW(named_pipe_name, sizeof(named_pipe_name), L"\\\\.\\pipe\\%ls_pipe", service_nameW);
67
69 if (!res)
70 return;
71
74 return;
75
76 service_trace("Service process starting...\n");
78 service_trace("Service process stopped.\n");
79
81}
82
83
84/*********** T E S T E R ( S E R V E R ) M O D U L E S I D E **********/
85
87 SC_HANDLE scm_handle,
89 PCSTR service_name, // LPCSTR lpServiceName,
90 PCSTR extra_args OPTIONAL,
91 DWORD dwDesiredAccess,
92 DWORD dwServiceType,
93 DWORD dwStartType,
94 DWORD dwErrorControl,
95 LPCSTR lpLoadOrderGroup OPTIONAL,
96 LPDWORD lpdwTagId OPTIONAL,
97 LPCSTR lpDependencies OPTIONAL,
98 LPCSTR lpServiceStartName OPTIONAL,
99 LPCSTR lpPassword OPTIONAL)
100{
101 SC_HANDLE service;
102 CHAR service_cmd[MAX_PATH+150];
103
104 /* Retrieve our full path */
105 if (!GetModuleFileNameA(NULL, service_cmd, MAX_PATH))
106 {
107 skip("GetModuleFileNameW failed with error %lu!\n", GetLastError());
108 return NULL;
109 }
110
111 /*
112 * Build up our custom command line. The first parameter is the test name,
113 * the second parameter is the flag used to decide whether we should start
114 * as a service.
115 */
116 StringCbCatA(service_cmd, sizeof(service_cmd), " ");
117 StringCbCatA(service_cmd, sizeof(service_cmd), test_name);
118 StringCbCatA(service_cmd, sizeof(service_cmd), " ");
119 StringCbCatA(service_cmd, sizeof(service_cmd), service_name);
120 if (extra_args)
121 {
122 StringCbCatA(service_cmd, sizeof(service_cmd), " ");
123 StringCbCatA(service_cmd, sizeof(service_cmd), extra_args);
124 }
125
126 trace("service_cmd \"%s\"\n", service_cmd);
127
129 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
130 service_cmd, lpLoadOrderGroup, lpdwTagId, lpDependencies,
131 lpServiceStartName, lpPassword);
132 if (!service && GetLastError() == ERROR_ACCESS_DENIED)
133 {
134 skip("Not enough access right to create service.\n");
135 return NULL;
136 }
137
138 ok(service != NULL, "CreateService failed: %lu\n", GetLastError());
139 return service;
140}
141
143 SC_HANDLE scm_handle,
145 PCWSTR service_name, // LPCWSTR lpServiceName,
146 PCWSTR extra_args OPTIONAL,
147 DWORD dwDesiredAccess,
148 DWORD dwServiceType,
149 DWORD dwStartType,
150 DWORD dwErrorControl,
151 LPCWSTR lpLoadOrderGroup OPTIONAL,
152 LPDWORD lpdwTagId OPTIONAL,
153 LPCWSTR lpDependencies OPTIONAL,
154 LPCWSTR lpServiceStartName OPTIONAL,
155 LPCWSTR lpPassword OPTIONAL)
156{
157 SC_HANDLE service;
158 WCHAR service_cmd[MAX_PATH+150];
159
160 /* Retrieve our full path */
161 if (!GetModuleFileNameW(NULL, service_cmd, MAX_PATH))
162 {
163 skip("GetModuleFileNameW failed with error %lu!\n", GetLastError());
164 return NULL;
165 }
166
167 /*
168 * Build up our custom command line. The first parameter is the test name,
169 * the second parameter is the flag used to decide whether we should start
170 * as a service.
171 */
172 StringCbCatW(service_cmd, sizeof(service_cmd), L" ");
173 StringCbCatW(service_cmd, sizeof(service_cmd), test_name);
174 StringCbCatW(service_cmd, sizeof(service_cmd), L" ");
175 StringCbCatW(service_cmd, sizeof(service_cmd), service_name);
176 if (extra_args)
177 {
178 StringCbCatW(service_cmd, sizeof(service_cmd), L" ");
179 StringCbCatW(service_cmd, sizeof(service_cmd), extra_args);
180 }
181
182 trace("service_cmd \"%ls\"\n", service_cmd);
183
185 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
186 service_cmd, lpLoadOrderGroup, lpdwTagId, lpDependencies,
187 lpServiceStartName, lpPassword);
188 if (!service && GetLastError() == ERROR_ACCESS_DENIED)
189 {
190 skip("Not enough access right to create service.\n");
191 return NULL;
192 }
193
194 ok(service != NULL, "CreateService failed: %lu\n", GetLastError());
195 return service;
196}
197
199 SC_HANDLE scm_handle,
202 PCSTR extra_args OPTIONAL)
203{
209 NULL, NULL, NULL, NULL, NULL);
210}
211
213 SC_HANDLE scm_handle,
216 PCWSTR extra_args OPTIONAL)
217{
223 NULL, NULL, NULL, NULL, NULL);
224}
225
227{
228 HANDLE hServerPipe = (HANDLE)param;
229 DWORD read;
230 BOOL res;
231 char buf[512];
232
233 // printf("pipe_thread -- ConnectNamedPipe...\n");
234 res = ConnectNamedPipe(hServerPipe, NULL);
235 ok(res || GetLastError() == ERROR_PIPE_CONNECTED, "ConnectNamedPipe failed: %lu\n", GetLastError());
236 // printf("pipe_thread -- ConnectNamedPipe ok\n");
237
238 while (1)
239 {
240 res = ReadFile(hServerPipe, buf, sizeof(buf), &read, NULL);
241 if (!res)
242 {
244 "ReadFile failed: %lu\n", GetLastError());
245 // printf("pipe_thread -- break loop\n");
246 break;
247 }
248
249 if (!strncmp(buf, "TRACE:", 6))
250 {
251 trace("service trace: %s", buf+6);
252 }
253 else if (!strncmp(buf, "OK:", 3))
254 {
255 ok(1, "service: %s", buf+3);
256 }
257 else if (!strncmp(buf, "FAIL:", 5))
258 {
259 ok(0, "service: %s", buf+5);
260 }
261 else
262 {
263 ok(0, "malformed service message: %s\n", buf);
264 }
265 }
266
267 // printf("pipe_thread -- DisconnectNamedPipe\n");
268
269 /*
270 * Flush the pipe to allow the client to read
271 * the pipe's contents before disconnecting.
272 */
273 FlushFileBuffers(hServerPipe);
274
275 DisconnectNamedPipe(hServerPipe);
276 trace("pipe disconnected\n");
277 return 0;
278}
279
280void test_runner(void (*run_test)(PCSTR, PCWSTR, void*), void *param)
281{
282 HANDLE hServerPipe = INVALID_HANDLE_VALUE;
284
285 StringCbPrintfW(service_nameW, sizeof(service_nameW), L"WineTestService%lu", GetTickCount());
287 //trace("service_name: %ls\n", service_nameW);
288 StringCbPrintfW(named_pipe_name, sizeof(named_pipe_name), L"\\\\.\\pipe\\%ls_pipe", service_nameW);
289
291 PIPE_TYPE_MESSAGE|PIPE_READMODE_MESSAGE|PIPE_WAIT, 10, 2048, 2048, 10000, NULL);
292 ok(hServerPipe != INVALID_HANDLE_VALUE, "CreateNamedPipe failed: %lu\n", GetLastError());
293 if (hServerPipe == INVALID_HANDLE_VALUE)
294 return;
295
296 hThread = CreateThread(NULL, 0, pipe_thread, (LPVOID)hServerPipe, 0, NULL);
297 ok(hThread != NULL, "CreateThread failed: %lu\n", GetLastError());
298 if (!hThread)
299 goto Quit;
300
302
303 ok(WaitForSingleObject(hThread, 10000) == WAIT_OBJECT_0, "Timeout waiting for thread\n");
304
305Quit:
306 if (hThread)
307 {
308 /* Be sure to kill the thread if it did not already terminate */
311 }
312
313 if (hServerPipe != INVALID_HANDLE_VALUE)
314 CloseHandle(hServerPipe);
315}
static char service_name[100]
static SC_HANDLE scm_handle
Definition: ServiceArgs.c:20
static int argc
Definition: ServiceArgs.c:12
int strncmp(const char *String1, const char *String2, ACPI_SIZE Count)
Definition: utclib.c:534
char * va_list
Definition: acmsvcex.h:78
#define va_end(ap)
Definition: acmsvcex.h:90
#define va_start(ap, A)
Definition: acmsvcex.h:91
#define read
Definition: acwin.h:96
#define trace
Definition: atltest.h:70
#define ok(value,...)
Definition: atltest.h:57
#define skip(...)
Definition: atltest.h:64
#define msg(x)
Definition: auth_time.c:54
#define NULL
Definition: types.h:112
#define CloseHandle
Definition: compat.h:739
#define CP_ACP
Definition: compat.h:109
#define OPEN_EXISTING
Definition: compat.h:775
#define ReadFile(a, b, c, d, e)
Definition: compat.h:742
#define INVALID_HANDLE_VALUE
Definition: compat.h:731
#define MAX_PATH
Definition: compat.h:34
#define ERROR_INVALID_HANDLE
Definition: compat.h:98
#define CreateFileW
Definition: compat.h:741
#define FILE_ATTRIBUTE_NORMAL
Definition: compat.h:137
#define WideCharToMultiByte
Definition: compat.h:111
#define MultiByteToWideChar
Definition: compat.h:110
#define ERROR_ACCESS_DENIED
Definition: compat.h:97
BOOL WINAPI FlushFileBuffers(IN HANDLE hFile)
Definition: fileinfo.c:25
BOOL WINAPI WriteFile(IN HANDLE hFile, IN LPCVOID lpBuffer, IN DWORD nNumberOfBytesToWrite OPTIONAL, OUT LPDWORD lpNumberOfBytesWritten, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: rw.c:24
DWORD WINAPI GetModuleFileNameW(HINSTANCE hModule, LPWSTR lpFilename, DWORD nSize)
Definition: loader.c:600
DWORD WINAPI GetModuleFileNameA(HINSTANCE hModule, LPSTR lpFilename, DWORD nSize)
Definition: loader.c:539
HANDLE WINAPI DECLSPEC_HOTPATCH CreateThread(IN LPSECURITY_ATTRIBUTES lpThreadAttributes, IN DWORD dwStackSize, IN LPTHREAD_START_ROUTINE lpStartAddress, IN LPVOID lpParameter, IN DWORD dwCreationFlags, OUT LPDWORD lpThreadId)
Definition: thread.c:137
BOOL WINAPI TerminateThread(IN HANDLE hThread, IN DWORD dwExitCode)
Definition: thread.c:587
DWORD WINAPI GetTickCount(VOID)
Definition: time.c:455
static HRESULT start_service(const WCHAR *name, VARIANT *retval)
Definition: service.c:169
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
GLuint res
Definition: glext.h:9613
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
GLfloat param
Definition: glext.h:5796
int WINAPI lstrlenA(LPCSTR lpString)
Definition: lstring.c:145
static const char * test_name
Definition: run.c:177
static __ms_va_list valist
Definition: printf.c:66
#define argv
Definition: mplay32.c:18
#define run_test(test)
Definition: ms_seh.c:71
HANDLE hThread
Definition: wizard.c:28
BOOL WINAPI ConnectNamedPipe(IN HANDLE hNamedPipe, IN LPOVERLAPPED lpOverlapped)
Definition: npipe.c:701
BOOL WINAPI DisconnectNamedPipe(HANDLE hNamedPipe)
Definition: npipe.c:961
HANDLE WINAPI CreateNamedPipeW(LPCWSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances, DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut, LPSECURITY_ATTRIBUTES lpSecurityAttributes)
Definition: npipe.c:246
BOOL WINAPI WaitNamedPipeW(LPCWSTR lpNamedPipeName, DWORD nTimeOut)
Definition: npipe.c:458
#define GENERIC_WRITE
Definition: nt_native.h:90
#define L(x)
Definition: ntvdm.h:50
SC_HANDLE WINAPI CreateServiceW(SC_HANDLE hSCManager, LPCWSTR lpServiceName, LPCWSTR lpDisplayName, DWORD dwDesiredAccess, DWORD dwServiceType, DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName, LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies, LPCWSTR lpServiceStartName, LPCWSTR lpPassword)
Definition: scm.c:812
SC_HANDLE WINAPI CreateServiceA(SC_HANDLE hSCManager, LPCSTR lpServiceName, LPCSTR lpDisplayName, DWORD dwDesiredAccess, DWORD dwServiceType, DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName, LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies, LPCSTR lpServiceStartName, LPCSTR lpPassword)
Definition: scm.c:680
#define _countof(array)
Definition: sndvol32.h:68
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
STRSAFEAPI StringCbVPrintfA(STRSAFE_LPSTR pszDest, size_t cbDest, STRSAFE_LPCSTR pszFormat, va_list argList)
Definition: strsafe.h:502
STRSAFEAPI StringCbCatA(STRSAFE_LPSTR pszDest, size_t cbDest, STRSAFE_LPCSTR pszSrc)
Definition: strsafe.h:337
STRSAFEAPI StringCbPrintfW(STRSAFE_LPWSTR pszDest, size_t cbDest, STRSAFE_LPCWSTR pszFormat,...)
Definition: strsafe.h:557
STRSAFEAPI StringCbCatW(STRSAFE_LPWSTR pszDest, size_t cbDest, STRSAFE_LPCWSTR pszSrc)
Definition: strsafe.h:342
STRSAFEAPI StringCbPrintfA(STRSAFE_LPSTR pszDest, size_t cbDest, STRSAFE_LPCSTR pszFormat,...)
Definition: strsafe.h:547
STRSAFEAPI StringCbCopyA(STRSAFE_LPSTR pszDest, size_t cbDest, STRSAFE_LPCSTR pszSrc)
Definition: strsafe.h:161
static CHAR service_nameA[100]
Definition: svchlp.c:21
void send_msg(const char *type, const char *msg)
Definition: svchlp.c:27
void service_trace(const char *msg,...)
Definition: svchlp.c:36
SC_HANDLE register_serviceW(SC_HANDLE scm_handle, PCWSTR test_name, PCWSTR service_name, PCWSTR extra_args OPTIONAL)
Definition: svchlp.c:212
SC_HANDLE register_service_exA(SC_HANDLE scm_handle, PCSTR test_name, PCSTR service_name, PCSTR extra_args OPTIONAL, DWORD dwDesiredAccess, DWORD dwServiceType, DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpLoadOrderGroup OPTIONAL, LPDWORD lpdwTagId OPTIONAL, LPCSTR lpDependencies OPTIONAL, LPCSTR lpServiceStartName OPTIONAL, LPCSTR lpPassword OPTIONAL)
Definition: svchlp.c:86
void test_runner(void(*run_test)(PCSTR, PCWSTR, void *), void *param)
Definition: svchlp.c:280
static HANDLE hClientPipe
Definition: svchlp.c:18
static WCHAR service_nameW[100]
Definition: svchlp.c:22
SC_HANDLE register_service_exW(SC_HANDLE scm_handle, PCWSTR test_name, PCWSTR service_name, PCWSTR extra_args OPTIONAL, DWORD dwDesiredAccess, DWORD dwServiceType, DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpLoadOrderGroup OPTIONAL, LPDWORD lpdwTagId OPTIONAL, LPCWSTR lpDependencies OPTIONAL, LPCWSTR lpServiceStartName OPTIONAL, LPCWSTR lpPassword OPTIONAL)
Definition: svchlp.c:142
void service_process(BOOL(*start_service)(PCSTR, PCWSTR), int argc, char **argv)
Definition: svchlp.c:60
void service_ok(int cnd, const char *msg,...)
Definition: svchlp.c:48
static WCHAR named_pipe_name[100]
Definition: svchlp.c:19
static DWORD WINAPI pipe_thread(void *param)
Definition: svchlp.c:226
SC_HANDLE register_serviceA(SC_HANDLE scm_handle, PCSTR test_name, PCSTR service_name, PCSTR extra_args OPTIONAL)
Definition: svchlp.c:198
DWORD WINAPI WaitForSingleObject(IN HANDLE hHandle, IN DWORD dwMilliseconds)
Definition: synch.c:82
const uint16_t * PCWSTR
Definition: typedefs.h:57
PVOID HANDLE
Definition: typedefs.h:73
uint32_t * LPDWORD
Definition: typedefs.h:59
const char * PCSTR
Definition: typedefs.h:52
#define PIPE_ACCESS_INBOUND
Definition: winbase.h:165
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
#define NMPWAIT_USE_DEFAULT_WAIT
Definition: winbase.h:134
#define PIPE_WAIT
Definition: winbase.h:171
#define PIPE_READMODE_MESSAGE
Definition: winbase.h:170
#define WAIT_OBJECT_0
Definition: winbase.h:406
#define PIPE_TYPE_MESSAGE
Definition: winbase.h:168
#define WINAPI
Definition: msvc.h:6
#define ERROR_BROKEN_PIPE
Definition: winerror.h:183
#define ERROR_PIPE_CONNECTED
Definition: winerror.h:352
#define SERVICE_ALL_ACCESS
Definition: winsvc.h:62
#define SERVICE_DEMAND_START
Definition: cmtypes.h:978
#define SERVICE_WIN32_OWN_PROCESS
Definition: cmtypes.h:962
#define SERVICE_ERROR_IGNORE
Definition: cmtypes.h:981
const char * LPCSTR
Definition: xmlstorage.h:183
__wchar_t WCHAR
Definition: xmlstorage.h:180
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
char CHAR
Definition: xmlstorage.h:175