Ticket #250: libbasic_fix_1_of_2_rev_4debcdcaf264_Issue__250__Smalltak_X_is_reading_Windows_Registry_only_in_ASCII_but_registry_is_UTF16.patch
File libbasic_fix_1_of_2_rev_4debcdcaf264_Issue__250__Smalltak_X_is_reading_Windows_Registry_only_in_ASCII_but_registry_is_UTF16.patch, 21.6 KB (added by , 5 years ago) |
---|
-
Win32OperatingSystem.st
# HG changeset patch # User Patrik Svestka <patrik.svestka@gmail.com> # Date 1544011404 -3600 # Wed Dec 05 13:03:24 2018 +0100 # Branch jv # Node ID 4debcdcaf26435461bea223bcd3431307dbeae0b # Parent 20f35741c92ddc9da0dda0e43d8b34c2072a1285 Issue #250: Smalltak/X is reading Windows Registry only in ASCII but registry is UTF16 All methods are now unicode only Fixed reading of unicode name and values from registry via valueNamed: - Added a REG_QWORD registry type (64bit number) - Added regression tests for the changes at RegressionTests::Win32OperatingSystemTest - removed all ASCII only reading -> only unicode version is now supported - replaced while(*cp++) itteration with wide-string search (wcschr) - faster & clear intent - added a character limit read to count the string lenght (REG_MULTI_SZ) - clearing the pointer after usage - renamed a method parameter aValueName to just name - added a nameUtf16Z which formats the input name into Unicode16String with terminating NULL - Added a comment on registry size limitations at #valueNamed:put: The #valueNameAtIndex: - The method is used at (all these now support unicode): - #valueNames - replaced nextPut: with nextPutUnicode: - #valueNamesAndValuesDo: - #valueNamesDo: The #subKeyAtIndex: - The method is used at (all these now support unicode): - #subKeysDo: - #allSubKeysDo: Others fixed: - #subKeyNameAndClassAtIndex: - #remoteKeyOnHost: - - added a hostNameUtf16Z which formats the input name into Unicode16String with terminating NULL - checking if registry value name is a string if not return nil and print message into transcript - defaultValue can be now used - reading a (default) value from a reagistry Key diff -r 20f35741c92d -r 4debcdcaf264 Win32OperatingSystem.st
a b 16073 16073 16074 16074 remoteKeyOnHost:hostName 16075 16075 "return the corresponding registry entry from 16076 a remote computers registry." 16077 16078 |newEntry remoteHandle errorNumber| 16079 16076 a remote computers registry. 16077 Note: The registry key must be form a predefined list defined by Microsoft." 16078 16079 |hostNameUtf16Z newEntry remoteHandle errorNumber| 16080 16081 hostNameUtf16Z := hostName notEmptyOrNil ifTrue:[hostName asUnicode16StringZ]. 16082 16080 16083 %{ 16081 16084 HKEY myKey, remoteKey = 0; 16082 16085 int _retVal; 16083 16086 16084 if (__isExternalAddressLike(__INST(handle)) && __isStringLike(hostName)) { 16087 /* Notes from MSDN: 16088 * link: https://docs.microsoft.com/en-us/windows/desktop/api/winreg/nf-winreg-regconnectregistryw 16089 * 16090 * 1) RegConnectRegistry requires the Remote Registry service to be running on the remote computer. 16091 * By default, this service is configured to be started manually. To configure the Remote Registry 16092 * service to start automatically, run Services.msc and change the Startup Type of the service to Automatic. 16093 * 16094 * 2) If the computer is joined to a workgroup and the "Force network logons using local accounts to authenticate as 16095 * Guest" policy is enabled, the function fails. Note that this policy is enabled by default if the computer is joined 16096 * to a workgroup. 16097 * 16098 * 3) If the current user does not have proper access to the remote computer, the call to RegConnectRegistry fails. To connect 16099 * to a remote registry, call LogonUser with LOGON32_LOGON_NEW_CREDENTIALS and ImpersonateLoggedOnUser before calling 16100 * RegConnectRegistry. 16101 * 16102 * 4) myKey must be a predefined registry handle. 16103 * more at: https://docs.microsoft.com/en-us/windows/desktop/SysInfo/predefined-keys 16104 * 16105 * 5) When a handle returned by RegConnectRegistry is no longer needed, it should be closed by calling RegCloseKey. (done by registerForFinaliation) 16106 * 16107 */ 16108 16109 if (__isExternalAddressLike(__INST(handle)) && __isUnicode16String(hostNameUtf16Z)) { 16085 16110 myKey = (HKEY)__externalAddressVal(__INST(handle)); 16086 if ((_retVal = RegConnectRegistry A(__stringVal(hostName), myKey, &remoteKey)) == ERROR_SUCCESS) {16111 if ((_retVal = RegConnectRegistryW(__unicode16StringVal(hostNameUtf16Z), myKey, &remoteKey)) == ERROR_SUCCESS) { 16087 16112 remoteHandle = __MKEXTERNALADDRESS(remoteKey); 16088 16113 } else { 16089 16114 if ((_retVal != ERROR_PATH_NOT_FOUND) … … 16100 16125 ]. 16101 16126 errorNumber notNil ifTrue:[ 16102 16127 (OperatingSystem errorHolderForNumber:errorNumber) reportError. 16103 ]. 16128 ]. 16129 16104 16130 ^ nil 16105 16131 16106 16132 " … … 16131 16157 16132 16158 subKeyAtIndex:subKeyIndex 16133 16159 "return a new registry entry below mySelf for the given subKey index. 16134 Return nil if no such key exists" 16160 Return nil if no such key exists 16161 WARNING: subKeyIndex is 0-based!!" 16162 16135 16163 16136 16164 |subKeyName subKeyClassName errorNumber| 16137 16165 16138 16166 %{ 16139 16167 HKEY myKey, subKey = 0; 16140 char nameBuffer[256]; 16141 DWORD nameSize = sizeof(nameBuffer) - 1; 16142 char classNameBuffer[256]; 16143 DWORD classNameSize = sizeof(classNameBuffer) - 1; 16168 16169 /* lpName (nameBuffer): 16170 * A pointer to a buffer that receives the name of the subkey, including the 16171 * terminating null character. The function copies only the name of the subkey, 16172 * not the full key hierarchy, to the buffer. If the function fails, no information is copied to this buffer. 16173 * 16174 * note: This actually means that the if the path fits within 255 chacaters you could get another 255 characters for the key itself. 16175 * This could help if you are having issues with the registry path lenght. 16176 */ 16177 wchar_t nameBuffer[256]; // 256 is due to Key name limit (including path) 16178 DWORD nameSize = sizeof(nameBuffer); 16179 16180 /* lpClass (classNameBuffer): 16181 * A pointer to a buffer that receives the user-defined class of the enumerated subkey. 16182 */ 16183 wchar_t classNameBuffer[256]; 16184 DWORD classNameSize = sizeof(classNameBuffer); 16144 16185 FILETIME modificationTime; 16145 16186 int _retVal; 16146 16187 16147 16188 if (__isExternalAddressLike(__INST(handle)) 16148 16189 && __isSmallInteger(subKeyIndex)) { 16149 16190 myKey = (HKEY)__externalAddressVal(__INST(handle)); 16150 if ((_retVal = RegEnumKeyEx A(myKey, __intVal(subKeyIndex),16191 if ((_retVal = RegEnumKeyExW(myKey, __intVal(subKeyIndex), 16151 16192 nameBuffer, &nameSize, 16152 16193 NULL, 16153 16194 classNameBuffer, &classNameSize, 16154 16195 &modificationTime)) == ERROR_SUCCESS) { 16155 16196 nameBuffer[nameSize] = '\0'; 16156 16197 classNameBuffer[classNameSize] = '\0'; 16157 subKeyName = __MK STRING(nameBuffer);16158 subKeyClassName = __MK STRING(classNameBuffer);16198 subKeyName = __MKU16STRING(nameBuffer); 16199 subKeyClassName = __MKU16STRING(classNameBuffer); 16159 16200 } else { 16160 16201 if ((_retVal != ERROR_PATH_NOT_FOUND) 16161 16202 && (_retVal != ERROR_FILE_NOT_FOUND) … … 16183 16224 16184 16225 subKeyNameAndClassAtIndex:subKeyIndex 16185 16226 "return the name and className of the given subKey at index as a pair. 16186 Return nil if no such key exists" 16227 Return nil if no such key exists 16228 WARNING: subKeyIndex is 0-based!!" 16187 16229 16188 16230 |subKeyName subKeyClassName errorNumber| 16189 16231 16190 16232 %{ 16191 16233 HKEY myKey, subKey = 0; 16192 char nameBuffer[256]; 16193 DWORD nameSize = sizeof(nameBuffer) - 1; 16194 char classNameBuffer[256]; 16195 DWORD classNameSize = sizeof(classNameBuffer) - 1; 16234 16235 /* lpName (nameBuffer): 16236 * A pointer to a buffer that receives the name of the subkey, including the 16237 * terminating null character. The function copies only the name of the subkey, 16238 * not the full key hierarchy, to the buffer. If the function fails, no information is copied to this buffer. 16239 * 16240 * note: This actually means that the if the path fits within 255 chacaters you could get another 255 characters for the key itself. 16241 * This could help if you are having issues with the registry path lenght. 16242 */ 16243 wchar_t nameBuffer[256]; // limiting the nameBuffer to 255 characters + null terminator 16244 DWORD nameSize = sizeof(nameBuffer); 16245 16246 /* lpClass (classNameBuffer): 16247 * A pointer to a buffer that receives the user-defined class of the enumerated subkey. 16248 */ 16249 wchar_t classNameBuffer[256]; // limiting the classNameBuffer to 255 characters + nul terminator 16250 DWORD classNameSize = sizeof(classNameBuffer); 16251 16196 16252 FILETIME modificationTime; 16197 16253 int _retVal; 16198 16254 16199 16255 if (__isExternalAddressLike(__INST(handle)) 16200 16256 && __isSmallInteger(subKeyIndex)) { 16201 16257 myKey = (HKEY)__externalAddressVal(__INST(handle)); 16202 if ((_retVal = RegEnumKeyEx A(myKey, __intVal(subKeyIndex),16258 if ((_retVal = RegEnumKeyExW(myKey, __intVal(subKeyIndex), 16203 16259 nameBuffer, &nameSize, 16204 16260 NULL, 16205 16261 classNameBuffer, &classNameSize, 16206 16262 &modificationTime)) == ERROR_SUCCESS) { 16207 16263 nameBuffer[nameSize] = '\0'; 16208 classNameBuffer[classNameSize] = '\0'; 16209 subKeyName = __MKSTRING(nameBuffer);16210 subKeyClassName = __MKSTRING(classNameBuffer);16264 classNameBuffer[classNameSize] = '\0'; 16265 subKeyName = __MKU16STRING(nameBuffer); 16266 subKeyClassName = __MKU16STRING(classNameBuffer); 16211 16267 } else { 16212 16268 if ((_retVal != ERROR_PATH_NOT_FOUND) 16213 16269 && (_retVal != ERROR_FILE_NOT_FOUND) … … 16432 16488 16433 16489 valueNameAtIndex:valueIndex 16434 16490 "return a values name for the given value index. 16435 Return nil if no such value exists" 16491 Return nil if no such value exists 16492 WARNING: valueIndex is 0-based!!" 16436 16493 16437 16494 |valueName errorNumber| 16438 16495 16439 16496 %{ 16440 16497 HKEY myKey; 16441 char nameBuffer[256]; 16442 DWORD nameSize = sizeof(nameBuffer) - 1; 16498 16499 /* nameBuffer (lpValueName in RegEnumValue function): 16500 * A pointer to a buffer that receives the name of the value as a null-terminated string. 16501 * This buffer must be large enough to include the terminating null character. 16502 * For more information, see Registry Element Size Limits. 16503 */ 16504 wchar_t nameBuffer[256]; // 256 is due to Key name limit (including path) + the null character 16505 16506 /* nameSize (lpcchValueName in RegEnumValue function): 16507 * 16508 * A pointer to a variable that specifies the size of the buffer pointed to by the lpValueName parameter, in characters. 16509 * When the function returns, the variable receives the number of characters stored in the buffer, not including the terminating null character. 16510 * 16511 * Registry value names are limited to 32,767 bytes. The ANSI version of this function treats this parameter as a SHORT value. 16512 * Therefore, if you specify a value greater than 32,767 bytes, there is an overflow and the function may return ERROR_MORE_DATA. 16513 */ 16514 DWORD nameSize = sizeof(nameBuffer); 16443 16515 DWORD valueType; 16444 16516 int _retVal; 16445 16517 16446 16518 if (__isExternalAddressLike(__INST(handle)) 16447 16519 && __isSmallInteger(valueIndex)) { 16448 16520 myKey = (HKEY)__externalAddressVal(__INST(handle)); 16449 if ((_retVal = RegEnumValue A(myKey, __intVal(valueIndex),16521 if ((_retVal = RegEnumValueW(myKey, __intVal(valueIndex), 16450 16522 nameBuffer, &nameSize, 16451 16523 NULL, 16452 16524 &valueType, 16453 16525 NULL, NULL)) == ERROR_SUCCESS) { 16454 16526 nameBuffer[nameSize] = '\0'; 16455 valueName = __MKSTRING(nameBuffer);16527 valueName = __MKU16STRING(nameBuffer); 16456 16528 } else { 16457 16529 if ((_retVal != ERROR_PATH_NOT_FOUND) 16458 16530 && (_retVal != ERROR_FILE_NOT_FOUND) … … 16475 16547 " 16476 16548 ! 16477 16549 16478 valueNamed: aValueName16550 valueNamed:name 16479 16551 "retrieve a value; the returned object depends upon the type: 16480 16552 REG_BINARY -> ByteArray 16481 16553 REG_SZ -> String … … 16484 16556 REG_NONE -> nil 16485 16557 " 16486 16558 16487 |stringArray retVal errorNumber| 16559 |nameUtf16Z stringArray retVal errorNumber| 16560 16561 "/ name must be a string 16562 name isString ifFalse: [ 16563 Transcript showCR: 'The registry value name must be a String!!'. 16564 ^ nil 16565 ]. 16566 16567 "/ adding terminating null into empty string 16568 name notNil ifTrue:[ 16569 name isEmpty ifTrue:[nameUtf16Z := (name, (Character codePoint: 0)) asUnicode16String] "/ needed for defaultValue 16570 ifFalse:[nameUtf16Z := name asUnicode16StringZ] 16571 ]. 16488 16572 16489 16573 %{ /* STACK: 20000 */ 16490 16574 HKEY myKey; 16491 16575 DWORD valueType; 16576 int val; 16492 16577 union { 16493 DWORD dWord; 16494 unsigned char dWordBytes[4]; 16495 unsigned char smallDataBuffer[1024*16]; 16578 DWORD dWord; 16579 unsigned char dWordBytes[4]; // needed for the shifts at REG_DWORD_LITTLE_ENDIAN and REG_DWORD_BIG_ENDIAN 16580 ULONGLONG qWord; // needed for the 64-bit int (QWORD) 16581 wchar_t wstringBuffer[1024*8]; // buffer for wide characters 16496 16582 } quickData; 16497 int val; 16583 16584 wchar_t *dataBuffer = NULL; 16498 16585 DWORD dataSize = sizeof(quickData); 16499 unsigned char *dataBuffer = NULL;16500 #define xxUSE_UNICODE16501 #ifdef USE_UNICODE16502 # define xRegQueryValueEx RegQueryValueExW16503 # define CHAR short16504 #else16505 # define RegQueryValueEx RegQueryValueExA16506 # define CHAR char16507 #endif16508 16586 16509 16587 if (__isExternalAddressLike(__INST(handle)) 16510 && __is StringLike(aValueName)) {16588 && __isUnicode16String(nameUtf16Z)) { 16511 16589 int ret; 16512 16590 16513 16591 myKey = (HKEY)__externalAddressVal(__INST(handle)); 16514 16592 16515 /* 16516 * try to get it with one call ... 16517 */ 16518 ret = RegQueryValueExA(myKey, __stringVal(aValueName), 16593 /* Reading values from registry 16594 * 16595 * LSTATUS RegQueryValueEx( // ends with either A(ascii) or W (unicode) 16596 * HKEY hKey, // a handle of a registry key 16597 * LPCWSTR lpValueName, // The name of the registry value 16598 * LPDWORD lpReserved, // reserved and must be NULL 16599 * LPDWORD lpType, // A pointer to a variable that recieves a code indicating the type of data stored in the specified value 16600 * LPBYTE lpData, // A pointer to a buffer that receives the value's data. This parameter can be NULL if datat is not required 16601 * LPDWORD lpcbData // A pointer to a variable that specifies the size of the buffer pointed to by the IpData parameter, in bytes. 16602 * // When the furnction returns, this variable contains the size of the data copied to IpData 16603 * ); 16604 */ 16605 16606 #if 0 16607 console_printf("================================================\n"); 16608 console_printf("Before - myKey: %p\n", &myKey); 16609 console_printf("Before - aValueName: %S\n", __unicode16StringVal(nameUtf16Z)); 16610 console_printf("Before - valueType: %p, valueTypeData: %lu\n", &valueType, valueType); 16611 console_printf("Before - QuickData dWord: %lu\n", quickData.dWord); 16612 console_printf("Before - QuickData dWordBytes: %S\n", quickData.dWordBytes); 16613 console_printf("Before - QuickData qWord: %lu\n", quickData.qWord); 16614 console_printf("Before - QuickData smallDataBuffer: %S\n", quickData.smallDataBuffer); 16615 console_printf("Before - Databuffer: %p, dataBufferData: %s\n", &dataBuffer, dataBuffer); 16616 console_printf("Before - dataSize: %p, dataSizeData: %lu\n", &dataSize, dataSize); 16617 console_printf("================================================\n"); 16618 #endif 16619 16620 /* 16621 * try to get it with one call ... 16622 */ 16623 ret = RegQueryValueExW(myKey, __unicode16StringVal(nameUtf16Z), 16519 16624 NULL, 16520 16625 &valueType, 16521 (char *)&quickData, 16626 (LPBYTE) &quickData.wstringBuffer, // LPBYTE aka (unsigned char *) 16522 16627 &dataSize); 16628 16629 #if 0 16630 console_printf("------------------------------------------------\n"); 16631 console_printf("After - myKey: %p\n", &myKey); 16632 console_printf("After - aValueName: %S\n", __unicode16StringVal(nameUtf16Z)); 16633 console_printf("After - valueType: %p, valueTypeData: %lu\n", &valueType, valueType); 16634 console_printf("After - QuickData dWord: %lu\n", quickData.dWord); 16635 console_printf("After - QuickData dWordBytes: %S\n", quickData.dWordBytes); 16636 console_printf("After - QuickData qWord: %lu\n", quickData.qWord); 16637 console_printf("After - QuickData smallDataBuffer: %S\n", quickData.smallDataBuffer); 16638 console_printf("After - Databuffer: %p, dataBufferData: %s\n", &dataBuffer, dataBuffer); 16639 console_printf("After - dataSize: %p, dataSizeData: %lu\n", &dataSize, dataSize); 16640 console_printf("------------------------------------------------\n"); 16641 #endif 16642 16523 16643 #if 0 16524 console_printf("get \"%s\": dataSize=%d ret=%d\n", __stringVal(aValueName), dataSize, ret); 16644 console_printf("Registry key: %p\n", (void *) myKey); 16645 console_printf("get \"%S\": dataSize=%d ret=%d\n", __unicode16StringVal(nameUtf16Z), dataSize, ret); 16525 16646 #endif 16526 16647 while (ret == ERROR_MORE_DATA) { 16527 16648 #if 0 16528 16649 console_printf("ERROR_MORE_DATA dataSize=%d valueType=%d\n", dataSize, valueType); 16529 16650 #endif 16530 16651 /* 16531 16652 * nope - need another one ... 16532 16653 */ 16533 if (myKey = HKEY_PERFORMANCE_DATA) {16654 if (myKey == HKEY_PERFORMANCE_DATA) { 16534 16655 dataSize = dataSize * 2; 16535 16656 } 16536 16657 switch (valueType) { 16537 16658 case REG_BINARY: 16538 16659 case REG_MULTI_SZ: 16539 dataBuffer = malloc(dataSize); ;16660 dataBuffer = malloc(dataSize); 16540 16661 break; 16541 16662 case REG_SZ: 16542 16663 dataBuffer = malloc(dataSize); … … 16546 16667 break; 16547 16668 } 16548 16669 if (dataBuffer) { 16549 ret = RegQueryValueEx (myKey, __stringVal(aValueName),16670 ret = RegQueryValueExW(myKey, __unicode16StringVal(nameUtf16Z), 16550 16671 NULL, 16551 16672 &valueType, 16552 dataBuffer,16673 (LPBYTE) dataBuffer, 16553 16674 &dataSize); 16554 16675 } else { 16555 16676 break; … … 16569 16690 retVal = nil; 16570 16691 break; 16571 16692 16572 case REG_BINARY: 16573 retVal = __MKBYTEARRAY(dataBuffer ? dataBuffer : quickData. smallDataBuffer, dataSize);16693 case REG_BINARY: 16694 retVal = __MKBYTEARRAY(dataBuffer ? dataBuffer : quickData.wstringBuffer, dataSize); 16574 16695 break; 16575 16696 16576 16697 case REG_SZ: 16577 16698 case REG_EXPAND_SZ: 16578 #ifdef USE_UNICODE 16579 retVal = __MKU16STRING(dataBuffer ? dataBuffer : quickData.smallDataBuffer); 16580 #else 16581 retVal = __MKSTRING(dataBuffer ? dataBuffer : quickData.smallDataBuffer); 16582 #endif 16699 16700 #if 0 16701 console_printf("dataBuffer before __MKU16STTRING: %S\n", dataBuffer); 16702 console_printf("QuickData smallDataBuffer before __MKU16STTRING: %S\n", quickData.wstringBuffer); 16703 #endif 16704 retVal = __MKU16STRING(dataBuffer ? dataBuffer : quickData.wstringBuffer); 16705 #if 0 16706 console_printf("QuickData smallDataBuffer: %S\n", quickData.wstringBuffer); 16707 console_printf("dataBuffer: %S\n", dataBuffer); 16708 #endif 16709 16583 16710 break; 16584 16711 16585 16712 #if 0 … … 16603 16730 val = (val << 8) | quickData.dWordBytes[3]; 16604 16731 retVal = __MKUINT(val); 16605 16732 break; 16606 16733 16734 case REG_QWORD: // only REG_QWORD_LITTLE_ENDIAN present (no need for shifts) 16735 retVal = __MKULARGEINT(quickData.qWord); 16736 break; 16737 16607 16738 case REG_MULTI_SZ: 16608 16739 { 16609 CHAR*cp, *cp0;16740 wchar_t *cp, *cp0; 16610 16741 int ns, i; 16611 16612 cp0 = dataBuffer ? dataBuffer : quickData.smallDataBuffer; 16742 16743 cp0 = dataBuffer ? dataBuffer : quickData.wstringBuffer; 16744 16613 16745 #if 0 16746 16614 16747 console_printf("**************\n"); 16615 16748 for (i=0;i<50;i++) { 16616 16749 console_printf("%x ", cp0[i]); … … 16627 16760 #endif 16628 16761 cp = cp0; 16629 16762 ns = 0; 16630 while (*cp) { 16631 while (*cp++) ;; 16632 ns++; 16763 16764 // datasize 16765 while ((((cp - cp0) * sizeof(wchar_t)) < (dataSize - 1)) // limits the string 16766 && *cp) { // check if the dereferenced value is NULL 16767 cp = wcschr(cp, '\0'); // wide string search for terminating null character 16768 *cp++; 16769 ns++; 16633 16770 } 16771 16772 // clear any remaining value 16773 *cp = '\0'; 16634 16774 stringArray = __ARRAY_NEW_INT(ns); 16635 16775 16636 16776 i = 0; 16637 16777 while (*cp0) { 16638 16778 OBJ s; 16639 CHAR *cp; 16640 16641 cp = cp0; 16642 while (*cp++) ;; 16643 #ifdef USE_UNICODE 16644 s = __MKU16STRING(cp0); __ArrayInstPtr(stringArray)->a_element[i] = s; __STORE(stringArray, s); 16645 #else 16646 s = __MKSTRING(cp0); __ArrayInstPtr(stringArray)->a_element[i] = s; __STORE(stringArray, s); 16647 #endif 16648 cp0 = cp; 16779 16780 cp = cp0; 16781 s = __MKU16STRING(cp0); __ArrayInstPtr(stringArray)->a_element[i] = s; __STORE(stringArray, s); 16782 cp = wcschr(cp, '\0'); 16783 *cp++; 16784 cp0 = cp; 16649 16785 i++; 16786 16650 16787 } 16651 16788 retVal = stringArray; 16652 break; 16653 } 16789 break; 16790 } 16654 16791 default: 16655 16792 console_printf("RegistryEntry [warning]: unhandled valueType: %d\n", valueType); 16656 16793 break; … … 16660 16797 && (ret != ERROR_FILE_NOT_FOUND)) { 16661 16798 errorNumber = __MKSMALLINT(ret); 16662 16799 } 16663 } 16800 } 16664 16801 } 16665 16802 if (dataBuffer) free(dataBuffer); 16803 16666 16804 %}. 16667 16805 errorNumber notNil ifTrue:[ 16668 16806 (OperatingSystem errorHolderForNumber:errorNumber) reportError. … … 16689 16827 16690 16828 |data stringArray errorNumber| 16691 16829 %{ 16830 /* Registry Element Size Limits 16831 * 16832 * Found at MSDN: https://docs.microsoft.com/en-us/windows/desktop/SysInfo/registry-element-size-limits 16833 * 16834 * Registry Element | Size Limit 16835 * Key name 255 characters. The key name includes the absolute path of the key in the registry, always starting at a base key, for example, HKEY_LOCAL_MACHINE. 16836 * Value name 16,383 characters; Windows 2000: 260 ANSI characters or 16,383 Unicode characters. 16837 * Value Available memory (latest format)1 MB (standard format) 16838 * Tree A registry tree can be 512 levels deep. You can create up to 32 levels at a time through a single registry API call. 16839 * 16840 * Notes: 16841 * - Long values (more than 2,048 bytes) should be stored in a file, and the location of the file should be stored in the registry. 16842 * This helps the registry perform efficiently. 16843 * 16844 * - The file location can be the name of a value or the data of a value. Each backslash in the location string must be preceded by 16845 * another backslash as an escape character. For example, specify "C:\\mydir\\myfile" to store the string "C:\mydir\myfile". 16846 * A file location can also be the name of a key if it is within the 255-character limit for key names and does not contain backslashes, 16847 * which are not allowed in key names. 16848 */ 16849 16692 16850 HKEY myKey; 16693 16851 DWORD valueType = -1; 16694 16852 int val; … … 16918 17076 "evaluate aBlock for all value names" 16919 17077 16920 17078 ^ Array streamContents:[:s | 16921 self valueNamesDo:[:nm | s nextPut :nm]17079 self valueNamesDo:[:nm | s nextPutUnicode:nm] 16922 17080 ]. 16923 17081 16924 17082 "Created: / 18-01-2011 / 20:24:52 / cg"