ReactOS  0.4.12-dev-90-g2e2e63e
NtApphelpCacheControl.c
Go to the documentation of this file.
1 /*
2  * PROJECT: ReactOS API Tests
3  * LICENSE: LGPL - See COPYING.LIB in the top level directory
4  * PURPOSE: Tests for SHIM engine caching.
5  * PROGRAMMER: Mark Jansen
6  */
7 
8 #include "precomp.h"
9 
10 #include <winsvc.h>
11 
13 {
16 };
17 
19 
21 {
22  APPHELP_CACHE_SERVICE_LOOKUP CacheEntry = { {0} };
24  CacheEntry.ImageName = *PathName;
25  if (WithMapping)
26  {
27  OBJECT_ATTRIBUTES LocalObjectAttributes;
29  InitializeObjectAttributes(&LocalObjectAttributes, PathName,
31  Status = NtOpenFile(&CacheEntry.ImageHandle,
33  &LocalObjectAttributes, &IoStatusBlock,
36  ok_ntstatus(Status, STATUS_SUCCESS);
37  }
38  else
39  {
40  CacheEntry.ImageHandle = INVALID_HANDLE_VALUE;
41  }
42  Status = pNtApphelpCacheControl(Service, &CacheEntry);
43  if (CacheEntry.ImageHandle != INVALID_HANDLE_VALUE)
44  NtClose(CacheEntry.ImageHandle);
45  return Status;
46 }
47 
48 int InitEnv(UNICODE_STRING* PathName)
49 {
51  if (Status == STATUS_INVALID_PARAMETER)
52  {
53  /* Windows Vista+ has a different layout for APPHELP_CACHE_SERVICE_LOOKUP */
54  return 0;
55  }
56  ok(Status == STATUS_SUCCESS || Status == STATUS_NOT_FOUND,
57  "Wrong value for Status, expected: SUCCESS or NOT_FOUND, got: 0x%lx\n",
58  Status);
59  return 1;
60 }
61 
63 {
64  APPHELP_CACHE_SERVICE_LOOKUP CacheEntry = { {0} };
66 
67  /* Validate the handling of a NULL pointer */
68  Status = pNtApphelpCacheControl(ApphelpCacheServiceRemove, NULL);
70  Status = pNtApphelpCacheControl(ApphelpCacheServiceLookup, NULL);
72 
73  /* Validate the handling of a NULL pointer inside the struct */
74  Status = pNtApphelpCacheControl(ApphelpCacheServiceRemove, &CacheEntry);
76  Status = pNtApphelpCacheControl(ApphelpCacheServiceLookup, &CacheEntry);
78 
79  /* Just call the dump function */
80  Status = pNtApphelpCacheControl(ApphelpCacheServiceDump, NULL);
81  ok_ntstatus(Status, STATUS_SUCCESS);
82 
83  /* Validate the handling of an invalid handle inside the struct */
84  CacheEntry.ImageName = *PathName;
85  CacheEntry.ImageHandle = (HANDLE)2;
86  Status = pNtApphelpCacheControl(ApphelpCacheServiceLookup, &CacheEntry);
88 
89  /* Validate the handling of an invalid service number */
90  Status = pNtApphelpCacheControl(999, NULL);
92  Status = pNtApphelpCacheControl(999, &CacheEntry);
94 }
95 
96 static BOOLEAN RequestAddition(SC_HANDLE service_handle, BOOLEAN WithMapping)
97 {
99  ControlService(service_handle, WithMapping ? RegisterShimCacheWithHandle :
101  /* TODO: how to get a return code from the service? */
102  return TRUE;
103 }
104 
106 {
108  UNICODE_STRING ntPath;
109  BOOLEAN Result;
111  APPHELP_CACHE_SERVICE_LOOKUP CacheEntry;
112 
113  GetModuleFileNameW(NULL, szPath, sizeof(szPath) / sizeof(szPath[0]));
114  Result = RtlDosPathNameToNtPathName_U(szPath, &ntPath, NULL, NULL);
115  ok(Result == TRUE, "RtlDosPathNameToNtPathName_U\n");
116  if (!InitEnv(&ntPath))
117  {
118  skip("NtApphelpCacheControl expects a different structure layout\n");
119  return;
120  }
121  /* At this point we have made sure that our binary is not present in the cache,
122  and that the NtApphelpCacheControl function expects the struct layout we use. */
123  CheckValidation(&ntPath);
124 
125  /* We expect not to find it */
126  Status = CallCacheControl(&ntPath, TRUE, ApphelpCacheServiceLookup);
127  ok_ntstatus(Status, STATUS_NOT_FOUND);
129  ok_ntstatus(Status, STATUS_NOT_FOUND);
130 
131  /* First we add our process without a file handle (so it will be registered without file info) */
132  RequestAddition(service_handle, FALSE);
133 
134  /* now we try to find it without validating file info */
136  ok_ntstatus(Status, STATUS_SUCCESS);
137  /* when validating file info the cache notices the file is wrong, so it is dropped from the cache */
138  Status = CallCacheControl(&ntPath, TRUE, ApphelpCacheServiceLookup);
139  ok_ntstatus(Status, STATUS_NOT_FOUND);
140  /* making the second check without info also fail. */
142  ok_ntstatus(Status, STATUS_NOT_FOUND);
143 
144 
145  /* Now we add the file with file info */
146  RequestAddition(service_handle, TRUE);
147 
148  /* so both checks should succeed */
149  Status = CallCacheControl(&ntPath, TRUE, ApphelpCacheServiceLookup);
150  ok_ntstatus(Status, STATUS_SUCCESS);
152  ok_ntstatus(Status, STATUS_SUCCESS);
153 
154  /* We know the file is in the cache now (assuming previous tests succeeded,
155  let's test invalid handle behavior */
156  CacheEntry.ImageName = ntPath;
157  CacheEntry.ImageHandle = 0;
158  Status = pNtApphelpCacheControl(ApphelpCacheServiceLookup, &CacheEntry);
159  ok_ntstatus(Status, STATUS_NOT_FOUND);
160 
161  /* re-add it for the next test */
162  RequestAddition(service_handle, TRUE);
163  Status = CallCacheControl(&ntPath, TRUE, ApphelpCacheServiceLookup);
164  ok_ntstatus(Status, STATUS_SUCCESS);
165  CacheEntry.ImageHandle = (HANDLE)1;
166  Status = pNtApphelpCacheControl(ApphelpCacheServiceLookup, &CacheEntry);
167  ok_ntstatus(Status, STATUS_NOT_FOUND);
168 
169  /* and again */
170  RequestAddition(service_handle, TRUE);
171  Status = CallCacheControl(&ntPath, TRUE, ApphelpCacheServiceLookup);
172  ok_ntstatus(Status, STATUS_SUCCESS);
173 #ifdef _WIN64
174  CacheEntry.ImageHandle = (HANDLE)0x8000000000000000ULL;
175 #else
176  CacheEntry.ImageHandle = (HANDLE)0x80000000;
177 #endif
178  Status = pNtApphelpCacheControl(ApphelpCacheServiceLookup, &CacheEntry);
179  ok_ntstatus(Status, STATUS_NOT_FOUND);
180 
181  RtlFreeHeap(RtlGetProcessHeap(), 0, ntPath.Buffer);
182 }
183 
184 
185 /* Most service related code was taken from services_winetest:service and modified for usage here
186  The rest came from MSDN */
187 
188 static SERVICE_STATUS_HANDLE (WINAPI *pRegisterServiceCtrlHandlerExA)(LPCSTR,LPHANDLER_FUNCTION_EX,LPVOID);
189 static char service_name[100] = "apphelp_test_service";
192 
194 {
196  UNICODE_STRING ntPath;
197  BOOLEAN Result;
199  GetModuleFileNameW(NULL, szPath, sizeof(szPath) / sizeof(szPath[0]));
200  Result = RtlDosPathNameToNtPathName_U(szPath, &ntPath, NULL, NULL);
201  if (!Result)
202  {
203  DbgPrint("RegisterInShimCache: RtlDosPathNameToNtPathName_U failed\n");
204  return FALSE;
205  }
206 
207  Status = CallCacheControl(&ntPath, WithMapping, ApphelpCacheServiceUpdate);
208  if (!NT_SUCCESS(Status))
209  {
210  DbgPrint("RegisterInShimCache: CallCacheControl failed\n");
211  RtlFreeHeap(RtlGetProcessHeap(), 0, ntPath.Buffer);
212  return FALSE;
213  }
214  RtlFreeHeap(RtlGetProcessHeap(), 0, ntPath.Buffer);
215  return TRUE;
216 }
217 
218 
219 static DWORD WINAPI service_handler(DWORD ctrl, DWORD event_type, void *event_data, void *context)
220 {
221  SERVICE_STATUS status = {0};
222  status.dwServiceType = SERVICE_WIN32;
224 
225  switch(ctrl)
226  {
230  status.dwControlsAccepted = 0;
232  SetEvent(service_stop_event);
233  return NO_ERROR;
236  {
237  /* TODO: how should we communicate a failure? */
238  }
239  break;
242  {
243  /* TODO: how should we communicate a failure? */
244  }
245  break;
246  default:
247  DbgPrint("Unhandled: %d\n", ctrl);
248  break;
249  }
252  return NO_ERROR;
253 }
254 
255 static void WINAPI service_main(DWORD argc, char **argv)
256 {
257  SERVICE_STATUS status = {0};
258  service_status = pRegisterServiceCtrlHandlerExA(service_name, service_handler, NULL);
259  if(!service_status)
260  return;
261 
262  status.dwServiceType = SERVICE_WIN32;
266 
267  WaitForSingleObject(service_stop_event, INFINITE);
268 
270  status.dwControlsAccepted = 0;
272 }
273 
274 static SC_HANDLE InstallService(SC_HANDLE scm_handle)
275 {
276  char service_cmd[MAX_PATH+150], *ptr;
277  SC_HANDLE service;
278 
279  ptr = service_cmd + GetModuleFileNameA(NULL, service_cmd, MAX_PATH);
280  strcpy(ptr, " NtApphelpCacheControl service");
281  ptr += strlen(ptr);
282 
283  service = CreateServiceA(scm_handle, service_name, service_name, GENERIC_ALL,
285  service_cmd, NULL, NULL, NULL, NULL, NULL);
286  if (!service)
287  {
288  skip("Could not create helper service\n");
289  return NULL;
290  }
291  return service;
292 }
293 
295 {
296  DWORD dwBytesNeeded;
297  DWORD dwStartTime = GetTickCount();
298  while (ssp->dwCurrentState != Status)
299  {
300  Sleep(40);
301  if (!QueryServiceStatusEx(service_handle, SC_STATUS_PROCESS_INFO,
302  (LPBYTE)ssp, sizeof(SERVICE_STATUS_PROCESS), &dwBytesNeeded ))
303  {
304  ok(0, "QueryServiceStatusEx failed waiting for %lu\n", Status);
305  break;
306  }
307  if ((GetTickCount() - dwStartTime) > 1000)
308  {
309  ok(0, "Timeout waiting for (%lu) from service, is: %lu.\n",
310  Status, ssp->dwCurrentState);
311  break;
312  }
313  }
314 }
315 
316 static void RunTest()
317 {
319  SC_HANDLE service_handle = InstallService(scm_handle);
320  if (service_handle)
321  {
322  SERVICE_STATUS_PROCESS ssp = {0};
323  BOOL res = StartServiceA(service_handle, 0, NULL);
324  if (res)
325  {
326  WaitService(service_handle, SERVICE_RUNNING, &ssp);
327  RunApphelpCacheControlTests(service_handle);
328  ControlService(service_handle, SERVICE_CONTROL_STOP, (LPSERVICE_STATUS)&ssp);
329  WaitService(service_handle, SERVICE_STOPPED, &ssp);
330  }
331  else
332  {
333  skip("Could not start helper service\n");
334  }
335  DeleteService(service_handle);
336  }
337  CloseServiceHandle(scm_handle);
338 }
339 
341 {
342  char **argv;
343  int argc;
344 
345  pRegisterServiceCtrlHandlerExA = (void*)GetProcAddress(GetModuleHandleA("advapi32.dll"), "RegisterServiceCtrlHandlerExA");
346  if (!pRegisterServiceCtrlHandlerExA)
347  {
348  win_skip("RegisterServiceCtrlHandlerExA not available, skipping tests\n");
349  return;
350  }
351 
352  pNtApphelpCacheControl = (void*)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtApphelpCacheControl");
353  if (!pNtApphelpCacheControl)
354  {
355  win_skip("NtApphelpCacheControl not available, skipping tests\n");
356  return;
357  }
358 
359  argc = winetest_get_mainargs(&argv);
360  if(argc < 3)
361  {
362  RunTest();
363  }
364  else
365  {
366  SERVICE_TABLE_ENTRYA servtbl[] = {
368  {NULL, NULL}
369  };
370  service_stop_event = CreateEventA(NULL, TRUE, FALSE, NULL);
372  Sleep(50);
373  CloseHandle(service_stop_event);
374  }
375 }
376 
377 
static LPVOID
DWORD WINAPI GetModuleFileNameW(HINSTANCE hModule, LPWSTR lpFilename, DWORD nSize)
Definition: loader.c:607
static DWORD WINAPI service_handler(DWORD ctrl, DWORD event_type, void *event_data, void *context)
static int argc
Definition: ServiceArgs.c:12
#define SERVICE_ERROR_IGNORE
Definition: cmtypes.h:979
#define GENERIC_ALL
Definition: nt_native.h:92
#define TRUE
Definition: types.h:120
#define CloseHandle
Definition: compat.h:398
VOID WINAPI DECLSPEC_HOTPATCH Sleep(IN DWORD dwMilliseconds)
Definition: synch.c:736
static PAPPHELP_CACHE_SERVICE_LOOKUP
DWORD dwCurrentState
Definition: winsvc.h:100
#define DbgPrint
Definition: loader.c:25
Definition: http.c:6587
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
static SC_HANDLE scm_handle
Definition: ServiceArgs.c:20
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
__wchar_t WCHAR
Definition: xmlstorage.h:180
static SERVICE_STATUS_HANDLE service_status
int InitEnv(UNICODE_STRING *PathName)
NTSTATUS CallCacheControl(UNICODE_STRING *PathName, BOOLEAN WithMapping, APPHELPCACHESERVICECLASS Service)
LONG NTSTATUS
Definition: precomp.h:26
#define SERVICE_ACCEPT_STOP
Definition: winsvc.h:28
BOOLEAN NTAPI RtlFreeHeap(IN PVOID HeapHandle, IN ULONG Flags, IN PVOID HeapBase)
Definition: heap.c:603
static LPHANDLER_FUNCTION_EX
DWORD WINAPI GetTickCount(VOID)
Definition: time.c:445
#define INVALID_HANDLE_VALUE
Definition: compat.h:391
BOOL WINAPI DECLSPEC_HOTPATCH SetEvent(IN HANDLE hEvent)
Definition: synch.c:679
static HANDLE service_stop_event
static SERVICE_STATUS_HANDLE service_handle
Definition: rpcss_main.c:38
BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel, LPBYTE lpBuffer, DWORD cbBufSize, LPDWORD pcbBytesNeeded)
Definition: scm.c:2829
BOOL WINAPI DeleteService(SC_HANDLE hService)
Definition: scm.c:915
#define NO_ERROR
Definition: dderror.h:5
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:676
BOOL WINAPI StartServiceCtrlDispatcherA(const SERVICE_TABLE_ENTRYA *lpServiceStartTable)
Definition: sctrl.c:995
DWORD WINAPI GetModuleFileNameA(HINSTANCE hModule, LPSTR lpFilename, DWORD nSize)
Definition: loader.c:546
static char ** argv
Definition: ServiceArgs.c:11
#define FILE_SHARE_READ
Definition: compat.h:125
static void WINAPI service_main(DWORD argc, char **argv)
BOOL WINAPI SetServiceStatus(SERVICE_STATUS_HANDLE hServiceStatus, LPSERVICE_STATUS lpServiceStatus)
Definition: sctrl.c:957
DWORD WINAPI WaitForSingleObject(IN HANDLE hHandle, IN DWORD dwMilliseconds)
Definition: synch.c:82
#define SERVICE_STOPPED
Definition: winsvc.h:21
unsigned char * LPBYTE
Definition: typedefs.h:52
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
SC_HANDLE WINAPI OpenSCManagerA(LPCSTR lpMachineName, LPCSTR lpDatabaseName, DWORD dwDesiredAccess)
Definition: scm.c:1966
static BOOLEAN RegisterInShimCache(BOOLEAN WithMapping)
#define FILE_READ_DATA
Definition: nt_native.h:628
#define SERVICE_RUNNING
Definition: winsvc.h:24
static PVOID ptr
Definition: dispmode.c:27
BOOL WINAPI CloseServiceHandle(SC_HANDLE hSCObject)
Definition: scm.c:576
static NTSTATUS(NTAPI *pNtApphelpCacheControl)(APPHELPCACHESERVICECLASS
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
static void RunTest()
_At_(*)(_In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName, _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace, _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints, _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp Result)(Mem)) NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO
Definition: wsk.h:426
HANDLE WINAPI DECLSPEC_HOTPATCH CreateEventA(IN LPSECURITY_ATTRIBUTES lpEventAttributes OPTIONAL, IN BOOL bManualReset, IN BOOL bInitialState, IN LPCSTR lpName OPTIONAL)
Definition: synch.c:583
#define ok_ntstatus(status, expected)
Definition: test.h:800
const char * LPCSTR
Definition: xmlstorage.h:183
#define SERVICE_WIN32_OWN_PROCESS
Definition: cmtypes.h:960
#define ctrl
Definition: input.c:1669
#define ok(value,...)
Definition: CComObject.cpp:34
BOOL WINAPI StartServiceA(SC_HANDLE hService, DWORD dwNumServiceArgs, LPCSTR *lpServiceArgVectors)
Definition: scm.c:2884
static SERVICE_STATUS_HANDLE(WINAPI *pRegisterServiceCtrlHandlerExA)(LPCSTR
UNICODE_STRING ImageName
Definition: pstypes.h:934
START_TEST(NtApphelpCacheControl)
NTSYSAPI NTSTATUS NTAPI NtOpenFile(OUT PHANDLE phFile, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, OUT PIO_STATUS_BLOCK pIoStatusBlock, IN ULONG ShareMode, IN ULONG OpenMode)
Definition: file.c:3929
#define STATUS_NOT_FOUND
Definition: shellext.h:67
#define SERVICE_ACCEPT_SHUTDOWN
Definition: winsvc.h:30
unsigned int BOOL
Definition: ntddk_ex.h:94
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:24
#define MAX_PATH
Definition: compat.h:26
static char service_name[100]
NTSTATUS NTAPI NtApphelpCacheControl(_In_ APPHELPCACHESERVICECLASS Service, _In_opt_ PAPPHELP_CACHE_SERVICE_LOOKUP ServiceData)
Definition: apphelp.c:729
unsigned long DWORD
Definition: ntddk_ex.h:95
PVOID HANDLE
Definition: typedefs.h:71
DWORD dwServiceType
Definition: winsvc.h:99
int winetest_get_mainargs(char ***pargv)
NTSTATUS NTAPI NtClose(IN HANDLE Handle)
Definition: obhandle.c:3393
#define OBJ_CASE_INSENSITIVE
Definition: winternl.h:228
#define FILE_READ_ATTRIBUTES
Definition: nt_native.h:647
#define FILE_SHARE_DELETE
Definition: nt_native.h:682
#define FILE_EXECUTE
Definition: nt_native.h:642
#define FILE_NON_DIRECTORY_FILE
Definition: constants.h:492
HMODULE WINAPI DECLSPEC_HOTPATCH GetModuleHandleA(LPCSTR lpModuleName)
Definition: loader.c:819
#define SYNCHRONIZE
Definition: nt_native.h:61
#define WINAPI
Definition: msvc.h:20
Status
Definition: gdiplustypes.h:24
static void WaitService(SC_HANDLE service_handle, DWORD Status, SERVICE_STATUS_PROCESS *ssp)
DWORD dwControlsAccepted
Definition: winsvc.h:101
LPCWSTR szPath
Definition: env.c:35
static void RunApphelpCacheControlTests(SC_HANDLE service_handle)
#define skip(...)
Definition: CString.cpp:57
#define SERVICE_WIN32
Definition: cmtypes.h:962
enum _APPHELPCACHESERVICECLASS APPHELPCACHESERVICECLASS
static SC_HANDLE InstallService(SC_HANDLE scm_handle)
static OUT PIO_STATUS_BLOCK IoStatusBlock
Definition: pipe.c:75
BOOL WINAPI ControlService(SC_HANDLE hService, DWORD dwControl, LPSERVICE_STATUS lpServiceStatus)
Definition: scm.c:618
#define SC_MANAGER_ALL_ACCESS
Definition: winsvc.h:13
#define FILE_SYNCHRONOUS_IO_NONALERT
Definition: from_kernel.h:31
static BOOLEAN RequestAddition(SC_HANDLE service_handle, BOOLEAN WithMapping)
GLuint res
Definition: glext.h:9613
char * strcpy(char *DstString, const char *SrcString)
Definition: utclib.c:388
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
#define GetProcAddress(x, y)
Definition: compat.h:410
#define SERVICE_CONTROL_STOP
Definition: winsvc.h:36
#define SERVICE_DEMAND_START
Definition: cmtypes.h:976
#define INFINITE
Definition: serial.h:102
return STATUS_SUCCESS
Definition: btrfs.c:2725
#define win_skip
Definition: test.h:141
#define SERVICE_STOP_PENDING
Definition: winsvc.h:23
void CheckValidation(UNICODE_STRING *PathName)
NTSYSAPI BOOLEAN NTAPI RtlDosPathNameToNtPathName_U(_In_opt_z_ PCWSTR DosPathName, _Out_ PUNICODE_STRING NtPathName, _Out_opt_ PCWSTR *NtFileNamePart, _Out_opt_ PRTL_RELATIVE_NAME_U DirectoryInfo)
#define SERVICE_CONTROL_SHUTDOWN
Definition: winsvc.h:40
Definition: ps.c:97