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

Posted on 2015-01-25
Last Modified: 2015-01-30
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?
Question by:DickStone
  • 5
  • 5
LVL 34

Expert Comment

ID: 40570268
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.


Author Comment

ID: 40570606
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.
LVL 34

Expert Comment

ID: 40571102
my understanding is that dmcopies is an output rather than an input.

you may read the docs at

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).

PeopleSoft Has Never Been Easier

PeopleSoft Adoption Made Smooth & Simple!

On-The-Job Training Is made Intuitive & Easy With WalkMe's On-Screen Guidance Tool.  Claim Your Free WalkMe Account Now


Author Comment

ID: 40572783
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?
LVL 34

Accepted Solution

sarabande earned 500 total points
ID: 40573078
So, either way, I can't print the copies.
I don't know whether the conclusion is correct. the documentation says that you can receive the user's choice of number of copies after call of PrintDlgEx either by nCopies from structure PRINTDLGEX or from dmCopies of structure DEVMODE depending on how you set PD_USEDEVMODECOPIESANDCOLLATE before calling PrintDlgEx.

in your last comment you didn't tell which values you have seen but how many copies the printer has actually printed if it was capable to print multiple copies at all.

can you set a breakpoint to call of PrintDlgEx function such that you can tell for sure that the information you were looking for is not available. even for that case you may debug in the OnPreparePrinting whether your settings really were passed to PrintDlgEx and were not overwritten somehow before. if you could get the user's input correctly from the structures you could reset the nCopies and/or dmCopies members you find in LPPRINTDLGEX that was returned by PrintDlgEx function to 1 what should prevent the printer driver (where you got a print dc from) from printing copies and what should allow you to provide the copies yourself.

see sample of calling PrintDlgEx function at

note, the statement after calling PrintDlgEx where they checked whether the user has clicked on the 'print' button.


Author Comment

ID: 40576659
In OnPreparePrinting sets:
   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.

Author Closing Comment

ID: 40576663
I never found a solution. However, the provider gave me lots of help.
LVL 34

Expert Comment

ID: 40576940
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.


Author Comment

ID: 40579866

The structure of my program is:

//      -PrintSetup - setup, call PrintDlg (get parameters), PrintFmt (build lines)
//      -OnPreparePrinting(info) - call DoPreparePrinting
//      -OnBeginPrinting(CDC,info) - when print properties needed
//            -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.
LVL 34

Expert Comment

ID: 40580367
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.


Featured Post

Online Training Solution

Drastically shorten your training time with WalkMe's advanced online training solution that Guides your trainees to action. Forget about retraining and skyrocket knowledge retention rates.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
What are the big features of MVC5? 4 96
object oriented programming comparison 5 86
Licensing Sharepoint 2016 for developers 11 77
One named event, multiple event handlers 2 45
What my article will show is if you ever had to do processing to a listbox without being able to just select all the items in it. My software Visual Studio 2008 crystal report v11 My issue was I wanted to add crystal report to a form and show…
Basic understanding on "OO- Object Orientation" is needed for designing a logical solution to solve a problem. Basic OOAD is a prerequisite for a coder to ensure that they follow the basic design of OO. This would help developers to understand the b…
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…
The viewer will be introduced to the member functions push_back and pop_back of the vector class. The video will teach the difference between the two as well as how to use each one along with its functionality.

696 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question