home *** CD-ROM | disk | FTP | other *** search
/ Computer Shopper 242 / Issue 242 - April 2008 - DPCS0408DVD.ISO / Open Source / AutoHotKey / Source / AutoHotkey104705_source.exe / source / script_registry.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2007-06-14  |  17.6 KB  |  435 lines

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // AutoIt
  4. //
  5. // Copyright (C)1999-2007:
  6. //        - Jonathan Bennett <jon@hiddensoft.com>
  7. //        - Others listed at http://www.autoitscript.com/autoit3/docs/credits.htm
  8. //      - Chris Mallett (support@autohotkey.com): adaptation of this file's
  9. //        functions to interface with AutoHotkey.
  10. //
  11. // This program is free software; you can redistribute it and/or modify
  12. // it under the terms of the GNU General Public License as published by
  13. // the Free Software Foundation; either version 2 of the License, or
  14. // (at your option) any later version.
  15. //
  16. ///////////////////////////////////////////////////////////////////////////////
  17. //
  18. // script_registry.cpp
  19. //
  20. // Contains registry handling routines.  Part of script.cpp
  21. //
  22. ///////////////////////////////////////////////////////////////////////////////
  23.  
  24.  
  25. // Includes
  26. #include "stdafx.h" // pre-compiled headers
  27. #include "script.h"
  28. #include "util.h" // for strlcpy()
  29. #include "globaldata.h"
  30.  
  31.  
  32. ResultType Line::IniRead(char *aFilespec, char *aSection, char *aKey, char *aDefault)
  33. {
  34.     if (!aDefault || !*aDefault)
  35.         aDefault = "ERROR";  // This mirrors what AutoIt2 does for its default value.
  36.     char    szFileTemp[_MAX_PATH+1];
  37.     char    *szFilePart;
  38.     char    szBuffer[65535] = "";                    // Max ini file size is 65535 under 95
  39.     // Get the fullpathname (ini functions need a full path):
  40.     GetFullPathName(aFilespec, _MAX_PATH, szFileTemp, &szFilePart);
  41.     GetPrivateProfileString(aSection, aKey, aDefault, szBuffer, sizeof(szBuffer), szFileTemp);
  42.     // The above function is supposed to set szBuffer to be aDefault if it can't find the
  43.     // file, section, or key.  In other words, it always changes the contents of szBuffer.
  44.     return OUTPUT_VAR->Assign(szBuffer); // Avoid using the length the API reported because it might be inaccurate if the data contains any binary zeroes, or if the data is double-terminated, etc.
  45.     // Note: ErrorLevel is not changed by this command since the aDefault value is returned
  46.     // whenever there's an error.
  47. }
  48.  
  49.  
  50.  
  51. ResultType Line::IniWrite(char *aValue, char *aFilespec, char *aSection, char *aKey)
  52. {
  53.     char    szFileTemp[_MAX_PATH+1];
  54.     char    *szFilePart;
  55.     // Get the fullpathname (ini functions need a full path) 
  56.     GetFullPathName(aFilespec, _MAX_PATH, szFileTemp, &szFilePart);
  57.     BOOL result = WritePrivateProfileString(aSection, aKey, aValue, szFileTemp);  // Returns zero on failure.
  58.     WritePrivateProfileString(NULL, NULL, NULL, szFileTemp);    // Flush
  59.     return g_script.mIsAutoIt2 ? OK : g_ErrorLevel->Assign(result ? ERRORLEVEL_NONE : ERRORLEVEL_ERROR);
  60. }
  61.  
  62.  
  63.  
  64. ResultType Line::IniDelete(char *aFilespec, char *aSection, char *aKey)
  65. // Note that aKey can be NULL, in which case the entire section will be deleted.
  66. {
  67.     char    szFileTemp[_MAX_PATH+1];
  68.     char    *szFilePart;
  69.     // Get the fullpathname (ini functions need a full path) 
  70.     GetFullPathName(aFilespec, _MAX_PATH, szFileTemp, &szFilePart);
  71.     BOOL result = WritePrivateProfileString(aSection, aKey, NULL, szFileTemp);  // Returns zero on failure.
  72.     WritePrivateProfileString(NULL, NULL, NULL, szFileTemp);    // Flush
  73.     return g_script.mIsAutoIt2 ? OK : g_ErrorLevel->Assign(result ? ERRORLEVEL_NONE : ERRORLEVEL_ERROR);
  74. }
  75.  
  76.  
  77.  
  78. ResultType Line::RegRead(HKEY aRootKey, char *aRegSubkey, char *aValueName)
  79. {
  80.     Var &output_var = *OUTPUT_VAR;
  81.     g_ErrorLevel->Assign(ERRORLEVEL_ERROR); // Set default ErrorLevel.
  82.     output_var.Assign(); // Init.  Tell it not to free the memory by not calling with "".
  83.  
  84.     HKEY    hRegKey;
  85.     DWORD    dwRes, dwBuf, dwType;
  86.     LONG    result;
  87.     // My: Seems safest to keep the limit just below 64K in case Win95 has problems with larger values.
  88.     char    szRegBuffer[65535]; // Only allow reading of 64Kb from a key
  89.  
  90.     if (!aRootKey)
  91.         return OK;  // Let ErrorLevel tell the story.
  92.  
  93.     // Open the registry key
  94.     if (RegOpenKeyEx(aRootKey, aRegSubkey, 0, KEY_READ, &hRegKey) != ERROR_SUCCESS)
  95.         return OK;  // Let ErrorLevel tell the story.
  96.  
  97.     // Read the value and determine the type.  If aValueName is the empty string, the key's default value is used.
  98.     if (RegQueryValueEx(hRegKey, aValueName, NULL, &dwType, NULL, NULL) != ERROR_SUCCESS)
  99.     {
  100.         RegCloseKey(hRegKey);
  101.         return OK;  // Let ErrorLevel tell the story.
  102.     }
  103.  
  104.     char *contents, *cp;
  105.  
  106.     // The way we read is different depending on the type of the key
  107.     switch (dwType)
  108.     {
  109.         case REG_DWORD:
  110.             dwRes = sizeof(dwBuf);
  111.             RegQueryValueEx(hRegKey, aValueName, NULL, NULL, (LPBYTE)&dwBuf, &dwRes);
  112.             RegCloseKey(hRegKey);
  113.             g_ErrorLevel->Assign(ERRORLEVEL_NONE); // Indicate success.
  114.             return output_var.Assign((DWORD)dwBuf);
  115.  
  116.         // Note: The contents of any of these types can be >64K on NT/2k/XP+ (though that is probably rare):
  117.         case REG_SZ:
  118.         case REG_EXPAND_SZ:
  119.         case REG_MULTI_SZ:
  120.             dwRes = 0; // Retained for backward compatibility because values >64K may cause it to fail on Win95 (unverified, and MSDN implies its value should be ignored for the following call).
  121.             // MSDN: If lpData is NULL, and lpcbData is non-NULL, the function returns ERROR_SUCCESS and stores
  122.             // the size of the data, in bytes, in the variable pointed to by lpcbData.
  123.             if (RegQueryValueEx(hRegKey, aValueName, NULL, NULL, NULL, &dwRes) != ERROR_SUCCESS // Find how large the value is.
  124.                 || !dwRes) // Can't find size (realistically might never happen), or size is zero.
  125.             {
  126.                 RegCloseKey(hRegKey);
  127.                 return g_ErrorLevel->Assign(ERRORLEVEL_NONE); // For backward compatibility, indicate success (these conditions should be very rare anyway).
  128.             }
  129.             // Set up the variable to receive the contents, enlarging it if necessary:
  130.             // Since dwRes includes the space for the zero terminator (if the MSDN docs
  131.             // are accurate), this will enlarge it to be 1 byte larger than we need,
  132.             // which leaves room for the final newline character to be inserted after
  133.             // the last item.  But add 2 to the requested capacity in case the data isn't
  134.             // terminated in the registry, which allows double-NULL to be put in for REG_MULTI_SZ later.
  135.             if (output_var.Assign(NULL, (VarSizeType)(dwRes + 2)) != OK)
  136.             {
  137.                 RegCloseKey(hRegKey);
  138.                 return FAIL; // FAIL is only returned when the error is a critical one such as this one.
  139.             }
  140.  
  141.             contents = output_var.Contents(); // This target buf should now be large enough for the result.
  142.  
  143.             result = RegQueryValueEx(hRegKey, aValueName, NULL, NULL, (LPBYTE)contents, &dwRes);
  144.             RegCloseKey(hRegKey);
  145.  
  146.             if (result != ERROR_SUCCESS || !dwRes) // Relies on short-circuit boolean order.
  147.                 *contents = '\0'; // MSDN says the contents of the buffer is undefined after the call in some cases, so reset it.
  148.                 // Above realistically probably never happens; for backward compatibility (and simplicity),
  149.                 // consider it a success.
  150.             else
  151.             {
  152.                 // See ReadRegString() for more comments about the following:
  153.                 // The MSDN docs state that we should ensure that the buffer is NULL-terminated ourselves:
  154.                 // "If the data has the REG_SZ, REG_MULTI_SZ or REG_EXPAND_SZ type, then lpcbData will also
  155.                 // include the size of the terminating null character or characters ... If the data has the
  156.                 // REG_SZ, REG_MULTI_SZ or REG_EXPAND_SZ type, the string may not have been stored with the
  157.                 // proper null-terminating characters. Applications should ensure that the string is properly
  158.                 // terminated before using it, otherwise, the application may fail by overwriting a buffer."
  159.                 //
  160.                 // Double-terminate so that the loop can find out the true end of the buffer.
  161.                 // The MSDN docs cited above are a little unclear.  The most likely interpretation is that
  162.                 // dwRes contains the true size retrieved.  For example, if dwRes is 1, the first char
  163.                 // in the buffer is either a NULL or an actual non-NULL character that was originally
  164.                 // stored in the registry incorrectly (i.e. without a terminator).  In either case, do
  165.                 // not change the first character, just leave it as is and add a NULL at the 2nd and
  166.                 // 3rd character positions to ensure that it is double terminated in every case:
  167.                 contents[dwRes] = contents[dwRes + 1] = '\0';
  168.  
  169.                 if (dwType == REG_MULTI_SZ) // Convert NULL-delimiters into newline delimiters.
  170.                 {
  171.                     for (cp = contents;; ++cp)
  172.                     {
  173.                         if (!*cp)
  174.                         {
  175.                             // Unlike AutoIt3, it seems best to have a newline character after the
  176.                             // last item in the list also.  It usually makes parsing easier:
  177.                             *cp = '\n';    // Convert to \n for later storage in the user's variable.
  178.                             if (!*(cp + 1)) // Buffer is double terminated, so this is safe.
  179.                                 // Double null terminator marks the end of the used portion of the buffer.
  180.                                 break;
  181.                         }
  182.                     }
  183.                     // else the buffer is empty (see above notes for explanation).  So don't put any newlines
  184.                     // into it at all, since each newline should correspond to an item in the buffer.
  185.                 }
  186.             }
  187.             g_ErrorLevel->Assign(ERRORLEVEL_NONE); // Indicate success.
  188.             output_var.Length() = (VarSizeType)strlen(contents); // Due to conservative buffer sizes above, length is probably too large by 3. So update to reflect the true length.
  189.             return output_var.Close();  // In case it's the clipboard.
  190.  
  191.         case REG_BINARY:
  192.         {
  193.             dwRes = sizeof(szRegBuffer);
  194.             result = RegQueryValueEx(hRegKey, aValueName, NULL, NULL, (LPBYTE)szRegBuffer, &dwRes);
  195.             RegCloseKey(hRegKey);
  196.  
  197.             if (result == ERROR_MORE_DATA)
  198.                 // The API docs state that the buffer's contents are undefined in this case,
  199.                 // so for no we don't support values larger than our buffer size:
  200.                 return OK; // Let ErrorLevel tell the story.  The output variable has already been made blank.
  201.  
  202.             // Set up the variable to receive the contents, enlarging it if necessary.
  203.             // AutoIt3: Each byte will turned into 2 digits, plus a final null:
  204.             if (output_var.Assign(NULL, (VarSizeType)(dwRes * 2)) != OK)
  205.                 return FAIL;
  206.             contents = output_var.Contents();
  207.             *contents = '\0';
  208.  
  209.             int j = 0;
  210.             DWORD i, n; // i and n must be unsigned to work
  211.             char szHexData[] = "0123456789ABCDEF";  // Access to local vars might be faster than static ones.
  212.             for (i = 0; i < dwRes; ++i)
  213.             {
  214.                 n = szRegBuffer[i];                // Get the value and convert to 2 digit hex
  215.                 contents[j + 1] = szHexData[n % 16];
  216.                 n /= 16;
  217.                 contents[j] = szHexData[n % 16];
  218.                 j += 2;
  219.             }
  220.             contents[j] = '\0'; // Terminate
  221.             g_ErrorLevel->Assign(ERRORLEVEL_NONE); // Indicate success.
  222.             return output_var.Close();  // In case it's the clipboard.  Length() was already set by the earlier call to Assign().
  223.         }
  224.     }
  225.  
  226.     // Since above didn't return, this is an unsupported value type.
  227.     return OK;  // Let ErrorLevel tell the story.
  228. } // RegRead()
  229.  
  230.  
  231.  
  232. ResultType Line::RegWrite(DWORD aValueType, HKEY aRootKey, char *aRegSubkey, char *aValueName, char *aValue)
  233. // If aValueName is the empty string, the key's default value is used.
  234. {
  235.     g_ErrorLevel->Assign(ERRORLEVEL_ERROR); // Set default ErrorLevel.
  236.  
  237.     HKEY    hRegKey;
  238.     DWORD    dwRes, dwBuf;
  239.  
  240.     // My: Seems safest to keep the limit just below 64K in case Win95 has problems with larger values.
  241.     char szRegBuffer[65535], *buf; // Only allow writing of 64Kb to a key for Win9x, which is all it supports.
  242.     #define SET_REG_BUF \
  243.         if (g_os.IsWin9x())\
  244.         {\
  245.             strlcpy(szRegBuffer, aValue, sizeof(szRegBuffer));\
  246.             buf = szRegBuffer;\
  247.         }\
  248.         else\
  249.             buf = aValue;
  250.  
  251.     if (!aRootKey || aValueType == REG_NONE || aValueType == REG_SUBKEY) // Can't write to these.
  252.         return OK;  // Let ErrorLevel tell the story.
  253.  
  254.     // Open/Create the registry key
  255.     // The following works even on root keys (i.e. blank subkey), although values can't be created/written to
  256.     // HKCU's root level, perhaps because it's an alias for a subkey inside HKEY_USERS.  Even when RegOpenKeyEx()
  257.     // is used on HKCU (which is probably redundant since it's a pre-opened key?), the API can't create values
  258.     // there even though RegEdit can.
  259.     if (RegCreateKeyEx(aRootKey, aRegSubkey, 0, "", REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hRegKey, &dwRes)
  260.         != ERROR_SUCCESS)
  261.         return OK;  // Let ErrorLevel tell the story.
  262.  
  263.     // Write the registry differently depending on type of variable we are writing
  264.     switch (aValueType)
  265.     {
  266.     case REG_SZ:
  267.         SET_REG_BUF
  268.         if (RegSetValueEx(hRegKey, aValueName, 0, REG_SZ, (CONST BYTE *)buf, (DWORD)strlen(buf)+1) == ERROR_SUCCESS)
  269.             g_ErrorLevel->Assign(ERRORLEVEL_NONE); // Indicate success.
  270.         RegCloseKey(hRegKey);
  271.         return OK;
  272.  
  273.     case REG_EXPAND_SZ:
  274.         SET_REG_BUF
  275.         if (RegSetValueEx(hRegKey, aValueName, 0, REG_EXPAND_SZ, (CONST BYTE *)buf, (DWORD)strlen(buf)+1) == ERROR_SUCCESS)
  276.             g_ErrorLevel->Assign(ERRORLEVEL_NONE); // Indicate success.
  277.         RegCloseKey(hRegKey);
  278.         return OK;
  279.     
  280.     case REG_MULTI_SZ:
  281.     {
  282.         // Don't allow values over 64K for this type because aValue might not be a writable
  283.         // string, and we would need to write to it to temporarily change the newline delimiters
  284.         // into zero-delimiters.  Even if we were to require callers to give us a modifiable string,
  285.         // its capacity be 1 byte too small to handle the double termination that's needed
  286.         // (i.e. if the last item in the list happens to not end in a newline):
  287.         strlcpy(szRegBuffer, aValue, sizeof(szRegBuffer) - 1);  // -1 to leave space for a 2nd terminator.
  288.         // Double-terminate:
  289.         size_t length = strlen(szRegBuffer);
  290.         szRegBuffer[length + 1] = '\0';
  291.  
  292.         // Remove any final newline the user may have provided since we don't want the length
  293.         // to include it when calling RegSetValueEx() -- it would be too large by 1:
  294.         if (length > 0 && szRegBuffer[length - 1] == '\n')
  295.             szRegBuffer[--length] = '\0';
  296.  
  297.         // Replace the script's delimiter char with the zero-delimiter needed by RegSetValueEx():
  298.         for (char *cp = szRegBuffer; *cp; ++cp)
  299.             if (*cp == '\n')
  300.                 *cp = '\0';
  301.  
  302.         if (RegSetValueEx(hRegKey, aValueName, 0, REG_MULTI_SZ, (CONST BYTE *)szRegBuffer
  303.             , (DWORD)(length ? length + 2 : 0)) == ERROR_SUCCESS)
  304.             g_ErrorLevel->Assign(ERRORLEVEL_NONE); // Indicate success.
  305.         RegCloseKey(hRegKey);
  306.         return OK;
  307.     }
  308.  
  309.     case REG_DWORD:
  310.         if (*aValue)
  311.             dwBuf = ATOU(aValue);  // Changed to ATOU() for v1.0.24 so that hex values are supported.
  312.         else // Default to 0 when blank.
  313.             dwBuf = 0;
  314.         if (RegSetValueEx(hRegKey, aValueName, 0, REG_DWORD, (CONST BYTE *)&dwBuf, sizeof(dwBuf) ) == ERROR_SUCCESS)
  315.             g_ErrorLevel->Assign(ERRORLEVEL_NONE); // Indicate success.
  316.         RegCloseKey(hRegKey);
  317.         return OK;
  318.  
  319.     case REG_BINARY:
  320.     {
  321.         int nLen = (int)strlen(aValue);
  322.  
  323.         // Stringlength must be a multiple of 2 
  324.         if (nLen % 2)
  325.         {
  326.             RegCloseKey(hRegKey);
  327.             return OK;  // Let ErrorLevel tell the story.
  328.         }
  329.  
  330.         // Really crappy hex conversion
  331.         int j = 0, i = 0, nVal, nMult;
  332.         while (i < nLen && j < sizeof(szRegBuffer))
  333.         {
  334.             nVal = 0;
  335.             for (nMult = 16; nMult >= 0; nMult = nMult - 15)
  336.             {
  337.                 if (aValue[i] >= '0' && aValue[i] <= '9')
  338.                     nVal += (aValue[i] - '0') * nMult;
  339.                 else if (aValue[i] >= 'A' && aValue[i] <= 'F')
  340.                     nVal += (((aValue[i] - 'A'))+10) * nMult;
  341.                 else if (aValue[i] >= 'a' && aValue[i] <= 'f')
  342.                     nVal += (((aValue[i] - 'a'))+10) * nMult;
  343.                 else
  344.                 {
  345.                     RegCloseKey(hRegKey);
  346.                     return OK;  // Let ErrorLevel tell the story.
  347.                 }
  348.                 ++i;
  349.             }
  350.             szRegBuffer[j++] = (char)nVal;
  351.         }
  352.  
  353.         if (RegSetValueEx(hRegKey, aValueName, 0, REG_BINARY, (CONST BYTE *)szRegBuffer, (DWORD)j) == ERROR_SUCCESS)
  354.             g_ErrorLevel->Assign(ERRORLEVEL_NONE); // Indicate success.
  355.         // else keep the default failure value for ErrorLevel
  356.     
  357.         RegCloseKey(hRegKey);
  358.         return OK;
  359.     }
  360.     } // switch()
  361.  
  362.     // If we reached here then the requested type was unknown/unsupported.
  363.     // Let ErrorLevel tell the story.
  364.     RegCloseKey(hRegKey);
  365.     return OK;
  366. } // RegWrite()
  367.  
  368.  
  369.  
  370. bool Line::RegRemoveSubkeys(HKEY hRegKey)
  371. {
  372.     // Removes all subkeys to the given key.  Will not touch the given key.
  373.     CHAR Name[256];
  374.     DWORD dwNameSize;
  375.     FILETIME ftLastWrite;
  376.     HKEY hSubKey;
  377.     bool Success;
  378.  
  379.     for (;;) 
  380.     { // infinite loop 
  381.         dwNameSize=255;
  382.         if (RegEnumKeyEx(hRegKey, 0, Name, &dwNameSize, NULL, NULL, NULL, &ftLastWrite) == ERROR_NO_MORE_ITEMS)
  383.             break;
  384.         if (RegOpenKeyEx(hRegKey, Name, 0, KEY_READ, &hSubKey) != ERROR_SUCCESS)
  385.             return false;
  386.         
  387.         Success=RegRemoveSubkeys(hSubKey);
  388.         RegCloseKey(hSubKey);
  389.         if (!Success)
  390.             return false;
  391.         else if (RegDeleteKey(hRegKey, Name) != ERROR_SUCCESS)
  392.             return false;
  393.     }
  394.     return true;
  395. }
  396.  
  397.  
  398.  
  399. ResultType Line::RegDelete(HKEY aRootKey, char *aRegSubkey, char *aValueName)
  400. {
  401.     g_ErrorLevel->Assign(ERRORLEVEL_ERROR); // Set default ErrorLevel.
  402.  
  403.     HKEY    hRegKey;
  404.  
  405.     if (!aRootKey)
  406.         return OK;  // Let ErrorLevel tell the story.
  407.  
  408.     // Open the key we want
  409.     if (RegOpenKeyEx(aRootKey, aRegSubkey, 0, KEY_READ | KEY_WRITE, &hRegKey) != ERROR_SUCCESS)
  410.         return OK;  // Let ErrorLevel tell the story.
  411.  
  412.     if (!aValueName || !*aValueName)
  413.     {
  414.         // Remove the entire Key
  415.         bool success = RegRemoveSubkeys(hRegKey); // Delete any subitems within the key.
  416.         RegCloseKey(hRegKey); // Close parent key.  Not sure if this needs to be done only after the above.
  417.         if (!success)
  418.             return OK;  // Let ErrorLevel tell the story.
  419.         if (RegDeleteKey(aRootKey, aRegSubkey) != ERROR_SUCCESS) 
  420.             return OK;  // Let ErrorLevel tell the story.
  421.     }
  422.     else
  423.     {
  424.         // Remove Value.  The special phrase "ahk_default" indicates that the key's default
  425.         // value (displayed as "(Default)" by RegEdit) should be deleted.  This is done to
  426.         // distinguish a blank (which deletes the entire subkey) from the default item.
  427.         LONG lRes = RegDeleteValue(hRegKey, stricmp(aValueName, "ahk_default") ? aValueName : "");
  428.         RegCloseKey(hRegKey);
  429.         if (lRes != ERROR_SUCCESS)
  430.             return OK;  // Let ErrorLevel tell the story.
  431.     }
  432.  
  433.     return g_ErrorLevel->Assign(ERRORLEVEL_NONE); // Indicate success.
  434. } // RegDelete()
  435.