mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 23:33:01 +00:00
[ROSTESTS]: advapi32_apitest: Add a test to extensively test services command-line arguments. By Thomas Faber.
[ADVAPI32]: Correctly set up both the ANSI and UNICODE service command-line arguments. Adapted from a patch by Thomas Faber. Thanks! [SERVICES] - Correctly pack the service command-line arguments in the control packet structure. In particular, the offsets stored in the vector are relative to the beginning of the vector (and not relative to the previous offset ^^). Improve comments... - Fix the definition of the SCM_CONTROL_PACKET control packet structure to make it Win2k3-compatible, so that we can use Win2k3' advapi32.dll or services.exe on ReactOS and vice-versa. CORE-9235 CORE-9838 svn path=/trunk/; revision=73413
This commit is contained in:
parent
b687b6775f
commit
0d21c76ef1
6 changed files with 592 additions and 133 deletions
|
@ -1216,17 +1216,17 @@ ScmSendStartCommand(PSERVICE Service,
|
||||||
DWORD argc,
|
DWORD argc,
|
||||||
LPWSTR* argv)
|
LPWSTR* argv)
|
||||||
{
|
{
|
||||||
|
DWORD dwError = ERROR_SUCCESS;
|
||||||
PSCM_CONTROL_PACKET ControlPacket;
|
PSCM_CONTROL_PACKET ControlPacket;
|
||||||
SCM_REPLY_PACKET ReplyPacket;
|
SCM_REPLY_PACKET ReplyPacket;
|
||||||
DWORD PacketSize;
|
DWORD PacketSize;
|
||||||
PWSTR Ptr;
|
|
||||||
DWORD dwWriteCount = 0;
|
|
||||||
DWORD dwReadCount = 0;
|
|
||||||
DWORD dwError = ERROR_SUCCESS;
|
|
||||||
DWORD i;
|
DWORD i;
|
||||||
|
PWSTR Ptr;
|
||||||
PWSTR *pOffPtr;
|
PWSTR *pOffPtr;
|
||||||
PWSTR pArgPtr;
|
PWSTR pArgPtr;
|
||||||
BOOL bResult;
|
BOOL bResult;
|
||||||
|
DWORD dwWriteCount = 0;
|
||||||
|
DWORD dwReadCount = 0;
|
||||||
#ifdef USE_ASYNCHRONOUS_IO
|
#ifdef USE_ASYNCHRONOUS_IO
|
||||||
OVERLAPPED Overlapped = {0};
|
OVERLAPPED Overlapped = {0};
|
||||||
#endif
|
#endif
|
||||||
|
@ -1234,26 +1234,32 @@ ScmSendStartCommand(PSERVICE Service,
|
||||||
DPRINT("ScmSendStartCommand() called\n");
|
DPRINT("ScmSendStartCommand() called\n");
|
||||||
|
|
||||||
/* Calculate the total length of the start command line */
|
/* Calculate the total length of the start command line */
|
||||||
PacketSize = sizeof(SCM_CONTROL_PACKET) +
|
PacketSize = sizeof(SCM_CONTROL_PACKET);
|
||||||
(DWORD)((wcslen(Service->lpServiceName) + 1) * sizeof(WCHAR));
|
PacketSize += (DWORD)((wcslen(Service->lpServiceName) + 1) * sizeof(WCHAR));
|
||||||
|
|
||||||
/* Calculate the required packet size for the start arguments */
|
/*
|
||||||
|
* Calculate the required packet size for the start argument vector 'argv',
|
||||||
|
* composed of the list of pointer offsets, followed by UNICODE strings.
|
||||||
|
* The strings are stored continuously after the vector of offsets, with
|
||||||
|
* the offsets being relative to the beginning of the vector, as in the
|
||||||
|
* following layout (with N == argc):
|
||||||
|
* [argOff(0)]...[argOff(N-1)][str(0)]...[str(N-1)] .
|
||||||
|
*/
|
||||||
if (argc > 0 && argv != NULL)
|
if (argc > 0 && argv != NULL)
|
||||||
{
|
{
|
||||||
PacketSize = ALIGN_UP(PacketSize, LPWSTR);
|
PacketSize = ALIGN_UP(PacketSize, PWSTR);
|
||||||
|
PacketSize += (argc * sizeof(PWSTR));
|
||||||
|
|
||||||
DPRINT("Argc: %lu\n", argc);
|
DPRINT("Argc: %lu\n", argc);
|
||||||
for (i = 0; i < argc; i++)
|
for (i = 0; i < argc; i++)
|
||||||
{
|
{
|
||||||
DPRINT("Argv[%lu]: %S\n", i, argv[i]);
|
DPRINT("Argv[%lu]: %S\n", i, argv[i]);
|
||||||
PacketSize += (DWORD)((wcslen(argv[i]) + 1) * sizeof(WCHAR) + sizeof(PWSTR));
|
PacketSize += (DWORD)((wcslen(argv[i]) + 1) * sizeof(WCHAR));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate a control packet */
|
/* Allocate a control packet */
|
||||||
ControlPacket = HeapAlloc(GetProcessHeap(),
|
ControlPacket = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, PacketSize);
|
||||||
HEAP_ZERO_MEMORY,
|
|
||||||
PacketSize);
|
|
||||||
if (ControlPacket == NULL)
|
if (ControlPacket == NULL)
|
||||||
return ERROR_NOT_ENOUGH_MEMORY;
|
return ERROR_NOT_ENOUGH_MEMORY;
|
||||||
|
|
||||||
|
@ -1262,22 +1268,23 @@ ScmSendStartCommand(PSERVICE Service,
|
||||||
? SERVICE_CONTROL_START_OWN
|
? SERVICE_CONTROL_START_OWN
|
||||||
: SERVICE_CONTROL_START_SHARE;
|
: SERVICE_CONTROL_START_SHARE;
|
||||||
ControlPacket->hServiceStatus = (SERVICE_STATUS_HANDLE)Service;
|
ControlPacket->hServiceStatus = (SERVICE_STATUS_HANDLE)Service;
|
||||||
ControlPacket->dwServiceNameOffset = sizeof(SCM_CONTROL_PACKET);
|
|
||||||
|
|
||||||
Ptr = (PWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset);
|
/* Copy the start command line */
|
||||||
|
ControlPacket->dwServiceNameOffset = sizeof(SCM_CONTROL_PACKET);
|
||||||
|
Ptr = (PWSTR)((ULONG_PTR)ControlPacket + ControlPacket->dwServiceNameOffset);
|
||||||
wcscpy(Ptr, Service->lpServiceName);
|
wcscpy(Ptr, Service->lpServiceName);
|
||||||
|
|
||||||
ControlPacket->dwArgumentsCount = 0;
|
ControlPacket->dwArgumentsCount = 0;
|
||||||
ControlPacket->dwArgumentsOffset = 0;
|
ControlPacket->dwArgumentsOffset = 0;
|
||||||
|
|
||||||
/* Copy argument list */
|
/* Copy the argument vector */
|
||||||
if (argc > 0 && argv != NULL)
|
if (argc > 0 && argv != NULL)
|
||||||
{
|
{
|
||||||
Ptr += wcslen(Service->lpServiceName) + 1;
|
Ptr += wcslen(Service->lpServiceName) + 1;
|
||||||
pOffPtr = (PWSTR*)ALIGN_UP_POINTER(Ptr, PWSTR);
|
pOffPtr = (PWSTR*)ALIGN_UP_POINTER(Ptr, PWSTR);
|
||||||
pArgPtr = (PWSTR)((ULONG_PTR)pOffPtr + argc * sizeof(PWSTR));
|
pArgPtr = (PWSTR)((ULONG_PTR)pOffPtr + argc * sizeof(PWSTR));
|
||||||
|
|
||||||
ControlPacket->dwArgumentsCount = argc;
|
ControlPacket->dwArgumentsCount = argc;
|
||||||
ControlPacket->dwArgumentsOffset = (DWORD)((ULONG_PTR)pOffPtr - (ULONG_PTR)ControlPacket);
|
ControlPacket->dwArgumentsOffset = (DWORD)((ULONG_PTR)pOffPtr - (ULONG_PTR)ControlPacket);
|
||||||
|
|
||||||
DPRINT("dwArgumentsCount: %lu\n", ControlPacket->dwArgumentsCount);
|
DPRINT("dwArgumentsCount: %lu\n", ControlPacket->dwArgumentsCount);
|
||||||
|
@ -1285,12 +1292,10 @@ ScmSendStartCommand(PSERVICE Service,
|
||||||
|
|
||||||
for (i = 0; i < argc; i++)
|
for (i = 0; i < argc; i++)
|
||||||
{
|
{
|
||||||
wcscpy(pArgPtr, argv[i]);
|
wcscpy(pArgPtr, argv[i]);
|
||||||
*pOffPtr = (PWSTR)((ULONG_PTR)pArgPtr - (ULONG_PTR)pOffPtr);
|
pOffPtr[i] = (PWSTR)((ULONG_PTR)pArgPtr - (ULONG_PTR)pOffPtr);
|
||||||
DPRINT("offset: %p\n", *pOffPtr);
|
DPRINT("offset[%lu]: %p\n", i, pOffPtr[i]);
|
||||||
|
pArgPtr += wcslen(argv[i]) + 1;
|
||||||
pArgPtr += wcslen(argv[i]) + 1;
|
|
||||||
pOffPtr++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -278,58 +278,88 @@ ScConnectControlPipe(HANDLE *hPipe)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ansi/Unicode argument layout of the vector passed to a service at startup,
|
||||||
|
* depending on the different versions of Windows considered:
|
||||||
|
*
|
||||||
|
* - XP/2003:
|
||||||
|
* [argv array of pointers][parameter 1][parameter 2]...[service name]
|
||||||
|
*
|
||||||
|
* - Vista:
|
||||||
|
* [argv array of pointers][align to 8 bytes]
|
||||||
|
* [parameter 1][parameter 2]...[service name]
|
||||||
|
*
|
||||||
|
* - Win7/8:
|
||||||
|
* [argv array of pointers][service name]
|
||||||
|
* [parameter 1][align to 4 bytes][parameter 2][align to 4 bytes]...
|
||||||
|
*
|
||||||
|
* Space for parameters and service name is always enough to store
|
||||||
|
* both the Ansi and the Unicode versions including NULL terminator.
|
||||||
|
*/
|
||||||
|
|
||||||
static DWORD
|
static DWORD
|
||||||
ScBuildUnicodeArgsVector(PSCM_CONTROL_PACKET ControlPacket,
|
ScBuildUnicodeArgsVector(PSCM_CONTROL_PACKET ControlPacket,
|
||||||
LPDWORD lpArgCount,
|
LPDWORD lpArgCount,
|
||||||
LPWSTR **lpArgVector)
|
LPWSTR **lpArgVector)
|
||||||
{
|
{
|
||||||
LPWSTR *lpVector;
|
PWSTR *lpVector;
|
||||||
LPWSTR *lpArg;
|
PWSTR pszServiceName;
|
||||||
LPWSTR pszServiceName;
|
|
||||||
DWORD cbServiceName;
|
DWORD cbServiceName;
|
||||||
|
DWORD cbArguments;
|
||||||
DWORD cbTotal;
|
DWORD cbTotal;
|
||||||
DWORD i;
|
DWORD i;
|
||||||
|
|
||||||
if (ControlPacket == NULL || lpArgCount == NULL || lpArgVector == NULL)
|
if (ControlPacket == NULL || lpArgCount == NULL || lpArgVector == NULL)
|
||||||
return ERROR_INVALID_PARAMETER;
|
return ERROR_INVALID_PARAMETER;
|
||||||
|
|
||||||
*lpArgCount = 0;
|
*lpArgCount = 0;
|
||||||
*lpArgVector = NULL;
|
*lpArgVector = NULL;
|
||||||
|
|
||||||
pszServiceName = (PWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset);
|
/* Retrieve and count the start command line (NULL-terminated) */
|
||||||
cbServiceName = lstrlenW(pszServiceName) * sizeof(WCHAR) + sizeof(UNICODE_NULL);
|
pszServiceName = (PWSTR)((ULONG_PTR)ControlPacket + ControlPacket->dwServiceNameOffset);
|
||||||
|
cbServiceName = lstrlenW(pszServiceName) * sizeof(WCHAR) + sizeof(UNICODE_NULL);
|
||||||
|
|
||||||
cbTotal = cbServiceName + sizeof(LPWSTR);
|
/*
|
||||||
|
* The total size of the argument vector is equal to the entry for
|
||||||
|
* the service name, plus the size of the original argument vector.
|
||||||
|
*/
|
||||||
|
cbTotal = sizeof(PWSTR) + cbServiceName;
|
||||||
if (ControlPacket->dwArgumentsCount > 0)
|
if (ControlPacket->dwArgumentsCount > 0)
|
||||||
cbTotal += ControlPacket->dwSize - ControlPacket->dwArgumentsOffset;
|
cbArguments = ControlPacket->dwSize - ControlPacket->dwArgumentsOffset;
|
||||||
|
else
|
||||||
|
cbArguments = 0;
|
||||||
|
cbTotal += cbArguments;
|
||||||
|
|
||||||
lpVector = HeapAlloc(GetProcessHeap(),
|
/* Allocate the new argument vector */
|
||||||
HEAP_ZERO_MEMORY,
|
lpVector = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbTotal);
|
||||||
cbTotal);
|
|
||||||
if (lpVector == NULL)
|
if (lpVector == NULL)
|
||||||
return ERROR_OUTOFMEMORY;
|
return ERROR_NOT_ENOUGH_MEMORY;
|
||||||
|
|
||||||
lpArg = lpVector;
|
/*
|
||||||
*lpArg = (LPWSTR)(lpArg + 1);
|
* The first argument is reserved for the service name, which
|
||||||
lpArg++;
|
* will be appended to the end of the argument string list.
|
||||||
|
*/
|
||||||
memcpy(lpArg, pszServiceName, cbServiceName);
|
|
||||||
lpArg = (LPWSTR*)((ULONG_PTR)lpArg + cbServiceName);
|
|
||||||
|
|
||||||
|
/* Copy the remaining arguments */
|
||||||
if (ControlPacket->dwArgumentsCount > 0)
|
if (ControlPacket->dwArgumentsCount > 0)
|
||||||
{
|
{
|
||||||
memcpy(lpArg,
|
memcpy(&lpVector[1],
|
||||||
((PBYTE)ControlPacket + ControlPacket->dwArgumentsOffset),
|
(PWSTR)((ULONG_PTR)ControlPacket + ControlPacket->dwArgumentsOffset),
|
||||||
ControlPacket->dwSize - ControlPacket->dwArgumentsOffset);
|
cbArguments);
|
||||||
|
|
||||||
for (i = 0; i < ControlPacket->dwArgumentsCount; i++)
|
for (i = 0; i < ControlPacket->dwArgumentsCount; i++)
|
||||||
{
|
{
|
||||||
*lpArg = (LPWSTR)((ULONG_PTR)lpArg + (ULONG_PTR)*lpArg);
|
lpVector[i + 1] = (PWSTR)((ULONG_PTR)&lpVector[1] + (ULONG_PTR)lpVector[i + 1]);
|
||||||
lpArg++;
|
TRACE("Unicode lpVector[%lu] = '%ls'\n", i + 1, lpVector[i + 1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*lpArgCount = ControlPacket->dwArgumentsCount + 1;
|
/* Now copy the service name */
|
||||||
|
lpVector[0] = (PWSTR)((ULONG_PTR)&lpVector[1] + cbArguments);
|
||||||
|
memcpy(lpVector[0], pszServiceName, cbServiceName);
|
||||||
|
TRACE("Unicode lpVector[%lu] = '%ls'\n", 0, lpVector[0]);
|
||||||
|
|
||||||
|
*lpArgCount = ControlPacket->dwArgumentsCount + 1;
|
||||||
*lpArgVector = lpVector;
|
*lpArgVector = lpVector;
|
||||||
|
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
|
@ -341,101 +371,48 @@ ScBuildAnsiArgsVector(PSCM_CONTROL_PACKET ControlPacket,
|
||||||
LPDWORD lpArgCount,
|
LPDWORD lpArgCount,
|
||||||
LPSTR **lpArgVector)
|
LPSTR **lpArgVector)
|
||||||
{
|
{
|
||||||
LPSTR *lpVector;
|
DWORD dwError;
|
||||||
LPSTR *lpPtr;
|
NTSTATUS Status;
|
||||||
LPWSTR lpUnicodeString;
|
DWORD ArgCount, i;
|
||||||
LPWSTR pszServiceName;
|
PWSTR *lpVectorW;
|
||||||
LPSTR lpAnsiString;
|
PSTR *lpVectorA;
|
||||||
DWORD cbServiceName;
|
UNICODE_STRING UnicodeString;
|
||||||
DWORD dwVectorSize;
|
ANSI_STRING AnsiString;
|
||||||
DWORD dwUnicodeSize;
|
|
||||||
DWORD dwAnsiSize = 0;
|
|
||||||
DWORD dwAnsiNameSize = 0;
|
|
||||||
DWORD i;
|
|
||||||
|
|
||||||
if (ControlPacket == NULL || lpArgCount == NULL || lpArgVector == NULL)
|
if (ControlPacket == NULL || lpArgCount == NULL || lpArgVector == NULL)
|
||||||
return ERROR_INVALID_PARAMETER;
|
return ERROR_INVALID_PARAMETER;
|
||||||
|
|
||||||
*lpArgCount = 0;
|
*lpArgCount = 0;
|
||||||
*lpArgVector = NULL;
|
*lpArgVector = NULL;
|
||||||
|
|
||||||
pszServiceName = (PWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset);
|
/* Build the UNICODE arguments vector */
|
||||||
cbServiceName = lstrlenW(pszServiceName) * sizeof(WCHAR) + sizeof(UNICODE_NULL);
|
dwError = ScBuildUnicodeArgsVector(ControlPacket, &ArgCount, &lpVectorW);
|
||||||
|
if (dwError != ERROR_SUCCESS)
|
||||||
|
return dwError;
|
||||||
|
|
||||||
dwAnsiNameSize = WideCharToMultiByte(CP_ACP,
|
/* Convert the vector to ANSI in place */
|
||||||
0,
|
lpVectorA = (PSTR*)lpVectorW;
|
||||||
pszServiceName,
|
for (i = 0; i < ArgCount; i++)
|
||||||
cbServiceName,
|
|
||||||
NULL,
|
|
||||||
0,
|
|
||||||
NULL,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
dwVectorSize = ControlPacket->dwArgumentsCount * sizeof(LPWSTR);
|
|
||||||
if (ControlPacket->dwArgumentsCount > 0)
|
|
||||||
{
|
{
|
||||||
lpUnicodeString = (LPWSTR)((PBYTE)ControlPacket +
|
RtlInitUnicodeString(&UnicodeString, lpVectorW[i]);
|
||||||
ControlPacket->dwArgumentsOffset +
|
RtlInitEmptyAnsiString(&AnsiString, lpVectorA[i], UnicodeString.MaximumLength);
|
||||||
dwVectorSize);
|
Status = RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString, FALSE);
|
||||||
dwUnicodeSize = (ControlPacket->dwSize -
|
if (!NT_SUCCESS(Status))
|
||||||
ControlPacket->dwArgumentsOffset -
|
{
|
||||||
dwVectorSize) / sizeof(WCHAR);
|
/* Failed to convert to ANSI; free the allocated vector and return */
|
||||||
|
dwError = RtlNtStatusToDosError(Status);
|
||||||
|
HeapFree(GetProcessHeap(), 0, lpVectorW);
|
||||||
|
return dwError;
|
||||||
|
}
|
||||||
|
|
||||||
dwAnsiSize = WideCharToMultiByte(CP_ACP,
|
/* NULL-terminate the string */
|
||||||
0,
|
AnsiString.Buffer[AnsiString.Length / sizeof(CHAR)] = ANSI_NULL;
|
||||||
lpUnicodeString,
|
|
||||||
dwUnicodeSize,
|
TRACE("Ansi lpVector[%lu] = '%s'\n", i, lpVectorA[i]);
|
||||||
NULL,
|
|
||||||
0,
|
|
||||||
NULL,
|
|
||||||
NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dwVectorSize += sizeof(LPWSTR);
|
*lpArgCount = ArgCount;
|
||||||
|
*lpArgVector = lpVectorA;
|
||||||
lpVector = HeapAlloc(GetProcessHeap(),
|
|
||||||
HEAP_ZERO_MEMORY,
|
|
||||||
dwVectorSize + dwAnsiNameSize + dwAnsiSize);
|
|
||||||
if (lpVector == NULL)
|
|
||||||
return ERROR_OUTOFMEMORY;
|
|
||||||
|
|
||||||
lpPtr = (LPSTR*)lpVector;
|
|
||||||
lpAnsiString = (LPSTR)((ULONG_PTR)lpVector + dwVectorSize);
|
|
||||||
|
|
||||||
WideCharToMultiByte(CP_ACP,
|
|
||||||
0,
|
|
||||||
pszServiceName,
|
|
||||||
cbServiceName,
|
|
||||||
lpAnsiString,
|
|
||||||
dwAnsiNameSize,
|
|
||||||
NULL,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
if (ControlPacket->dwArgumentsCount > 0)
|
|
||||||
{
|
|
||||||
lpAnsiString = (LPSTR)((ULONG_PTR)lpAnsiString + dwAnsiNameSize);
|
|
||||||
|
|
||||||
WideCharToMultiByte(CP_ACP,
|
|
||||||
0,
|
|
||||||
lpUnicodeString,
|
|
||||||
dwUnicodeSize,
|
|
||||||
lpAnsiString,
|
|
||||||
dwAnsiSize,
|
|
||||||
NULL,
|
|
||||||
NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
lpAnsiString = (LPSTR)((ULONG_PTR)lpVector + dwVectorSize);
|
|
||||||
for (i = 0; i < ControlPacket->dwArgumentsCount + 1; i++)
|
|
||||||
{
|
|
||||||
*lpPtr = lpAnsiString;
|
|
||||||
|
|
||||||
lpPtr++;
|
|
||||||
lpAnsiString += (strlen(lpAnsiString) + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
*lpArgCount = ControlPacket->dwArgumentsCount + 1;
|
|
||||||
*lpArgVector = lpVector;
|
|
||||||
|
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,9 +29,9 @@ typedef struct _SCM_CONTROL_PACKET
|
||||||
{
|
{
|
||||||
DWORD dwSize;
|
DWORD dwSize;
|
||||||
DWORD dwControl;
|
DWORD dwControl;
|
||||||
|
DWORD dwArgumentsCount;
|
||||||
SERVICE_STATUS_HANDLE hServiceStatus;
|
SERVICE_STATUS_HANDLE hServiceStatus;
|
||||||
DWORD dwServiceNameOffset;
|
DWORD dwServiceNameOffset;
|
||||||
DWORD dwArgumentsCount;
|
|
||||||
DWORD dwArgumentsOffset;
|
DWORD dwArgumentsOffset;
|
||||||
} SCM_CONTROL_PACKET, *PSCM_CONTROL_PACKET;
|
} SCM_CONTROL_PACKET, *PSCM_CONTROL_PACKET;
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ list(APPEND SOURCE
|
||||||
RegQueryValueExW.c
|
RegQueryValueExW.c
|
||||||
RtlEncryptMemory.c
|
RtlEncryptMemory.c
|
||||||
SaferIdentifyLevel.c
|
SaferIdentifyLevel.c
|
||||||
|
ServiceArgs.c
|
||||||
testlist.c)
|
testlist.c)
|
||||||
|
|
||||||
add_executable(advapi32_apitest ${SOURCE})
|
add_executable(advapi32_apitest ${SOURCE})
|
||||||
|
|
475
rostests/apitests/advapi32/ServiceArgs.c
Normal file
475
rostests/apitests/advapi32/ServiceArgs.c
Normal file
|
@ -0,0 +1,475 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS api tests
|
||||||
|
* LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory
|
||||||
|
* PURPOSE: Test for service arguments
|
||||||
|
* PROGRAMMER: Jacek Caban for CodeWeavers
|
||||||
|
* Thomas Faber <thomas.faber@reactos.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <apitest.h>
|
||||||
|
#include <winnls.h>
|
||||||
|
#include <winsvc.h>
|
||||||
|
#include <strsafe.h>
|
||||||
|
|
||||||
|
static char **argv;
|
||||||
|
static int argc;
|
||||||
|
|
||||||
|
static HANDLE pipe_handle = INVALID_HANDLE_VALUE;
|
||||||
|
static char service_nameA[100];
|
||||||
|
static WCHAR service_nameW[100];
|
||||||
|
static WCHAR named_pipe_name[100];
|
||||||
|
|
||||||
|
/* Test process global variables */
|
||||||
|
static SC_HANDLE scm_handle;
|
||||||
|
static SERVICE_STATUS_HANDLE service_handle;
|
||||||
|
|
||||||
|
static void send_msg(const char *type, const char *msg)
|
||||||
|
{
|
||||||
|
DWORD written = 0;
|
||||||
|
char buf[512];
|
||||||
|
|
||||||
|
StringCbPrintfA(buf, sizeof(buf), "%s:%s", type, msg);
|
||||||
|
WriteFile(pipe_handle, buf, strlen(buf)+1, &written, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void service_trace(const char *msg, ...)
|
||||||
|
{
|
||||||
|
va_list valist;
|
||||||
|
char buf[512];
|
||||||
|
|
||||||
|
va_start(valist, msg);
|
||||||
|
StringCbVPrintfA(buf, sizeof(buf), msg, valist);
|
||||||
|
va_end(valist);
|
||||||
|
|
||||||
|
send_msg("TRACE", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void service_ok(int cnd, const char *msg, ...)
|
||||||
|
{
|
||||||
|
va_list valist;
|
||||||
|
char buf[512];
|
||||||
|
|
||||||
|
va_start(valist, msg);
|
||||||
|
StringCbVPrintfA(buf, sizeof(buf), msg, valist);
|
||||||
|
va_end(valist);
|
||||||
|
|
||||||
|
send_msg(cnd ? "OK" : "FAIL", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static VOID WINAPI service_handler(DWORD ctrl)
|
||||||
|
{
|
||||||
|
SERVICE_STATUS status;
|
||||||
|
|
||||||
|
status.dwServiceType = SERVICE_WIN32;
|
||||||
|
status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
|
||||||
|
status.dwWin32ExitCode = 0;
|
||||||
|
status.dwServiceSpecificExitCode = 0;
|
||||||
|
status.dwCheckPoint = 0;
|
||||||
|
status.dwWaitHint = 0;
|
||||||
|
|
||||||
|
switch(ctrl)
|
||||||
|
{
|
||||||
|
case SERVICE_CONTROL_STOP:
|
||||||
|
status.dwCurrentState = SERVICE_STOP_PENDING;
|
||||||
|
status.dwControlsAccepted = 0;
|
||||||
|
SetServiceStatus(service_handle, &status);
|
||||||
|
default:
|
||||||
|
status.dwCurrentState = SERVICE_RUNNING;
|
||||||
|
SetServiceStatus(service_handle, &status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void service_main_common(void)
|
||||||
|
{
|
||||||
|
SERVICE_STATUS status;
|
||||||
|
BOOL res;
|
||||||
|
|
||||||
|
service_handle = RegisterServiceCtrlHandlerW(service_nameW, service_handler);
|
||||||
|
service_ok(service_handle != NULL, "RegisterServiceCtrlHandler failed: %lu\n", GetLastError());
|
||||||
|
if (!service_handle)
|
||||||
|
return;
|
||||||
|
|
||||||
|
status.dwServiceType = SERVICE_WIN32;
|
||||||
|
status.dwCurrentState = SERVICE_RUNNING;
|
||||||
|
status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
|
||||||
|
status.dwWin32ExitCode = 0;
|
||||||
|
status.dwServiceSpecificExitCode = 0;
|
||||||
|
status.dwCheckPoint = 0;
|
||||||
|
status.dwWaitHint = 10000;
|
||||||
|
res = SetServiceStatus(service_handle, &status);
|
||||||
|
service_ok(res, "SetServiceStatus(SERVICE_RUNNING) failed: %lu", GetLastError());
|
||||||
|
|
||||||
|
Sleep(100);
|
||||||
|
|
||||||
|
status.dwCurrentState = SERVICE_STOPPED;
|
||||||
|
status.dwControlsAccepted = 0;
|
||||||
|
res = SetServiceStatus(service_handle, &status);
|
||||||
|
service_ok(res, "SetServiceStatus(SERVICE_STOPPED) failed: %lu", GetLastError());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A/W argument layout XP/2003:
|
||||||
|
* [argv array of pointers][parameter 1][parameter 2]...[service name]
|
||||||
|
*
|
||||||
|
* A/W argument layout Vista:
|
||||||
|
* [argv array of pointers][align to 8 bytes][parameter 1][parameter 2]...[service name]
|
||||||
|
*
|
||||||
|
* A/W argument layout Win7/8:
|
||||||
|
* [argv array of pointers][service name]
|
||||||
|
* [parameter 1][align to 4 bytes][parameter 2][align to 4 bytes]...
|
||||||
|
*
|
||||||
|
* Space for parameters and service name is always enough to store
|
||||||
|
* the WCHAR version including null terminator.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void WINAPI service_mainA(DWORD service_argc, char **service_argv)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char *next_arg;
|
||||||
|
char *next_arg_aligned;
|
||||||
|
|
||||||
|
service_ok(service_argc == argc - 3, "service_argc = %d, expected %d", service_argc, argc - 3);
|
||||||
|
if (service_argc == argc - 3)
|
||||||
|
{
|
||||||
|
service_ok(!strcmp(service_argv[0], service_nameA), "service_argv[0] = %s, expected %s", service_argv[0], service_nameA);
|
||||||
|
service_ok(service_argv[0] == (char *)&service_argv[service_argc] ||
|
||||||
|
service_argv[1] == (char *)&service_argv[service_argc] ||
|
||||||
|
service_argv[1] == (char *)(((ULONG_PTR)&service_argv[service_argc] + 7) & ~7), "service_argv[0] = %p, [1] = %p, expected one of them to be %p", service_argv[0], service_argv[1], &service_argv[service_argc]);
|
||||||
|
//service_trace("service_argv[0] = %p", service_argv[0]);
|
||||||
|
next_arg_aligned = next_arg = NULL;
|
||||||
|
for (i = 1; i < service_argc; i++)
|
||||||
|
{
|
||||||
|
//service_trace("service_argv[%d] = %p", i, service_argv[i]);
|
||||||
|
service_ok(!strcmp(service_argv[i], argv[i + 3]), "service_argv[%d] = %s, expected %s", i, service_argv[i], argv[i + 3]);
|
||||||
|
service_ok(next_arg == NULL ||
|
||||||
|
service_argv[i] == next_arg ||
|
||||||
|
service_argv[i] == next_arg_aligned, "service_argv[%d] = %p, expected %p or %p", i, service_argv[i], next_arg, next_arg_aligned);
|
||||||
|
next_arg = service_argv[i];
|
||||||
|
next_arg += 2 * (strlen(next_arg) + 1);
|
||||||
|
next_arg_aligned = (char *)(((ULONG_PTR)next_arg + 3) & ~3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
service_main_common();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void WINAPI service_mainW(DWORD service_argc, WCHAR **service_argv)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
WCHAR argW[32];
|
||||||
|
WCHAR *next_arg;
|
||||||
|
WCHAR *next_arg_aligned;
|
||||||
|
|
||||||
|
service_ok(service_argc == argc - 3, "service_argc = %d, expected %d", service_argc, argc - 3);
|
||||||
|
if (service_argc == argc - 3)
|
||||||
|
{
|
||||||
|
service_ok(!wcscmp(service_argv[0], service_nameW), "service_argv[0] = %ls, expected %ls", service_argv[0], service_nameW);
|
||||||
|
service_ok(service_argv[0] == (WCHAR *)&service_argv[service_argc] ||
|
||||||
|
service_argv[1] == (WCHAR *)&service_argv[service_argc] ||
|
||||||
|
service_argv[1] == (WCHAR *)(((ULONG_PTR)&service_argv[service_argc] + 7) & ~7), "service_argv[0] = %p, [1] = %p, expected one of them to be %p", service_argv[0], service_argv[1], &service_argv[service_argc]);
|
||||||
|
//service_trace("service_argv[0] = %p", service_argv[0]);
|
||||||
|
next_arg_aligned = next_arg = NULL;
|
||||||
|
for (i = 1; i < service_argc; i++)
|
||||||
|
{
|
||||||
|
//service_trace("service_argv[%d] = %p", i, service_argv[i]);
|
||||||
|
MultiByteToWideChar(CP_ACP, 0, argv[i + 3], -1, argW, _countof(argW));
|
||||||
|
service_ok(!wcscmp(service_argv[i], argW), "service_argv[%d] = %ls, expected %ls", i, service_argv[i], argW);
|
||||||
|
service_ok(next_arg == NULL ||
|
||||||
|
service_argv[i] == next_arg ||
|
||||||
|
service_argv[i] == next_arg_aligned, "service_argv[%d] = %p, expected %p or %p", i, service_argv[i], next_arg, next_arg_aligned);
|
||||||
|
next_arg = service_argv[i];
|
||||||
|
next_arg += wcslen(next_arg) + 1;
|
||||||
|
next_arg_aligned = (WCHAR *)(((ULONG_PTR)next_arg + 3) & ~3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
service_main_common();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void service_process(BOOLEAN unicode)
|
||||||
|
{
|
||||||
|
BOOL res;
|
||||||
|
|
||||||
|
SERVICE_TABLE_ENTRYA servtblA[] =
|
||||||
|
{
|
||||||
|
{ service_nameA, service_mainA },
|
||||||
|
{ NULL, NULL }
|
||||||
|
};
|
||||||
|
SERVICE_TABLE_ENTRYW servtblW[] =
|
||||||
|
{
|
||||||
|
{ service_nameW, service_mainW },
|
||||||
|
{ NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
res = WaitNamedPipeW(named_pipe_name, NMPWAIT_USE_DEFAULT_WAIT);
|
||||||
|
if (!res)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pipe_handle = CreateFileW(named_pipe_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
|
if (pipe_handle == INVALID_HANDLE_VALUE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
//service_trace("Starting...");
|
||||||
|
if (unicode)
|
||||||
|
{
|
||||||
|
res = StartServiceCtrlDispatcherW(servtblW);
|
||||||
|
service_ok(res, "StartServiceCtrlDispatcherW failed: %lu\n", GetLastError());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
res = StartServiceCtrlDispatcherA(servtblA);
|
||||||
|
service_ok(res, "StartServiceCtrlDispatcherA failed: %lu\n", GetLastError());
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseHandle(pipe_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
static SC_HANDLE register_service(PCWSTR extra_args)
|
||||||
|
{
|
||||||
|
WCHAR service_cmd[MAX_PATH+150];
|
||||||
|
SC_HANDLE service;
|
||||||
|
|
||||||
|
GetModuleFileNameW(NULL, service_cmd, MAX_PATH);
|
||||||
|
|
||||||
|
StringCbCatW(service_cmd, sizeof(service_cmd), L" ServiceArgs ");
|
||||||
|
StringCbCatW(service_cmd, sizeof(service_cmd), service_nameW);
|
||||||
|
StringCbCatW(service_cmd, sizeof(service_cmd), extra_args);
|
||||||
|
|
||||||
|
trace("service_cmd \"%ls\"\n", service_cmd);
|
||||||
|
|
||||||
|
service = CreateServiceW(scm_handle, service_nameW, service_nameW, GENERIC_ALL,
|
||||||
|
SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_IGNORE,
|
||||||
|
service_cmd, NULL, NULL, NULL, NULL, NULL);
|
||||||
|
if (!service && GetLastError() == ERROR_ACCESS_DENIED)
|
||||||
|
{
|
||||||
|
skip("Not enough access right to create service\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ok(service != NULL, "CreateService failed: %lu\n", GetLastError());
|
||||||
|
return service;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DWORD WINAPI pipe_thread(void *arg)
|
||||||
|
{
|
||||||
|
char buf[512];
|
||||||
|
DWORD read;
|
||||||
|
BOOL res;
|
||||||
|
|
||||||
|
res = ConnectNamedPipe(pipe_handle, NULL);
|
||||||
|
ok(res || GetLastError() == ERROR_PIPE_CONNECTED, "ConnectNamedPipe failed: %lu\n", GetLastError());
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
res = ReadFile(pipe_handle, buf, sizeof(buf), &read, NULL);
|
||||||
|
if (!res)
|
||||||
|
{
|
||||||
|
ok(GetLastError() == ERROR_BROKEN_PIPE || GetLastError() == ERROR_INVALID_HANDLE,
|
||||||
|
"ReadFile failed: %lu\n", GetLastError());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strncmp(buf, "TRACE:", 6))
|
||||||
|
{
|
||||||
|
trace("service trace: %s\n", buf+6);
|
||||||
|
}
|
||||||
|
else if (!strncmp(buf, "OK:", 3))
|
||||||
|
{
|
||||||
|
ok(1, "service: %s\n", buf+3);
|
||||||
|
}
|
||||||
|
else if (!strncmp(buf, "FAIL:", 5))
|
||||||
|
{
|
||||||
|
ok(0, "service: %s\n", buf+5);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ok(0, "malformed service message: %s\n", buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DisconnectNamedPipe(pipe_handle);
|
||||||
|
//trace("pipe disconnected\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_startA(SC_HANDLE service_handle, int service_argc, const char **service_argv)
|
||||||
|
{
|
||||||
|
SERVICE_STATUS status;
|
||||||
|
BOOL res;
|
||||||
|
|
||||||
|
res = StartServiceA(service_handle, service_argc, service_argv);
|
||||||
|
ok(res, "StartService failed: %lu\n", GetLastError());
|
||||||
|
if (!res)
|
||||||
|
return;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
Sleep(100);
|
||||||
|
ZeroMemory(&status, sizeof(status));
|
||||||
|
res = QueryServiceStatus(service_handle, &status);
|
||||||
|
} while (res && status.dwCurrentState != SERVICE_STOPPED);
|
||||||
|
ok(res, "QueryServiceStatus failed: %lu\n", GetLastError());
|
||||||
|
ok(status.dwCurrentState == SERVICE_STOPPED, "status.dwCurrentState = %lx\n", status.dwCurrentState);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_startW(SC_HANDLE service_handle, int service_argc, const WCHAR **service_argv)
|
||||||
|
{
|
||||||
|
SERVICE_STATUS status;
|
||||||
|
BOOL res;
|
||||||
|
|
||||||
|
res = StartServiceW(service_handle, service_argc, service_argv);
|
||||||
|
ok(res, "StartService failed: %lu\n", GetLastError());
|
||||||
|
if (!res)
|
||||||
|
return;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
Sleep(100);
|
||||||
|
ZeroMemory(&status, sizeof(status));
|
||||||
|
res = QueryServiceStatus(service_handle, &status);
|
||||||
|
} while (res && status.dwCurrentState != SERVICE_STOPPED);
|
||||||
|
ok(res, "QueryServiceStatus failed: %lu\n", GetLastError());
|
||||||
|
ok(status.dwCurrentState == SERVICE_STOPPED, "status.dwCurrentState = %lx\n", status.dwCurrentState);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_runner(BOOLEAN unicode, PCWSTR extra_args, int service_argc, void *service_argv)
|
||||||
|
{
|
||||||
|
HANDLE thread;
|
||||||
|
SC_HANDLE service_handle;
|
||||||
|
BOOL res;
|
||||||
|
|
||||||
|
StringCbPrintfW(service_nameW, sizeof(service_nameW), L"WineTestService%lu", GetTickCount());
|
||||||
|
WideCharToMultiByte(CP_ACP, 0, service_nameW, -1, service_nameA, _countof(service_nameA), NULL, NULL);
|
||||||
|
//trace("service_name: %ls\n", service_nameW);
|
||||||
|
StringCbPrintfW(named_pipe_name, sizeof(named_pipe_name), L"\\\\.\\pipe\\%ls_pipe", service_nameW);
|
||||||
|
|
||||||
|
pipe_handle = CreateNamedPipeW(named_pipe_name, PIPE_ACCESS_INBOUND,
|
||||||
|
PIPE_TYPE_MESSAGE|PIPE_READMODE_MESSAGE|PIPE_WAIT, 10, 2048, 2048, 10000, NULL);
|
||||||
|
ok(pipe_handle != INVALID_HANDLE_VALUE, "CreateNamedPipe failed: %lu\n", GetLastError());
|
||||||
|
if (pipe_handle == INVALID_HANDLE_VALUE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
thread = CreateThread(NULL, 0, pipe_thread, NULL, 0, NULL);
|
||||||
|
ok(thread != NULL, "CreateThread failed: %lu\n", GetLastError());
|
||||||
|
if (!thread)
|
||||||
|
return;
|
||||||
|
|
||||||
|
service_handle = register_service(extra_args);
|
||||||
|
if (!service_handle)
|
||||||
|
return;
|
||||||
|
|
||||||
|
//trace("starting...\n");
|
||||||
|
|
||||||
|
if (unicode)
|
||||||
|
test_startW(service_handle, service_argc, service_argv);
|
||||||
|
else
|
||||||
|
test_startA(service_handle, service_argc, service_argv);
|
||||||
|
|
||||||
|
res = DeleteService(service_handle);
|
||||||
|
ok(res, "DeleteService failed: %lu\n", GetLastError());
|
||||||
|
|
||||||
|
CloseServiceHandle(service_handle);
|
||||||
|
|
||||||
|
ok(WaitForSingleObject(thread, 10000) == WAIT_OBJECT_0, "Timeout waiting for thread\n");
|
||||||
|
CloseHandle(thread);
|
||||||
|
CloseHandle(pipe_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
START_TEST(ServiceArgs)
|
||||||
|
{
|
||||||
|
argc = winetest_get_mainargs(&argv);
|
||||||
|
|
||||||
|
scm_handle = OpenSCManagerW(NULL, NULL, GENERIC_ALL);
|
||||||
|
ok(scm_handle != NULL, "OpenSCManager failed: %lu\n", GetLastError());
|
||||||
|
if (!scm_handle)
|
||||||
|
{
|
||||||
|
skip("Failed to open service control manager. Skipping test\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc < 3)
|
||||||
|
{
|
||||||
|
char *service_argvA[10];
|
||||||
|
WCHAR *service_argvW[10];
|
||||||
|
|
||||||
|
test_runner(FALSE, L" A", 0, NULL);
|
||||||
|
test_runner(FALSE, L" W", 0, NULL);
|
||||||
|
test_runner(TRUE, L" A", 0, NULL);
|
||||||
|
test_runner(TRUE, L" W", 0, NULL);
|
||||||
|
|
||||||
|
service_argvA[0] = "x";
|
||||||
|
service_argvW[0] = L"x";
|
||||||
|
test_runner(FALSE, L" A x", 1, service_argvA);
|
||||||
|
test_runner(FALSE, L" W x", 1, service_argvA);
|
||||||
|
test_runner(TRUE, L" A x", 1, service_argvW);
|
||||||
|
test_runner(TRUE, L" W x", 1, service_argvW);
|
||||||
|
|
||||||
|
service_argvA[1] = "y";
|
||||||
|
service_argvW[1] = L"y";
|
||||||
|
test_runner(FALSE, L" A x y", 2, service_argvA);
|
||||||
|
test_runner(FALSE, L" W x y", 2, service_argvA);
|
||||||
|
test_runner(TRUE, L" A x y", 2, service_argvW);
|
||||||
|
test_runner(TRUE, L" W x y", 2, service_argvW);
|
||||||
|
|
||||||
|
service_argvA[0] = "ab";
|
||||||
|
service_argvW[0] = L"ab";
|
||||||
|
test_runner(FALSE, L" A ab y", 2, service_argvA);
|
||||||
|
test_runner(FALSE, L" W ab y", 2, service_argvA);
|
||||||
|
test_runner(TRUE, L" A ab y", 2, service_argvW);
|
||||||
|
test_runner(TRUE, L" W ab y", 2, service_argvW);
|
||||||
|
|
||||||
|
service_argvA[0] = "abc";
|
||||||
|
service_argvW[0] = L"abc";
|
||||||
|
test_runner(FALSE, L" A abc y", 2, service_argvA);
|
||||||
|
test_runner(FALSE, L" W abc y", 2, service_argvA);
|
||||||
|
test_runner(TRUE, L" A abc y", 2, service_argvW);
|
||||||
|
test_runner(TRUE, L" W abc y", 2, service_argvW);
|
||||||
|
|
||||||
|
service_argvA[0] = "abcd";
|
||||||
|
service_argvW[0] = L"abcd";
|
||||||
|
test_runner(FALSE, L" A abcd y", 2, service_argvA);
|
||||||
|
test_runner(FALSE, L" W abcd y", 2, service_argvA);
|
||||||
|
test_runner(TRUE, L" A abcd y", 2, service_argvW);
|
||||||
|
test_runner(TRUE, L" W abcd y", 2, service_argvW);
|
||||||
|
|
||||||
|
service_argvA[0] = "abcde";
|
||||||
|
service_argvW[0] = L"abcde";
|
||||||
|
test_runner(FALSE, L" A abcde y", 2, service_argvA);
|
||||||
|
test_runner(FALSE, L" W abcde y", 2, service_argvA);
|
||||||
|
test_runner(TRUE, L" A abcde y", 2, service_argvW);
|
||||||
|
test_runner(TRUE, L" W abcde y", 2, service_argvW);
|
||||||
|
|
||||||
|
service_argvA[0] = "abcdef";
|
||||||
|
service_argvW[0] = L"abcdef";
|
||||||
|
test_runner(FALSE, L" A abcdef y", 2, service_argvA);
|
||||||
|
test_runner(FALSE, L" W abcdef y", 2, service_argvA);
|
||||||
|
test_runner(TRUE, L" A abcdef y", 2, service_argvW);
|
||||||
|
test_runner(TRUE, L" W abcdef y", 2, service_argvW);
|
||||||
|
|
||||||
|
service_argvA[0] = "abcdefg";
|
||||||
|
service_argvW[0] = L"abcdefg";
|
||||||
|
test_runner(FALSE, L" A abcdefg y", 2, service_argvA);
|
||||||
|
test_runner(FALSE, L" W abcdefg y", 2, service_argvA);
|
||||||
|
test_runner(TRUE, L" A abcdefg y", 2, service_argvW);
|
||||||
|
test_runner(TRUE, L" W abcdefg y", 2, service_argvW);
|
||||||
|
|
||||||
|
service_argvA[0] = "";
|
||||||
|
service_argvW[0] = L"";
|
||||||
|
test_runner(FALSE, L" A \"\" y", 2, service_argvA);
|
||||||
|
test_runner(FALSE, L" W \"\" y", 2, service_argvA);
|
||||||
|
test_runner(TRUE, L" A \"\" y", 2, service_argvW);
|
||||||
|
test_runner(TRUE, L" W \"\" y", 2, service_argvW);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
strcpy(service_nameA, argv[2]);
|
||||||
|
MultiByteToWideChar(CP_ACP, 0, service_nameA, -1, service_nameW, _countof(service_nameW));
|
||||||
|
StringCbPrintfW(named_pipe_name, sizeof(named_pipe_name), L"\\\\.\\pipe\\%ls_pipe", service_nameW);
|
||||||
|
if (!strcmp(argv[3], "A"))
|
||||||
|
service_process(FALSE);
|
||||||
|
else
|
||||||
|
service_process(TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseServiceHandle(scm_handle);
|
||||||
|
}
|
|
@ -16,6 +16,7 @@ extern void func_RegQueryInfoKey(void);
|
||||||
extern void func_RegQueryValueExW(void);
|
extern void func_RegQueryValueExW(void);
|
||||||
extern void func_RtlEncryptMemory(void);
|
extern void func_RtlEncryptMemory(void);
|
||||||
extern void func_SaferIdentifyLevel(void);
|
extern void func_SaferIdentifyLevel(void);
|
||||||
|
extern void func_ServiceArgs(void);
|
||||||
|
|
||||||
const struct test winetest_testlist[] =
|
const struct test winetest_testlist[] =
|
||||||
{
|
{
|
||||||
|
@ -32,7 +33,7 @@ const struct test winetest_testlist[] =
|
||||||
{ "RegQueryValueExW", func_RegQueryValueExW },
|
{ "RegQueryValueExW", func_RegQueryValueExW },
|
||||||
{ "RtlEncryptMemory", func_RtlEncryptMemory },
|
{ "RtlEncryptMemory", func_RtlEncryptMemory },
|
||||||
{ "SaferIdentifyLevel", func_SaferIdentifyLevel },
|
{ "SaferIdentifyLevel", func_SaferIdentifyLevel },
|
||||||
|
{ "ServiceArgs", func_ServiceArgs },
|
||||||
{ 0, 0 }
|
{ 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue