Author Topic: Windows Printer API  (Read 5362 times)

0 Members and 1 Guest are viewing this topic.

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Windows Printer API
« on: November 08, 2019, 03:03:37 pm »
Some old, lost code from [abandoned, outdated and now likely malicious qb64 dot net website - don’t go there], recovered thanks to Richard, which allows us to call up the windows printer interface from within QB64.  From my testing, this works on the old SDL versions and some of the older GL versions, but I have yet to get it to work properly with the latest versions of QB64 itself.  Folks with older versions of QB64 might be interested in using this (if you can, kindly tell me what version you have that it works on, so I can trace back to which point it stopped working), and people who are familiar with DECLARE LIBRARY and the Windows API might be interested in using this as a roadmap to sort out what's wrong and get it to working for the rest of us.  (I'll dig into it myself, to see if I can sort it back out later as well.)

Code: QB64: [Select]
  1. CONST PD_ALLPAGES = 0
  2. CONST PD_CURRENTPAGE = &H00400000
  3. CONST PD_DISABLEPRINTTOFILE = &H00080000
  4. CONST PD_PAGENUMS = 2
  5. CONST PD_RETURNDC = &H00000100
  6. CONST PD_RETURNDEFAULT = &H00000400
  7. CONST PD_SELECTION = 1
  8. CONST PD_USEDEVMODECOPIESANDCOLLATE = &H00040000
  9. CONST START_PAGE_GENERAL = -1
  10. CONST PD_RESULT_CANCEL = 0
  11. CONST PD_RESULT_PRINT = 1
  12. CONST PD_RESULT_APPLY = 2
  13. CONST CCHDEVICENAME = 32
  14. CONST CCHFORMNAME = 32
  15.  
  16. CONST TA_UPDATECP = 1
  17.  
  18. CONST S_OK = 0
  19. ' CONST E_HANDLE = &H80070006
  20.  
  21. CONST GDI_ERROR = -1
  22.  
  23.  
  24.     FUNCTION GlobalFree~%& (BYVAL hMem~%&)
  25.     FUNCTION GetLastError~& ()
  26.  
  27.     FUNCTION DeleteDC& (BYVAL hdc~%&)
  28.     FUNCTION SetTextAlign~& (BYVAL hdc~%&, BYVAL fMode~&)
  29.     FUNCTION GetTextAlign~& (BYVAL hdc~%&)
  30.     FUNCTION TextOutA& (BYVAL hdc~%&, BYVAL nXStart&, BYVAL nYStart&, BYVAL lpString~%&, BYVAL cchString&)
  31.     FUNCTION StartDocA& (BYVAL hdc~%&, BYVAL lpdi~%&)
  32.     FUNCTION AbortDoc& (BYVAL hdc~%&)
  33.     FUNCTION StartPage& (BYVAL hDC~%&)
  34.     FUNCTION EndPage& (BYVAL hdc~%&)
  35.     FUNCTION EndDoc& (BYVAL hdc~%&)
  36.     FUNCTION ResetDCA~%& (BYVAL hdc~%&, BYVAL lpInitData~%&)
  37.  
  38.     FUNCTION FindWindowA%& (BYVAL lpClassName%&, BYVAL lpWindowName%&)
  39.  
  40.     FUNCTION PrintDlgExA~& (BYVAL lppd~%&) ' returns an HRESULT
  41.  
  42. ' http://www.[abandoned, outdated and now likely malicious qb64 dot net website - don’t go there]/forum/index.php?topic=10886.msg91583#msg91583
  43.     SUB SUB_READDEVMODE (BYVAL p~%&)
  44.     SUB SUB_READDEVNAMES (BYVAL p~%&)
  45.  
  46. TYPE DOCINFOA
  47.     cbSize AS LONG
  48.     lpszDocName AS _UNSIGNED _OFFSET ' LPCSTR
  49.     lpszOutput AS _UNSIGNED _OFFSET ' LPCSTR
  50.     lpszDatatype AS _UNSIGNED _OFFSET ' LPCSTR
  51.     fwType AS _UNSIGNED LONG
  52.  
  53.  
  54. TYPE POINTL
  55.     x AS LONG
  56.     y AS LONG
  57.  
  58. CONST len_DEVMODEA = 156
  59. TYPE DEVMODEA
  60.     dmDeviceName AS STRING * CCHDEVICENAME
  61.     dmSpecVersion AS _UNSIGNED INTEGER
  62.     dmDriverVersion AS _UNSIGNED INTEGER
  63.     dmSize AS _UNSIGNED INTEGER
  64.     dmDriverExtra AS _UNSIGNED INTEGER
  65.     dmFields AS _UNSIGNED LONG
  66.     ' union {
  67.     ' struct { comment either the following 8 lines
  68.     dmOrientation AS INTEGER
  69.     dmPaperSize AS INTEGER
  70.     dmPaperLength AS INTEGER
  71.     dmPaperWidth AS INTEGER
  72.     dmScale AS INTEGER
  73.     dmCopies AS INTEGER
  74.     dmDefaultSource AS INTEGER
  75.     dmPrintQuality AS INTEGER
  76.     ' };
  77.     ' struct { or the following 3 lines
  78.     ' dmPosition AS POINTL
  79.     ' dmDisplayOrientation AS _UNSIGNED LONG
  80.     ' dmDisplayFixedOutput AS _UNSIGNED LONG
  81.     ' };
  82.     ' };
  83.     dmColor AS INTEGER
  84.     dmDuplex AS INTEGER
  85.     dmYResolution AS INTEGER
  86.     dmTTOption AS INTEGER
  87.     dmCollate AS INTEGER
  88.     dmFormName AS STRING * CCHFORMNAME
  89.     dmLogPixels AS _UNSIGNED INTEGER
  90.     dmBitsPerPel AS _UNSIGNED LONG
  91.     dmPelsWidth AS _UNSIGNED LONG
  92.     dmPelsHeight AS _UNSIGNED LONG
  93.     ' union { comment exactly 1 of the following 2 lines
  94.     ' dmDisplayFlags AS _UNSIGNED LONG
  95.     dmNup AS _UNSIGNED LONG
  96.     ' };
  97.     dmDisplayFrequency AS _UNSIGNED LONG
  98.     dmICMMethod AS _UNSIGNED LONG
  99.     dmICMIntent AS _UNSIGNED LONG
  100.     dmMediaType AS _UNSIGNED LONG
  101.     dmDitherType AS _UNSIGNED LONG
  102.     dmReserved1 AS _UNSIGNED LONG
  103.     dmReserved2 AS _UNSIGNED LONG
  104.     dmPanningWidth AS _UNSIGNED LONG
  105.     dmPanningHeight AS _UNSIGNED LONG
  106.  
  107. TYPE DEVNAMES
  108.     wDriverOffset AS _UNSIGNED INTEGER
  109.     wDeviceOffset AS _UNSIGNED INTEGER
  110.     wOutputOffset AS _UNSIGNED INTEGER
  111.     wDefault AS _UNSIGNED INTEGER
  112.  
  113. TYPE PRINTPAGERANGE
  114.     nFromPage AS _UNSIGNED LONG
  115.     nToPage AS _UNSIGNED LONG
  116.  
  117. TYPE PRINTDLGEX
  118.     lStructSize AS _UNSIGNED LONG
  119.     hwndOwner AS _UNSIGNED _OFFSET ' HWND
  120.     hDevMode AS _UNSIGNED _OFFSET ' HGLOBAL
  121.     hDevNames AS _UNSIGNED _OFFSET ' HGLOBAL
  122.     hDC AS _UNSIGNED _OFFSET ' HDC
  123.     Flags AS _UNSIGNED LONG
  124.     Flags2 AS _UNSIGNED LONG
  125.     ExclusionFlags AS _UNSIGNED LONG
  126.     nPageRanges AS _UNSIGNED LONG
  127.     nMaxPageRanges AS _UNSIGNED LONG
  128.     lpPageRanges AS _UNSIGNED _OFFSET ' LPPRINTPAGERANGE
  129.     nMinPage AS _UNSIGNED LONG
  130.     nMaxPage AS _UNSIGNED LONG
  131.     nCopies AS _UNSIGNED LONG
  132.     hInstance AS _UNSIGNED _OFFSET ' HINSTANCE
  133.     lpPrintTemplateName AS _UNSIGNED _OFFSET ' LPCSTR
  134.     lpCallback AS _UNSIGNED _OFFSET ' LPUNKNOWN
  135.     nPropertyPages AS _UNSIGNED LONG
  136.     lphPropertyPages AS _UNSIGNED _OFFSET ' HPROPSHEETPAGE *
  137.     nStartPage AS _UNSIGNED LONG
  138.     dwResultAction AS _UNSIGNED LONG
  139.  
  140. DIM pageranges(0 TO 7) AS PRINTPAGERANGE
  141. DIM pde AS PRINTDLGEX
  142. DIM t1 AS STRING * 16
  143. DIM doc AS DOCINFOA
  144.  
  145. _DELAY .5 ' race condition for the window's appearance.
  146. t = "qb64 prn test" + STR$(TIMER) 'random title for FindWindowA
  147. t = t + CHR$(0)
  148. hWnd = FindWindowA(0, _OFFSET(t))
  149. _TITLE "Whatever you actually want the title to be"
  150.  
  151. pde.lStructSize = LEN(pde)
  152. pde.hwndOwner = hWnd
  153. pde.hDevMode = 0
  154. pde.hDevNames = 0
  155. pde.Flags = PD_ALLPAGES OR PD_RETURNDC OR PD_USEDEVMODECOPIESANDCOLLATE
  156. pde.Flags2 = 0
  157. pde.nPageRanges = 0
  158. pde.nMaxPageRanges = 1 + UBOUND(pageranges)
  159. pde.lpPageRanges = _OFFSET(pageranges(0))
  160. pde.nMinPage = 1
  161. pde.nMaxPage = 1
  162. pde.nCopies = 1
  163. pde.hInstance = 0
  164. pde.lpCallback = 0
  165. pde.nPropertyPages = 0
  166. pde.lphPropertyPages = 0
  167. pde.nStartPage = START_PAGE_GENERAL
  168. pde.dwResultAction = 0
  169.  
  170. hr = PrintDlgExA(_OFFSET(pde))
  171. IF S_OK <> hr THEN PRINT "Error. HRESULT: 0x" + LCASE$(HEX$(hr))
  172. PRINT pde.dwResultAction
  173.  
  174. IF pde.hDevMode THEN SUB_READDEVMODE _OFFSET(pde.hDevMode)
  175. IF pde.hDevNames THEN SUB_READDEVNAMES _OFFSET(pde.hDevNames)
  176.  
  177. IF PD_RESULT_PRINT = pde.dwResultAction THEN
  178.     IF pde.hDC THEN
  179.         t1 = "qb64 prn test" + CHR$(0) ' fixed len str so it won't move
  180.         doc.cbSize = LEN(doc)
  181.         doc.lpszDocName = _OFFSET(t1)
  182.         doc.lpszOutput = 0
  183.         doc.lpszDatatype = 0
  184.         doc.fwType = 0
  185.         IF 0 >= StartDocA(pde.hDC, _OFFSET(doc)) THEN PRINT "doc error"
  186.         IF 0 >= StartPage(pde.hDC) THEN PRINT "doc error"
  187.  
  188.         IF GDI_ERROR = SetTextAlign(pde.hDC, GetTextAlign(pde.hDC) OR TA_UPDATECP) THEN PRINT "GDI error"
  189.         t = "Hello, world!"
  190.         IF 0 = TextOutA(pde.hDC, 0, 0, _OFFSET(t), LEN(t)) THEN PRINT "error"
  191.  
  192.         IF 0 >= EndPage(pde.hDC) THEN PRINT "doc error"
  193.         IF 0 >= EndDoc(pde.hDC) THEN PRINT "doc error"
  194.     END IF
  195.  
  196. IF pde.hDevMode THEN
  197.     IF 0 <> GlobalFree(pde.hDevMode) THEN PRINT "Error: 0x" + LCASE$(HEX$(GetLastError))
  198. IF pde.hDevNames THEN
  199.     IF 0 <> GlobalFree(pde.hDevNames) THEN PRINT "Error: 0x" + LCASE$(HEX$(GetLastError))
  200. IF pde.hDC THEN
  201.     IF 0 = DeleteDC(pde.hDC) THEN PRINT "Error: 0x" + LCASE$(HEX$(GetLastError))
  202.  
  203.  
  204. SUB readDevMode (t AS DEVMODEA)
  205. PRINT t.dmDeviceName
  206. ' etc...
  207.  
  208. SUB readDevNames (t AS DEVNAMES)
  209. t$ = SPACE$(255)
  210.  
  211. m = _MEM(_OFFSET(t) + t.wDriverOffset, 255)
  212. _MEMGET m, m.OFFSET, t$
  213.  
  214. m = _MEM(_OFFSET(t) + t.wDeviceOffset, 255)
  215. _MEMGET m, m.OFFSET, t$
  216.  
  217. m = _MEM(_OFFSET(t) + t.wOutputOffset, 255)
  218. _MEMGET m, m.OFFSET, t$
  219.  
  220.  
  221.  
  222. 'PRINT peekstr(_OFFSET(t) + t.wDriverOffset)
  223. 'PRINT peekstr(_OFFSET(t) + t.wDeviceOffset)
  224. 'PRINT peekstr(_OFFSET(t) + t.wOutputOffset)
  225.  
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Windows Printer API
« Reply #1 on: November 08, 2019, 03:20:41 pm »
Modified code which works on QB64 v1.3 -- 32-bit version.   Offsets or padding needs to change something somewhere to work in QB64-64bit versions, but what I have here is working as it should for the 32-bit version of QB64:

Code: QB64: [Select]
  1. CONST PD_ALLPAGES = 0
  2. CONST PD_CURRENTPAGE = &H00400000
  3. CONST PD_DISABLEPRINTTOFILE = &H00080000
  4. CONST PD_PAGENUMS = 2
  5. CONST PD_RETURNDC = &H00000100
  6. CONST PD_RETURNDEFAULT = &H00000400
  7. CONST PD_SELECTION = 1
  8. CONST PD_USEDEVMODECOPIESANDCOLLATE = &H00040000
  9. CONST START_PAGE_GENERAL = -1
  10. CONST PD_RESULT_CANCEL = 0
  11. CONST PD_RESULT_PRINT = 1
  12. CONST PD_RESULT_APPLY = 2
  13. CONST CCHDEVICENAME = 32
  14. CONST CCHFORMNAME = 32
  15.  
  16. CONST TA_UPDATECP = 1
  17.  
  18. CONST S_OK = 0
  19. ' CONST E_HANDLE = &H80070006
  20.  
  21. CONST GDI_ERROR = -1
  22.  
  23.  
  24.     FUNCTION GlobalFree~%& (BYVAL hMem~%&)
  25.     FUNCTION GetLastError~& ()
  26.  
  27.     FUNCTION DeleteDC& (BYVAL hdc~%&)
  28.     FUNCTION SetTextAlign~& (BYVAL hdc~%&, BYVAL fMode~&)
  29.     FUNCTION GetTextAlign~& (BYVAL hdc~%&)
  30.     FUNCTION TextOutA& (BYVAL hdc~%&, BYVAL nXStart&, BYVAL nYStart&, BYVAL lpString~%&, BYVAL cchString&)
  31.     FUNCTION StartDocA& (BYVAL hdc~%&, BYVAL lpdi~%&)
  32.     FUNCTION AbortDoc& (BYVAL hdc~%&)
  33.     FUNCTION StartPage& (BYVAL hDC~%&)
  34.     FUNCTION EndPage& (BYVAL hdc~%&)
  35.     FUNCTION EndDoc& (BYVAL hdc~%&)
  36.     FUNCTION ResetDCA~%& (BYVAL hdc~%&, BYVAL lpInitData~%&)
  37.  
  38.     FUNCTION FindWindowA%& (BYVAL lpClassName%&, BYVAL lpWindowName%&)
  39.  
  40.     FUNCTION PrintDlgExA~& (BYVAL lppd~%&) ' returns an HRESULT
  41.  
  42.     ' http://www.[abandoned, outdated and now likely malicious qb64 dot net website - don’t go there]/forum/index.php?topic=10886.msg91583#msg91583
  43.     SUB SUB_READDEVMODE (BYVAL p~%&)
  44.     SUB SUB_READDEVNAMES (BYVAL p~%&)
  45.  
  46. TYPE DOCINFOA
  47.     cbSize AS LONG
  48.     lpszDocName AS _UNSIGNED _OFFSET ' LPCSTR
  49.     lpszOutput AS _UNSIGNED _OFFSET ' LPCSTR
  50.     lpszDatatype AS _UNSIGNED _OFFSET ' LPCSTR
  51.     fwType AS _UNSIGNED LONG
  52.  
  53.  
  54. TYPE POINTL
  55.     x AS LONG
  56.     y AS LONG
  57.  
  58. CONST len_DEVMODEA = 156
  59. TYPE DEVMODEA
  60.     dmDeviceName AS STRING * CCHDEVICENAME
  61.     dmSpecVersion AS _UNSIGNED INTEGER
  62.     dmDriverVersion AS _UNSIGNED INTEGER
  63.     dmSize AS _UNSIGNED INTEGER
  64.     dmDriverExtra AS _UNSIGNED INTEGER
  65.     dmFields AS _UNSIGNED LONG
  66.     ' union {
  67.     ' struct { comment either the following 8 lines
  68.     dmOrientation AS INTEGER
  69.     dmPaperSize AS INTEGER
  70.     dmPaperLength AS INTEGER
  71.     dmPaperWidth AS INTEGER
  72.     dmScale AS INTEGER
  73.     dmCopies AS INTEGER
  74.     dmDefaultSource AS INTEGER
  75.     dmPrintQuality AS INTEGER
  76.     ' };
  77.     ' struct { or the following 3 lines
  78.     ' dmPosition AS POINTL
  79.     ' dmDisplayOrientation AS _UNSIGNED LONG
  80.     ' dmDisplayFixedOutput AS _UNSIGNED LONG
  81.     ' };
  82.     ' };
  83.     dmColor AS INTEGER
  84.     dmDuplex AS INTEGER
  85.     dmYResolution AS INTEGER
  86.     dmTTOption AS INTEGER
  87.     dmCollate AS INTEGER
  88.     dmFormName AS STRING * CCHFORMNAME
  89.     dmLogPixels AS _UNSIGNED INTEGER
  90.     dmBitsPerPel AS _UNSIGNED LONG
  91.     dmPelsWidth AS _UNSIGNED LONG
  92.     dmPelsHeight AS _UNSIGNED LONG
  93.     ' union { comment exactly 1 of the following 2 lines
  94.     ' dmDisplayFlags AS _UNSIGNED LONG
  95.     dmNup AS _UNSIGNED LONG
  96.     ' };
  97.     dmDisplayFrequency AS _UNSIGNED LONG
  98.     dmICMMethod AS _UNSIGNED LONG
  99.     dmICMIntent AS _UNSIGNED LONG
  100.     dmMediaType AS _UNSIGNED LONG
  101.     dmDitherType AS _UNSIGNED LONG
  102.     dmReserved1 AS _UNSIGNED LONG
  103.     dmReserved2 AS _UNSIGNED LONG
  104.     dmPanningWidth AS _UNSIGNED LONG
  105.     dmPanningHeight AS _UNSIGNED LONG
  106.  
  107. TYPE DEVNAMES
  108.     wDriverOffset AS _UNSIGNED INTEGER
  109.     wDeviceOffset AS _UNSIGNED INTEGER
  110.     wOutputOffset AS _UNSIGNED INTEGER
  111.     wDefault AS _UNSIGNED INTEGER
  112.  
  113. TYPE PRINTPAGERANGE
  114.     nFromPage AS _UNSIGNED LONG
  115.     nToPage AS _UNSIGNED LONG
  116.  
  117. TYPE PRINTDLGEX
  118.     lStructSize AS _UNSIGNED LONG
  119.     hwndOwner AS _UNSIGNED _OFFSET ' HWND
  120.     hDevMode AS _UNSIGNED _OFFSET ' HGLOBAL
  121.     hDevNames AS _UNSIGNED _OFFSET ' HGLOBAL
  122.     hDC AS _UNSIGNED _OFFSET ' HDC
  123.     Flags AS _UNSIGNED LONG
  124.     Flags2 AS _UNSIGNED LONG
  125.     ExclusionFlags AS _UNSIGNED LONG
  126.     nPageRanges AS _UNSIGNED LONG
  127.     nMaxPageRanges AS _UNSIGNED LONG
  128.     lpPageRanges AS _UNSIGNED _OFFSET ' LPPRINTPAGERANGE
  129.     nMinPage AS _UNSIGNED LONG
  130.     nMaxPage AS _UNSIGNED LONG
  131.     nCopies AS _UNSIGNED LONG
  132.     hInstance AS _UNSIGNED _OFFSET ' HINSTANCE
  133.     lpPrintTemplateName AS _UNSIGNED _OFFSET ' LPCSTR
  134.     lpCallback AS _UNSIGNED _OFFSET ' LPUNKNOWN
  135.     nPropertyPages AS _UNSIGNED LONG
  136.     lphPropertyPages AS _UNSIGNED _OFFSET ' HPROPSHEETPAGE *
  137.     nStartPage AS _UNSIGNED LONG
  138.     dwResultAction AS _UNSIGNED LONG
  139.  
  140. DIM pageranges(0 TO 7) AS PRINTPAGERANGE
  141. DIM pde AS PRINTDLGEX
  142. DIM t1 AS STRING * 16
  143. DIM doc AS DOCINFOA
  144.  
  145. hWnd = _WINDOWHANDLE 'FindWindowA(0, _OFFSET(t))
  146. _TITLE "Printer API demo"
  147.  
  148. pde.lStructSize = LEN(pde)
  149. pde.hwndOwner = hWnd
  150. pde.hDevMode = 0
  151. pde.hDevNames = 0
  152. pde.Flags = PD_ALLPAGES OR PD_RETURNDC OR PD_USEDEVMODECOPIESANDCOLLATE
  153. pde.Flags2 = 0
  154. pde.nPageRanges = 0
  155. pde.nMaxPageRanges = 1 + UBOUND(pageranges)
  156. pde.lpPageRanges = _OFFSET(pageranges(0))
  157. pde.nMinPage = 1
  158. pde.nMaxPage = 1
  159. pde.nCopies = 1
  160. pde.hInstance = 0
  161. pde.lpCallback = 0
  162. pde.nPropertyPages = 0
  163. pde.lphPropertyPages = 0
  164. pde.nStartPage = START_PAGE_GENERAL
  165. pde.dwResultAction = 0
  166.  
  167. hr = PrintDlgExA(_OFFSET(pde))
  168. IF S_OK <> hr THEN PRINT "ZZError. HRESULT: 0x" + LCASE$(HEX$(hr))
  169. PRINT pde.dwResultAction
  170.  
  171. IF pde.hDevMode THEN SUB_READDEVMODE _OFFSET(pde.hDevMode)
  172. IF pde.hDevNames THEN SUB_READDEVNAMES _OFFSET(pde.hDevNames)
  173.  
  174. IF PD_RESULT_PRINT = pde.dwResultAction THEN
  175.     IF pde.hDC THEN
  176.         t1 = "qb64 prn test" + CHR$(0) ' fixed len str so it won't move
  177.         doc.cbSize = LEN(doc)
  178.         doc.lpszDocName = _OFFSET(t1)
  179.         doc.lpszOutput = 0
  180.         doc.lpszDatatype = 0
  181.         doc.fwType = 0
  182.         IF 0 >= StartDocA(pde.hDC, _OFFSET(doc)) THEN PRINT "doc error"
  183.         IF 0 >= StartPage(pde.hDC) THEN PRINT "doc error"
  184.  
  185.         IF GDI_ERROR = SetTextAlign(pde.hDC, GetTextAlign(pde.hDC) OR TA_UPDATECP) THEN PRINT "GDI error"
  186.         t = "Hello, world!"
  187.         IF 0 = TextOutA(pde.hDC, 0, 0, _OFFSET(t), LEN(t)) THEN PRINT "error"
  188.  
  189.         IF 0 >= EndPage(pde.hDC) THEN PRINT "doc error"
  190.         IF 0 >= EndDoc(pde.hDC) THEN PRINT "doc error"
  191.     END IF
  192.  
  193. IF pde.hDevMode THEN
  194.     IF 0 <> GlobalFree(pde.hDevMode) THEN PRINT "Error: 0x" + LCASE$(HEX$(GetLastError))
  195. IF pde.hDevNames THEN
  196.     IF 0 <> GlobalFree(pde.hDevNames) THEN PRINT "Error: 0x" + LCASE$(HEX$(GetLastError))
  197. IF pde.hDC THEN
  198.     IF 0 = DeleteDC(pde.hDC) THEN PRINT "Error: 0x" + LCASE$(HEX$(GetLastError))
  199.  
  200.  
  201. SUB readDevMode (t AS DEVMODEA)
  202.     PRINT t.dmDeviceName
  203.     ' etc...
  204.  
  205. SUB readDevNames (t AS DEVNAMES)
  206.     DIM m AS _MEM
  207.     t$ = SPACE$(255)
  208.  
  209.     m = _MEM(_OFFSET(t) + t.wDriverOffset, 255)
  210.     _MEMGET m, m.OFFSET, t$
  211.     PRINT t$
  212.  
  213.     m = _MEM(_OFFSET(t) + t.wDeviceOffset, 255)
  214.     _MEMGET m, m.OFFSET, t$
  215.     PRINT t$
  216.  
  217.     m = _MEM(_OFFSET(t) + t.wOutputOffset, 255)
  218.     _MEMGET m, m.OFFSET, t$
  219.     PRINT t$
  220.  
  221.  
  222.  
  223.     'PRINT peekstr(_OFFSET(t) + t.wDriverOffset)
  224.     'PRINT peekstr(_OFFSET(t) + t.wDeviceOffset)
  225.     'PRINT peekstr(_OFFSET(t) + t.wOutputOffset)
  226.  
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Marked as best answer by SMcNeill on November 08, 2019, 11:06:42 am

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Windows Printer API
« Reply #2 on: November 08, 2019, 03:55:38 pm »
This version appears to work for me with both the latest 32-bit and 64-bit versions of QB64.  Test it out guys and tell me if it works as you'd expect.

