C/C++ 打开外部程序
2023-02-18 16:46:19 时间
WinExec
int main()
{
/* WinExec
1.#include <Windows.h>
2.某些 exe 如果不使用管理员权限运行 VS 则会报 740 错误
*/
WinExec("E:\\MyToolBar\\Programming\\取色器.exe", SW_SHOWNORMAL);
cout << "取色器 GetLastError = " << GetLastError() << endl;
WinExec("D:\\MyFiles\\WeGame\\tgp_daemon.exe", SW_SHOWNORMAL);
cout << "tgp_daemon GetLastError = " << GetLastError() << endl;
WinExec("C:\\Windows\\SysNative\\calc.exe", SW_SHOWNORMAL);
cout << "calc GetLastError = " << GetLastError() << endl;
getchar();
return 0;
}
ShellExecute ShellExecute 在不使用管理员权限运行 VS2019 的情况下仍然可以正常打开任何程序,不报 740 错误。
int main()
{
/* ShellExecute
不需要使用管理员权限打开 VS2019 也可以打开 WinExec 不能打开的程序
*/
ShellExecute(
NULL, // 父窗口句柄
L"open", // edit:编辑,open:打开,print:打印,explore:浏览,find:搜索
L"E:\\MyToolBar\\Programming\\取色器.exe", // 文件全路径或文件夹名
NULL, // 程序启动时的命令行参数
NULL, // 默认操作目录为当前目录
SW_SHOWNORMAL // 显示方式 更多宏定义参考:https://docs.microsoft.com/zh-cn/windows/win32/api/winuser/nf-winuser-showwindow
); cout << "取色器 GetLastError = " << GetLastError() << endl;
ShellExecute(NULL,L"open",L"D:\\MyFiles\\WeGame\\tgp_daemon.exe",NULL,NULL,SW_SHOWNORMAL);
cout << "tgp_daemon GetLastError = " << GetLastError() << endl;
ShellExecute(NULL, L"open", L"C:\\Windows\\SysNative\\calc.exe", NULL, NULL, SW_SHOWNORMAL);
cout << "calc GetLastError = " << GetLastError() << endl;
getchar();
return 0;
}
ShellExecuteEX 与 ShellExecute 一样,ShellExecuteEX 也不需要管理员启动就可以打开所有进程
int main()
{
/* ShellExecuteEX
1.ZeroMemory(&sei, sizeof(SHELLEXECUTEINFO)); // 用 0x00 初始化内存
2.sei.cbSize = sizeof(SHELLEXECUTEINFO); // 必须加,否则无法打开程序
*/
// 初始化
SHELLEXECUTEINFO sei;
/* 参考:https://docs.microsoft.com/zh-cn/windows/win32/api/shellapi/ns-shellapi-shellexecuteinfoa
typedef struct _SHELLEXECUTEINFOA {
DWORD cbSize; // 必须存在,可以用 sizeof(SHELLEXECUTEINFO) 赋值
ULONG fMask; // 指定结构成员的有效性
HWND hwnd; // 父窗口句柄
LPCSTR lpVerb; // edit:编辑、explore:浏览、find:搜索、open:打开(默认)、print:打印、properties:显示属性、runas:管理员运行
LPCSTR lpFile; // 目标文件
LPCSTR lpParameters; // 程序启动参数
LPCSTR lpDirectory; // 工作目录
int nShow; // 显示方式
HINSTANCE hInstApp; // 接收 ShellExcuteEX 的返回值
void *lpIDList; // 指向 ITEMIDLIST 对象的指针
LPCSTR lpClass; // 附加信息,可以是程序标识符、协议类型、文件后缀、注册表路径
HKEY hkeyClass; // 当 fMask = SEE_MASK_CLASSNAME 时使用
DWORD dwHotKey; // 与应用程序关联的键盘快捷键
union {
HANDLE hIcon; // 目标文件图标句柄,fMask = SEE_MASK_ICON 时使用
HANDLE hMonitor; // 文档监视器句柄,fMask = SEE_MASK_HMONITOR 时使用
} DUMMYUNIONNAME;
HANDLE hProcess; // 新启动的应用程序的句柄
} SHELLEXECUTEINFOA, *LPSHELLEXECUTEINFOA;
*/
ZeroMemory(&sei, sizeof(SHELLEXECUTEINFO));
// 打开程序
sei.cbSize = sizeof(SHELLEXECUTEINFO);
sei.lpFile = L"E:\\MyToolBar\\Programming\\取色器.exe";
ShellExecuteEx(&sei);
cout << "取色器 GetLastError = " << GetLastError() << endl;
sei.lpFile = L"D:\\MyFiles\\WeGame\\tgp_daemon.exe";
ShellExecuteEx(&sei);
cout << "tgp_daemon GetLastError = " << GetLastError() << endl;
sei.lpFile = L"C:\\Windows\\SysNative\\calc.exe";
ShellExecuteEx(&sei);
cout << "calc GetLastError = " << GetLastError() << endl;
getchar();
return 0;
}
CreateProcess 这个函数启动外部程序可以说是一波三折,首先,先看下 ASCII 或者叫 UTF-8:
int main()
{
// 初始化
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
ZeroMemory(&pi, sizeof(pi));
BOOL bRet = CreateProcess(
NULL, // 不在此指定可执行文件的文件名
"E:\\MyToolBar\\Programming\\取色器.exe", // 命令行参数
NULL, // 默认进程安全性
NULL, // 默认线程安全性
FALSE, // 指定当前进程内的句柄不可以被子进程继承
CREATE_NEW_CONSOLE, // 为新进程创建一个新的控制台窗口,更多宏定义参考:https://docs.microsoft.com/zh-cn/windows/win32/procthread/process-creation-flags
NULL, // 使用本进程的环境变量
NULL, // 使用本进程的驱动器和目录
&si, // STARTUPINFO 结构体指针
&pi // PROCESS_INFORMATION 结构体指针
);if(!bRet){cout << "取色器 GetLastError = " << GetLastError() << endl; }
getchar();
return 0;
}
正常打开,没有什么问题
下面再看 Unicode 编码,仍然用上面的代码,运行一下,发现程序在调用 CreateProcess 的时候触发了空指针异常:
将代码改成如下:
int main()
{
// 初始化
WCHAR* szCommandLine = L"E:\\MyToolBar\\Programming\\取色器.exe";
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
ZeroMemory(&pi, sizeof(pi));
BOOL bRet = CreateProcess(
NULL, // 不在此指定可执行文件的文件名
szCommandLine , // 命令行参数
NULL, // 默认进程安全性
NULL, // 默认线程安全性
FALSE, // 指定当前进程内的句柄不可以被子进程继承
CREATE_NEW_CONSOLE, // 为新进程创建一个新的控制台窗口,更多宏定义参考:https://docs.microsoft.com/zh-cn/windows/win32/procthread/process-creation-flags
NULL, // 使用本进程的环境变量
NULL, // 使用本进程的驱动器和目录
&si, // STARTUPINFO 结构体指针
&pi // PROCESS_INFORMATION 结构体指针
);if(!bRet){cout << "取色器 GetLastError = " << GetLastError() << endl; }
getchar();
return 0;
}
发现异常仍然存在:
看下 MSDN 的介绍,发现 CreateProcess 的第二个参数有一句这么写到:
也就是说 CreateProcessW 的第二个参数不能是一个常量字符串,或者是一个指向只读地址的指针,这么也就说通了,因为L"E:\\MyToolBar\\Programming\\取色器.exe"
是常量字符串,WCHAR* szCommandLine = L"E:\\MyToolBar\\Programming\\取色器.exe";
是一个指针,那么最后验证一下它指向的是否是一个只读内存就可以了。
我使用 CE 验证的,通过勾选和不勾选 “可写”,可以发现 WCHAR* szCommandLine
的确是只读变量(指针):
既然这样我们只能修改代码:
int main()
{
// 初始化
WCHAR szCommandLine[] = L"E:\\MyToolBar\\Programming\\取色器.exe";
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
ZeroMemory(&pi, sizeof(pi));
BOOL bRet = CreateProcess(
NULL, // 不在此指定可执行文件的文件名
szCommandLine , // 命令行参数
NULL, // 默认进程安全性
NULL, // 默认线程安全性
FALSE, // 指定当前进程内的句柄不可以被子进程继承
CREATE_NEW_CONSOLE, // 为新进程创建一个新的控制台窗口,更多宏定义参考:https://docs.microsoft.com/zh-cn/windows/win32/procthread/process-creation-flags
NULL, // 使用本进程的环境变量
NULL, // 使用本进程的驱动器和目录
&si, // STARTUPINFO 结构体指针
&pi // PROCESS_INFORMATION 结构体指针
);if(!bRet){cout << "取色器 GetLastError = " << GetLastError() << endl; }
getchar();
return 0;
}
然后就可以正常运行了:
最后介绍下这两个结构体:
// 进程创建时的窗体信息
typedef struct _STARTUPINFO {
DWORD cb; // 结构体大小
LPWSTR lpReserved; // 保留,NULL
LPWSTR lpDesktop; // 进程 窗口站/桌面 名称
LPWSTR lpTitle; // 控制台进程的窗口标题
DWORD dwX; // 窗口左上角 x坐标
DWORD dwY; // 窗口左上角 y坐标
DWORD dwXSize; // 窗口宽
DWORD dwYSize; // 窗口高
DWORD dwXCountChars; // 屏幕缓冲区宽度
DWORD dwYCountChars; // 屏幕缓冲区高度
DWORD dwFillAttribute; // 控制台初始字体和背景色
DWORD dwFlags; // 控制其他参数哪个生效的宏 (关键)参考:https://docs.microsoft.com/zh-cn/windows/win32/api/processthreadsapi/ns-processthreadsapi-startupinfow
WORD wShowWindow; //
WORD cbReserved2; // 保留,NULL
LPBYTE lpReserved2; // 保留,NULL
HANDLE hStdInput; // 标准输入句柄(默认是键盘缓冲区)
HANDLE hStdOutput; // 标准输出句柄(默认是控制台缓冲区)
HANDLE hStdError; // 标准错误句柄(默认是控制台缓冲区)
} STARTUPINFO, *LPSTARTUPINFO;
/*******************************************/
// 新进程创建时的进程和主线程信息
typedef struct _PROCESS_INFORMATION {
HANDLE hProcess; // 新创建进程的句柄
HANDLE hThread; // 新创建进程的主线程的句柄
DWORD dwProcessId; // 新创建进程的 PID
DWORD dwThreadId; // 新创建进程的主线程的 TID
} PROCESS_INFORMATION, *PPROCESS_INFORMATION, *LPPROCESS_INFORMATION;
相关文章
- Linux 文件操作命令(cat tac竟然可以反着写)
- Linux:Find命令详解-找对象
- Golang模拟实现任务调度状态检测
- 卡塔尔世界杯门线技术(GOAL LINE TECHNOLOGY)背后的黑科技
- linux-top命令
- Linux 命令(215)—— iptables 命令
- Linux 命令(216)—— iptables-save 命令
- Linux 命令(217)—— iptables-restore 命令
- Linux 命令(218)—— lnstat 命令
- Golang 判断是否为 zip 文件
- 《安富莱嵌入式周报》第295期:世界杯球员和足球实时跟踪,开源手持矢量网络分析仪,自制柔性电容式传感器,IAR加强对VSCode支持、索尼早期PSX的光驱模拟器
- 你不知道的 Git 技巧:如何实现核心代码保护
- C++基础入门丨6. 函数——定义、调用和声明
- 嵌入式:ARM立即寻址与寄存器寻址
- .NET Core应用如何通过SSL访问MongoDB?
- USB总线-Linux内核USB3.0设备控制器之dwc3 gadget驱动初始化过程分析(五)
- Linux服务器多公网IP多出口配置
- 微星B550主板修改BIOS开机启动Logo
- 嵌入式:ARM间接寻址、变址寻址与多寄存器寻址
- PHP 处理数据为树状结构