如何在 c++ 中调用 unicode 函数 CreateProcessW 来启动 Windows 可执行文件

How do I call the unicode function CreateProcessW in c++ to launch a Windows executable?

本文关键字:CreateProcessW 启动 Windows 可执行文件 函数 unicode c++ 调用      更新时间:2023-10-16

这里有一个如何在堆栈交换上调用CreateProcess的示例,但是Windows 10似乎不再支持此功能,您必须使用Unicode版本CreateProcessW。

与ASCI版本类似,我正在寻找一个例子:

  1. 启动 EXE
  2. 等待 EXE 完成。
  3. 可执行文件
  4. 完成后正确关闭所有句柄。

在这方面,Windows 10没有什么新鲜事。你的问题实际上是关于Unicode与ANSI,以及Visual Studio使用Unicode的新默认设置。

CreateProcess是宏,则定义为

#ifdef UNICODE
#define CreateProcess  CreateProcessW
#else
#define CreateProcess  CreateProcessA
#endif // !UNICODE

此外STARTUPINFO是用于STARTUPINFOASTARTUPINFOW的宏

CreateProcessA使用 ANSI 字符字符串char*STARTUPINFOA

CreateProcessW使用 Unicode 宽字符字符串wchar_t*STARTUPINFOW

如果您坚持使用 ANSI(不推荐),请转到项目设置 ->字符集并禁用 Unicode。

如果您坚持使用具有 Unicode 设置的 ANSI 版本(仍然不推荐),则需要

//Using ANSI when UNICODE is defined (not recommended):
STARTUPINFOA si = { sizeof(si) };
PROCESS_INFORMATION pi;
std::string path = "c:\windows\notepad.exe "c:\test\_text.txt"";
//if not using C++11 or later, force a zero at the end 
//to make sure path is null-ternminated
path.push_back(0);
if(CreateProcessA(NULL, &path[0], NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
{
    WaitForSingleObject(pi.hProcess, INFINITE); 
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
}

只要目录名称与 ANSI 兼容,上面的代码就可以工作。但推荐的版本是:

//recommended:
{
    STARTUPINFO si = { sizeof(si) };
    PROCESS_INFORMATION pi;
    std::wstring path = L"c:\windows\notepad.exe "c:\test\_text.txt"";
    //if not using C++11 or later, force a zero at the end 
    //to make sure path is null-ternminated
    path.push_back(0);
    if(CreateProcess(0, &path[0], NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
    {
        WaitForSingleObject(pi.hProcess, INFINITE);
        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);
    }
}

此外,不要按如下方式从常量字符串转换为字符串:

wchar_t* arg_concat = const_cast<wchar_t*>( input.c_str() );

wchar_t* CreateProcess中的第二个参数,因为该过程可能会修改命令行。

这个例子是注释的,希望是不言自明的。

#ifdef _WIN32
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <cstdlib>
#include <string>
#include <algorithm>
class process
{
public:
    static PROCESS_INFORMATION launchProcess(std::string app, std::string arg)
    {
        // Prepare handles.
        STARTUPINFO si;
        PROCESS_INFORMATION pi; // The function returns this
        ZeroMemory( &si, sizeof(si) );
        si.cb = sizeof(si);
        ZeroMemory( &pi, sizeof(pi) );
        //Prepare CreateProcess args
        std::wstring app_w(app.length(), L' '); // Make room for characters
        std::copy(app.begin(), app.end(), app_w.begin()); // Copy string to wstring.
        std::wstring arg_w(arg.length(), L' '); // Make room for characters
        std::copy(arg.begin(), arg.end(), arg_w.begin()); // Copy string to wstring.
        std::wstring input = app_w + L" " + arg_w;
        wchar_t* arg_concat = const_cast<wchar_t*>( input.c_str() );
        const wchar_t* app_const = app_w.c_str();
        // Start the child process.
        if( !CreateProcessW(
            app_const,      // app path
            arg_concat,     // Command line (needs to include app path as first argument. args seperated by whitepace)
            NULL,           // Process handle not inheritable
            NULL,           // Thread handle not inheritable
            FALSE,          // Set handle inheritance to FALSE
            0,              // No creation flags
            NULL,           // Use parent's environment block
            NULL,           // Use parent's starting directory
            &si,            // Pointer to STARTUPINFO structure
            &pi )           // Pointer to PROCESS_INFORMATION structure
        )
        {
            printf( "CreateProcess failed (%d).n", GetLastError() );
            throw std::exception("Could not create child process");
        }
        else
        {
            // Return process handle
            return pi;
        }

    }
    static bool checkIfProcessIsActive(PROCESS_INFORMATION pi)
    {
        // Check if handle is closed
            if ( pi.hProcess == NULL )
            {
                printf( "Process handle is closed or invalid (%d).n");
                return FALSE;
            }
        // If handle open, check if process is active
        DWORD lpExitCode = 0;
        if( GetExitCodeProcess(pi.hProcess, &lpExitCode) == 0)
        {
            printf( "Cannot return exit code (%d).n", GetLastError() );
            throw std::exception("Cannot return exit code");
        }
        else
        {
            if (lpExitCode == STILL_ACTIVE)
            {
                return TRUE;
            }
            else
            {
                return FALSE;
            }
        }
    }
    static bool stopProcess( PROCESS_INFORMATION &pi)
    {
        // Check if handle is invalid or has allready been closed
            if ( pi.hProcess == NULL )
            {
                printf( "Process handle invalid. Possibly allready been closed (%d).n");
                return 0;
            }
        // Terminate Process
            if( !TerminateProcess(pi.hProcess,1))
            {
                printf( "ExitProcess failed (%d).n", GetLastError() );
                return 0;
            }
        // Wait until child process exits.
            if( WaitForSingleObject( pi.hProcess, INFINITE ) == WAIT_FAILED)
            {
                printf( "Wait for exit process failed(%d).n", GetLastError() );
                return 0;
            }
        // Close process and thread handles.
            if( !CloseHandle( pi.hProcess ))
            {
                printf( "Cannot close process handle(%d).n", GetLastError() );
                return 0;
            }
            else
            {
                pi.hProcess = NULL;
            }
            if( !CloseHandle( pi.hThread ))
            {
                printf( "Cannot close thread handle (%d).n", GetLastError() );
                return 0;
            }
            else
            {
                 pi.hProcess = NULL;
            }
            return 1;
    }
};//class process
#endif //win32