Code: QB64: [Select]
  1. CONST PD_ALLPAGES = 0
  2. CONST PD_CURRENTPAGE = &H00400000
  3. CONST PD_DISABLEPRINTTOFILE = &H00080000
  4. CONST PD_PAGENUMS = 2
  5. CONST PD_RETURNDC = &H00000100
  6. CONST PD_RETURNDEFAULT = &H00000400
  7. CONST PD_SELECTION = 1
  8. CONST PD_USEDEVMODECOPIESANDCOLLATE = &H00040000
  9. CONST START_PAGE_GENERAL = -1
  10. CONST PD_RESULT_CANCEL = 0
  11. CONST PD_RESULT_PRINT = 1
  12. CONST PD_RESULT_APPLY = 2
  13. CONST CCHDEVICENAME = 32
  14. CONST CCHFORMNAME = 32
  15.  
  16. CONST TA_UPDATECP = 1
  17.  
  18. CONST S_OK = 0
  19. ' CONST E_HANDLE = &H80070006
  20.  
  21. CONST GDI_ERROR = -1
  22.  
  23.  
  24.     FUNCTION GlobalFree~%& (BYVAL hMem~%&)
  25.     FUNCTION GetLastError~& ()
  26.  
  27.     FUNCTION DeleteDC& (BYVAL hdc~%&)
  28.     FUNCTION SetTextAlign~& (BYVAL hdc~%&, BYVAL fMode~&)
  29.     FUNCTION GetTextAlign~& (BYVAL hdc~%&)
  30.     FUNCTION TextOutA& (BYVAL hdc~%&, BYVAL nXStart&, BYVAL nYStart&, BYVAL lpString~%&, BYVAL cchString&)
  31.     FUNCTION StartDocA& (BYVAL hdc~%&, BYVAL lpdi~%&)
  32.     FUNCTION AbortDoc& (BYVAL hdc~%&)
  33.     FUNCTION StartPage& (BYVAL hDC~%&)
  34.     FUNCTION EndPage& (BYVAL hdc~%&)
  35.     FUNCTION EndDoc& (BYVAL hdc~%&)
  36.     FUNCTION ResetDCA~%& (BYVAL hdc~%&, BYVAL lpInitData~%&)
  37.  
  38.     FUNCTION FindWindowA%& (BYVAL lpClassName%&, BYVAL lpWindowName%&)
  39.  
  40.     FUNCTION PrintDlgExA~& (BYVAL lppd~%&) ' returns an HRESULT
  41.  
  42.     ' http://www.[abandoned, outdated and now likely malicious qb64 dot net website - don’t go there]/forum/index.php?topic=10886.msg91583#msg91583
  43.     SUB SUB_READDEVMODE (BYVAL p~%&)
  44.     SUB SUB_READDEVNAMES (BYVAL p~%&)
  45.  
  46. TYPE DOCINFOA
  47.     cbSize AS LONG
  48.     lpszDocName AS _UNSIGNED _OFFSET ' LPCSTR
  49.     lpszOutput AS _UNSIGNED _OFFSET ' LPCSTR
  50.     lpszDatatype AS _UNSIGNED _OFFSET ' LPCSTR
  51.     fwType AS _UNSIGNED LONG
  52.  
  53.  
  54. TYPE POINTL
  55.     x AS LONG
  56.     y AS LONG
  57.  
  58. CONST len_DEVMODEA = 156
  59. TYPE DEVMODEA
  60.     dmDeviceName AS STRING * CCHDEVICENAME
  61.     dmSpecVersion AS _UNSIGNED INTEGER
  62.     dmDriverVersion AS _UNSIGNED INTEGER
  63.     dmSize AS _UNSIGNED INTEGER
  64.     dmDriverExtra AS _UNSIGNED INTEGER
  65.     dmFields AS _UNSIGNED LONG
  66.     ' union {
  67.     ' struct { comment either the following 8 lines
  68.     dmOrientation AS INTEGER
  69.     dmPaperSize AS INTEGER
  70.     dmPaperLength AS INTEGER
  71.     dmPaperWidth AS INTEGER
  72.     dmScale AS INTEGER
  73.     dmCopies AS INTEGER
  74.     dmDefaultSource AS INTEGER
  75.     dmPrintQuality AS INTEGER
  76.     ' };
  77.     ' struct { or the following 3 lines
  78.     ' dmPosition AS POINTL
  79.     ' dmDisplayOrientation AS _UNSIGNED LONG
  80.     ' dmDisplayFixedOutput AS _UNSIGNED LONG
  81.     ' };
  82.     ' };
  83.     dmColor AS INTEGER
  84.     dmDuplex AS INTEGER
  85.     dmYResolution AS INTEGER
  86.     dmTTOption AS INTEGER
  87.     dmCollate AS INTEGER
  88.     dmFormName AS STRING * CCHFORMNAME
  89.     dmLogPixels AS _UNSIGNED INTEGER
  90.     dmBitsPerPel AS _UNSIGNED LONG
  91.     dmPelsWidth AS _UNSIGNED LONG
  92.     dmPelsHeight AS _UNSIGNED LONG
  93.     ' union { comment exactly 1 of the following 2 lines
  94.     ' dmDisplayFlags AS _UNSIGNED LONG
  95.     dmNup AS _UNSIGNED LONG
  96.     ' };
  97.     dmDisplayFrequency AS _UNSIGNED LONG
  98.     dmICMMethod AS _UNSIGNED LONG
  99.     dmICMIntent AS _UNSIGNED LONG
  100.     dmMediaType AS _UNSIGNED LONG
  101.     dmDitherType AS _UNSIGNED LONG
  102.     dmReserved1 AS _UNSIGNED LONG
  103.     dmReserved2 AS _UNSIGNED LONG
  104.     dmPanningWidth AS _UNSIGNED LONG
  105.     dmPanningHeight AS _UNSIGNED LONG
  106.  
  107. TYPE DEVNAMES
  108.     wDriverOffset AS _UNSIGNED INTEGER
  109.     wDeviceOffset AS _UNSIGNED INTEGER
  110.     wOutputOffset AS _UNSIGNED INTEGER
  111.     wDefault AS _UNSIGNED INTEGER
  112.  
  113. TYPE PRINTPAGERANGE
  114.     nFromPage AS _UNSIGNED LONG
  115.     nToPage AS _UNSIGNED LONG
  116.  
  117. $IF 32BIT THEN
  118.     TYPE PRINTDLGEX
  119.     lStructSize AS _UNSIGNED LONG
  120.     hwndOwner AS _UNSIGNED _OFFSET ' HWND
  121.     hDevMode AS _UNSIGNED _OFFSET ' HGLOBAL
  122.     hDevNames AS _UNSIGNED _OFFSET ' HGLOBAL
  123.     hDC AS _UNSIGNED _OFFSET ' HDC
  124.     Flags AS _UNSIGNED LONG
  125.     Flags2 AS _UNSIGNED LONG
  126.     ExclusionFlags AS _UNSIGNED LONG
  127.     nPageRanges AS _UNSIGNED LONG
  128.     nMaxPageRanges AS _UNSIGNED LONG
  129.     lpPageRanges AS _UNSIGNED _OFFSET ' LPPRINTPAGERANGE
  130.     nMinPage AS _UNSIGNED LONG
  131.     nMaxPage AS _UNSIGNED LONG
  132.     nCopies AS _UNSIGNED LONG
  133.     hInstance AS _UNSIGNED _OFFSET ' HINSTANCE
  134.     lpPrintTemplateName AS _UNSIGNED _OFFSET ' LPCSTR
  135.     lpCallback AS _UNSIGNED _OFFSET ' LPUNKNOWN
  136.     nPropertyPages AS _UNSIGNED LONG
  137.     lphPropertyPages AS _UNSIGNED _OFFSET ' HPROPSHEETPAGE *
  138.     nStartPage AS _UNSIGNED LONG
  139.     dwResultAction AS _UNSIGNED LONG
  140.     END TYPE
  141.     TYPE PRINTDLGEX
  142.         lStructSize AS _UNSIGNED _INTEGER64
  143.         hwndOwner AS _UNSIGNED _OFFSET ' HWND
  144.         hDevMode AS _UNSIGNED _OFFSET ' HGLOBAL
  145.         hDevNames AS _UNSIGNED _OFFSET ' HGLOBAL
  146.         hDC AS _UNSIGNED _OFFSET ' HDC
  147.         Flags AS _UNSIGNED LONG
  148.         Flags2 AS _UNSIGNED LONG
  149.         ExclusionFlags AS _UNSIGNED LONG
  150.         nPageRanges AS _UNSIGNED LONG
  151.         nMaxPageRanges AS _UNSIGNED _INTEGER64
  152.         lpPageRanges AS _UNSIGNED _OFFSET ' LPPRINTPAGERANGE
  153.         nMinPage AS _UNSIGNED LONG
  154.         nMaxPage AS _UNSIGNED LONG
  155.         nCopies AS _UNSIGNED _INTEGER64 'LONG
  156.         hInstance AS _UNSIGNED _OFFSET ' HINSTANCE
  157.         lpPrintTemplateName AS _UNSIGNED _OFFSET ' LPCSTR
  158.         lpCallback AS _UNSIGNED _OFFSET ' LPUNKNOWN
  159.         nPropertyPages AS _UNSIGNED _INTEGER64 'LONG
  160.         lphPropertyPages AS _UNSIGNED _OFFSET ' HPROPSHEETPAGE *
  161.         nStartPage AS _UNSIGNED LONG
  162.         dwResultAction AS _UNSIGNED LONG
  163.     END TYPE
  164.  
  165. DIM pageranges(0 TO 7) AS PRINTPAGERANGE
  166. DIM pde AS PRINTDLGEX
  167. DIM t1 AS STRING * 16
  168. DIM doc AS DOCINFOA
  169.  
  170. hWnd = _WINDOWHANDLE 'FindWindowA(0, _OFFSET(t))
  171. _TITLE "Printer API demo"
  172. pde.lStructSize = LEN(pde)
  173. pde.hwndOwner = hWnd
  174. pde.hDevMode = 0
  175. pde.hDevNames = 0
  176. pde.Flags = PD_ALLPAGES OR PD_RETURNDC OR PD_USEDEVMODECOPIESANDCOLLATE
  177. pde.Flags2 = 0
  178. pde.nPageRanges = 0
  179. pde.nMaxPageRanges = 1 + UBOUND(pageranges)
  180. pde.lpPageRanges = _OFFSET(pageranges(0))
  181. pde.nMinPage = 1
  182. pde.nMaxPage = 1
  183. pde.nCopies = 1
  184. pde.hInstance = 0
  185. pde.lpCallback = 0
  186. pde.nPropertyPages = 0
  187. pde.lphPropertyPages = 0
  188. pde.nStartPage = START_PAGE_GENERAL
  189. pde.dwResultAction = 0
  190.  
  191. hr = PrintDlgExA(_OFFSET(pde))
  192. IF S_OK <> hr THEN PRINT "ZZError. HRESULT: 0x" + LCASE$(HEX$(hr))
  193. PRINT pde.dwResultAction
  194.  
  195. IF pde.hDevMode THEN SUB_READDEVMODE _OFFSET(pde.hDevMode)
  196. IF pde.hDevNames THEN SUB_READDEVNAMES _OFFSET(pde.hDevNames)
  197.  
  198. IF PD_RESULT_PRINT = pde.dwResultAction THEN
  199.     IF pde.hDC THEN
  200.         t1 = "qb64 prn test" + CHR$(0) ' fixed len str so it won't move
  201.         doc.cbSize = LEN(doc)
  202.         doc.lpszDocName = _OFFSET(t1)
  203.         doc.lpszOutput = 0
  204.         doc.lpszDatatype = 0
  205.         doc.fwType = 0
  206.         IF 0 >= StartDocA(pde.hDC, _OFFSET(doc)) THEN PRINT "doc error"
  207.         IF 0 >= StartPage(pde.hDC) THEN PRINT "doc error"
  208.  
  209.         IF GDI_ERROR = SetTextAlign(pde.hDC, GetTextAlign(pde.hDC) OR TA_UPDATECP) THEN PRINT "GDI error"
  210.         t = "Hello, world!"
  211.         IF 0 = TextOutA(pde.hDC, 0, 0, _OFFSET(t), LEN(t)) THEN PRINT "error"
  212.  
  213.         IF 0 >= EndPage(pde.hDC) THEN PRINT "doc error"
  214.         IF 0 >= EndDoc(pde.hDC) THEN PRINT "doc error"
  215.     END IF
  216.  
  217. IF pde.hDevMode THEN
  218.     IF 0 <> GlobalFree(pde.hDevMode) THEN PRINT "Error: 0x" + LCASE$(HEX$(GetLastError))
  219. IF pde.hDevNames THEN
  220.     IF 0 <> GlobalFree(pde.hDevNames) THEN PRINT "Error: 0x" + LCASE$(HEX$(GetLastError))
  221. IF pde.hDC THEN
  222.     IF 0 = DeleteDC(pde.hDC) THEN PRINT "Error: 0x" + LCASE$(HEX$(GetLastError))
  223.  
  224.  
  225. SUB readDevMode (t AS DEVMODEA)
  226.     PRINT t.dmDeviceName
  227.     ' etc...
  228.  
  229. SUB readDevNames (t AS DEVNAMES)
  230.     DIM m AS _MEM
  231.     t$ = SPACE$(255)
  232.  
  233.     m = _MEM(_OFFSET(t) + t.wDriverOffset, 255)
  234.     _MEMGET m, m.OFFSET, t$
  235.     PRINT t$
  236.  
  237.     m = _MEM(_OFFSET(t) + t.wDeviceOffset, 255)
  238.     _MEMGET m, m.OFFSET, t$
  239.     PRINT t$
  240.  
  241.     m = _MEM(_OFFSET(t) + t.wOutputOffset, 255)
  242.     _MEMGET m, m.OFFSET, t$
  243.     PRINT t$
  244.  
  245.  
  246.  
  247.     'PRINT peekstr(_OFFSET(t) + t.wDriverOffset)
  248.     'PRINT peekstr(_OFFSET(t) + t.wDeviceOffset)
  249.     'PRINT peekstr(_OFFSET(t) + t.wOutputOffset)
  250.  
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline Dimster

  • Forum Resident
  • Posts: 500
    • View Profile
