5

I'm tasked with solving the following issue: My application crashes when running on a 64 bit machine when the PrintDlg() function is called.

After digging and hair pulling, I've decided the best solution is to replace the original calls of PrintDlg() with its bigger brother, PrintDlgEx().

Doing so fixes one problem (it no longer crashes!), but causes another. When I execute the code, it is not showing the print dialog, just returning a success code, and giving me all of the information for my default printer. I need this function to show the standard "print setup" window, I don't know how the heck to make it happen. Shown below are the sample values I'm trying to use to get my dialog to show.

Any thoughts? Thanks in advance.

//  Initialize the PRINTDLGEX structure.
pd2.lStructSize = sizeof(PRINTDLGEX);
pd2.hwndOwner = wnddata->wnd.hnd;
pd2.hDevMode = NULL;
pd2.hDevNames = NULL;
pd2.hDC = NULL;
pd2.Flags = PD_RETURNDC | PD_COLLATE;
pd2.Flags2 = 0;
pd2.ExclusionFlags = 0;
pd2.nPageRanges = 0;
pd2.nMaxPageRanges = 10;
pd2.lpPageRanges = NULL;
pd2.nMinPage = 1;
pd2.nMaxPage = 1000;
pd2.nCopies = 1;
pd2.hInstance = 0;
pd2.lpPrintTemplateName = NULL;
pd2.lpCallback = NULL;
pd2.nPropertyPages = 0;
pd2.lphPropertyPages = NULL;
pd2.nStartPage = START_PAGE_GENERAL;
pd2.dwResultAction = 0;
pdrc = PrintDlgEx  (&pd2);
razlebe
  • 7,134
  • 6
  • 42
  • 57
greggorob64
  • 2,487
  • 2
  • 27
  • 55
  • 1
    What is the return value from `PrintDlgEx`? – MSN Jun 09 '11 at 18:08
  • It was a negative value, I'm testing a workaround at the moment; if it doesn't work I'll drop the code back in and get the exact number. – greggorob64 Jun 09 '11 at 18:41
  • 1
    Negative HRESULT return codes are failures, not successes. – Jon Jun 09 '11 at 18:53
  • why don't you fix the call to PrintDlg? – David Heffernan Jun 09 '11 at 19:00
  • The call to PrintDlg is the same code its been forever. On my 64-bit machine, it just seg faults when you call it (this is new, and we 'believe' the root cause is that our apps have a different entry point, which is throwing a wrench into the printing for some random reason). After looking at the documentation for PrintDlg, it said "Use PrintDlgEx... its better". Using PrintDlgEx is indeed not crashing now, which is a big improvement. I just have to figure out how to ge tthe dialog to show – greggorob64 Jun 09 '11 at 19:09
  • The return code is 0x80070057 – greggorob64 Jun 09 '11 at 19:15

1 Answers1

5

You are most likely getting a return code of E_INVALIDARG, due to failure to read the fine print on the PRINTDLGEX structure. Specifically, it says "If the PD_NOPAGENUMS flag is not specified, lpPageRanges must be non-NULL."

The underlying problem with PrintDlg / PrintDlgEx is due to a missing attribute on your WinMain. You need to tag WinMain as [STAThreadAttribute] to indicate that your COM threading model is single-threaded apartment. Other threading models MAY work, but I can't say for sure.

