How to set __IE_PrinterCmd_DevMode Property to a DEVMODE structure in print template in IE with Visual C++

904 Views Asked by At

The print template in IE uses this property to determine information about the selected printer after a user closes the Print dialog box. How can I set this property to a DEVMODE structure with code in Visual C++. How can I convert DEVMODE structure to variant. If it possible, I can pass variant to print template and then set __IE_PrinterCmd_DevMode property in jscript.

2

There are 2 best solutions below

2
On

I have just had this same issue and have found that __IE_PrinterCmd_DevMode and __IE_PrinterCmd_DevNames can be set from an IntPtr.

This is on a X86 application, so not sure what would happen on x64 or AnyCPU.

As suggested, I use a class to pass in the DevMode and DevNames through the external object.

Here's the main parts of the code, for this:

Public Class PrintObjCls
 Public Printer As String
 Public DevMode As IntPtr
 Public DevNames As IntPtr
 Public Printing As Boolean
 Public Failed As Boolean 
 Public Progress As Integer
End Class

Sub PrintToTemplate(Web as WebBrowser, Settings as PrinterSettings)
 Dim Obj As New PrintObjCls
 Obj.Printer = Settings.PrinterName
 Obj.DevMode = Settings.GetHdevmode
 Obj.DevNames = Settings.GetHdevnames
 Web.ObjectForScripting = Obj
End Sub

Then in the Print Template

var ext = doc.parentWindow.external;
dialogArguments.__IE_PrinterCMD_Printer = ext.Printer;
dialogArguments.__IE_PrinterCmd_DevMode = ext.DevMode;
dialogArguments.__IE_PrinterCmd_DevNames = ext.DevNames;
0
On

Marc Durdin has an excelent blog post with a detailed example in Delphi. It's easily portable to C++ and other languages:

Demystifying printing with the Microsoft WebBrowser control and ShowHTMLDialogEx

In particular, __IE_PrinterCmd_DevMode should be an unlocked HGLOBAL (typically a valid return value from GlobalAlloc or GlobalReAlloc). This is not documented anywhere, I guess Marc discovered the hard way by trial and error, finally finding it working with the values in the PRINTDLG.hDevMode and PRINTDLG.hDevNames fields, as directly provided by a call to PrintDlg.

I've been able to pass HGLOBALs as integers to a template's script and use them to initialize __IE_PrinterCmd_DevMode and __IE_PrinterCmd_DevNames, before creating a TemplatePrinter. This is handy if you don't want to call ShowHTMLDialogEx yourself and you already have a hook into your application. I'm using the original window's external scripting object. To access it from the template, I use:

dialogArguments.__IE_BrowseDocument.parentWindow.external

PS: Passing an HGLOBAL as an integer works on a 32-bit process, because JScript's numbers are actually double floats, which can represent sequential integers up to 53-bit. But due to this limitation, passing an HGLOBAL as an integer on a 64-bit process is not reliable.

Maybe you can make your window.external object have a method, which expects a print template's dialogArguments object, that sets the __IE_PrinterCmd_DevMode and __IE_PrinterCmd_DevNames with integer VARIANTs (VT_I8 or VT_UI8).

I haven't tested this yet.

If you just want to select a printer other than the system default, you may just as well set the __IE_PrinterCMD_Printer property. You can do it in JScript, it'll affect the TemplatePrinter behavior objects that you create after setting it. However, with this property alone, you cannot control the initial settings or know which printer the user finally chose.