2

Objective: Print text to AdobePDF from multiple sources in Access using WinAPI GDI Print functions. Specifically,

  • Get user printer preferences using PrintDlgEx
    • Use either of these below to call StartDoc
      • PRINTDLGEX.hDC OR
      • hDC = CreateDC(), using the DEVMODE outputted from the PrintDlgEx

Problem: StartDoc always returns -1 for hDCs (for Adobe PDF) created using a DEVMODE and returns > 0 for all other printers chosen. Is the DEVMODE different size or format for Adobe PDF?

Info: Here's what I've tried and the results thus far:

  • NEW INFO 8/22/14 Works for PDF when Adobe PDF is not my default printer. Works for other printers, regardless of default setting. Why would it only fail when Adobe PDF is default but not fail for other printers?
  • MORE NEW INFO 8/22/14 When Adobe PDF is default, if users clicks another printer and then back on Adobe PDF in the PrintDlgEx, it works. WTF?!? This is getting ridiculous.
  • Identical code works for other printers.
  • IsValidDevMode = True.
  • Tried multiple different versions of the DEVMODE type, all of which seem to work for other printers, but not Adobe PDF.
  • When StartDoc does return -1, Err.LastDllError returns 0.
  • When using CreateDC with type DEVMODE for last parameter, code works for all printers except Adobe PDF.
  • Declaring CreateDC with type Long for the DEVMODE parameter and passing 0 works. But this doesn't incorporate the user's options. The printer defaults are always used.
  • Using the CreateDC above and then ResetDC using the DEVMODE from PrintDlgEx causes same problem.
  • Setting Application.Printer settings manually, instead of all of this. Doesn't work.
  • Using different DOCINFO parameters when Adobe PDF is chosen.

Code:

Public Function printRawData(objRTB As Object, Optional strFilename As String = "cBasePrint") As Boolean
  Dim hDCPrinter As Long, sDeviceName As String, lJob As Long
  Dim udtDevMode As DEVMODE, udtDocInfo As DOCINFO

  If printPrintDialog(udtDevMode, hDCPrinter) Then
    Debug.Print hDCPrinter, IsValidDevMode(udtDevMode, LenB(udtDevMode)), udtDevMode.dmOrientation, udtDevMode.dmDeviceName

    If hDCPrinter <> 0 Then
        udtDocInfo.pDocName = strFilename
        udtDocInfo.pOutputFile = vbNullString
        udtDocInfo.pDatatype = "RAW"
        udtDocInfo.fType = 0
        udtDocInfo.sSize = LenB(udtDocInfo)

        lJob = StartDoc(hDCPrinter, udtDocInfo)
        Debug.Print lJob, Err.LastDllError

        If lJob > 0 Then
            objRTB.SelPrint hDCPrinter, 0
            EndDoc (hDCPrinter)
        End If

        DeleteDC (hDCPrinter)
    End If
  End If
End Function

Related Questions:
Raw Printing Set DevMode options (Orientation, copies, margins, default source, etc.)
How to show printer properties/preferences dialog and save changes?

References:
Lessan Vaezi: Printer Settings Nearly identical code to mine.
MS KB: Saving DEVMODE Properties Don't want to do this. My PrintDlgEx call works and returns a valid DEVMODE for other printers.
CodeGuru: Printing-using-Win32-Printer Identical issue from what I can tell. No answer.
Adobe PDF Community Most of the way down the thread, people are having the same issues.

Community
  • 1
  • 1
usncahill
  • 469
  • 6
  • 16
  • 1
    Get the same issue with another PDF driver. Did you solve your problem? – MiniScalope Aug 03 '17 at 15:48
  • 1
    @MiniScalope I have a deleted answer below but I'm not sure it works. The DEVMODE struct is missing private data that makes Adobe PDF driver work, which is only populated when the user selects Adobe PDF as a printer manually. My deleted answer attempts to retrieve this private data, but I am unsure if it works, and frankly I think it's BS that it is necessary when doing it the way describe above works for all other printer drivers I've tried. Adobe just needs to be special >:( – usncahill Aug 25 '17 at 16:24

1 Answers1

0

Hope it's not too late. But I found a solution by studying some sample MFC projects created by MS

        // Determine name of Adobe PDF Printer if installed.
        CString AdobePrinterName = L"";
        DWORD cbNeeded, cReturned;
        EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 2, NULL, 0, &cbNeeded, &cReturned);
        PRINTER_INFO_2* pPrinterInfo = (PRINTER_INFO_2*)malloc(cbNeeded);
        EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 2, (LPBYTE)pPrinterInfo, cbNeeded, &cbNeeded, &cReturned);
        for (int i = 0; i < cReturned; i++) {
            if (wcscmp(pPrinterInfo[i].pDriverName, L"Adobe PDF Converter") == 0) {
                // Adobe PDF printer is found
                AdobePrinterName = pPrinterInfo[i].pPrinterName;
                break;
            }
        }

        int started = 0;
        // start the print document
        if (po->printerName.CompareNoCase(AdobePrinterName) == 0) {

            // This is a work around for printing to Adobe PDF printer.
            DOCINFO docInfo;
            memset(&docInfo, 0, sizeof(DOCINFO));
            docInfo.cbSize = sizeof(DOCINFO);
            docInfo.lpszDocName = L"_untitle"; // <-- Adobe PDF printer needed this to work properly
            started = dc.StartDoc(&docInfo);
        }
        else {
            started = StartDoc(&dc, po);
        }

        if (!started)
        {
            DWORD error = GetLastError();
            goto fail;
        }
Daniel
  • 11
  • 3
  • I'll review and see if it works for my use case. Need to convert to VBA. Might be a bit before I can say this is the answer. – usncahill Feb 17 '23 at 22:46