VCpp的CreateProcess函数和ShellExecute函数

⌚Time: 2022-12-28 11:48:16

👨‍💻Author: Jack Ge

AI生成,由我提问

CreateProcess 和 ShellExecute 函数详解

这两个Windows API函数都用于创建进程或执行程序,但功能和用法有显著区别。


一、CreateProcess 函数

1. 函数原型

BOOL CreateProcess(
  LPCTSTR lpApplicationName,           // 可执行文件名称
  LPTSTR lpCommandLine,                 // 命令行参数
  LPSECURITY_ATTRIBUTES lpProcessAttributes,   // 进程安全属性
  LPSECURITY_ATTRIBUTES lpThreadAttributes,    // 线程安全属性
  BOOL bInheritHandles,                  // 句柄继承标志
  DWORD dwCreationFlags,                 // 创建标志
  LPVOID lpEnvironment,                   // 环境变量
  LPCTSTR lpCurrentDirectory,             // 当前目录
  LPSTARTUPINFO lpStartupInfo,            // 启动信息
  LPPROCESS_INFORMATION lpProcessInformation // 进程信息
);

2. 基本使用示例

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

int main() {
    STARTUPINFO si = { sizeof(si) };
    PROCESS_INFORMATION pi;
    
    // 创建一个记事本进程
    BOOL success = CreateProcess(
        L"C:\\Windows\\System32\\notepad.exe",  // 应用程序路径
        NULL,           // 命令行参数
        NULL,           // 进程安全属性
        NULL,           // 线程安全属性
        FALSE,          // 不继承句柄
        0,              // 默认创建标志
        NULL,           // 使用父进程环境变量
        NULL,           // 使用父进程当前目录
        &si,            // 启动信息
        &pi             // 进程信息
    );
    
    if (success) {
        std::wcout << L"进程创建成功!" << std::endl;
        std::wcout << L"进程ID: " << pi.dwProcessId << std::endl;
        std::wcout << L"线程ID: " << pi.dwThreadId << std::endl;
        
        // 等待进程结束
        WaitForSingleObject(pi.hProcess, INFINITE);
        
        // 关闭句柄
        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);
    } else {
        std::wcout << L"进程创建失败,错误码: " << GetLastError() << std::endl;
    }
    
    return 0;
}

3. 高级用法示例

// 带命令行参数的创建
CreateProcess(
    L"C:\\Windows\\System32\\cmd.exe",
    L" /c dir C:\\",   // 注意:前面需要空格
    NULL, NULL, FALSE,
    CREATE_NEW_CONSOLE, // 创建新控制台窗口
    NULL, NULL, &si, &pi
);

// 隐藏窗口执行
STARTUPINFO si = { sizeof(si) };
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;  // 隐藏窗口

CreateProcess(
    L"C:\\MyApp.exe",
    NULL, NULL, NULL, FALSE,
    CREATE_NO_WINDOW,     // 不创建窗口
    NULL, NULL, &si, &pi
);

二、ShellExecute 函数

1. 函数原型

HINSTANCE ShellExecute(
  HWND hwnd,           // 父窗口句柄
  LPCTSTR lpOperation, // 操作类型 ("open", "print", "explore"等)
  LPCTSTR lpFile,      // 要操作的文件
  LPCTSTR lpParameters,// 参数
  LPCTSTR lpDirectory, // 默认目录
  INT nShowCmd         // 显示方式
);

2. 基本使用示例

#include <windows.h>
#include <shellapi.h>  // 需要包含此头文件
#include <iostream>

int main() {
    // 1. 打开记事本
    HINSTANCE result = ShellExecute(
        NULL,                 // 父窗口句柄
        L"open",              // 操作类型
        L"notepad.exe",       // 程序名
        NULL,                 // 参数
        NULL,                 // 默认目录
        SW_SHOWNORMAL         // 正常显示
    );
    
    // 检查返回值(大于32表示成功)
    if ((int)result > 32) {
        std::wcout << L"执行成功!" << std::endl;
    } else {
        std::wcout << L"执行失败,错误码: " << (int)result << std::endl;
    }
    
    // 2. 打开文件(使用关联程序)
    ShellExecute(NULL, L"open", L"C:\\document.txt", NULL, NULL, SW_SHOWNORMAL);
    
    // 3. 打开网址
    ShellExecute(NULL, L"open", L"https://www.example.com", NULL, NULL, SW_SHOWNORMAL);
    
    // 4. 打印文档
    ShellExecute(NULL, L"print", L"C:\\document.txt", NULL, NULL, SW_HIDE);
    
    // 5. 浏览文件夹
    ShellExecute(NULL, L"explore", L"C:\\Windows", NULL, NULL, SW_SHOWNORMAL);
    
    // 6. 以管理员权限运行(需要UAC提示)
    ShellExecute(NULL, L"runas", L"setup.exe", NULL, NULL, SW_SHOWNORMAL);
    
    return 0;
}

3. 更多用法示例

// 使用ShellExecute执行带参数的程序
ShellExecute(
    NULL, 
    L"open", 
    L"cmd.exe", 
    L"/c dir C:\\",  // 命令行参数
    NULL, 
    SW_HIDE          // 隐藏窗口
);

// 发送邮件
ShellExecute(
    NULL,
    L"open",
    L"mailto:someone@example.com?subject=Hello&body=Test",
    NULL, NULL, SW_SHOWNORMAL
);

三、主要区别对比

特性 CreateProcess ShellExecute
用途 专门创建进程 执行文件操作、打开文档、运行程序
功能范围 只能执行可执行文件 可以打开任意文件(使用关联程序)
灵活性 高度可控,可设置进程属性 简单易用,但控制较少
返回值 详细的进程信息 简单成功/失败指示
权限控制 可使用进程安全属性 支持runas提权
资源消耗 较高 较低
异步/同步 可同步等待进程结束 默认异步

四、选择建议

使用 CreateProcess 的场景:

使用 ShellExecute 的场景:


五、综合示例

// 一个更完整的比较示例
#include <windows.h>
#include <shellapi.h>
#include <iostream>
#include <string>

// 使用CreateProcess执行并等待
bool RunWithCreateProcess(const std::wstring& appPath, const std::wstring& args) {
    STARTUPINFO si = { sizeof(si) };
    PROCESS_INFORMATION pi;
    
    std::wstring cmdLine = L"\"" + appPath + L"\" " + args;
    
    if (CreateProcess(NULL, &cmdLine[0], NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
        WaitForSingleObject(pi.hProcess, INFINITE);  // 等待完成
        
        DWORD exitCode;
        GetExitCodeProcess(pi.hProcess, &exitCode);
        
        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);
        
        std::wcout << L"CreateProcess: 退出码 = " << exitCode << std::endl;
        return true;
    }
    return false;
}

// 使用ShellExecute执行(异步)
bool RunWithShellExecute(const std::wstring& operation, const std::wstring& file) {
    HINSTANCE result = ShellExecute(NULL, operation.c_str(), file.c_str(), NULL, NULL, SW_SHOWNORMAL);
    return ((int)result > 32);
}

int main() {
    // 使用CreateProcess运行命令并等待
    RunWithCreateProcess(L"C:\\Windows\\System32\\cmd.exe", L"/c dir C:\\ > c:\\dir.txt");
    
    // 使用ShellExecute打开文本文件
    RunWithShellExecute(L"open", L"C:\\dir.txt");
    
    // 使用ShellExecute打开网址
    RunWithShellExecute(L"open", L"https://www.example.com");
    
    return 0;
}

这两个函数各有优势,根据具体需求选择合适的函数可以提高开发效率。