Page 1 of 2
Printer: How to get the device name
Posted: Mon Aug 07, 2006 9:16 pm
by TerryHough
How can I retrieve the "device name" of the chosen printer after a
PrintRequester()
or
PrintDlg_().
I am lost trying to do this.
Terry
Posted: Mon Aug 07, 2006 9:51 pm
by Edwin Knoppert
I don't know the pb requester but once the PrintDlg() is invoked OK then you'll have pointer to a DEVMODE and a DEVNAMES structure.
By using the correct offsets you can obtain the drivers and device name.
Posted: Mon Aug 07, 2006 9:53 pm
by Edwin Knoppert
You're in trouble, the pb calls don't provide any way acc. the help..
Posted: Mon Aug 07, 2006 10:39 pm
by Xombie
I added a couple lines to one of the functions from my xPrint library (
http://www.purebasic.fr/english/viewtopic.php?t=22409 ) that illustrates what you're looking for...
Code: Select all
Procedure.l _xp_GetDefaultPrinterSettings(*HoldJob.s_xp_PrintJob)
; Fills the DEVMODE and PRINTDLG structures with information about the current default printer.
Define.DEVNAMES myDevNames
;
Define.l *HoldMode
;
Define.l lResult, ResultDLG
;
*HoldMode = AllocateMemory(SizeOf(DEVMODE))
;
If *HoldMode
;
*HoldJob\HoldDialog\lStructSize = SizeOf(PRINTDLG)
*HoldJob\HoldDialog\flags = #PD_RETURNDC | #PD_RETURNDEFAULT
*HoldJob\HoldDialog\hwndOwner = #Null
*HoldJob\HoldDialog\hDevMode = *HoldMode
*HoldJob\HoldDialog\hDevNames = #Null
*HoldJob\HoldDialog\hInstance = 0
*HoldJob\HoldDialog\lpfnSetupHook = #Null
*HoldJob\HoldDialog\lpPrintSetupTemplateName = #Null
*HoldJob\HoldDialog\lpPrintTemplateName = #Null
;
lResult = CopyMemory(@*HoldJob\HoldMode, *HoldMode, SizeOf(DEVMODE))
;
ResultDLG = PrintDlg_(*HoldJob\HoldDialog)
;
lResult = CopyMemory(*HoldMode, @*HoldJob\HoldMode, SizeOf(DEVMODE))
;/ The following block illustrates retrieving the printer name
Define.DEVMODE *HoldDev
*HoldDev = *HoldJob\HoldDialog\hDevMode
Debug PeekS(@*HoldDev\dmDeviceName[0])
;/
FreeMemory(*HoldMode)
;
EndIf
;
EndProcedure
Note that the code is original based on code by Rings. Hope that helps!
Posted: Tue Aug 08, 2006 8:30 am
by Shardik
Code: Select all
i.L
PrintDlg.PRINTDLG
PrinterName.S
Result.L
DevMode = GlobalAlloc_(#GMEM_MOVEABLE | #GMEM_ZEROINIT, SizeOf(DEVMODE))
DevModeLocked = GlobalLock_(DevMode)
PrintDlg\lStructSize = SizeOf(PRINTDLG)
PrintDlg\Flags = #PD_ALLPAGES
PrintDlg\hDevMode = DevModeLocked
Result = PrintDlg_(PrintDlg)
If Result <> #False
*DevMode.DEVMODE = PrintDlg\hDevMode
While i < 32 And PeekB(*DevMode + i) <> 0
PrinterName = PrinterName + Chr(PeekB(*DevMode + i))
i = i + 1
Wend
If Len(PrinterName) = 31
PrinterName = PrinterName + "..."
EndIf
MessageRequester("Printer Device Name", PrinterName, #MB_ICONINFORMATION)
EndIf
GlobalUnlock_(DevMode)
GlobalFree_(DevMode)
Posted: Tue Aug 08, 2006 9:43 am
by Shardik
Xombie,
one small advice for your code example. If you are requesting a DC handle with #PD_RETURNDC you should delete it afterwards:
Code: Select all
If lResult <> 0
DeleteDC_(*HoldJob\HoldDialog\hDC)
End If
For further information take a look at the C example "Displaying the Print Dialog Box" in the MSDN:
http://windowssdk.msdn.microsoft.com/en ... 46829.aspx
Posted: Tue Aug 08, 2006 12:16 pm
by Edwin Knoppert
Afaik the devmode devicename can be empty or truncated.
The devnames structure contains the correct name(s).
Posted: Tue Aug 08, 2006 2:09 pm
by Shardik
Edwin,
you are right that ist is probably safer to read the device name from the DEVNAMES control structure. The MSDN says:
Note that the dmDeviceName member of the DEVMODE structure also specifies a printer name. However, dmDeviceName is limited to 32 characters, and the wDeviceOffset name is not. If the wDeviceOffset and dmDeviceName names are not the same, PrintDlg initializes the dialog box using the printer specified by wDeviceOffset.
http://windowssdk.msdn.microsoft.com/en ... 46843.aspx
But because the call of the PrintDlg() function initializes the dialog box with the printer from wDeviceOffset it should be nearly as safe to use my code after the call of this function.
The possible truncation of the device name is already taken care of in my code and was successfully tested with a very long "friendly" printer name.
Nevertheless here is the "safer" solution which doesn't truncate the "friendly" printer name:
Code: Select all
PrintDlg.PRINTDLG
DevNames = GlobalAlloc_(#GMEM_MOVEABLE | #GMEM_ZEROINIT, SizeOf(DEVNAMES))
DevModeLocked = GlobalLock_(DevNames)
PrintDlg\hDevMode = 0
PrintDlg\hDevNames = DevModeLocked
PrintDlg\lStructSize = SizeOf(PRINTDLG)
PrintDlg\Flags = #PD_ALLPAGES
If PrintDlg_(PrintDlg) <> #False
*DEVNAMES.DEVNAMES = PrintDlg\hDevNames
MessageRequester("Printer Device Name", PeekS(*DEVNAMES + *DEVNAMES\wDeviceOffset), #MB_ICONINFORMATION)
EndIf
GlobalUnlock_(DevNames)
GlobalFree_(DevNames)
Posted: Tue Aug 08, 2006 2:40 pm
by Edwin Knoppert
1)
You should not pass a locked global mem but it's unlocked handle.
Somehow it sees it's already locked but it's not what it should expect.
2)
The first time you have succesful printdlg call(+OK) the devmode+devnames structures *are* created for you.
You better continue using those throughout the program.
No need to prepare a memory block yourself.
Posted: Tue Aug 08, 2006 2:42 pm
by Edwin Knoppert
The global mem is a type of #GHND which should be #GMEM_MOVEABLE + #GMEM_ZEROINIT
(Which you did but it's better to follow the rules)
Posted: Tue Aug 08, 2006 3:04 pm
by TerryHough
Thanks for all the responses, guys.
However, I still don't have a valid "friendly" printer name being returned.
Shardik's latest code returns a "Q" which certainly isn't the name.
So far, I haven't been able to utilize Xombie's code and get any response. Probably something I did, but I just get a memory error with it.
No wonder I was confused. This seems terribly difficult.
Posted: Tue Aug 08, 2006 3:09 pm
by Edwin Knoppert
I rewrote it and shows the printername:
Code: Select all
PrintDlg.PRINTDLG
PrintDlg\hDevMode = 0
PrintDlg\hDevNames = 0
PrintDlg\lStructSize = SizeOf(PRINTDLG)
PrintDlg\Flags = #PD_ALLPAGES
If PrintDlg_(PrintDlg) <> #FALSE
*DEVNAMES.DEVNAMES = GlobalLock_(PrintDlg\hDevNames)
MessageRequester("Printer Device Name", PeekS(*DEVNAMES + *DEVNAMES\wDeviceOffset), #MB_ICONINFORMATION)
GlobalUnlock_(PrintDlg\hDevNames)
EndIf
; Only at the end of the app
GlobalFree_(PrintDlg\hDevNames)
Of course it lacks testing for valid memory and such..
Posted: Tue Aug 08, 2006 3:32 pm
by TerryHough
Edwin Knoppert wrote:I rewrote it and shows the printername:
Thanks, Edwin. That works for me here.
I got into this trying to print a page in landscape mode. Now, I can
at least try to get that working.
In fact, I have to also get the printer to select a second tray.
I will need all the help I can get.
Thanks to everyone who responded. It was all a big help.
Terry
Posted: Tue Aug 08, 2006 4:07 pm
by Edwin Knoppert
Make sure you add some testing, i left these out..
Posted: Wed Aug 09, 2006 8:22 am
by Shardik
Terry,
I am sorry that my code didn't work for you. Did you test it with Win98? I had no problems running both examples under WinNT SP6 and WinXP SP2.
How do you want to switch to landscape mode? If you want to display the print dialog and preset to landscape mode, take a look at a code example from wichtel in the German forum:
http://www.purebasic.fr/german/archive/ ... php?t=1680
If you don't want to display the print dialog and change the landscape mode only for the default printer and the current print, take a look at this code example in the German forum:
http://www.purebasic.fr/german/archive/ ... c.php?t=83
If you want to change the default of a print dialog setting without displaying the print dialog, take a look at a code example from me in the German forum, which changes the number of copies to print for the default printer:
http://www.purebasic.fr/german/viewtopic.php?t=6453
Tell me, if you want to change the default setting to landscape mode (without displaying the print dialog) and I will post an adapted example for you.
Edwin,
thank you very much for optimizing my code and pinpointing its shortcuts. You are right that it is unnecessary to allocate memory and passing it to the print dialog if you only want to read from the DEVNAMES or DEVMODE structure. But the example was adapted from a code which manipulated the contents of the print dialog...