Re: Windows Printer API
« Reply #3 on: November 08, 2019, 04:42:08 pm »
Thanks very much Steve and Richard. I ran the code for 64 bit and was so happy to see "Hello,world!" on top left corner of my printed page. I am trying to do more with this code but I'm a little lost (well maybe a lot lost). To print a screen of text, I would use "select all" to highlight it but how then would I change Line 230, where Hello world is located to send the highlighted screen text to the printer. And to print a file from line 230 is it just a matter of " t = "d:FileName" ?? doesn't seem to be working for me at moment.

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Windows Printer API
« Reply #4 on: November 08, 2019, 04:59:02 pm »
I've really got to get a printer hooked back up to my PC sometime soonish, and then I can test it and sort out how to make it all work once again, Dimster.  ;)

This poor old code was written back in Oct 2013, and disappeared with the old [abandoned, outdated and now likely malicious qb64 dot net website - don’t go there] forums went down, and I'll need some time to sort out where/how it is supposed to work once again, before I can really answer many questions for it.  At the moment, I'm just happy to have it popping up the printer selection screen and letting me choose from the list of printers for my machine. 

My initial thinking is that the best way to use this would be to incorporate it into a set of SUB/FUNCTIONS.

Currently, if I remember correctly, this only prints a single test line of code, and that's basically from these lines:

        t = "Hello, world!"
        IF 0 = TextOutA(pde.hDC, 0, 0, _OFFSET(t), LEN(t)) THEN PRINT "error"

