Printer: How to get the device name

Just starting out? Need help? Post your questions and find answers here.
TerryHough
Enthusiast
Enthusiast
Posts: 781
Joined: Fri Apr 25, 2003 6:51 pm
Location: NC, USA
Contact:

Printer: How to get the device name

Post 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
Edwin Knoppert
Addict
Addict
Posts: 1073
Joined: Fri Apr 25, 2003 11:13 pm
Location: Netherlands
Contact:

Post 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.
Edwin Knoppert
Addict
Addict
Posts: 1073
Joined: Fri Apr 25, 2003 11:13 pm
Location: Netherlands
Contact:

Post by Edwin Knoppert »

You're in trouble, the pb calls don't provide any way acc. the help..
Xombie
Addict
Addict
Posts: 898
Joined: Thu Jul 01, 2004 2:51 am
Location: Tacoma, WA
Contact:

Post 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!
User avatar
Shardik
Addict
Addict
Posts: 2058
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Post 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)
User avatar
Shardik
Addict
Addict
Posts: 2058
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Post 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
Edwin Knoppert
Addict
Addict
Posts: 1073
Joined: Fri Apr 25, 2003 11:13 pm
Location: Netherlands
Contact:

Post by Edwin Knoppert »

Afaik the devmode devicename can be empty or truncated.
The devnames structure contains the correct name(s).
User avatar
Shardik
Addict
Addict
Posts: 2058
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Post 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)
Last edited by Shardik on Wed Aug 09, 2006 12:48 pm, edited 1 time in total.
Edwin Knoppert
Addict
Addict
Posts: 1073
Joined: Fri Apr 25, 2003 11:13 pm
Location: Netherlands
Contact:

Post 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.
Edwin Knoppert
Addict
Addict
Posts: 1073
Joined: Fri Apr 25, 2003 11:13 pm
Location: Netherlands
Contact:

Post 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)
TerryHough
Enthusiast
Enthusiast
Posts: 781
Joined: Fri Apr 25, 2003 6:51 pm
Location: NC, USA
Contact:

Post 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.
Edwin Knoppert
Addict
Addict
Posts: 1073
Joined: Fri Apr 25, 2003 11:13 pm
Location: Netherlands
Contact:

Post 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..
TerryHough
Enthusiast
Enthusiast
Posts: 781
Joined: Fri Apr 25, 2003 6:51 pm
Location: NC, USA
Contact:

Post 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
Edwin Knoppert
Addict
Addict
Posts: 1073
Joined: Fri Apr 25, 2003 11:13 pm
Location: Netherlands
Contact:

Post by Edwin Knoppert »

Make sure you add some testing, i left these out..
User avatar
Shardik
Addict
Addict
Posts: 2058
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Post 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...
Post Reply