ReactOS  0.4.13-dev-551-gf37fb1f
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 
19 static WCHAR named_pipe_name[100]; // Shared: FIXME!
20 
21 static CHAR service_nameA[100];
22 static 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 
27 void 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, strlen(buf)+1, &written, NULL);
34 }
35 
36 void service_trace(const char *msg, ...)
37 {
39  char buf[512];
40 
42  StringCbVPrintfA(buf, sizeof(buf), msg, valist);
43  va_end(valist);
44 
45  send_msg("TRACE", buf);
46 }
47 
48 void service_ok(int cnd, const char *msg, ...)
49 {
51  char buf[512];
52 
54  StringCbVPrintfA(buf, sizeof(buf), msg, valist);
55  va_end(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 
280 void test_runner(void (*run_test)(PCSTR, PCWSTR, void*), void *param)
281 {
282  HANDLE hServerPipe = INVALID_HANDLE_VALUE;
283  HANDLE hThread;
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 
305 Quit:
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 }
DWORD WINAPI GetModuleFileNameW(HINSTANCE hModule, LPWSTR lpFilename, DWORD nSize)
Definition: loader.c:607
BOOL WINAPI WriteFile(IN HANDLE hFile, IN LPCVOID lpBuffer, IN DWORD nNumberOfBytesToWrite OPTIONAL, OUT LPDWORD lpNumberOfBytesWritten, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: rw.c:24
static int argc
Definition: ServiceArgs.c:12
const uint16_t * PCWSTR
Definition: typedefs.h:55
#define trace(...)
Definition: kmt_test.h:217
#define SERVICE_ERROR_IGNORE
Definition: cmtypes.h:979
#define CloseHandle
Definition: compat.h:398
BOOL WINAPI TerminateThread(IN HANDLE hThread, IN DWORD dwExitCode)
Definition: thread.c:548
#define WideCharToMultiByte
Definition: compat.h:101
SC_HANDLE register_serviceW(SC_HANDLE scm_handle, PCWSTR test_name, PCWSTR service_name, PCWSTR extra_args OPTIONAL)
Definition: svchlp.c:212
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
#define PIPE_TYPE_MESSAGE
Definition: winbase.h:168
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
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:808
static SC_HANDLE scm_handle
Definition: ServiceArgs.c:20
static DWORD WINAPI pipe_thread(void *param)
Definition: svchlp.c:226
static CHAR service_nameA[100]
Definition: svchlp.c:21
#define CP_ACP
Definition: compat.h:99
#define _countof(array)
Definition: fontsub.cpp:30
char CHAR
Definition: xmlstorage.h:175
BOOL WINAPI WaitNamedPipeW(LPCWSTR lpNamedPipeName, DWORD nTimeOut)
Definition: npipe.c:458
#define ERROR_INVALID_HANDLE
Definition: compat.h:88
DWORD WINAPI GetTickCount(VOID)
Definition: time.c:445
#define PIPE_WAIT
Definition: winbase.h:171
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
#define INVALID_HANDLE_VALUE
Definition: compat.h:391
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1059
#define NMPWAIT_USE_DEFAULT_WAIT
Definition: winbase.h:134
#define SERVICE_ALL_ACCESS
Definition: winsvc.h:62
#define argv
Definition: mplay32.c:18
SC_HANDLE register_serviceA(SC_HANDLE scm_handle, PCSTR test_name, PCSTR service_name, PCSTR extra_args OPTIONAL)
Definition: svchlp.c:198
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:677
DWORD WINAPI GetModuleFileNameA(HINSTANCE hModule, LPSTR lpFilename, DWORD nSize)
Definition: loader.c:546
STRSAFEAPI StringCbCatW(STRSAFE_LPWSTR pszDest, size_t cbDest, STRSAFE_LPCWSTR pszSrc)
Definition: strsafe.h:342
DWORD WINAPI WaitForSingleObject(IN HANDLE hHandle, IN DWORD dwMilliseconds)
Definition: synch.c:82
#define va_end(ap)
Definition: acmsvcex.h:90
#define ERROR_ACCESS_DENIED
Definition: compat.h:87
unsigned int BOOL
Definition: ntddk_ex.h:94
#define GENERIC_WRITE
Definition: nt_native.h:90
#define ok(value,...)
void service_ok(int cnd, const char *msg,...)
Definition: svchlp.c:48
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:111
smooth NULL
Definition: ftsmooth.c:416
STRSAFEAPI StringCbPrintfW(STRSAFE_LPWSTR pszDest, size_t cbDest, STRSAFE_LPCWSTR pszFormat,...)
Definition: strsafe.h:557
STRSAFEAPI StringCbCopyA(STRSAFE_LPSTR pszDest, size_t cbDest, STRSAFE_LPCSTR pszSrc)
Definition: strsafe.h:161
#define run_test(info, expect_button, expect_radio_button, verification_checked, seq, context)
Definition: taskdialog.c:395
static HRESULT start_service(const WCHAR *name, VARIANT *retval)
Definition: service.c:170
char * va_list
Definition: acmsvcex.h:78
const char * LPCSTR
Definition: xmlstorage.h:183
#define SERVICE_WIN32_OWN_PROCESS
Definition: cmtypes.h:960
void service_trace(const char *msg,...)
Definition: svchlp.c:36
#define OPEN_EXISTING
Definition: compat.h:426
#define WAIT_OBJECT_0
Definition: winbase.h:387
BOOL WINAPI FlushFileBuffers(IN HANDLE hFile)
Definition: fileinfo.c:175
STRSAFEAPI StringCbPrintfA(STRSAFE_LPSTR pszDest, size_t cbDest, STRSAFE_LPCSTR pszFormat,...)
Definition: strsafe.h:547
__wchar_t WCHAR
Definition: xmlstorage.h:180
GLfloat param
Definition: glext.h:5796
#define MAX_PATH
Definition: compat.h:26
#define WINAPI
Definition: msvc.h:8
int strncmp(const char *String1, const char *String2, ACPI_SIZE Count)
Definition: utclib.c:534
static char service_name[100]
PVOID HANDLE
Definition: typedefs.h:71
unsigned long DWORD
Definition: ntddk_ex.h:95
#define ERROR_BROKEN_PIPE
Definition: winerror.h:183
STRSAFEAPI StringCbVPrintfA(STRSAFE_LPSTR pszDest, size_t cbDest, STRSAFE_LPCSTR pszFormat, va_list argList)
Definition: strsafe.h:502
#define FILE_ATTRIBUTE_NORMAL
Definition: compat.h:126
static const WCHAR L[]
Definition: oid.c:1250
#define ERROR_PIPE_CONNECTED
Definition: winerror.h:352
BOOL WINAPI DisconnectNamedPipe(HANDLE hNamedPipe)
Definition: npipe.c:961
#define PIPE_READMODE_MESSAGE
Definition: winbase.h:170
static const char * test_name
Definition: run.c:166
static WCHAR named_pipe_name[100]
Definition: svchlp.c:19
STRSAFEAPI StringCbCatA(STRSAFE_LPSTR pszDest, size_t cbDest, STRSAFE_LPCSTR pszSrc)
Definition: strsafe.h:337
#define PIPE_ACCESS_INBOUND
Definition: winbase.h:165
static WCHAR service_nameW[100]
Definition: svchlp.c:22
#define va_start(ap, A)
Definition: acmsvcex.h:91
HANDLE hThread
Definition: wizard.c:27
#define MultiByteToWideChar
Definition: compat.h:100
#define CreateFileW
Definition: compat.h:400
#define skip(...)
#define msg(x)
Definition: auth_time.c:54
void test_runner(void(*run_test)(PCSTR, PCWSTR, void *), void *param)
Definition: svchlp.c:280
GLuint res
Definition: glext.h:9613
uint32_t * LPDWORD
Definition: typedefs.h:57
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
static __ms_va_list valist
Definition: printf.c:59
void send_msg(const char *type, const char *msg)
Definition: svchlp.c:27
const char * PCSTR
Definition: typedefs.h:51
static HANDLE hClientPipe
Definition: svchlp.c:18
HANDLE WINAPI CreateNamedPipeW(LPCWSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances, DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut, LPSECURITY_ATTRIBUTES lpSecurityAttributes)
Definition: npipe.c:246
#define SERVICE_DEMAND_START
Definition: cmtypes.h:976
BOOL WINAPI ReadFile(IN HANDLE hFile, IN LPVOID lpBuffer, IN DWORD nNumberOfBytesToRead, OUT LPDWORD lpNumberOfBytesRead OPTIONAL, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: rw.c:123
BOOL WINAPI ConnectNamedPipe(IN HANDLE hNamedPipe, IN LPOVERLAPPED lpOverlapped)
Definition: npipe.c:701
_CRTIMP int __cdecl read(_In_ int _FileHandle, _Out_writes_bytes_(_MaxCharCount) void *_DstBuf, _In_ unsigned int _MaxCharCount)
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
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68