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

ShellExecuteEx使用方法与常用实例

一、ShellExecuteEx

使用 ShellExecuteEx 打开文件或执行程序
可以使用 ShellExecuteEx 打开文件或执行程序,与 ShellExecute 比较,ShellExecuteEx 提供了更多的控制。
原型:

BOOL ShellExecuteEx(
  _Inout_ SHELLEXECUTEINFO *pExecInfo
);
SHELLEXECUTEINFO参数说明:
typedef struct _SHELLEXECUTEINFO {
  DWORD     cbSize;//结构大小,sizeof(SHELLEXECUTEINFO)
  ULONG     fMask;//指定结构成员的有效性
  HWND      hwnd;//父窗口句柄或出错时显示错误父窗口的句柄,可以为 NULL
  LPCTSTR   lpVerb;//指定该函数的执行动作
  LPCTSTR   lpFile;//操作对象路径
  LPCTSTR   lpParameters;//执行参数,可以为 ULL
  LPCTSTR   lpDirectory;//工作目录,可以为 NULL
  int       nShow;//显示方式
  HINSTANCE hInstApp;//如果设置了 SEE_MASK_NOCLOSEPROCESS ,并且调用成功则该值大于32,调用失败者被设置错误值
  LPVOID    lpIDList;//ITEMIDLIST结构的地址,存储成员的特别标识符,当fMask不包括SEE_MASK_IDLIST或SEE_MASK_INVOKEIDLIST时该项被忽略
  LPCTSTR   lpClass;//指明文件类别的名字或GUID,当fMask不包括SEE_MASK_CLASSNAME时该项被忽略
  HKEY      hkeyClass;//获得已在系统注册的文件类型的Handle,当fMask不包括SEE_MASK_HOTKEY时该项被忽略
  DWORD     dwHotKey;//程序的热键关联,低位存储虚拟关键码(Key Code),高位存储修改标志位(HOTKEYF_),当fmask不包括SEE_MASK_HOTKEY时该项被忽略
  union {
    HANDLE hIcon;//取得对应文件类型的图标的Handle,当fMask不包括SEE_MASK_ICON时该项被忽略
    HANDLE hMonitor;//将文档显示在显示器上的Handle,当fMask不包括SEE_MASK_HMONITOR时该项被忽略
  } DUMMYUNIONNAME;
  HANDLE    hProcess;//指向新启动的程序的句柄。若fMask不设为SEE_MASK_NOCLOSEPROCESS则该项值为NULL。
                     //但若程序没有启动,即使fMask设为SEE_MASK_NOCLOSEPROCESS,该值也仍为NULL。
                     //如果没有新创建进程,也会为空
} SHELLEXECUTEINFO, *LPSHELLEXECUTEINFO;

fMask 用于指定结构成员的内容和有效性,可为下列值的组合:
SEE_MASK_DEFAULT (0)默认
SEE_MASK_CLASSNAME 使用 lpClass 参数,如果 SEE_MASK_CLASSKEY 也有效,则用后者
SEE_MASK_CLASSKEY 使用 hkeyClass 参数
SEE_MASK_IDLIST 使用 lpIDList 参数
SEE_MASK_INVOKEIDLIST 使用选定项目的快捷菜单 IContextMenu 接口处理程序
SEE_MASK_ICON 使用 hIcon 给出的菜单,不能与 SEE_MASK_HMONITOR 共用,Vista之后
SEE_MASK_HOTKEY 使用 dwHotKey 参数
SEE_MASK_NOCLOSEPROCESS 如果执行之后需要返回进程句柄,或者等待执行完毕的话,则需要指定该参数,从结构参数意义可以看到 hProcess 和 hInstApp 都依赖该选项
SEE_MASK_CONNECTNETDRV 验证共享并连接到驱动器号
SEE_MASK_NOASYNC 不等待操作完成,直接返回,会创建一个后台线程运行。
SEE_MASK_FLAG_DDEWAIT 弃用,使用 SEE_MASK_NOASYNC
SEE_MASK_DOENVSUBST 环境变量会被展开
SEE_MASK_FLAG_NO_UI 出现错误,不显示错误消息框,比如不会弹出找不到文件之类的窗口,直接返回失败
SEE_MASK_UNICODE UNICODE 程序
SEE_MASK_NO_CONSOLE 继承父进程的控制台,而不是创建新的控制台,与 CREATE_NEW_CONSOLE 相反
SEE_MASK_ASYNCOK 执行在后台线程,调用立即返回
SEE_MASK_NOQUERYCLASSSTORE 弃用
SEE_MASK_HMONITOR 使用 hmonitor,不能与 SEE_MASK_ICON 共存
SEE_MASK_NOZONECHECKS 不执行区域检查
SEE_MASK_WAITFORINPUTIDLE 创建新进程后,等待进程变为空闲状态再返回,超时时间为1分钟
SEE_MASK_FLAG_LOG_USAGE 跟踪应用程序启动次数
SEE_MASK_FLAG_HINST_IS_SITE

