[Webinar] Streamline your web hosting managementRegister Today

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1139
  • Last Modified:

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?
0
ble
Asked:
ble
  • 8
  • 8
1 Solution
 
nietodCommented:
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.)
0
 
bleAuthor Commented:
Yes, but how do I free the memory? I have tried GlobalFree, but that does not help (or I freed the wrong stuff?)
0
 
nietodCommented:
You should use GlobalFree().   Can you post the code?  The memory must not be locked when you call GlobalFree().
0
The new generation of project management tools

With monday.com’s project management tool, you can see what everyone on your team is working in a single glance. Its intuitive dashboards are customizable, so you can create systems that work for you.

 
bleAuthor Commented:
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);
0
 
nietodCommented:
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.)
0
 
bleAuthor Commented:
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); */
0
 
nietodCommented:
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.
0
 
bleAuthor Commented:
Sorry nietod, but I hope someone else can help me. Thansk for helping so far.
0
 
nietodCommented:
Did you confrm that the handles were not initialized before GetPrinterDeviceDefaults()?
0
 
bleAuthor Commented:
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.
0
 
nietodCommented:
I meant did the CPrintDialog object initialize the handles.   Thus when you do GetPrinterDeviceDefaults() you may be loosing the initialized handles.  
0
 
bleAuthor Commented:
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?
0
 
bleAuthor Commented:
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.
0
 
nietodCommented:
>> 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.  
0
 
bleAuthor Commented:
No, GetPrinter.. isn't used anymore.
0
 
nietodCommented:
I see.  That is more like the way it is done in non-MFC.
0
 
StuTheDogCommented:
I've run into the same problem in a CPrintDialog subclass, what I ended up doing is saving the original devmode handles, allocating and manipulating my own (my app prints to non-default devices), then free the structures.  However you have to release the lock count before you can free (this code is in the destructor):

if( hDevMode )
{
  while( ::GlobalUnlock( hDevMode ) );
  ::GlobalFree( shDevMode );
}
if( hDevNames )
{
  while( ::GlobalUnlock( hDevNames ) );
  ::GlobalFree( hDevNames );
}
0

Featured Post

The new generation of project management tools

With monday.com’s project management tool, you can see what everyone on your team is working in a single glance. Its intuitive dashboards are customizable, so you can create systems that work for you.

  • 8
  • 8
Tackle projects and never again get stuck behind a technical roadblock.
Join Now