Автор Тема: Дополнительные функции для работы с реестром  (Прочитано 34294 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн assch [?]

  • Новичок
  • *
  • Сообщений: 166
  • Репутация: 4
    • Награды
Отлично
Спасибо Yashied
Прости за наглость не подскажешь как избавится от пробелов
между строками а то файл получается в два раза больше

Русское сообщество AutoIt

Re: Дополнительные функции для работы с реестром
« Ответ #15 Отправлен: Октябрь 08, 2010, 15:54:07 »

Оффлайн Yashied [?]

  • AutoIt MVP
  • Глобальный модератор
  • *
  • Сообщений: 5379

  • Автор темы
  • Репутация: 2695
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.x.x
Код: AutoIt [Выделить]
#Include <Constants.au3>
#Include <WinAPIEx.au3>

$sReg = _RegExportEx('HKEY_CLASSES_ROOT', 'r.reg')
If @error Then
    ConsoleWrite(_WinAPI_GetErrorMessage(@extended) & @CR)
Else
;    ConsoleWrite($sReg & @CR)
EndIf

Func _RegExportEx($sKey, $sFile = '', $fAssurance = 0)

    Local $aData = StringSplit(StringUpper($sKey), '\', 2)
    Local $tData, $hRoot, $sRoot, $sReg = ''
    Local $Error = 1

    If Not IsArray($aData) Then
        Return SetError(1, 0, '')
    EndIf

    Switch $aData[0]
        Case 'HKEY_CLASSES_ROOT', 'HKEY_CURRENT_USER', 'HKEY_LOCAL_MACHINE', 'HKEY_USERS', 'HKEY_CURRENT_CONFIG'
            $sRoot = $aData[0]
        Case 'HKCR'
            $sRoot = 'HKEY_CLASSES_ROOT'
        Case 'HKCU'
            $sRoot = 'HKEY_CURRENT_USER'
        Case 'HKLM'
            $sRoot = 'HKEY_LOCAL_MACHINE'
        Case 'HKU'
            $sRoot = 'HKEY_USERS'
        Case 'HKCC'
            $sRoot = 'HKEY_CURRENT_CONFIG'
        Case Else
            Return SetError(1, 0, '')
    EndSwitch
    $sKey = StringTrimLeft($sKey, StringLen($aData[0]) + 1)
    Do
        $hRoot = _WinAPI_RegOpenKey(Eval($sRoot), $sKey, BitOR($KEY_ENUMERATE_SUB_KEYS, $KEY_QUERY_VALUE))
        If @error Then
            ExitLoop
        EndIf
        $tData = DllStructCreate('byte[1048576]')
        If Not _RegEnumProc($hRoot, StringRegExpReplace($sRoot & '\' & $sKey, '\\*\Z', ''), $fAssurance, $sReg, $tData) Then
            ExitLoop
        EndIf
        $Error = 0
    Until 1
    If $Error Then
        Switch @extended
            Case 0
                $Error = -1
            Case Else
                $Error = @extended
        EndSwitch
    EndIf
    If $hRoot Then
        _WinAPI_RegCloseKey($hRoot)
    EndIf
    If $Error Then
        Return SetError(2, $Error, '')
    EndIf
    If $sFile Then
        $hFile = FileOpen($sFile, 2 + 32)
        If $hFile = -1 Then
            Return SetError(3, 0, '')
        EndIf
        If Not FileWrite($hFile, 'Windows Registry Editor Version 5.00' & @CRLF & @CRLF & $sReg) Then
            $Error = 1
        EndIf
        FileClose($hFile)
        If $Error Then
            Return SetError(3, 0, '')
        EndIf
        Return 1
    EndIf
    Return $sReg
EndFunc   ;==>_RegExportEx

Func _RegEnumProc($hRoot, $sRoot, $fAssurance, ByRef $sData, ByRef $tData, $sParam = 0)

    Local $hKey, $sKey, $sVal, $Pos, $Size, $Type
    Local $pData = DllStructGetPtr($tData)
    Local $Count = 0, $Error = 0

    If $sParam Then
        $sData &= '[' & $sRoot & '\' & $sParam & ']' & @CRLF
    Else
        $sData = '[' & $sRoot & ']' & @CRLF
    EndIf

#cs

    While 1
        $sVal = _WinAPI_RegEnumValue($hRoot, $Count)
        If @error Then
            Switch @extended
                Case 259 ; ERROR_NO_MORE_ITEMS
                    ExitLoop
                Case Else
                    Return SetError(1, @extended, 0)
            EndSwitch
        EndIf
        $Size = _WinAPI_RegQueryValue($hRoot, $sVal, $tData)
        If @error Then
            Return SetError(1, @extended, 0)
        EndIf
        $Type = @extended
        If $sVal Then
            $sVal = '"' & StringReplace(StringReplace($sVal, '\', '\\'), '"', '\"') & '"='
        Else
            $sVal = '@='
        EndIf
        If Not $Size Then
            Switch $Type
                Case 1 ; REG_SZ
                    $sVal &= '""'
                Case Else
                    Switch $Type
                        Case 3 ; REG_BINARY
                            $sVal &= 'hex:'
                        Case Else
                            $sVal &= 'hex(' & StringLower(Hex($Type, 1)) & '):'
                    EndSwitch
            EndSwitch
        Else
            Switch $Type
                Case 1 ; REG_SZ
                    $sVal &= '"' & StringReplace(StringReplace(DllStructGetData(DllStructCreate('wchar[' & $Size & ']', $pData), 1), '\', '\\'), '"', '\"') & '"'
                Case 4 ; REG_DWORD
                    $sVal &= 'dword:' & StringLower(Hex(Number(DllStructGetData(DllStructCreate('dword', $pData), 1))))
                Case Else
                    Switch $Type
                        Case 3 ; REG_BINARY
                            $sVal &= 'hex:'
                        Case Else
                            $sVal &= 'hex(' & StringLower(Hex($Type, 1)) & '):'
                    EndSwitch
                    $sVal &= StringTrimRight(StringRegExpReplace(StringLower(StringTrimLeft(DllStructGetData(DllStructCreate('byte[' & $Size & ']', $pData), 1), 2)), '(.{2})', '\1,'), 1)
                    $Pos = StringInStr($sVal, ',', 0, 1, 77)
                    If $Pos Then
                        $sVal = StringLeft($sVal, $Pos) & '\' & @CRLF & '  ' & StringRegExpReplace(StringTrimLeft($sVal, $Pos), '(.{75})', '\1\\' & @CRLF & '  ')
                    EndIf
            EndSwitch
        EndIf
        $sData &= $sVal & @CRLF
        $Count += 1
    WEnd
    $Count = 0

#ce


    While 1
        $sKey = _WinAPI_RegEnumKey($hRoot, $Count)
        If @error Then
            Switch @extended
                Case 259 ; ERROR_NO_MORE_ITEMS
                    ExitLoop
                Case Else
                    Return SetError(1, @extended, 0)
            EndSwitch
        EndIf
        $hKey = _WinAPI_RegOpenKey($hRoot, $sKey, BitOR($KEY_ENUMERATE_SUB_KEYS, $KEY_QUERY_VALUE))
        If @error Then
            If $fAssurance Then
                Return SetError(1, @extended, 0)
            EndIf
        Else
            If $sParam Then
                _RegEnumProc($hKey, $sRoot, $fAssurance, $sData, $tData, $sParam & '\' & $sKey)
            Else
                _RegEnumProc($hKey, $sRoot, $fAssurance, $sData, $tData, $sKey)
            EndIf
            If @error Then
                Switch @extended
                    Case 0
                        $Error = -1
                    Case Else
                        $Error = @extended
                EndSwitch
            EndIf
        EndIf
        If $hKey Then
            _WinAPI_RegCloseKey($hKey)
        EndIf
        $Count += 1
        If $Error Then
            ExitLoop
        EndIf
    WEnd
    If $Error Then
        Return SetError(1, $Error, 0)
    Else
        Return 1
    EndIf
EndFunc   ;==>_RegEnumProc



Думай, прежде чем говорить.

Оффлайн assch [?]

  • Новичок
  • *
  • Сообщений: 166
  • Репутация: 4
    • Награды
 :IL_AutoIt_1:
Интересно вроде бы та функция была простенькая обычная рекурсия а работает медленнее
 

Оффлайн Yashied [?]

  • AutoIt MVP
  • Глобальный модератор
  • *
  • Сообщений: 5379

  • Автор темы
  • Репутация: 2695
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.x.x
Потому что RegEnum... являются самодостаточными функциями, т.е. при каждом вызове они открывают раздел, считывают данные, а затем закрывают раздел. При следующем вызове все повторяется. Плюс внутренний код и всякие проверки. Если использовать _WinAPI_Reg... функции, то достаточно один раз открыть раздел, сделать там все, что нужно, и затем закрыть его. Сильное падение скорости для RegEnum... происходит именно из-за постоянных открытий-закрытий. Но зато они относительно просты в использовании.

Русское сообщество AutoIt

Re: Дополнительные функции для работы с реестром
« Ответ #18 Отправлен: Октябрь 08, 2010, 16:38:39 »

Оффлайн assch [?]

  • Новичок
  • *
  • Сообщений: 166
  • Репутация: 4
    • Награды
Спасибо за разъяснение.
Функция и в правду работает быстрее делает снимок ключей этой ветки за 13 секунд.
Для справки:
Не подскажешь можно ли эту функцию или часть этого кода перегнать на ассемблер
то есть сделать ассемблерную вставку, работа с регистрами наверное будет идти
быстрее чем с переменными или нет?


Добавлено: Октябрь 08, 2010, 17:12:18
Интересная деталь
если функцию прогнать так
Код: AutoIt [Выделить]
$sReg = _RegExportEx('HKEY_CLASSES_ROOT', 'r.reg')

то она создаст файл r.reg весом 5.44мб
а если так
Код: AutoIt [Выделить]
$sReg = _RegExportEx('HKEY_CLASSES_ROOT')
FileWrite("r.reg", $sReg)
FileClose("r.reg")

то она создаст такой же файл с таким же количеством строк (кроме первой строчки)
но вес у него 2.72мб

« Последнее редактирование: Октябрь 08, 2010, 17:36:05 от assch, Причина: Объединение сообщений »

Оффлайн Yashied [?]

  • AutoIt MVP
  • Глобальный модератор
  • *
  • Сообщений: 5379

  • Автор темы
  • Репутация: 2695
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.x.x
В первом случае - Unicode.

Код: AutoIt [Выделить]
FileOpen($sFile, 2 + 32)


Оффлайн Yashied [?]

  • AutoIt MVP
  • Глобальный модератор
  • *
  • Сообщений: 5379

  • Автор темы
  • Репутация: 2695
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.x.x
Во втором случае FileClose("r.reg") вообще лишний.

:)

Оффлайн assch [?]

  • Новичок
  • *
  • Сообщений: 166
  • Репутация: 4
    • Награды
Вот что с вашей большой помощью удалось сделать
Функция для снятия ключей реестра
За основу взял ваши функции.
Пришлось комбинировать снимать двумя способами.
Ваша функция отлично снимает ключи на ветки HKCR -13 секунд против 57 секунд.
А вот на остальных ветках отстаёт например ветку HKLM -17 секунд против 4 секунд.
Не беда как говорится одна голова хорошо а две лучше.
Не посмотрите на предмет оптимизации?

(нажмите для показа/скрытия)

Русское сообщество AutoIt

Re: Дополнительные функции для работы с реестром
« Ответ #22 Отправлен: Октябрь 08, 2010, 20:20:00 »

Оффлайн Yashied [?]

  • AutoIt MVP
  • Глобальный модератор
  • *
  • Сообщений: 5379

  • Автор темы
  • Репутация: 2695
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.x.x
Ваша функция отлично снимает ключи на ветки HKCR -13 секунд против 57 секунд.
А вот на остальных ветках отстаёт например ветку HKLM -17 секунд против 4 секунд.

Я не знаю почему так происходит. Даже разработчики AutoIt ничего путного по этому поводу не смогли сказать. Остается использовать RegEnumKey() для перечисления разделов в тех ветвях, где _WinAPI_RegEnumKey() проигрывает. Но я думаю, что такое положение вещей будет иметь место только для перечисления разделов. Если перечислять переменные, то RegEnumVal(), будет значительно уступать _WinAPI_RegEnumValue().


Добавлено: Октябрь 09, 2010, 02:09:00
По поводу оптимизации. Я советую тебе присмотреться к функции _WinAPI_RegQueryLastWriteTime(). Ее очень удобно использовать перед перечислением переменных в каждом разделе. Если любой параметр в опрашиваемом разделе изменится, будет удален или добавлен, то измениться соответственно и время последней модификации раздела. Чтобы лишний раз не перечислять переменные и считывать их значения, можно сравнить только времена модификаций. Это должно существенно повысить скорость сравнения снимков разделов реестра.
« Последнее редактирование: Октябрь 09, 2010, 02:09:00 от Yashied, Причина: Объединение сообщений »

Оффлайн assch [?]

  • Новичок
  • *
  • Сообщений: 166
  • Репутация: 4
    • Награды
Для этого как минимум нужно вытащить и записать значения последней модификации хотя бы ключей первой вложенности.
Кстати ключи первой вложенности любой ветки реестра можно вытащить и записать практически мнгновенно. Не исключено что такой метод повысит скорость выявления изменений в реестре. А вот как приспособить функцию _WinAPI_RegQueryLastWriteTime()
чтобы сделать список последней модификации этих ключей?

Оффлайн assch [?]

  • Новичок
  • *
  • Сообщений: 166
  • Репутация: 4
    • Награды
Yashied

 Есть функция RegNotifyChangeKeyValue
В твоей библиотеке WinAPIEx.au3 её нет. Не подскажешь как с ней работать?
По описанию и параметрам вроде бы тоже заточена для отслеживания изменений в реестре.
Не большое описание:
(нажмите для показа/скрытия)

 Попробывал коряво её собрать но скорее всего не правильно.
Код: AutoIt [Выделить]
#Include <WinAPIEx.au3>

$hKey = _WinAPI_RegOpenKey($HKEY_CLASSES_ROOT, ".djvu")
DllCall ( "Advapi32.dll", "int", "RegNotifyChangeKeyValue", "hwnd", $hKey, "int", TRUE, "int", 0x00000001, "int", FALSE, "int", TRUE)


Оффлайн Yashied [?]

  • AutoIt MVP
  • Глобальный модератор
  • *
  • Сообщений: 5379

  • Автор темы
  • Репутация: 2695
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.x.x
Там, откуда ты взял это описание, очень подробно рассказано, как работать с этой функцией. В AutoIt, использовать ее будет проблематично, т.к. не поддерживаются потоки. Скрипт будет все время в "зависшем" состоянии, ожидая изменений в реестре.

Оффлайн assch [?]

  • Новичок
  • *
  • Сообщений: 166
  • Репутация: 4
    • Награды
Извини Yashied
Я просто думал что с её помощью тоже можно снять какие то данные и при втором заходе сравнить ,но если нельзя значит нельзя.
По твоему совету попробывал приспособить функцию _WinAPI_RegQueryLastWriteTime()
Посмотри пожалуйста может что то не так или что то лишнее.

Код: AutoIt [Выделить]
#Include <WinAPIEx.au3>

$a = "HKEY_LOCAL_MACHINE"
Global $sData

_KeyList($a)
$Txt = FileOpen("1.txt",2)
FileWrite($Txt, $sData)
FileClose($Txt)

Func _KeyList($key)
$i = 1
While 1
$var = RegEnumKey($key, $i)
If @error <> 0 then ExitLoop
$Array = $key&"\"& $var
$w1 = StringInStr($Array,"\",0,1)
$w2 = StringTrimLeft($Array, $w1)
$hKey = _WinAPI_RegOpenKey($HKEY_LOCAL_MACHINE, $w2)
$tTime = _WinAPI_RegQueryLastWriteTime($hKey)
_WinAPI_RegCloseKey($hKey)
$sData &= $a & '\' & $w2 & '\' & DllStructGetData($tTime, 1) & @CRLF
$i = $i + 1
_KeyList($key&"\"&$var)            
WEnd  
EndFunc


Оффлайн Yashied [?]

  • AutoIt MVP
  • Глобальный модератор
  • *
  • Сообщений: 5379

  • Автор темы
  • Репутация: 2695
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.x.x
Есть функция RegNotifyChangeKeyValue()...

Немного поздно, но...

Код: AutoIt [Выделить]
Global Const $REG_NOTIFY_CHANGE_NAME = 0x01
Global Const $REG_NOTIFY_CHANGE_ATTRIBUTES = 0x02
Global Const $REG_NOTIFY_CHANGE_LAST_SET = 0x04
Global Const $REG_NOTIFY_CHANGE_SECURITY = 0x08

; #FUNCTION# ====================================================================================================================
; Name...........: _WinAPI_RegNotifyChangeKeyValue
; Description....: Notifies the caller about changes to the attributes or contents of a specified registry key.
; Syntax.........: _WinAPI_RegNotifyChangeKeyValue ( $hKey, $iFilter [, $fSubtree [, $fAsync [, $hEvent]]] )
; Parameters.....: $hKey     - Handle to an open registry key. The key must have been opened with the KEY_NOTIFY access right.
;                              This handle is returned by the _WinAPI_RegCreateKey() or _WinAPI_RegOpenKey() function. It can also
;                              be one of the following predefined keys.
;
;                              $HKEY_CLASSES_ROOT
;                              $HKEY_CURRENT_CONFIG
;                              $HKEY_CURRENT_USER
;                              $HKEY_LOCAL_MACHINE
;                              $HKEY_USERS
;
;                  $iFilter  - Indicates the changes that should be reported. This parameter can be one or more of the following values.
;
;                              $REG_NOTIFY_CHANGE_NAME
;                              $REG_NOTIFY_CHANGE_ATTRIBUTES
;                              $REG_NOTIFY_CHANGE_LAST_SET
;                              $REG_NOTIFY_CHANGE_SECURITY
;
;                  $fSubtree - Specifies whether report changes in the subkeys of the specified key, valid values:
;                  |TRUE     - The function reports changes in the specified key and all its subkeys.
;                  |FALSE    - The function reports changes only in the specified key. (Default)
;                  $fAsync   - Specifies whether return immediately, valid values:
;                  |TRUE     - The function returns immediately and reports changes by signaling the specified event.
;                  |FALSE    - The function does not return until a change has occurred. (Default)
;                  $hEvent   - Handle to an event. If the $fAsync parameter is TRUE, the function returns immediately and changes are
;                              reported by signaling this event, otherwise this parameter is ignored.
; Return values..: Success   - 1.
;                  Failure   - 0 and sets the @error flag to non-zero, @extended flag may contain the system error code.
; Author.........: Yashied
; Modified.......:
; Remarks........: If the specified key is closed, the event is signaled. This means that an application should not depend on the
;                  key being open after returning from a wait operation on the event.
; Related........:
; Link...........: @@[email protected]@ RegNotifyChangeKeyValue
; Example........: Yes
; ===============================================================================================================================

Func _WinAPI_RegNotifyChangeKeyValue_($hKey, $iFilter, $fSubtree = 0, $fAsync = 0, $hEvent = 0)

    Local $Ret = DllCall('advapi32.dll', 'long', 'RegNotifyChangeKeyValue', 'ulong_ptr', $hKey, 'int', $fSubtree, 'dword', $iFilter, 'ptr', $hEvent, 'int', $fAsync)

    If @error Then
        Return SetError(1, 0, 0)
    Else
        If $Ret[0] Then
            Return SetError(1, $Ret[0], 0)
        EndIf
    EndIf
    Return 1
EndFunc   ;==>_WinAPI_RegNotifyChangeKeyValue

#Include <WinAPIEx.au3>

$hKey = _WinAPI_RegOpenKey($HKEY_CURRENT_USER, 'Software\Microsoft\Windows\CurrentVersion\Run', $KEY_NOTIFY)
If _WinAPI_RegNotifyChangeKeyValue_($hKey, $REG_NOTIFY_CHANGE_LAST_SET) Then
    MsgBox(48, 'Registry', 'The registry hive has been modified.' & @CR & @CR & 'HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run')
EndIf
_WinAPI_RegCloseKey($hKey)


Во время ожидания изменений, скрипт будет приостановлен. Возможно лучше будет запустить эту функцию в отдельном процессе, и при изменениях в соответствующем ключе, он (процесс) будет сигнализировать об этом в основную программу.
« Последнее редактирование: Октябрь 26, 2010, 15:21:48 от Yashied »

Оффлайн assch [?]

  • Новичок
  • *
  • Сообщений: 166
  • Репутация: 4
    • Награды
Yashied не подскажешь какое значение можно подставить вместо фильтра $REG_NOTIFY_CHANGE_LAST_SET а то выдаёт ошибку
(нажмите для показа/скрытия)

Русское сообщество AutoIt

Re: Дополнительные функции для работы с реестром
« Ответ #29 Отправлен: Октябрь 26, 2010, 15:09:44 »

 

Похожие темы

  Тема / Автор Ответов Последний ответ
16 Ответов
12708 Просмотров
Последний ответ Май 24, 2015, 00:16:05
от WSWR
5 Ответов
5467 Просмотров
Последний ответ Апрель 27, 2011, 15:15:41
от anonymous7
14 Ответов
9671 Просмотров
Последний ответ Март 21, 2011, 20:06:47
от Kalisnik
9 Ответов
5332 Просмотров
Последний ответ Март 09, 2011, 00:48:18
от JimmyN
6 Ответов
3363 Просмотров
Последний ответ Апрель 01, 2012, 13:29:22
от Garrett
0 Ответов
1823 Просмотров
Последний ответ Апрель 01, 2012, 00:16:10
от CreatoR
14 Ответов
13250 Просмотров
Последний ответ Март 21, 2014, 22:32:34
от Garrett
2 Ответов
3599 Просмотров
Последний ответ Сентябрь 27, 2013, 09:23:06
от black1
1 Ответов
1006 Просмотров
Последний ответ Ноябрь 08, 2014, 21:52:13
от winstan
10 Ответов
2658 Просмотров
Последний ответ Декабрь 22, 2016, 10:03:04
от chaos-13