Still celebrating National IT Professionals Day with 3 months of free Premium Membership. Use Code ITDAY17


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

Posted on 2015-01-25
Medium Priority
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
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 5
  • 5
LVL 35

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 35

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

NFR key for Veeam Agent for Linux

Veeam is happy to provide a free NFR license for one year.  It allows for the non‑production use and valid for five workstations and two servers. Veeam Agent for Linux is a simple backup tool for your Linux installations, both on‑premises and in the public cloud.


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 35

Accepted Solution

sarabande earned 1500 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 35

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 35

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

Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

Question has a verified solution.

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

Article by: SunnyDark
This article's goal is to present you with an easy to use XML wrapper for C++ and also present some interesting techniques that you might use with MS C++. The reason I built this class is to ease the pain of using XML files with C++, since there is…
Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation…
The viewer will learn additional member functions of the vector class. Specifically, the capacity and swap member functions will be introduced.
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.

722 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