Go Premium for a chance to win a PS4. Enter to Win

x
?
Solved

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

Posted on 2015-01-25
10
Medium Priority
?
368 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
  • 5
  • 5
10 Comments
 
LVL 35

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 35

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
Veeam Task Manager for Hyper-V

Task Manager for Hyper-V provides critical information that allows you to monitor Hyper-V performance by displaying real-time views of CPU and memory at the individual VM-level, so you can quickly identify which VMs are using host resources.

 

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 35

Accepted Solution

by:
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
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 35

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 35

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

Microsoft Certification Exam 74-409

Veeam® is happy to provide the Microsoft community with a study guide prepared by MVP and MCT, Orin Thomas. This guide will take you through each of the exam objectives, helping you to prepare for and pass the examination.

Question has a verified solution.

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

IntroductionThis article is the second in a three part article series on the Visual Studio 2008 Debugger.  It provides tips in setting and using breakpoints. If not familiar with this debugger, you can find a basic introduction in the EE article loc…
Introduction This article is a continuation of the C/C++ Visual Studio Express debugger series. Part 1 provided a quick start guide in using the debugger. Part 2 focused on additional topics in breakpoints. As your assignments become a little more …
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.

971 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