Link to home
Start Free TrialLog in
Avatar of ble
ble

asked on

CPrintDialog and landscape gives problem

In VC++ 5.0 I use the following code in order to set the printer in landscape mode:

  CPrintDialog PrintDialog(FALSE);
 
  //set landscape mode
  AfxGetApp()->GetPrinterDeviceDefaults(&PrintDialog.m_pd);
  DEVMODE  FAR *lpDevMode  = (DEVMODE  FAR *)       ::GlobalLock(PrintDialog.m_pd.hDevMode);
  lpDevMode->dmOrientation = DMORIENT_LANDSCAPE;
  ::GlobalUnlock(PrintDialog.m_pd.hDevMode);

  if (PrintDialog.DoModal() == IDCANCEL)
    return;

After this I do the printing, and everything seems to work fine until I close the application. Then a debug assertion error in winutil.cpp (procedure AfxGlobalFree) occurs.
By commenting out parts I found that the problem lies in the GetPrinterDeviceDefaults. If this is not used there is no problem. I suppose something must be freed, cleared or something like that. Who can help me?
Avatar of nietod
nietod

If you set the hDevMode and/or hDevName members of the PRINTDLG structure to NULL, then the OS will allocate memory for these structures using GlobalAlloc() and return the handles to the memory in the hDevMode and/or hDevName members.  It is your responsability to free this memory when it is no monger needed  (When done setting up printing.)
Avatar of ble

ASKER

Yes, but how do I free the memory? I have tried GlobalFree, but that does not help (or I freed the wrong stuff?)
You should use GlobalFree().   Can you post the code?  The memory must not be locked when you call GlobalFree().
Avatar of ble

ASKER

Here is the code:

  CPrintDialog PrintDialog(FALSE);
 
  //set landscape mode
  AfxGetApp()->GetPrinterDeviceDefaults(&PrintDialog.m_pd);
  DEVMODE  FAR *lpDevMode  = (DEVMODE  FAR *)   ::GlobalLock(PrintDialog.m_pd.hDevMode);
  lpDevMode->dmOrientation = DMORIENT_LANDSCAPE;
  ::GlobalUnlock(PrintDialog.m_pd.hDevMode);

  if (PrintDialog.DoModal() == IDCANCEL)
    return;

  CDC DC;
  DC.Attach(PrintDialog.GetPrinterDC());

  //set the document info
  DOCINFO di;
  CString strTitle;
  memset (&di,0,sizeof(DOCINFO));
  strTitle.LoadString (AFX_IDS_APP_TITLE);
  di.cbSize = sizeof(DOCINFO);
  di.lpszDocName = strTitle;
  strTitle.Empty();

  //start the actual printing
  DC.StartDoc (&di);
  DC.StartPage ();

  DC.TextOut (Xoff,0, _T(PatInfo));
<etc>

  DC.EndPage();
  DC.EndDoc();

  //cleanup
  DC.Detach();
  DC.DeleteDC();
  GlobalFree(PrintDialog.m_pd.hDevMode);
  GlobalFree(PrintDialog.m_pd.hDevNames);
I don't see a problem with the two GlobalFree()s.  What do they return?  (Should return NULL).

Are you setting the document name correctly?  I don't think so.  It looks like you convert strTitle to a LPCTSTR when you do

 di.lpszDocName = strTitle;

That pointer may be invalidated the next time the CString is changed. The next line empties the CString, which may invlidate the pointer (although since it was already empty, it might not in this case, but it still isn't a good practice.)
Avatar of ble

ASKER

The GlobalFree's return NULL.

The problem can not be in the document name (but you are right, something is wrong there). Everything works fine if I don't set the printer in landscape mode. If I comment out the following lines there is no problem.

/* //set landscape mode
                         AfxGetApp()->GetPrinterDeviceDefaults(&PrintDialog.m_pd);
DEVMODE  FAR *lpDevMode  = (DEVMODE  FAR *)     ::GlobalLock(PrintDialog.m_pd.hDevMode);
lpDevMode->dmOrientation = DMORIENT_LANDSCAPE;
::GlobalUnlock(PrintDialog.m_pd.hDevMode); */
This is beyond my knowledge of MFC, but what _might_ be happening is that those two handles are initialized by the CPrintDialog.  Then you overwrite the handles when you call GetPrinterDeviceDefaults().  So the handles are lost and the memory associated with them can never be deleted.  You may be able to verify this by looking at the CPrintDialog constructor.   If this is the case, then you need to GlobalFree() the handles before getting the printer defaults.
Avatar of ble

ASKER

Sorry nietod, but I hope someone else can help me. Thansk for helping so far.
Did you confrm that the handles were not initialized before GetPrinterDeviceDefaults()?
Avatar of ble

ASKER

How should the handles be initialized? Must there be someting done between

  CPrintDialog PrintDialog(FALSE);
                     
and
                       AfxGetApp()->GetPrinterDeviceDefaults(&PrintDialog.m_pd);

?

B.T.W. If I press Cancel in the Dialog, no problem occurs, only if I press OK.
I meant did the CPrintDialog object initialize the handles.   Thus when you do GetPrinterDeviceDefaults() you may be loosing the initialized handles.  
Avatar of ble

ASKER

I don't know if CPrintDialog initializes the handles. How can one tell?

What should then be done to print in landscape mode if I can not call GetPrinterDeviceDefaults?
Avatar of ble

ASKER

I found the following code elsewhere:

  PrintDialog.m_pd.hDevMode = ::GlobalAlloc( GHND, sizeof(DEVMODE) );
  DEVMODE * devMode = (DEVMODE *) ::GlobalLock(     PrintDialog.m_pd.hDevMode );
  devMode->dmSize = sizeof(DEVMODE);
  devMode->dmOrientation = DMORIENT_LANDSCAPE;
  devMode->dmFields = DM_ORIENTATION;
  ::GlobalUnlock( devMode );  

This works fine.
>> I don't know if CPrintDialog initializes the
>> handles. How can one tell?
If the handles are NULL, they are not initialized.  If they are not NULL, they probably are initialized.  In that case, just step throught the constructor to make sure that it really is initializing them.

>> found the following code elsewhere:
That code allocates the memory rather than making GetPrinterDevicedefaults() do it.  Where is that code being placed in relation to GetPrinter...()?  Before it, I assume.  
Avatar of ble

ASKER

No, GetPrinter.. isn't used anymore.
I see.  That is more like the way it is done in non-MFC.
ASKER CERTIFIED SOLUTION
Avatar of StuTheDog
StuTheDog

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial