Win32 应用程序在启动时不运行
Posted
技术标签:
【中文标题】Win32 应用程序在启动时不运行【英文标题】:Win32 application doesn't run on startup 【发布时间】:2015-11-19 15:38:04 【问题描述】:我在 Visual Studio 2015 中创建了一个 C++ Win32 应用程序。我的目标是让它在启动时运行。我在注册表中添加了一个新条目(HKCU\Software\Microsoft\Windows\CurrentVersion\Run)。由于未知原因,它不起作用。
但是,它在“启动”选项卡的任务管理器中正确显示,但在“进程”选项卡中却没有显示,这意味着它根本没有运行。我试图将它包装在一个bat文件中。 bat 运行,但应用程序似乎在启动时失败(或完全忽略,我无法准确判断)。如果我从 Program Files 目录手动启动,它会正常运行。
这是一个朋友的旧 Visual 项目,它是在当前 Visual (2015) 中转换的。如果我从头开始创建一个新项目,它就可以工作。但这种行为是没有理由的。
最后的想法 - 我成功解决了我的问题。我的程序无法找到 SQLite 文件,因为 Windows 在启动时启动的任何程序都使用“c:\Windows\System32”作为当前目录。我刚刚应用了 Marko Popovic 的解决方案。这只是一个简单的当前目录问题。
PS - Marko Popovic 的解决方案很好,但@IInspectable 警告此方法可能出现的传入错误。他建议只使用完全限定的路径名而不更改目录。
【问题讨论】:
问题大概是“如何诊断故障模式?” 它是否可能与它的启动目录有关,可能是从当前目录加载 DLL 并且该目录不在路径中?会不会是在读取尚未设置的环境变量? @Matt:这往往会导致更大的故障。但这并非完全不可能。 你说你从一个批处理文件开始。如果您打开 cmd.exe 控制台,cd 到 c:\ (cd /d c:\
) 并从那里启动带有完整路径的批处理文件,它会启动吗?如果您进入系统目录 (cd /d c:\Windows
),同样的问题?
我从批处理文件中运行以进行测试。它既不能与 bat 一起使用,也不能直接使用。
【参考方案1】:
当应用程序使用“运行”键启动时,其工作目录不是其映像文件 (*.exe) 所在的目录。您可以通过在 main 函数的最开始调用 Win32 函数 SetCurrentDirectory
来更改此设置。这是一个解决方案的框架:
// Use GetModuleFileName to retrieve path of the executable file
TCHAR pszPathToSelf[MAX_PATH];
DWORD dwPathLength = GetModuleFileName(NULL, pszPathToSelf, MAX_PATH);
if(dwPathLength > 0)
// Code that extracts directory path from pszPathToSelf and places it into variable pszNewWorkingDirectory of type TCHAR
...
BOOL bSuccess = SetCurrentDirectory(pszNewWorkingDirectory);
if(0 == bSuccess)
// SetCurrentDirectory failed for some reason, handle how you see fit
....
这样,您的函数将更改其工作目录并加载必要的 DLL。
编辑:
正如用户 IInspectable 指出的那样,上述方法在默认情况下不起作用,而仅在某些特殊情况下起作用。更好的方法是在App Paths
注册表项下注册您的应用程序。如果您的应用程序名为 my_app.exe
,请创建以下注册表项:
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\App Paths\my_app.exe
然后创建一个名为Path
的REG_SZ
值,其中将包含保存my_app.exe
的目录的路径。
更多详情,请参考以下 MSDN 页面:
https://msdn.microsoft.com/en-us/library/windows/desktop/ee872121%28v=vs.85%29.aspx
抱歉最初的错误!
【讨论】:
这无济于事,除非应用程序使用/DELAYLOAD 链接器选项。默认情况下,所有 DLL 导入都会在您的任何代码运行之前解析。无论如何设置工作目录都是错误的。 SetDllDirectory/AddDllDirectory 是适当的 API,它们的工作并非巧合。 @IInspectable 嗯,你是对的!我忘了导入之前已经解决了。这仅适用于延迟加载的 DLL,或者如果它们是使用LoadLibrary
动态加载的。
感谢@MarkoPopovic,这解决了我的问题。它不是 DLL,而是 SQLite 文件。我的程序在 Windows 目录中找不到或创建此文件。但是我发现我的程序在它自己的目录中查找 DLL。我猜这是因为动态链接的工作方式。
@Spiralwise:SetCurrentDirectory 不能解决您的问题。 CWD 是每个进程的属性。任何线程和任何库都可以随时更改 CWD(例如,通用文件对话框会这样做)。您的问题的解决方案是使用完全限定的路径名。是的,加载应用程序的目录位于Dynamic-Link Library Search Order 的顶部,所以这个答案既错误又没有任何帮助。
因为我的DLL和可执行文件在同一个目录下,所以这部分没有问题。由于@MarkoPopovic 的方法,我得到了完全限定的路径名,所以我不太明白到底出了什么问题。 (不过,我会更正我的帖子更新。)以上是关于Win32 应用程序在启动时不运行的主要内容,如果未能解决你的问题,请参考以下文章
Flyway Spring Boot应用程序在启动时不应用插入脚本
LaunchFullTrustProcessForCurrentAppAsync杀死win32应用程序