Я попытался создать небольшое приложение на C #, чтобы изменить встроенный манифест, чтобы он не запрашивал привилегии администратора. Это решение, которое я наконец-то придумал, сделало несколько вызовов Win32 для извлечения манифеста и замены существующего манифеста. Это уже достаточно долго, поэтому я пропустил часть, где я фактически изменяю манифест (только некоторые основные операции с XML).
Здесь есть два статических метода: LoadManifestResource , который загружает строковое представление встроенного манифеста исполняемого файла, и SaveManifestResource , который сохраняет строковое представление ресурса манифеста в указанный исполняемый файл, перезаписывая старый.
Это быстрое и грязное решение, которое отлично сработало для меня, но вполне может работать не во всех случаях.
public static class Library
{
[DllImport("kernel32.dll")]
static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hReservedNull, LoadLibraryFlags dwFlags);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool FreeLibrary(IntPtr hModule);
[DllImport("kernel32.dll")]
static extern IntPtr FindResource(IntPtr hModule, int lpName, int lpType);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr LoadResource(IntPtr hModule, IntPtr hResInfo);
[DllImport("kernel32.dll")]
static extern IntPtr LockResource(IntPtr hResData);
[DllImport("Kernel32.dll", EntryPoint = "SizeofResource", SetLastError = true)]
private static extern uint SizeofResource(IntPtr hModule, IntPtr hResource);
[System.Flags]
enum LoadLibraryFlags : uint
{
DONT_RESOLVE_DLL_REFERENCES = 0x00000001,
LOAD_IGNORE_CODE_AUTHZ_LEVEL = 0x00000010,
LOAD_LIBRARY_AS_DATAFILE = 0x00000002,
LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE = 0x00000040,
LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x00000020,
LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008
}
public static unsafe string LoadManifestResource(string fileName)
{
// load library to retrieve manifest from
var libraryHandle = LoadLibraryEx(fileName, IntPtr.Zero, LoadLibraryFlags.LOAD_LIBRARY_AS_DATAFILE);
if (libraryHandle.ToInt32() == 0)
{
throw new Win32Exception(Marshal.GetLastWin32Error(), "couldn't load library");
}
try
{
// find manifest
var resource = FindResource(libraryHandle, 1, 24);
if (resource.ToInt32() == 0)
{
throw new Win32Exception(Marshal.GetLastWin32Error(), "couldn't find manifest resource");
}
// load manifest
var loadedManifest = LoadResource(libraryHandle, resource);
if (loadedManifest.ToInt32() == 0)
{
throw new Win32Exception(Marshal.GetLastWin32Error(), "couldn't load manifest resource");
}
// lock manifest
var lockedManifest = LockResource(loadedManifest);
if (lockedManifest.ToInt32() == 0)
{
throw new Win32Exception(Marshal.GetLastWin32Error(), "couldn't lock manifest resource");
}
// calculate size of manifest, copy to byte array and convert to string
int manifestSize = (int)SizeofResource(libraryHandle, resource);
byte[] data = new byte[manifestSize];
Marshal.Copy(lockedManifest, data, 0, manifestSize);
var manifest = Encoding.UTF8.GetString(data);
return manifest;
}
finally
{
FreeLibrary(libraryHandle);
}
}
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr BeginUpdateResource(string pFileName,
[MarshalAs(UnmanagedType.Bool)]bool bDeleteExistingResources);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool UpdateResource(IntPtr hUpdate, string lpType, string lpName, ushort wLanguage, IntPtr lpData, uint cbData);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool UpdateResource(IntPtr hUpdate, int lpType, int lpName, ushort wLanguage, IntPtr lpData, uint cbData);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool EndUpdateResource(IntPtr hUpdate, bool fDiscard);
public static unsafe void SaveManifestResource(string file, string manifest)
{
var hUpdate = BeginUpdateResource(file, false);
byte[] bytes = Encoding.UTF8.GetBytes(manifest);
IntPtr ptr = Marshal.AllocHGlobal(bytes.Length);
try
{
Marshal.Copy(bytes, 0, ptr, bytes.Length);
if (!UpdateResource(hUpdate, 24, 1, 0, ptr, (uint)bytes.Length))
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
if (!EndUpdateResource(hUpdate, false))
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
finally
{
Marshal.FreeHGlobal(ptr);
}
}
}