Solved

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

Posted on 2015-01-25
10
337 Views
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?
0
Comment
Question by:DickStone
[X]
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
10 Comments
 
LVL 34

Expert Comment

by:sarabande
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.

Sara
0
 

Author Comment

by:DickStone
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.
0
 
LVL 34

Expert Comment

by:sarabande
ID: 40571102
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
0
NEW Veeam Agent for Microsoft Windows

Backup and recover physical and cloud-based servers and workstations, as well as endpoint devices that belong to remote users. Avoid downtime and data loss quickly and easily for Windows-based physical or public cloud-based workloads!

 

Author Comment

by:DickStone
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?
0
 
LVL 34

Accepted Solution

by:
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
https://msdn.microsoft.com/en-us/library/windows/desktop/ms646829(v=vs.85).aspx#print_property

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

Sara
0
 

Author Comment

by:DickStone
ID: 40576659
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.
0
 

Author Closing Comment

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

Expert Comment

by:sarabande
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.

Sara
0
 

Author Comment

by:DickStone
ID: 40579866
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.
0
 
LVL 34

Expert Comment

by:sarabande
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.

Sara
0

Featured Post

[Live Webinar] The Cloud Skills Gap

As Cloud technologies come of age, business leaders grapple with the impact it has on their team's skills and the gap associated with the use of a cloud platform.

Join experts from 451 Research and Concerto Cloud Services on July 27th where we will examine fact and fiction.

Question has a verified solution.

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

For most people, the WrapPanel seems like a magic when they switch from WinForms to WPF. Most of us will think that the code that is used to write a control like that would be difficult. However, most of the work is done by the WPF engine, and the W…
A theme is a collection of property settings that allow you to define the look of pages and controls, and then apply the look consistently across pages in an application. Themes can be made up of a set of elements: skins, style sheets, images, and o…
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.

632 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