Issue #250: methods that need predefined nameBuffer now detect it automatically via RegQueryInfoKey jv
authorPatrik Svestka <patrik.svestka@gmail.com>
Mon, 10 Dec 2018 16:20:36 +0100
branchjv
changeset 23612 36a5be9c6aa5
parent 23611 bf5d0e51cd26
child 23613 27c3cc6f5371
Issue #250: methods that need predefined nameBuffer now detect it automatically via RegQueryInfoKey All methods that needed a predefined nameBuffer, nameSize size now detect it automatically via RegQueryInfoKey by checking the stored name sizes first and then setting the buffer sizes appropriately The affected methods are: - valueNameAtIndex: - subKeyNameAndClassAtIndex: - subKeyAtIndex: minor refactoring - remoteKeyOnHost: - changed hostName to hostNameString to indicate that the parameter must be a string - valueNamed: - - changed name to nameString to indicate that the parameter must be a string
Win32OperatingSystem.st
--- a/Win32OperatingSystem.st	Fri Dec 07 09:42:38 2018 +0100
+++ b/Win32OperatingSystem.st	Mon Dec 10 16:20:36 2018 +0100
@@ -16071,14 +16071,14 @@
     "
 !
 
-remoteKeyOnHost:hostName
+remoteKeyOnHost:hostNameString
     "return the corresponding registry entry from
      a remote computers registry.
      Note: The registry key must be form a predefined list defined by Microsoft."
 
     |hostNameUtf16Z newEntry remoteHandle errorNumber|
 
