2

Our program is crashing whenever the user brings up the Windows print dialog via PrintDlgEx when a particular printer is the default printer. If that printer is not the default, everything is fine, unless the user selects that printer from within the dialog, in which case the dialog immediately crashes.

The printer is an HP LaserJet Pro 400 M451nw, and the problem occurs with multiple computers on the same network trying to access that printer. However, other programs can print to that printer, including Notepad. The computers are running 32-bit Windows 7; the program is written in VS C++.

Here is the code:

PRINTDLGEX printer = { 0 }; 
printer.lStructSize = sizeof( printer );
printer.hwndOwner = my_win;
printer.Flags = PD_RETURNDC | PD_NOPAGENUMS | PD_NOCURRENTPAGE | PD_USEDEVMODECOPIES;   
printer.nCopies = 1;                                        
printer.nStartPage = START_PAGE_GENERAL;
PrintDlgEx( &printer );

Here is what the customer sent me:

enter image description here Any idea as to what could cause such a crash, or how we would go about figuring it out?

Dev93
  • 668
  • 1
  • 6
  • 18
  • Did you try playing around with the flags to see if one of them triggers it? – Jonathan Potter Sep 24 '14 at 20:25
  • Might be something to do with the COM state? For example, perhaps you're using a multi-threaded apartment model and the printer driver can't cope? (You did remember to initialize COM?) – Harry Johnston Sep 24 '14 at 20:32
  • @Jonathan Potter: I've played around with many of the flags (reducing it to just PD_RETURNDC and adding other member variables, as well as adding flags. No joy. – Dev93 Sep 24 '14 at 20:48
  • @HarryJohnston: I'm fairly confident COM is initialized earlier in the program (it gets initialized "as needed" with COINIT_APARTMENTTHREADED). Regardless, I didn't see any documentation that said that COM initialization was required for PrintDlg/Ex. Can you point me to that? – Dev93 Sep 24 '14 at 20:54
  • @Dev93 - Is this a plain Win32 app (no COM involved)? It would be easy to verify if this were just a Win32 app. Just a few lines in main() would trigger the error. – PaulMcKenzie Sep 24 '14 at 20:56
  • 1
    Does [this question](http://stackoverflow.com/questions/6297077/win32-printdlg-printdlgex-crashing-and-quirkiness) apply? It sounds very similar. – Jonathan Potter Sep 24 '14 at 20:57
  • The fact that PrintDlg returns a COM error code is a strong hint that it uses COM internally, but I don't know whether or not there is supposed to be a requirement to initialize COM yourself. (I was speculating that perhaps the printer driver is supposed to initialize it, but this particular driver fails to do so.) – Harry Johnston Sep 24 '14 at 21:21
  • 2
    Tell us about the "crash". At least the exception code and a stack trace. – Hans Passant Sep 24 '14 at 21:22
  • @PaulMcKenzie: It does use COM for certain things, such as CLSID_FileOpenDialog. I believe that COM is initialized before any such calls, but I could put in a unconditional statement at program start to ensure that (however, I've been unable to find any docs that say PrintDlgEx requires COM initialization). – Dev93 Sep 24 '14 at 23:50
  • @JonathanPotter, I had read that question before posting, but it refers to an issue with .NET, which we are not using. – Dev93 Sep 24 '14 at 23:52
  • @HansPassant: This is only occurring at a remote customer site, so I need to minimize what I ask of them. I've never found myself in this situation before, where I can't reproduce it locally and debug print logs can't help. To get a stack trace, I think I would need to have them install [DebugDiag tool](http://www.microsoft.com/en-in/download/details.aspx?id=40336), and [do this](http://gerrydevstory.com/2014/02/10/generating-visual-c-crash-dump-for-debugging/), correct? Is there a better way? I don't know that a stack trace would help me in this case, but if you can use it, I'll get it! – Dev93 Sep 25 '14 at 00:10
  • It is a printer driver problem. That's neither yours nor our problem. – Hans Passant Sep 25 '14 at 00:12
  • The question Jonathan linked to *is* relevant; the resolution was to initialize COM in single-threaded-apartment mode. You do that differently in .NET than in Win32, but the impact is the same either way. Also, have you tried reproducing the problem by installing a dummy printer queue with the same printer driver that the customer is using? – Harry Johnston Sep 25 '14 at 03:38
  • Have your customers checked that they are using the latest available version of the HP printer driver? – Harry Johnston Sep 25 '14 at 03:40
  • @Dev93 - I would also check to see if this is a driver issue. I remember some years ago having a buggy HP driver that reset the FPU flags on a call to PrintDlgEx. – PaulMcKenzie Sep 25 '14 at 03:52
  • @HansPassant: The customer reports these crashes with 2 different up-to-date drivers for the same printer (a "generic" one, and one that's more specific). I'd like to believe it's a flawed driver, but other programs work fine with it. In fact, I installed one of these drivers on a Win7 32-bit OS (to match customer), and everything works. FWIW, COM _is_ initialized with COINIT_APARTMENTTHREADED (although I haven'seen any docs that say this is necessary). I tried to trap all exceptions when running on customer machine, and got nothing but a crash. I attached their event log image to post. – Dev93 Sep 26 '14 at 03:03
  • If that c0000093 is the exception code (?) then apparently it is a floating point underflow. Could perhaps be caused by the FPU being in a different mode than the driver expects it to be? Are you loading any third-party libraries that might do weird things to the FPU? – Harry Johnston Sep 26 '14 at 05:30
  • @HarryJohnston: You nailed it. Took a while to sort through with the customer on vacation, but our own app turns on FP exception reporting, and apparently this printer driver doesn't like that on certain computers. Temporarily masking all FPEs before calling PrintDlgEx eliminates the crash. If you write up the answer, I'll mark it solved. – Dev93 Oct 06 '14 at 23:51

1 Answers1

0

The event log details provided the critical clue: the exception code 0xC0000093, which translates to STATUS_FLOAT_UNDERFLOW, indicating that the FPU is involved. Because floating point is so complicated, there are lots of different configurations for the FPU, and unfortunately code can be sensitive to this.

In this particular case it appears that printer driver expected FP exception reporting to be off (not unreasonably, I suppose) but the application that was hosting the call into the driver had turned it on. Masking the FP exceptions before calling PrintDlgEx eliminated the crash.

(There are two lessons to be learned from this: firstly, when calling third-party code, you need to try to provide as clean an environment as possible; secondly, printer drivers shouldn't use floating point. It also points to a design weakness in Windows, IMO, though probably one that was necessary on older computers.)

Harry Johnston
  • 35,639
  • 6
  • 68
  • 158