2 * PROJECT: ReactOS Spooler API
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Functions giving information about DEVMODE structures
5 * COPYRIGHT: Copyright 2016-2017 Colin Finck (colin@reactos.org)
10 typedef struct _MINIMUM_SIZE_TABLE
15 MINIMUM_SIZE_TABLE
, *PMINIMUM_SIZE_TABLE
;
18 * Minimum required DEVMODEA structure size based on the used fields. Must be in descending order!
20 static MINIMUM_SIZE_TABLE MinimumSizeA
[] = {
21 { DM_PANNINGHEIGHT
, FIELD_OFFSET(DEVMODEA
, dmPanningHeight
) + RTL_FIELD_SIZE(DEVMODEA
, dmPanningHeight
) },
22 { DM_PANNINGWIDTH
, FIELD_OFFSET(DEVMODEA
, dmPanningWidth
) + RTL_FIELD_SIZE(DEVMODEA
, dmPanningWidth
) },
23 { DM_DITHERTYPE
, FIELD_OFFSET(DEVMODEA
, dmDitherType
) + RTL_FIELD_SIZE(DEVMODEA
, dmDitherType
) },
24 { DM_MEDIATYPE
, FIELD_OFFSET(DEVMODEA
, dmMediaType
) + RTL_FIELD_SIZE(DEVMODEA
, dmMediaType
) },
25 { DM_ICMINTENT
, FIELD_OFFSET(DEVMODEA
, dmICMIntent
) + RTL_FIELD_SIZE(DEVMODEA
, dmICMIntent
) },
26 { DM_ICMMETHOD
, FIELD_OFFSET(DEVMODEA
, dmICMMethod
) + RTL_FIELD_SIZE(DEVMODEA
, dmICMMethod
) },
27 { DM_DISPLAYFREQUENCY
, FIELD_OFFSET(DEVMODEA
, dmDisplayFrequency
) + RTL_FIELD_SIZE(DEVMODEA
, dmDisplayFrequency
) },
28 { DM_NUP
, FIELD_OFFSET(DEVMODEA
, dmNup
) + RTL_FIELD_SIZE(DEVMODEA
, dmNup
) },
29 { DM_DISPLAYFLAGS
, FIELD_OFFSET(DEVMODEA
, dmDisplayFlags
) + RTL_FIELD_SIZE(DEVMODEA
, dmDisplayFlags
) },
30 { DM_PELSHEIGHT
, FIELD_OFFSET(DEVMODEA
, dmPelsHeight
) + RTL_FIELD_SIZE(DEVMODEA
, dmPelsHeight
) },
31 { DM_PELSWIDTH
, FIELD_OFFSET(DEVMODEA
, dmPelsWidth
) + RTL_FIELD_SIZE(DEVMODEA
, dmPelsWidth
) },
32 { DM_BITSPERPEL
, FIELD_OFFSET(DEVMODEA
, dmBitsPerPel
) + RTL_FIELD_SIZE(DEVMODEA
, dmBitsPerPel
) },
33 { DM_LOGPIXELS
, FIELD_OFFSET(DEVMODEA
, dmLogPixels
) + RTL_FIELD_SIZE(DEVMODEA
, dmLogPixels
) },
34 { DM_FORMNAME
, FIELD_OFFSET(DEVMODEA
, dmFormName
) + RTL_FIELD_SIZE(DEVMODEA
, dmFormName
) },
35 { DM_COLLATE
, FIELD_OFFSET(DEVMODEA
, dmCollate
) + RTL_FIELD_SIZE(DEVMODEA
, dmCollate
) },
36 { DM_TTOPTION
, FIELD_OFFSET(DEVMODEA
, dmTTOption
) + RTL_FIELD_SIZE(DEVMODEA
, dmTTOption
) },
37 { DM_YRESOLUTION
, FIELD_OFFSET(DEVMODEA
, dmYResolution
) + RTL_FIELD_SIZE(DEVMODEA
, dmYResolution
) },
38 { DM_DUPLEX
, FIELD_OFFSET(DEVMODEA
, dmDuplex
) + RTL_FIELD_SIZE(DEVMODEA
, dmDuplex
) },
39 { DM_COLOR
, FIELD_OFFSET(DEVMODEA
, dmColor
) + RTL_FIELD_SIZE(DEVMODEA
, dmColor
) },
40 { DM_DISPLAYFIXEDOUTPUT
, FIELD_OFFSET(DEVMODEA
, dmDisplayFixedOutput
) + RTL_FIELD_SIZE(DEVMODEA
, dmDisplayFixedOutput
) },
41 { DM_DISPLAYORIENTATION
, FIELD_OFFSET(DEVMODEA
, dmDisplayOrientation
) + RTL_FIELD_SIZE(DEVMODEA
, dmDisplayOrientation
) },
42 { DM_POSITION
, FIELD_OFFSET(DEVMODEA
, dmPosition
) + RTL_FIELD_SIZE(DEVMODEA
, dmPosition
) },
43 { DM_PRINTQUALITY
, FIELD_OFFSET(DEVMODEA
, dmPrintQuality
) + RTL_FIELD_SIZE(DEVMODEA
, dmPrintQuality
) },
44 { DM_DEFAULTSOURCE
, FIELD_OFFSET(DEVMODEA
, dmDefaultSource
) + RTL_FIELD_SIZE(DEVMODEA
, dmDefaultSource
) },
45 { DM_COPIES
, FIELD_OFFSET(DEVMODEA
, dmCopies
) + RTL_FIELD_SIZE(DEVMODEA
, dmCopies
) },
46 { DM_SCALE
, FIELD_OFFSET(DEVMODEA
, dmScale
) + RTL_FIELD_SIZE(DEVMODEA
, dmScale
) },
47 { DM_PAPERWIDTH
, FIELD_OFFSET(DEVMODEA
, dmPaperWidth
) + RTL_FIELD_SIZE(DEVMODEA
, dmPaperWidth
) },
48 { DM_PAPERLENGTH
, FIELD_OFFSET(DEVMODEA
, dmPaperLength
) + RTL_FIELD_SIZE(DEVMODEA
, dmPaperLength
) },
49 { DM_PAPERSIZE
, FIELD_OFFSET(DEVMODEA
, dmPaperSize
) + RTL_FIELD_SIZE(DEVMODEA
, dmPaperSize
) },
50 { DM_ORIENTATION
, FIELD_OFFSET(DEVMODEA
, dmOrientation
) + RTL_FIELD_SIZE(DEVMODEA
, dmOrientation
) },
55 * Minimum required DEVMODEW structure size based on the used fields. Must be in descending order!
57 static MINIMUM_SIZE_TABLE MinimumSizeW
[] = {
58 { DM_PANNINGHEIGHT
, FIELD_OFFSET(DEVMODEW
, dmPanningHeight
) + RTL_FIELD_SIZE(DEVMODEW
, dmPanningHeight
) },
59 { DM_PANNINGWIDTH
, FIELD_OFFSET(DEVMODEW
, dmPanningWidth
) + RTL_FIELD_SIZE(DEVMODEW
, dmPanningWidth
) },
60 { DM_DITHERTYPE
, FIELD_OFFSET(DEVMODEW
, dmDitherType
) + RTL_FIELD_SIZE(DEVMODEW
, dmDitherType
) },
61 { DM_MEDIATYPE
, FIELD_OFFSET(DEVMODEW
, dmMediaType
) + RTL_FIELD_SIZE(DEVMODEW
, dmMediaType
) },
62 { DM_ICMINTENT
, FIELD_OFFSET(DEVMODEW
, dmICMIntent
) + RTL_FIELD_SIZE(DEVMODEW
, dmICMIntent
) },
63 { DM_ICMMETHOD
, FIELD_OFFSET(DEVMODEW
, dmICMMethod
) + RTL_FIELD_SIZE(DEVMODEW
, dmICMMethod
) },
64 { DM_DISPLAYFREQUENCY
, FIELD_OFFSET(DEVMODEW
, dmDisplayFrequency
) + RTL_FIELD_SIZE(DEVMODEW
, dmDisplayFrequency
) },
65 { DM_NUP
, FIELD_OFFSET(DEVMODEW
, dmNup
) + RTL_FIELD_SIZE(DEVMODEW
, dmNup
) },
66 { DM_DISPLAYFLAGS
, FIELD_OFFSET(DEVMODEW
, dmDisplayFlags
) + RTL_FIELD_SIZE(DEVMODEW
, dmDisplayFlags
) },
67 { DM_PELSHEIGHT
, FIELD_OFFSET(DEVMODEW
, dmPelsHeight
) + RTL_FIELD_SIZE(DEVMODEW
, dmPelsHeight
) },
68 { DM_PELSWIDTH
, FIELD_OFFSET(DEVMODEW
, dmPelsWidth
) + RTL_FIELD_SIZE(DEVMODEW
, dmPelsWidth
) },
69 { DM_BITSPERPEL
, FIELD_OFFSET(DEVMODEW
, dmBitsPerPel
) + RTL_FIELD_SIZE(DEVMODEW
, dmBitsPerPel
) },
70 { DM_LOGPIXELS
, FIELD_OFFSET(DEVMODEW
, dmLogPixels
) + RTL_FIELD_SIZE(DEVMODEW
, dmLogPixels
) },
71 { DM_FORMNAME
, FIELD_OFFSET(DEVMODEW
, dmFormName
) + RTL_FIELD_SIZE(DEVMODEW
, dmFormName
) },
72 { DM_COLLATE
, FIELD_OFFSET(DEVMODEW
, dmCollate
) + RTL_FIELD_SIZE(DEVMODEW
, dmCollate
) },
73 { DM_TTOPTION
, FIELD_OFFSET(DEVMODEW
, dmTTOption
) + RTL_FIELD_SIZE(DEVMODEW
, dmTTOption
) },
74 { DM_YRESOLUTION
, FIELD_OFFSET(DEVMODEW
, dmYResolution
) + RTL_FIELD_SIZE(DEVMODEW
, dmYResolution
) },
75 { DM_DUPLEX
, FIELD_OFFSET(DEVMODEW
, dmDuplex
) + RTL_FIELD_SIZE(DEVMODEW
, dmDuplex
) },
76 { DM_COLOR
, FIELD_OFFSET(DEVMODEW
, dmColor
) + RTL_FIELD_SIZE(DEVMODEW
, dmColor
) },
77 { DM_DISPLAYFIXEDOUTPUT
, FIELD_OFFSET(DEVMODEW
, dmDisplayFixedOutput
) + RTL_FIELD_SIZE(DEVMODEW
, dmDisplayFixedOutput
) },
78 { DM_DISPLAYORIENTATION
, FIELD_OFFSET(DEVMODEW
, dmDisplayOrientation
) + RTL_FIELD_SIZE(DEVMODEW
, dmDisplayOrientation
) },
79 { DM_POSITION
, FIELD_OFFSET(DEVMODEW
, dmPosition
) + RTL_FIELD_SIZE(DEVMODEW
, dmPosition
) },
80 { DM_PRINTQUALITY
, FIELD_OFFSET(DEVMODEW
, dmPrintQuality
) + RTL_FIELD_SIZE(DEVMODEW
, dmPrintQuality
) },
81 { DM_DEFAULTSOURCE
, FIELD_OFFSET(DEVMODEW
, dmDefaultSource
) + RTL_FIELD_SIZE(DEVMODEW
, dmDefaultSource
) },
82 { DM_COPIES
, FIELD_OFFSET(DEVMODEW
, dmCopies
) + RTL_FIELD_SIZE(DEVMODEW
, dmCopies
) },
83 { DM_SCALE
, FIELD_OFFSET(DEVMODEW
, dmScale
) + RTL_FIELD_SIZE(DEVMODEW
, dmScale
) },
84 { DM_PAPERWIDTH
, FIELD_OFFSET(DEVMODEW
, dmPaperWidth
) + RTL_FIELD_SIZE(DEVMODEW
, dmPaperWidth
) },
85 { DM_PAPERLENGTH
, FIELD_OFFSET(DEVMODEW
, dmPaperLength
) + RTL_FIELD_SIZE(DEVMODEW
, dmPaperLength
) },
86 { DM_PAPERSIZE
, FIELD_OFFSET(DEVMODEW
, dmPaperSize
) + RTL_FIELD_SIZE(DEVMODEW
, dmPaperSize
) },
87 { DM_ORIENTATION
, FIELD_OFFSET(DEVMODEW
, dmOrientation
) + RTL_FIELD_SIZE(DEVMODEW
, dmOrientation
) },
92 * Replace the last character by a null terminator if the given ANSI string is not null-terminated.
95 _FixStringA(PBYTE String
, DWORD cbString
)
97 const PBYTE pLastCharacter
= &String
[cbString
/ sizeof(BYTE
) - 1];
102 if (p
== pLastCharacter
)
113 * Replace the last character by a null terminator if the given Unicode string is not null-terminated.
116 _FixStringW(PWSTR String
, DWORD cbString
)
118 const PWSTR pLastCharacter
= &String
[cbString
/ sizeof(WCHAR
) - 1];
123 if (p
== pLastCharacter
)
134 IsValidDevmodeA(PDEVMODEA pDevmode
, size_t DevmodeSize
)
136 PMINIMUM_SIZE_TABLE pTable
= MinimumSizeA
;
139 TRACE("IsValidDevmodeA(%p, %lu)\n", pDevmode
, DevmodeSize
);
141 // Check if a Devmode was given at all.
145 // Verify that DevmodeSize is large enough to hold the public and private members of the structure.
146 if (DevmodeSize
< pDevmode
->dmSize
+ pDevmode
->dmDriverExtra
)
149 // If the structure has private members, the public structure must be 32-bit packed.
150 if (pDevmode
->dmDriverExtra
&& pDevmode
->dmSize
% 4)
153 // Now determine the minimum possible dmSize based on the given fields in dmFields.
154 wRequiredSize
= FIELD_OFFSET(DEVMODEA
, dmFields
) + RTL_FIELD_SIZE(DEVMODEA
, dmFields
);
156 while (pTable
->dwField
)
158 if (pDevmode
->dmFields
& pTable
->dwField
)
160 wRequiredSize
= pTable
->wSize
;
167 // Verify that the value in dmSize is big enough for the used fields.
168 if (pDevmode
->dmSize
< wRequiredSize
)
171 // Check if dmDeviceName and (if used) dmFormName are null-terminated.
172 // Fix this if they aren't.
173 _FixStringA(pDevmode
->dmDeviceName
, sizeof(pDevmode
->dmDeviceName
));
174 if (pDevmode
->dmFields
& DM_FORMNAME
)
175 _FixStringA(pDevmode
->dmFormName
, sizeof(pDevmode
->dmFormName
));
177 // Return success without setting the error code.
181 SetLastError(ERROR_INVALID_DATA
);
186 IsValidDevmodeW(PDEVMODEW pDevmode
, size_t DevmodeSize
)
188 PMINIMUM_SIZE_TABLE pTable
= MinimumSizeW
;
191 TRACE("IsValidDevmodeW(%p, %lu)\n", pDevmode
, DevmodeSize
);
193 // Check if a Devmode was given at all.
197 // Verify that DevmodeSize is large enough to hold the public and private members of the structure.
198 if (DevmodeSize
< pDevmode
->dmSize
+ pDevmode
->dmDriverExtra
)
201 // If the structure has private members, the public structure must be 32-bit packed.
202 if (pDevmode
->dmDriverExtra
&& pDevmode
->dmSize
% 4)
205 // Now determine the minimum possible dmSize based on the given fields in dmFields.
206 wRequiredSize
= FIELD_OFFSET(DEVMODEW
, dmFields
) + RTL_FIELD_SIZE(DEVMODEW
, dmFields
);
208 while (pTable
->dwField
)
210 if (pDevmode
->dmFields
& pTable
->dwField
)
212 wRequiredSize
= pTable
->wSize
;
219 // Verify that the value in dmSize is big enough for the used fields.
220 if (pDevmode
->dmSize
< wRequiredSize
)
223 // Check if dmDeviceName and (if used) dmFormName are null-terminated.
224 // Fix this if they aren't.
225 _FixStringW(pDevmode
->dmDeviceName
, sizeof(pDevmode
->dmDeviceName
));
226 if (pDevmode
->dmFields
& DM_FORMNAME
)
227 _FixStringW(pDevmode
->dmFormName
, sizeof(pDevmode
->dmFormName
));
229 // Return success without setting the error code.
233 SetLastError(ERROR_INVALID_DATA
);
238 IsValidDevmodeNoSizeW(PDEVMODEW pDevmode
)
240 PMINIMUM_SIZE_TABLE pTable
= MinimumSizeW
;
243 TRACE("IsValidDevmodeNoSizeW(%p)\n", pDevmode
);
245 // Check if a Devmode was given at all.
249 // If the structure has private members, the public structure must be 32-bit packed.
250 if (pDevmode
->dmDriverExtra
&& pDevmode
->dmSize
% 4)
253 // Now determine the minimum possible dmSize based on the given fields in dmFields.
254 wRequiredSize
= FIELD_OFFSET(DEVMODEW
, dmFields
) + RTL_FIELD_SIZE(DEVMODEW
, dmFields
);
256 while (pTable
->dwField
)
258 if (pDevmode
->dmFields
& pTable
->dwField
)
260 wRequiredSize
= pTable
->wSize
;
267 // Verify that the value in dmSize is big enough for the used fields.
268 if (pDevmode
->dmSize
< wRequiredSize
)
271 // Check if dmDeviceName and (if used) dmFormName are null-terminated.
272 // Fix this if they aren't.
273 _FixStringW(pDevmode
->dmDeviceName
, sizeof(pDevmode
->dmDeviceName
));
274 if (pDevmode
->dmFields
& DM_FORMNAME
)
275 _FixStringW(pDevmode
->dmFormName
, sizeof(pDevmode
->dmFormName
));
277 // Return success without setting the error code.
281 SetLastError(ERROR_INVALID_DATA
);
285 void RosConvertAnsiDevModeToUnicodeDevmode(PDEVMODEA pDevModeInput
, PDEVMODEW
*pDevModeOutput
)
287 // FIXME: This function should become ConvertAnsiDevModeToUnicodeDevmode when its parameters are known!
289 // Check if a pDevModeInput and pDevModeOutput are both not NULL.
290 if (!pDevModeInput
|| !pDevModeOutput
)
293 *pDevModeOutput
= GdiConvertToDevmodeW(pDevModeInput
);
296 // Internal counterpart to GdiConvertToDevmodeW from gdi32
297 static __inline DEVMODEA
*
298 _ConvertToDevmodeA(const DEVMODEW
*dmW
)
301 WORD dmA_size
, dmW_size
;
304 dmW_size
= dmW
->dmSize
;
306 /* this is the minimal dmSize that XP accepts */
307 if (dmW_size
< FIELD_OFFSET(DEVMODEW
, dmFields
))
310 // Guard against callers that set dmSize incorrectly.
311 if (dmW_size
> sizeof(DEVMODEW
))
312 dmW_size
= sizeof(DEVMODEW
);
314 // dmA_size must become dmW_size without the additional 1 byte per character for each Unicode string (dmDeviceName and dmFormName).
315 dmA_size
= dmW_size
- CCHDEVICENAME
;
316 if (dmW_size
>= FIELD_OFFSET(DEVMODEW
, dmFormName
) + CCHFORMNAME
* sizeof(WCHAR
))
317 dmA_size
-= CCHFORMNAME
;
319 // Allocate the required bytes, that is dmSize for the ANSI DEVMODEA structure plus any extra bytes requested through dmDriverExtra.
320 dmA
= HeapAlloc(GetProcessHeap(), 0, dmA_size
+ dmW
->dmDriverExtra
);
321 if (!dmA
) return NULL
;
323 // Every valid DEVMODEW has a dmDeviceName, which we convert to ANSI here.
324 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmDeviceName
, -1, (LPSTR
)dmA
->dmDeviceName
, CCHDEVICENAME
, NULL
, NULL
);
326 // Copy everything up to dmFormName or the remaining dmW_size, whatever is smaller.
327 BytesToCopy
= min(FIELD_OFFSET(DEVMODEW
, dmFormName
) - FIELD_OFFSET(DEVMODEW
, dmSpecVersion
), dmW_size
- CCHDEVICENAME
* sizeof(WCHAR
));
328 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
, BytesToCopy
);
330 // Handle dmFormName if the input DEVMODEW is large enough to contain one.
331 if (dmW_size
>= FIELD_OFFSET(DEVMODEW
, dmFormName
) + CCHFORMNAME
* sizeof(WCHAR
))
333 if (dmW
->dmFields
& DM_FORMNAME
)
334 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmFormName
, -1, (LPSTR
)dmA
->dmFormName
, CCHFORMNAME
, NULL
, NULL
);
336 dmA
->dmFormName
[0] = 0;
338 // Copy the remaining fields.
339 if (dmW_size
> FIELD_OFFSET(DEVMODEW
, dmLogPixels
))
340 memcpy(&dmA
->dmLogPixels
, &dmW
->dmLogPixels
, dmW_size
- FIELD_OFFSET(DEVMODEW
, dmLogPixels
));
343 // Append dmDriverExtra if required.
344 if (dmW
->dmDriverExtra
)
345 memcpy((char *)dmA
+ dmA_size
, (const char *)dmW
+ dmW_size
, dmW
->dmDriverExtra
);
347 // Set the corrected dmSize and we are done.
348 dmA
->dmSize
= dmA_size
;
353 void RosConvertUnicodeDevModeToAnsiDevmode(PDEVMODEW pDevModeInput
, PDEVMODEA pDevModeOutput
)
357 // FIXME: This function should become ConvertUnicodeDevModeToAnsiDevmode when its parameters are known!
359 // Check if a pDevModeInput and pDevModeOutput are both not NULL.
360 if (!pDevModeInput
|| !pDevModeOutput
)
363 pTmp
= _ConvertToDevmodeA(pDevModeInput
);
364 memcpy( pDevModeOutput
, pTmp
, pTmp
->dmSize
+ pTmp
->dmDriverExtra
); // Copy into a Wide char (Larger) buffer.
365 HeapFree(hProcessHeap
, 0, pTmp
);