-    hostNameUtf16Z := hostName notEmptyOrNil ifTrue:[hostName asUnicode16StringZ].
+    hostNameUtf16Z := hostNameString notEmptyOrNil ifTrue:[hostNameString asUnicode16StringZ].
     
 %{
     HKEY myKey, remoteKey = 0;
@@ -16163,18 +16163,30 @@
     |subKeyName errorNumber|
 
 %{
+   /* dwIndex (subKeyIndex)
+    * The index of the subkey to retrieve. This parameter should be zero for the first call to the RegEnumKeyEx function and then 
+    * incremented for subsequent calls. Because subkeys are not ordered, any new subkey will have an arbitrary index. This means
+    * that the function may return subkeys in any order.
+    *
+    * lpName (nameBuffer):
+    * A pointer to a buffer that receives the name of the subkey, including the 
+    * terminating null character. The function copies only the name of the subkey, 
+    * not the full key hierarchy, to the buffer. If the function fails, no information is copied to this buffer.
+    * 
+    * lpcchName (nameSize):
+    * A pointer to a variable that specifies the size of the buffer specified by the lpName parameter, in characters. 
+    * This size should include the terminating null character. If the function succeeds, the variable pointed to by lpcName
+    * contains the number of characters stored in the buffer, not including the terminating null character.
+    * To determine the required buffer size, use the RegQueryInfoKey function to determine the size of the largest subkey for the key 
+    * identified by the hKey parameter
+    *
+    * note: This actually means that the if the path fits within 255 chacaters you could get another 255 characters for the key itself.
+    *       This could help if you are having issues with the registry path lenght.
+    * 
+    */
+
     HKEY myKey, subKey = 0;
-
-    /* lpName (nameBuffer):
-     * A pointer to a buffer that receives the name of the subkey, including the 
-     * terminating null character. The function copies only the name of the subkey, 
-     * not the full key hierarchy, to the buffer. If the function fails, no information is copied to this buffer.
-     * 
-     * note: This actually means that the if the path fits within 255 chacaters you could get another 255 characters for the key itself.
-     *       This could help if you are having issues with the registry path lenght.
-     */
-    wchar_t nameBuffer[256];  // 256 is due to Key name limit (including path)
-    DWORD nameSize = sizeof(nameBuffer);
+    DWORD maxSubKeyLength = 0;
  
     FILETIME modificationTime;
     int _retVal;
@@ -16182,17 +16194,36 @@
     if (__isExternalAddressLike(__INST(handle))
      && __isSmallInteger(subKeyIndex)) {
 	myKey = (HKEY)__externalAddressVal(__INST(handle));
-	if ((_retVal = RegEnumKeyExW(myKey, __intVal(subKeyIndex),
-			 nameBuffer, &nameSize,
-			 NULL,
-			 NULL, NULL, //classNameBuffer, classNameSize
-			 &modificationTime)) == ERROR_SUCCESS) {
-	    nameBuffer[nameSize] = '\0';
-	    subKeyName = __MKU16STRING(nameBuffer);
+    if ((_retVal = RegQueryInfoKey(myKey,
+             NULL, NULL,                 // buffer for class name and size of class string
+             NULL,                       // reserved 
+             NULL,                       // number of subkeys
+             &maxSubKeyLength,           // longest detected subkey size
+             NULL,                       // longest detected class string
+             NULL,                       // number of values for this key
+             NULL,                       // longest detected value name (in unicode characters (not including NULL character))
+             NULL,                       // longest value data (among key's values in bytes)
+             NULL,                       // security descriptor
+             NULL)) == ERROR_SUCCESS) {  // last write time
+        //console_printf("maxSubKeyLength: %d\n", maxSubKeyLength);
+        wchar_t nameBuffer[maxSubKeyLength + 1]; // the number array fields + terminating NULL
+        // number of characters + terminating NULL - the overall limit registry limit for Value name is 16,383 characters
+        DWORD nameSize = maxSubKeyLength + 1;      
+    	if ((_retVal = RegEnumKeyExW(myKey, __intVal(subKeyIndex),
+    			 nameBuffer, &nameSize,
+    			 NULL,
+    			 NULL, NULL, //classNameBuffer, classNameSize
+    			 &modificationTime)) == ERROR_SUCCESS) {
+    	    nameBuffer[nameSize] = '\0';
+    	    subKeyName = __MKU16STRING(nameBuffer);
+        } else {
+            if (_retVal != ERROR_NO_MORE_ITEMS) {
+            errorNumber = __MKSMALLINT(_retVal);
+            }
+        }
 	} else {
 	    if ((_retVal != ERROR_PATH_NOT_FOUND)
-	     && (_retVal != ERROR_FILE_NOT_FOUND)
-	     && (_retVal != ERROR_NO_MORE_ITEMS)) {
+	     && (_retVal != ERROR_FILE_NOT_FOUND)) {
 		errorNumber = __MKSMALLINT(_retVal);
 	    }
 	}
@@ -16222,24 +16253,38 @@
     |subKeyName subKeyClassName errorNumber|
 
 %{
+   /* dwIndex (subKeyIndex)
+    * The index of the subkey to retrieve. This parameter should be zero for the first call to the RegEnumKeyEx function and then 
+    * incremented for subsequent calls. Because subkeys are not ordered, any new subkey will have an arbitrary index. This means
+    * that the function may return subkeys in any order.
+    *
+    * lpName (nameBuffer):
+    * A pointer to a buffer that receives the name of the subkey, including the 
+    * terminating null character. The function copies only the name of the subkey, 
+    * not the full key hierarchy, to the buffer. If the function fails, no information is copied to this buffer.
+    * 
+    * lpcchName (nameSize):
+    * A pointer to a variable that specifies the size of the buffer specified by the lpName parameter, in characters. 
+    * This size should include the terminating null character. If the function succeeds, the variable pointed to by lpcName
+    * contains the number of characters stored in the buffer, not including the terminating null character.
+    * To determine the required buffer size, use the RegQueryInfoKey function to determine the size of the largest subkey for the key 
+    * identified by the hKey parameter
+    * 
+    * lpClass (classNameBuffer):
+    * A pointer to a buffer that receives the user-defined class of the enumerated subkey. 
+    *
+    * lpcchClass (classNameSize):
+    * A pointer to a variable that specifies the size of the buffer specified by the lpClass parameter, in characters. 
+    * The size should include the terminating null character. If the function succeeds, lpcClass contains the number of 
+    * characters stored in the buffer, not including the terminating null character. This parameter can be NULL only if lpClass is NULL.
+    *
+    * note: This actually means that the if the path fits within 255 chacaters you could get another 255 characters for the key itself.
+    *       This could help if you are having issues with the registry path lenght.
+    * 
+    */
+
     HKEY myKey, subKey = 0;
-
-/* lpName (nameBuffer):
- * A pointer to a buffer that receives the name of the subkey, including the 
- * terminating null character. The function copies only the name of the subkey, 
- * not the full key hierarchy, to the buffer. If the function fails, no information is copied to this buffer.
- * 
- * note: This actually means that the if the path fits within 255 chacaters you could get another 255 characters for the key itself.
- *       This could help if you are having issues with the registry path lenght.
- */
-    wchar_t nameBuffer[256];  // limiting the nameBuffer to 255 characters + null terminator
-    DWORD nameSize = sizeof(nameBuffer);
-
- /* lpClass (classNameBuffer):
-  * A pointer to a buffer that receives the user-defined class of the enumerated subkey. 
-  */
-    wchar_t classNameBuffer[256]; // limiting the classNameBuffer to 255 characters + nul terminator
-    DWORD classNameSize = sizeof(classNameBuffer);
+    DWORD maxSubKeyLength, maxClassNameLength = 0;
 
     FILETIME modificationTime;
     int _retVal;
@@ -16247,19 +16292,41 @@
     if (__isExternalAddressLike(__INST(handle))
      && __isSmallInteger(subKeyIndex)) {
 	myKey = (HKEY)__externalAddressVal(__INST(handle));
-	if ((_retVal = RegEnumKeyExW(myKey, __intVal(subKeyIndex),
-			 nameBuffer, &nameSize,
-			 NULL,
-			 classNameBuffer, &classNameSize,
-			 &modificationTime)) == ERROR_SUCCESS) {
-	    nameBuffer[nameSize] = '\0';
-	    classNameBuffer[classNameSize] = '\0';        
-        subKeyName = __MKU16STRING(nameBuffer);
-        subKeyClassName = __MKU16STRING(classNameBuffer);
+    if ((_retVal = RegQueryInfoKey(myKey,
+             NULL, NULL,                 // buffer for class name and size of class string
+             NULL,                       // reserved 
+             NULL,                       // number of subkeys
+             &maxSubKeyLength,           // longest detected subkey size
+             &maxClassNameLength,        // longest detected class string
+             NULL,                       // number of values for this key
+             NULL,                       // longest detected value name (in unicode characters (not including NULL character))
+             NULL,                       // longest value data (among key's values in bytes)
+             NULL,                       // security descriptor
+             NULL)) == ERROR_SUCCESS) {  // last write time
+        //console_printf("maxSubKeyLength: %d and maxClassNameLength: %d\n", maxSubKeyLength, maxClassNameLength);
+        wchar_t nameBuffer[maxSubKeyLength + 1]; // the number array fields + terminating NULL
+        // number of characters + terminating NULL - the overall limit registry limit for Value name is 16,383 characters
+        DWORD nameSize = maxSubKeyLength + 1;
+        wchar_t classNameBuffer[maxClassNameLength + 1]; // the number array fields + terminating NULL
+        // number of characters + terminating NULL - the overall limit registry limit for Value name is 16,383 characters
+        DWORD classNameSize = maxClassNameLength + 1;
+    	if ((_retVal = RegEnumKeyExW(myKey, __intVal(subKeyIndex),
+    			 nameBuffer, &nameSize,
+    			 NULL,
+    			 classNameBuffer, &classNameSize,
+    			 &modificationTime)) == ERROR_SUCCESS) {
+    	    nameBuffer[nameSize] = '\0';
+    	    classNameBuffer[classNameSize] = '\0';        
+            subKeyName = __MKU16STRING(nameBuffer);
+            subKeyClassName = __MKU16STRING(classNameBuffer);
+        } else {
+            if (_retVal != ERROR_NO_MORE_ITEMS) {
+            errorNumber = __MKSMALLINT(_retVal);
+            }
+        }
 	} else {
 	    if ((_retVal != ERROR_PATH_NOT_FOUND)
-	     && (_retVal != ERROR_FILE_NOT_FOUND)
-	     && (_retVal != ERROR_NO_MORE_ITEMS)) {
+	     && (_retVal != ERROR_FILE_NOT_FOUND)) {
 		errorNumber = __MKSMALLINT(_retVal);
 	    }
 	}
@@ -16486,44 +16553,64 @@
     |valueName errorNumber|
 
 %{
+   /* dwIndex (valueIndex)
+    * The index of the value to be retrieved. This parameter should be zero for the first call to the RegEnumValue function and then be 
+    * incremented for subsequent calls. Because values are not ordered, any new value will have an arbitrary index. This means that the 
+    * function may return values in any order.
+    *
+    * lpValueName (nameBuffer):
+    * A pointer to a buffer that receives the name of the value as a null-terminated string.
+    * This buffer must be large enough to include the terminating null character.
+    * 
+    * lpcchValueName (nameSize):
+    * A pointer to a variable that specifies the size of the buffer pointed to by the lpValueName parameter, in characters. 
+    * When the function returns, the variable receives the number of characters stored in the buffer, not including the terminating null character.
+    * Registry value names are limited to 32,767 bytes. The ANSI version of this function treats this parameter as a SHORT value. 
+    * Therefore, if you specify a value greater than 32,767 bytes, there is an overflow and the function may return ERROR_MORE_DATA.
+    *
+    * For more information, see Registry Element Size Limits.
+    */
+
     HKEY myKey;
-
-/* nameBuffer (lpValueName in RegEnumValue function):
- * A pointer to a buffer that receives the name of the value as a null-terminated string.
- * This buffer must be large enough to include the terminating null character.
- * For more information, see Registry Element Size Limits.
- */
-  wchar_t nameBuffer[256]; // 256 is due to Key name limit (including path) + the null character
-
-/* nameSize (lpcchValueName in RegEnumValue function):
- *
- * A pointer to a variable that specifies the size of the buffer pointed to by the lpValueName parameter, in characters. 
- * When the function returns, the variable receives the number of characters stored in the buffer, not including the terminating null character.
- *
- * Registry value names are limited to 32,767 bytes. The ANSI version of this function treats this parameter as a SHORT value. 
- * Therefore, if you specify a value greater than 32,767 bytes, there is an overflow and the function may return ERROR_MORE_DATA.
- */
-    DWORD nameSize = sizeof(nameBuffer);
+    DWORD maxValueNameLength = 0;
     DWORD valueType;
     int _retVal;
 
     if (__isExternalAddressLike(__INST(handle))
      && __isSmallInteger(valueIndex)) {
 	myKey = (HKEY)__externalAddressVal(__INST(handle));
-	if ((_retVal = RegEnumValueW(myKey, __intVal(valueIndex),
-			 nameBuffer, &nameSize,
-			 NULL,
-			 &valueType,
-			 NULL, NULL)) == ERROR_SUCCESS) {
-	    nameBuffer[nameSize] = '\0';
-        valueName = __MKU16STRING(nameBuffer);
-	} else {
-	    if ((_retVal != ERROR_PATH_NOT_FOUND)
-	     && (_retVal != ERROR_FILE_NOT_FOUND)
-	     && (_retVal != ERROR_NO_MORE_ITEMS)) {
-		errorNumber = __MKSMALLINT(_retVal);
-	    }
-	}
+    if ((_retVal = RegQueryInfoKey(myKey,
+             NULL, NULL,                 // buffer for class name and size of class string
+             NULL,                       // reserved 
+             NULL,                       // number of subkeys
+             NULL, NULL,                 // longest subkey size and longest class string
+             NULL,                       // number of values for this key
+             &maxValueNameLength,        // longest detected value name (in unicode characters (not including NULL character))
+             NULL,                       // longest value data (among key's values in bytes)
+             NULL,                       // security descriptor
+             NULL)) == ERROR_SUCCESS) {  // last write time
+        //console_printf("maxValueNameLength: %d\n", maxValueNameLength);
+        wchar_t nameBuffer[maxValueNameLength + 1]; // the number array fields + terminating NULL
+        // number of characters + terminating NULL - the overall limit registry limit for Value name is 16,383 characters
+        DWORD nameSize = maxValueNameLength + 1;
+        if ((_retVal = RegEnumValueW(myKey, __intVal(valueIndex),
+    			 nameBuffer, &nameSize,
+    			 NULL,
+    			 &valueType,
+    			 NULL, NULL)) == ERROR_SUCCESS) {
+    	    nameBuffer[nameSize] = '\0';
+            valueName = __MKU16STRING(nameBuffer);
+        } else {
+            if (_retVal != ERROR_NO_MORE_ITEMS) {
+            errorNumber = __MKSMALLINT(_retVal);
+            }
+        }
+    } else {
+        if ((_retVal != ERROR_PATH_NOT_FOUND)
+         && (_retVal != ERROR_FILE_NOT_FOUND)) {
+        errorNumber = __MKSMALLINT(_retVal);
+        }
+    }
     }
 %}.
     errorNumber notNil ifTrue:[
@@ -16539,7 +16626,7 @@
     "
 !
 
-valueNamed:name
+valueNamed:nameString
     "retrieve a value; the returned object depends upon the type:
 	REG_BINARY      -> ByteArray
 	REG_SZ          -> String
@@ -16550,11 +16637,10 @@
 
     |nameUtf16Z stringArray retVal errorNumber|
 
-    "/ name must be a string
     "/ adding terminating null into empty string
-    name notNil ifTrue:[
-        name isEmpty ifTrue:[nameUtf16Z := (name, (Character codePoint: 0)) asUnicode16String] "/ needed for defaultValue
-                    ifFalse:[nameUtf16Z := name asUnicode16StringZ]
+    nameString notNil ifTrue:[
+        nameString isEmpty ifTrue:[nameUtf16Z := (nameString, (Character codePoint: 0)) asUnicode16String] "/ needed for defaultValue
+                    ifFalse:[nameUtf16Z := nameString asUnicode16StringZ]
     ].
 
 %{  /* STACK: 20000 */
@@ -16569,7 +16655,8 @@
     } quickData;
 
     wchar_t *dataBuffer = NULL;
-    DWORD dataSize = sizeof(quickData);
+    // A pointer to a variable that specifies the size of the buffer pointed to by the lpData parameter, in bytes
+    DWORD dataSize = sizeof(quickData); 
 
     if (__isExternalAddressLike(__INST(handle))
      && __isUnicode16String(nameUtf16Z)) {
@@ -17185,6 +17272,7 @@
 %}.
 
     "Created: / 19.5.1999 / 21:45:05 / cg"
+
 ! !
 
 !Win32OperatingSystem::TextMetricsStructure class methodsFor:'instance creation'!