Index: src/OFConstantString.m ================================================================== --- src/OFConstantString.m +++ src/OFConstantString.m @@ -672,10 +672,19 @@ [self finishInitialization]; return self.decomposedStringWithCompatibilityMapping; } #endif + +#ifdef OF_WINDOWS +- (OFString *)stringByExpandingWindowsEnvironmentStrings +{ + [self finishInitialization]; + + return self.stringByExpandingWindowsEnvironmentStrings; +} +#endif #ifdef OF_HAVE_FILES - (void)writeToFile: (OFString *)path { [self finishInitialization]; Index: src/OFDNSResolverSettings.m ================================================================== --- src/OFDNSResolverSettings.m +++ src/OFDNSResolverSettings.m @@ -483,15 +483,17 @@ [self setDefaults]; #if defined(OF_WINDOWS) # ifdef OF_HAVE_FILES - path = [[OFWindowsRegistryKey localMachineKey] - stringForValue: @"DataBasePath" - subkeyPath: @"SYSTEM\\CurrentControlSet\\Services\\" - @"Tcpip\\Parameters"]; - path = [path stringByAppendingPathComponent: @"hosts"]; + OFWindowsRegistryKey *key = [[OFWindowsRegistryKey localMachineKey] + openSubkeyAtPath: @"SYSTEM\\CurrentControlSet\\Services\\" + @"Tcpip\\Parameters" + securityAndAccessRights: KEY_QUERY_VALUE]; + path = [[[key stringForValue: @"DataBasePath"] + stringByAppendingPathComponent: @"hosts"] + stringByExpandingWindowsEnvironmentStrings]; if (path != nil) [self parseHosts: path]; # endif Index: src/OFString.h ================================================================== --- src/OFString.h +++ src/OFString.h @@ -285,10 +285,18 @@ * @brief The string in Unicode Normalization Form KD (NFKD). */ @property (readonly, nonatomic) OFString *decomposedStringWithCompatibilityMapping; # endif + +# ifdef OF_WINDOWS +/*! + * @brief The string with the Windows Environment Strings expanded. + */ +@property (readonly, nonatomic) + OFString *stringByExpandingWindowsEnvironmentStrings; +# endif /*! * @brief Creates a new OFString. * * @return A new, autoreleased OFString Index: src/OFString.m ================================================================== --- src/OFString.m +++ src/OFString.m @@ -2705,10 +2705,25 @@ { return decomposedString(self, of_unicode_decomposition_compat_table, OF_UNICODE_DECOMPOSITION_COMPAT_TABLE_SIZE); } #endif + +#ifdef OF_WINDOWS +- (OFString *)stringByExpandingWindowsEnvironmentStrings +{ + wchar_t buffer[512]; + size_t length; + + if ((length = ExpandEnvironmentStringsW(self.UTF16String, buffer, + sizeof(buffer))) == 0) + return self; + + return [OFString stringWithUTF16String: buffer + length: length - 1]; +} +#endif #ifdef OF_HAVE_FILES - (void)writeToFile: (OFString *)path { [self writeToFile: path Index: src/OFWindowsRegistryKey.h ================================================================== --- src/OFWindowsRegistryKey.h +++ src/OFWindowsRegistryKey.h @@ -130,26 +130,22 @@ */ - (OFWindowsRegistryKey *) createSubkeyAtPath: (OFString *)path options: (DWORD)options securityAndAccessRights: (REGSAM)securityAndAccessRights - securityAttributes: (nullable LPSECURITY_ATTRIBUTES)securityAttributes - disposition: (nullable LPDWORD)disposition; + securityAttributes: (nullable SECURITY_ATTRIBUTES *)securityAttributes + disposition: (nullable DWORD *)disposition; /*! * @brief Returns the data for the specified value at the specified path. * * @param value The name of the value to return - * @param subkeyPath The path of the key from which to retrieve the value - * @param flags Extra flags for `RegGetValue()`. Usually 0. * @param type A pointer to store the type of the value, or NULL * @return The data for the specified value */ - (nullable OFData *)dataForValue: (nullable OFString *)value - subkeyPath: (nullable OFString *)subkeyPath - flags: (DWORD)flags - type: (nullable LPDWORD)type; + type: (nullable DWORD *)type; /*! * @brief Sets the data for the specified value. * * @param data The data to set the value to @@ -162,29 +158,23 @@ /*! * @brief Returns the string for the specified value at the specified path. * * @param value The name of the value to return - * @param subkeyPath The path of the key from which to retrieve the value * @return The string for the specified value */ -- (nullable OFString *)stringForValue: (nullable OFString *)value - subkeyPath: (nullable OFString *)subkeyPath; +- (nullable OFString *)stringForValue: (nullable OFString *)value; /*! * @brief Returns the string for the specified value at the specified path. * * @param value The name of the value to return - * @param subkeyPath The path of the key from which to retrieve the value - * @param flags Extra flags for `RegGetValue()`. Usually 0. * @param type A pointer to store the type of the value, or NULL * @return The string for the specified value */ - (nullable OFString *)stringForValue: (nullable OFString *)value - subkeyPath: (nullable OFString *)subkeyPath - flags: (DWORD)flags - type: (nullable LPDWORD)type; + type: (nullable DWORD *)type; /*! * @brief Sets the string for the specified value. * * @param string The string to set the value to Index: src/OFWindowsRegistryKey.m ================================================================== --- src/OFWindowsRegistryKey.m +++ src/OFWindowsRegistryKey.m @@ -167,23 +167,21 @@ close: true] autorelease]; } - (OFData *)dataForValue: (OFString *)value - subkeyPath: (OFString *)subkeyPath - flags: (DWORD)flags type: (LPDWORD)type { void *pool = objc_autoreleasePoolPush(); - char stackBuffer[256], *buffer = stackBuffer; + BYTE stackBuffer[256], *buffer = stackBuffer; DWORD length = sizeof(stackBuffer); OFMutableData *ret = nil; LSTATUS status; for (;;) { - status = RegGetValueW(_hKey, subkeyPath.UTF16String, - value.UTF16String, flags, type, buffer, &length); + status = RegQueryValueExW(_hKey, value.UTF16String, NULL, type, + buffer, &length); switch (status) { case ERROR_SUCCESS: if (buffer == stackBuffer) { objc_autoreleasePoolPop(pool); @@ -213,12 +211,10 @@ continue; default: @throw [OFGetWindowsRegistryValueFailedException exceptionWithRegistryKey: self value: value - subkeyPath: subkeyPath - flags: flags status: status]; } } } @@ -241,27 +237,20 @@ type: type status: status]; } - (OFString *)stringForValue: (OFString *)value - subkeyPath: (OFString *)subkeyPath { return [self stringForValue: value - subkeyPath: subkeyPath - flags: RRF_RT_REG_SZ type: NULL]; } - (OFString *)stringForValue: (OFString *)value - subkeyPath: (OFString *)subkeyPath - flags: (DWORD)flags type: (LPDWORD)type { void *pool = objc_autoreleasePoolPush(); OFData *data = [self dataForValue: value - subkeyPath: subkeyPath - flags: flags type: type]; const of_char16_t *UTF16String; size_t length; OFString *ret; Index: src/exceptions/OFGetWindowsRegistryValueFailedException.h ================================================================== --- src/exceptions/OFGetWindowsRegistryValueFailedException.h +++ src/exceptions/OFGetWindowsRegistryValueFailedException.h @@ -30,11 +30,11 @@ * @brief An exception indicating that getting a Windows registry value failed. */ @interface OFGetWindowsRegistryValueFailedException: OFException { OFWindowsRegistryKey *_registryKey; - OFString *_Nullable _value, *_Nullable _subkeyPath; + OFString *_Nullable _value; DWORD _flags; LSTATUS _status; } /*! @@ -45,20 +45,10 @@ /*! * @brief The value which could not be retrieved. */ @property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFString *value; -/*! - * @brief The subkey path at which getting the value failed. - */ -@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFString *subkeyPath; - -/*! - * @brief The flags with which getting the value failed. - */ -@property (readonly, nonatomic) DWORD flags; - /*! * @brief The status returned by RegGetValueEx(). */ @property (readonly, nonatomic) LSTATUS status; @@ -67,19 +57,15 @@ * exception. * * @param registryKey The registry key on which getting the value at the sub * key path failed * @param value The value which could not be retrieved - * @param subkeyPath The subkey path at which getting the value failed - * @param flags The flags with which getting the value failed * @param status The status returned by RegGetValueEx() * @return A new, autoreleased get Windows registry value failed exception */ + (instancetype)exceptionWithRegistryKey: (OFWindowsRegistryKey *)registryKey value: (nullable OFString *)value - subkeyPath: (nullable OFString *)subkeyPath - flags: (DWORD)flags status: (LSTATUS)status; - (instancetype)init OF_UNAVAILABLE; /*! @@ -87,18 +73,14 @@ * exception. * * @param registryKey The registry key on which getting the value at the sub * key path failed * @param value The value which could not be retrieved - * @param subkeyPath The subkey path at which getting the value failed - * @param flags The flags with which getting the value failed * @param status The status returned by RegGetValueEx() * @return An initialized get Windows registry value failed exception */ - (instancetype)initWithRegistryKey: (OFWindowsRegistryKey *)registryKey value: (nullable OFString *)value - subkeyPath: (nullable OFString *)subkeyPath - flags: (DWORD)flags status: (LSTATUS)status OF_DESIGNATED_INITIALIZER; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFGetWindowsRegistryValueFailedException.m ================================================================== --- src/exceptions/OFGetWindowsRegistryValueFailedException.m +++ src/exceptions/OFGetWindowsRegistryValueFailedException.m @@ -18,23 +18,18 @@ #include "config.h" #import "OFGetWindowsRegistryValueFailedException.h" @implementation OFGetWindowsRegistryValueFailedException -@synthesize registryKey = _registryKey, value = _value; -@synthesize subkeyPath = _subkeyPath, flags = _flags, status = _status; +@synthesize registryKey = _registryKey, value = _value, status = _status; + (instancetype)exceptionWithRegistryKey: (OFWindowsRegistryKey *)registryKey value: (OFString *)value - subkeyPath: (OFString *)subkeyPath - flags: (DWORD)flags status: (LSTATUS)status { return [[[self alloc] initWithRegistryKey: registryKey value: value - subkeyPath: subkeyPath - flags: flags status: status] autorelease]; } - (instancetype)init { @@ -41,21 +36,17 @@ OF_INVALID_INIT_METHOD } - (instancetype)initWithRegistryKey: (OFWindowsRegistryKey *)registryKey value: (OFString *)value - subkeyPath: (OFString *)subkeyPath - flags: (DWORD)flags status: (LSTATUS)status { self = [super init]; @try { _registryKey = [registryKey retain]; _value = [value copy]; - _subkeyPath = [subkeyPath copy]; - _flags = flags; _status = status; } @catch (id e) { [self release]; @throw e; } @@ -65,17 +56,16 @@ - (void)dealloc { [_registryKey release]; [_value release]; - [_subkeyPath release]; [super dealloc]; } - (OFString *)description { return [OFString stringWithFormat: - @"Failed to get value %@ at subkey path %@: %@", - _value, _subkeyPath, of_windows_status_to_string(_status)]; + @"Failed to get value %@: %@", + _value, of_windows_status_to_string(_status)]; } @end Index: tests/OFWindowsRegistryKeyTests.m ================================================================== --- tests/OFWindowsRegistryKeyTests.m +++ tests/OFWindowsRegistryKeyTests.m @@ -27,11 +27,10 @@ void *pool = objc_autoreleasePoolPush(); OFData *data = [OFData dataWithItems: "abcdef" count: 6]; OFWindowsRegistryKey *softwareKey, *ObjFWKey; DWORD type; - OFString *string; TEST(@"+[OFWindowsRegistryKey classesRootKey]", [OFWindowsRegistryKey classesRootKey]) TEST(@"+[OFWindowsRegistryKey currentConfigKey]", @@ -62,14 +61,12 @@ R([ObjFWKey setData: data forValue: @"data" type: REG_BINARY])) TEST(@"-[dataForValue:subkeyPath:flags:type:]", - [[softwareKey dataForValue: @"data" - subkeyPath: @"ObjFW" - flags: RRF_RT_REG_BINARY - type: &type] isEqual: data] && + [[ObjFWKey dataForValue: @"data" + type: &type] isEqual: data] && type == REG_BINARY) TEST(@"-[setString:forValue:type:]", R([ObjFWKey setString: @"foobar" forValue: @"string"]) && @@ -76,25 +73,18 @@ R([ObjFWKey setString: @"%PATH%;foo" forValue: @"expand" type: REG_EXPAND_SZ])) TEST(@"-[stringForValue:subkeyPath:]", - [[softwareKey stringForValue: @"string" - subkeyPath: @"ObjFW"] isEqual: @"foobar"] && - [[softwareKey stringForValue: @"expand" - subkeyPath: @"ObjFW" - flags: RRF_RT_REG_EXPAND_SZ | RRF_NOEXPAND - type: &type] isEqual: @"%PATH%;foo"] && - type == REG_EXPAND_SZ && - (string = [ObjFWKey stringForValue: @"expand" - subkeyPath: nil]) && - ![string isEqual: @"%PATH%;foo"] && - [string hasSuffix: @";foo"]) + [[ObjFWKey stringForValue: @"string"] isEqual: @"foobar"] && + [[ObjFWKey stringForValue: @"expand" + type: &type] isEqual: @"%PATH%;foo"] && + type == REG_EXPAND_SZ) TEST(@"-[deleteValue:]", R([ObjFWKey deleteValue: @"data"])) TEST(@"-[deleteSubkeyAtPath:]", R([softwareKey deleteSubkeyAtPath: @"ObjFW"])) objc_autoreleasePoolPop(pool); } @end