📑 从“CreateProcess需要管理员权限”问题到最终解决过程总结
1. 问题起因
在 ModuleLoginSDK::LoadLoginModule()
中调用:
CreateProcess(filePath.c_str(), NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
发现启动 sdologin.exe
失败,CreateProcess
返回 FALSE
。
GetLastError 返回错误码 740
(ERROR_ELEVATION_REQUIRED
)。
2. 初步分析
CreateProcess
自身不需要管理员权限。- 但是如果被启动的子程序(
sdologin.exe
)要求管理员权限,而父进程没有提权,则CreateProcess
会直接失败。
3. 进一步排查 Manifest 文件
提取 sdologin.exe
的 .manifest
内容,发现如下:
<requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
确认:
requireAdministrator
意味着:必须管理员权限才能启动。- 普通权限的
CreateProcess
无法直接启动它。
4. 初步方案
有两种应对方式:
方案 | 方法 | 特点 |
---|---|---|
使用 ShellExecuteEx 带 "runas" | 让系统弹出 UAC 确认 | 用户体验差,弹窗 |
修改 manifest 为 asInvoker | 子程序随父进程权限运行 | 最干净,免弹窗 |
最终决定:修改 manifest
文件内容,降级到普通权限。
5. 排查项目配置(.vcproj
)
阅读 sdologin.vcproj
后发现:
-
没有直接写
/MANIFESTUAC
指令。 -
但是在
<Tool Name="VCLinkerTool" ...>
节点下有:<?xml version="1.0" encoding="gb2312"?> <VisualStudioProject ProjectType="Visual C++" Version="9.00" Name="sdologin" ProjectGUID="{C5E8C5E9-7E64-4A77-9964-59A0679EABDC}" RootNamespace="GameLogin" Keyword="Win32Proj" TargetFrameworkVersion="131072" > <Platforms> <Platform Name="Win32" /> </Platforms> <ToolFiles> </ToolFiles> <Configurations> <Configuration Name="Debug|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="1" CharacterSet="1" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=".;./LianXiang;./ADSClient;../../include;../public;../CrashRpt/CrashReport;../duiex/;../../include/sdgupdate/" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;USE_SDO_CUSTOMUI;NOTCATCH_EXCEPTION;DUILIB_DEBUGVIEW" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="1" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="false" DebugInformationFormat="4" CallingConvention="0" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="Protectedsd.lib tinyxmlsd.lib SafeStored.lib procnetd.lib CrashRptd.lib SdoBaseClientd.lib sdostatesvrclientd.lib sdologinkitd.lib DuiExLibD.lib duilibd.lib ADSClientSDK.lib libeay32.lib ssleay32.lib" OutputFile="../../bin/$(ConfigurationName)/sdologin/sdologin.exe" LinkIncremental="2" AdditionalLibraryDirectories="../../lib/" IgnoreDefaultLibraryNames="" GenerateDebugInformation="true" SubSystem="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> <Configuration Name="Release|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="1" CharacterSet="1" WholeProgramOptimization="1" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" WholeProgramOptimization="false" AdditionalIncludeDirectories=".;./LianXiang;../../include;../public;../CrashRpt/CrashReport;../duiex/;../../include/sdgupdate/" PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;USE_SDO_CUSTOMUI;USE_BINFORMAT_CONFIG" RuntimeLibrary="0" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="false" DebugInformationFormat="3" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="Protecteds.lib tinyxmls.lib safestore.lib duilib.lib procnet.lib Crashrpt.lib sdostatesvrclient.lib sdologinkit.lib DuiExLib.lib ADSClientSDK.lib libeay32.lib ssleay32.lib SdoBaseClient.lib" OutputFile="../../bin/$(ConfigurationName)/sdologin/sdologin.exe" LinkIncremental="1" AdditionalLibraryDirectories="../../lib" UACExecutionLevel="0" GenerateDebugInformation="true" ProgramDatabaseFile="../../bin/$(ConfigurationName)/pdb/$(TargetName).pdb" GenerateMapFile="true" MapFileName="../../bin/$(ConfigurationName)/pdb/$(TargetName).map" SubSystem="2" OptimizeReferences="2" EnableCOMDATFolding="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="$(ConfigurationName)\$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" EmbedManifest="false" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> </Configurations> <References> </References> </Files> <Globals> </Globals> </VisualStudioProject>
UACExecutionLevel="2"
这行配置直接导致了生成的 manifest 强制为 requireAdministrator
。
UACExecutionLevel="2"` ➔ `requireAdministrator` `UACExecutionLevel="1"` ➔ `highestAvailable` `UACExecutionLevel="0"` ➔ `asInvoker
6. 初步改动
第一次修改时,将 UACExecutionLevel
从 2
改成了 1
。
结果 .manifest
变成了:
<requestedExecutionLevel level="highestAvailable" uiAccess="false"/>
虽然不强制要求管理员,但如果父进程是管理员还是会请求提权,不是完全跟随父进程权限。
7. 正确最终修改
为了彻底做到普通权限,最终操作是:
- 将
.vcproj
文件里的UACExecutionLevel="2"
改成:
UACExecutionLevel="0"
或者直接删除 UACExecutionLevel
这一行。
然后重新编译。
最终生成的 .manifest
文件内容变为:
<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
✅ 彻底跟随父进程权限。
✅ 不再需要管理员权限。
✅ CreateProcess
成功启动子进程,无需弹出UAC确认。
8. 解决结果确认
sdologin.exe
编译生成的 manifest 成功降级为asInvoker
。- 程序通过普通权限的
CreateProcess
成功启动。 - 整个过程无UAC弹窗,提升了用户体验。
- 以后无需修改其他逻辑。
📌 总结一张表
阶段 | 发现的问题 | 处理操作 | 结果 |
---|---|---|---|
初步 CreateProcess 失败 | 子程序需要管理员权限 | 查看 manifest | 确认是 requireAdministrator |
尝试修改 | 修改 UACExecutionLevel="1" | 生成 highestAvailable | 仍有轻微提权行为 |
正确修改 | 改成 UACExecutionLevel="0" 或删掉 | 生成 asInvoker | 成功以普通权限运行 |
📚 重要补充知识
什么是 requestedExecutionLevel
?
Level | 含义 | 使用场景 |
---|---|---|
asInvoker | 跟随父进程权限,完全无感知 | 普通应用、子进程 |
highestAvailable | 能提权就提,不能提就普通运行 | 开发工具 |
requireAdministrator | 必须提权,否则不能运行 | 安装程序、服务管理工具 |
🚀 小提示
如果想快速检查 .exe
里面的 manifest 内容,可以用 mt.exe
:
mt.exe -inputresource:your_program.exe;#1 -out:manifest.txt
这条命令能直接提取 embedded manifest 文件,确认权限等级。
✨ 最后一行总结
已经成功把
sdologin.exe
从必须管理员权限 ➔ 降级成跟随父进程权限 (asInvoker
),CreateProcess彻底正常,用户体验无弹窗,流程完美!
🛡 遇到 CreateProcess 错误740快速排查 Checklist
步骤 | 检查项 | 说明 |
---|---|---|
1 | 检查子程序的 Manifest 文件 | 是否包含 requireAdministrator |
2 | 检查父进程权限 | 是否以管理员权限运行父程序 |
3 | 检查 .vcproj 文件 | 是否有 UACExecutionLevel="2" 配置 |
4 | 使用 mt.exe 提取 Manifest | 确认真实运行时嵌入的 Manifest 内容 |
5 | 修改 Manifest 为 asInvoker | 改 .vcproj ➔ 重新编译 |
6 | 最后重新测试 CreateProcess | 确认是否成功,无需弹UAC |