Что нового

Реестр (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 712
Код:
#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 712
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 712
Во-первых, нужно искать не в 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 712
Код:
#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 712
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 712
Я не могу понять, зачем ты используешь одновременно и _WinAPI_Reg..., и Reg... функции. Это глупо. А структура в моем примере нужна для того, чтобы считать значение в разделе ShellNew. Структура, это просто выделенная область памяти, куда собственно и помещает данные функция _WinAPI_RegQueryValue(). Так уж работают большинство функций в WinAPI.

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

 
Автор
S

saavaage

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

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

Yashied

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

saavaage

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

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

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5 379
Репутация
2 712
Код:
#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)
 
Верх