[GFLAGS] Move code around to handle multiple options
authorMark Jansen <mark.jansen@reactos.org>
Fri, 12 Oct 2018 23:14:15 +0000 (01:14 +0200)
committerMark Jansen <mark.jansen@reactos.org>
Fri, 19 Oct 2018 21:13:38 +0000 (23:13 +0200)
modules/rosapps/applications/cmdutils/gflags/CMakeLists.txt
modules/rosapps/applications/cmdutils/gflags/gflags.c
modules/rosapps/applications/cmdutils/gflags/gflags.h [new file with mode: 0644]
modules/rosapps/applications/cmdutils/gflags/pageheap.c [new file with mode: 0644]

index a6936de..fd935e7 100644 (file)
@@ -1,7 +1,14 @@
 
-add_executable(gflags gflags.c gflags.rc)
+
+list(APPEND SOURCE
+    gflags.c
+    pageheap.c
+    gflags.h)
+
+add_executable(gflags ${SOURCE} gflags.rc)
 set_module_type(gflags win32cui UNICODE)
 add_importlibs(gflags advapi32 user32 msvcrt kernel32)
+add_pch(gflags gflags.h SOURCE)
 
 if(MSVC)
     add_importlibs(gflags ntdll)
index 260c6d5..b0751a0 100644 (file)
@@ -1,27 +1,17 @@
 /*
- * COPYRIGHT:   See COPYING in the top level directory
- * PROJECT:     ReactOS ping utility
- * FILE:        applications/cmdutils/gflags/gflags.c
- * PURPOSE:     Global Flags utility
- * PROGRAMMERS: Pierre Schweitzer <pierre@reactos.org>
+ * PROJECT:     Global Flags utility
+ * LICENSE:     GPL-2.0 (https://spdx.org/licenses/GPL-2.0)
+ * PURPOSE:     Global Flags utility entrypoint
+ * COPYRIGHT:   Copyright 2017 Pierre Schweitzer (pierre@reactos.org)
+ *              Copyright 2018 Mark Jansen (mark.jansen@reactos.org)
  */
 
-#define WIN32_NO_STATUS
-#include <stdarg.h>
-#include <windef.h>
-#include <winbase.h>
-#include <winuser.h>
-#include <winreg.h>
-#include <stdio.h>
-#include <stdlib.h>
+#include "gflags.h"
 
-static BOOL Set = FALSE;
-static BOOL Unset = FALSE;
-static BOOL Full = FALSE;
-static PWSTR Image = NULL;
-static WCHAR ImageExecOptionsString[] = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options";
+static BOOL UsePageHeap = FALSE;
 
