none
Print dialog problem

    Question

  • My program can load a bitmap from the clipboard and send it to the default printer.  But if I use a print dialog to select the printer, it never works.  Here's my code:

        if ( ctrlDwn ) {        // print a bitmap copy to the current printer
            OnBmpbutton();

            if (::OpenClipboard(NULL))
            {
                hBitmap = (HBITMAP)GetClipboardData(CF_BITMAP);

                if (hBitmap)
                {
                    CBitmap* pBmp = CBitmap::FromHandle(hBitmap);
                    BITMAP bm;
                    pBmp->GetBitmap(&bm);
                    int iBmpWidth = bm.bmWidth;
                    int iBmpHeight = bm.bmHeight;
                    bxWidth = bm.bmWidth;
                    bxHeight = bm.bmHeight;

                    CPrintDialog* pDlg = new CPrintDialog(FALSE);

                    //if (pDlg->DoModal() == IDCANCEL) {    // this runs the dialog, but the page is blank!
                    //    return;
                    //}

                    if (pDlg->GetDefaults() == FALSE)        // this fails if you run the dialog above
                    {
                        delete pDlg;
                        return;
                    }

                    HDC prn;
                    prn = pDlg->GetPrinterDC();

                    cxpage = GetDeviceCaps (prn, HORZRES);
                    cypage = GetDeviceCaps (prn, VERTRES);
                    cypage = cxpage*bxHeight/bxWidth;        // keep aspect ratio
                    hdcMem = CreateCompatibleDC(prn);
                    HBITMAP hbmOld = (HBITMAP)SelectObject(hdcMem, hBitmap);

                    StartDoc (prn, &di);
                    StartPage (prn) ;
                    SetMapMode (prn, MM_ISOTROPIC);
                    SetWindowExtEx(prn, cxpage, cypage, NULL);
                    SetViewportExtEx(prn, cxpage, cypage, NULL);

                    SetViewportOrgEx(prn, 0, 0, NULL);
                    StretchBlt(prn, 20, 20, cxpage, cypage, hdcMem, 0, 0, bxWidth, bxHeight, SRCCOPY);
                    EndPage (prn);
                    EndDoc(prn);
                    DeleteDC(prn);
                    SelectObject(hdcMem, hbmOld);
                    DeleteDC(hdcMem);

                    ctrlDwn = false;

                    ::EmptyClipboard();
                    ::CloseClipboard();
                    delete pDlg;
                    return;
                }
            }
        }

    Sunday, December 03, 2017 5:15 PM

