【问题标题】:Win32 application doesn't run on startupWin32 应用程序在启动时不运行
【发布时间】: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 一起使用,也不能直接使用。

标签: c++ winapi visual-studio-2015


【解决方案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 然后创建一个名为PathREG_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 的方法,我得到了完全限定的路径名​​,所以我不太明白到底出了什么问题。 (不过,我会更正我的帖子更新。)
猜你喜欢
  • 1970-01-01
  • 2021-08-23
  • 2015-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多