import registrydef, strutils, typetraits, winlean type RegistryError* = object of ValueError const FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x100 FORMAT_MESSAGE_IGNORE_INSERTS = 0x200 FORMAT_MESSAGE_FROM_SYSTEM = 0x1000 ERROR_SUCCESS = 0 ERROR_FILE_NOT_FOUND = 2 USER_LANGUAGE = 0x0400 MAX_KEY_LEN = 255 MAX_VALUE_LEN = 16383 proc getErrorMessage(code: int32): string {.raises: [].} = var msgbuf: pointer when useWinUnicode: discard formatMessageW(FORMAT_MESSAGE_FROM_SYSTEM or FORMAT_MESSAGE_ALLOCATE_BUFFER or FORMAT_MESSAGE_IGNORE_INSERTS, nil, code, USER_LANGUAGE, msgbuf.addr, 0, nil) result = $cast[WideCString](msgbuf) else: discard formatMessageA(FORMAT_MESSAGE_FROM_SYSTEM or FORMAT_MESSAGE_ALLOCATE_BUFFER or FORMAT_MESSAGE_IGNORE_INSERTS, nil, code, USER_LANGUAGE, msgbuf.addr, 0, nil) result = $cast[CString](msgbuf) localFree(msgbuf) proc raiseError(code: int32) {.inline, raises: [RegistryError].} = raise newException(RegistryError, $code & ": " & getErrorMessage(code)) proc close*(this: RegistryKey) {.raises: [RegistryError].} = ## Closes the key and flushes it to disk if its contents have been modified. let code = regCloseKey(this) if unlikely(code != ERROR_SUCCESS): raiseError(code) proc createSubKey*(this: RegistryKey, subkey: string, writable: bool): RegistryKey {.raises: [RegistryError].} = ## Creates a new subkey or opens an existing subkey with the specified access. var createdHandle: RegistryKey when useWinUnicode: let code = regCreateKeyExW(this, newWideCString(subkey), 0, nil, 0, if writable: KEY_ALL_ACCESS else: KEY_READ, nil, createdHandle.addr, nil) else: let code = regCreateKeyExA(this, newCString(subkey), 0, nil, 0, if writable: KEY_ALL_ACCESS else: KEY_READ, nil, createdHandle.addr, nil) if unlikely(code != ERROR_SUCCESS): raiseError(code) return createdHandle proc createSubKey*(this: RegistryKey, subkey: string): RegistryKey {.raises: [RegistryError].} = ## Creates a new subkey or opens an existing subkey for write access. return this.createSubKey(subkey, true) proc deleteSubKey*(this: RegistryKey, subkey: string, raiseOnMissingSubKey: bool) {.raises: [RegistryError].} = ## Deletes the specified subkey, and specifies whether an exception is raised if the subkey is not found. when useWinUnicode: let code = regDeleteKeyW(this, newWideCString(subkey)) else: let code = regDeleteKeyA(this, newCString(subkey)) if unlikely(code != ERROR_SUCCESS) and (raiseOnMissingSubKey or code != ERROR_FILE_NOT_FOUND): raiseError(code) proc deleteSubKey*(this: RegistryKey, subkey: string) {.raises: [RegistryError].} = ## Deletes the specified subkey. this.deleteSubKey(subkey, true) proc deleteSubKeyTree*(this: RegistryKey, subkey: string, raiseOnMissingSubKey: bool) {.raises: [RegistryError].} = ## Deletes the specified subkey and any child subkeys recursively, and ## specifies whether an exception is raised if the subkey is not found. when useWinUnicode: let code = regDeleteTreeW(this, newWideCString(subkey)) else: let code = regDeleteTreeA(this, newCString(subkey)) if unlikely(code != ERROR_SUCCESS) and (raiseOnMissingSubKey or code != ERROR_FILE_NOT_FOUND): raiseError(code) proc deleteSubKeyTree*(this: RegistryKey, subkey: string) {.raises: [RegistryError].} = ## Deletes a subkey and any child subkeys recursively. this.deleteSubKeyTree(subkey, true) proc deleteValue*(this: RegistryKey, name: string, raiseOnMissingValue: bool) {.raises: [RegistryError].} = ## Deletes the specified value from this key, and specifies whether ## an exception is raised if the value is not found. when useWinUnicode: let code = regDeleteKeyValueW(this, nil, newWideCString(name)) else: let code = regDeleteKeyValueA(this, nil, newCString(name)) if unlikely(code != ERROR_SUCCESS) and (raiseOnMissingValue or code != ERROR_FILE_NOT_FOUND): raiseError(code) proc deleteValue*(this: RegistryKey, name: string) {.raises: [RegistryError].} = ## Deletes the specified value from this key. this.deleteValue(name, true) proc flush*(this: RegistryKey) {.raises: [RegistryError].} = ## Writes all the attributes of the specified open registry key into the registry. let code = regFlushKey(this) if unlikely(code != ERROR_SUCCESS): raiseError(code) iterator getSubKeyNames*(this: RegistryKey): string {.raises: [RegistryError].} = ## Retrieves an iterator of strings that runs over all the subkey names. var keyCount: int32 when useWinUnicode: let code = regQueryInfoKeyW(this, nil, nil, nil, keyCount.addr, nil, nil, nil, nil, nil, nil, nil) if unlikely(code != ERROR_SUCCESS): raiseError(code) var nameBuffer: WideCString unsafeNew(nameBuffer, (MAX_KEY_LEN + 1) * sizeof(Utf16Char)) for i in 0..