【问题标题】:Chaining multiple ShellExecute calls链接多个 ShellExecute 调用
【发布时间】:2010-03-15 16:38:40
【问题描述】:

考虑以下代码及其可执行文件 - runner.exe

#include <iostream>
#include <string>
#include <windows.h>

using namespace std;

int main(int argc, char *argv[])
{
    SHELLEXECUTEINFO shExecInfo;

    shExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);

    shExecInfo.fMask = NULL;
    shExecInfo.hwnd = NULL;
    shExecInfo.lpVerb = "open";
    shExecInfo.lpFile = argv[1];

    string Params = "";
    for ( int i = 2; i < argc; ++i )
        Params += argv[i] + ' ';

    shExecInfo.lpParameters = Params.c_str();

    shExecInfo.lpDirectory = NULL;
    shExecInfo.nShow = SW_SHOWNORMAL;
    shExecInfo.hInstApp = NULL;

    ShellExecuteEx(&shExecInfo);

    return 0;
}

这两个批处理文件都做了它们应该做的事情,即运行 notepad.exe 并运行 notepad.exe 并告诉它尝试打开 test.txt:

1.
runner.exe notepad.exe

2.
runner.exe notepad.exe test.txt

现在,考虑这个批处理文件:

3.
runner.exe runner.exe notepad.exe

这个应该运行 runner.exe 并将 notepad.exe 作为其命令行参数之一发送,不是吗?然后,runner.exe 的第二个实例应该运行 notepad.exe - 这不会发生,我得到一个“Windows 找不到 'am'。确保你输入了正确的名称,然后再试一次”错误。如果我打印argc 参数,则 14 表示第二个 runner.exe 实例,它们都是奇怪的东西,例如 Files\Microsoft、SQL、Files\Common 等等。我不明白为什么会这样。我希望能够使用命令行参数将尽可能多的 runner.exe 调用串起来,或者至少 2 个。我该怎么做?

如果有什么不同,我正在使用 Windows 7。

【问题讨论】:

  • 工作目录是什么?
  • 你能在调用ShellExecute函数之前尝试打印出SHELLEXECUTEINFO结构的值吗?
  • @lunixbochs - bat 文件和 runner.exe 文件都在同一个目录中。 notepad.exe 在其他地方,但它应该有关系,因为runner.exe notepad.exe 工作正常吗? shExecInfo.lpDirectory = NULL; 会是问题吗?我不确定我是否回答了你的问题,如果我没有回答,对不起......
  • @dirkgently - 你如何打印结构的值?您是指shExecInfo 变量的地址吗?程序的两个实例的地址是相同的 - 这应该发生吗?

标签: c++ winapi shellexecute


【解决方案1】:

你在这一行有一个错误:

Params += argv[i] + ' ';

这会将 32 添加到指针 argv[i],这不是您想要的。你可以把它分成两行:

Params += argv[i];
Params += ' ';

或使用:

Params += string(argv[i]) + ' ';

您可能还想在每个参数周围添加引号,以防它包含空格。


我还将 fMask 设置为 SEE_MASK_NOASYNC,因为 MSDN 声明:

在调用 ShellExecuteEx 后立即退出的应用程序应指定此标志。

【讨论】:

  • 成功了,谢谢!我忘记了 argv[i] 是一个指针。
【解决方案2】:

问题出在这一行:

Params += argv[i] + ' '

因为argv[i]char * 类型,所以将32 加到argv[i] 所以会给你一个指向随机内存中间的指针。

我会把它改写成:

Params += std::string(argv[i]) + ' ';

或者,如果你想变得更好,你可以修改它,只在真正需要的时候添加一个空格:

for ( int i = 2; i < argc; ++i )
{
    if (!Params.empty())
        Params += ' ';
    Params += argv[i];
}

【讨论】:

    【解决方案3】:

    我认为问题在于如何为下一次调用创建命令行参数:

     Params += argv[i] + ' ';
    

    没有按预期工作。尝试以下方法:

    #include <windows.h>
    #include <fstream>
    #include <iostream>
    #include <tchar.h>
    using namespace std;
    
    #ifdef _UNICODE
        typedef std::wstring tstring;
    #else
        typedef std::string tstring;
    #endif
    
    int _tmain(int argc, TCHAR *argv[])
    {
        {
            std::ofstream f("C:\\output.txt", std::ios::app);
            f << "app called" << std::endl;
        }
        SHELLEXECUTEINFO shExecInfo;
    
        shExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
    
        shExecInfo.fMask = NULL;
        shExecInfo.hwnd = NULL;
        shExecInfo.lpVerb = _T("open");
        shExecInfo.lpFile = argv[1];
    
        tstring Params(_T(""));
        for ( int i = 2; i < argc; ++i )
        {
            Params += argv[i]; 
            Params += _T(' ');
        }
    
        shExecInfo.lpParameters = Params.c_str();
    
        shExecInfo.lpDirectory = NULL;
        shExecInfo.nShow = SW_SHOWNORMAL;
        shExecInfo.hInstApp = NULL;
    
        ShellExecuteEx(&shExecInfo);
    
        return 0;
    }
    

    【讨论】:

    • @dirkgently - 希望你不介意,但我将你的代码修改为完全启用 tchar,因此它可以在 Unicode 或 MBCS 模式下编译。
    猜你喜欢
    • 2012-06-25
    • 2018-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-16
    • 1970-01-01
    • 1970-01-01
    • 2018-03-24
    相关资源
    最近更新 更多