[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