-static DWORD ReagFlagsFromRegistry(HKEY SubKey, PVOID Buffer, PWSTR Value, DWORD MaxLen)
+
+DWORD ReagFlagsFromRegistry(HKEY SubKey, PVOID Buffer, PWSTR Value, DWORD MaxLen)
 {
     DWORD Len, Flags, Type;
 
@@ -35,299 +25,13 @@ static DWORD ReagFlagsFromRegistry(HKEY SubKey, PVOID Buffer, PWSTR Value, DWORD
     return Flags;
 }
 
-static VOID ModifyStatus(VOID)
-{
-    LONG Ret;
-    DWORD MaxLen, GlobalFlags;
-    PVOID Buffer;
-    HKEY HandleKey, HandleSubKey;
-
-    Ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, ImageExecOptionsString, 0, KEY_WRITE | KEY_READ, &HandleKey);
-    if (Ret != ERROR_SUCCESS)
-    {
-        wprintf(L"MS: RegOpenKeyEx failed (%d)\n", Ret);
-        return;
-    }
-
-    Ret = RegCreateKeyEx(HandleKey, Image, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE | KEY_READ, NULL, &HandleSubKey, NULL);
-    if (Ret != ERROR_SUCCESS)
-    {
-        wprintf(L"MS: RegCreateKeyEx failed (%d)\n", Ret);
-        return;
-    }
-
-    Ret = RegQueryInfoKey(HandleSubKey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &MaxLen, NULL, NULL);
-    if (Ret != ERROR_SUCCESS)
-    {
-        wprintf(L"MS: RegQueryInfoKey failed (%d)\n", Ret);
-        RegCloseKey(HandleSubKey);
-        RegCloseKey(HandleKey);
-        return;
-    }
-
-    MaxLen = max(MaxLen, 11 * sizeof(WCHAR));
-    Buffer = HeapAlloc(GetProcessHeap(), 0, MaxLen);
-    if (Buffer == NULL)
-    {
-        wprintf(L"MS: HeapAlloc failed\n");
-        RegCloseKey(HandleSubKey);
-        RegCloseKey(HandleKey);
-        return;
-    }
-
-    GlobalFlags = ReagFlagsFromRegistry(HandleSubKey, Buffer, L"GlobalFlag", MaxLen);
-    if (Set)
-    {
-        GlobalFlags |= 0x02000000;
-    }
-    else
-    {
-        GlobalFlags &= ~0x02000000;
-    }
-
-    if (GlobalFlags != 0)
-    {
-        wsprintf(Buffer, L"0x%08x", GlobalFlags);
-        Ret = RegSetValueEx(HandleSubKey, L"GlobalFlag", 0, REG_SZ, Buffer, 11 * sizeof(WCHAR));
-        if (Ret != ERROR_SUCCESS)
-        {
-            wprintf(L"MS: RegSetValueEx failed (%d)\n", Ret);
-        }
-    }
-    else
-    {
-        Ret = RegDeleteValue(HandleSubKey, L"GlobalFlag");
-        if (Ret != ERROR_SUCCESS)
-        {
-            wprintf(L"MS: RegDeleteValue failed (%d)\n", Ret);
-        }
-    }
-
-    if (Unset)
-    {
-        Ret = RegDeleteValue(HandleSubKey, L"PageHeapFlags");
-        if (Ret != ERROR_SUCCESS)
-        {
-            wprintf(L"MS: RegDeleteValue failed (%d)\n", Ret);
-        }
-    }
-    else
-    {
-        DWORD PageHeapFlags;
-
-        PageHeapFlags = ReagFlagsFromRegistry(HandleSubKey, Buffer, L"PageHeapFlags", MaxLen);
-        PageHeapFlags &= ~3;
-
-        if (Full)
-        {
-            PageHeapFlags |= 1;
-        }
-        PageHeapFlags |= 2;
-
-        wsprintf(Buffer, L"0x%x", PageHeapFlags);
-        Ret = RegSetValueEx(HandleSubKey, L"PageHeapFlags", 0, REG_SZ, Buffer, 11 * sizeof(WCHAR));
-        if (Ret != ERROR_SUCCESS)
-        {
-            wprintf(L"MS: RegSetValueEx failed (%d)\n", Ret);
-        }
-    }
-
-    if (Set)
-    {
-        DWORD Type, VerifierFlags, Len;
-
-        VerifierFlags = 0;
-        Len = MaxLen;
-        if (RegQueryValueEx(HandleSubKey, L"VerifierFlags", NULL, &Type, Buffer, &Len) == ERROR_SUCCESS &&
-            Type == REG_DWORD && Len == sizeof(DWORD))
-        {
-            VerifierFlags = ((DWORD *)Buffer)[0];
-            VerifierFlags &= ~0x8001;
-        }
-
-        if (Full)
-        {
-            VerifierFlags |= 1;
-        }
-        else
-        {
-            VerifierFlags |= 0x8000;
-        }
-
-        Ret = RegSetValueEx(HandleSubKey, L"VerifierFlags", 0, REG_DWORD, (const BYTE *)&VerifierFlags, sizeof(DWORD));
-        if (Ret != ERROR_SUCCESS)
-        {
-            wprintf(L"MS: RegSetValueEx failed (%d)\n", Ret);
-        }
-    }
-
-    wprintf(L"path: %s\n", ImageExecOptionsString);
-    wprintf(L"\t%s: page heap %s\n", Image, (Set ? L"enabled" : L"disabled"));
-
-    HeapFree(GetProcessHeap(), 0, Buffer);
-    RegCloseKey(HandleSubKey);
-    RegCloseKey(HandleKey);
-}
-
-static BOOL DisplayImageInfo(HKEY HandleKey, PWSTR SubKey, PBOOL Header)
-{
-    LONG Ret;
-    BOOL Handled;
-    DWORD MaxLen, GlobalFlags;
-    HKEY HandleSubKey;
-    PVOID Buffer;
-
-    Ret = RegOpenKeyEx(HandleKey, SubKey, 0, KEY_READ, &HandleSubKey);
-    if (Ret != ERROR_SUCCESS)
-    {
-        wprintf(L"DII: RegOpenKeyEx failed (%d)\n", Ret);
-        return FALSE;
-    }
-
-    Ret = RegQueryInfoKey(HandleSubKey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &MaxLen, NULL, NULL);
-    if (Ret != ERROR_SUCCESS)
-    {
-        wprintf(L"DII: RegQueryInfoKey failed (%d)\n", Ret);
-        RegCloseKey(HandleSubKey);
-        return FALSE;
-    }
-
-    Buffer = HeapAlloc(GetProcessHeap(), 0, MaxLen);
-    if (Buffer == NULL)
-    {
-        wprintf(L"DII: HeapAlloc failed\n");
-        RegCloseKey(HandleSubKey);
-        return FALSE;
-    }
-
-    Handled = FALSE;
-    GlobalFlags = ReagFlagsFromRegistry(HandleSubKey, Buffer, L"GlobalFlag", MaxLen);
-    if (GlobalFlags & 0x02000000)
-    {
-        DWORD PageHeapFlags;
-
-        if (Image == NULL)
-        {
-            if (!*Header)
-            {
-                wprintf(L"path: %s\n", ImageExecOptionsString);
-                *Header = TRUE;
-            }
-            wprintf(L"\t%s: page heap enabled with flags (", SubKey);
-        }
-        else
-        {
-            wprintf(L"Page heap is enabled for %s with flags (", SubKey);
-        }
-
-        PageHeapFlags = ReagFlagsFromRegistry(HandleSubKey, Buffer, L"PageHeapFlags", MaxLen);
-        if (PageHeapFlags & 0x1)
-        {
-            wprintf(L"full ");
-        }
-
-        if (PageHeapFlags & 0x2)
-        {
-            wprintf(L"traces");
-        }
-
-        wprintf(L")\n");
-
-        Handled = TRUE;
-    }
-
-    HeapFree(GetProcessHeap(), 0, Buffer);
-    RegCloseKey(HandleSubKey);
-
-    return Handled;
-}
-
-static VOID DisplayStatus(VOID)
-{
-    LONG Ret;
-    HKEY HandleKey;
-    DWORD Index, MaxLen, Handled;
-    TCHAR * SubKey;
-    BOOL Header;
-
-    Ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, ImageExecOptionsString, 0, KEY_READ, &HandleKey);
-    if (Ret != ERROR_SUCCESS)
-    {
-        wprintf(L"DS: RegOpenKeyEx failed (%d)\n", Ret);
-        return;
-    }
-
-    Ret = RegQueryInfoKey(HandleKey, NULL, NULL, NULL, NULL, &MaxLen, NULL, NULL, NULL, NULL, NULL, NULL);
-    if (Ret != ERROR_SUCCESS)
-    {
-        wprintf(L"DS: RegQueryInfoKey failed (%d)\n", Ret);
-        RegCloseKey(HandleKey);
-        return;
-    }
-
-    ++MaxLen; // NULL-char
-    SubKey = HeapAlloc(GetProcessHeap(), 0, MaxLen * sizeof(TCHAR));
-    if (SubKey == NULL)
-    {
-        wprintf(L"DS: HeapAlloc failed\n");
-        RegCloseKey(HandleKey);
-        return;
-    }
-
-    Index = 0;
-    Handled = 0;
-    Header = FALSE;
-    do
-    {
-        Ret = RegEnumKey(HandleKey, Index, SubKey, MaxLen);
-        if (Ret != ERROR_NO_MORE_ITEMS)
-        {
-            if (Image == NULL || wcscmp(SubKey, Image) == 0)
-            {
-                if (DisplayImageInfo(HandleKey, SubKey, &Header))
-                {
-                    ++Handled;
-                }
-            }
-
-            ++Index;
-        }
-    } while (Ret != ERROR_NO_MORE_ITEMS);
-
-    if (Handled == 0)
-    {
-        if (Image == NULL)
-        {
-            wprintf(L"No application has page heap enabled.\n");
-        }
-        else
-        {
-            wprintf(L"Page heap is not enabled for %s\n", Image);
-        }
-    }
-
-    HeapFree(GetProcessHeap(), 0, SubKey);
-    RegCloseKey(HandleKey);
-}
-
-static VOID Usage(VOID)
-{
-    wprintf(L"Usage: gflags /p [image.exe] [/enable|/disable [/full]]\n"
-            L"\timage.exe:\tImage you want to deal with\n"
-            L"\t/enable:\tenable page heap for the image\n"
-            L"\t/disable:\tdisable page heap for the image\n"
-            L"\t/full:\t\tactivate full debug page heap\n");
-}
-
 static BOOL ParseCmdline(int argc, LPWSTR argv[])
 {
     INT i;
-    BOOL UsePageHeap = FALSE;
 
     if (argc < 2)
     {
-        wprintf(L"Not enough args!\n", argc);
-        Usage();
+        wprintf(L"Not enough args!\n");
         return FALSE;
     }
 
@@ -338,37 +42,12 @@ static BOOL ParseCmdline(int argc, LPWSTR argv[])
             if (argv[i][1] == L'p' && argv[i][2] == UNICODE_NULL)
             {
                 UsePageHeap = TRUE;
-            }
-            else if (argv[i][1] == L'p' && argv[i][2] != UNICODE_NULL)
-            {
-                wprintf(L"Invalid option: %s\n", argv[i]);
-                Usage();
-                return FALSE;
-            }
-            else
-            {
-                if (wcscmp(argv[i], L"/enable") == 0)
-                {
-                    Set = TRUE;
-                }
-                else if (wcscmp(argv[i], L"/disable") == 0)
-                {
-                    Unset = TRUE;
-                }
-                else if (wcscmp(argv[i], L"/full") == 0)
-                {
-                    Full = TRUE;
-                }
+                return PageHeap_ParseCmdline(i + 1, argc, argv);
             }
         }
