none
Drucken Querformat RRS feed

  • Frage

  • folgender Quelltext (erklärung darunter):

    bool CPrnBasePrinter::SetupPrinter(HWND hParent, bool bDefault, bool bForceOrientationLandscape)
    {
    	PRINTDLG dlgSelPrinter;
    	memset(&dlgSelPrinter, 0, sizeof(dlgSelPrinter));
    
    	dlgSelPrinter.lStructSize = sizeof(dlgSelPrinter);
    	dlgSelPrinter.hwndOwner  = hParent;
    	dlgSelPrinter.Flags    = PD_ALLPAGES | PD_NOSELECTION | PD_RETURNDC ;
    	dlgSelPrinter.hDevNames  = NULL;
    	dlgSelPrinter.hDevMode  = NULL;
    
    	if (bDefault)
    	{
    		dlgSelPrinter.Flags |= PD_RETURNDEFAULT;
    	}
    
    	if (bForceOrientationLandscape){
    		dlgSelPrinter.hDevMode = GlobalAlloc(GHND,sizeof(DEVMODE));
    		DEVMODE* pDevMode = (DEVMODE*)::GlobalLock(dlgSelPrinter.hDevMode);
    		ASSERT(pDevMode != NULL, _T("Devmode des Druckers nicht ermittelbar => Querformat kann nicht eingestellt werden"));
    		if(pDevMode != NULL){
    			pDevMode->dmSize=sizeof(DEVMODE);
    			pDevMode->dmFields |= DM_ORIENTATION;
    			pDevMode->dmOrientation = DMORIENT_LANDSCAPE;
    			::GlobalUnlock(dlgSelPrinter.hDevMode);
    		}
    	}
    
    	BOOL bRet = PrintDlg(&dlgSelPrinter); //Druckerauswahl-Dialog
    	GlobalFree(dlgSelPrinter.hDevMode);
    	if (bRet == FALSE && CommDlgExtendedError()) return false;
    	if (bRet == FALSE && !CommDlgExtendedError()) return true;
    
    	m_hPrintDC = dlgSelPrinter.hDC;
    
    	return (m_hPrintDC != NULL);
    }
    
    

    zweck der methode ist es, einen Context auf einen Drucker zu besorgen (in m_hPrintDC)

    die beiden flags:

    - bDefault: Wenn true soll der Druckerauswahldialog nicht erscheinen, sondern gleich der Context auf den in windows eingestellten standardrucker (mit dessen einstellungen) erstellt werden

    - bForceOrientationLandscape: wenn true soll bei der druckerauswahl die orientierung des druckers per default auf "querformat" stehen

     

    die flagkombinationen

    - false/false (druckerauswahl, keine vorauswahl für orientierung)

    - true/false (drucke auf standarddrucker, mit dessen standardausrichtung)

    - false/true (druckerauswahl, selektiere "querformat" vor)

    funktionieren auch tadellos. lediglich die kombination true/true (keine druckerauswahl, querformat drucken) funktioniert nicht

    was passieren soll ist, einen context auf den standarddrucker zu besorgen, aber dessen einstellung für die orientierung ist auf "quer" zu setzen

    CommDlgExtendedError liefert mir in diesem fall PDERR_RETDEFFAILURE

     frage ist also: wie bekomme ich ein handle auf den standarddrucker, aber unabhängig von dessen einstellung mit der ausrichtung "quer"

     

    micha

     

    Donnerstag, 16. Dezember 2010 15:19

