埋め込みマニフェストを修正して管理者権限を要求しないように、小さなC#アプリケーションを作成しようとしました。これは私が最終的に思いついた解決策であり、マニフェストを抽出して既存のマニフェストを置き換えるWin32呼び出しをたくさん作成しています。すでに十分な長さなので、実際にマニフェストを変更する部分(省略時のXML操作)は省略しました。
ここでは2つの静的メソッドがあります。指定された実行可能でマニフェストリソースの文字列表現を保存し、実行し、SaveManifestResourceの埋め込みマニフェストの文字列表現をロードLoadManifestResource、古いものを上書きするには、 。
これは私のためにうまくいきましたが、すべての場合にうまく動作しないかもしれない迅速かつ汚れた解決策です。
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);
}
}
}
http://stackoverflow.com/questions/8784692/how-to-avoid-user-account-control-or-run-windows-application-in-win7-always-in-a –
@Jasonそれはここで尋ねられていることとは反対のようです。 – cHao
@cHao:しかし、これは必要な可能性のあるマニフェストの可能な変更を洞察し、それを逆転させます。 –