Что нового

Реестр (Registry) Получить файлы, находящиеся в контекстном меню \"Создать\"

saavaage

Знающий
Сообщения
171
Репутация
17
Вообщем, стоит задача найти в реестре и вывести в массив все файлы, которые прописаны в меню "Создать". Конечная цель этой манипуляции - получение возможности редактирования этого меню (удаление и добавление программ).

На данный момент получился такой скрипт:

Код:
#Include <Array.au3>
#Include <WinAPIEx.au3>

Opt('MustDeclareVars', 1)

Global $hKey, $hKeySub, $Count, $test, $Sub, $testSub

$hKey = _WinAPI_RegOpenKey($HKEY_LOCAL_MACHINE, 'SOFTWARE\Classes')
$Count = _WinAPI_RegQueryInfoKey($hKey)
Dim $aKey[$Count[0]]
Dim $aRas[1]

For $i = 0 To UBound($aKey) - 1
     $test = RegRead('HKEY_LOCAL_MACHINE\SOFTWARE\Classes\'&_WinAPI_RegEnumKey($hKey, $i)&'\ShellNew', 'NullFle')
    If @error <>1 Then
	   _ArrayAdd($aRas, _WinAPI_RegEnumKey($hKey, $i))
	Else
		$hKeySub = _WinAPI_RegOpenKey($HKEY_LOCAL_MACHINE, 'SOFTWARE\Classes\'&_WinAPI_RegEnumKey($hKey, $i)&'')
		$Sub = _WinAPI_RegQueryInfoKey($hKeySub)

        Dim $aKeySub[5];[$Sub[0]]
		For $p = 0 To UBound($aKeySub) - 1
          $testSub = RegRead('HKEY_LOCAL_MACHINE\SOFTWARE\Classes\'&_WinAPI_RegEnumKey($hKey, $i)&'\'& _WinAPI_RegEnumKey($hKeySub, $p)&'\ShellNew', 'NullFle')
;~ 		 MsgBox(0, '', @error)
         If @error <>1 Then   _ArrayAdd($aRas, _WinAPI_RegEnumKey($hKey, $i))
	    Next
	    _WinAPI_RegCloseKey($hKeySub)
	 Endif
Next
_WinAPI_RegCloseKey($hKey)

_ArrayDelete($aRas, 0)
_ArrayDisplay($aRas)

И все вроде хорошо, но мне надо, чтобы в этот список попадали только ключи (key), у которых есть значение (value) "NullFile"

Попробовал ставить доп. условие @error <> -1, на выходе получился вообще вред (все значения ветки)

Вот моя попытка-недокод:
Код:
#Include <Array.au3>
#Include <WinAPIEx.au3>

Opt('MustDeclareVars', 1)

Global $hKey, $hKeySub, $Count, $test, $Sub, $testSub

$hKey = _WinAPI_RegOpenKey($HKEY_LOCAL_MACHINE, 'SOFTWARE\Classes')
$Count = _WinAPI_RegQueryInfoKey($hKey)
Dim $aKey[$Count[0]]
Dim $aRas[1]

For $i = 0 To UBound($aKey) - 1
     $test = RegRead('HKEY_LOCAL_MACHINE\SOFTWARE\Classes\'&_WinAPI_RegEnumKey($hKey, $i)&'\ShellNew', 'NullFle')
;~  		MsgBox(0, '', @error)
    If @error <>1 OR @error <>-1 Then
	   _ArrayAdd($aRas, _WinAPI_RegEnumKey($hKey, $i))
	Else
		$hKeySub = _WinAPI_RegOpenKey($HKEY_LOCAL_MACHINE, 'SOFTWARE\Classes\'&_WinAPI_RegEnumKey($hKey, $i)&'')
		$Sub = _WinAPI_RegQueryInfoKey($hKeySub)

        Dim $aKeySub[5];[$Sub[0]]
		For $p = 0 To UBound($aKeySub) - 1
          $testSub = RegRead('HKEY_LOCAL_MACHINE\SOFTWARE\Classes\'&_WinAPI_RegEnumKey($hKey, $i)&'\'& _WinAPI_RegEnumKey($hKeySub, $p)&'\ShellNew', 'NullFle')
        If @error <>1 OR @error <>-1 Then   _ArrayAdd($aRas, _WinAPI_RegEnumKey($hKey, $i))
	    Next
	    _WinAPI_RegCloseKey($hKeySub)
	 Endif
Next
_WinAPI_RegCloseKey($hKey)

_ArrayDelete($aRas, 0)
_ArrayDisplay($aRas)
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,714
Код:
#Include <Array.au3>
#Include <WinAPIEx.au3>

Opt('MustDeclareVars', 1)

Global $hKey, $sKey, $hSubKey, $aData, $tData, $sData = '', $Count = 1

$tData = DllStructCreate('wchar[260]')
$hKey = _WinAPI_RegOpenKey($HKEY_LOCAL_MACHINE, 'SOFTWARE\Classes', $KEY_READ)
While 1
	$sKey = _WinAPI_RegEnumKey($hKey, $Count)
	If (@error) Or (StringLeft($sKey, 1) <> '.') Then
		ExitLoop
	EndIf
	$hSubKey = _WinAPI_RegOpenKey($hKey, $sKey & '\ShellNew', $KEY_READ)
	If Not @error Then
		If _WinAPI_RegQueryValue($hSubKey, 'NullFile', $tData) Then
			$sData &= $sKey & '|'
		EndIf
		_WinAPI_RegCloseKey($hSubKey)
	EndIf
	$Count += 1
WEnd
_WinAPI_RegCloseKey($hKey)
$aData = StringSplit(StringTrimRight($sData, 1), '|', 2)
_ArrayDisplay($aData)
 
Автор
S

saavaage

Знающий
Сообщения
171
Репутация
17
К сожалению, Ваш ответ выдает список из 6 файлов. Я старался вычленить еще и excel, word и т.д.
У меня тоже самое получилось в таком варианте:

Код:
#Include <Array.au3>
#Include <WinAPIEx.au3>

Opt('MustDeclareVars', 1)

Global $hKey, $hKeySub, $Count, $test, $Sub, $testSub

$hKey = _WinAPI_RegOpenKey($HKEY_LOCAL_MACHINE, 'SOFTWARE\Classes')
$Count = _WinAPI_RegQueryInfoKey($hKey)
Dim $aKey[$Count[0]]
Dim $aRas[1]

For $i = 0 To UBound($aKey) - 1
     $test = RegRead('HKEY_LOCAL_MACHINE\SOFTWARE\Classes\'&_WinAPI_RegEnumKey($hKey, $i)&'\ShellNew', 'NullFle')
    If @error <>1 Then  _ArrayAdd($aRas, _WinAPI_RegEnumKey($hKey, $i))
Next
_WinAPI_RegCloseKey($hKey)

_ArrayDelete($aRas, 0)
_ArrayDisplay($aRas)
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,714
saavaage сказал(а):
...у которых есть значение (value) "NullFile".

В таком случае, зачем ты написал это условие?

Код:
#Include <Array.au3>
#Include <WinAPIEx.au3>

Opt('MustDeclareVars', 1)

Global $hKey, $sKey, $hSubKey, $aData, $tData, $sData = '', $Count = 1

$tData = DllStructCreate('wchar[260]')
$hKey = _WinAPI_RegOpenKey($HKEY_LOCAL_MACHINE, 'SOFTWARE\Classes', $KEY_READ)
While 1
	$sKey = _WinAPI_RegEnumKey($hKey, $Count)
	If (@error) Or (StringLeft($sKey, 1) <> '.') Then
		ExitLoop
	EndIf
	$hSubKey = _WinAPI_RegOpenKey($hKey, $sKey & '\ShellNew', $KEY_READ)
	If Not @error Then
;		If _WinAPI_RegQueryValue($hSubKey, 'NullFile', $tData) Then
			$sData &= $sKey & '|'
;		EndIf
		_WinAPI_RegCloseKey($hSubKey)
	EndIf
	$Count += 1
WEnd
_WinAPI_RegCloseKey($hKey)
$aData = StringSplit(StringTrimRight($sData, 1), '|', 2)
_ArrayDisplay($aData)
 
Автор
S

saavaage

Знающий
Сообщения
171
Репутация
17
Дело в том, что проблема раскладывается на 6 частей:
1. ищем в ветке все каталоги с папкой "ShellNew" и они после отбора попадают в массив. На выходе получаем несколько файлов (у меня 6)
2. проверил свое контекстное меню и обнаружил там еще офисные файлы (и не только)
3. более углубленное изучение проблемы показало, что ряд (офисные в первую очередь) содержат "ShellNew" во втором уровне вложений (например, ".doc").
Так родился мой вариант скрипта, который отбирает не только "ShellNew" первого уровня, но и второго.
4. Получился довольно большой список, что вызвало у меня дополнительный вопрос о некорректности такого отбора.
5. Изучил в реестре каталоги тех файлов, которые у меня в контекстном меню и обнаружил закономерность - все они имеют в "ShellNew" пустой NullFile, в отличие от левых файлов, где в "ShellNew", кроме значения "(по умолчанию), больше ничего нет.
6. Логично было ввести в скрипт, кроме условия отбора @error <>1, еще и @error <>-1 ("-1 if unable to open requested value"). Однако вместо нормально фильтра, получил вывод всего списка..

Вот вкратце, мои рассуждения на эту тему.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,714
Во-первых, нужно искать не в HKLM, а в HKCR. Во-вторых, в разделе ShellNew нужно искать один из двух параметров: FileName или NullFile. В первом случае в качестве шаблона берется указанный файл, во втором - просто создается пустой файл. В обоих случаях, в контекстном меню появится соответствующий пункт. В Windows 7 вместо FileName может использоваться ItemName, что, видимо, тоже самое.

saavaage, нужно правильно ставить изначально задачу. Следующий код в точности повторяет мое контекстное меню "New"/"Создать". (Windows 7)

Код:
#Include <Array.au3>
#Include <WinAPIEx.au3>

Opt('MustDeclareVars', 1)

Global $hKey, $sKey, $hSubKey, $aData, $tData, $sData = '', $Count = 1

$tData = DllStructCreate('wchar[260]')
$hKey = _WinAPI_RegOpenKey($HKEY_LOCAL_MACHINE, 'SOFTWARE\Classes', $KEY_READ)
While 1
    $sKey = _WinAPI_RegEnumKey($hKey, $Count)
    If @error Then
        ExitLoop
    EndIf
    $hSubKey = _WinAPI_RegOpenKey($hKey, $sKey & '\ShellNew', $KEY_READ)
    If Not @error Then
       If (_WinAPI_RegQueryValue($hSubKey, 'NullFile', $tData)) Or (_WinAPI_RegQueryValue($hSubKey, 'FileName', $tData)) Or ()_WinAPI_RegQueryValue($hSubKey, 'ItemName', $tData) Then
            $sData &= $sKey & '|'
       EndIf
        _WinAPI_RegCloseKey($hSubKey)
    EndIf
    $Count += 1
WEnd
_WinAPI_RegCloseKey($hKey)
$aData = StringSplit(StringTrimRight($sData, 1), '|', 2)
_ArrayDisplay($aData)
 
Автор
S

saavaage

Знающий
Сообщения
171
Репутация
17
Yashied, ничего не изменилось. Офисные файлы так и не отображаются... :(

PS У меня XP SP3

на всякий случай, цитирую себя:
"3. более углубленное изучение проблемы показало, что ряд (офисные в первую очередь) содержат "ShellNew" во втором уровне вложений (например, ".doc").
Так родился мой вариант скрипта, который отбирает не только "ShellNew" первого уровня, но и второго."
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,714
Код:
#Include <Array.au3>
#Include <WinAPIEx.au3>

Opt('MustDeclareVars', 1)

Global $hKey, $sKey, $hSubKey, $sData, $tData, $aList, $sList = '', $Count = 1

$tData = DllStructCreate('wchar[260]')
$hKey = _WinAPI_RegOpenKey($HKEY_LOCAL_MACHINE, 'SOFTWARE\Classes', $KEY_READ)
While 1
	$sKey = _WinAPI_RegEnumKey($hKey, $Count)
	If @error Then
		ExitLoop
	EndIf
	$Count += 1
	$hSubKey = _WinAPI_RegOpenKey($hKey, $sKey & '\ShellNew', $KEY_READ)
	If @error Then
		If StringLeft($sKey, 1) <> '.' Then
			ContinueLoop
		EndIf
		$hSubKey = _WinAPI_RegOpenKey($hKey, $sKey, $KEY_READ)
		If @error Then
			ContinueLoop
		EndIf
		If _WinAPI_RegQueryValue($hSubKey, '', $tData) Then
			$sData = DllStructGetData($tData, 1)
		Else
			$sData = ''
		EndIf
		_WinAPI_RegCloseKey($hSubKey)
		If Not $sData Then
			ContinueLoop
		EndIf
		$hSubKey = _WinAPI_RegOpenKey($hKey, $sKey & '\' & $sData & '\ShellNew', $KEY_READ)
		If @error Then
			ContinueLoop
		EndIf
	EndIf
	If (_WinAPI_RegQueryValue($hSubKey, 'NullFile', $tData)) Or (_WinAPI_RegQueryValue($hSubKey, 'FileName', $tData)) Or (_WinAPI_RegQueryValue($hSubKey, 'ItemName', $tData)) Then
		$sList &= $sKey & '|'
	EndIf
	_WinAPI_RegCloseKey($hSubKey)
WEnd
_WinAPI_RegCloseKey($hKey)
$aList = StringSplit(StringTrimRight($sList, 1), '|', 2)
_ArrayDisplay($aList)
 
Автор
S

saavaage

Знающий
Сообщения
171
Репутация
17
Yashied, Вам впору менять подпись на "там где Yashied, там - Победа!" :smile: :smile: :smile:

Тема Решена.
 
Автор
S

saavaage

Знающий
Сообщения
171
Репутация
17
мы еще забыли про создание ярлыков... В связи с этим, небльшая коррекция конца скрипта Yashied:

Код:
If (_WinAPI_RegQueryValue($hSubKey, 'NullFile', $tData)) Or (_WinAPI_RegQueryValue($hSubKey, 'Command', $tData)) or (_WinAPI_RegQueryValue($hSubKey, 'FileName', $tData)) Or (_WinAPI_RegQueryValue($hSubKey, 'ItemName', $tData)) Then
        $sList &= $sKey & '|'
    EndIf
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,714
saavaage сказал(а):
мы еще забыли про создание ярлыков...

Вот это ты завернул! Каким боком _WinAPI_RegQueryValue($hSubKey, 'Command', $tData) связано с ярлыками???

:blink:
 
Автор
S

saavaage

Знающий
Сообщения
171
Репутация
17
Речь шла о контекстном меню и его редактировании, если помнишь. У меня там есть ярлык... Command - значение ветки .lnk (HKEY_CLASSES_ROOT\.lnk\ShellNew), по которому я его и отфильтровал..

Вопрос, не могу разобраться с
DllStructCreate, DllStructGetData. Что это такое и с чем его едят? Технология его применения в данном скрипте? Хоть немного просвети, плиз... На худой конец, можно ли обойтись без него?

У меня самый мин. список в массив выводится таким скриптом.

Код:
#Include <Array.au3>
#Include <WinAPIEx.au3>

Opt('MustDeclareVars', 1)

Global $hKey, $hKeySub, $Count, $test1, $test2, $test3, $Sub, $testSub1, $testSub2, $testSub3

$hKey = _WinAPI_RegOpenKey($HKEY_CLASSES_ROOT)
$Count = _WinAPI_RegQueryInfoKey($hKey)
Dim $aKey[$Count[0]]
Dim $aRas[1]

For $i = 0 To UBound($aKey) - 1
 IF StringLeft(_WinAPI_RegEnumKey($hKey, $i), 1) = '.' Then
    $test1 = RegRead('HKCR\'&_WinAPI_RegEnumKey($hKey, $i)&'\ShellNew', 'NullFile')
	If not @error  then
		_ArrayAdd($aRas, _WinAPI_RegEnumKey($hKey, $i))
		ContinueLoop
	EndIf

	$test2 = RegRead('HKCR\'&_WinAPI_RegEnumKey($hKey, $i)&'\ShellNew', 'Command')
	If not @error  Then
		_ArrayAdd($aRas, _WinAPI_RegEnumKey($hKey, $i))
		ContinueLoop
	EndIf

	$test3 = RegRead('HKCR\'&_WinAPI_RegEnumKey($hKey, $i)&'\ShellNew', 'FileName')
	If not @error  Then
		_ArrayAdd($aRas, _WinAPI_RegEnumKey($hKey, $i))
		ContinueLoop
	EndIf

    $hKeySub = _WinAPI_RegOpenKey($HKEY_CLASSES_ROOT, '\'&_WinAPI_RegEnumKey($hKey, $i)&'')
    $Sub = _WinAPI_RegQueryInfoKey($hKeySub)
    Dim $aKeySub[5]

  For $p = 0 To UBound($aKeySub) - 1
   $testSub1 = RegRead('HKCR\'&_WinAPI_RegEnumKey($hKey, $i)&'\'& _WinAPI_RegEnumKey($hKeySub, $p)&'\ShellNew', 'NullFile')
    If not @error  Then
		  _ArrayAdd($aRas, _WinAPI_RegEnumKey($hKey, $i))
		  ContinueLoop
    EndIf

	$testSub3 = RegRead('HKCR\'&_WinAPI_RegEnumKey($hKey, $i)&'\'& _WinAPI_RegEnumKey($hKeySub, $p)&'\ShellNew', 'Filename')
	If not @error  Then
          _ArrayAdd($aRas, _WinAPI_RegEnumKey($hKey, $i))
		  ContinueLoop
    EndIf
  Next
  _WinAPI_RegCloseKey($hKeySub)
  Endif
Next
_WinAPI_RegCloseKey($hKey)


_ArrayDisplay($aRas)

Ума не приложу, как у тебя получилось дать точный вывод.. Возьмем, например, .ppt и .pptx - у них же и там и там есть в ShellNew значение Filename... Если не сложно, просвети, как твой скрипт их различает (т.е. выводит в массив .pptx, а .ppt игнорирует)...
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,714
Я не могу понять, зачем ты используешь одновременно и _WinAPI_Reg..., и Reg... функции. Это глупо. А структура в моем примере нужна для того, чтобы считать значение в разделе ShellNew. Структура, это просто выделенная область памяти, куда собственно и помещает данные функция _WinAPI_RegQueryValue(). Так уж работают большинство функций в WinAPI.

Ответ на второй вопрос (ShellNew ищем только в этих подразделах):

Template.png
 
Автор
S

saavaage

Знающий
Сообщения
171
Репутация
17
Yashied, не подскажешь, как с помощью твоего скрипта вывести в массив не просто название файла, а полный путь к нему...

PS Пробовал сегодня разобрать твой скрипт, но еще слишком "мал" - понимаю через раз. По крайней мере, модернизировать под эту задачу не смог :(
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,714
Что ты имеешь в виду под "названием фйла"? Путь в реестре?
 
Автор
S

saavaage

Знающий
Сообщения
171
Репутация
17
мне желательно получить в 1 столбце название расширения файла (например, .docx), во-втором - путь к ShellNew (например, HKLM\SOFTWARE\Classes\.docx\Word.Document.12\ShellNew).

Цель - хочу получить возможность редактирования пунктов меню "Создать"
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,714
Код:
#Include <Array.au3>
#Include <WinAPIEx.au3>

Opt('MustDeclareVars', 1)

Global $hKey, $sKey, $hSubKey, $sData, $tData, $aList, $sList = '', $Count = 1

$tData = DllStructCreate('wchar[260]')
$hKey = _WinAPI_RegOpenKey($HKEY_CLASSES_ROOT, '', $KEY_READ)
While 1
	$sData = ''
    $sKey = _WinAPI_RegEnumKey($hKey, $Count)
    If @error Then
        ExitLoop
    EndIf
    $Count += 1
    $hSubKey = _WinAPI_RegOpenKey($hKey, $sKey & '\ShellNew', $KEY_READ)
    If @error Then
        If StringLeft($sKey, 1) <> '.' Then
            ContinueLoop
        EndIf
        $hSubKey = _WinAPI_RegOpenKey($hKey, $sKey, $KEY_READ)
        If @error Then
            ContinueLoop
        EndIf
        If _WinAPI_RegQueryValue($hSubKey, '', $tData) Then
            $sData = DllStructGetData($tData, 1)
        Else
            $sData = ''
        EndIf
        _WinAPI_RegCloseKey($hSubKey)
        If Not $sData Then
            ContinueLoop
        EndIf
        $hSubKey = _WinAPI_RegOpenKey($hKey, $sKey & '\' & $sData & '\ShellNew', $KEY_READ)
        If @error Then
            ContinueLoop
        EndIf
    EndIf
    If (_WinAPI_RegQueryValue($hSubKey, 'NullFile', $tData)) Or (_WinAPI_RegQueryValue($hSubKey, 'FileName', $tData)) Or (_WinAPI_RegQueryValue($hSubKey, 'ItemName', $tData)) Then
        $sList &= StringRegExpReplace('HKEY_CLASSES_ROOT\' & $sKey & '\' & $sData, '\\*\Z', '') & '\ShellNew' & '|'
    EndIf
    _WinAPI_RegCloseKey($hSubKey)
WEnd
_WinAPI_RegCloseKey($hKey)
$aList = StringSplit(StringTrimRight($sList, 1), '|', 2)
_ArrayDisplay($aList)
 
Верх