Antworten

  • Folgender Code ist simpel unkompliziert und funktioniert:

        PRINTDLG pd;
        if(AfxGetApp()->GetPrinterDeviceDefaults(&pd))
        {
     // protect memory handle with ::GlobalLock and ::GlobalUnlock
     DEVMODE FAR *pDevMode = (DEVMODE FAR *)::GlobalLock(pd.hDevMode);
     // set orientation to landscape
     pDevMode->dmFields|=DM_ORIENTATION;
     pDevMode->dmOrientation = DMORIENT_LANDSCAPE;
     ::GlobalUnlock(pd.hDevMode);
        }
        else
        {
     // Get DC
     CPrintDialog dlg(FALSE);
     if (dlg.GetDefaults())
     {
         CDC dc;
         dc.Attach(dlg.m_pd.hDC);
             AfxMessageBox(_T("Print"));
     }
        }
    

    Martin Richter -- MVP for VC++ [Germany] -- http://blog.m-ri.de
    Freitag, 17. Dezember 2010 16:26
    Moderator
  • 1. Sehe ich darin kein Problem, denn für mich zählt eigentlich immer was der Benutzer einstellt.
    Wenn ich in meinem Programm was einstelle, dann will ich nicht, dass externe Einstellungen das verbiegen.
    Warum sollte mein Programm, dass eben noch richtig gedruckt hat, anders drucken, nur weil man was an den Druckereinstellungen extern verbogen hat?
    2. Ist Dein Szenario wohl auch eher selten. ;)
    3. Kannst Du mit UpdatePrinterSelection(TRUE); die Grundeinstellungen wieder laden.


    Martin Richter -- MVP for VC++ [Germany] -- http://blog.m-ri.de
    Sonntag, 19. Dezember 2010 19:34
    Moderator
  • hilft tatsächlich und tut, was ich gern möchte - danke. ist zwar in CWinApp protected, aber mit überschreiben in meiner eigenen App klappt das.

    Es geht auch mit dem Aufruf:

    AfxGetApp()->SelectPrinter(NULL,NULL,TRUE);

    Damit vergisst die MFC alle alten Einstellungen was den Drucker betrifft..


    Martin Richter -- MVP for VC++ [Germany] -- http://blog.m-ri.de
    Montag, 20. Dezember 2010 11:30
    Moderator

