C/C++ 使用 API 函数 ShellExecuteEx 实现文件打印

本文章主要介绍使用ShellExecuteEx实现打印文件的功能。

函数原型:BOOL ShellExecuteExA(__inout SHELLEXECUTEINFOA *pExecInfo)
输入输出参数都是 SHELLEXECUTEINFO 结构体。
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 参数与 ShellExecute 的 lpOperation 参数一致:

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

nShow 与 ShellExecute 的该参数一致:

  • SW_HIDE 隐藏窗口,活动状态给令一个窗口
  • SW_MINIMIZE 最小化窗口,活动状态给令一个窗口
  • SW_RESTORE 用原来的大小和位置显示一个窗口,同时令其进入活动状态
  • SW_SHOW 用当前的大小和位置显示一个窗口,同时令其进入活动状态
  • SW_SHOWMAXIMIZED 最大化窗口,并将其激活
  • SW_SHOWMINIMIZED 最小化窗口,并将其激活
  • SW_SHOWMINNOACTIVE 最小化一个窗口,同时不改变活动窗口
  • SW_SHOWNA 用当前的大小和位置显示一个窗口,不改变活动窗口
  • SW_SHOWNOACTIVATE 用最近的大小和位置显示一个窗口,同时不改变活动窗口
  • SW_SHOWNORMAL 与SW_RESTORE相同

如果设置了 SEE_MASK_NOCLOSEPROCESS ,调用成功则 hInstApp 返回大于32的值,调用失败会返回:

  • SE_ERR_FNF (2) 文件未找到
  • SE_ERR_PNF (3) 路径未找到
  • SE_ERR_ACCESSDENIED (5) 拒绝访问
  • SE_ERR_OOM (8) 内存不足
  • SE_ERR_DLLNOTFOUND (32) 动态库未找到
  • SE_ERR_SHARE (26) 无法共享打开的文件
  • SE_ERR_ASSOCINCOMPLETE (27) 文件关联信息不完整
  • SE_ERR_DDETIMEOUT (28) 操作超时
  • SE_ERR_DDEFAIL (29) 操作失败
  • SE_ERR_DDEBUSY (30) DDE 操作忙
  • SE_ERR_NOASSOC (31) 文件关联不可用

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

  • ERROR_FILE_NOT_FOUND 文件不存在
  • ERROR_PATH_NOT_FOUND 路径不存在
  • ERROR_DDE_FAIL DDE(动态数据交换)失败
  • ERROR_NO_ASSOCIATION 未找到与指定文件拓展名关联的应用
  • ERROR_ACCESS_DENIED 拒绝访问
  • ERROR_DLL_NOT_FOUND 未找到dll
  • ERROR_CANCELLED 功能提示用户提供额外信息,但是用户取消请求。
  • ERROR_NOT_ENOUGH_MEMORY 内存不足
  • ERROR_SHARING_VIOLATION 发生共享冲突

以后介绍完了ShellExecuteEx的函数说明。现在就开始如何使用ShellExecuteEx完成打印文件了。

  1. 创建一个命名为PrintByShellExecuteEx的MFC项目
  2. 界面设计
    对话框窗口设计如下图所示
    在这里插入图片描述
  3. 编辑控件,添加变量。
    打印机名称m_PrintName,打印机路径m_Path
  4. 在源文件头部添加上依赖库
#include "winspool.h"
#include <io.h>
#include "shlwapi.h"
  1. 编辑打印按钮
int nLen_FilePath = 0;
BOOL bRet = FALSE;
char szPrinter[256] = {0x00};
char PrintFilePath[MAX_PATH] = { 0x00 };

m_PrintName.GetWindowText(szPrinter, sizeof(szPrinter));	//获取打印机名称
bRet = SetDefaultPrinter(szPrinter);						//设置默认打印机
if (!bRet)
{
	MessageBox("设备默认打印机失败");
	return;
}

m_Path.GetWindowText(PrintFilePath, sizeof(PrintFilePath));

nLen_FilePath = strlen(PrintFilePath);
if ((strcmp(PrintFilePath + nLen_FilePath - 3, "pdf") != 0) && (strcmp(PrintFilePath + nLen_FilePath - 3, "PDF") != 0) &&
	(strcmp(PrintFilePath + nLen_FilePath - 3, "txt") != 0) && (strcmp(PrintFilePath + nLen_FilePath - 3, "TXT") != 0) &&
	(strcmp(PrintFilePath + nLen_FilePath - 3, "doc") != 0) && (strcmp(PrintFilePath + nLen_FilePath - 3, "DOC") != 0) &&
	(strcmp(PrintFilePath + nLen_FilePath - 3, "HTM") != 0) && (strcmp(PrintFilePath + nLen_FilePath - 3, "htm") != 0) &&
	(strcmp(PrintFilePath + nLen_FilePath - 3, "jpg") != 0) && (strcmp(PrintFilePath + nLen_FilePath - 3, "JPG") != 0) &&
	(strcmp(PrintFilePath + nLen_FilePath - 4, "docx") != 0) && (strcmp(PrintFilePath + nLen_FilePath - 4, "DOCX") != 0) &&
	(strcmp(PrintFilePath + nLen_FilePath - 4, "HTML") != 0) && (strcmp(PrintFilePath + nLen_FilePath - 4, "html") != 0))
{
	return ;
}

if (_access(PrintFilePath, 0) != 0 && PathFileExists(PrintFilePath) != TRUE)
{
	return;
}
else
{
	if ((strcmp(PrintFilePath + nLen_FilePath - 4, "HTML") != 0) && (strcmp(PrintFilePath + nLen_FilePath - 4, "html") != 0) &&
		(strcmp(PrintFilePath + nLen_FilePath - 3, "HTM") != 0) && (strcmp(PrintFilePath + nLen_FilePath - 3, "htm") != 0))
	{
		SHELLEXECUTEINFO ShExecInfo = { 0 };
		ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
		ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
		ShExecInfo.hwnd = NULL;
		ShExecInfo.lpVerb = TEXT("print");
		ShExecInfo.lpFile = TEXT(PrintFilePath);  //打印机文件路径
		ShExecInfo.lpParameters = TEXT("");
		ShExecInfo.lpDirectory = NULL;
		ShExecInfo.nShow = SW_HIDE;
		ShExecInfo.hInstApp = NULL;
		ShellExecuteEx(&ShExecInfo);
		WaitForSingleObject(ShExecInfo.hProcess, INFINITE);
		if ((int)ShExecInfo.hInstApp <= 32)
		{
			MessageBox("打印失败");
			return;
		}
	}
}

这样就能完成使用 API 函数 ShellExecuteEx 实现打印文件的功能。
工程项目代码下载地址:

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值