If you want to print more text, you can use the TextOutA command to tell the printer to print something for you, such as:

        t = "This would be the first line of text to print out!"
        IF 0 = TextOutA(pde.hDC, 0, 0, _OFFSET(t), LEN(t)) THEN PRINT "error"
        t = "This would be the second line of text to print out!"
        IF 0 = TextOutA(pde.hDC, 0, 0, _OFFSET(t), LEN(t)) THEN PRINT "error"
        t = "This would be the final line of text to print out!"
        IF 0 = TextOutA(pde.hDC, 0, 0, _OFFSET(t), LEN(t)) THEN PRINT "error"

Substitute those lines in place of the original 2 there, and you should be able to print all 3 lines on a single sheet of paper sequentially.  (Which is why I said making a SUB to handle that would probably be the best way to go...)

All of this was really more of a "proof of concept" set of code back in the day, just to mainly change printers and prove that we could interact with the windows API commands inside QB64, than something which was ever fully developed and fleshed out to make it super useful.   

Now that it's been recovered, maybe somebody will be inspired by it to expand upon it and make it a truly useful library for us.  (Heck, I might even do that, if I can just find a few extra hours in the day somewhere.)  ;)
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline SierraKen

  • Forum Resident
  • Posts: 1454
    • View Profile
Re: Windows Printer API
« Reply #5 on: November 08, 2019, 09:08:32 pm »
If you just want simple text, you can just use it the old fashion way and use LPRINT. Like in this example.
I think this will only work in Windows. There's another command to print images which I've used a few times on my printer.
I just tested this and it works. But for some reason it prints after you close the program. This is USB Printer compatible.