Alle Antworten

  • Meiner Ansicht nach ist Dein Umgang mit hDevMode falsch.
    Die MFC benutzt einen internen Satz dieses Handles für den Druck Dialog.
    Die Handles dürfen nicht freigegeben werden.

    Speziell dafür hat CWinApp die Methode GetPrinterDeviceDefaults
    http://msdn.microsoft.com/en-us/library/t5799e1d(VS.80).aspx

    Und netterweise behandelt der Beispielcode direkt die Umstellung auf Landscape. ;)

    IMHO solltest Du mit dieser Funktion perfekt klar kommen.


    Martin Richter -- MVP for VC++ [Germany] -- http://blog.m-ri.de
    Donnerstag, 16. Dezember 2010 20:05
    Moderator
  • > IMHO solltest Du mit dieser Funktion perfekt klar kommen

    komme ich leider nicht ;-(

    problem ist der dort abgebildete quelltext. was ist m_hDevMode und wo wird der wie gesetzt?

    wie auch immer, wenn ich das zum laufen bringe (m_hDevMode als Klassenmember und auf den ermittelten hDevMode der PRINTDLG-Struktur setzen), befüllt mir GetPrinterDeviceDefaults zwar die PRINTDLG-Struktur, aber der member hDC darin wird nicht gesetzt.

    mit der so befülltem struktur kann ich aber auch nicht PrintDlg aufrufen. Entweder, es erscheint ganz normal der Druckerauswahldialog, oder, wenn ich in den Flags PD_RETURNDEFAULT mit setze, wieder der Fehler PDERR_RETDEFFAILURE (was zumindest mal der Dokumentation entspricht, die besagt, daß beim gesetzten Flag der hDevMode auf NULL stehen muß)

    nur leider hilft mir das so nicht weiter ;-(

    Freitag, 17. Dezember 2010 10:11
  • Hallo,

     

    m_hDevMode gehört zu CWinApp und in deiner davon abgeleiteten Application Klasse solltest Du demnach die Ausrichtung durchführen.

     

    Gruß


    - Florian
    Freitag, 17. Dezember 2010 14:01
  • FAST:

    also, auf den standarddrucker, aber quer drucken, geht so:

     

    if (bDefault){
    	//Default-Drucker nehmen, nicht beim Benutzer nachfragen
    	CWinApp* pTheApp = AfxGetApp();
    	ASSERT(pTheApp != NULL, _T("App nicht ermittelbar => Standarddrucker auch nicht"));
    	if (pTheApp != NULL){
    		CPrintDialog printDlgG(FALSE);
    		BOOL bGetDefaults = pTheApp->GetPrinterDeviceDefaults(&printDlgG.m_pd);
    		ASSERT(bGetDefaults == TRUE, _T("Defaultdrucker nicht ermittelbar"));
    		if (bGetDefaults == TRUE){
    			if (bForceOrientationLandscape){
    				//Umschalten auf Querformat
    				LPDEVMODE dev = printDlgG.GetDevMode();
    				dev->dmOrientation=DMORIENT_LANDSCAPE;
    				GlobalUnlock(dev); //GetDevMode macht GlobalLock => hier wieder entlocken
    			}
    		}
    		m_hPrintDC = printDlgG.CreatePrinterDC();
    	}
    }
    
    
    

     

    einziger haken im moment: wenn ich bei nächsten aufruf der funktion bForceOrientationLandscape nicht setze, also keine Orientierung explizit angebe, wird nicht auf die im default-drucker eingestellte gedruckt, sondern wieder im querformat.

    soweit noch nicht schlimm, dachte ich mir eben. ich merke mir vor dem ersten umsetzen den initialzustand und setze den dann wieder explizit im nicht-landscape-fall.

    also so:

     

    if (bGetDefaults == TRUE){
    	LPDEVMODE dev = printDlgG.GetDevMode();
    	if (bForceOrientationLandscape){
    		//Umschalten auf Querformat
    		//Ausrichtung merken, für evt. Zurücksetzen beim nächsten Druck
    		ORIGINAL_PRINTER_ORIENTATION = dev->dmOrientation;
    		dev->dmOrientation=DMORIENT_LANDSCAPE;
    	}
    	else{
    		if (ORIGINAL_PRINTER_ORIENTATION != Constants::FIELD_NOT_SET){
    			//Wenn nicht Querformat gewünscht ist, aber schonmal am Format gespielt wurde,
    			//das originale Format (das u. U. auch Quer sein könnte, wer weiß), wiederherstellen.
    			//wird das nicht getan, wird weiterhin auf Quer gedruckt, nachdem das einmal eingestellt wurde
    			dev->dmOrientation=ORIGINAL_PRINTER_ORIENTATION;
    		}
    	}
    	GlobalUnlock(dev); //GetDevMode macht GlobalLock => hier wieder entlocken
    }
    
    

     

    funktioniert auch, aber was ich abei natürlich ausgehebelt habe, ist, die default-drucker-einstellungen in windows während der laufzeit meines programms zu ändert.

    ich vermute mal, daß CWinApp::GetPrinterDeviceDefaults beim 2. Aufruf wieder meine geänderten Einstellungen zurückgibt, statt nochmal alles vom windows-drucker einzusammeln. noch jemand eine idee, wie ich das ändern könnte?

    Freitag, 17. Dezember 2010 14:03
  • Folgender Code ist simpel unkompliziert und funktioniert:

        PRINTDLG pd;
        if(AfxGetApp()->GetPrinterDeviceDefaults(&pd))
        {
     // protect memory handle with ::GlobalLock and ::GlobalUnlock
     DEVMODE FAR *pDevMode = (DEVMODE FAR *)::GlobalLock(pd.hDevMode);
     // set orientation to landscape
     pDevMode->dmFields|=DM_ORIENTATION;
     pDevMode->dmOrientation = DMORIENT_LANDSCAPE;
     ::GlobalUnlock(pd.hDevMode);
        }
        else
        {
     // Get DC
     CPrintDialog dlg(FALSE);
     if (dlg.GetDefaults())
     {
         CDC dc;
         dc.Attach(dlg.m_pd.hDC);
             AfxMessageBox(_T("Print"));
     }
        }
    

    Martin Richter -- MVP for VC++ [Germany] -- http://blog.m-ri.de
    Freitag, 17. Dezember 2010 16:26
    Moderator
  • einziger haken im moment: wenn ich bei nächsten aufruf der funktion DMORIENT_LANDSCAPE nicht setze (also nicht explizit im querformat drucken möchte, sondern in dem format, das im windows-stadard-drucker eingestellt ist), wird nicht auf die im default-drucker eingestellte orientierung gedruckt, sondern wieder im querformat.
    Samstag, 18. Dezember 2010 18:46
  • Was exakt dem entspricht wie alle Programme funktionieren.
    Deshalb gibt es ja den zentralen hDevMode.
    Was der User einstellt, das bleibt! Sie andere Software...

    Und wenn Du das nicht willst, dann kannst Du nach Deiner Operation die Orientierung zurückstellen.


    Martin Richter -- MVP for VC++ [Germany] -- http://blog.m-ri.de
    Sonntag, 19. Dezember 2010 09:29
    Moderator
  • ja klar kann ich das nach der operation wieder zurückstellen, was ich auch tue.

    problem ist dann aber: es wird beim nächsten mal auf das zurückgestellte format gedruckt.

    wenn nun in der zwischenzeit die einstellungen des windows-standardruckers geändert werden, dann kommen diese änderungen aber nicht bei mir im programm "an".

    mit anderen worten für den benutzer stellt es sich so dar:

    - solange nicht die funktion benutzt wird, die explizit quer druckt, druckt das programm immer so, wie es im windows-standarddrucker eingestellt ist (auch, wenn diese einstellung zur laufzeit des programms geändert wird)

    - sobald die drucke-quer-funktion zum ersten mal benutzt wurde, druckt die drucke-auf-default-funktion immer auf das format, auf dem der windows-drucker stand, als zum ersten mal quer gedruckt wurde, egal, was zwischenzeitlich in windows eingestellt wird.

     

    Sonntag, 19. Dezember 2010 16:25
  • 1. Sehe ich darin kein Problem, denn für mich zählt eigentlich immer was der Benutzer einstellt.
    Wenn ich in meinem Programm was einstelle, dann will ich nicht, dass externe Einstellungen das verbiegen.
    Warum sollte mein Programm, dass eben noch richtig gedruckt hat, anders drucken, nur weil man was an den Druckereinstellungen extern verbogen hat?
    2. Ist Dein Szenario wohl auch eher selten. ;)
    3. Kannst Du mit UpdatePrinterSelection(TRUE); die Grundeinstellungen wieder laden.


    Martin Richter -- MVP for VC++ [Germany] -- http://blog.m-ri.de
    Sonntag, 19. Dezember 2010 19:34
    Moderator
  • > Warum sollte mein Programm, [dass eben noch richtig gedruckt hat] anders drucken, nur weil man was an den Druckereinstellungen extern verbogen hat?

    weil mein programm 2 verschiedene funktionen hat:

    1. drucke auf den windows-standarddrucker mit der dort eingestellten ausrichtung.

    2. drucke auf den windows-standarddrucker im querformat, unabhängig von der im drucker eingestellten ausrichtung

    1. und 2. dürfen natürlich beliebig oft in beliebieger reihenfolge aufgerufen werden

     

    > 2.

    stimmt. werd ich dem kunden so ausrichten ;-)

     

    > 3.

    hilft tatsächlich und tut, was ich gern möchte - danke.

    ist zwar in CWinApp protected, aber mit überschreiben in meiner eigenen App klappt das.

     

    gruß

    micha

     

    Montag, 20. Dezember 2010 10:43
  • hilft tatsächlich und tut, was ich gern möchte - danke. ist zwar in CWinApp protected, aber mit überschreiben in meiner eigenen App klappt das.

    Es geht auch mit dem Aufruf:

    AfxGetApp()->SelectPrinter(NULL,NULL,TRUE);

    Damit vergisst die MFC alle alten Einstellungen was den Drucker betrifft..


    Martin Richter -- MVP for VC++ [Germany] -- http://blog.m-ri.de
    Montag, 20. Dezember 2010 11:30
    Moderator
  • > AfxGetApp()->SelectPrinter(NULL,NULL,TRUE);

    Das ist natürlich noch besser, ja. funktioniert ebenfalls. danke

    Montag, 20. Dezember 2010 11:55