Одна из проблем использования самоустанавливающегося архива, создаваемого программой IExpress, под Windows Vista или Windows 7 с включенным UAC – это обилие вопросов о безопасности, которые задаются пользователю в процессе установки. Эти вопросы возникают из за того, что в манифесте получаемого исполняемого файла указан требуемый уровень доступа как asInvoker, в то время как запускаемые в виде дочерних процессов программы установки требуют более высокого уровня доступа. Проблему можно решить, изменив манифест созданного IExpress приложения, указав более высокие требования.
Для того чтобы сделать это, я сделал маленькую программку, которая позволяет заменить манифест существующего приложения с командной строки:
UpdateManifest.exe MyInstaller.EXE manifest-for-web-setup.xml
Здесь файл манифеста – это слегка модифицированный манифест исходного приложения. Исходный манифест был выгружен из приложения с помощью редактора ресурсов Visual Studio.
Программа получилась очень простая, но полезная. Привожу исходный текст, может быть кому-нибудь понадобится.
Собранная программа, применяемая мной в сценарии сборки на момент написания статьи доступна для скачивания.
Для того чтобы сделать это, я сделал маленькую программку, которая позволяет заменить манифест существующего приложения с командной строки:
UpdateManifest.exe MyInstaller.EXE manifest-for-web-setup.xml
Здесь файл манифеста – это слегка модифицированный манифест исходного приложения. Исходный манифест был выгружен из приложения с помощью редактора ресурсов Visual Studio.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!-- Copyright (c) Microsoft Corporation -->
<!--
Copyright (c) Microsoft Corporation. All rights reserved.
Authors:
GaryY
Module name:
wextract.manifest
Abstract:
Manifest to support IExpress WExtract.exe.
-->
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
version="1.0.0.0"
processorArchitecture="x86"
name="wextract"
type="win32"
/>
<description>IExpress extraction tool</description>
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="x86"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
<!-- Identify the application security requirements. -->
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel
level="requireAdministrator"
uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
</assembly>
Программа получилась очень простая, но полезная. Привожу исходный текст, может быть кому-нибудь понадобится.
void ErrorHandler( LPCSTR errorMsg )
{
throw exception(errorMsg);
}
void UpdateApplicationManifest( _TCHAR* applicationPath, _TCHAR* manifestPath )
{
BOOL result = FALSE;
HANDLE hmanifestfile = CreateFile(manifestPath, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
if (hmanifestfile == INVALID_HANDLE_VALUE)
{
ErrorHandler("Cannot open manifest file");
return;
}
DWORD dwFileSize = GetFileSize(hmanifestfile, NULL);
if (dwFileSize == INVALID_FILE_SIZE)
{
ErrorHandler("Cannot read manifest file length");
return;
}
byte * pManifestBuf = new byte[dwFileSize];
DWORD readBytes;
if (!ReadFile(hmanifestfile, pManifestBuf, dwFileSize, &readBytes, NULL))
{
ErrorHandler("Cannot read manifest file content");
return;
}
// Open the file to which you want to add the dialog box resource.
HANDLE hUpdateRes = BeginUpdateResource(applicationPath, FALSE);
if (hUpdateRes == NULL)
{
ErrorHandler("Could not open file for writing.");
return;
}
// Add the dialog box resource to the update list.
result = UpdateResource(hUpdateRes, // update resource handle
RT_MANIFEST, // change manifest resource
MAKEINTRESOURCE(1), // manifest id
MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), // english language
pManifestBuf, // ptr to resource info
dwFileSize); // size of resource info
if (result == FALSE)
{
ErrorHandler("Could not add or update resource.");
return;
}
// Write changes to FOOT.EXE and then close it.
if (!EndUpdateResource(hUpdateRes, FALSE))
{
ErrorHandler("Could not write changes to file.");
return;
}
//clean up
CloseHandle(hmanifestfile);
delete [] pManifestBuf;
}
void DisplayInfo()
{
cout << "usage : UpdateMainfest.exe [application (EXE)] [manifestfile (XML)]\n";
}
int _tmain(int argc, _TCHAR* argv[])
{
if (argc <= 1)
{
DisplayInfo();
}
else if (argc != 3)
{
cout << "Invalid parameters count\n";
}
else
{
try
{
UpdateApplicationManifest(argv[1], argv[2]);
cout << "resource update completed ok\n";
}
catch (exception & e)
{
cout << "failed: " << e.what() << "\n";
}
}
return 0;
}
Собранная программа, применяемая мной в сценарии сборки на момент написания статьи доступна для скачивания.
Комментариев нет:
Отправить комментарий