当前位置: 首页 > web >正文

【C++】在 Windows 系统调用第三方程序(创建进程)

文章目录

  • 零、对比总结
  • 一、通过 CreateProcess 调用第三方程序
    • 1.1 官方 API 文档
    • 1.2 API 介绍
    • 1.3 使用示例
      • 1.3.1 简单调用
      • 1.3.2 调用+挂起+执行
  • 二、通过 ShellExecute 调用第三方程序
    • 2.1 官方 API 文档
    • 2.2 API 介绍
      • 2.2.1 ShellExecute
      • 2.2.2 ShellExecuteEx

零、对比总结

注意:以下 API 都需要包含头文件 #include <windows.h>
注意:以下 API 都需要包含头文件 #include <windows.h>
注意:以下 API 都需要包含头文件 #include <windows.h>

特性CreateProcessShellExecuteShellExecuteEx
复杂度中等
性能最高中等中等
文件关联不支持支持支持
进程句柄支持不支持支持
同步执行支持不支持支持
打开文档不支持支持支持
管理员权限复杂支持支持
错误处理详细简单详细
重定向IO支持不支持不支持

选择建议

  1. 使用 CreateProcess:
    • 需要精确控制进程创建
    • 需要重定向输入输出
    • 只启动可执行文件
    • 对性能要求很高
  2. 使用 ShellExecute:
    • 简单的文件打开操作
    • 不需要等待进程结束
    • 打开文档、网页等
    • 代码简洁性优先
  3. 使用 ShellExecuteEx:
    • 需要等待进程结束(如安装程序)
    • 需要以管理员权限运行
    • 需要进程句柄进行后续操作
    • 平衡功能和易用性

一、通过 CreateProcess 调用第三方程序

1.1 官方 API 文档

  CreateProcess 是宏定义,实际使用的是 CreateProcessACreateProcessW 函数,他会根据是否定义了 UNICODE 宏来决定使用哪个版本,如果定义了,则使用 CreateProcessW 版本,否则,则使用 CreateProcessA 版本。

访问:CreateProcessA    CreateProcessW

1.2 API 介绍

BOOL CreateProcess([in, optional]      LPCSTR                lpApplicationName,[in, out, optional] LPSTR                 lpCommandLine,[in, optional]      LPSECURITY_ATTRIBUTES lpProcessAttributes,[in, optional]      LPSECURITY_ATTRIBUTES lpThreadAttributes,[in]                BOOL                  bInheritHandles,[in]                DWORD                 dwCreationFlags,[in, optional]      LPVOID                lpEnvironment,[in, optional]      LPCSTR                lpCurrentDirectory,[in]                LPSTARTUPINFOA        lpStartupInfo,[out]               LPPROCESS_INFORMATION lpProcessInformation
);
  1. lpApplicationName —— 第三方程序路径,比如:D:\yyh\earn_money.exe ,也可以填 NULL ,如果为 NULL,则第二个参数必须指定第三方程序路径
  2. lpCommandLine —— 调用参数,比如:--earn ,如果第一个参数为 NULL,则该参数必须指定第三方程序路径,同时为了区分第三方程序路径和参数,最好使用双引号将路径包裹起来(避免路径中有空格而造成错误),例如:"D:\yyh day\sleep.exe" --sleep
  3. lpProcessAttributes —— 进程安全属性,99% 的情况下都填 NULL ,除非需要特殊的安全设置或句柄继承控制
  4. lpThreadAttributes —— 线程安全属性,99% 的情况下都填 NULL ,除非需要特殊的安全设置或句柄继承控制
  5. bInheritHandles —— 继承句柄,子进程是否可以继承父进程的句柄,一般填 FALSE ,除非被创建的进程需要共享父进程打开的资源(文件、管道、事件等),才填 TRUE
  6. dwCreationFlags —— 创建标志,具体可以访问:进程创建标志,下面列出一些常用的:
    • 0 - 默认值,正常创建进程
    • CREATE_SUSPENDED - 创建后立即挂起主线程,只有调用 ResumeThread 函数后才执行。
  7. lpEnvironment —— 环境,一般填 NULL ,表示继承父进程的环境,除非使用新的环境变量;
  8. lpCurrentDirectory —— 当前目录,一般填 NULL ,表示继承父进程的工作目录,除非使用新的工作目录;
  9. lpStartupInfo —— 启动信息,用于指定新进程主窗口的外观和行为,参数类型如下:
