首先澄清一下,这篇文章并没有讲如何用Metro App弹UAC,而讲的是如果用户在一个全屏的Metro app里,那么如何让桌面Program弹出的UAC正常地被用户看到。当然,在Windows 10预览版已经发布的时候谈这个话题可能已经有点晚了,因为Windows 10当前版本根本不存在这个问题。
熟悉Windows 8.1的用户肯定知道,当用户打开了一个全屏的Metro App时,大部分桌面程序如果弹出UAC,是不会直接出现在屏幕上的,而是会出现在任务栏上闪动(如下图)。

其实这个比较影响用户体验,因为用户在全屏App中根本看不到任务栏,而容易错过这样的提示。(错过了不一定是坏事,因为弹UAC窗口真的是打扰用户的行为)
查找了一下相关资料,巨硬从某个Windows版本之后,只有当创建UAC进程的父进程的窗口句柄在最前端时才会直接显示UAC安全桌面(Secure desktop),其它的情况下将会在任务栏上显示闪动的盾牌图标。
于是这个问题就比较好解决了,以C#的Process为例,创建进程时可以设置ErrorDialogParentHandle属性指定父窗口句柄。于是这样就将目标转化为了取得当前正在运行的Metro App的hWnd。

我们主要需要FindWindow或FindWindowEx函数。

[DllImport("User32.dll", EntryPoint = "FindWindow")]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("User32.dll", EntryPoint = "FindWindowEx")]
private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpClassName, string lpWindowName);

以下为调用示例。假定[文件名].exe在manifest里已经写明权限highestAvailable,那么使用Process类启动它时就会弹出UAC窗口。而FindWindowEx(IntPtr.Zero, IntPtr.Zero, "Windows.UI.Core.CoreWindow", null)返回的是当前运行的Metro App的hWnd或NULL(IntPtr.Zero,如果当前没有Metro App在前台)

var newproc = new System.Diagnostics.Process();
var info = new System.Diagnostics.ProcessStartInfo("[文件名].exe")
{
    UseShellExecute = true,
    ErrorDialog = true,
};
var window = FindWindowEx(IntPtr.Zero, IntPtr.Zero, "Windows.UI.Core.CoreWindow", null);
if (window != IntPtr.Zero)
    info.ErrorDialogParentHandle = window;
newproc.StartInfo = info;
newproc.Start();  

附赠一段直接用Metro App弹UAC的gif效果图(与本文关系不大,本文是实现过程中遇到的问题之一)

具体实现方法不难,不影响上架机器审核和WACK,但是欠折腾Orz,而且可能影响人工审核。。