-        else if (Image == NULL)
-        {
-            Image = argv[i];
-        }
         else
         {
             wprintf(L"Invalid option: %s\n", argv[i]);
-            Usage();
             return FALSE;
         }
     }
@@ -376,49 +55,28 @@ static BOOL ParseCmdline(int argc, LPWSTR argv[])
     if (!UsePageHeap)
     {
         wprintf(L"Only page heap flags are supported\n");
-        Usage();
-        return FALSE;
-    }
-
-    if (Set && Unset)
-    {
-        wprintf(L"ENABLE and DISABLED cannot be set together\n");
-        Usage();
-        return FALSE;
-    }
-
-    if (Image == NULL && (Set || Unset || Full))
-    {
-        wprintf(L"Can't ENABLE or DISABLE with no image\n");
-        Usage();
-        return FALSE;
-    }
-
-    if (!Set && !Unset && Full)
-    {
-        wprintf(L"Cannot deal with full traces with no other indication\n");
-        Usage();
         return FALSE;
     }
 
     return TRUE;
 }
 
+
 int wmain(int argc, LPWSTR argv[])
 {
     if (!ParseCmdline(argc, argv))
     {
+        wprintf(L"Usage: gflags /p [image.exe] [/enable|/disable [/full]]\n"
+                L"\timage.exe:\tImage you want to deal with\n"
+                L"\t/enable:\tenable page heap for the image\n"
+                L"\t/disable:\tdisable page heap for the image\n"
+                L"\t/full:\t\tactivate full debug page heap\n");
         return 1;
     }
 
-    if (!Set && !Unset)
-    {
-        DisplayStatus();
-    }
-    else
+    if (UsePageHeap)
     {
-        ModifyStatus();
+        return PageHeap_Execute();
     }
-
-    return 0;
+    return 2;
 }
