最近项目中需要实现在虚拟打印时,自动添加文件名
找了好多主要有两种方案
一:隐藏print操作中的自带的SaveFileDialog,自己创建一个,通过设置FileName实现,但是这种实现方式是在低版本的framework,winform中实现。
二: 通过FindWindow找到界面上的文件另存为界面,再通过层层FindWindowEx,找到你要修改值的control,最后通过sendmessage实现值的修改。
第一种方案:
我未能隐藏printDialog.PrintDocument操作中弹出来的文件另存为的框,不能实现我想要的效果
DialogResult userResp = printDialog.ShowDialog();if (userResp == DialogResult.OK){if (printDialog.PrinterSettings.PrinterName == "Microsoft Print to PDF"){ // force a reasonable filenamestring basename = Path.GetFileNameWithoutExtension(myFileName);string directory = Path.GetDirectoryName(myFileName);prtDoc.PrinterSettings.PrintToFile = true;// confirm the user wants to use that nameSaveFileDialog pdfSaveDialog = new SaveFileDialog();pdfSaveDialog.InitialDirectory = directory;pdfSaveDialog.FileName = basename + ".pdf";pdfSaveDialog.Filter = "PDF File|*.pdf";userResp = pdfSaveDialog.ShowDialog();if (userResp != DialogResult.Cancel)prtDoc.PrinterSettings.PrintFileName = pdfSaveDialog.FileName;}if (userResp != DialogResult.Cancel) // in case they canceled the save as dialog{prtDoc.Print();}}
第二种方案:
因为printDialog.PrintDocument执行完后,才弹出文件另存为window,如果你不点击保存或取消,是不会继续执行后面的代码。所以选择用一个timer实现,每隔一段时间自动触发搜索操作,一旦找到或者用户点击保存或取消就终止timer的tick事件的执行。
[DllImport("user32.dll")]static extern IntPtr FindWindow(string lpClassName, string lpWindowName);[DllImport("user32.dll")]static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfeter, string lpszClass, string lpszWindow);[DllImport("user32.dll")]static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, String lParam);[DllImport("user32.dll")]static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);//Win32消息定义const uint WM_SETTEXT = 0x000c;const uint WM_IME_KEYDOWN = 0x0290;const uint WM_LBUTTONDOWN = 0x0201;const uint WM_LBUTTONUP = 0x0202;IntPtr hWnd = FindWindow("#32770", "文件另存为");if (hWnd != IntPtr.Zero){IntPtr hChild;// 由于输入框被多个控件嵌套,因此需要一级一级的往控件内找到输入框hChild = FindWindowEx(hWnd, IntPtr.Zero, "DUIViewWndClassName", String.Empty);hChild = FindWindowEx(hChild, IntPtr.Zero, "DirectUIHWND", String.Empty);hChild = FindWindowEx(hChild, IntPtr.Zero, "FloatNotifySink", String.Empty);hChild = FindWindowEx(hChild, IntPtr.Zero, "ComboBox", String.Empty);hChild = FindWindowEx(hChild, IntPtr.Zero, "Edit", String.Empty);var ret = SendMessage(hChild, WM_SETTEXT, IntPtr.Zero, this.PatientUID);if (ret != IntPtr.Zero){LogAdapter.Logger.Info("[PrintQueryTimerTick]:success find filename combobx");if (printQueryTimer != null && printQueryTimer.IsEnabled){printQueryTimer.Stop();}return;}}
#32770"表示的dialog类型,DUIViewWndClassName等都是类名,可以通过spy查看
函数:FindWindow(lpClassName, lpWindowName): HWND
参数:
IpClassName :
窗口的类名,指向一个指定了类名的空结束字符串,或一个标识类名字符串的成员的指针。如果该参数为一个成员,则它必须为前次调用theGlobafAddAtom函数产生的全局成员。该成员为16位,必须位于IpClassName的低 16位,高位必须为 0.
IpWindowName:
窗口的标题,指向一个指定了窗口名(窗口标题)的空结束字符串。如果该参数为空,则为所有窗口全匹配。
在搜索的时候不一定两者都知道,但至少要知道其中的一个。返回窗口的句柄,失败返回0
函数: HWND FindWindowEx(HWND hwndParent,HWND hwndChildAfter,LPCTSTR lpszClass,LPCTSTR lpszWindow)
参数:
hwndParent:
要查找子窗口的父窗口句柄。
如果hwnjParent为NULL,则函数以桌面窗口为父窗口,查找桌面窗口的所有子窗口。
Windows NT5.0 and later:如果hwndParent是HWND_MESSAGE,函数仅查找所有消息窗口。
hwndChildAfter :
子窗口句柄。查找从在Z序中的下一个子窗口开始。子窗口必须为hwndPareRt窗口的直接子窗口而非后代窗口。如果HwndChildAfter为NULL,查找从hwndParent的第一个子窗口开始。如果hwndParent 和 hwndChildAfter同时为NULL,则函数查找所有的顶层窗口及消息窗口。
lpszClass:
指向一个指定了类名的空结束字符串,或一个标识类名字符串的成员的指针。如果该参数为一个成员,则它必须为前次调用theGlobaIAddAtom函数产生的全局成员。该成员为16位,必须位于lpClassName的低16位,高位必须为0。
lpszWindow:
指向一个指定了窗口名(窗口标题)的空结束字符串。如果该参数为 NULL,则为所有窗口全匹配。返回值:如果函数成功,返回值为具有指定类名和窗口名的窗口句柄。如果函数失败,返回值为NULL
参考链接:
1 /weixin_34075268/article/details/86398143
2 /questions/33985624/programmatically-set-filename-and-path-in-microsoft-print-to-pdf-printer
3 /coolszy/article/details/5523784