Link to home
Start Free TrialLog in
Avatar of DickStone
DickStone

asked on

How to detect (or better prevent) print drivers making multiple copies in MS MFC (C++)

My MS C++ 2010 MFC application has the ability to print multiple copies. I tried to tell the MFC that I'll take care of multiple copies, but the print driver prints them anyway.  So, when the user asks for 3, he gets 3 from me times 3 from the print driver, or 9.

In OnPreparePrinting, I put in before the call to DoPreparePrinting, the following:
      pInfo->m_pPD->m_pd.Flags &= ~PD_USEDEVMODECOPIESANDCOLLATE;      // clear flag in order to show I'll handle
      pInfo->m_pPD->m_pd.Flags |= PD_COLLATE;  // collate defaults on
      pInfo->m_pPD->m_pd.Flags |= PD_RETURNDC;  // need DC

In OnBeginPrinting, nCopies shows 3, and dmCopies shows 1. So I think I'm supposed to print 3, but the print driver is also handling, so I'm getting the 9 as described above.

1. Is there a way to prevent the driver from printing multiple copies in addition to mine?

2. Is there a way to figure out that the driver is doing the 3 copies, so that I stop my software only makes multiple copies when I find out that print driver can't handle multiple copies?
Avatar of sarabande
sarabande
Flag of Luxembourg image

In OnBeginPrinting, nCopies shows 3, and dmCopies shows 1. So I think I'm supposed to print 3,
it is some time ago that i used mfc print support myself, but i don't think that the assertment is right.

the nCopies is an output of the driver indicating that it would print 3 copies. the dmCopies member would be an input which could overrule the number of copies to be printed if you set the PD_USEDEVMODECOPIESANDCOLLATE bit.

Is there a way to prevent the driver from printing multiple copies in addition to mine?
since you provided to print multiple copies yourself anyhow why you do you additionally use the printer's capability of the same functionality? i would do the one or the other but not both.

Sara
Avatar of DickStone
DickStone

ASKER

I don't set the PD_USEDEVMODECOPIESANDCOLLATE bit, I clear it. This is supposed to tell the driver that I'll be handling the multiple copies myself. This way, my program would work even if the driver can't do multiple copies itself.

Also, my understanding is that dmcopies is an output rather than an input. It is supposed to be the number of copies the driver is making (1 if  PD_USEDEVMODECOPIESANDCOLLATE is set, and number of copies if not set).

In answer to the last question, I don't want to use the printer's capabilities. That's the issue and why I set  PD_USEDEVMODECOPIESANDCOLLATE to 0. However, if I can't stop the printer's capabilities, then I'd at least like to know when it's kicking in and I don't know how to find that.
my understanding is that dmcopies is an output rather than an input.

you may read the docs at https://msdn.microsoft.com/en-us/library/windows/desktop/ms646844(v=vs.85).aspx.

it says:

....
A set of bit flags that you can use to initialize the Print property sheet. When the PrintDlgEx function returns, it sets these flags to indicate the user's input. This member can be one or more of the following values.

To ensure that PrintDlg or PrintDlgEx returns the correct values in the dmCopies and dmCollate members of the DEVMODE structure, set PD_RETURNDC = TRUE and PD_USEDEVMODECOPIESANDCOLLATE = TRUE. In so doing, the nCopies member of the PRINTDLG structure is always 1 and PD_COLLATE is always FALSE.

To ensure that PrintDlg or PrintDlgEx returns the correct values in nCopies and PD_COLLATE, set PD_RETURNDC = TRUE and PD_USEDEVMODECOPIESANDCOLLATE = FALSE. In so doing, dmCopies is always 1 and dmCollate is always FALSE.

since you set the PD_USEDEVMODECOPIESANDCOLLATE to FALSE (what is cleared) the 2nd case applies and 'nCopies' is an output of printer driver to indicate that it will print 3 copies.

those functions are always tricky but I would try to set the PD_USEDEVMODECOPIESANDCOLLATE to TRUE, PD_COLLATE to FALSE, and actively set dmCopies to 1 before calling PrintDlgEx (what probably is in OnPreparePrinting befor call of DoPreparePrinting).

Sara
Setting the flag doesn't work. The trouble with setting the flag is:

If this flag is set and the printer driver does not support multiple copies, the Copies edit control is disabled.

I I set the the flag, then the print driver prints it if can. If it can't, the number of copies is disabled and the user can't put in the number of copies for me to print -- so I can't print the copies.

If I don't set the flag, the print driver prints the copies if it can (even though the documentation says it's not supposed to). If it can't, I have no way of knowing this -- so I can't print the copies because it might have already done that.

So, either way, I can't print the copies. Which gets to my original two questions:

1) How do I stop the print driver from working (PD_USEDEVMODECOPIESANDCOLLATE=0 is supposed to do that, but doesn't)?

2) If I can't stop the print driver and can't set PD_USEDEVMODECOPIESANDCOLLATE=1, how do I find out if it's printing the copies?
ASKER CERTIFIED SOLUTION
Avatar of sarabande
sarabande
Flag of Luxembourg image

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
In OnPreparePrinting sets:
   PD_USEDEVMODECOPIESANDCOLLATE = 0
   PD_COLLATE = 1
   PD_RETURNDC = 1
   nCopies = 1
  dmCopies = 1

OnBeginPrinting passes me:
   nCopies = 3   (if that's what the user sets)
  dmCopies = 1

My changing nCopies = 1 has no effect in OnBeginPrinting. The driver still prints 3.

At this point I'm going to give up and just let the print driver handle it if it can, and if it can't then they don't get multiple copies.
I never found a solution. However, the provider gave me lots of help.
OnBeginPrinting passes me:
    nCopies = 3   (if that's what the user sets)
that is too late. you have to change the nCopies in OnPreparePrinting after the call of PrintDlgEx.

Sara
Sara,

The structure of my program is:

//Functions
//---------
//      -PrintSetup - setup, call PrintDlg (get parameters), PrintFmt (build lines)
//      -OnPreparePrinting(info) - call DoPreparePrinting
//      -OnBeginPrinting(CDC,info) - when print properties needed
//            -Set PD_USEDEVMODECOPIESANDCOLLATE, PD_COLLATE, PD_RETURNDC
//            -Call DoPreparePrinting(pInfo) called to display print dialog
//            -Read nCopies, dmCopies
//      -Loop by page:
//            -OnPrepareDC(CDC,info) - specific page info
//            -OnDraw(CDC,info) or OnPrint(CDC,info) - draw or print page
//      -OnEndPrinting(CDC,info) - free GDI resources

Are you saying that "-Read nCopies, dmCopies" should be done up in PrintSetup ? That seems much too early. It's where the user tells me things they want printed. They never set copies until I call DoPreparePrinting in OnBeginPrinting.

I'll send you the software if you give me a non-public way to do it.
ee only allows to share code here. but i have a project where i could simulate your case if i would know what you were doing,

i only would need your code of PrintSetup, OnPreparePrinting, OnBeginPrinting. you may strip off any private code which is not relevant for the issue.

what i wonder is that you call PrintDlg and DoPreparePrinting twice. the best place to modify the members of the print structures would be after call of printdlgex when the user has made his choice and before any printing has happened. but two calls to printdlg(ex) is somewhat strange.

Sara