[PATCH] kernel32: implement QueryFullProcessImageFileName
Mikołaj Zalewski
mikolaj at zalewski.pl
Sun Mar 29 16:36:33 CDT 2009
---
dlls/kernel32/kernel32.spec | 2 +
dlls/kernel32/process.c | 53 +++++++++++++++++++++
dlls/kernel32/tests/process.c | 105 +++++++++++++++++++++++++++++++++++++++++
dlls/ntdll/process.c | 2 +
dlls/ntdll/tests/info.c | 1 +
include/winbase.h | 5 ++
6 files changed, 168 insertions(+), 0 deletions(-)
diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec
index c615ef1..23be134 100644
--- a/dlls/kernel32/kernel32.spec
+++ b/dlls/kernel32/kernel32.spec
@@ -865,6 +865,8 @@
@ stdcall QueryDepthSList(ptr) ntdll.RtlQueryDepthSList
@ stdcall QueryDosDeviceA(str ptr long)
@ stdcall QueryDosDeviceW(wstr ptr long)
+@ stub QueryFullProcessImageNameA
+@ stdcall QueryFullProcessImageNameW(ptr long wstr ptr)
@ stdcall QueryInformationJobObject(long long ptr long ptr)
# @ stub QueryMemoryResourceNotification
@ stub QueryNumberOfEventLogRecords
diff --git a/dlls/kernel32/process.c b/dlls/kernel32/process.c
index fea63a8..dc87f5f 100644
--- a/dlls/kernel32/process.c
+++ b/dlls/kernel32/process.c
@@ -3110,6 +3110,59 @@ BOOL WINAPI GetProcessHandleCount(HANDLE hProcess, DWORD *cnt)
return !status;
}
+/******************************************************************
+ * QueryFullProcessImageNameW (KERNEL32.@)
+ */
+BOOL WINAPI QueryFullProcessImageNameW(HANDLE hProcess, DWORD dwFlags, LPWSTR lpExeName, PDWORD pdwSize)
+{
+ BYTE buffer[sizeof(UNICODE_STRING) + MAX_PATH*sizeof(WCHAR)]; /* this buffer should be enough */
+ UNICODE_STRING *dynamic_buffer = NULL;
+ UNICODE_STRING nt_path;
+ UNICODE_STRING *result = NULL;
+ NTSTATUS status;
+ DWORD needed;
+
+ RtlInitUnicodeStringEx(&nt_path, NULL);
+ /* FIXME: On Windows, ProcessImageFileName return an NT path. We rely that it being a DOS path,
+ * as this is on Wine. */
+ status = NtQueryInformationProcess(hProcess, ProcessImageFileName, buffer, sizeof(buffer), &needed);
+ if (status == STATUS_INFO_LENGTH_MISMATCH)
+ {
+ dynamic_buffer = HeapAlloc(GetProcessHeap(), 0, needed);
+ status = NtQueryInformationProcess(hProcess, ProcessImageFileName, (LPBYTE)dynamic_buffer, needed, &needed);
+ result = dynamic_buffer;
+ }
+ else
+ result = (PUNICODE_STRING)buffer;
+
+ if (status) goto cleanup;
+
+ if (dwFlags & PROCESS_NAME_NATIVE)
+ {
+ if (!RtlDosPathNameToNtPathName_U(result->Buffer, &nt_path, NULL, NULL))
+ {
+ status = STATUS_OBJECT_PATH_NOT_FOUND;
+ goto cleanup;
+ }
+ result = &nt_path;
+ }
+
+ if (result->Length/sizeof(WCHAR) + 1 > *pdwSize)
+ {
+ status = STATUS_BUFFER_TOO_SMALL;
+ goto cleanup;
+ }
+
+ lstrcpynW(lpExeName, result->Buffer, result->Length/sizeof(WCHAR) + 1);
+ *pdwSize = result->Length/sizeof(WCHAR);
+
+cleanup:
+ HeapFree(GetProcessHeap(), 0, dynamic_buffer);
+ RtlFreeUnicodeString(&nt_path);
+ if (status) SetLastError( RtlNtStatusToDosError(status) );
+ return !status;
+}
+
/***********************************************************************
* ProcessIdToSessionId (KERNEL32.@)
* This function is available on Terminal Server 4SP4 and Windows 2000
diff --git a/dlls/kernel32/tests/process.c b/dlls/kernel32/tests/process.c
index 21dff3c..5d6e710 100644
--- a/dlls/kernel32/tests/process.c
+++ b/dlls/kernel32/tests/process.c
@@ -35,9 +35,42 @@
#include "wine/test.h"
+#define expect_eq_d(expected, actual) \
+ do { \
+ int value = (actual); \
+ ok((expected) == value, "Expected " #actual " to be %d (" #expected ") is %d\n", \
+ (expected), value); \
+ } while (0)
+#define expect_eq_ws_i(expected, actual) \
+ do { \
+ LPCWSTR value = (actual); \
+ ok(lstrcmpiW((expected), value) == 0, "Expected " #actual " to be L\"%s\" (" #expected ") is L\"%s\"\n", \
+ wine_dbgstr_w(expected), wine_dbgstr_w(value)); \
+ } while (0)
+
+/* A simpler version of wine_dbgstr_w. Note that the returned buffer will be
+ * invalid after 16 calls to this funciton. */
+const char *wine_dbgstr_w(LPCWSTR wstr)
+{
+ static char *buffers[16] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
+ static int curr_buffer = 0;
+
+ int size;
+
+ curr_buffer = (curr_buffer + 1) % 16;
+ if (buffers[curr_buffer])
+ HeapFree(GetProcessHeap(), 0, buffers[curr_buffer]);
+ size = WideCharToMultiByte(CP_ACP, 0, wstr, -1, NULL, 0, NULL, NULL);
+ buffers[curr_buffer] = HeapAlloc(GetProcessHeap(), 0, size);
+ size = WideCharToMultiByte(CP_ACP, 0, wstr, -1, buffers[curr_buffer], size, NULL, NULL);
+ return buffers[curr_buffer];
+}
+
static HINSTANCE hkernel32;
static LPVOID (WINAPI *pVirtualAllocEx)(HANDLE, LPVOID, SIZE_T, DWORD, DWORD);
static BOOL (WINAPI *pVirtualFreeEx)(HANDLE, LPVOID, SIZE_T, DWORD);
+static BOOL (WINAPI *pQueryFullProcessImageNameW)(HANDLE hProcess, DWORD dwFlags, LPWSTR lpExeName, PDWORD lpdwSize);
/* ############################### */
static char base[MAX_PATH];
@@ -175,6 +208,7 @@ static int init(void)
hkernel32 = GetModuleHandleA("kernel32");
pVirtualAllocEx = (void *) GetProcAddress(hkernel32, "VirtualAllocEx");
pVirtualFreeEx = (void *) GetProcAddress(hkernel32, "VirtualFreeEx");
+ pQueryFullProcessImageNameW = (void *) GetProcAddress(hkernel32, "QueryFullProcessImageNameW");
return 1;
}
@@ -1520,6 +1554,76 @@ static void test_GetProcessVersion(void)
CloseHandle(pi.hThread);
}
+static void test_ProcessName(void)
+{
+ HANDLE hSelf;
+ WCHAR module_name[1024];
+ WCHAR deviceW[] = {'\\','D', 'e','v','i','c','e',0};
+ WCHAR buf[1024];
+ DWORD size;
+
+ if (!pQueryFullProcessImageNameW)
+ {
+ win_skip("QueryFullProcessImageNameW unavailable (added in Windows Vista)\n");
+ return;
+ }
+
+ ok(GetModuleFileNameW(NULL, module_name, 1024), "GetModuleFileNameW(NULL, ...) failed\n");
+
+ /* GetCurrentProcess pseudo-handle */
+ size = sizeof(buf) / sizeof(buf[0]);
+ expect_eq_d(TRUE, pQueryFullProcessImageNameW(GetCurrentProcess(), 0, buf, &size));
+ expect_eq_d(lstrlenW(buf), size);
+ expect_eq_ws_i(buf, module_name);
+
+ hSelf = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, GetCurrentProcessId());
+ /* Real handle */
+ size = sizeof(buf) / sizeof(buf[0]);
+ expect_eq_d(TRUE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
+ expect_eq_d(lstrlenW(buf), size);
+ expect_eq_ws_i(buf, module_name);
+
+ /* Buffer too small */
+ size = lstrlenW(module_name)/2;
+ lstrcpyW(buf, deviceW);
+ SetLastError(0xdeadbeef);
+ expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
+ expect_eq_d(lstrlenW(module_name)/2, size); /* size not changed(!) */
+ expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
+ expect_eq_ws_i(deviceW, buf); /* buffer not changed */
+
+ /* Too small - not space for NUL terminator */
+ size = lstrlenW(module_name);
+ SetLastError(0xdeadbeef);
+ expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
+ expect_eq_d(lstrlenW(module_name), size); /* size not changed(!) */
+ expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
+
+ /* NULL buffer */
+ size = 0;
+ expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, NULL, &size));
+ expect_eq_d(0, size);
+ expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
+
+ /* native path */
+ size = sizeof(buf) / sizeof(buf[0]);
+ expect_eq_d(TRUE, pQueryFullProcessImageNameW(hSelf, PROCESS_NAME_NATIVE, buf, &size));
+ expect_eq_d(lstrlenW(buf), size);
+ ok(buf[0] == '\\', "NT path should begin with '\\'\n");
+ todo_wine ok(memcmp(buf, deviceW, sizeof(WCHAR)*lstrlenW(deviceW)) == 0, "NT path should begin with \\Device\n");
+
+ /* Buffer too small */
+ size = lstrlenW(module_name)/2;
+ SetLastError(0xdeadbeef);
+ lstrcpyW(buf, module_name);
+ expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
+ expect_eq_d(lstrlenW(module_name)/2, size); /* size not changed(!) */
+ expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
+ expect_eq_ws_i(module_name, buf); /* buffer not changed */
+
+ CloseHandle(hSelf);
+}
+
static void test_Handles(void)
{
HANDLE handle = GetCurrentProcess();
@@ -1573,6 +1677,7 @@ START_TEST(process)
test_ExitCode();
test_OpenProcess();
test_GetProcessVersion();
+ test_ProcessName();
test_Handles();
/* things that can be tested:
* lookup: check the way program to be executed is searched
diff --git a/dlls/ntdll/process.c b/dlls/ntdll/process.c
index 82bc6a7..76c8410 100644
--- a/dlls/ntdll/process.c
+++ b/dlls/ntdll/process.c
@@ -313,6 +313,8 @@ NTSTATUS WINAPI NtQueryInformationProcess(
else ret = STATUS_INFO_LENGTH_MISMATCH;
break;
case ProcessImageFileName:
+ /* FIXME: this will return a DOS path. Windows returns an NT path. Changing this would require also changing kernel32.QueryFullProcessImageName.
+ * The latter may be harder because of the lack of RtlNtPathNameToDosPathName. */
SERVER_START_REQ(get_dll_info)
{
UNICODE_STRING *image_file_name_str = ProcessInformation;
diff --git a/dlls/ntdll/tests/info.c b/dlls/ntdll/tests/info.c
index b118bd3..22284a4 100644
--- a/dlls/ntdll/tests/info.c
+++ b/dlls/ntdll/tests/info.c
@@ -818,6 +818,7 @@ static void test_query_process_image_file_name(void)
file_nameA[len] = '\0';
HeapFree(GetProcessHeap(), 0, buffer);
trace("process image file name: %s\n", file_nameA);
+ todo_wine ok(strncmp(file_nameA, "\\Device\\", 8) == 0, "Process image name should be an NT path beginning with \\Device\\ (is %s)", file_nameA);
HeapFree(GetProcessHeap(), 0, file_nameA);
}
diff --git a/include/winbase.h b/include/winbase.h
index 3f0a24e..85f39e4 100644
--- a/include/winbase.h
+++ b/include/winbase.h
@@ -1181,6 +1181,8 @@ typedef struct tagCOMMTIMEOUTS {
#define SET_TAPE_MEDIA_INFORMATION 0
#define SET_TAPE_DRIVE_INFORMATION 1
+#define PROCESS_NAME_NATIVE 1
+
typedef void (CALLBACK *PAPCFUNC)(ULONG_PTR);
typedef void (CALLBACK *PTIMERAPCROUTINE)(LPVOID,DWORD,DWORD);
@@ -1957,6 +1959,9 @@ WINBASEAPI USHORT WINAPI QueryDepthSList(PSLIST_HEADER);
WINBASEAPI DWORD WINAPI QueryDosDeviceA(LPCSTR,LPSTR,DWORD);
WINBASEAPI DWORD WINAPI QueryDosDeviceW(LPCWSTR,LPWSTR,DWORD);
#define QueryDosDevice WINELIB_NAME_AW(QueryDosDevice)
+WINBASEAPI BOOL WINAPI QueryFullProcessImageNameA(HANDLE,DWORD,LPSTR,PDWORD);
+WINBASEAPI BOOL WINAPI QueryFullProcessImageNameW(HANDLE,DWORD,LPWSTR,PDWORD);
+#define QueryFullProcessImageName WINELIB_NAME_AW(QueryFullProcessImageName)
WINBASEAPI BOOL WINAPI QueryInformationJobObject(HANDLE,JOBOBJECTINFOCLASS,LPVOID,DWORD,DWORD*);
WINBASEAPI BOOL WINAPI QueryPerformanceCounter(LARGE_INTEGER*);
WINBASEAPI BOOL WINAPI QueryPerformanceFrequency(LARGE_INTEGER*);
--
1.5.4
--------------090205080503030604000803--
More information about the wine-patches
mailing list