我继承了一个应用程序的维护,当它运行时,偶尔会出现UAC管理员提升(你希望允许这个吗?)对话框。对我来说,首先要尝试的是“打开UAC日志记录”,重新运行应用程序以显示对话框,然后在日志中找到条目,例如“2013-11-23-19: 10:03 [MyApplication]尝试编写注册表项[MyRegistryKey]。需要管理员授权“,然后采取措施解决问题,以便在使用应用程序时对话框不会出现。
然而,有些人在2008/09年发布了有关Vista的UAC日志记录的问题,答案是“UAC没有登录,但这对未来版本来说是一个很棒的功能”。 UAC日志记录是在Windows 7中还是作为补丁版本实施的?如果没有,是否有常用的替代技术?
答案 0 :(得分:2)
我最终解决了这个问题。这是发生了什么。
1)我尝试过Ben关于使用sysinternals工具的建议。似乎有用的工具是
DependencyWalker ProcessExplorer 的ProcessMonitor
他们每个人都提供了很多有关正在发生的事情的信息,我可以看到这些问题需要成为许多(如果不是大多数)Windows问题的第一个停靠点。但是,在我的情况下,我双击了应用程序并获得了UAC用户ID /密码对话框,但随后发现工具写入的信息不多,直到对话框浮出水面。
在尝试解决UAC问题时,看起来似乎有必要消化Microsoft Press Windows Internals书籍的内容。
2)我尝试使用应用程序兼容性工具包,但它显示该程序在XP(它工作的地方)或Windows 7(都是标准用户,显示UAC对话框和管理员用户,这有效)的问题没有问题
3)然后我尝试从头开始艰苦地重新创建应用程序,从一个空项目开始,然后一点一点地复制文件和设置。在每个阶段,我检查了应用程序是否会在没有显示UAC对话框的情况下启动。
最终我应用了一个更改,这导致UAC对话框浮出水面。这是一个VB6应用程序,我在对话框Project,Properties,Make中更改了“应用程序标题”和“产品名称”。每个字段的先前(失败)值是“ApplicationName Update”。要使应用程序在没有UAC提升的情况下工作,我必须删除“更新”一词。
正如Ian在上面所建议的那样,它看起来像是应用了UAC启发式,以及exe中的值。我看到Windows Internals书确实讨论了在决定是否提升时在exe中扫描字节序列。
4)总而言之,对我有用的方法是逐位重新组合app,看看UAC对话框在什么阶段被触发。一旦发生这种情况,Ian在前一个答案中给出的四个理由的知识变得很重要。
5)我应该指出,我通过删除启发式中被标记的内容来解决问题,但没有考虑Ian建议的替代方案:“asInvoker”。这可能是尝试而不是花时间处理(遗留)应用修复问题的最佳方法。
答案 1 :(得分:0)
在日志中查找条目,例如“2013-11-23-19:10:03 [MyApplication]尝试编写注册表项[MyRegistryKey]。需要管理员授权”
UAC不是那样的。 Windows不会监视应用程序,并根据活动决定下次应该运行它。
在这方面,Windows 7的行为与Windows XP大致相同。如果您的应用以标准用户身份运行,请尝试写入:
HKLM\Software\Cotoso\Litware
您的应用程序将收到Access Denied
错误消息。
不幸的是,大多数应用程序编写得很糟糕。大多数应用程序在Windows 2000或Windows XP上作为标准用户运行时都会崩溃。自1999年以来,作为Windows徽标要求的一部分,Microsoft要求开发人员在作为标准用户运行时测试其应用程序。几乎没有人做过。
这就是为什么,从Windows Vista开始,微软增加了一项功能,让您的错误应用程序思考成功写入 HKLM 或程序文件。如果写入失败,如果用户是管理员,将成功,那么Windows将重新发出写操作,除非这次重定向到某个成功的位置。例如:
writes to
HKLM\Software
are redirected to
HKCU\<User SID>_Classes\VirtualStore\Machine\Software
writes to
C:\Program Files
are redirected to
C:\Users\Westwell\AppData\Local\VirtualStore\Program Files
这些重定向机制都不会导致您的应用程序在下次启动时被提升。这两个功能都是临时兼容性攻击。通过在应用程序的程序集清单中添加requestedExecutionLevel
asInvoker
,可以通知Windows您正确编写了应用程序,选择退出文件和注册表虚拟化:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity version="1.0.0.0" processorArchitecture="X86" name="client" type="win32"/>
<description>Westwell Contoso</description>
<!-- Disable file and registry virtualization -->
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
</assembly>
现在只消除了为什么有时写入能够成功的侧面讨论,即使用户是标准用户。
应用程序可能会在启动时提示提升的原因有五个:
您表明您的应用程序需要以管理员身份运行。
如果您的应用需要以管理员身份运行,并且在不是管理员的情况下无法执行任何有用的功能,那么您可以将应用程序显示为requireAdministrator
(而不是asInvoker
):
<description>Westwell Contoso</description>
<!-- Disable file and registry virtualization -->
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
如果是这种情况,那么应用程序将始终以管理员身份运行。那就不是了。
您表明,只有用户实际上是管理员时,您的应用程序才会以管理员身份运行。
RegEdit 等应用程序可以作为标准用户正常运行,不需要提升。但如果用户实际上是管理员,则RegEdit可以提示升级到用户的完整管理员资格。这是通过将您的应用标记为highestAvailable
(而不是asInvoker
或requireAdministrator
)来完成的:
<description>Westwell Contoso</description>
<!-- Disable file and registry virtualization -->
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
如果是这种情况,您的应用会提示管理员提升,但不会提示标准用户。这可能不是原因,因为您的应用程序没有清单。
Compatibilty选项将应用程序标记为以管理员身份运行。
用户可以选择标记应用程序,以便提示提升:
此复选框的状态(以及其他复选框)存储在注册表中:
HKCU\Software\Microsoft\WindowsNT\CurrentVersion\AppCompatFlags\Layers
和“所有用户”位于:
HKLM\Software\Microsoft\WindowsNT\CurrentVersion\AppCompatFlags\Layers
此选项可以是每个用户,也可以是每台计算机。因此,某些用户可能会看到提升提示,而其他用户则不会。这可能是您问题的根源。
Installer detection heuristics。
默认情况下,Windows会尝试识别应用程序可能是安装程序(例如setup.exe
,install.exe
,update.exe
)并提示用户提升。可以通过组策略禁用此功能,策略名称为User Account Control: Detect application installations and prompt for elevation。
简单的解决方法是简单地标记您的应用asInvoker
。这将禁用启发式。
之后,它必须是机器上的兼容性设置(HKCU或HKLM中的AppCompatFlags)。