Jon
  • 3,065
  • 1
  • 19
  • 29
  • I wish I could upvote this 1000 more times. I just threw the PD_NOPAGENUMS flag on their (i'm print graphs, no paging necessary). Thanks! – greggorob64 Jun 09 '11 at 19:26
  • Well, I lied, its crashing now too. Error code is: 0x000006E4 – greggorob64 Jun 09 '11 at 19:54
  • 1
    I'm not terribly surprised. Whatever was going wrong with PrintDlg is probably occuring with PrintDlgEx. I'm not sure how you got the code 0x000006E4, but that frequently maps to RPC_S_CANNOT_SUPPORT. Are you compiling as 32 bit and running on a 64 bit machine when you see this crash? Is it across multiple 64 bit machines? – Jon Jun 09 '11 at 20:00
  • It is compiled under 32 bit, and being run on 64 bit. Unfortunately, thats a design constraint. Having two version of our product is not yet a possibility. From testing, its worked in 3 XP-32bit machines, and consistantly crashes on 2 win7-64bit. I have yet to test win7-32 bit, but i predict that will work. – greggorob64 Jun 09 '11 at 20:07
  • Full error text: First-chance exception at 0x75b2b727 in display.exe: 0x000006E4: The requested operation is not supported. A first chance exception of type 'System.Runtime.InteropServices.SEHException' occurred in display.exe Additional information: External component has thrown an exception. – greggorob64 Jun 09 '11 at 20:08
  • Interesting. Two things you can try: replace the hwnd in pd2 with a NULL, or run the app elevated. This may be an xp to win7 issue, rather than 32bit to 64bit issue. – Jon Jun 09 '11 at 20:21
  • I've tried setting the hwnd to null, and just finished trying to run the app as a "regular user" (we normally run as admin). No dice on both. – greggorob64 Jun 09 '11 at 20:38
  • I can't reproduce this locally on a 64 bit win7 box. Is there anything unusual about the setup of these 64 bit machines, or about the rest of the app? You might also want to start a new question for this crash - you won't get many more views on this one, since it's already got an accepted answer. – Jon Jun 09 '11 at 20:59
  • Its very tricky. PrintDlg worked since (beginning of time) up until the following change was made: we wanted our unmanaged code to call dotnet functions. – greggorob64 Jun 10 '11 at 13:34
  • (continued) Making this changed cause our enterprise app to crash when bieng run from remote desktop, which is funky. The solution was to start all of our unmanaged apps inside the context of .net. Basically, our entry points are in a .lib file, and calls the original entry points from within a .net static object. Its very jacked up, but its the only way we could get our unmanaged .exes to link with the managed dlls. – greggorob64 Jun 10 '11 at 13:36
  • That definitely falls into the category of 'something unusual'. Could you clarify 'calls the original entry points from within a .net static object'. Do you mean that your entire app is being kicked off from within the constructor of some static object in .net? If so, you may be running into problems with the DLL loader lock. – Jon Jun 14 '11 at 16:33
  • That's exactly what we're doing. Kind of long winded, but here we go. Or original app all ran fine (mixed of unmanaged and managed C++.net applications) for a very, very long time. Eventually we implented some functions that called managed functions (not dynamically, all linked in at build time). This caused a very strange interaction. Our product would fail to load when ran through remote desktops on XP machines.... – greggorob64 Jun 14 '11 at 19:50
  • After a lot of fighting, some dll's just failing to load (MFCv90 to name one). This VERY strange fix worked. Instead of having our projects run from the normal "WinMain" they always did, we renamed them to "SecondMain". We created a small .net .lib file that contains a WinMain, which just turns around and calls "SecondMain" from within a statically constructed .net object. From there we just had all of the applications link in this new .lib file and everything worked magically. – greggorob64 Jun 14 '11 at 19:52
  • The only (so far!) issue found is that this damn PrintDlg fails to load! – greggorob64 Jun 14 '11 at 19:53
  • Is the call to SecondMain occurring from the constructor of the static .net object, or is it being called as a result of WinMain being called in the .net lib? – Jon Jun 14 '11 at 20:08
  • If the call to SecondMain is being called by the constructor of the static object, switching it to be the result of the call to WinMain in the .net lib will most likely fix the problem. – Jon Jun 14 '11 at 20:18
  • WinMain is in .lib file linked in. Winmain, then turns around and calls "SomeManagedGlass::RunSecondMain(params)". RunSecondMain is a static function that calls "SecondMain", which will then continue execution normally. – greggorob64 Jun 15 '11 at 12:24
  • Could you explain your most recent comment a little further? I don't totally understand. Should I initialize the .net object first, have it return, then call the "RunSecondMain" function? – greggorob64 Jun 15 '11 at 12:26
  • 1
    My most recent comment is irrelevant - it was based on an incorrect assumption about your .net code. – Jon Jun 15 '11 at 17:00
  • Well, the good news is I can duplicate the problem. Bad news is I don't really know why it fails. Your best bet would be to open a new question for this problem in the hopes of bringing in someone that knows a bit more about how the CLR plays with RPC and native functions. – Jon Jun 15 '11 at 21:24
  • 1
    Ok, scratch that - I think I found it: You are most likely missing `[STAThreadAttribute]` from your definition of WinMain in the .net lib. – Jon Jun 15 '11 at 22:23
  • thats scary-simple, I'll give it a try. – greggorob64 Jun 16 '11 at 12:13
  • Your new solution worked! I was going to ask you to make another post to "remove the attribute" so that I can mark that instead, incase anyone else runs across it. Thanks for your help, I'll owe ya a beer :P – greggorob64 Jun 16 '11 at 20:24
  • I'll refine this answer instead. – Jon Jun 16 '11 at 21:22