All replies

  • Hi,

    Thank you for posting here.

    Did you get other error message or exception?  Did the printer get the correct value?

    For printer dialog, the Microsoft has provided the PrintDlgEx function to display a Print Property Sheet,

    which has a General page containing controls similar to the Print dialog box.

    I suggest that you can try PrintDlg.

    You can direct PrintDlg to create a device context or information context for the printer by setting the PD_RETURNDC or PD_RETURNIC flag in the Flags member of the PRINTDLG structure. The function returns a handle to the device context or information context in the hDC member.

    If you use the PD_RETURNDC flag, you can use the device context to generate output for the printer.

    I think that you could get wrong device context for printer.

    Best Regards,

    Hart

    Edit:

         //if (pDlg->DoModal() == IDCANCEL) {    // this runs the dialog, but the page is blank!
                    //    return;
                    //}
    
                    if (pDlg->GetDefaults() == FALSE)        // this fails if you run the dialog above
                    {
                        delete pDlg;
                        return;
                    }

    As far as I know that the CPrintDialog::GetDefaults retrieves the device defaults of the default printer without displaying a dialog box. 

    I think that this is main reason why this fails if you run the dialog above.  This is self-contradictory with having dialog box. 

    About how to get default device, you can reference the CPrintDialog::GetDefaults demo. 

    If you want to use dialog box to choose printer, you could use the above method PrintDlgEx


    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.


    Monday, December 04, 2017 2:36 AM
    Moderator
  • If I uncomment the pDlg section, the program displays the print dialog as it should.  When I click OK, the dialog closes.  No error message.

    But then GetDefaults() comes back false and it quits.  If I delete that test, prn comes back zero and the printer ejects a blank page.

    Monday, December 04, 2017 1:49 PM
  • Hello,

    as Hart Wang already said, look at the demo of GetDefaults.

    So try this:

    if (!pDlg->GetDefaults()) // use Default printer
    {
      if (pDlg->DoModal() != IDOK) // or select printer
      {
        delete pDlg;
        return;
      }
    }
    

    Regards, Guido


    Monday, December 04, 2017 2:03 PM
  • That's not what I want.  The default works fine, but I want to give the user the option to select a different printer.
    Monday, December 04, 2017 2:55 PM
  • If you have set a default printer in Windows, then GetDefaults will always be true and your programme will use this printer.

    If you want the user select a printer, you don't need to call GetDefaults - you only start the dialog.

    if (pDlg->DoModal() != IDOK) // let the user select the printer
    {
      delete pDlg;
      return;
    }
    

    Regards, Guido

    Tuesday, December 05, 2017 6:55 AM
  • I tried that.  The print dialog closes, and the code goes to

                    HDC prn;
                    prn = pDlg->GetPrinterDC();

                    cxpage = GetDeviceCaps (prn, HORZRES);
                    cypage = GetDeviceCaps (prn, VERTRES);
                    cypage = cxpage*bxHeight/bxWidth;        // keep aspect ratio
                    hdcMem = CreateCompatibleDC(prn);
                    HBITMAP hbmOld = (HBITMAP)SelectObject(hdcMem, hBitmap);

                    StartDoc (prn, &di);
                    StartPage (prn) ;
                    SetMapMode (prn, MM_ISOTROPIC);
                    SetWindowExtEx(prn, cxpage, cypage, NULL);
                    SetViewportExtEx(prn, cxpage, cypage, NULL);

                    SetViewportOrgEx(prn, 0, 0, NULL);
                    StretchBlt(prn, 20, 20, cxpage, cypage, hdcMem, 0, 0, bxWidth, bxHeight, SRCCOPY);
                    EndPage (prn);
                    EndDoc(prn);
                    DeleteDC(prn);
                    SelectObject(hdcMem, hbmOld);
                    DeleteDC(hdcMem);

    prn looks like a valid handle, and the printer ejects a page.  But the page is blank!  Can you figure out why?

    If I don't use the print dialog and just do GetDefaults(), the page has a picture in it.

    Tuesday, December 05, 2017 2:05 PM
  • Hi,

    >>prn looks like a valid handle, and the printer ejects a page.  But the page is blank!  Can you figure out why?   If I don't use the print dialog and just do GetDefaults(), the page has a picture in it.

    According to the description, it seems that the DC is invalid.

    When you have no default printer, you can use the following method to get correct DC that you are given. 

     CDC dc;
     dc.Attach(dlg.m_pd.hDC);

    Could you please provide a reproducing demo for us to test the issue on one drive? 

    Best Regards,

    Hart


    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Wednesday, December 06, 2017 6:18 AM
    Moderator
  • A demo is not simple; this program has about 470,000 lines of code.

    Here's what I have now.  The printer ejects a blank page.

                    CPrintDialog* pDlg = new CPrintDialog(FALSE);

                    if (pDlg->DoModal()  != IDOK ) {    // this runs the dialog, but the page is blank!
                        delete pDlg;
                        return;
                    }

                     CDC prn;
                     prn.Attach(pDlg->m_pd.hDC);

                    cxpage = GetDeviceCaps (prn, HORZRES);
                    cypage = GetDeviceCaps (prn, VERTRES);
                    cypage = cxpage*bxHeight/bxWidth;        // keep aspect ratio
                    hdcMem = CreateCompatibleDC(prn);
                    HBITMAP hbmOld = (HBITMAP)SelectObject(hdcMem, hBitmap);

                    StartDoc (prn, &di);
                    StartPage (prn) ;
                    SetMapMode (prn, MM_ISOTROPIC);
                    SetWindowExtEx(prn, cxpage, cypage, NULL);
                    SetViewportExtEx(prn, cxpage, cypage, NULL);

                    SetViewportOrgEx(prn, 0, 0, NULL);
                    StretchBlt(prn, 20, 20, cxpage, cypage, hdcMem, 0, 0, bxWidth, bxHeight, SRCCOPY);
                    EndPage (prn);
                    EndDoc(prn);
                    DeleteDC(prn);
                    SelectObject(hdcMem, hbmOld);
                    DeleteDC(hdcMem);

    Wednesday, December 06, 2017 1:50 PM
  • I think you are right; the DC is invalid.  So how do I get a valid handle after closing the print dialog?  That seems to be the whole problem.
    Wednesday, December 06, 2017 8:03 PM
  • Hello,

    I have read about problems with the DC if the font is not defined. But you want to print a picture, so I don't know if these links can help you:

    https://www.experts-exchange.com/questions/22493001/CDC-invalid-handle-0xC0000008.html

    https://www.codeproject.com/Articles/14023/Quick-Print

    Regards, Guido

    Thursday, December 07, 2017 7:18 AM
  • This looks promising.  The first link suggests adding some code about a font:

    m_FieldInfoFont.CreateFont

    (FIELD_INFO_SIZE*nMapFactor, 0, 0, 0, FW_BOLD, FALSE, bUnderLineFieldInfo, FALSE, ANSI_CHARSET, OUT_TT_PRECIS, CLIP_TT_ALWAYS, DEFAULT_QUALITY, DEFAULT_PITCH, "Arial");  //"Times New Roman");

    But it doesn't declare m_FieldInfoFont, so I don't know what it is.  Is that a good lead?

    Thursday, December 07, 2017 1:42 PM
  • I think it's a CFont.

    Thursday, December 07, 2017 1:50 PM
  • There are  code samples in MSDN  :

    CPrintDialog Class


    • Edited by Castorix31 Thursday, December 07, 2017 1:54 PM
    Thursday, December 07, 2017 1:53 PM
  • I did what the link says. The page comes out blank.

                     CPrintDialog dlg(FALSE);
                       if (dlg.DoModal() == IDOK)
                       {


                    HDC prn = dlg.GetPrinterDC();
                    ASSERT(prn);

                    cxpage = GetDeviceCaps (prn, HORZRES);
                    cypage = GetDeviceCaps (prn, VERTRES);
                    cypage = cxpage*bxHeight/bxWidth;        // keep aspect ratio
                    hdcMem = CreateCompatibleDC(prn);
                    HBITMAP hbmOld = (HBITMAP)SelectObject(hdcMem, hBitmap);

                    StartDoc (prn, &di);
                    StartPage (prn) ;
                    SetMapMode (prn, MM_ISOTROPIC);
                    SetWindowExtEx(prn, cxpage, cypage, NULL);
                    SetViewportExtEx(prn, cxpage, cypage, NULL);

                    SetViewportOrgEx(prn, 0, 0, NULL);
                    StretchBlt(prn, 20, 20, cxpage, cypage, hdcMem, 0, 0, bxWidth, bxHeight, SRCCOPY);
                    EndPage (prn);
                    EndDoc(prn);
                    DeleteDC(prn);
                    SelectObject(hdcMem, hbmOld);
                    DeleteDC(hdcMem);

    Thursday, December 07, 2017 5:26 PM
  • I don't use MFC, but I have converted your code in C++/Win32 and it should work in MFC.

    I tested with a PDF printer and it works on my PC (hWnd is the main window handle) :

    if (OpenClipboard(NULL))
    {
    	HBITMAP hBitmap = (HBITMAP)GetClipboardData(CF_BITMAP);
    	if (hBitmap)
    	{
    		BITMAP bm;
    		GetObject(hBitmap, sizeof(BITMAP), &bm);
    		int bxWidth = bm.bmWidth;
    		int bxHeight = bm.bmHeight;
    
    		PRINTDLG pdlg = { 0 };
    		pdlg.lStructSize = sizeof(pdlg);
    		pdlg.hwndOwner = hWnd;
    		pdlg.Flags = PD_RETURNDC;
    
    		WCHAR wsBuffer[256];
    		if (PrintDlg(&pdlg) == TRUE)
    		{
    			HDC hPrinterDC = pdlg.hDC;
    			int cxpage = GetDeviceCaps(hPrinterDC, HORZRES);
    			int cypage = GetDeviceCaps(hPrinterDC, VERTRES);
    			cypage = cxpage*bxHeight / bxWidth;        // keep aspect ratio
    			HDC hdcMem = CreateCompatibleDC(hPrinterDC);
    			HBITMAP hbmOld = (HBITMAP)SelectObject(hdcMem, hBitmap);
    
    			DOCINFO di;
    			ZeroMemory(&di, sizeof(di));
    			di.cbSize = sizeof(di);
    			di.lpszDocName = L"Test";
    			StartDoc(hPrinterDC, &di);
    			StartPage(hPrinterDC);
    			SetMapMode(hPrinterDC, MM_ISOTROPIC);
    			SetWindowExtEx(hPrinterDC, cxpage, cypage, NULL);
    			SetViewportExtEx(hPrinterDC, cxpage, cypage, NULL);
    
    			SetViewportOrgEx(hPrinterDC, 0, 0, NULL);
    			StretchBlt(hPrinterDC, 20, 20, cxpage, cypage, hdcMem, 0, 0, bxWidth, bxHeight, SRCCOPY);
    			EndPage(hPrinterDC);
    			EndDoc(hPrinterDC);
    			DeleteDC(hPrinterDC);
    			SelectObject(hdcMem, hbmOld);
    			DeleteDC(hdcMem);
    		}
    		else
    		{
    			// Code
    		}
    	}
    	CloseClipboard();
    }



    • Edited by Castorix31 Thursday, December 07, 2017 6:12 PM
    Thursday, December 07, 2017 6:08 PM
  • Good suggestion -- but it still makes a blank page.

    The only thing I left out was

    //        pdlg.hwndOwner = hWnd;

    because hWnd is undefined.  Does that matter?

    Thursday, December 07, 2017 7:13 PM
  • Good suggestion -- but it still makes a blank page.

    The only thing I left out was

    //        pdlg.hwndOwner = hWnd;

    because hWnd is undefined.  Does that matter?

    On any printer ?

    Even if you print a text on the printer DC with TextOut() ? (StretchBlt() can fail on some printers)

    Thursday, December 07, 2017 7:48 PM
  • The weird thing is the printer shows the bitmap just fine if I don't use the print dialog but just

                    HDC prn;
                    prn = pDlg->GetPrinterDC();

    to use the current default printer.  It's only when I use the dialog (and select the same printer) it screws up.  So StretchBlt() in fact works.

    Thursday, December 07, 2017 8:42 PM
  • Or even with minimal code, it prints nothing ? :

    PRINTDLG pdlg = { 0 };
    pdlg.lStructSize = sizeof(pdlg);
    pdlg.Flags = PD_RETURNDC;
    if (PrintDlg(&pdlg) == TRUE)
    {
    	HDC hPrinterDC = pdlg.hDC;
    	DOCINFO di;
    	ZeroMemory(&di, sizeof(di));
    	di.cbSize = sizeof(di);
    	di.lpszDocName = L"Test";
    	StartDoc(hPrinterDC, &di);
    	StartPage(hPrinterDC);
    	WCHAR wsText[255] = L"TEST";
    	TextOut(hPrinterDC, 100, 100, wsText, lstrlen(wsText));
    	EndPage(hPrinterDC);
    	EndDoc(hPrinterDC);
    }

    Thursday, December 07, 2017 9:26 PM
  • I get compiler errors:

    di.lpszDocName = L"Test";

    a value of type "const wchar_t" cannot be assigned to an entity of type 'LPCSTR"

    TextOut(hPrinterDC, 100, 100, wsText, lstrlen(wsText));

    argument of type "WCHAR" is incompatible with parameter of type "LPCSTR"

    Friday, December 08, 2017 1:09 PM
  • I always use Unicode...

    Just use ANSI strings if you don't use Unicode
    • Edited by Castorix31 Friday, December 08, 2017 1:12 PM
    Friday, December 08, 2017 1:12 PM
  • Don't know anything about Unicode, sorry.

    If I do this:

    PRINTDLG pdlg = { 0 };
    pdlg.lStructSize = sizeof(pdlg);
    pdlg.Flags = PD_RETURNDC;
    if (PrintDlg(&pdlg) == TRUE)
    {
        HDC hPrinterDC = pdlg.hDC;
        DOCINFO di;
        ZeroMemory(&di, sizeof(di));
        di.cbSize = sizeof(di);
    //    di.lpszDocName = L"Test";
        StartDoc(hPrinterDC, &di);
        StartPage(hPrinterDC);
        WCHAR wsText[255] = L"TEST";
        TextOut(hPrinterDC, 100, 100, "TEST", lstrlen("TEST"));
        EndPage(hPrinterDC);
        EndDoc(hPrinterDC);

        return;
    }

    The printer just sits there.  No page.

    Friday, December 08, 2017 1:13 PM
  • Even with

    Microsoft Print to PDF

    or

    Microsoft XPS Document Writer

    printers ?

    (everything works on my PC (Windows 10))

    Friday, December 08, 2017 1:43 PM