суббота, 3 апреля 2010 г.

О странностях UAC

Много слышал (и не раз видел), как здорово UAC защищает нас от всяких вредоносных программ, злых вирусов, которые так и норовят проникнуть в компьютер, раз пользователь работает с правами администратора. Снизошла на нас благодать Microsoft, сделали они User Access Control, чтобы каждое действия злого вируса сопровождалось запросом, а разрешить ли ему проникать на компьютер со своими злонамеренными целями или не разрешить. Оказывается, не только вируса. Оказывается, не только злонамеренного. Компилирую в Delphi 2010 под Windows 7 старый проект, имя проекта: ArgoInstaller. Компилируется без ошибок, а вот запускаться из-под среды не желает.

Unable to create process: Запрошенная операция требует повышения.
 
Запуск из-под проводника выводит запрос, разрешить ли программе неизвестного издателя внесение изменений на данном компьютере (хотя программа ни сном ни духом, ни в помыслах, никаких изменений вносить не намерена).
 
Сломал голову, искал, что же может быть причиной, пересмотрел все используемые секции initialization в проекте и в используемых компонентах - ничего криминального не нашел.
Поискал в гугле, как бы узнать, какое именно действие программы вызывает страшный диалог, но скорее, задавал вопрос слишком общо, потому что практически во всех найденных ссылках рассказывалось о том, как здорово, что у нас есть UAC или как его выключить совсем. О том, что UAC это здорово, я знаю и без ссылок в гугле, отключать его я не намерен, а вот в
http://msdn.microsoft.com/en-us/library/aa905330.aspx
обнаружилось, в UAC оказывается есть автодетектирование инсталлятора:
"Before a 32 bit process is created, the following attributes are checked to determine whether it is an installer:
•Filename includes keywords such as "install," "setup," and "update.""
•Keywords in the following Versioning Resource fields: Vendor, Company Name, Product Name, File Description, Original Filename, Internal Name, and Export Name.
•Keywords in the side-by-side application manifest embedded in the executable.
•Keywords in specific StringTable entries linked in the executable.
•Key attributes in the resource file data linked in the executable.
•Targeted sequences of bytes within the executable
 
Стоило переименовать проект, как он стал запускаться из-под среды и из проводника без запросов на разрешение внесения изменений.
 
Оказывается, такая проверка включена по умолчанию. Оказывается ее можно отключить. Стоит или не стоит отключать, решать каждому самостоятельно.
 
"Note The User Account Control: Detect application installations and prompt for elevation setting must be enabled for installer detection to detect installation programs. This setting is enabled by default and can be configured using the Security Policy Manager snap-in "
 
И быть внимательнее при выборе имен проектов :)
 
Что интересно, простой проект с формой, сохраненный с тем же именем ArgoInstaller или с именем UpdateSetupInstall, превосходно запустился из-под среды. Видимо, дело еще в
•Targeted sequences of bytes within the executable


потому что оригинальный проект, будучи переименованый в любое имя, содержащее setup, install или update вызывает диалог UAC и невозможность запуска из среды.

Перемудрили наши братья по разуму, с моей точки зрения :)

Upd #1: Наличествует этот же проект, когда-то скомпилированный Delphi 2006, в Windows 7 точно также выдает предупреждение UAC, разрешить ли этой программе внесение изменений. Интересная ситуация: программа скомпилирована с run-time packages и сначала выдается запрос UAC, а потом сообщение о невозможности запуска, так как отсутствует rtl100.bpl, то есть "автообнаружение инсталлятора" производится до анализа доступности DLL для разрешения импортируемых ссылок. Переименование старого Exe-шника в что-то безобидное типа foobar.exe, приводит к сообщению об отсутствии rtl100.bpl. Переименование нового приводит к его благополучному запуску. Переименование в IAmNotAnInstallerOrSetup.exe приводит к выдаче сообщения UAC :)

Upd #2: Понятно, почему сообщения об отсутствующих DLL выдаются после запроса UAC, в MSDN честно пишут, что Installation detection выполняется "Before 32-bit process is created", а разрешения импорта происходит уже после создания процесса. По совету сочувствующих, создал манифест в виде файла рядом с исполняемым модулем, ArgoInstaller.exe.manifest:


<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity version="1.0.0.0"
processorArchitecture="X86"
name="ArgoInstaller"
type="win32"/>
<description>Argo database installation application</description>
<!-- Identify the application security requirements. -->
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
</assembly>

При этом манифесте при запуске из Far/проводника сразу выдается сообщение: Запрошенная операция требует повышения, Cannot execute.

Upd#3, помогло включение манифеста в ресурсы приложения. Видимо, файл манифеста рядом с программой и то же содержимое, но в ресурсах - это с точки зрения UAC, две огромные разницы. Вдруг какой-то вредитель файлом манифеста пытается доблестный UAC обмануть и замаскировать коварный setup.

Upd#4
полезная статья по теме: http://blogs.msdn.com/cjacks/archive/2009/06/18/pca-changes-for-windows-7-how-to-tell-us-you-are-not-an-installer-take-2-because-we-changed-the-rules-on-you.aspx


ссылка на решение: http://technet.microsoft.com/en-us/library/dd638326(WS.10).aspx

Upd#5 Ларчик открывается гораздо проще, достаточно убить файл .res старого проекта, вынудить Delphi 2010 его пересоздать, внести туда нужные изменения, например икону проекта, и возможность отладки в среде как по волшебству появляется, и UAC не надоедает.
Благодарю http://www.delphimaster.ru/cgi-bin/forum.pl?n=3&id=1270305381&from=78

суббота, 27 марта 2010 г.

Последний раз о Delphi 2010 и ошибке с GetprocessId :)

Появилась лицензионная версия Delphi 2010, ура. В ней при запуске кода с объявленной функцией GetProcessId честно выдается сообщение об отсутствующей точке входа. Набор апдейтов такой же, как у триала. Спишем на недостаток триала - за месяц людям будет чего поизучать и без поведения программ, скомпилированных с некорректными импортами :)

пятница, 12 марта 2010 г.

Опять о поведении Delphi 2010

Выяснилось, что кроме тихой смерти приложения при запуске я наткнулся на известную в QC ошибку: http://qc.embarcadero.com/wc/qcmain.aspx?d=80448, связанную с некорретным объявлением функции GetProcessId в Windows.pas

Одним махом удалось наступить на двух зайцев. Коллеги утверждают, что мой код, скомпилированный в их версии 2010 честно говорит об отсутствующей точке входа. Видимо, набор updates не совпадает.

понедельник, 8 марта 2010 г.

Неожиданное поведение Delphi 2010

Windows 7, 64-бита, Delphi 2010, последний день триального периода. В связи с вопросом http://www.delphikingdom.ru/asp/answer.asp?IDAnswer=75999 набираю пример тестового кода

procedure TForm1.Button1Click(Sender: TObject);

begin
  RunApplication;
end;

procedure TForm1.RunApplication;

var
  sexinfo: SHELLEXECUTEINFO;
  AContext: TEWContextRecord;
  S: string;
begin
  FillChar(sexinfo, 0, SizeOf(sexinfo));
  sexinfo.cbSize := SizeOf(sexinfo);
  sexinfo.fMask := SEE_MASK_NOCLOSEPROCESS;
  sexinfo.lpFile := 'C:\Foo\bar.exe';
  Win32Check(ShellExecuteEx(@sexinfo));
  AContext.AppProcess := GetProcessId(sexinfo.hProcess);
  AContext.AppWnd := 0;
  EnumWindows(@MyEnumWindowsProc, Integer(@AContext));
  if IsWindow(AContext.AppWnd) then
  begin
    .....
    //Что-то
  end;
end;

Запускаю и удивляюсь - такое ощущение, что приложение запускается и тут же завершается. Если закомментировать строку AContext.AppProcess := GetProcessId(sexinfo.hProcess);  запускается, как положено, появляется форма с кнопкой, а стоит строку раскомментировать. Во всех окнах среды нет никаких замечаний, компиляция проходит без ошибок, предупреждений и хинтов. При запуске скомпилированного приложения вне среды, наконец появляется причина такого странного поведения:
Точка входа в процедуру GetProcessID не найдена в библиотеке DLL kernel32.dll.

Так как триал заканчивается завтра, скорее всего, не буду пытаться побороть.

Upd 09.03.2010: Delphi 2006 честно предупреждает об отсутствующей точке входа при попытке выполнить приложения в среде.