typedef struct _STARTUPINFO {DWORD  cb;              // 结构体大小LPSTR  lpReserved;      // 保留,必须为NULLLPSTR  lpDesktop;       // 桌面名称LPSTR  lpTitle;         // 控制台窗口标题DWORD  dwX;             // 窗口左上角X坐标DWORD  dwY;             // 窗口左上角Y坐标DWORD  dwXSize;         // 窗口宽度DWORD  dwYSize;         // 窗口高度DWORD  dwXCountChars;   // 控制台缓冲区宽度(字符)DWORD  dwYCountChars;   // 控制台缓冲区高度(字符)DWORD  dwFillAttribute; // 控制台文本和背景颜色DWORD  dwFlags;         // 指定哪些成员有效WORD   wShowWindow;     // 窗口显示状态WORD   cbReserved2;     // 保留,必须为0LPBYTE lpReserved2;     // 保留,必须为NULLHANDLE hStdInput;       // 标准输入句柄HANDLE hStdOutput;      // 标准输出句柄HANDLE hStdError;       // 标准错误句柄
} STARTUPINFO;

常用的初始化流程:

STARTUPINFO si = {0};
si.cb = sizeof(STARTUPINFO);CreateProcess(NULL, L"xxx.exe", NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
STARTUPINFO si = {0};
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_USESHOWWINDOW; // 使用 wShowWindow
si.wShowWindow = SW_HIDE;  // 隐藏窗口CreateProcess(NULL, L"xxx.exe", NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
  1. lpProcessInformation —— 进程信息,输出参数,指向 PROCESS_INFORMATION 结构体,用于接收新创建进程和线程的信息,参数类型:
typedef struct _PROCESS_INFORMATION {HANDLE hProcess;      // 新进程的句柄HANDLE hThread;       // 新进程主线程的句柄DWORD  dwProcessId;   // 新进程的进程ID (PID)DWORD  dwThreadId;    // 新进程主线程的线程ID (TID)
} PROCESS_INFORMATION;

可以用来控制创建的进程的状态,比如:

STARTUPINFO si = {0};
PROCESS_INFORMATION pi = {0};  // 接收进程信息
si.cb = sizeof(STARTUPINFO);BOOL success = CreateProcess(NULL, L"xxx.exe", NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);if (success) {printf("进程ID: %d\n", pi.dwProcessId);printf("线程ID: %d\n", pi.dwThreadId);// 恢复进程执行ResumeThread(pi.hThread);// 等待进程结束WaitForSingleObject(pi.hProcess, INFINITE);// 获取退出代码DWORD exitCode;GetExitCodeProcess(pi.hProcess, &exitCode);// 必须关闭句柄CloseHandle(pi.hProcess);CloseHandle(pi.hThread);
}
  1. 返回值,创建成功返回 TRUE ,失败返回 FALSE

1.3 使用示例

1.3.1 简单调用

  std::wstring cmdLine = L"\"D:\\yyh\\happy.exe\" --play --eat";STARTUPINFO si = {sizeof(si)};PROCESS_INFORMATION pi;BOOL success = CreateProcess(NULL,                                 // 应用程序名称const_cast<LPWSTR>(cmdLine.c_str()),  // 命令行NULL,                                 // 进程安全属性NULL,                                 // 线程安全属性FALSE,                                // 继承句柄0,                                    // 创建标志NULL,                                 // 环境NULL,                                 // 当前目录&si,                                  // 启动信息&pi                                   // 进程信息);if (success) {WaitForSingleObject(pi.hProcess, INFINITE); // 等待进程完成DWORD exitCode;GetExitCodeProcess(pi.hProcess, &exitCode); // 获取退出码CloseHandle(pi.hProcess);CloseHandle(pi.hThread);return exitCode;} else {DWORD err = GetLastError(); // 获取错误信息return err;}

1.3.2 调用+挂起+执行

  std::wstring exePath = L"D:\\yyh\\happy.exe";std::wstring param = L"--play --eat";STARTUPINFO si = {sizeof(si)};PROCESS_INFORMATION pi;// 创建进程BOOL success = CreateProcess(exePath,           // 应用程序名称param,             // 命令行NULL,              // 进程安全属性NULL,              // 线程安全属性FALSE,             // 继承句柄CREATE_SUSPENDED,  // 创建标志 - 先挂起,检查成功后再恢复NULL,              // 环境NULL,              // 当前目录&si,               // 启动信息&pi                // 进程信息);DWORD exitCode;if (success) {// 恢复进程执行ResumeThread(pi.hThread);// 等待进程完成,设置超时时间(5分钟)DWORD waitResult = WaitForSingleObject(pi.hProcess, 5 * 60 * 1000);if (waitResult == WAIT_TIMEOUT) {// 超时,直接强制终止TerminateProcess(pi.hProcess, 1);exitCode = -1;} else if (waitResult == WAIT_OBJECT_0) {// 进程正常结束,获取退出码if (!GetExitCodeProcess(pi.hProcess, &exitCode)) {// 获取退出码失败exitCode = GetLastError();}} else {// 等待进程完成出现其他问题exitCode = GetLastError();}CloseHandle(pi.hProcess);CloseHandle(pi.hThread);} else {// 创建进程失败DWORD exitCode = GetLastError();// 根据具体错误码提供更详细的错误信息switch (exitCode) {case ERROR_FILE_NOT_FOUND:Logger::LogDebug(L"没有找到文件!");break;case ERROR_ACCESS_DENIED:Logger::LogDebug(L"权限不够!");break;case ERROR_BAD_EXE_FORMAT:Logger::LogDebug(L"非法的调用格式!");break;case ERROR_OUTOFMEMORY:Logger::LogDebug(L"超过内存限制!");break;case ERROR_PATH_NOT_FOUND:Logger::LogDebug(L"没有找到路径!");break;default:Logger::LogDebug(L"不知道什么问题!");break;}}return exitCode;

二、通过 ShellExecute 调用第三方程序

2.1 官方 API 文档

  ShellExecute 也是宏定义,实际使用时也是根据是否定义了 UNICODE 宏来判断使用哪个版本,如果定义了,则使用 ShellExecuteW 版本,或者使用 ShellExecuteA 版本。
  ShellExecute异步的,创建完只知道是否创建成功,不知道运行情况。如果需要知道运行情况,则使用增强版本 ShellExecuteEx ,同样,它也是宏定义,实际也是根据 UNICODE 来决定使用 ShellExecuteExA 还是 ShellExecuteExW

访问:ShellExecuteA    ShellExecuteW    ShellExecuteExA    ShellExecuteExW

2.2 API 介绍

2.2.1 ShellExecute

HINSTANCE ShellExecute([in, optional] HWND   hwnd,[in, optional] LPCSTR lpOperation,[in]           LPCSTR lpFile,[in, optional] LPCSTR lpParameters,[in, optional] LPCSTR lpDirectory,[in]           INT    nShowCmd
);
  1. hwnd
    类型: HWND
    功能: 父窗口句柄
    说明: 如果操作失败需要显示错误对话框,该对话框的父窗口。可以为 NULL
  2. lpOperation
    类型: LPCSTR
    功能: 指定要执行的操作
    常用值:
    • open” - 打开文件或程序(默认操作)
    • edit” - 编辑文件
    • print” - 打印文件
    • explore” - 浏览文件夹
    • find” - 搜索
    • runas” - 以管理员权限运行
    • NULL - 使用默认操作
  3. lpFile
    类型: LPCSTR
    功能: 要打开的文件名或程序名
    示例:"notepad.exe" ,"C:\\test.txt","https://www.example.com"
  4. lpParameters
    类型: LPCSTR
    功能: 传递给程序的命令行参数
    说明: 如果 lpFile 是文档文件,此参数应为 NULL
  5. lpDirectory
    类型: LPCSTR
    功能: 指定工作目录
    说明: 程序启动时的当前目录,可以为 NULL
  6. nShowCmd
    类型: INT
    功能: 指定程序窗口的显示方式
    常用值:
    • SW_HIDE (0) - 隐藏窗口
    • SW_SHOWNORMAL (1) - 正常显示
    • SW_SHOWMINIMIZED (2) - 最小化显示
    • SW_SHOWMAXIMIZED (3) - 最大化显示
  7. 返回值
    成功: 返回值 > 32
    失败: 返回值 ≤ 32,具体错误码含义:
0: 内存不足
2: 文件未找到
3: 路径未找到
5: 访问被拒绝
8: 内存不足
26: 共享冲突
27: 关联不完整
28: DDE 超时
29: DDE 失败
30: DDE 忙
31: 没有关联

2.2.2 ShellExecuteEx

BOOL ShellExecuteExW([in, out] SHELLEXECUTEINFOW *pExecInfo
);
  1. pExecInfo —— 执行信息,类型为 SHELLEXECUTEINFO* ,结构如下:
typedef struct _SHELLEXECUTEINFO {DWORD     cbSize;           // 结构体大小ULONG     fMask;            // 标志位,指定哪些成员有效HWND      hwnd;             // 父窗口句柄LPCSTR    lpVerb;           // 操作类型(如 "open", "runas")LPCSTR    lpFile;           // 要执行的文件LPCSTR    lpParameters;     // 命令行参数LPCSTR    lpDirectory;      // 工作目录int       nShow;            // 窗口显示方式HINSTANCE hInstApp;         // 应用程序实例句柄(输出)LPVOID    lpIDList;         // PIDL(项目标识符列表)LPCSTR    lpClass;          // 文件类HKEY      hkeyClass;        // 注册表键DWORD     dwHotKey;         // 热键union {HANDLE  hIcon;            // 图标句柄HANDLE  hMonitor;         // 监视器句柄} DUMMYUNIONNAME;HANDLE    hProcess;         // 进程句柄(输出)
} SHELLEXECUTEINFO, *LPSHELLEXECUTEINFO;

实际使用时,不需要每个参数都要填写,只需要指定部分参数即可,例如:

SHELLEXECUTEINFO sei = { 0 };
sei.cbSize = sizeof(SHELLEXECUTEINFO); // 结构体大小
sei.fMask = SEE_MASK_NOCLOSEPROCESS; // 保持进程句柄打开,可以通过 hProcess 获取进程句柄
sei.hwnd = NULL;
sei.lpVerb = "open"; // 打开文件,如果要以管理员权限打开,则改为 "runas"
sei.lpFile = "xxx.exe";
sei.lpParameters = "--abc --cde";
sei.lpDirectory = NULL;
sei.nShow = SW_SHOWNORMAL; // 正常显示窗口if (ShellExecuteEx(&sei)) {// 成功启动if (sei.hProcess) {// 等待进程结束WaitForSingleObject(sei.hProcess, INFINITE);CloseHandle(sei.hProcess);}
} else {// 失败处理DWORD error = GetLastError();
}
http://www.xdnf.cn/news/20034.html

相关文章:

  • 专项智能练习(Photoshop软件基础)
  • mysql高级进阶(存储过程)
  • H3C UIS Cell 3020 G3服务器更换raid卡安装ONEStor记录
  • windows系统服务器测试部署springboot+vue+mysql项目
  • 企业网络安全建设三阶段实战指南
  • 商家自动运营(四)足浴店管理—东方仙盟
  • 一文掌握Redisson分布式锁
  • 【Rhino】【Python】将开放曲面转换为边界线和填充
  • [特殊字符] DA1-13 复习学习笔记
  • 极空间打造 “超级中枢”,从书签笔记到聊天分享,一键全搞定!
  • 非力扣100原题
  • FTL文件格式的原理与应用(AI)
  • AI歌手功能终于上线!Suno AI 带你保存歌曲的灵魂
  • 【教程】2025 IDEA 快速创建springboot(maven)项目
  • spring boot autoconfigure 自动配置的类,和手工 @configuration + @bean 本质区别
  • 硬件开发1-51单片机2-按键、中断
  • 域名不做网站使用,还需要备案吗
  • 这才是真正懂C/C++的人,写代码时怎么区分函数指针和指针函数?
  • Qt + windows + Linux+QtInstallerFramework打包教程
  • RabbitMQ相关知识
  • 基于 STM32N6-AI Image Classification 使用 git bash 命令行示例 LAT1552
  • 单片机点灯
  • 【C++上岸】C++常见面试题目--算法篇(第十八期)
  • 网络:tcp
  • 关于稳定币的一些问答
  • 封装一个redis获取并解析数据的工具类
  • FPGA学习笔记——SDR SDRAM简介
  • 【golang长途旅行第37站】Redis连接池
  • OCR 发票识别与验真接口:助力电子化发票新时代
  • 融云:当我们谈论 AI 重构业务时,我们到底在谈论什么