You can read more here: https://qb64.org/wiki/LPRINT

Code: QB64: [Select]
  1. INPUT "Type what you want on the printer: ",a$
  2.  



« Last Edit: November 08, 2019, 09:16:35 pm by SierraKen »

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Windows Printer API
« Reply #6 on: November 08, 2019, 09:24:15 pm »
If you just want simple text, you can just use it the old fashion way and use LPRINT. Like in this example.
I think this will only work in Windows. There's another command to print images which I've used a few times on my printer.
I just tested this and it works. But for some reason it prints after you close the program. This is USB Printer compatible.

You can read more here: https://qb64.org/wiki/LPRINT

Code: QB64: [Select]
  1. INPUT "Type what you want on the printer: ",a$
  2.  

LPRINT works, but you can't change which printer it uses, or any of the other settings with it, and it doesn't support any of the formatting options which you can use with the windows API, such as aligning the text, changing fonts or fontsizes, and all those things... 

The demo here is mainly to showcase how to pull up the printer options, moreso than it is to print the "Hello World" to your printer.  ;)
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline Dimster

  • Forum Resident
  • Posts: 500
    • View Profile
Re: Windows Printer API
« Reply #7 on: November 09, 2019, 09:53:17 am »
I got a little over excited there - thanks for resetting my perspective Steve - with everything you have on your plate, this one can wait it's turn, if it's turn ever tickles your fancy. I'm over my head in memory coding and watching your videos faithfully, one day "TextOutA(pde.hDC, 0, 0, _OFFSET(t), LEN(t)" will make sense to me.

Thanks SierraKen - LPRINT I am familiar with and will mess around with it.

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Windows Printer API
« Reply #8 on: November 09, 2019, 10:43:10 am »
I got a little over excited there - thanks for resetting my perspective Steve - with everything you have on your plate, this one can wait it's turn, if it's turn ever tickles your fancy. I'm over my head in memory coding and watching your videos faithfully, one day "TextOutA(pde.hDC, 0, 0, _OFFSET(t), LEN(t)" will make sense to me.