lpVerb 参数说明:
edit 用编辑器打开 lpFile 指定的文档,如果 lpFile 不是文档,则会失败
explore 浏览 lpFile 指定的文件夹
find 搜索 lpDirectory 指定的目录
open 打开 lpFile 文件,lpFile 可以是文件或文件夹
print 打印 lpFile,如果 lpFile 不是文档,则函数失败
properties 显示属性
runas 请求以管理员权限运行,比如以管理员权限运行某个exe
NULL 执行默认”open”动作

返回值说明:
函数执行成功,返回 TRUE ,否则返回 FALSE ,可使用 GetLastError 获取错误码。

引用头文件
#include <ShlObj.h>

二、使用实例

//管理员执行cmd命令
    SHELLEXECUTEINFO sei;
    ZeroMemory(&sei, sizeof(SHELLEXECUTEINFO));//使用前最好清空
    sei.cbSize = sizeof(SHELLEXECUTEINFO);//管理员权限执行cmd,最基本的使用与 ShellExecute 类似
    sei.lpFile = _T("cmd.exe");
    sei.nShow = SW_SHOW;
    sei.lpVerb = _T("runas");
    ShellExecuteEx(&sei);

		//显示c盘属性
    ZeroMemory(&sei, sizeof(SHELLEXECUTEINFO));
    sei.cbSize = sizeof(SHELLEXECUTEINFO);//打开 c:\\ 的属性
    sei.lpFile = _T("c:\\");
    sei.nShow = SW_SHOW;
    sei.fMask = SEE_MASK_INVOKEIDLIST;//使用 SEE_MASK_FLAG_NO_UI 使出错的情况下不提示错误
    sei.lpVerb = _T("properties");
    ShellExecuteEx(&sei);

		//执行cmd命令(阻塞,一直等待执行完毕)
		SHELLEXECUTEINFO sei;
		ZeroMemory(&sei, sizeof(SHELLEXECUTEINFO));
		sei.cbSize = sizeof(SHELLEXECUTEINFO);
		sei.lpFile = _T("cmd.exe");
		sei.nShow = SW_SHOW;
		sei.fMask = SEE_MASK_NOCLOSEPROCESS;//使用SEE_MASK_NOCLOSEPROCESS 参数
		sei.lpVerb = _T("open");
		if (ShellExecuteEx(&sei))//执行成功
		{
			if (sei.hProcess)//指定 SEE_MASK_NOCLOSEPROCESS 并其成功执行,则 hProcess 将会返回执行成功的进程句柄
			{
				WaitForSingleObject(sei.hProcess, INFINITE);//等待执行完毕
				if (sei.hProcess != NULL)
				{
					CloseHandle(sei.hProcess);
					sei.hProcess = NULL;
				}
			}
		}
		else
		{
			printf("ShellExecuteEx error,error code:%d\n", GetLastError());
		}
    
    //打开计算器
	  SHELLEXECUTEINFO sei;
		ZeroMemory(&sei, sizeof(SHELLEXECUTEINFO));
		sei.cbSize = sizeof(SHELLEXECUTEINFO);
		sei.lpFile = _T("calc.exe");
		sei.nShow = SW_SHOW;
		sei.fMask = SEE_MASK_DEFAULT;
		sei.lpVerb = _T("open");
		BOOL b = ShellExecuteEx(&sei);
		
		//打开一个指定的程序
		SHELLEXECUTEINFO sei;
		ZeroMemory(&sei, sizeof(SHELLEXECUTEINFO));
		sei.cbSize = sizeof(SHELLEXECUTEINFO);
		sei.lpFile = _T("C:\\Program Files (x86)\\Notepad++\\notepad++.exe");
		sei.nShow = SW_SHOW;
		sei.fMask = SEE_MASK_DEFAULT;
		sei.lpVerb = _T("open");
		BOOL b = ShellExecuteEx(&sei);
		
		//打开一个指定的文件
		SHELLEXECUTEINFO sei;
		ZeroMemory(&sei, sizeof(SHELLEXECUTEINFO));
		sei.cbSize = sizeof(SHELLEXECUTEINFO);
		sei.lpFile = _T("D:\\test\\book.pdf");
		sei.nShow = SW_SHOW;
		sei.fMask = SEE_MASK_DEFAULT;
		sei.lpVerb = _T("open");
		BOOL b = ShellExecuteEx(&sei);
		
		//打开一个指定的文件夹
		SHELLEXECUTEINFO sei;
		ZeroMemory(&sei, sizeof(SHELLEXECUTEINFO));
		sei.cbSize = sizeof(SHELLEXECUTEINFO);
		sei.lpFile = _T("D:\\test");
		sei.nShow = SW_SHOW;
		sei.fMask = SEE_MASK_DEFAULT;
		sei.lpVerb = _T("open");
		BOOL b = ShellExecuteEx(&sei);
		
		//打开网址
		SHELLEXECUTEINFO sei;
		ZeroMemory(&sei, sizeof(SHELLEXECUTEINFO));
		sei.cbSize = sizeof(SHELLEXECUTEINFO);
		sei.lpFile = _T("http://www.baidu.com");
		sei.nShow = SW_SHOW;
		sei.fMask = SEE_MASK_DEFAULT;
		sei.lpVerb = _T("open");
		BOOL b = ShellExecuteEx(&sei);

		//打开一个exe程序
		SHELLEXECUTEINFO sei;
		ZeroMemory(&sei, sizeof(SHELLEXECUTEINFO));
		sei.cbSize = sizeof(SHELLEXECUTEINFO);
		sei.nShow = SW_SHOW;
		sei.fMask = SEE_MASK_NOCLOSEPROCESS;
		sei.hInstApp = NULL;
		sei.lpVerb = NULL;
		sei.lpFile = _T("curl.exe");
		sei.lpParameters = _T("-o d:\\downloadfile.zip https://curl.se/windows/dl-8.0.1_7/curl-8.0.1_7-win64-mingw.zip");//程序的参数
		sei.lpDirectory = _T("C:\\Users\\Administrator\\Downloads\\curl-8.0.1_7-win32\\bin");//curl程序路径
		if (ShellExecuteEx(&sei))//执行成功
		{
			if (sei.hProcess)//指定 SEE_MASK_NOCLOSEPROCESS 并其成功执行,则 hProcess 将会返回执行成功的进程句柄
			{
				WaitForSingleObject(sei.hProcess, INFINITE);//等待执行完毕
				if (sei.hProcess != NULL)
				{
					CloseHandle(sei.hProcess);
					sei.hProcess = NULL;
				}
			}
		}
		
		//执行dir命令(用参数传命令的时候,要在命令字符开始加上"/c",不然命令不会执行。)
		SHELLEXECUTEINFO sei;
		ZeroMemory(&sei, sizeof(SHELLEXECUTEINFO));
		sei.cbSize = sizeof(SHELLEXECUTEINFO);
		sei.nShow = SW_SHOW;
		sei.fMask = SEE_MASK_NOCLOSEPROCESS;
		sei.lpVerb = _T("open");
		sei.lpFile = _T("cmd");
		sei.lpParameters = _T("/c dir");
		if (ShellExecuteEx(&sei))//执行成功
		{
			if (sei.hProcess)//指定 SEE_MASK_NOCLOSEPROCESS 并其成功执行,则 hProcess 将会返回执行成功的进程句柄
			{
				WaitForSingleObject(sei.hProcess, INFINITE);//等待执行完毕
				if (sei.hProcess != NULL)
				{
					CloseHandle(sei.hProcess);
					sei.hProcess = NULL;
				}
			}
		}
		
	//执行dir命令并且保存内容至文件中。(命令行执行结果可以使用">"来保存到文件。)
	SHELLEXECUTEINFO sei;
	ZeroMemory(&sei, sizeof(SHELLEXECUTEINFO));
	sei.cbSize = sizeof(SHELLEXECUTEINFO);
	sei.nShow = SW_HIDE;
	sei.fMask = SEE_MASK_NOCLOSEPROCESS;
	//sei.hInstApp = NULL;
	sei.lpVerb = _T("open");
	sei.lpFile = _T("cmd");
	sei.lpParameters = _T("/c dir > D:\\test2.txt");
	if (ShellExecuteEx(&sei))//执行成功
	{
		if (sei.hProcess)//指定 SEE_MASK_NOCLOSEPROCESS 并其成功执行,则 hProcess 将会返回执行成功的进程句柄
		{
			WaitForSingleObject(sei.hProcess, INFINITE);//等待执行完毕
			if (sei.hProcess != NULL)
			{
				CloseHandle(sei.hProcess);
				sei.hProcess = NULL;
			}
		}
	}
	
	//执行ffprobe命令并且保存内容至文件中。
	SHELLEXECUTEINFO sei;
	ZeroMemory(&sei, sizeof(SHELLEXECUTEINFO));
	sei.cbSize = sizeof(SHELLEXECUTEINFO);
	sei.nShow = SW_SHOW;
	sei.fMask = SEE_MASK_NOCLOSEPROCESS;
	sei.hInstApp = NULL;
	sei.lpVerb = _T("open");
	sei.lpFile = _T("cmd");
	sei.lpParameters = _T("/c F:\\develop\\ffmpeg\\ffmpeg-3.4.2\\ffmpeg-3.4.2-shared\\bin\\ffprobe.exe -v error -show_streams -print_format json \"E:\\film.mp4\" > \"d:\\test3.txt\" 2>&1");//cmd命令的重定向输出 2>&1 (stdout直接送往文件a ,stderr是继承了FD1的管道之后,再被送往文件a 。a文件只被打开一遍,就是FD1将其打开。)
	sei.lpDirectory = _T("");
	/*
	或者
	sei.lpParameters = _T("/c ffprobe.exe -v error -show_streams -print_format json \"E:\\film.mp4\" > \"d:\\test3.txt\" 2>&1");
	sei.lpDirectory = _T("F:\\develop\\ffmpeg\\ffmpeg-3.4.2\\ffmpeg-3.4.2-shared\\bin");
	*/
	if (ShellExecuteEx(&sei))//执行成功
	{
		if (sei.hProcess)//指定 SEE_MASK_NOCLOSEPROCESS 并其成功执行,则 hProcess 将会返回执行成功的进程句柄
		{
			WaitForSingleObject(sei.hProcess, INFINITE);//等待执行完毕
			if (sei.hProcess != NULL)
			{
				CloseHandle(sei.hProcess);
				sei.hProcess = NULL;
			}
		}
	}
	
	//执行ffmpeg命令并且保存内容至文件中。
	SHELLEXECUTEINFO sei;
	ZeroMemory(&sei, sizeof(SHELLEXECUTEINFO));
	sei.cbSize = sizeof(SHELLEXECUTEINFO);
	sei.nShow = SW_SHOW;
	sei.fMask = SEE_MASK_NOCLOSEPROCESS;
	sei.hInstApp = NULL;
	sei.lpVerb = _T("open");
	sei.lpFile = _T("cmd");
	sei.lpParameters = _T("/c F:\\develop\\ffmpeg\\ffmpeg-3.4.2\\ffmpeg-3.4.2-shared\\bin\\ffmpeg.exe -i \"E:\\film.mp4\" > \"d:/test4.json\" 2>&1");
	sei.lpDirectory = _T("");
	if (ShellExecuteEx(&sei))//执行成功
	{
		if (sei.hProcess)//指定 SEE_MASK_NOCLOSEPROCESS 并其成功执行,则 hProcess 将会返回执行成功的进程句柄
		{
			WaitForSingleObject(sei.hProcess, INFINITE);//等待执行完毕
			if (sei.hProcess != NULL)
			{
				CloseHandle(sei.hProcess);
				sei.hProcess = NULL;
			}
		}
	}

	//执行curl下载文件并保存进度信息到文件中
	SHELLEXECUTEINFO sei;
	ZeroMemory(&sei, sizeof(SHELLEXECUTEINFO));
	sei.cbSize = sizeof(SHELLEXECUTEINFO);
	sei.nShow = SW_SHOW;
	sei.fMask = SEE_MASK_NOCLOSEPROCESS;
	sei.hInstApp = NULL;
	sei.lpVerb = NULL;
	sei.lpVerb = _T("open");
	sei.lpFile = _T("cmd");
	sei.lpParameters = _T("/c curl.exe -o d:\\downloadfile.zip https://curl.se/windows/dl-8.0.1_7/curl-8.0.1_7-win64-mingw.zip --progress-bar > d:\\1.log 2>&1");
	sei.lpDirectory = _T("C:\\Users\\Administrator\\Downloads\\curl-8.0.1_7-win64-mingw\\curl-8.0.1_7-win32\\bin");
	if (ShellExecuteEx(&sei))//执行成功
	{
		if (sei.hProcess)//指定 SEE_MASK_NOCLOSEPROCESS 并其成功执行,则 hProcess 将会返回执行成功的进程句柄
		{
			WaitForSingleObject(sei.hProcess, INFINITE);//等待执行完毕
			if (sei.hProcess != NULL)
			{
				CloseHandle(sei.hProcess);
				sei.hProcess = NULL;
			}
		}
	}

