Вопрос или проблема
Я использую Inno Setup, чтобы проверить, установлены ли определённые приложения (начинающиеся с “XYZ”) на системе, ищя ключи реестра Uninstall. Мой скрипт проверяет как 32-битные, так и 64-битные разделы Uninstall, но он не всегда находит приложения, особенно когда ищет 32-битные приложения на 64-битной системе или наоборот.
Например, код, похоже, вообще не находит Notepad++ согласно логу, эта запись существует в моем реестре, но лог не показывает её;
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Notepad++
function IsXYZInstalled: Boolean;
var
KeyNames: array[0..3] of String;
i, j: Integer;
SubkeyNames: TArrayOfString;
SubkeyNames2: TArrayOfString;
DisplayName: String;
begin
Result := False;
// Инициализировать массив путей реестра для ключей Uninstall
KeyNames[0] := 'Software\Microsoft\Windows\CurrentVersion\Uninstall';
KeyNames[1] := 'Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall';
// Перебирать каждый путь реестра
for i := 0 to 1 do
begin
log('начать HKEY_CURRENT_USER USER '+KeyNames[i]);
// Получить список подкладеров (каждый представляет установленное приложение)
if RegGetSubkeyNames(HKEY_CURRENT_USER, KeyNames[i], SubkeyNames) then
begin
// Перебирать каждый подкласс
for j := 0 to GetArrayLength(SubkeyNames) - 1 do
begin
log (inttostr(j)+ ' ' +KeyNames[i] + '\' + SubkeyNames[j]);
log(DisplayName);
// Попробовать прочитать значение DisplayName для каждого подкласса
if RegQueryStringValue(HKEY_CURRENT_USER, KeyNames[i] + '\' + SubkeyNames[j], 'DisplayName', DisplayName) then
begin
// Проверить, начинается ли DisplayName с "XYZ"
if Pos('XYZ', DisplayName) = 1 then
begin
Result := True;
Exit;
end;
end;
end;
end;
end;
// Перебирать каждый путь реестра
for i := 0 to 1 do
begin
log('НАЧАЛО HKEY_LOCAL_MACHINE\'+KeyNames[i]);
// Получить список подкладеров (каждый представляет установленное приложение)
if RegGetSubkeyNames(HKEY_LOCAL_MACHINE, KeyNames[i], SubkeyNames2) then
begin
// Перебирать каждый подкласс
for j := 0 to GetArrayLength(SubkeyNames2) - 1 do
begin
log (inttostr(j)+ ' HKEY_LOCAL_MACHINE ' +KeyNames[i] + '\' + SubkeyNames2[j]);
// Попробовать прочитать значение DisplayName для каждого подкласса
if RegQueryStringValue(HKEY_LOCAL_MACHINE, KeyNames[i] + '\' + SubkeyNames2[j], 'DisplayName', DisplayName) then
begin
log (inttostr(j)+ ' !HKEY_LOCAL_MACHINE ' +KeyNames[i] + '\' + SubkeyNames2[j]+'\'+DisplayName);
// Проверить, начинается ли DisplayName с "XYZ"
if Pos('XYZ', DisplayName) = 1 then
begin
Result := True;
Exit;
end;
end;
end;
end;
end;
end;
Ответ или решение
Ваш Inno Setup скрипт может не обнаруживать 32-разрядные или 64-разрядные приложения в реестре, по нескольким причинам, связанным с архитектурными нюансами Windows и некоторыми особенностями вашего кода. В этом ответе мы подробно рассмотрим причины и предложим решения.
1. Архитектурные аспекты Windows
Существует различие между 32-разрядными и 64-разрядными приложениями в контексте работы с реестром в Windows. 64-разрядные ОС в обязательном порядке поддерживают 32-разрядные приложения, но информация о них хранится в отдельном пространстве реестра — HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node
. Ваш код должен работать с этим, и вы это правильно учли, однако есть несколько нюансов, которые могут вызвать проблемы.
2. Корректное обращение к реестру
По вашему коду видно, что вы дважды обращаетесь к HKEY_CURRENT_USER
и HKEY_LOCAL_MACHINE
, но не указали для каждого из этих случаев, к какому пространству реестра (32-разрядному или 64-разрядному) вы обращаетесь. Если ваш скрипт работает на 64-разрядной системе, а вы пытаетесь получить доступ к 32-разрядному ключу, вам нужно использовать соответствующие функции.
if RegGetSubkeyNames(HKEY_LOCAL_MACHINE, KeyNames[i], SubkeyNames) then
здесь должно быть обеспечено правильное обращение к 32/64-разрядным значениям.
3. Обработка реестра
Убедитесь, что вы правильно проверяете наличие нужного ключа. Например, возможно, что Notepad++ установлен как 32-разрядное приложение на 64-разрядной системе. Поэтому вам следует всегда проверять оба пространства реестра:
// Ищем в HKEY_LOCAL_MACHINE
for i := 0 to 1 do
begin
log('Поиск в HKEY_LOCAL_MACHINE ' + KeyNames[i]);
if RegGetSubkeyNames(HKEY_LOCAL_MACHINE, KeyNames[i], SubkeyNames2) then
begin
for j := 0 to GetArrayLength(SubkeyNames2) - 1 do
begin
if RegQueryStringValue(HKEY_LOCAL_MACHINE, KeyNames[i] + '\' + SubkeyNames2[j], 'DisplayName', DisplayName) then
begin
if Pos('XYZ', DisplayName) = 1 then
begin
Result := True; // Найдено нужное приложение
Exit;
end;
end;
end;
end;
end;
4. Логи и отладка
Обратите внимание на вашу отладочную информацию. Убедитесь, что вы логируете ключи реестра, которые проверяете. Это поможет вам увидеть, какие ключи обрабатываются, и поможет вам отследить, почему некоторые из них не находятся.
log('Проверка ключа: ' + KeyNames[i] + '\' + SubkeyNames[j]);
5. Права доступа
Не забудьте проверить, есть ли у вашего скрипта права доступа к соответствующим ключам реестра. Иногда это может стать причиной, по которой приложение не может получить нужную информацию.
Заключение
Для успешного обнаружения установленных приложений с помощью вашего Inno Setup скрипта требуется четко понимать и учитывать архитектурные особенности Windows, правильно обращаться к нужным разделам реестра и правильно обрабатывать их с помощью вашей логики в скрипте. Проведение тщательной отладки, внимание к деталям и грамотное логирование помогут выявить и устранить неполадки, а также обеспечат вам надежный инструмент для работы с установленными приложениями.