Bug 1106321 - Printing Page Setup Settings Disobeyed Under e10s
Looks like Black and White and a few other settings aren't being serialized correctly.

The problem is that the DEVMODE that's created on the parent side isn't being fully serialized. We used to be able to get away with that, because the DEVMODE was still stored and used to communicate to the OS / printer driver. Because we're serializing and using the DEVMODE in the child, we can't really get away with that. We have to serialize the things in the DEVMODE.

Looks like there are already two nsIPrintSettings <-> DEVMODE methods already. Those are:

DEVMODE -> nsIPrintSettings
nsDeviceContextSpecWin::SetPrintSettingsFromDevMode

and

static SetupDevModeFromSettings

So it looks like DEVMODE's are shared between printer drivers and like… display drivers or something.

I only care about members that printers use on this struct. What are they?

https://msdn.microsoft.com/en-us/library/windows/desktop/dd183565%28v=vs.85%29.aspx

typedef struct _devicemode {
TCHAR dmDeviceName[CCHDEVICENAME];
WORD  dmSpecVersion;
WORD  dmDriverVersion;
WORD  dmSize;
WORD  dmDriverExtra;
DWORD dmFields;
union {
struct {
short dmOrientation;
short dmPaperSize;
short dmPaperLength;
short dmPaperWidth;
short dmScale;
short dmCopies;
short dmDefaultSource;
short dmPrintQuality;
};
struct {
POINTL dmPosition;
DWORD  dmDisplayOrientation;
DWORD  dmDisplayFixedOutput;
};
};
short dmColor;
short dmDuplex;
short dmYResolution;
short dmTTOption;
short dmCollate;
TCHAR dmFormName[CCHFORMNAME];
WORD  dmLogPixels;
DWORD dmBitsPerPel;
DWORD dmPelsWidth;
DWORD dmPelsHeight;
union {
DWORD dmDisplayFlags;
DWORD dmNup;
};
DWORD dmDisplayFrequency;
# if (WINVER >= 0x0400)
DWORD dmICMMethod;
DWORD dmICMIntent;
DWORD dmMediaType;
DWORD dmDitherType;
DWORD dmReserved1;
DWORD dmReserved2;
# if (WINVER >= 0x0500) || (_WIN32_WINNT >= 0x0400)
DWORD dmPanningWidth;
DWORD dmPanningHeight;
#endif
#endif
} DEVMODE, *PDEVMODE, *LPDEVMODE;

Huh… dmDriverExtra sounds interesting. I guess it's possible that a printer driver might jam some extra data after the struct? Sheeeit.

So, uh, I guess I just need to add something to PrintData to carry those bytes? Yeah, probably.


2:55 PM < & billm > mconley: oh, I see. we save a copy of the devmode here: http://mxr.mozilla.org/mozilla-central/source/widget/windows/nsPrintSettingsWin.cpp#78
2:55 PM < & billm > mconley: it's probably fine to copy the devmode bytes down to the child
2:56 PM < & billm > mconley: we might have trouble with specific printers, but probably not
2:56 PM < & billm > mconley: at worst, the child crashes
2:56 PM < & billm > mconley: anyway, you can send the bytes via an nsCString I think
2:56 PM < & billm > mconley: or you can use nsTArray<uint8_t> or something
2:58 PM < mconley > billm: okie dokie. Do we have example code anywhere where we do this kind of wholesale bit transfer? I used memcpy. Once. a looooong time ago.
2:58 PM < mconley > and I have no idea if that's appropriate for our IPC stuff, or if there's a better way.
2:59 PM < & billm > mconley: jld's save document patch did something like that: https://hg.mozilla.org/integration/mozilla-inbound/rev/d19a0d92455b#l28.103
3:00 PM < & billm > mconley: the memcpy call in the code I pasted is probably similar to what you'll need
3:00 PM < & billm > mconley: (in nsPrintSettingsWin.cpp)

From https://msdn.microsoft.com/en-us/library/windows/desktop/dd183565%28v=vs.85%29.aspx :

A device driver's private data follows the public portion of the DEVMODE structure. The size of the public data can vary for different versions of the structure. The dmSize member specifies the number of bytes of public data, and the dmDriverExtra member specifies the number of bytes of private data.

FUCK. So I have to like… maybe send an arbitrarily large message across IPC. JESUS.

Ok. Keep calm. How would that work?

Well, the easiest thing would be to flat out fail if the DEVMODE size exceeds the message limit. I wonder how far that would get us?

Maybe it'd be far enough. Because if it turns out we don't need the private data with bobowen's stuff, then we can just hold on to the dev mode until the child is ready to roll.

I'm starting to like that.

SO, plan of action:

Add a devModeData member to the PrintData struct
When serializing to PrintData, if we're in the parent process, serialize the devmode.
If the PrintData struct size, plus dmSize and dmDriverExtra size exceeds 65536 bytes, return NS_ERROR_ something.
When deserializing to nsIPrintSettings, if we're in the content process, deserialize the devmode.

Is it necessary for the child to have created a DEVMODE in the first place?

Not really - not unless it's printing silently, in which case it won't need to communicate with the parent process at all (until bobowen's stuff gets rolling).

Profit?

This seems to work. I've spun out a try build to get the reporter to try.

Okay, jimm has some suggestions. TIL about nsWindowsHelpers.h. Noice - I can create an Auto pointer thing for DevMode.