三、注意事项

1、用参数传命令的时候,要在命令字符开始加上"/c"
2、如果命令中的路径包含空格,要把路径去掉头尾用双引号包含起来。
3、命令中路径,建议使用绝对路径。
4、ShellExecuteEx调用控制台程序并传入多个参数,多个参数之间以空格隔开。
5、调用第三方程序有很多方法, 包括system , WinExec , CreateProcess, ShellExecute, ShellExecuteEx。对比这几个启动进程的函数。支持提权的函数包括:CreateProcess, ShellExecute, ShellExecuteEx,但是CreateProcess调用UAC提权,提权界面CreateProcess是没有的。


http://www.kler.cn/a/14001.html

相关文章:

  • 基于HFSS软件24GHz雷达天线设计
  • 蓝牙耳机哪个牌子的音质好一些?三百内音质最好的蓝牙耳机排行
  • TX-LCN:分布式事务框架
  • Python numpy.float32方法代码示例
  • 学系统集成项目管理工程师(中项)系列07_信息(文档)管理
  • ai文案生成器免费-ai文案改写软件免费
  • Spring框架及源码(二)---Spring IoC高级应用与源码剖析
  • SVN通过备份、过滤、再导入的方式彻底删除废弃目录
  • Elasticsearch:使用 Elastic APM 监控 Android 应用程序(二)
  • 【模板】Hexo Docker Nginx 个人博客服务器部署
  • HTTP1.1(十二)Cookie的格式与约束
  • 部署你的flask应用到docker
  • BufferedOutputStream,BufferedInputStream是字节流,对象处理流,序列化,输入输出流,转换流
  • Bito:一款 iead/webstorm 神级插件,由 ChatGPT 团队开发,堪称辅助神器
  • Linux目录
  • RHCE第六次作业
  • JavaSE学习进阶day06_02 Set集合和Set接口
  • Python从入门到精通10天(文件的处理)
  • 推荐好用的数据库软件sql studio
  • ffmpeg学习发现av_err2str使用报错问题