MONKEY.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:31k
源码类别:

Windows编程

开发平台:

Visual C++

  1. /******************************************************************************
  2. *       This is a part of the Microsoft Source Code Samples. 
  3. *       Copyright (C) 1993-1997 Microsoft Corporation.
  4. *       All rights reserved. 
  5. *       This source code is only intended as a supplement to 
  6. *       Microsoft Development Tools and/or WinHelp documentation.
  7. *       See these sources for detailed information regarding the 
  8. *       Microsoft samples programs.
  9. ******************************************************************************/
  10. /*************************************************************************
  11. *
  12. *  PROGRAM: Monkey: the Registry Monkey Utility.
  13. *  PURPOSE: To demonstrate Registry API.
  14. *  COMMENTS:
  15. *
  16. *************************************************************************/
  17. #define STRICT
  18. #include <windows.h>
  19. #include <string.h>
  20. #define _MBCS
  21. #include <mbstring.h>
  22. #include <stdlib.h>
  23. #include <stdio.h>
  24. #include "monkey.h"
  25. HANDLE hInst;
  26. HWND   hDlg;
  27. HANDLE hHeap;
  28. /*************************************************************************
  29. *
  30. *  FUNCTION: WinMain(HANDLE, HANDLE, LPSTR, int)
  31. *
  32. *  PURPOSE: Creates the dialogbox.
  33. *
  34. *  COMMENTS:
  35. *
  36. *************************************************************************/
  37. int APIENTRY WinMain (HINSTANCE hInstance,
  38.                       HINSTANCE hPrevInstance,
  39.                       LPSTR     lpCmdLine,
  40.                       int       nCmdShow)
  41. {
  42.   DWORD retCode;
  43.   UNREFERENCED_PARAMETER( nCmdShow );
  44.   UNREFERENCED_PARAMETER( lpCmdLine );
  45.   UNREFERENCED_PARAMETER( hPrevInstance );
  46.   hInst   = hInstance;
  47.   hHeap   = HeapCreate (0, 0, 0);
  48.   retCode = DialogBox ((HANDLE)hInst, (LPCSTR)"MonkeyDlg",
  49.                         NULL, (DLGPROC)MonkeyDlgProc);
  50.   HeapDestroy (hHeap);
  51.   return  (retCode);
  52. }
  53. /************************************************************************
  54. *
  55. *  FUNCTION: MonkeyDlgProc();
  56. *
  57. *  PURPOSE:  Handle the Monkey dialog box messages.
  58. *
  59. *  MESSAGES:
  60. *
  61. *    WM_INITDIALOG  - Posts WM_GETFIRSTKEY message.
  62. *
  63. *    WM_GETFIRSTKEY - Puts the first 4 pre-defined keys in the listbox.
  64. *
  65. *    IDL_LISTBOX    - Trapped when an item in the left hand listbox
  66. *                     has been double clicked.  It posts a IDB_NEXT message.
  67. *
  68. *    IDL_LISTBOX2   - Trapped when an item in the right hand listbox has
  69. *                     been double clicked.  It basically calls DisplayKeyData,
  70. *                     which fills the Value edit fields with the data from
  71. *                     the current key's specified value information.
  72. *
  73. *    IDB_PRINT      - Basically calls PrintTree() which does a recursive
  74. *                     print of the Registry from the current key to the
  75. *                     end of it's branches.
  76. *
  77. *    IDB_BACK       - Sets the dialog box with the information from the
  78. *                     previously selected key (one closer to the root of
  79. *                     the registry, the parent of the current key).
  80. *
  81. *    IDB_NEXT       - Sets the dialog box with the information on the
  82. *                     selected key child.
  83. *
  84. *    IDR_FULL       - Sets a global variable used to determine if the
  85. *                     user wants to print full Registry information
  86. *                     or only information from keys that have value
  87. *                     associated with it.  Variable is set to TRUE.
  88. *
  89. *    IDR_TRIMMED    - Same as above, only the variable is set to FALSE.
  90. *
  91. ************************************************************************/
  92. int APIENTRY MonkeyDlgProc (HWND hDlg, WORD wMsg, LONG wParam, LONG lParam)
  93.   {
  94.    ULONG    KeyClassLength = 256;
  95.    ULONG    KeyNameLength = 256;
  96.    DWORD    indexLB;
  97.    CHAR     *putNullAt;
  98.    CHAR     lpBuffer1[128];
  99.    CHAR     lpBuffer2[128];
  100.    static   CHAR     RegPath[MAX_PATH]  = "";
  101.    static   CHAR     NameLBSelect[256]  = "";
  102.    static   HKEY     hKeyRoot;
  103.    static   DWORD    RegLevel;
  104.    static   BOOL     FullBranches = TRUE;
  105.    static   HANDLE   hFile = INVALID_HANDLE_VALUE;
  106.    static   HANDLE   hBootIni;
  107.   UNREFERENCED_PARAMETER( lParam );
  108.   switch (wMsg)
  109.     {
  110.       case WM_INITDIALOG:
  111.           // Post a message to get the first 4 pre-defined keys, and set
  112.           // Full Branches to be the print default.
  113.         PostMessage (hDlg, WM_GETFIRSTKEY, 0, 0);
  114.         CheckDlgButton (hDlg, IDR_FULL, TRUE);
  115.         return (0);
  116.       case WM_GETFIRSTKEY:
  117.           // Initialize by putting the first 4 predefined keys of the
  118.           // registry in the list box.
  119.         SendMessage (GetDlgItem(hDlg, IDL_LISTBOX),
  120.                      LB_ADDSTRING, 0, (LONG)"HKEY_LOCAL_MACHINE");
  121.         SendMessage (GetDlgItem(hDlg, IDL_LISTBOX),
  122.                      LB_ADDSTRING, 0, (LONG)"HKEY_CURRENT_USER");
  123.         SendMessage (GetDlgItem(hDlg, IDL_LISTBOX),
  124.                      LB_ADDSTRING, 0, (LONG)"HKEY_USERS");
  125.         SendMessage (GetDlgItem(hDlg, IDL_LISTBOX),
  126.                      LB_ADDSTRING, 0, (LONG)"HKEY_CLASSES_ROOT");
  127.         hKeyRoot = 0;                   // Initialize hKeyRoot.
  128.         return (0);
  129.       case WM_SYSCOMMAND:
  130.         if (wParam == SC_CLOSE)
  131.           {
  132.           EndDialog (hDlg, TRUE);
  133.           if (hFile != INVALID_HANDLE_VALUE)
  134.             CloseHandle (hFile);
  135.           return (TRUE);
  136.           }
  137.         break;
  138.       case WM_COMMAND:
  139.         switch (LOWORD(wParam))
  140.           {
  141.             case IDR_FULL:
  142.                 // If Full Branches pressed, set global var to TRUE.
  143.               FullBranches = TRUE;
  144.               return (0);
  145.             case IDR_TRIMMED:
  146.                 // If Trimmed Branches pressed, set global var to FALSE.
  147.               FullBranches = FALSE;
  148.               return (0);
  149.             case IDL_LISTBOX:
  150.                  // If double click in left hand listbox, clear Value
  151.                  // edit fields, and execute Next functionality.
  152.                if ( HIWORD (wParam) == LBN_DBLCLK)
  153.                 {
  154.                  SetDlgItemText (hDlg, IDE_VALUE1, "");
  155.                  SetDlgItemText (hDlg, IDE_VALUE2, "");
  156.                  PostMessage (hDlg, WM_COMMAND, IDB_NEXT, 0);
  157.                 }
  158.                return (0);
  159.             case IDL_LISTBOX2:
  160.                  // If double click right hand listbox, clear Value edit
  161.                  // fields, then display the key's data.
  162.                if ( HIWORD (wParam) == LBN_DBLCLK)
  163.                 {
  164.                  SetDlgItemText (hDlg, IDE_VALUE1, "");
  165.                  SetDlgItemText (hDlg, IDE_VALUE2, "");
  166.                  DisplayKeyData (hDlg, RegPath, hKeyRoot);
  167.                 }
  168.                return (0);
  169.             case IDB_NEXT:
  170.                  // Get the index of the cursor selection
  171.                  // in the list box.
  172.                indexLB = SendMessage (GetDlgItem (hDlg, IDL_LISTBOX),
  173.                                       LB_GETCURSEL, 0, 0);
  174.                  // If nothing is selected, flag user and return, otherwise
  175.                  // process the selected key.
  176.                                        // LB_ERR indicates nothing selected.
  177.                if (indexLB == LB_ERR)
  178.                  {
  179.                  LoadString(hInst, IDS_SELECTMSG, lpBuffer1, sizeof(lpBuffer1));
  180.                  LoadString(hInst, IDS_NAME, lpBuffer2, sizeof(lpBuffer2));
  181.                  MessageBox (hDlg, lpBuffer1, lpBuffer2, MB_OK);
  182.                  return (0);
  183.                  }
  184.                  // If listbox item 0 is pressed, user wants to move
  185.                  // back up.  Execute the Back functionality.
  186.                if (indexLB == 0 && hKeyRoot)
  187.                 {
  188.                 PostMessage (hDlg, WM_COMMAND, IDB_BACK, 0);
  189.                 return (0);
  190.                 }
  191.                                        // Get text from selection in LB.
  192.                SendMessage (GetDlgItem (hDlg, IDL_LISTBOX),
  193.                             LB_GETTEXT, indexLB, (LPARAM)NameLBSelect);
  194.                                        // Put name of chosen item in Name field.
  195.                SetDlgItemText (hDlg, IDE_NAME, NameLBSelect);
  196.                                        // Then clear ListBox entries.
  197.                SendMessage (GetDlgItem (hDlg, IDL_LISTBOX),
  198.                             LB_RESETCONTENT, 0, 0);
  199.                SendMessage (GetDlgItem (hDlg, IDL_LISTBOX2),
  200.                             LB_RESETCONTENT, 0, 0);
  201.                EnumerateLevel (hDlg, NameLBSelect, RegPath, &hKeyRoot);
  202.                return (0);
  203.             case IDB_BACK:
  204.                  // For this case (hRootKey = 0)you're at the top level already.
  205.                  // Tell the user, then return
  206.                if (!hKeyRoot)
  207.                  {
  208.                  LoadString(hInst, IDS_TOPLEVEL, lpBuffer1, sizeof(lpBuffer1));
  209.                  LoadString(hInst, IDS_NAME, lpBuffer2, sizeof(lpBuffer2));
  210.                  MessageBox (hDlg, lpBuffer1, lpBuffer2, MB_OK);
  211.                  return (0);
  212.                  }
  213.                  //For all remaining cases, clear the listboxes.
  214.                SendMessage (GetDlgItem (hDlg, IDL_LISTBOX),
  215.                             LB_RESETCONTENT, 0, 0);
  216.                SendMessage (GetDlgItem (hDlg, IDL_LISTBOX2),
  217.                             LB_RESETCONTENT, 0, 0);
  218.                  // If hRootKey has a value, but the pathname is blank,
  219.                  // then you must be 1 level deep, reset to level 0 by
  220.                  // posting WM_GETFIRSTKEY.
  221.                if (strcmp (RegPath, "") == 0)
  222.                  {
  223.                  SetDlgItemText (hDlg, IDE_NAME, "");
  224.                  PostMessage (hDlg, WM_GETFIRSTKEY, 0, 0);
  225.                  return (0);
  226.                  }
  227.                  // Two cases left.  One in which the path has only one
  228.                  // key name in it, and no back slash character (meaning
  229.                  // strrchr() will return NULL); and one the other case
  230.                  // where there are more than one key name in the path (
  231.                  // and at least one back slash for strrchr().  If this
  232.                  // is the first case, we want to fakeout EnumerateLevel
  233.                  // into thinking we just picked one of the pre-defined keys,
  234.                  // and then re-enumerate it's child keys.
  235.                if ((putNullAt = _mbsrchr (RegPath, '\')) == NULL)
  236.                  {
  237.                  RegPath[0] = '';
  238.                  switch ((DWORD)hKeyRoot)
  239.                    {
  240.                    case (DWORD)HKEY_LOCAL_MACHINE:
  241.                      strcpy (NameLBSelect, "HKEY_LOCAL_MACHINE");
  242.                      break;
  243.                    case (DWORD)HKEY_USERS:
  244.                      strcpy (NameLBSelect, "HKEY_USERS");
  245.                      break;
  246.                    case (DWORD)HKEY_CURRENT_USER:
  247.                      strcpy (NameLBSelect, "HKEY_CURRENT_USER");
  248.                      break;
  249.                    case (DWORD)HKEY_CLASSES_ROOT:
  250.                      strcpy (NameLBSelect, "HKEY_CLASSES_ROOT");
  251.                      break;
  252.                    }
  253.                  SetDlgItemText (hDlg, IDE_NAME, NameLBSelect);
  254.                  hKeyRoot = 0;
  255.                  EnumerateLevel (hDlg, NameLBSelect, RegPath, &hKeyRoot);
  256.                  }
  257.                else
  258.                  {
  259.                    // In the final case, we can just trim the last key
  260.                    // name off the path, and re-enumerate the level.
  261.                  *putNullAt = '';
  262.                  putNullAt = _mbsrchr (RegPath, '\');
  263.                  if (putNullAt)
  264.                    {
  265.                    strcpy (NameLBSelect, putNullAt+1);
  266.                    *putNullAt = '';
  267.                    }
  268.                  else
  269.                    {
  270.                    strcpy (NameLBSelect, RegPath);
  271.                    *RegPath = '';
  272.                    }
  273.                  SetDlgItemText (hDlg, IDE_NAME, NameLBSelect);
  274.                  EnumerateLevel (hDlg, NameLBSelect, RegPath, &hKeyRoot);
  275.                  }
  276.                return (0);
  277.             default:
  278.                return (0);
  279.           }
  280.      }
  281.     return (FALSE);
  282.   }
  283. /************************************************************************
  284. *
  285. *  FUNCTION: EnumerateLevel();
  286. *
  287. *  PURPOSE: To get a valid key handle (either to determine if the one sent
  288. *           to the function was one of the pre-defined, or to open a key
  289. *           specified by the path), and to pass that key handle along
  290. *           to QueryKey().
  291. *
  292. *           To enumerate the children of a key, you must have
  293. *           an open handle to it.  The four top keys of the
  294. *           Registry are predefined and open for use:
  295. *           HKEY_LOCAL_MACHINE, HKEY_USERS, HKEY_CURRENT_USER,
  296. *           and HKEY_CLASSES_ROOT.  These 4 can be used for
  297. *           RegEnumKey as is; but to RegEnumKey on any of the
  298. *           children of these you must first have an open key
  299. *           handle to the child.
  300. *
  301. *           If hKeyRoot != 0, assume you are lower than the
  302. *           first level of the Registry and the user is trying
  303. *           to enumerate one of the children.  First calculate
  304. *           the name of the child, and then use RegOpenKey to
  305. *           get an open handle.
  306. *
  307. *           If hKeyRoot == 0, assume you are at the top level
  308. *           of the Registry, and set the hKey to be enumerated
  309. *           to be one of the 4 predefined values, the specific
  310. *           one indicated by the ListBox selection.
  311. *
  312. ************************************************************************/
  313.   VOID EnumerateLevel (HWND hDlg, LPTSTR NameLBSelect,
  314.                        LPTSTR RegPath, HKEY *hKeyRoot)
  315.   {
  316.     HKEY hKey;
  317.     DWORD  retCode;
  318.     CHAR   Buf[100];
  319.     CHAR   lpBuffer[128];
  320.     if (*hKeyRoot)
  321.       {
  322.                                        // If RegPath is not NULL, then
  323.                                        // you have to add a backslash to the
  324.                                        // path name before appending the next
  325.                                        // level child name.
  326.       if (strcmp (RegPath, "") != 0)
  327.         strcat (RegPath, "\");
  328.                                        // Add the next level child name.
  329.       strcat (RegPath, NameLBSelect);
  330.                                        // Use RegOpenKeyEx() with the new
  331.                                        // Registry path to get an open handle
  332.                                        // to the child key you want to
  333.                                        // enumerate.
  334.       retCode = RegOpenKeyEx (*hKeyRoot,
  335.                               RegPath,
  336.                               0,
  337.                               KEY_ENUMERATE_SUB_KEYS |
  338.                               KEY_EXECUTE |
  339.                               KEY_QUERY_VALUE,
  340.                               &hKey);
  341.       if (retCode != ERROR_SUCCESS)
  342.         {
  343.         if (retCode == ERROR_ACCESS_DENIED) {
  344.           LoadString(hInst, IDS_CANTOPENKEY, lpBuffer, sizeof(lpBuffer));
  345.           wsprintf (Buf, lpBuffer);
  346.         }
  347.         else {
  348.           LoadString(hInst, IDS_OPENKEYERR, lpBuffer, sizeof(lpBuffer));
  349.           wsprintf (Buf, lpBuffer, retCode, __LINE__);
  350.         }
  351.         MessageBox (hDlg, Buf, "", MB_OK);
  352.         PostMessage (hDlg, WM_COMMAND, IDB_BACK, 0);
  353.         return;
  354.         }
  355.       }
  356.     else
  357.       {
  358.                                        // Set the *hKeyRoot handle based
  359.                                        // on the text taken from the ListBox.
  360.       if (strcmp (NameLBSelect, "HKEY_CLASSES_ROOT") == 0)
  361.         *hKeyRoot = HKEY_CLASSES_ROOT;
  362.       if (strcmp (NameLBSelect, "HKEY_USERS") == 0)
  363.         *hKeyRoot = HKEY_USERS;
  364.       if (strcmp (NameLBSelect, "HKEY_LOCAL_MACHINE") == 0)
  365.         *hKeyRoot = HKEY_LOCAL_MACHINE;
  366.       if (strcmp (NameLBSelect, "HKEY_CURRENT_USER") == 0)
  367.         *hKeyRoot = HKEY_CURRENT_USER;
  368.       hKey = *hKeyRoot;     // hKey is used in RegEnumKey().
  369.       }//end if/else *hKeyRoot
  370.       QueryKey (hDlg, hKey);
  371.       RegCloseKey (hKey);   // Close the key handle.
  372. //      rect.top = 0; rect.left = 5; rect.right = 1200; rect.bottom = 25;
  373. //      hDC = GetDC (hDlg);
  374. //      FillRect (hDC, &rect, GetStockObject(WHITE_BRUSH));
  375. //      TextOut (hDC, 5, 5, RegPath, strlen(RegPath));
  376. //      ReleaseDC (hDlg, hDC);
  377.       SetDlgItemText (hDlg, IDE_TEXTOUT, RegPath);
  378.   }
  379. /************************************************************************
  380. *
  381. *  FUNCTION: QueryKey();
  382. *
  383. *  PURPOSE:  To display the key's children (subkeys) and the names of
  384. *            the Values associated with it.  This function uses RegEnumKey,
  385. *            RegEnumValue, and RegQueryInfoKey.
  386. *
  387. ************************************************************************/
  388. VOID QueryKey (HWND hDlg, HANDLE hKey)
  389.   {
  390.   CHAR     KeyName[MAX_PATH];
  391.   CHAR     ClassName[MAX_PATH] = ""; // Buffer for class name.
  392.   DWORD    dwcClassLen = MAX_PATH;   // Length of class string.
  393.   DWORD    dwcSubKeys;               // Number of sub keys.
  394.   DWORD    dwcMaxSubKey;             // Longest sub key size.
  395.   DWORD    dwcMaxClass;              // Longest class string.
  396.   DWORD    dwcValues;                // Number of values for this key.
  397.   DWORD    dwcMaxValueName;          // Longest Value name.
  398.   DWORD    dwcMaxValueData;          // Longest Value data.
  399.   DWORD    dwcSecDesc;               // Security descriptor.
  400.   FILETIME ftLastWriteTime;          // Last write time.
  401.   DWORD i;
  402.   DWORD retCode;
  403.   DWORD j;
  404.   DWORD retValue;
  405.   CHAR  ValueName[MAX_VALUE_NAME];
  406.   DWORD dwcValueName = MAX_VALUE_NAME;
  407.   CHAR  Buf[80];
  408.   CHAR  lpBuffer[80];
  409.   // Get Class name, Value count.
  410.   RegQueryInfoKey (hKey,              // Key handle.
  411.                    ClassName,         // Buffer for class name.
  412.                    &dwcClassLen,      // Length of class string.
  413.                    NULL,              // Reserved.
  414.                    &dwcSubKeys,       // Number of sub keys.
  415.                    &dwcMaxSubKey,     // Longest sub key size.
  416.                    &dwcMaxClass,      // Longest class string.
  417.                    &dwcValues,        // Number of values for this key.
  418.                    &dwcMaxValueName,  // Longest Value name.
  419.                    &dwcMaxValueData,  // Longest Value data.
  420.                    &dwcSecDesc,       // Security descriptor.
  421.                    &ftLastWriteTime); // Last write time.
  422.   SetDlgItemText (hDlg, IDE_CLASS, ClassName);
  423.   SetDlgItemInt  (hDlg, IDE_CVALUES, dwcValues, FALSE);
  424.   SendMessage (GetDlgItem (hDlg, IDL_LISTBOX),
  425.                LB_ADDSTRING, 0, (LONG)"..");
  426.                                        // Loop until RegEnumKey fails, get
  427.                                        // the name of each child and enter
  428.                                        // it into the box.
  429.   // Enumerate the Child Keys.
  430.   SetCursor (LoadCursor (NULL, IDC_WAIT));
  431.   for (i=0, retCode = ERROR_SUCCESS; retCode == ERROR_SUCCESS; i++)
  432.     {
  433.     retCode = RegEnumKey (hKey, i,
  434.                           KeyName, MAX_PATH);
  435.     if (retCode == (DWORD)ERROR_SUCCESS)
  436.       SendMessage (GetDlgItem(hDlg, IDL_LISTBOX),
  437.                    LB_ADDSTRING, 0, (LONG)KeyName);
  438.     }
  439.   SetCursor (LoadCursor (NULL, IDC_ARROW));
  440.   // Enumerate the Key Values
  441.         SetCursor (LoadCursor (NULL, IDC_WAIT));
  442.         if (dwcValues)
  443.           for (j = 0, retValue = ERROR_SUCCESS; j < dwcValues; j++)
  444.             {
  445.             dwcValueName = MAX_VALUE_NAME;
  446.             ValueName[0] = '';
  447.             retValue = RegEnumValue (hKey, j, ValueName,
  448.                                      &dwcValueName,
  449.                                      NULL,
  450.                                      NULL,               //&dwType,
  451.                                      NULL,               //&bData,
  452.                                      NULL);              //&bcData);
  453.             if (retValue != (DWORD)ERROR_SUCCESS &&
  454.                 retValue != ERROR_INSUFFICIENT_BUFFER)
  455.               {
  456.               LoadString(hInst, IDS_REGERR, lpBuffer, sizeof(lpBuffer));
  457.               wsprintf (Buf, lpBuffer, __LINE__, j, retValue, dwcValueName);
  458.               LoadString(hInst, IDS_DEBUG, lpBuffer, sizeof(lpBuffer));
  459.               MessageBox (hDlg, Buf, lpBuffer, MB_OK);
  460.               }
  461.             Buf[0] = '';
  462.             if (!strlen(ValueName)) {
  463.               LoadString(hInst, IDS_NONAME, lpBuffer, sizeof(lpBuffer));
  464.               strcpy (ValueName, lpBuffer);
  465.             }
  466.             wsprintf (Buf, "%d) %s ", j, ValueName);
  467.             SendMessage (GetDlgItem (hDlg, IDL_LISTBOX2),
  468.                            LB_ADDSTRING, 0, (LONG)Buf);
  469.             }// end for(;;)
  470.         SetCursor (LoadCursor (NULL, IDC_ARROW));
  471.   }
  472. /************************************************************************
  473. *
  474. *  FUNCTION: DisplayKeyData();
  475. *
  476. *  PURPOSE:  To display the keys values and value types to the Value edit
  477. *            field.  This function is called when the right hand listbox
  478. *            is double clicked.  The functionality is much like that found
  479. *            in the function PrintTree, please see it for more details.
  480. *
  481. ************************************************************************/
  482. VOID DisplayKeyData (HWND hDlg, CHAR *RegPath, HANDLE hKeyRoot)
  483.   {
  484.   HKEY   hKey;
  485.   DWORD  dwLBIndex;
  486.   CHAR   Buf[LINE_LEN];
  487.   CHAR   ValueName[MAX_VALUE_NAME];
  488.   DWORD  cbValueName = MAX_VALUE_NAME;
  489.   DWORD  dwType;
  490.   DWORD  retCode;
  491.   CHAR   lpBuffer[128];
  492.   CHAR   lpBuffer2[128];
  493.   CHAR   ClassName[MAX_PATH];
  494.   DWORD  dwcClassLen = MAX_PATH;
  495.   DWORD  dwcSubKeys;
  496.   DWORD  dwcMaxSubKey;
  497.   DWORD  dwcMaxClass;
  498.   DWORD  dwcValues;
  499.   DWORD  dwcMaxValueName;
  500.   DWORD  dwcMaxValueData;
  501.   DWORD  dwcSecDesc;
  502.   FILETIME  ftLastWriteTime;
  503.   BYTE   *bData;
  504.   DWORD  cbData;
  505.   CHAR   *outBuf;
  506.   DWORD  i;
  507.   DWORD  cStrLen;
  508.   CHAR   *BinaryStrBuf;
  509.   CHAR   ByteBuf[4];
  510.   CHAR   *ptr;
  511.   // OPEN THE KEY.
  512.                                 // LBIndex should == value index.
  513.   dwLBIndex = SendMessage (GetDlgItem (hDlg, IDL_LISTBOX2),
  514.                            LB_GETCURSEL, 0, 0);
  515.   retCode = RegOpenKeyEx (hKeyRoot,    // Key handle at root level.
  516.                           RegPath,     // Path name of child key.
  517.                           0,           // Reserved.
  518.                           KEY_EXECUTE, // Requesting read access.
  519.                           &hKey);      // Address of key to be returned.
  520.   if (retCode)
  521.     {
  522.     LoadString(hInst, IDS_REGOPENERR, lpBuffer, sizeof(lpBuffer));
  523.     wsprintf (Buf, lpBuffer, retCode);
  524.     MessageBox (hDlg, Buf, "DisplayKeyData()", MB_OK);
  525.     return;
  526.     }
  527. // ADD A QUERY AND ALLOCATE A BUFFER FOR BDATA.
  528.   retCode =
  529.   RegQueryInfoKey (hKey,              // Key handle.
  530.                    ClassName,         // Buffer for class name.
  531.                    &dwcClassLen,      // Length of class string.
  532.                    NULL,              // Reserved.
  533.                    &dwcSubKeys,       // Number of sub keys.
  534.                    &dwcMaxSubKey,     // Longest sub key size.
  535.                    &dwcMaxClass,      // Longest class string.
  536.                    &dwcValues,        // Number of values for this key.
  537.                    &dwcMaxValueName,  // Longest Value name.
  538.                    &dwcMaxValueData,  // Longest Value data.
  539.                    &dwcSecDesc,       // Security descriptor.
  540.                    &ftLastWriteTime); // Last write time.
  541.    if (retCode)
  542.     {
  543.     LoadString(hInst, IDS_REGQUERYERR, lpBuffer, sizeof(lpBuffer));
  544.     wsprintf (Buf, lpBuffer, retCode, __LINE__);
  545.     MessageBox (hDlg, Buf, "", MB_OK);
  546.     }
  547.    bData = HeapAlloc (hHeap, 0, dwcMaxValueData);
  548.    cbData = dwcMaxValueData;
  549.   // ENUMERATE THE KEY.
  550.   retCode = RegEnumValue (hKey,        // Key handle returned from RegOpenKeyEx.
  551.                           dwLBIndex,   // Value index, taken from listbox.
  552.                           ValueName,   // Name of value.
  553.                           &cbValueName,// Size of value name.
  554.                           NULL,        // Reserved, dword = NULL.
  555.                           &dwType,     // Type of data.
  556.                           bData,       // Data buffer.
  557.                           &cbData);    // Size of data buffer.
  558.   if (retCode != ERROR_SUCCESS)
  559.     {
  560.     if (dwType < REG_FULL_RESOURCE_DESCRIPTOR)
  561.       {
  562.       LoadString(hInst, IDS_REGENUMERR, lpBuffer, sizeof(lpBuffer));
  563.       wsprintf (Buf, lpBuffer, retCode, cbData, __LINE__);
  564.       MessageBox (hDlg, Buf, "", MB_OK);
  565.       }
  566.     }
  567.   switch (dwType)
  568.     {
  569. //    REG_NONE                    ( 0 )   // No value type
  570. //    REG_SZ                      ( 1 )   // Unicode nul terminated string
  571. //    REG_EXPAND_SZ               ( 2 )   // Unicode nul terminated string
  572.                                             // (with environment variable references)
  573. //    REG_BINARY                  ( 3 )   // Free form binary
  574. //    REG_DWORD                   ( 4 )   // 32-bit number
  575. //    REG_DWORD_LITTLE_ENDIAN     ( 4 )   // 32-bit number (same as REG_DWORD)
  576. //    REG_DWORD_BIG_ENDIAN        ( 5 )   // 32-bit number
  577. //    REG_LINK                    ( 6 )   // Symbolic Link (unicode)
  578. //    REG_MULTI_SZ                ( 7 )   // Multiple Unicode strings
  579. //    REG_RESOURCE_LIST           ( 8 )   // Resource list in the resource map
  580. //    REG_FULL_RESOURCE_DESCRIPTOR ( 9 )  // Resource list in the hardware description
  581.     case REG_NONE:
  582.       LoadString(hInst, IDS_REGNONE, lpBuffer, sizeof(lpBuffer));
  583.       SetDlgItemText (hDlg, IDE_VALUE1, lpBuffer);
  584.       break;
  585.     case REG_SZ:
  586.       LoadString(hInst, IDS_REGSZ, lpBuffer, sizeof(lpBuffer));
  587.       SetDlgItemText (hDlg, IDE_VALUE1, lpBuffer);
  588.       outBuf = HeapAlloc (hHeap, 0, cbData + 2);
  589.       *outBuf = '';
  590.       strcat (outBuf, """);
  591.       strcat (outBuf, bData);
  592.       strcat (outBuf, """);
  593.       SetDlgItemText (hDlg, IDE_VALUE2, outBuf);
  594.       HeapFree (hHeap, 0, outBuf);
  595.       break;
  596.     case REG_EXPAND_SZ:
  597.       LoadString(hInst, IDS_REGEXPSZ, lpBuffer, sizeof(lpBuffer));
  598.       SetDlgItemText (hDlg, IDE_VALUE1, lpBuffer);
  599.       outBuf = HeapAlloc (hHeap, 0, cbData + 2);
  600.       *outBuf = '';
  601.       strcat (outBuf, """);
  602.       strcat (outBuf, bData);
  603.       strcat (outBuf, """);
  604.       SetDlgItemText (hDlg, IDE_VALUE2, outBuf);
  605.       HeapFree (hHeap, 0, outBuf);
  606.       break;
  607.     case REG_BINARY:
  608.       LoadString(hInst, IDS_REGBIN, lpBuffer, sizeof(lpBuffer));
  609.       SetDlgItemText (hDlg, IDE_VALUE1, lpBuffer);
  610.       SetCursor (LoadCursor (NULL, IDC_WAIT));
  611.       BinaryStrBuf = HeapAlloc (hHeap, 0, (3 * cbData) + 1);
  612.       if (BinaryStrBuf)
  613.         {
  614.         *BinaryStrBuf = '';
  615.         *ByteBuf = '';
  616.         for (i = 0; i < cbData; i++)
  617.           {
  618.           sprintf (ByteBuf, "%02x ", (BYTE)bData[i]);
  619.           strcat (BinaryStrBuf, ByteBuf);
  620.           }
  621.         SetDlgItemText (hDlg, IDE_VALUE2, BinaryStrBuf);
  622.         }
  623.       else
  624.         {
  625.         LoadString(hInst, IDS_MALLOCERR, lpBuffer, sizeof(lpBuffer));
  626.         LoadString(hInst, IDS_DBGTITLE, lpBuffer2, sizeof(lpBuffer2));
  627.         MessageBox (hDlg, lpBuffer, lpBuffer2, MB_OK);
  628.         }
  629.       SetDlgItemText (hDlg, IDL_LISTBOX2, BinaryStrBuf);
  630.       HeapFree (hHeap, 0, BinaryStrBuf);
  631.       SetCursor (LoadCursor (NULL, IDC_ARROW));
  632.       break;
  633.     case REG_DWORD:
  634.       LoadString(hInst, IDS_REGDWORD, lpBuffer, sizeof(lpBuffer));
  635.       SetDlgItemText (hDlg, IDE_VALUE1, lpBuffer);
  636.       SetDlgItemInt (hDlg, IDE_VALUE2, *(UINT *)bData, FALSE);
  637.       break;
  638.     case REG_DWORD_BIG_ENDIAN:
  639.       LoadString(hInst, IDS_REGBIGEND, lpBuffer, sizeof(lpBuffer));
  640.       SetDlgItemText (hDlg, IDE_VALUE1, lpBuffer);
  641.       SetDlgItemInt (hDlg, IDE_VALUE2, *(UINT *)bData, TRUE);
  642.       break;
  643.     case REG_LINK:
  644.       LoadString(hInst, IDS_REGLINK, lpBuffer, sizeof(lpBuffer));
  645.       SetDlgItemText (hDlg, IDE_VALUE1, lpBuffer);
  646.       SetDlgItemText (hDlg, IDE_VALUE2, bData);
  647.       break;
  648.     case REG_MULTI_SZ:
  649.       LoadString(hInst, IDS_REGMULTI, lpBuffer, sizeof(lpBuffer));
  650.       SetDlgItemText (hDlg, IDE_VALUE1, lpBuffer);
  651.       SetCursor (LoadCursor (NULL, IDC_WAIT));
  652.                                        // Count the NULLs in the buffer to
  653.                                        // find out how many strings there are.
  654.       for (i=0, cStrLen=4; i < cbData; i++)
  655.         if (!bData[i])
  656.           cStrLen+=4;                  // Add room for two quotes and two
  657.                                        // spaced per string.
  658.       outBuf = HeapAlloc (hHeap, 0, cbData + cStrLen);
  659.       ptr = bData;                     // Set ptr to beginning of buffer.
  660.       *outBuf = '';                  // Initialize output string.
  661.       strcat (outBuf, "{ ");           // Do first bracket.
  662.       while (*ptr)                     // Loop til you hit 2 NULLs in a row.
  663.         {
  664.          strcat (outBuf, """);        // Put quotes around each string.
  665.          strcat (outBuf, ptr);
  666.          strcat (outBuf, ""  ");
  667.          ptr += strlen(ptr)+1;
  668.         }
  669.       strcat (outBuf, "}");            // Add final bracket.
  670.       SetDlgItemText (hDlg, IDE_VALUE2, outBuf);
  671.       SetCursor (LoadCursor (NULL, IDC_ARROW));
  672.       HeapFree (hHeap, 0, outBuf);                 // free output string.
  673.       break;
  674.     case REG_RESOURCE_LIST:            // CM_RESOURCE_LIST is complex.  Print it
  675.                                        // as a free formed binary data for now.
  676.       LoadString(hInst, IDS_REGRESLST, lpBuffer, sizeof(lpBuffer));
  677.       SetDlgItemText (hDlg, IDE_VALUE1, lpBuffer);
  678.       BinaryStrBuf = HeapAlloc (hHeap, 0, (3 * cbData) + 1);
  679.       if (BinaryStrBuf)
  680.         {
  681.         *BinaryStrBuf = '';
  682.         *ByteBuf = '';
  683.         for (i = 0; i < cbData; i++)
  684.           {
  685.           sprintf (ByteBuf, "%02x ", (BYTE)bData[i]);
  686.           strcat (BinaryStrBuf, ByteBuf);
  687.           }
  688.         SetDlgItemText (hDlg, IDE_VALUE2, BinaryStrBuf);
  689.         }
  690.       else
  691.         {
  692.         LoadString(hInst, IDS_MALLOCERR, lpBuffer, sizeof(lpBuffer));
  693.         LoadString(hInst, IDS_DBGTITLE, lpBuffer2, sizeof(lpBuffer2));
  694.         MessageBox (hDlg, lpBuffer, lpBuffer2, MB_OK);
  695.         }
  696.       SetDlgItemText (hDlg, IDL_LISTBOX2, BinaryStrBuf);
  697.       HeapFree (hHeap, 0, BinaryStrBuf);
  698.       break;
  699.     case REG_FULL_RESOURCE_DESCRIPTOR:
  700.       LoadString(hInst, IDS_REGFULLDESC, lpBuffer, sizeof(lpBuffer));
  701.       SetDlgItemText (hDlg, IDE_VALUE1, lpBuffer);
  702.       break;
  703.     default:
  704.       LoadString(hInst, IDS_REGUNDEFINE, lpBuffer, sizeof(lpBuffer));
  705.       wsprintf (Buf, lpBuffer, dwType);
  706.       SetDlgItemText (hDlg, IDE_VALUE1, Buf);
  707.       break;
  708.     } // end switch
  709.     HeapFree (hHeap, 0, bData);
  710.   }