Thanks SierraKen - LPRINT I am familiar with and will mess around with it.

I had to look it up to sort out what all those parameters stand for once again, and if I'm reading the documentation correctly, TextOutA is more versitile than I'd first thought -- it's basically like _PRINTSTRING, except it prints to various places and not just the screen.

TextOutA(pde.hDC, 0, 0, _OFFSET(t), LEN(t)) --- let's break this down step by step for you:

TextOutA -- the name of the FUNCTION we're calling.  It should return an OK code, or an ERROR code if it screws up.
pde.h -- this is the handle of the device that we're sending text out to.  In this case, we're sending it to our printer which we initialized earlier.
0, 0 -- these are X,Y coordinates of where the text should print, inside the boundaries of our page.
_OFFSET(t) -- the offset of the string which we want to print out.
LEN(t) -- the length of the string which we want to print out.

I'll need to so some testing to see if it works as intended, but according to the documention, that's how it works.  :P

https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-textouta
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Windows Printer API
« Reply #9 on: November 17, 2019, 01:48:47 pm »
I was playing around with this again a bit today, and had some interesting results which I thought I'd share for folks:

Code: QB64: [Select]
  1. CONST PD_ALLPAGES = 0
  2. CONST PD_CURRENTPAGE = &H00400000
  3. CONST PD_DISABLEPRINTTOFILE = &H00080000
  4. CONST PD_PAGENUMS = 2
  5. CONST PD_RETURNDC = &H00000100
  6. CONST PD_RETURNDEFAULT = &H00000400
  7. CONST PD_SELECTION = 1
  8. CONST PD_USEDEVMODECOPIESANDCOLLATE = &H00040000
  9. CONST START_PAGE_GENERAL = -1
  10. CONST PD_RESULT_CANCEL = 0
  11. CONST PD_RESULT_PRINT = 1
  12. CONST PD_RESULT_APPLY = 2
  13. CONST CCHDEVICENAME = 32
  14. CONST CCHFORMNAME = 32
  15.  
  16. CONST TA_UPDATECP = 1
  17.  
  18. CONST S_OK = 0
  19. ' CONST E_HANDLE = &H80070006
  20.  
  21. CONST GDI_ERROR = -1
  22.  
  23.  
  24.     FUNCTION GlobalFree~%& (BYVAL hMem~%&)
  25.     FUNCTION GetLastError~& ()
  26.  
  27.     FUNCTION DeleteDC& (BYVAL hdc~%&)
  28.     FUNCTION SetTextAlign~& (BYVAL hdc~%&, BYVAL fMode~&)
  29.     FUNCTION GetTextAlign~& (BYVAL hdc~%&)
  30.     FUNCTION TextOutA& (BYVAL hdc~%&, BYVAL nXStart&, BYVAL nYStart&, BYVAL lpString~%&, BYVAL cchString&)
  31.     FUNCTION StartDocA& (BYVAL hdc~%&, BYVAL lpdi~%&)
  32.     FUNCTION AbortDoc& (BYVAL hdc~%&)
  33.     FUNCTION StartPage& (BYVAL hDC~%&)
  34.     FUNCTION EndPage& (BYVAL hdc~%&)
  35.     FUNCTION EndDoc& (BYVAL hdc~%&)
  36.     FUNCTION ResetDCA~%& (BYVAL hdc~%&, BYVAL lpInitData~%&)
  37.  
  38.     FUNCTION PrintDlgExA~& (BYVAL lppd~%&) ' returns an HRESULT
  39.  
  40. TYPE DOCINFOA
  41.     cbSize AS LONG
  42.     lpszDocName AS _UNSIGNED _OFFSET ' LPCSTR
  43.     lpszOutput AS _UNSIGNED _OFFSET ' LPCSTR
  44.     lpszDatatype AS _UNSIGNED _OFFSET ' LPCSTR
  45.     fwType AS _UNSIGNED LONG
  46.  
  47.  
  48. TYPE POINTL
  49.     x AS LONG
  50.     y AS LONG
  51.  
  52. CONST len_DEVMODEA = 156
  53. TYPE DEVMODEA
  54.     dmDeviceName AS STRING * CCHDEVICENAME
  55.     dmSpecVersion AS _UNSIGNED INTEGER
  56.     dmDriverVersion AS _UNSIGNED INTEGER
  57.     dmSize AS _UNSIGNED INTEGER
  58.     dmDriverExtra AS _UNSIGNED INTEGER
  59.     dmFields AS _UNSIGNED LONG
  60.     ' union {
  61.     ' struct { comment either the following 8 lines
  62.     dmOrientation AS INTEGER
  63.     dmPaperSize AS INTEGER
  64.     dmPaperLength AS INTEGER
  65.     dmPaperWidth AS INTEGER
  66.     dmScale AS INTEGER
  67.     dmCopies AS INTEGER
  68.     dmDefaultSource AS INTEGER
  69.     dmPrintQuality AS INTEGER
  70.     ' };
  71.     ' struct { or the following 3 lines
  72.     ' dmPosition AS POINTL
  73.     ' dmDisplayOrientation AS _UNSIGNED LONG
  74.     ' dmDisplayFixedOutput AS _UNSIGNED LONG
  75.     ' };
  76.     ' };
  77.     dmColor AS INTEGER
  78.     dmDuplex AS INTEGER
  79.     dmYResolution AS INTEGER
  80.     dmTTOption AS INTEGER
  81.     dmCollate AS INTEGER
  82.     dmFormName AS STRING * CCHFORMNAME
  83.     dmLogPixels AS _UNSIGNED INTEGER
  84.     dmBitsPerPel AS _UNSIGNED LONG
  85.     dmPelsWidth AS _UNSIGNED LONG
  86.     dmPelsHeight AS _UNSIGNED LONG
  87.     ' union { comment exactly 1 of the following 2 lines
  88.     ' dmDisplayFlags AS _UNSIGNED LONG
  89.     dmNup AS _UNSIGNED LONG
  90.     ' };
  91.     dmDisplayFrequency AS _UNSIGNED LONG
  92.     dmICMMethod AS _UNSIGNED LONG
  93.     dmICMIntent AS _UNSIGNED LONG
  94.     dmMediaType AS _UNSIGNED LONG
  95.     dmDitherType AS _UNSIGNED LONG
  96.     dmReserved1 AS _UNSIGNED LONG
  97.     dmReserved2 AS _UNSIGNED LONG
  98.     dmPanningWidth AS _UNSIGNED LONG
  99.     dmPanningHeight AS _UNSIGNED LONG
  100.  
  101. TYPE DEVNAMES
  102.     wDriverOffset AS _UNSIGNED INTEGER
  103.     wDeviceOffset AS _UNSIGNED INTEGER
  104.     wOutputOffset AS _UNSIGNED INTEGER
  105.     wDefault AS _UNSIGNED INTEGER
  106.  
  107. TYPE PRINTPAGERANGE
  108.     nFromPage AS _UNSIGNED LONG
  109.     nToPage AS _UNSIGNED LONG
  110.  
  111. $IF 32BIT THEN
  112.     TYPE PRINTDLGEX
  113.     lStructSize AS _UNSIGNED LONG
  114.     hwndOwner AS _UNSIGNED _OFFSET ' HWND
  115.     hDevMode AS _UNSIGNED _OFFSET ' HGLOBAL
  116.     hDevNames AS _UNSIGNED _OFFSET ' HGLOBAL
  117.     hDC AS _UNSIGNED _OFFSET ' HDC
  118.     Flags AS _UNSIGNED LONG
  119.     Flags2 AS _UNSIGNED LONG
  120.     ExclusionFlags AS _UNSIGNED LONG
  121.     nPageRanges AS _UNSIGNED LONG
  122.     nMaxPageRanges AS _UNSIGNED LONG
  123.     lpPageRanges AS _UNSIGNED _OFFSET ' LPPRINTPAGERANGE
  124.     nMinPage AS _UNSIGNED LONG
  125.     nMaxPage AS _UNSIGNED LONG
  126.     nCopies AS _UNSIGNED LONG
  127.     hInstance AS _UNSIGNED _OFFSET ' HINSTANCE
  128.     lpPrintTemplateName AS _UNSIGNED _OFFSET ' LPCSTR
  129.     lpCallback AS _UNSIGNED _OFFSET ' LPUNKNOWN
  130.     nPropertyPages AS _UNSIGNED LONG
  131.     lphPropertyPages AS _UNSIGNED _OFFSET ' HPROPSHEETPAGE *
  132.     nStartPage AS _UNSIGNED LONG
  133.     dwResultAction AS _UNSIGNED LONG
  134.     END TYPE
  135.     TYPE PRINTDLGEX
  136.         lStructSize AS _UNSIGNED _INTEGER64
  137.         hwndOwner AS _UNSIGNED _OFFSET ' HWND
  138.         hDevMode AS _UNSIGNED _OFFSET ' HGLOBAL
  139.         hDevNames AS _UNSIGNED _OFFSET ' HGLOBAL
  140.         hDC AS _UNSIGNED _OFFSET ' HDC
  141.         Flags AS _UNSIGNED LONG
  142.         Flags2 AS _UNSIGNED LONG
  143.         ExclusionFlags AS _UNSIGNED LONG
  144.         nPageRanges AS _UNSIGNED LONG
  145.         nMaxPageRanges AS _UNSIGNED _INTEGER64
  146.         lpPageRanges AS _UNSIGNED _OFFSET ' LPPRINTPAGERANGE
  147.         nMinPage AS _UNSIGNED LONG
  148.         nMaxPage AS _UNSIGNED LONG
  149.         nCopies AS _UNSIGNED _INTEGER64 'LONG
  150.         hInstance AS _UNSIGNED _OFFSET ' HINSTANCE
  151.         lpPrintTemplateName AS _UNSIGNED _OFFSET ' LPCSTR
  152.         lpCallback AS _UNSIGNED _OFFSET ' LPUNKNOWN
  153.         nPropertyPages AS _UNSIGNED _INTEGER64 'LONG
  154.         lphPropertyPages AS _UNSIGNED _OFFSET ' HPROPSHEETPAGE *
  155.         nStartPage AS _UNSIGNED LONG
  156.         dwResultAction AS _UNSIGNED LONG
  157.     END TYPE
  158.  
  159. DIM pageranges(0 TO 7) AS PRINTPAGERANGE
  160. DIM pde AS PRINTDLGEX
  161. DIM t1 AS STRING * 16
  162. DIM doc AS DOCINFOA
  163.  
  164. hWnd = _WINDOWHANDLE 'FindWindowA(0, _OFFSET(t))
  165. _TITLE "Printer API demo"
  166. pde.lStructSize = LEN(pde)
  167. pde.hwndOwner = hWnd
  168. pde.hDevMode = 0
  169. pde.hDevNames = 0
  170. pde.Flags = PD_ALLPAGES OR PD_RETURNDC OR PD_USEDEVMODECOPIESANDCOLLATE
  171. pde.Flags2 = 0
  172. pde.nPageRanges = 0
  173. pde.nMaxPageRanges = 1 + UBOUND(pageranges)
  174. pde.lpPageRanges = _OFFSET(pageranges(0))
  175. pde.nMinPage = 1
  176. pde.nMaxPage = 1
  177. pde.nCopies = 1
  178. pde.hInstance = 0
  179. pde.lpCallback = 0
  180. pde.nPropertyPages = 0
  181. pde.lphPropertyPages = 0
  182. pde.nStartPage = START_PAGE_GENERAL
  183. pde.dwResultAction = 0
  184.  
  185. hr = PrintDlgExA(_OFFSET(pde))
  186. IF S_OK <> hr THEN PRINT "ZZError. HRESULT: 0x" + LCASE$(HEX$(hr))
  187.  
  188. IF PD_RESULT_PRINT = pde.dwResultAction THEN
  189.     IF pde.hDC THEN
  190.         t1 = "qb64 prn test" + CHR$(0) ' fixed len str so it won't move
  191.         doc.cbSize = LEN(doc)
  192.         doc.lpszDocName = _OFFSET(t1)
  193.         doc.lpszOutput = 0
  194.         doc.lpszDatatype = 0
  195.         doc.fwType = 0
  196.         IF 0 >= StartDocA(pde.hDC, _OFFSET(doc)) THEN PRINT "doc error"
  197.         IF 0 >= StartPage(pde.hDC) THEN PRINT "doc error"
  198.  
  199.         LPRINT "Foo"
  200.         LPRINT "poo"
  201.         LPRINT "snoo"
  202.  
  203.         IF 0 >= EndPage(pde.hDC) THEN PRINT "doc error"
  204.         IF 0 >= EndDoc(pde.hDC) THEN PRINT "doc error"
  205.     END IF
  206.  
  207. PRINT "Printed!!"
  208.  
  209.  
  210. IF pde.hDevMode THEN
  211.     IF 0 <> GlobalFree(pde.hDevMode) THEN PRINT "Error: 0x" + LCASE$(HEX$(GetLastError))
  212. IF pde.hDevNames THEN
  213.     IF 0 <> GlobalFree(pde.hDevNames) THEN PRINT "Error: 0x" + LCASE$(HEX$(GetLastError))
  214. IF pde.hDC THEN
  215.     IF 0 = DeleteDC(pde.hDC) THEN PRINT "Error: 0x" + LCASE$(HEX$(GetLastError))
  216.  