diff --git a/modules/rosapps/applications/cmdutils/gflags/gflags.h b/modules/rosapps/applications/cmdutils/gflags/gflags.h
new file mode 100644 (file)
index 0000000..740f6a7
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+* PROJECT:     Global Flags utility
+* LICENSE:     GPL-2.0 (https://spdx.org/licenses/GPL-2.0)
+* PURPOSE:     Global Flags utility page heap options
+* COPYRIGHT:   Copyright 2017 Pierre Schweitzer (pierre@reactos.org)
+*/
+
+#define WIN32_NO_STATUS
+#include <stdarg.h>
+#include <windef.h>
+#include <winbase.h>
+#include <winuser.h>
+#include <winreg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+/* Option specific commandline parsing */
+BOOL PageHeap_ParseCmdline(INT i, int argc, LPWSTR argv[]);
+
+/* Execute parsed options */
+INT PageHeap_Execute();
+
+/* Common functions */
+DWORD ReagFlagsFromRegistry(HKEY SubKey, PVOID Buffer, PWSTR Value, DWORD MaxLen);
+
diff --git a/modules/rosapps/applications/cmdutils/gflags/pageheap.c b/modules/rosapps/applications/cmdutils/gflags/pageheap.c
new file mode 100644 (file)
index 0000000..33d11b1
--- /dev/null
@@ -0,0 +1,355 @@
+/*
+ * PROJECT:     Global Flags utility
+ * LICENSE:     GPL-2.0 (https://spdx.org/licenses/GPL-2.0)
+ * PURPOSE:     Global Flags utility page heap options
+ * COPYRIGHT:   Copyright 2017 Pierre Schweitzer (pierre@reactos.org)
+ */
+
+#include "gflags.h"
+
+static BOOL Set = FALSE;
+static BOOL Unset = FALSE;
+static BOOL Full = FALSE;
+static PWSTR Image = NULL;
+static WCHAR ImageExecOptionsString[] = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options";
+
+
+static VOID ModifyStatus(VOID)
+{
+    LONG Ret;
+    DWORD MaxLen, GlobalFlags;
+    PVOID Buffer;
+    HKEY HandleKey, HandleSubKey;
+
+    Ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, ImageExecOptionsString, 0, KEY_WRITE | KEY_READ, &HandleKey);
+    if (Ret != ERROR_SUCCESS)
+    {
+        wprintf(L"MS: RegOpenKeyEx failed (%d)\n", Ret);
+        return;
+    }
+
+    Ret = RegCreateKeyEx(HandleKey, Image, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE | KEY_READ, NULL, &HandleSubKey, NULL);
+    if (Ret != ERROR_SUCCESS)
+    {
+        wprintf(L"MS: RegCreateKeyEx failed (%d)\n", Ret);
+        return;
+    }
+
+    Ret = RegQueryInfoKey(HandleSubKey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &MaxLen, NULL, NULL);
+    if (Ret != ERROR_SUCCESS)
+    {
+        wprintf(L"MS: RegQueryInfoKey failed (%d)\n", Ret);
+        RegCloseKey(HandleSubKey);
+        RegCloseKey(HandleKey);
+        return;
+    }
+
+    MaxLen = max(MaxLen, 11 * sizeof(WCHAR));
+    Buffer = HeapAlloc(GetProcessHeap(), 0, MaxLen);
+    if (Buffer == NULL)
+    {
+        wprintf(L"MS: HeapAlloc failed\n");
+        RegCloseKey(HandleSubKey);
+        RegCloseKey(HandleKey);
+        return;
+    }
+
+    GlobalFlags = ReagFlagsFromRegistry(HandleSubKey, Buffer, L"GlobalFlag", MaxLen);
+    if (Set)
+    {
+        GlobalFlags |= 0x02000000;
+    }
+    else
+    {
+        GlobalFlags &= ~0x02000000;
+    }
+
+    if (GlobalFlags != 0)
+    {
+        wsprintf(Buffer, L"0x%08x", GlobalFlags);
+        Ret = RegSetValueEx(HandleSubKey, L"GlobalFlag", 0, REG_SZ, Buffer, 11 * sizeof(WCHAR));
+        if (Ret != ERROR_SUCCESS)
+        {
+            wprintf(L"MS: RegSetValueEx failed (%d)\n", Ret);
+        }
+    }
+    else
+    {
+        Ret = RegDeleteValue(HandleSubKey, L"GlobalFlag");
+        if (Ret != ERROR_SUCCESS)
+        {
+            wprintf(L"MS: RegDeleteValue failed (%d)\n", Ret);
+        }
+    }
+
+    if (Unset)
+    {
+        Ret = RegDeleteValue(HandleSubKey, L"PageHeapFlags");
+        if (Ret != ERROR_SUCCESS)
+        {
+            wprintf(L"MS: RegDeleteValue failed (%d)\n", Ret);
+        }
+    }
+    else
+    {
+        DWORD PageHeapFlags;
+
+        PageHeapFlags = ReagFlagsFromRegistry(HandleSubKey, Buffer, L"PageHeapFlags", MaxLen);
+        PageHeapFlags &= ~3;
+
+        if (Full)
+        {
+            PageHeapFlags |= 1;
+        }
+        PageHeapFlags |= 2;
+
+        wsprintf(Buffer, L"0x%x", PageHeapFlags);
+        Ret = RegSetValueEx(HandleSubKey, L"PageHeapFlags", 0, REG_SZ, Buffer, 11 * sizeof(WCHAR));
+        if (Ret != ERROR_SUCCESS)
+        {
+            wprintf(L"MS: RegSetValueEx failed (%d)\n", Ret);
+        }
+    }
+
+    if (Set)
+    {
+        DWORD Type, VerifierFlags, Len;
+
+        VerifierFlags = 0;
+        Len = MaxLen;
+        if (RegQueryValueEx(HandleSubKey, L"VerifierFlags", NULL, &Type, Buffer, &Len) == ERROR_SUCCESS &&
+            Type == REG_DWORD && Len == sizeof(DWORD))
+        {
+            VerifierFlags = ((DWORD *)Buffer)[0];
+            VerifierFlags &= ~0x8001;
+        }
+
+        if (Full)
+        {
+            VerifierFlags |= 1;
+        }
+        else
+        {
+            VerifierFlags |= 0x8000;
+        }
+
+        Ret = RegSetValueEx(HandleSubKey, L"VerifierFlags", 0, REG_DWORD, (const BYTE *)&VerifierFlags, sizeof(DWORD));
+        if (Ret != ERROR_SUCCESS)
+        {
+            wprintf(L"MS: RegSetValueEx failed (%d)\n", Ret);
+        }
+    }
+
+    wprintf(L"path: %s\n", ImageExecOptionsString);
+    wprintf(L"\t%s: page heap %s\n", Image, (Set ? L"enabled" : L"disabled"));
+
+    HeapFree(GetProcessHeap(), 0, Buffer);
+    RegCloseKey(HandleSubKey);
+    RegCloseKey(HandleKey);
+}
+
+static BOOL DisplayImageInfo(HKEY HandleKey, PWSTR SubKey, PBOOL Header)
+{
+    LONG Ret;
+    BOOL Handled;
+    DWORD MaxLen, GlobalFlags;
+    HKEY HandleSubKey;
+    PVOID Buffer;
+
+    Ret = RegOpenKeyEx(HandleKey, SubKey, 0, KEY_READ, &HandleSubKey);
+    if (Ret != ERROR_SUCCESS)
+    {
+        wprintf(L"DII: RegOpenKeyEx failed (%d)\n", Ret);
+        return FALSE;
+    }
+
+    Ret = RegQueryInfoKey(HandleSubKey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &MaxLen, NULL, NULL);
+    if (Ret != ERROR_SUCCESS)
+    {
+        wprintf(L"DII: RegQueryInfoKey failed (%d)\n", Ret);
+        RegCloseKey(HandleSubKey);
+        return FALSE;
+    }
+
+    Buffer = HeapAlloc(GetProcessHeap(), 0, MaxLen);
+    if (Buffer == NULL)
+    {
+        wprintf(L"DII: HeapAlloc failed\n");
+        RegCloseKey(HandleSubKey);
+        return FALSE;
+    }
+
+    Handled = FALSE;
+    GlobalFlags = ReagFlagsFromRegistry(HandleSubKey, Buffer, L"GlobalFlag", MaxLen);
+    if (GlobalFlags & 0x02000000)
+    {
+        DWORD PageHeapFlags;
+
+        if (Image == NULL)
+        {
+            if (!*Header)
+            {
+                wprintf(L"path: %s\n", ImageExecOptionsString);
+                *Header = TRUE;
+            }
+            wprintf(L"\t%s: page heap enabled with flags (", SubKey);
+        }
+        else
+        {
+            wprintf(L"Page heap is enabled for %s with flags (", SubKey);
+        }
+
+        PageHeapFlags = ReagFlagsFromRegistry(HandleSubKey, Buffer, L"PageHeapFlags", MaxLen);
+        if (PageHeapFlags & 0x1)
+        {
+            wprintf(L"full ");
+        }
+
+        if (PageHeapFlags & 0x2)
+        {
+            wprintf(L"traces");
+        }
+
+        wprintf(L")\n");
+
+        Handled = TRUE;
+    }
+
+    HeapFree(GetProcessHeap(), 0, Buffer);
+    RegCloseKey(HandleSubKey);
+
+    return Handled;
+}
+
+static VOID DisplayStatus(VOID)
+{
+    LONG Ret;
+    HKEY HandleKey;
+    DWORD Index, MaxLen, Handled;
+    TCHAR * SubKey;
+    BOOL Header;
+
+    Ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, ImageExecOptionsString, 0, KEY_READ, &HandleKey);
+    if (Ret != ERROR_SUCCESS)
+    {
+        wprintf(L"DS: RegOpenKeyEx failed (%d)\n", Ret);
+        return;
+    }
+
+    Ret = RegQueryInfoKey(HandleKey, NULL, NULL, NULL, NULL, &MaxLen, NULL, NULL, NULL, NULL, NULL, NULL);
+    if (Ret != ERROR_SUCCESS)
+    {
+        wprintf(L"DS: RegQueryInfoKey failed (%d)\n", Ret);
+        RegCloseKey(HandleKey);
+        return;
+    }
+
+    ++MaxLen; // NULL-char
+    SubKey = HeapAlloc(GetProcessHeap(), 0, MaxLen * sizeof(TCHAR));
+    if (SubKey == NULL)
+    {
+        wprintf(L"DS: HeapAlloc failed\n");
+        RegCloseKey(HandleKey);
+        return;
+    }
+
+    Index = 0;
+    Handled = 0;
+    Header = FALSE;
+    do
+    {
+        Ret = RegEnumKey(HandleKey, Index, SubKey, MaxLen);
+        if (Ret != ERROR_NO_MORE_ITEMS)
+        {
+            if (Image == NULL || wcscmp(SubKey, Image) == 0)
+            {
+                if (DisplayImageInfo(HandleKey, SubKey, &Header))
+                {
+                    ++Handled;
+                }
+            }
+
+            ++Index;
+        }
+    } while (Ret != ERROR_NO_MORE_ITEMS);
+
+    if (Handled == 0)
+    {
+        if (Image == NULL)
+        {
+            wprintf(L"No application has page heap enabled.\n");
+        }
+        else
+        {
+            wprintf(L"Page heap is not enabled for %s\n", Image);
+        }
+    }
+
+    HeapFree(GetProcessHeap(), 0, SubKey);
+    RegCloseKey(HandleKey);
+}
+
+BOOL PageHeap_ParseCmdline(INT i, int argc, LPWSTR argv[])
+{
+    for (; i < argc; i++)
+    {
+        if (argv[i][0] == L'/')
+        {
+            if (wcscmp(argv[i], L"/enable") == 0)
+            {
+                Set = TRUE;
+            }
+            else if (wcscmp(argv[i], L"/disable") == 0)
+            {
+                Unset = TRUE;
+            }
+            else if (wcscmp(argv[i], L"/full") == 0)
+            {
+                Full = TRUE;
+            }
+        }
+        else if (Image == NULL)
+        {
+            Image = argv[i];
+        }
+        else
+        {
+            wprintf(L"Invalid option: %s\n", argv[i]);
+            return FALSE;
+        }
+    }
+
+    if (Set && Unset)
+    {
+        wprintf(L"ENABLE and DISABLED cannot be set together\n");
+        return FALSE;
+    }
+
+    if (Image == NULL && (Set || Unset || Full))
+    {
+        wprintf(L"Can't ENABLE or DISABLE with no image\n");
+        return FALSE;
+    }
+
+    if (!Set && !Unset && Full)
+    {
+        wprintf(L"Cannot deal with full traces with no other indication\n");
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+INT PageHeap_Execute()
+{
+    if (!Set && !Unset)
+    {
+        DisplayStatus();
+    }
+    else
+    {
+        ModifyStatus();
+    }
+
+    return 0;
+}