Встраивание манифеста приложения в исполняемый файл VB6

Недавно я просмотрел несколько автономных утилит, написанных на VB6, чтобы убедиться, что виртуализация реестра отключена для Windows Vista и выше. Я создал отдельный файл манифеста для каждого EXE-файла, установите requestedExecutionLevel соответственно (некоторые из них необходимо изменить HKEY_LOCAL_MACHINE ключей реестра, других нет) и их проверял. Все они, кажется, работают правильно.

У меня осталась только одна маленькая проблема. Так как они являются автономными утилитами, люди привыкли просто копировать их по сети и запускать их вручную. Если кто-то забудет скопировать файл манифеста, а также exe-файл, то exe-файл будет молча записывать в виртуальный раздел реестра вместо реального и вызывать проблемы, которые трудно отладить.

Очевидное решение - встроить манифест в exe как ресурс. Все статьи, которые я прочитал в сети, говорят о том, что вы должны встраивать ресурс следующим образом

#define CREATEPROCESS_MANIFEST_RESOURCE_ID 1
#define RT_MANIFEST 24
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "app.manifest"

Это должно работать нормально, за исключением того, что компилятор VB всегда создает значок приложения с идентификатором ресурса = 1. Когда я попробовал приведенный выше код, Windows отказалась запускать exe, жалуясь на ошибку ресурса (я обновлю этот пост с помощью подробности позже). Я попытался изменить идентификатор ресурса на другой номер, после чего Windows успешно запустила программу, но не распознала содержимое манифеста.

Кто-нибудь знает способ заставить встроенный манифест работать в VB6 exe, или я должен просто придерживаться внешнего файла?

ОБНОВЛЕНИЕ 1

Приведенный выше текст является полным содержанием .rc файл. Я собираю это в .res файл как это:

"%ProgramFiles%\Microsoft Visual Studio\VB98\Wizards\rc.exe" /r /fo "Resources.res" "Resources.rc"

И вставьте его в файл проекта VB6 следующим образом:

Type=Exe
Reference=*\G{00020430-0000-0000-C000-000000000046}#2.0#0#..\..\..\..\..\..\..\..\WINDOWS\system32\stdole2.tlb#OLE Automation
Form=Main.frm
ResFile32="Resources.res"
IconForm="FMain"
Startup="FMain"
HelpFile=""
Title="Windows Vista Registry Test - VB6"
ExeName32="RegistryTestVB6.exe"
Path32=""
Command32=""
Name="RegistryTestVB6"
HelpContextID="0"
CompatibleMode="0"
MajorVer=1
MinorVer=0
RevisionVer=0
AutoIncrementVer=0
ServerSupportFiles=0
VersionComments="Windows Vista Registry Test - VB6"
VersionCompanyName=""
VersionFileDescription="Windows Vista Registry Test - VB6"
VersionLegalCopyright=""
VersionProductName="Windows Vista Registry Test - VB6"
CondComp=""
CompilationType=0
OptimizationType=0
FavorPentiumPro(tm)=0
CodeViewDebugInfo=0
NoAliasing=0
BoundsCheck=0
OverflowCheck=0
FlPointCheck=0
FDIVCheck=0
UnroundedFP=0
StartMode=0
Unattended=0
Retained=0
ThreadPerObject=0
MaxNumberOfThreads=1

Когда я читаю скомпилированный exe-файл в редакторе ресурсов VS2008, он выглядит так:

RegistryTestVB6.exe
    Icon
        1 [Neutral]
    RT_MANIFEST
        1 [English (United States)]
    Version
        1 [English (United States)]

Когда я создаю точное эквивалентное тестовое приложение VB.NET в VS2008, а затем загружаю его в редактор ресурсов, оно выглядит следующим образом:

RegistryTestNET.exe
    Icon
        32512 [Neutral]
    RT_MANIFEST
        1 [Neutral]
    Version
        1 [Neutral]

ОБНОВЛЕНИЕ 2

Тестирование -.NET exe работает нормально как в Windows XP, так и в Windows 7. Однако VB6 exe выдает следующую ошибку в XP:

Это приложение не удалось запустить из-за неправильной конфигурации приложения. Переустановка приложения может решить проблему.

и следующая ошибка на 7:

Не удалось запустить приложение, так как его параллельная конфигурация неверна. Пожалуйста, смотрите журнал событий приложения или используйте инструмент командной строки sxstrace.exe для более подробной информации.

Глядя в журнал событий, я вижу следующую запись:

Сбой генерации контекста активации для "RegistryTestVB6.exe". Ошибка в манифесте или файле политики "RegistryTestVB6.exe" в строке 10. Неверный синтаксис XML.

Само собой разумеется, что XML не является недействительным, это точно такой же файл с той же кодировкой, которую я использовал для.NET exe, и этот работает.

РАЗРЕШАЮЩАЯ СПОСОБНОСТЬ

Компилятор VB6 действительно требует, чтобы произвольный текстовый файл, включенный в ресурс, был кратным 4 байтам. Я просто добавил пробелы в XML, пока Notepad++ не сказал мне, что общий размер файла, включая спецификацию, был кратен 4.

Спасибо и Майклу, и Джиму за то, что они указали мне правильное направление. Жаль, я не могу отметить вас обоих как ответ!

3 ответа

Решение

Интересно, что недавно мне пришлось сделать то же самое. Следуя шагам, описанным Кристианом, я заставил его работать с первого раза. Для процветания, вот весь рабочий процесс, за которым я следовал:

  1. Создан RC файл, как описано в оригинальном вопросе
  2. Создан app.manifest, сохраняющий пробельные символы, которые ОЧЕНЬ ВАЖНЫ для того, чтобы это работало. Как указано в предыдущих ответах, размер файла должен быть кратным 4.

  3. Запустите RC.EXE, как описано в исходном вопросе, к rc, чтобы сгенерировать файл.res.

  4. Отредактировал мой файл Project.VBP, добавив следующую строку вверху:

ResFile32 = "Resources.res"

  1. Встроенный EXE в стандартной среде vb6. При развертывании на компьютере с Vista или Win7 появляется экран и пользователю предлагается работать от имени администратора. Открывая EXE-файл в студии, я проверил ресурсы.

  2. Notepad ++ говорит мне, что кодировка в моем файле app.manifest - ANSI. Он не включал метку порядка байтов в начале файла.

Если у вас все еще есть проблемы, дайте мне знать, и я поделюсь с вами всем, что смогу. Кроме этого, я не уверен, что вам сказать, кроме работ на моей машине!

У VB6 есть особенность в том, что любой элемент ресурса должен быть кратным длине 4. Попробуйте заполнить файл манифеста пробелами, чтобы убедиться в этом, и посмотрите, изменит ли это поведение.

Эта причуда была задокументирована в статье Microsoft Q297112 (архив).

Кроме того, вы можете добавить ресурс, используя IDE VB6 вместо редактирования VBP. Эффект может быть таким же, но редактор ресурсов является стандартным средством для этого.

Использование Resource Compiler (rc.exe) - это долгий путь. Существует гораздо более простая опция для встраивания манифеста приложения в исполняемый файл, будь то C++, VB6 или любой другой язык. Manifest Tool (mt.exe) был специально создан для встраивания манифестов в двоичные файлы и предоставляется бесплатно вместе с Windows SDK. Дополнительным преимуществом использования mt.exe является то, что он автоматически обрабатывает любые необходимые отступы.

Просто запустите следующую командную строку после того, как двоичный файл был скомпилирован. Я использовал соглашение об именах, используемое внутри компилятором Visual C++ 2005, где имя файла манифеста содержит полное имя программы с добавлением ".intermediate.manifest".

mt.exe -nologo -manifest "program.exe.intermediate.manifest" -outputresource:"program.exe;#1

Обновление: я лично использую это в процессе автоматической сборки с исполняемыми файлами VB6 уже более двух лет. Он оказался настолько успешным, что мы исключили тесты совместимости ОС - специфичные для манифестов - из нашего регрессионного тестирования.

Другие вопросы по тегам