Run this and it'll pop up a print selection window for you, and then print 3 lines to whatever you tell it to print to: "Foo Poo Shoo"  (or something equally nonsensical). 

By itself, this demo really isn't all that impressive, but once you play with it just a bit, you can see why I was interested in resurrecting this old bit of code.  Change from your default printer to "Microsoft Print To PDF" and then Print.  At this point, you'll now be asked for a filename to save to your drive under, and if you enter one, you''ll generate a PDF file PRESTO-MAGICO!!  (Example PDF created from this process and posted below...)

If you look at the code, you'll see that I took out several of the windows library calls and replaced them with the old standard LPRINT which we all know and loved from back in the QBASIC days of the language...

Code: [Select]
        LPRINT "Foo"
        LPRINT "poo"
        LPRINT "snoo"

If you're interested in making PDFs (as was posted about in other topics), this seems like an awfully easy way to make and create them in Windows.  (Won't work for Linux or Mac, but what can I say.. I don't have a Linux or Mac machine for testing/development, so I can't really sort out how to make things like this work on those systems very readily.  Sorry.)

Code has been cleaned up quite a bit and should be easier to follow at this point in time, so people can make it a library and plug it into their own projects if they want.  I wouldn't say it's 100% perfect yet, as there's a lot of options which haven't been incorporated into it such as font changes, alignment, or any such thing, but it basically does what it's supposed to do:  It allows us to access the windows printer selection GUI, choose a printer, and then print stuff to it -- even if what we choose is the "Print To PDF", or "Print To Fax" options....

And that alone, seems like it's enough of a worthwhile accomplishment by itself to make me happy that Richard could help me find and recover this lost bit of code. 

MANY THANKS RICHARD!!
* foo.pdf (Filesize: 123.28 KB, Downloads: 182)
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!