Ticket #250: libbasic_fix_1_of_1_rev_76c9eea92a48_Issue__250__Smalltak_X_is_reading_Windows_Registry_only_in_ASCII_but_registry_is_UTF16.patch

File libbasic_fix_1_of_1_rev_76c9eea92a48_Issue__250__Smalltak_X_is_reading_Windows_Registry_only_in_ASCII_but_registry_is_UTF16.patch, 18.0 KB (added by patrik.svestka@…, 5 years ago)

UTF16 reading from registry re-fix

  • Win32OperatingSystem.st

    # HG changeset patch
    # User Patrik Svestka <patrik.svestka@gmail.com>
    # Date 1544455236 -3600
    #      Mon Dec 10 16:20:36 2018 +0100
    # Branch jv
    # Node ID 76c9eea92a484c356c8b228e10e6ea997052ff77
    # Parent  fdb7878c15fb3c6baa09581bf3e518401748b553
    Issue #250: Smalltak/X is reading Windows Registry only in ASCII but registry is UTF16
    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
    
    diff -r fdb7878c15fb -r 76c9eea92a48 Win32OperatingSystem.st
    a b  
    1607116071    "
    1607216072!
    1607316073
    16074 remoteKeyOnHost:hostName
     16074remoteKeyOnHost:hostNameString
    1607516075    "return the corresponding registry entry from
    1607616076     a remote computers registry.
    1607716077     Note: The registry key must be form a predefined list defined by Microsoft."
    1607816078
    1607916079    |hostNameUtf16Z newEntry remoteHandle errorNumber|
    1608016080
    16081     hostNameUtf16Z := hostName notEmptyOrNil ifTrue:[hostName asUnicode16StringZ].
     16081    hostNameUtf16Z := hostNameString notEmptyOrNil ifTrue:[hostNameString asUnicode16StringZ].
    1608216082   
    1608316083%{
    1608416084    HKEY myKey, remoteKey = 0;
     
    1616316163    |subKeyName errorNumber|
    1616416164
    1616516165%{
     16166   /* dwIndex (subKeyIndex)
     16167    * The index of the subkey to retrieve. This parameter should be zero for the first call to the RegEnumKeyEx function and then
     16168    * incremented for subsequent calls. Because subkeys are not ordered, any new subkey will have an arbitrary index. This means
     16169    * that the function may return subkeys in any order.
     16170    *
     16171    * lpName (nameBuffer):
     16172    * A pointer to a buffer that receives the name of the subkey, including the
     16173    * terminating null character. The function copies only the name of the subkey,
     16174    * not the full key hierarchy, to the buffer. If the function fails, no information is copied to this buffer.
     16175    *
     16176    * lpcchName (nameSize):
     16177    * A pointer to a variable that specifies the size of the buffer specified by the lpName parameter, in characters.
     16178    * This size should include the terminating null character. If the function succeeds, the variable pointed to by lpcName
     16179    * contains the number of characters stored in the buffer, not including the terminating null character.
     16180    * To determine the required buffer size, use the RegQueryInfoKey function to determine the size of the largest subkey for the key
     16181    * identified by the hKey parameter
     16182    *
     16183    * note: This actually means that the if the path fits within 255 chacaters you could get another 255 characters for the key itself.
     16184    *       This could help if you are having issues with the registry path lenght.
     16185    *
     16186    */
     16187
    1616616188    HKEY myKey, subKey = 0;
    16167 
    16168     /* lpName (nameBuffer):
    16169      * A pointer to a buffer that receives the name of the subkey, including the
    16170      * terminating null character. The function copies only the name of the subkey,
    16171      * not the full key hierarchy, to the buffer. If the function fails, no information is copied to this buffer.
    16172      *
    16173      * note: This actually means that the if the path fits within 255 chacaters you could get another 255 characters for the key itself.
    16174      *       This could help if you are having issues with the registry path lenght.
    16175      */
    16176     wchar_t nameBuffer[256];  // 256 is due to Key name limit (including path)
    16177     DWORD nameSize = sizeof(nameBuffer);
     16189    DWORD maxSubKeyLength = 0;
    1617816190 
    1617916191    FILETIME modificationTime;
    1618016192    int _retVal;
     
    1618216194    if (__isExternalAddressLike(__INST(handle))
    1618316195     && __isSmallInteger(subKeyIndex)) {
    1618416196        myKey = (HKEY)__externalAddressVal(__INST(handle));
    16185         if ((_retVal = RegEnumKeyExW(myKey, __intVal(subKeyIndex),
    16186                          nameBuffer, &nameSize,
    16187                          NULL,
    16188                          NULL, NULL, //classNameBuffer, classNameSize
    16189                          &modificationTime)) == ERROR_SUCCESS) {
    16190             nameBuffer[nameSize] = '\0';
    16191             subKeyName = __MKU16STRING(nameBuffer);
     16197    if ((_retVal = RegQueryInfoKey(myKey,
     16198             NULL, NULL,                 // buffer for class name and size of class string
     16199             NULL,                       // reserved
     16200             NULL,                       // number of subkeys
     16201             &maxSubKeyLength,           // longest detected subkey size
     16202             NULL,                       // longest detected class string
     16203             NULL,                       // number of values for this key
     16204             NULL,                       // longest detected value name (in unicode characters (not including NULL character))
     16205             NULL,                       // longest value data (among key's values in bytes)
     16206             NULL,                       // security descriptor
     16207             NULL)) == ERROR_SUCCESS) {  // last write time
     16208        //console_printf("maxSubKeyLength: %d\n", maxSubKeyLength);
     16209        wchar_t nameBuffer[maxSubKeyLength + 1]; // the number array fields + terminating NULL
     16210        // number of characters + terminating NULL - the overall limit registry limit for Value name is 16,383 characters
     16211        DWORD nameSize = maxSubKeyLength + 1;     
     16212        if ((_retVal = RegEnumKeyExW(myKey, __intVal(subKeyIndex),
     16213                         nameBuffer, &nameSize,
     16214                         NULL,
     16215                         NULL, NULL, //classNameBuffer, classNameSize
     16216                         &modificationTime)) == ERROR_SUCCESS) {
     16217            nameBuffer[nameSize] = '\0';
     16218            subKeyName = __MKU16STRING(nameBuffer);
     16219        } else {
     16220            if (_retVal != ERROR_NO_MORE_ITEMS) {
     16221            errorNumber = __MKSMALLINT(_retVal);
     16222            }
     16223        }
    1619216224        } else {
    1619316225            if ((_retVal != ERROR_PATH_NOT_FOUND)
    16194              && (_retVal != ERROR_FILE_NOT_FOUND)
    16195              && (_retVal != ERROR_NO_MORE_ITEMS)) {
     16226             && (_retVal != ERROR_FILE_NOT_FOUND)) {
    1619616227                errorNumber = __MKSMALLINT(_retVal);
    1619716228            }
    1619816229        }
     
    1622216253    |subKeyName subKeyClassName errorNumber|
    1622316254
    1622416255%{
     16256   /* dwIndex (subKeyIndex)
     16257    * The index of the subkey to retrieve. This parameter should be zero for the first call to the RegEnumKeyEx function and then
     16258    * incremented for subsequent calls. Because subkeys are not ordered, any new subkey will have an arbitrary index. This means
     16259    * that the function may return subkeys in any order.
     16260    *
     16261    * lpName (nameBuffer):
     16262    * A pointer to a buffer that receives the name of the subkey, including the
     16263    * terminating null character. The function copies only the name of the subkey,
     16264    * not the full key hierarchy, to the buffer. If the function fails, no information is copied to this buffer.
     16265    *
     16266    * lpcchName (nameSize):
     16267    * A pointer to a variable that specifies the size of the buffer specified by the lpName parameter, in characters.
     16268    * This size should include the terminating null character. If the function succeeds, the variable pointed to by lpcName
     16269    * contains the number of characters stored in the buffer, not including the terminating null character.
     16270    * To determine the required buffer size, use the RegQueryInfoKey function to determine the size of the largest subkey for the key
     16271    * identified by the hKey parameter
     16272    *
     16273    * lpClass (classNameBuffer):
     16274    * A pointer to a buffer that receives the user-defined class of the enumerated subkey.
     16275    *
     16276    * lpcchClass (classNameSize):
     16277    * A pointer to a variable that specifies the size of the buffer specified by the lpClass parameter, in characters.
     16278    * The size should include the terminating null character. If the function succeeds, lpcClass contains the number of
     16279    * characters stored in the buffer, not including the terminating null character. This parameter can be NULL only if lpClass is NULL.
     16280    *
     16281    * note: This actually means that the if the path fits within 255 chacaters you could get another 255 characters for the key itself.
     16282    *       This could help if you are having issues with the registry path lenght.
     16283    *
     16284    */
     16285
    1622516286    HKEY myKey, subKey = 0;
    16226 
    16227 /* lpName (nameBuffer):
    16228  * A pointer to a buffer that receives the name of the subkey, including the
    16229  * terminating null character. The function copies only the name of the subkey,
    16230  * not the full key hierarchy, to the buffer. If the function fails, no information is copied to this buffer.
    16231  *
    16232  * note: This actually means that the if the path fits within 255 chacaters you could get another 255 characters for the key itself.
    16233  *       This could help if you are having issues with the registry path lenght.
    16234  */
    16235     wchar_t nameBuffer[256];  // limiting the nameBuffer to 255 characters + null terminator
    16236     DWORD nameSize = sizeof(nameBuffer);
    16237 
    16238  /* lpClass (classNameBuffer):
    16239   * A pointer to a buffer that receives the user-defined class of the enumerated subkey.
    16240   */
    16241     wchar_t classNameBuffer[256]; // limiting the classNameBuffer to 255 characters + nul terminator
    16242     DWORD classNameSize = sizeof(classNameBuffer);
     16287    DWORD maxSubKeyLength, maxClassNameLength = 0;
    1624316288
    1624416289    FILETIME modificationTime;
    1624516290    int _retVal;
     
    1624716292    if (__isExternalAddressLike(__INST(handle))
    1624816293     && __isSmallInteger(subKeyIndex)) {
    1624916294        myKey = (HKEY)__externalAddressVal(__INST(handle));
    16250         if ((_retVal = RegEnumKeyExW(myKey, __intVal(subKeyIndex),
    16251                          nameBuffer, &nameSize,
    16252                          NULL,
    16253                          classNameBuffer, &classNameSize,
    16254                          &modificationTime)) == ERROR_SUCCESS) {
    16255             nameBuffer[nameSize] = '\0';
    16256             classNameBuffer[classNameSize] = '\0';       
    16257         subKeyName = __MKU16STRING(nameBuffer);
    16258         subKeyClassName = __MKU16STRING(classNameBuffer);
     16295    if ((_retVal = RegQueryInfoKey(myKey,
     16296             NULL, NULL,                 // buffer for class name and size of class string
     16297             NULL,                       // reserved
     16298             NULL,                       // number of subkeys
     16299             &maxSubKeyLength,           // longest detected subkey size
     16300             &maxClassNameLength,        // longest detected class string
     16301             NULL,                       // number of values for this key
     16302             NULL,                       // longest detected value name (in unicode characters (not including NULL character))
     16303             NULL,                       // longest value data (among key's values in bytes)
     16304             NULL,                       // security descriptor
     16305             NULL)) == ERROR_SUCCESS) {  // last write time
     16306        //console_printf("maxSubKeyLength: %d and maxClassNameLength: %d\n", maxSubKeyLength, maxClassNameLength);
     16307        wchar_t nameBuffer[maxSubKeyLength + 1]; // the number array fields + terminating NULL
     16308        // number of characters + terminating NULL - the overall limit registry limit for Value name is 16,383 characters
     16309        DWORD nameSize = maxSubKeyLength + 1;
     16310        wchar_t classNameBuffer[maxClassNameLength + 1]; // the number array fields + terminating NULL
     16311        // number of characters + terminating NULL - the overall limit registry limit for Value name is 16,383 characters
     16312        DWORD classNameSize = maxClassNameLength + 1;
     16313        if ((_retVal = RegEnumKeyExW(myKey, __intVal(subKeyIndex),
     16314                         nameBuffer, &nameSize,
     16315                         NULL,
     16316                         classNameBuffer, &classNameSize,
     16317                         &modificationTime)) == ERROR_SUCCESS) {
     16318            nameBuffer[nameSize] = '\0';
     16319            classNameBuffer[classNameSize] = '\0';       
     16320            subKeyName = __MKU16STRING(nameBuffer);
     16321            subKeyClassName = __MKU16STRING(classNameBuffer);
     16322        } else {
     16323            if (_retVal != ERROR_NO_MORE_ITEMS) {
     16324            errorNumber = __MKSMALLINT(_retVal);
     16325            }
     16326        }
    1625916327        } else {
    1626016328            if ((_retVal != ERROR_PATH_NOT_FOUND)
    16261              && (_retVal != ERROR_FILE_NOT_FOUND)
    16262              && (_retVal != ERROR_NO_MORE_ITEMS)) {
     16329             && (_retVal != ERROR_FILE_NOT_FOUND)) {
    1626316330                errorNumber = __MKSMALLINT(_retVal);
    1626416331            }
    1626516332        }
     
    1648616553    |valueName errorNumber|
    1648716554
    1648816555%{
     16556   /* dwIndex (valueIndex)
     16557    * The index of the value to be retrieved. This parameter should be zero for the first call to the RegEnumValue function and then be
     16558    * incremented for subsequent calls. Because values are not ordered, any new value will have an arbitrary index. This means that the
     16559    * function may return values in any order.
     16560    *
     16561    * lpValueName (nameBuffer):
     16562    * A pointer to a buffer that receives the name of the value as a null-terminated string.
     16563    * This buffer must be large enough to include the terminating null character.
     16564    *
     16565    * lpcchValueName (nameSize):
     16566    * A pointer to a variable that specifies the size of the buffer pointed to by the lpValueName parameter, in characters.
     16567    * When the function returns, the variable receives the number of characters stored in the buffer, not including the terminating null character.
     16568    * Registry value names are limited to 32,767 bytes. The ANSI version of this function treats this parameter as a SHORT value.
     16569    * Therefore, if you specify a value greater than 32,767 bytes, there is an overflow and the function may return ERROR_MORE_DATA.
     16570    *
     16571    * For more information, see Registry Element Size Limits.
     16572    */
     16573
    1648916574    HKEY myKey;
    16490 
    16491 /* nameBuffer (lpValueName in RegEnumValue function):
    16492  * A pointer to a buffer that receives the name of the value as a null-terminated string.
    16493  * This buffer must be large enough to include the terminating null character.
    16494  * For more information, see Registry Element Size Limits.
    16495  */
    16496   wchar_t nameBuffer[256]; // 256 is due to Key name limit (including path) + the null character
    16497 
    16498 /* nameSize (lpcchValueName in RegEnumValue function):
    16499  *
    16500  * A pointer to a variable that specifies the size of the buffer pointed to by the lpValueName parameter, in characters.
    16501  * When the function returns, the variable receives the number of characters stored in the buffer, not including the terminating null character.
    16502  *
    16503  * Registry value names are limited to 32,767 bytes. The ANSI version of this function treats this parameter as a SHORT value.
    16504  * Therefore, if you specify a value greater than 32,767 bytes, there is an overflow and the function may return ERROR_MORE_DATA.
    16505  */
    16506     DWORD nameSize = sizeof(nameBuffer);
     16575    DWORD maxValueNameLength = 0;
    1650716576    DWORD valueType;
    1650816577    int _retVal;
    1650916578
    1651016579    if (__isExternalAddressLike(__INST(handle))
    1651116580     && __isSmallInteger(valueIndex)) {
    1651216581        myKey = (HKEY)__externalAddressVal(__INST(handle));
    16513         if ((_retVal = RegEnumValueW(myKey, __intVal(valueIndex),
    16514                          nameBuffer, &nameSize,
    16515                          NULL,
    16516                          &valueType,
    16517                          NULL, NULL)) == ERROR_SUCCESS) {
    16518             nameBuffer[nameSize] = '\0';
    16519         valueName = __MKU16STRING(nameBuffer);
    16520         } else {
    16521             if ((_retVal != ERROR_PATH_NOT_FOUND)
    16522              && (_retVal != ERROR_FILE_NOT_FOUND)
    16523              && (_retVal != ERROR_NO_MORE_ITEMS)) {
    16524                 errorNumber = __MKSMALLINT(_retVal);
    16525             }
    16526         }
     16582    if ((_retVal = RegQueryInfoKey(myKey,
     16583             NULL, NULL,                 // buffer for class name and size of class string
     16584             NULL,                       // reserved
     16585             NULL,                       // number of subkeys
     16586             NULL, NULL,                 // longest subkey size and longest class string
     16587             NULL,                       // number of values for this key
     16588             &maxValueNameLength,        // longest detected value name (in unicode characters (not including NULL character))
     16589             NULL,                       // longest value data (among key's values in bytes)
     16590             NULL,                       // security descriptor
     16591             NULL)) == ERROR_SUCCESS) {  // last write time
     16592        //console_printf("maxValueNameLength: %d\n", maxValueNameLength);
     16593        wchar_t nameBuffer[maxValueNameLength + 1]; // the number array fields + terminating NULL
     16594        // number of characters + terminating NULL - the overall limit registry limit for Value name is 16,383 characters
     16595        DWORD nameSize = maxValueNameLength + 1;
     16596        if ((_retVal = RegEnumValueW(myKey, __intVal(valueIndex),
     16597                         nameBuffer, &nameSize,
     16598                         NULL,
     16599                         &valueType,
     16600                         NULL, NULL)) == ERROR_SUCCESS) {
     16601            nameBuffer[nameSize] = '\0';
     16602            valueName = __MKU16STRING(nameBuffer);
     16603        } else {
     16604            if (_retVal != ERROR_NO_MORE_ITEMS) {
     16605            errorNumber = __MKSMALLINT(_retVal);
     16606            }
     16607        }
     16608    } else {
     16609        if ((_retVal != ERROR_PATH_NOT_FOUND)
     16610         && (_retVal != ERROR_FILE_NOT_FOUND)) {
     16611        errorNumber = __MKSMALLINT(_retVal);
     16612        }
     16613    }
    1652716614    }
    1652816615%}.
    1652916616    errorNumber notNil ifTrue:[
     
    1653916626    "
    1654016627!
    1654116628
    16542 valueNamed:name
     16629valueNamed:nameString
    1654316630    "retrieve a value; the returned object depends upon the type:
    1654416631        REG_BINARY      -> ByteArray
    1654516632        REG_SZ          -> String
     
    1655016637
    1655116638    |nameUtf16Z stringArray retVal errorNumber|
    1655216639
    16553     "/ name must be a string
    1655416640    "/ adding terminating null into empty string
    16555     name notNil ifTrue:[
    16556         name isEmpty ifTrue:[nameUtf16Z := (name, (Character codePoint: 0)) asUnicode16String] "/ needed for defaultValue
    16557                     ifFalse:[nameUtf16Z := name asUnicode16StringZ]
     16641    nameString notNil ifTrue:[
     16642        nameString isEmpty ifTrue:[nameUtf16Z := (nameString, (Character codePoint: 0)) asUnicode16String] "/ needed for defaultValue
     16643                    ifFalse:[nameUtf16Z := nameString asUnicode16StringZ]
    1655816644    ].
    1655916645
    1656016646%{  /* STACK: 20000 */
     
    1656916655    } quickData;
    1657016656
    1657116657    wchar_t *dataBuffer = NULL;
    16572     DWORD dataSize = sizeof(quickData);
     16658    // A pointer to a variable that specifies the size of the buffer pointed to by the lpData parameter, in bytes
     16659    DWORD dataSize = sizeof(quickData);
    1657316660
    1657416661    if (__isExternalAddressLike(__INST(handle))
    1657516662     && __isUnicode16String(nameUtf16Z)) {
     
    1718517272%}.
    1718617273
    1718717274    "Created: / 19.5.1999 / 21:45:05 / cg"
     17275
    1718817276! !
    1718917277
    1719017278!Win32OperatingSystem::TextMetricsStructure class methodsFor:'instance creation'!