Do you own a Debenu Quick PDF Library version 7, 8, 9, 10, 11, 12, 13 or iSEDQuickPDF license? Upgrade to Debenu Quick PDF Library 14 today!
![]() |
Show Printer Dialog and use options when printing |
Post Reply ![]() |
Author | |
Kent ![]() Beginner ![]() Joined: 15 Mar 16 Location: New Zealand Status: Offline Points: 10 |
![]() ![]() ![]() ![]() ![]() Posted: 15 Mar 16 at 4:06AM |
Hi,
I want to show the standard windows print dialog - allowing the user to set printer specific options (eg. Duplex, Paper Tray, Booklet Mode, Staple + Fold, etc.) and then use this when printing the PDF. Something along the lines of below. However, 'SetPrinterDevModeFromString' requires a string... Can I just create a std::wstring and copy the 'DevMode' to it or is there a special way to do this ? thanks Kent. ---------------------------------------------------- PRINTDLG pd; memset(&pd, 0, sizeof(pd)); pd.lStructSize = sizeof(PRINTDLG); pd.Flags = PD_RETURNDC | PD_DISABLEPRINTTOFILE | PD_HIDEPRINTTOFILE; if (PrintDlg(&pd) == TRUE) { pdf->SetPrinterDevModeFromString(pd.hDevMode); int options = pdf->PrintOptions(0,0, L"Printing Test"); pdf->PrintDocument( L"Office", 0, 9999, options); }
|
|
![]() |
|
Ingo ![]() Moderator Group ![]() ![]() Joined: 29 Oct 05 Status: Offline Points: 3529 |
![]() ![]() ![]() ![]() ![]() |
Hi Kent,
using virtual keycodes could be the easiest solution. Ctrl+P shows always the printer dialog. Cheers and welcome here, Ingo |
|
Cheers,
Ingo |
|
![]() |
|
Kent ![]() Beginner ![]() Joined: 15 Mar 16 Location: New Zealand Status: Offline Points: 10 |
![]() ![]() ![]() ![]() ![]() |
Hi Ingo,
I'm not sure I understand your answer, sorry. What I want, is to show the standard Printer dialog (which I can do) - allow the user to specify settings (which can be specific to the printer / copier) and then use the selected settings for the resulting print jobs. I could query the results from the print dialog, and try to set them using the SDK, which will work for things like Duplex maybe - but not the 1000's printer specific settings (such as booklet, fold & staple, etc). I figure the 'SetPrinterDevModeFromString' would be the way - but how ? thanks Kent.
|
|
![]() |
|
Kent ![]() Beginner ![]() Joined: 15 Mar 16 Location: New Zealand Status: Offline Points: 10 |
![]() ![]() ![]() ![]() ![]() |
Or, is there a way from the SDK to show a Printer Dialog - which is then used for printouts ?
Which I could then store (using the 'GetPrinterDevModeAsString' function) and then used for all future printings using the 'SetPrinterDevModeFromString' ? Kent.
|
|
![]() |
|
JensBP ![]() Beginner ![]() ![]() Joined: 19 Dec 06 Location: Denmark Status: Offline Points: 9 |
![]() ![]() ![]() ![]() ![]() |
Hi Kent
In an application we have we use the following code snippets for getting the Printer Settings including Custom setings in a way that the QuickPDF function can use, this code is written in VB.NET so you may have to modify and extrapolate to your development environment and language: Private printerName As String = "" Private devModeBytes() As Byte Sub SavePrinterSettings() If PrintDialog1.ShowDialog = Windows.Forms.DialogResult.OK Then printerName = PrintDialog1.PrinterSettings.PrinterName 'Get Printer Setup as binary data Byte Array Dim hDevMode As IntPtr 'handle to the DEVMODE Dim pDevMode As IntPtr 'pointer to the DEVMODE Dim devMode As DEVMODE 'the actual DEVMODE structure Dim printerSettings As Drawing.Printing.PrinterSettings = PrintDialog1.PrinterSettings 'Get a handle to a DEVMODE for the printer settings hDevMode = printerSettings.GetHdevmode() 'Obtain a lock on the handle and get an actual pointer so Windows won't 'move it around while we're futzing with it pDevMode = GlobalLock(hDevMode) 'Marshal the memory at that pointer into our P/Invoke version of DEVMODE devMode = DirectCast(Marshal.PtrToStructure(pDevMode, GetType(DEVMODE)), DEVMODE) 'Read the bytes into a Byte Array ReDim devModeBytes(devMode.dmSize + (devMode.dmDriverExtra - 1)) For i As Integer = 0 To devMode.dmSize + (devMode.dmDriverExtra - 1) devModeBytes(i) = Marshal.ReadByte(pDevMode, i) Next 'Unlock the handle, we're done futzing around with memory GlobalUnlock(hDevMode) 'And to boot, we don't need that DEVMODE anymore, either GlobalFree(hDevMode) 'Here we have a devModeBytes array which can be used directly in the QuickPDF function SetPrinterDevModeFromString 'QuickPDF.SetPrinterDevModeFromString(printDevMode) Else printerName = "" End If End Sub 'The above code needs some Window API definitions: <Flags()> _ Enum DM As Integer Orientation = &H1 PaperSize = &H2 PaperLength = &H4 PaperWidth = &H8 Scale = &H10 Position = &H20 NUP = &H40 DisplayOrientation = &H80 Copies = &H100 DefaultSource = &H200 PrintQuality = &H400 Color = &H800 Duplex = &H1000 YResolution = &H2000 TTOption = &H4000 Collate = &H8000 FormName = &H10000 LogPixels = &H20000 BitsPerPixel = &H40000 PelsWidth = &H80000 PelsHeight = &H100000 DisplayFlags = &H200000 DisplayFrequency = &H400000 ICMMethod = &H800000 ICMIntent = &H1000000 MediaType = &H2000000 DitherType = &H4000000 PanningWidth = &H8000000 PanningHeight = &H10000000 DisplayFixedOutput = &H20000000 End Enum <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)> _ Public Structure DEVMODE Public Const CCHDEVICENAME As Integer = 32 Public Const CCHFORMNAME As Integer = 32 <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=CCHDEVICENAME)> _ Public dmDeviceName As String Public dmSpecVersion As Short Public dmDriverVersion As Short Public dmSize As Short Public dmDriverExtra As Short Public dmFields As DM Public dmOrientation As Short Public dmPaperSize As Short Public dmPaperLength As Short Public dmPaperWidth As Short Public dmScale As Short Public dmCopies As Short Public dmDefaultSource As Short Public dmPrintQuality As Short Public dmColor As Short Public dmDuplex As Short Public dmYResolution As Short Public dmTTOption As Short Public dmCollate As Short <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=CCHFORMNAME)> _ Public dmFormName As String Public dmLogPixels As Short Public dmBitsPerPel As Integer ' Declared wrong in the full framework Public dmPelsWidth As Integer Public dmPelsHeight As Integer Public dmDisplayFlags As Integer Public dmDisplayFrequency As Integer Public dmICMMethod As Integer Public dmICMIntent As Integer Public dmMediaType As Integer Public dmDitherType As Integer Public dmReserved1 As Integer Public dmReserved2 As Integer Public dmPanningWidth As Integer Public dmPanningHeight As Integer 'Public dmPositionX As Integer ' Using a PointL Struct does not work 'Public dmPositionY As Integer End Structure <DllImport("kernel32.dll", ExactSpelling:=True)> _ Friend Shared Function GlobalFree(ByVal handle As IntPtr) As IntPtr End Function <DllImport("kernel32.dll", ExactSpelling:=True)> _ Friend Shared Function GlobalLock(ByVal handle As IntPtr) As IntPtr End Function <DllImport("kernel32.dll", ExactSpelling:=True)> _ Friend Shared Function GlobalUnlock(ByVal handle As IntPtr) As IntPtr End Function This code snippet has been put together from some other sample code on the QuickPDF forum and some code find using google. The important parts is that the SetPrinterDevModeFromString function (at least in VB.NET) needs a byte array, and how to get this from the Printer Settings object. Regards, Jens
|
|
![]() |
|
Ingo ![]() Moderator Group ![]() ![]() Joined: 29 Oct 05 Status: Offline Points: 3529 |
![]() ![]() ![]() ![]() ![]() |
Hi Kent,
what i wanna tell you was that it's possible showing the normal printer dialog using virtual keycodes inside your app. But i've read now that you need a lot more ;-) Regarding different outputformats the SetupCustomPrinter can be a solution: http://www.debenu.com/docs/pdf_library_reference/SetupCustomPrinter.php |
|
Cheers,
Ingo |
|
![]() |
|
Kent ![]() Beginner ![]() Joined: 15 Mar 16 Location: New Zealand Status: Offline Points: 10 |
![]() ![]() ![]() ![]() ![]() |
Hi JensBP,
Thanks - that's the approach that I'm trying to take - but haven't yet got the magic touch happening. Or, is it that Duplex has to be set via the API, but the other settings via the DEVMODE. This is what I'm trying to do (I'll worry about different printer names later). So far, it doesn't appear to be working. thanks Kent. PRINTDLG pd; memset(&pd, 0, sizeof(pd)); pd.lStructSize = sizeof(PRINTDLG); pd.Flags = PD_RETURNDC | PD_DISABLEPRINTTOFILE | PD_HIDEPRINTTOFILE | PD_NOPAGENUMS | PD_NOSELECTION; if (PrintDlg(&pd) == TRUE) { std::string orig; orig = pdf->GetPrinterDevModeToString(L"Office"); DEVMODE * hDevMode = (DEVMODE *)pd.hDevMode; WORD s = sizeof(DEVMODE) + hDevMode->dmDriverExtra; std::string devmode; devmode.assign((const char *)pd.hDevMode, s); pdf->SetPrinterDevModeFromString(devmode); int options = pdf->PrintOptions(0, 0, L"Printing Test"); pdf->PrintDocument(L"Office", 0, 9999, options); } |
|
![]() |
|
Kent ![]() Beginner ![]() Joined: 15 Mar 16 Location: New Zealand Status: Offline Points: 10 |
![]() ![]() ![]() ![]() ![]() |
Hi Ingo,
Yeah - I need to be able to take advantage of photo copier specific features - such as folding / staple / etc. and it doesn't look like I can control any of these specific functions through the API. I can see it's possible to control things like duplex, etc. but I need more. Kent.
|
|
![]() |
|
JensBP ![]() Beginner ![]() ![]() Joined: 19 Dec 06 Location: Denmark Status: Offline Points: 9 |
![]() ![]() ![]() ![]() ![]() |
Hi Kent
When I used this advanced functionality in our application it took some time, and I several times saved the DevMode structure to a binary file so I could compare the structure when trying different settings in the Printer settings dialog. I have no experience with C++ and the QuickPDF interface, but just know that when using .NET the DevMode has to be handled as a raw array of bytes in the call to the QuickPDF function. Regards, Jens
|
|
![]() |
|
Kent ![]() Beginner ![]() Joined: 15 Mar 16 Location: New Zealand Status: Offline Points: 10 |
![]() ![]() ![]() ![]() ![]() |
Hi Jens,
Thanks for the reply - still playing. In your VB.NET code, why did you subtract 1 from the declaration (devMode.dmDriverExtra - 1) ? > ReDim devModeBytes(devMode.dmSize + (devMode.dmDriverExtra - 1)) > For i As Integer = 0 To devMode.dmSize + (devMode.dmDriverExtra - 1) > devModeBytes(i) = Marshal.ReadByte(pDevMode, i) > Next I don't know VB, but assuming the array is zero based - won't this create an array 1 byte too small ? Kent. |
|
![]() |
|
Kent ![]() Beginner ![]() Joined: 15 Mar 16 Location: New Zealand Status: Offline Points: 10 |
![]() ![]() ![]() ![]() ![]() |
Hi Jens,
This is where I've got to. I'm getting the printer name okay - and am fairly certain I have the 'DEVMODE' string - but obviously missing something as it's not making a difference. Ideas appreciated. Kent. //======================================================================================================================================================== #define PRINTERMAX 256 PRINTDLGEX pd2; std::string devmodestr; std::wstring printername; BOOL haveDonePrinterSetup = false; void initPrinterSettings(void) { // Initialize the PRINTDLGEX structure. pd2.lStructSize = sizeof(PRINTDLGEX); pd2.hwndOwner = GetForegroundWindow(); pd2.hDevMode = NULL; pd2.hDevNames = NULL; pd2.hDC = NULL; pd2.Flags = PD_RETURNDC | PD_HIDEPRINTTOFILE | PD_NOCURRENTPAGE | PD_NOSELECTION | PD_COLLATE; pd2.Flags2 = 0; pd2.ExclusionFlags = 0; pd2.nPageRanges = 1; pd2.nMaxPageRanges = 1; pd2.nMinPage = 1; pd2.nMaxPage = 9999; pd2.nCopies = 1; pd2.hInstance = 0; pd2.lpPrintTemplateName = NULL; pd2.lpCallback = NULL; pd2.nPropertyPages = 0; pd2.lphPropertyPages = NULL; pd2.nStartPage = START_PAGE_GENERAL; pd2.dwResultAction = 0; } //======================================================================================================================================================== static long pdf_PrintDialog(void) { // http://msdn.microsoft.com/en-us/library/windows/desktop/ms646844(v=vs.85).aspx PRINTPAGERANGE pageRanges[2]; pageRanges->nFromPage = 1; pageRanges->nToPage = 999; pd2.lpPageRanges = pageRanges; pd2.hwndOwner = GetForegroundWindow(); HRESULT err = PrintDlgEx(&pd2); if (err != S_OK) { return -1; } DWORD action = pd2.dwResultAction; if (action == PD_RESULT_CANCEL) return 0; if (pd2.hDevMode) // get the printer settings (colour, paper size, etc) { DEVMODE * pDevMode; pDevMode = (DEVMODE*)GlobalLock(pd2.hDevMode); // Make sure it doesn't get moved while we are trying to copy it. int dwBytesNeeded = pDevMode->dmSize + pDevMode->dmDriverExtra; // sizeof( DEVMODE ) + dmDriverExtra info char * str = new char[dwBytesNeeded]; memcpy(str, pDevMode, dwBytesNeeded); devmodestr.assign(str, dwBytesNeeded); haveDonePrinterSetup = true; delete str; GlobalUnlock(pd2.hDevMode); } if (pd2.hDevNames) // get the printer Name { DEVNAMES * pDevNames; pDevNames = (DEVNAMES*)GlobalLock(pd2.hDevNames); WORD devOS = pDevNames->wDeviceOffset; long i; char * pDN = (char *)pDevNames; wchar_t tmp[PRINTERMAX]; i = 0; while ((i < (PRINTERMAX - 1)) && (pDN[devOS + i])) { tmp = pDN[devOS + i]; i++; } tmp = 0; // Copy the 'Printer' name printername.assign(tmp, i); GlobalUnlock(pd2.hDevNames); } return 1; } //======================================================================================================================================================== static void pdf_Print( void ) { if (haveDonePrinterSetup) { std::string tmp; pdf->SetPrinterDevModeFromString(devmodestr); } int options = pdf->PrintOptions(0, 0, L"Printing Test"); pdf->PrintDocument(printername, 0, 9999, options); } |
|
![]() |
|
JensBP ![]() Beginner ![]() ![]() Joined: 19 Dec 06 Location: Denmark Status: Offline Points: 9 |
![]() ![]() ![]() ![]() ![]() |
Hi Kent
Yes VB.NET arrays are zero based but when declaring an array the number specified is the index for the last element, so a Dim or ReDim someArray(someSize) as SomeType has a length of someSize+1 elements. In C based languages the number in the declaration is the number of elements, so this is the difference. Regards, Jens
|
|
![]() |
|
JensBP ![]() Beginner ![]() ![]() Joined: 19 Dec 06 Location: Denmark Status: Offline Points: 9 |
![]() ![]() ![]() ![]() ![]() |
Hi Kent
I looked at my code and see one potential difference. In my code the sequence is the following: myPrintOptions = QP.PrintOptions(<some arguments here>) QP.SetPrinterDevModeFromString(devModeString) QP.PrintDocument(<some arguments here>) In your sample the first two staments are switched, maybe the sequence is important? The QP.PrintOptions() maybe modifies the devMode for the active printer? Regards, Jens
|
|
![]() |
|
Kent ![]() Beginner ![]() Joined: 15 Mar 16 Location: New Zealand Status: Offline Points: 10 |
![]() ![]() ![]() ![]() ![]() |
Hi Jens,
Thanks for taking the time and effort to read through my code. I didn't believe that would make any difference - but gave it a try anyway with no joys - I'm at the point of trying anything :) I've emailed Debenu support as well - but they seem to be extremely slow in replying - is this normal ? Kent. ---------------------- static void pdf_Print( void ) { int options = pdf->PrintOptions(0, 0, L"Printing Test"); if (haveDonePrinterSetup) { std::string tmp; pdf->SetPrinterDevModeFromString(devmodestr); } pdf->PrintDocument(printername, 0, 9999, options); } |
|
![]() |
|
Kent ![]() Beginner ![]() Joined: 15 Mar 16 Location: New Zealand Status: Offline Points: 10 |
![]() ![]() ![]() ![]() ![]() |
Hi All, For anyone else that battles this like I have - I discovered today that the size of my DEVMODE was always 64 bytes smaller than the one returned by 'GetPrinterDevModeToString' returned. After a bit of research, I discovered this was because I needed to use 'PRINTDLGEXW' instead of 'PRINTDLGEX' (ie. the Unicode version). (the main difference being 'dmDeviceName' and 'dmFormName ' - both 32 characters - which un unicode explain the extra 64 bytes). Once I had changed this (and adjusted my other code appropriately) - it now appears to be working :) cheers Kent.
|
|
![]() |
Post Reply ![]() |
|
Tweet
|
Forum Jump | Forum Permissions ![]() You cannot post new topics in this forum You cannot reply to topics in this forum You cannot delete your posts in this forum You cannot edit your posts in this forum You cannot create polls in this forum You cannot vote in polls in this forum |
Copyright © 2017 Debenu. Debenu Quick PDF Library is a PDF SDK. All rights reserved. About — Contact — Blog — Support — Online Store