1 /*
2  * PROJECT:     ReactOS Spooler Router
3  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE:     Functions for managing print Forms
5  * COPYRIGHT:   Copyright 2020 ReactOS
6  */
7 
8 #include "precomp.h"
9 
10 #define FORMINFOSIG '.2'
11 #define FORMMAXNAMESIZE CCHDEVICENAME-1
12 
13 typedef struct _FORM_INFO_LIST
14 {
15     LIST_ENTRY List;
16     DWORD Sig;
17     DWORD Index;
18     FORM_INFO_2W;
19 } FORM_INFO_LIST, *PFORM_INFO_LIST;
20 
21 LIST_ENTRY FormList;
22 static DWORD _dwLastForm;
23 
24 // Local Constants
25 static DWORD dwFormInfo1Offsets[] = {
26     FIELD_OFFSET(FORM_INFO_1W, pName),
27     MAXDWORD
28 };
29 
30 static DWORD dwFormInfo2Offsets[] = {
31     FIELD_OFFSET(FORM_INFO_2W, pName),
32     FIELD_OFFSET(FORM_INFO_2W, pKeyword),
33     FIELD_OFFSET(FORM_INFO_2W, pMuiDll),
34     FIELD_OFFSET(FORM_INFO_2W, pDisplayName),
35     MAXDWORD
36 };
37 
38 
39 // Built in Form names
40 WCHAR wszLetter[] = L"Letter";
41 WCHAR wszLetterSmall[] = L"Letter Small";
42 WCHAR wszTabloid[] = L"Tabloid";
43 WCHAR wszLedger[] = L"Ledger";
44 WCHAR wszLegal[] = L"Legal";
45 WCHAR wszStatement[] = L"Statement";
46 WCHAR wszExecutive[] = L"Executive";
47 WCHAR wszA3[] = L"A3";
48 WCHAR wszA4[] = L"A4";
49 WCHAR wszA4Small[] = L"A4 Small";
50 WCHAR wszA5[] = L"A5";
51 WCHAR wszB4JIS[] = L"B4 (JIS)";
52 WCHAR wszB5JIS[] = L"B5 (JIS)";
53 WCHAR wszFolio[] = L"Folio";
54 WCHAR wszQuarto[] = L"Quarto";
55 WCHAR wsz10x14[] = L"10 x 14";
56 WCHAR wsz11x17[] = L"11 x 17";
57 WCHAR wszNote[] = L"Note";
58 WCHAR wszEnvelope9[] = L"Envelope #9";
59 WCHAR wszEnvelope10[] = L"Envelope #10";
60 WCHAR wszEnvelope11[] = L"Envelope #11";
61 WCHAR wszEnvelope12[] = L"Envelope #12";
62 WCHAR wszEnvelope14[] = L"Envelope #14";
63 WCHAR wszCsizesheet[] = L"C size sheet";
64 WCHAR wszDsizesheet[] = L"D size sheet";
65 WCHAR wszEsizesheet[] = L"E size sheet";
66 WCHAR wszEnvelopeDL[] = L"Envelope DL";
67 WCHAR wszEnvelopeC5[] = L"Envelope C5";
68 WCHAR wszEnvelopeC3[] = L"Envelope C3";
69 WCHAR wszEnvelopeC4[] = L"Envelope C4";
70 WCHAR wszEnvelopeC6[] = L"Envelope C6";
71 WCHAR wszEnvelope65[] = L"Envelope 65";
72 WCHAR wszEnvelopeB4[] = L"Envelope B4";
73 WCHAR wszEnvelopeB5[] = L"Envelope B5";
74 WCHAR wszEnvelopeB6[] = L"Envelope B6";
75 WCHAR wszEnvelope[] = L"Envelope";
76 WCHAR wszEnvelopeMonarch[] = L"Envelope Monarch";
77 WCHAR wsz634Envelope[] = L"6 3/4 Envelope";
78 WCHAR wszUSStdFanfold[] = L"US Std Fanfold";
79 WCHAR wszGermanStdFanfold[] = L"German Std Fanfold";
80 WCHAR wszGermanLegalFanfold[] = L"German Legal Fanfold";
81 WCHAR wszB4ISO[] = L"B4 (ISO)";
82 WCHAR wszJapanesePostcard[] = L"Japanese Postcard";
83 WCHAR wsz9x11[] = L"9 x 11";
84 WCHAR wsz10x11[] = L"10 x 11";
85 WCHAR wsz15x11[] = L"15 x 11";
86 WCHAR wszEnvelopeInvite[] = L"Envelope Invite";
87 WCHAR wszReserved48[] = L"Reserved48";
88 WCHAR wszReserved49[] = L"Reserved49";
89 WCHAR wszLetterExtra[] = L"Letter Extra";
90 WCHAR wszLegalExtra[] = L"Legal Extra";
91 WCHAR wszTabloidExtra[] = L"Tabloid Extra";
92 WCHAR wszA4Extra[] = L"A4 Extra";
93 WCHAR wszLetterTransverse[] = L"Letter Transverse";
94 WCHAR wszA4Transverse[] = L"A4 Transverse";
95 WCHAR wszLetterExtraTransverse[] = L"Letter Extra Transverse";
96 WCHAR wszSuperA[] = L"Super A";
97 WCHAR wszSuperB[] = L"Super B";
98 WCHAR wszLetterPlus[] = L"Letter Plus";
99 WCHAR wszA4Plus[] = L"A4 Plus";
100 WCHAR wszA5Transverse[] = L"A5 Transverse";
101 WCHAR wszB5JISTransverse[] = L"B5 (JIS) Transverse";
102 WCHAR wszA3Extra[] = L"A3 Extra";
103 WCHAR wszA5Extra[] = L"A5 Extra";
104 WCHAR wszB5ISOExtra[] = L"B5 (ISO) Extra";
105 WCHAR wszA0[] = L"A0";
106 WCHAR wszA3Transverse[] = L"A3 Transverse";
107 WCHAR wszA3ExtraTransverse[] = L"A3 Extra Transverse";
108 WCHAR wszJapaneseDoublePostcard[] = L"Japanese Double Postcard";
109 WCHAR wszA1[] = L"A1";
110 WCHAR wszJapaneseEnvelopeKaku2[] = L"Japanese Envelope Kaku #2";
111 WCHAR wszJapaneseEnvelopeKaku3[] = L"Japanese Envelope Kaku #3";
112 WCHAR wszJapaneseEnvelopeChou3[] = L"Japanese Envelope Chou #3";
113 WCHAR wszJapaneseEnvelopeChou4[] = L"Japanese Envelope Chou #4";
114 WCHAR wszLetterRotated[] = L"Letter Rotated";
115 WCHAR wszA3Rotated[] = L"A3 Rotated";
116 WCHAR wszA4Rotated[] = L"A4 Rotated";
117 WCHAR wszA5Rotated[] = L"A5 Rotated";
118 WCHAR wszB4JISRotated[] = L"B4 (JIS) Rotated";
119 WCHAR wszB5JISRotated[] = L"B5 (JIS) Rotated";
120 WCHAR wszJapanesePostcardRotated[] = L"Japanese Postcard Rotated";
121 WCHAR wszDoubleJapanPostcardRotated[] = L"Double Japan Postcard Rotated";
122 WCHAR wsA6Rotatedz[] = L"A6 Rotated";
123 WCHAR wszJapanEnvelopeKaku2Rotated[] = L"Japan Envelope Kaku #2 Rotated";
124 WCHAR wszJapanEnvelopeKaku3Rotated[] = L"Japan Envelope Kaku #3 Rotated";
125 WCHAR wszJapanEnvelopeChou3Rotated[] = L"Japan Envelope Chou #3 Rotated";
126 WCHAR wszJapanEnvelopeChou4Rotated[] = L"Japan Envelope Chou #4 Rotated";
127 WCHAR wszB6JIS[] = L"B6 (JIS)";
128 WCHAR wszB6JISRotated[] = L"B6 (JIS) Rotated";
129 WCHAR wsz12x11[] = L"12 x 11";
130 WCHAR wszJapanEnvelopeYou4[] = L"Japan Envelope You #4";
131 WCHAR wszJapanEnvelopeYou4Rotated[] = L"Japan Envelope You #4 Rotated";
132 WCHAR wszPRC16K[] = L"PRC 16K";
133 WCHAR wszPRC32K[] = L"PRC 32K";
134 WCHAR wszPRC32KBig[] = L"PRC 32K(Big)";
135 WCHAR wszPRCEnvelope1[] = L"PRC Envelope #1";
136 WCHAR wszPRCEnvelope2[] = L"PRC Envelope #2";
137 WCHAR wszPRCEnvelope3[] = L"PRC Envelope #3";
138 WCHAR wszPRCEnvelope4[] = L"PRC Envelope #4";
139 WCHAR wszPRCEnvelope5[] = L"PRC Envelope #5";
140 WCHAR wszPRCEnvelope6[] = L"PRC Envelope #6";
141 WCHAR wszPRCEnvelope7[] = L"PRC Envelope #7";
142 WCHAR wszPRCEnvelope8[] = L"PRC Envelope #8";
143 WCHAR wszPRCEnvelope9[] = L"PRC Envelope #9";
144 WCHAR wszPRCEnvelope10[] = L"PRC Envelope #10";
145 WCHAR wszPRC16KRotated[] = L"PRC 16K Rotated";
146 WCHAR wszPRC32KRotated[] = L"PRC 32K Rotated";
147 WCHAR wszPRC32KBigRotated[] = L"PRC 32K(Big) Rotated";
148 WCHAR wszPRCEnvelope1Rotated[] = L"PRC Envelope #1 Rotated";
149 WCHAR wszPRCEnvelope2Rotated[] = L"PRC Envelope #2 Rotated";
150 WCHAR wszPRCEnvelope3Rotated[] = L"PRC Envelope #3 Rotated";
151 WCHAR wszPRCEnvelope4Rotated[] = L"PRC Envelope #4 Rotated";
152 WCHAR wszPRCEnvelope5Rotated[] = L"PRC Envelope #5 Rotated";
153 WCHAR wszPRCEnvelope6Rotated[] = L"PRC Envelope #6 Rotated";
154 WCHAR wszPRCEnvelope7Rotated[] = L"PRC Envelope #7 Rotated";
155 WCHAR wszPRCEnvelope8Rotated[] = L"PRC Envelope #8 Rotated";
156 WCHAR wszPRCEnvelope9Rotated[] = L"PRC Envelope #9 Rotated";
157 WCHAR wszPRCEnvelope10Rotated[] = L"PRC Envelope #10 Rotated";
158 
159 // Built in Forms
160 FORM_INFO_1W BuiltInForms[] =
161 {
162     { FORM_USER, wszLetter,                    {215900, 279400},{ 0, 0, 215900, 279400}},
163     { FORM_USER, wszLetterSmall,               {215900, 279400},{ 0, 0, 215900, 279400}},
164     { FORM_USER, wszTabloid,                   {279400, 431800},{ 0, 0, 279400, 431800}},
165     { FORM_USER, wszLedger,                    {431800, 279400},{ 0, 0, 431800, 279400}},
166     { FORM_USER, wszLegal,                     {215900, 355600},{ 0, 0, 215900, 355600}},
167     { FORM_USER, wszStatement,                 {139700, 215900},{ 0, 0, 139700, 215900}},
168     { FORM_USER, wszExecutive,                 {184150, 266700},{ 0, 0, 184150, 266700}},
169     { FORM_USER, wszA3,                        {297000, 420000},{ 0, 0, 297000, 420000}},
170     { FORM_USER, wszA4,                        {210000, 297000},{ 0, 0, 210000, 297000}},
171     { FORM_USER, wszA4Small,                   {210000, 297000},{ 0, 0, 210000, 297000}},
172     { FORM_USER, wszA5,                        {148000, 210000},{ 0, 0, 148000, 210000}},
173     { FORM_USER, wszB4JIS,                     {257000, 364000},{ 0, 0, 257000, 364000}},
174     { FORM_USER, wszB5JIS,                     {182000, 257000},{ 0, 0, 182000, 257000}},
175     { FORM_USER, wszFolio,                     {215900, 330200},{ 0, 0, 215900, 330200}},
176     { FORM_USER, wszQuarto,                    {215000, 275000},{ 0, 0, 215000, 275000}},
177     { FORM_USER, wsz10x14,                     {254000, 355600},{ 0, 0, 254000, 355600}},
178     { FORM_USER, wsz11x17,                     {279400, 431800},{ 0, 0, 279400, 431800}},
179     { FORM_USER, wszNote,                      {215900, 279400},{ 0, 0, 215900, 279400}},
180     { FORM_USER, wszEnvelope9,                 { 98425, 225425},{ 0, 0,  98425, 225425}},
181     { FORM_USER, wszEnvelope10,                {104775, 241300},{ 0, 0, 104775, 241300}},
182     { FORM_USER, wszEnvelope11,                {114300, 263525},{ 0, 0, 114300, 263525}},
183     { FORM_USER, wszEnvelope12,                {120650, 279400},{ 0, 0, 120650, 279400}},
184     { FORM_USER, wszEnvelope14,                {127000, 292100},{ 0, 0, 127000, 292100}},
185     { FORM_USER, wszCsizesheet,                {431800, 558800},{ 0, 0, 431800, 558800}},
186     { FORM_USER, wszDsizesheet,                {558800, 863600},{ 0, 0, 558800, 863600}},
187     { FORM_USER, wszEsizesheet,                {863600,1117600},{ 0, 0, 863600,1117600}},
188     { FORM_USER, wszEnvelopeDL,                {110000, 220000},{ 0, 0, 110000, 220000}},
189     { FORM_USER, wszEnvelopeC5,                {162000, 229000},{ 0, 0, 162000, 229000}},
190     { FORM_USER, wszEnvelopeC3,                {324000, 458000},{ 0, 0, 324000, 458000}},
191     { FORM_USER, wszEnvelopeC4,                {229000, 324000},{ 0, 0, 229000, 324000}},
192     { FORM_USER, wszEnvelopeC6,                {114000, 162000},{ 0, 0, 114000, 162000}},
193     { FORM_USER, wszEnvelope65,                {114000, 229000},{ 0, 0, 114000, 229000}},
194     { FORM_USER, wszEnvelopeB4,                {250000, 353000},{ 0, 0, 250000, 353000}},
195     { FORM_USER, wszEnvelopeB5,                {176000, 250000},{ 0, 0, 176000, 250000}},
196     { FORM_USER, wszEnvelopeB6,                {176000, 125000},{ 0, 0, 176000, 125000}},
197     { FORM_USER, wszEnvelope,                  {110000, 230000},{ 0, 0, 110000, 230000}},
198     { FORM_USER, wszEnvelopeMonarch,           { 98425, 190500},{ 0, 0,  98425, 190500}},
199     { FORM_USER, wsz634Envelope,               { 92075, 165100},{ 0, 0,  92075, 165100}},
200     { FORM_USER, wszUSStdFanfold,              {377825, 279400},{ 0, 0, 377825, 279400}},
201     { FORM_USER, wszGermanStdFanfold,          {215900, 304800},{ 0, 0, 215900, 304800}},
202     { FORM_USER, wszGermanLegalFanfold,        {215900, 330200},{ 0, 0, 215900, 330200}},
203 // add more, I'm lazy
204     { FORM_USER, wszDoubleJapanPostcardRotated,{148000, 200000},{ 0, 0, 148000, 200000}},
205 //
206     { FORM_USER, wszPRCEnvelope10Rotated,      {458000, 324009},{ 0, 0, 458000, 324009}},
207     { FORM_USER, 0,                            {     0,      0},{ 0, 0,      0,      0}}
208 };
209 
210 //
211 // Form information Registry entry stucture, in correct format.
212 //
213 // Example : 11 x 17  REG_BINARY  68 43 04 00 b8 96 06 00 00 00 00 00 00 00 00 00 68 43 04 00 b8 96 06 00 01 00 00 00 02 00 00 00
214 //                               [        Size           |               ImageableArea                   | Index 1 + |   Flags   ] , is FORM_PRINTER.
215 //
216 typedef struct _REGISTRYFORMINFO
217 {
218     SIZEL Size;
219     RECTL ImageableArea;
220     DWORD Index;
221     DWORD Flags;
222 } REGISTRYFORMINFO, *PREGISTRYFORMINFO;
223 
224 HKEY hFormCKey = NULL;
225 HKEY hFormsKey = NULL;
226 
227 BOOL
228 InitializeFormList(VOID)
229 {
230     DWORD dwErrorCode;
231     PFORM_INFO_LIST pfil;
232     REGISTRYFORMINFO rfi;
233 
234     FIXME("InitializeFormList\n");
235 
236     dwErrorCode = (DWORD)RegCreateKeyExW( HKEY_LOCAL_MACHINE,
237                                          L"SYSTEM\\CurrentControlSet\\Control\\Print\\Forms",
238                                           0,
239                                           NULL,
240                                           REG_OPTION_VOLATILE,
241                                           KEY_ALL_ACCESS,
242                                           NULL,
243                                          &hFormCKey,
244                                           NULL ); // KEY_OPENED_EXISTING_KEY );
245 
246     if ( dwErrorCode != ERROR_SUCCESS && dwErrorCode != ERROR_ALREADY_EXISTS )
247     {
248         ERR("RegCreateKeyExW failed for the Forms with error %lu!\n", dwErrorCode);
249         goto Cleanup;
250     }
251 
252     // Open some registry keys and leave them open. We need them multiple times throughout the Local Spooler.
253     dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Print\\Forms", 0, KEY_ALL_ACCESS, &hFormsKey);
254     if (dwErrorCode != ERROR_SUCCESS)
255     {
256         ERR("RegOpenKeyExW failed for \"Forms\" with error %lu!\n", dwErrorCode);
257         goto Cleanup;
258     }
259 
260     _dwLastForm = 1;
261 
262     InitializeListHead(&FormList);
263 
264     {
265         int i = 0, Size;
266         while ( BuiltInForms[ i ].pName != NULL )
267         {
268             TRACE("InitializeFormList L s %S\n",BuiltInForms[ i ].pName );
269 
270             Size = sizeof(FORM_INFO_LIST) + ((wcslen(BuiltInForms[ i ].pName) + 1) * sizeof(WCHAR));
271 
272             pfil = DllAllocSplMem( Size );
273 
274             pfil->pName         = wcscpy( (PWSTR)(pfil+1), BuiltInForms[ i ].pName );
275             pfil->Flags         = BuiltInForms[ i ].Flags;
276             pfil->Size          = BuiltInForms[ i ].Size;
277             pfil->ImageableArea = BuiltInForms[ i ].ImageableArea;
278             pfil->Sig           = FORMINFOSIG;
279             pfil->Index         = _dwLastForm++;
280             pfil->pKeyword      = NULL;
281             pfil->StringType    = STRING_NONE;
282             pfil->pMuiDll       = NULL;
283             pfil->dwResourceId  = 0;
284             pfil->pDisplayName  = NULL;
285             pfil->wLangId       = 0;
286 
287             InsertTailList( &FormList, &pfil->List );
288 
289             rfi.Size          = pfil->Size;
290             rfi.ImageableArea = pfil->ImageableArea;
291             rfi.Index         = pfil->Index;
292             rfi.Flags         = pfil->Flags;
293 
294             dwErrorCode = RegSetValueExW( hFormsKey, pfil->pName, 0, REG_BINARY, (PBYTE)&rfi, sizeof( rfi ) );
295             if ( dwErrorCode == ERROR_SUCCESS )
296             {
297                 TRACE("Init : RQVEW : %S added\n",pfil->pName);
298             }
299 
300             i++;
301         }
302     }
303 
304 Cleanup:
305     return TRUE;
306 }
307 
308 PFORM_INFO_LIST
309 FASTCALL
310 FindForm( WCHAR * pFormName, WCHAR * pKeyword )
311 {
312     PLIST_ENTRY ListEntry;
313     PFORM_INFO_LIST pfil;
314 
315     ListEntry = FormList.Flink;
316 
317     while (ListEntry != &FormList)
318     {
319         pfil = CONTAINING_RECORD(ListEntry, FORM_INFO_LIST, List);
320 
321         ListEntry = ListEntry->Flink;
322 
323         if ( pFormName && !_wcsicmp( pfil->pName, pFormName ) )
324             return pfil;
325 
326         if ( pKeyword && !_wcsicmp( (WCHAR*)pfil->pKeyword, pKeyword ) )
327             return pfil;
328     }
329     return NULL;
330 }
331 
332 static void
333 _LocalGetFormLevel1(PFORM_INFO_LIST pfil, PFORM_INFO_1W* ppFormInfo, PBYTE* ppFormInfoEnd, PDWORD pcbNeeded)
334 {
335     DWORD n;
336     PCWSTR pwszStrings[1];
337 
338     pwszStrings[0] = pfil->pName;
339 
340     // Calculate the string lengths.
341     if (!ppFormInfo)
342     {
343         for (n = 0; n < _countof(pwszStrings); ++n)
344         {
345             *pcbNeeded += (wcslen(pwszStrings[n]) + 1) * sizeof(WCHAR);
346         }
347 
348         *pcbNeeded += sizeof(FORM_INFO_1W);
349         return;
350     }
351 
352     (*ppFormInfo)->Flags         = pfil->Flags;
353     (*ppFormInfo)->Size          = pfil->Size;
354     (*ppFormInfo)->ImageableArea = pfil->ImageableArea;
355 
356     // Finally copy the structure and advance to the next one in the output buffer.
357     *ppFormInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppFormInfo), dwFormInfo1Offsets, *ppFormInfoEnd);
358     (*ppFormInfo)++;
359 }
360 
361 static void
362 _LocalGetFormLevel2(PFORM_INFO_LIST pfil, PFORM_INFO_2W* ppFormInfo, PBYTE* ppFormInfoEnd, PDWORD pcbNeeded)
363 {
364     DWORD n;
365     PCWSTR pwszStrings[4];
366 
367     pwszStrings[0] = pfil->pName;
368     pwszStrings[1] = (PCWSTR)pfil->pKeyword;
369     pwszStrings[2] = pfil->pMuiDll;
370     pwszStrings[3] = pfil->pDisplayName;
371 
372     // Calculate the string lengths.
373     if (!ppFormInfo)
374     {
375         for (n = 0; n < _countof(pwszStrings); ++n)
376         {
377             if (pwszStrings[n])
378             {
379                 *pcbNeeded += (wcslen(pwszStrings[n]) + 1) * sizeof(WCHAR);
380             }
381         }
382         *pcbNeeded += sizeof(FORM_INFO_2W);
383         return;
384     }
385 
386     (*ppFormInfo)->Flags         = pfil->Flags;
387     (*ppFormInfo)->Size          = pfil->Size;
388     (*ppFormInfo)->ImageableArea = pfil->ImageableArea;
389     (*ppFormInfo)->StringType    = pfil->StringType; //// If caller is remote, set STRING_LANGPAIR always;
390     (*ppFormInfo)->dwResourceId  = pfil->dwResourceId;
391 
392     // Finally copy the structure and advance to the next one in the output buffer.
393     *ppFormInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppFormInfo), dwFormInfo2Offsets, *ppFormInfoEnd);
394     (*ppFormInfo)++;
395 }
396 
397 typedef void (*PLocalGetFormLevelFunc)(PFORM_INFO_LIST, PVOID, PBYTE*, PDWORD);
398 
399 static const PLocalGetFormLevelFunc pfnGetFormLevels[] = {
400     NULL,
401     (PLocalGetFormLevelFunc)&_LocalGetFormLevel1,
402     (PLocalGetFormLevelFunc)&_LocalGetFormLevel2
403 };
404 
405 //
406 // API Functions
407 //
408 BOOL WINAPI
409 LocalAddForm(HANDLE hPrinter, DWORD Level, PBYTE pForm)
410 {
411     DWORD dwErrorCode, Size, cbNeeded;
412     PFORM_INFO_LIST pfil;
413     PLOCAL_HANDLE pHandle;
414     REGISTRYFORMINFO rfi;
415     PFORM_INFO_1W pfi1w = (PFORM_INFO_1W)pForm;
416     PFORM_INFO_2W pfi2w = (PFORM_INFO_2W)pForm;
417 
418     FIXME("AddForm(%p, %lu, %p)\n", hPrinter, Level, pForm);
419 
420     // Check if this is a printer handle.
421     pHandle = (PLOCAL_HANDLE)hPrinter;
422     if (pHandle->HandleType != HandleType_Printer)
423     {
424         dwErrorCode = ERROR_INVALID_HANDLE;
425         goto Cleanup;
426     }
427 
428     // Only support 1 & 2
429     if (Level < 1 || Level > 2)
430     {
431         // The caller supplied an invalid level.
432         dwErrorCode = ERROR_INVALID_LEVEL;
433         goto Cleanup;
434     }
435 
436     pfil = FindForm( pfi1w->pName, NULL );
437     if ( pfil )
438     {
439         dwErrorCode = ERROR_FILE_EXISTS;
440         goto Cleanup;
441     }
442 
443     dwErrorCode = RegQueryValueExW( hFormsKey, pfi1w->pName, NULL, NULL, NULL, &cbNeeded );
444     if ( dwErrorCode == ERROR_SUCCESS )
445     {
446         dwErrorCode = ERROR_FILE_EXISTS;
447         goto Cleanup;
448     }
449 
450     if ( wcslen(pfi1w->pName) > FORMMAXNAMESIZE ) // Limit REG Name size.
451     {
452         dwErrorCode = ERROR_INVALID_PARAMETER;
453         goto Cleanup;
454     }
455 
456     Size = sizeof(FORM_INFO_LIST) + ((MAX_PATH + 1) * sizeof(WCHAR));
457 
458     pfil = DllAllocSplMem( Size );
459     if ( !pfil )
460     {
461         dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
462         goto Cleanup;
463     }
464 
465     pfil->Sig           = FORMINFOSIG;
466     pfil->Index         = _dwLastForm++;
467     pfil->pName         = wcscpy( (PWSTR)(pfil+1), pfi1w->pName );
468     pfil->Flags         = pfi1w->Flags;
469     pfil->Size          = pfi1w->Size;
470     pfil->ImageableArea = pfi1w->ImageableArea;
471     pfil->StringType    = STRING_NONE;
472 
473     if ( Level > 1 )
474     {
475         pfil->pKeyword     = pfi2w->pKeyword;
476         pfil->pMuiDll      = pfi2w->pMuiDll;
477         pfil->pDisplayName = pfi2w->pDisplayName;
478         pfil->StringType   = pfi2w->StringType;
479         pfil->dwResourceId = pfi2w->dwResourceId;
480     }
481 
482     rfi.Size          = pfil->Size;
483     rfi.ImageableArea = pfil->ImageableArea;
484     rfi.Index         = pfil->Index;
485     rfi.Flags         = pfil->Flags;
486 
487     dwErrorCode = RegSetValueExW( hFormsKey, pfil->pName, 0, REG_BINARY, (PBYTE)&rfi, sizeof( rfi ) );
488 
489     BroadcastChange(pHandle);
490 
491     InsertTailList( &FormList, &pfil->List );
492 
493 Cleanup:
494     SetLastError(dwErrorCode);
495     return (dwErrorCode == ERROR_SUCCESS);
496 }
497 
498 BOOL WINAPI
499 LocalDeleteForm(HANDLE hPrinter, PWSTR pFormName)
500 {
501     DWORD dwErrorCode, cbNeeded;
502     PFORM_INFO_LIST pfil;
503     REGISTRYFORMINFO rfi;
504     PLOCAL_HANDLE pHandle;
505 
506     FIXME("DeleteForm(%p, %S)\n", hPrinter, pFormName);
507 
508     // Check if this is a printer handle.
509     pHandle = (PLOCAL_HANDLE)hPrinter;
510     if (pHandle->HandleType != HandleType_Printer)
511     {
512         dwErrorCode = ERROR_INVALID_HANDLE;
513         goto Cleanup;
514     }
515 
516     pfil = FindForm( pFormName, NULL );
517     if ( !pfil )
518     {
519         dwErrorCode = ERROR_INVALID_PARAMETER;
520         goto Cleanup;
521     }
522 
523     dwErrorCode = RegQueryValueExW( hFormsKey, pFormName, NULL, NULL, (PBYTE)&rfi, &cbNeeded );
524     if ( dwErrorCode != ERROR_SUCCESS )
525     {
526         goto Cleanup;
527     }
528 
529     dwErrorCode = RegDeleteValueW(hFormsKey, pFormName);
530     if ( dwErrorCode != ERROR_SUCCESS )
531     {
532         goto Cleanup;
533     }
534 
535     RemoveEntryList(&pfil->List);
536 
537     DllFreeSplMem(pfil);
538 
539     BroadcastChange(pHandle);
540 
541     dwErrorCode = ERROR_SUCCESS;
542 
543 Cleanup:
544     SetLastError(dwErrorCode);
545     return (dwErrorCode == ERROR_SUCCESS);
546 }
547 
548 BOOL WINAPI
549 LocalEnumForms(HANDLE hPrinter, DWORD Level, PBYTE pForm, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
550 {
551     DWORD dwErrorCode;
552     PFORM_INFO_LIST pfil = NULL;
553     PBYTE pEnd = &pForm[cbBuf];
554     PLOCAL_HANDLE pHandle;
555     PLIST_ENTRY ListEntry;
556 
557     FIXME("EnumForms(%p, %lu, %p, %lu, %p, %p)\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
558 
559     // Check if this is a printer handle.
560     pHandle = (PLOCAL_HANDLE)hPrinter;
561     if (pHandle->HandleType != HandleType_Printer)
562     {
563         dwErrorCode = ERROR_INVALID_HANDLE;
564         goto Cleanup;
565     }
566 
567     // Only support 1 & 2
568     if (Level < 1 || Level > 2)
569     {
570         // The caller supplied an invalid level.
571         dwErrorCode = ERROR_INVALID_LEVEL;
572         goto Cleanup;
573     }
574 
575     // Count the required buffer size.
576     *pcbNeeded = 0;
577 
578     ListEntry = FormList.Flink;
579 
580     if (IsListEmpty(ListEntry))
581     {
582         dwErrorCode = ERROR_INVALID_PARAMETER;
583         goto Cleanup;
584     }
585 
586     while ( ListEntry != &FormList )
587     {
588         pfil = CONTAINING_RECORD(ListEntry, FORM_INFO_LIST, List);
589         ListEntry = ListEntry->Flink;
590 
591         pfnGetFormLevels[Level](pfil, NULL, NULL, pcbNeeded);
592     }
593 
594     // Check if the supplied buffer is large enough.
595     if (cbBuf < *pcbNeeded)
596     {
597         ERR("Insuffisient Buffer size\n");
598         dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
599         goto Cleanup;
600     }
601 
602     // Copy over the information.
603     pEnd = &pForm[*pcbNeeded];
604 
605     ListEntry = FormList.Flink;
606 
607     while ( ListEntry != &FormList )
608     {
609         pfil = CONTAINING_RECORD(ListEntry, FORM_INFO_LIST, List);
610         ListEntry = ListEntry->Flink;
611 
612         pfnGetFormLevels[Level](pfil, &pForm, &pEnd, NULL);
613         (*pcReturned)++;
614     }
615 
616     dwErrorCode = ERROR_SUCCESS;
617 
618 Cleanup:
619     SetLastError(dwErrorCode);
620     return (dwErrorCode == ERROR_SUCCESS);
621 }
622 
623 BOOL WINAPI
624 LocalGetForm(HANDLE hPrinter, PWSTR pFormName, DWORD Level, PBYTE pForm, DWORD cbBuf, PDWORD pcbNeeded)
625 {
626     DWORD dwErrorCode;
627     PFORM_INFO_LIST pfil;
628     PBYTE pEnd = &pForm[cbBuf];
629     PLOCAL_HANDLE pHandle;
630 
631     FIXME("GetForm(%p, %S, %lu, %p, %lu, %p)\n", hPrinter, pFormName, Level, pForm, cbBuf, pcbNeeded);
632 
633     // Check if this is a printer handle.
634     pHandle = (PLOCAL_HANDLE)hPrinter;
635     if (pHandle->HandleType != HandleType_Printer)
636     {
637         dwErrorCode = ERROR_INVALID_HANDLE;
638         goto Cleanup;
639     }
640 
641     // Only support 1 & 2
642     if (Level < 1 || Level > 2)
643     {
644         // The caller supplied an invalid level.
645         dwErrorCode = ERROR_INVALID_LEVEL;
646         goto Cleanup;
647     }
648 
649     pfil = FindForm( pFormName, NULL );
650     if ( !pfil )
651     {
652         dwErrorCode = ERROR_INVALID_PARAMETER;
653         goto Cleanup;
654     }
655 
656     // Count the required buffer size.
657     *pcbNeeded = 0;
658 
659     pfnGetFormLevels[Level](pfil, NULL, NULL, pcbNeeded);
660 
661     // Check if the supplied buffer is large enough.
662     if (cbBuf < *pcbNeeded)
663     {
664         ERR("Insuffisient Buffer size\n");
665         dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
666         goto Cleanup;
667     }
668 
669     // Copy over the information.
670     pEnd = &pForm[*pcbNeeded];
671 
672     pfnGetFormLevels[Level](pfil, &pForm, &pEnd, NULL);
673 
674     dwErrorCode = ERROR_SUCCESS;
675 
676 Cleanup:
677     SetLastError(dwErrorCode);
678     return (dwErrorCode == ERROR_SUCCESS);
679 }
680 
681 BOOL WINAPI
682 LocalSetForm(HANDLE hPrinter, PWSTR pFormName, DWORD Level, PBYTE pForm)
683 {
684     DWORD dwErrorCode, cbNeeded;
685     PFORM_INFO_LIST pfil;
686     REGISTRYFORMINFO rfi;
687     PLOCAL_HANDLE pHandle;
688     PFORM_INFO_1W pfi1w = (PFORM_INFO_1W)pForm;
689     PFORM_INFO_2W pfi2w = (PFORM_INFO_2W)pForm;
690 
691     FIXME("SetFormW(%p, %S, %lu, %p)\n", hPrinter, pFormName, Level, pForm);
692 
693     // Check if this is a printer handle.
694     pHandle = (PLOCAL_HANDLE)hPrinter;
695     if (pHandle->HandleType != HandleType_Printer)
696     {
697         dwErrorCode = ERROR_INVALID_HANDLE;
698         goto Cleanup;
699     }
700 
701     // Only support 1 & 2
702     if (Level < 1 || Level > 2)
703     {
704         // The caller supplied an invalid level.
705         dwErrorCode = ERROR_INVALID_LEVEL;
706         goto Cleanup;
707     }
708 
709     pfil = FindForm( pFormName, NULL );
710     if ( !pfil )
711     {
712         dwErrorCode = ERROR_INVALID_PARAMETER;
713         goto Cleanup;
714     }
715 
716     dwErrorCode = RegQueryValueExW( hFormsKey, pFormName, NULL, NULL, (PBYTE)&rfi, &cbNeeded) ;
717     if ( dwErrorCode != ERROR_SUCCESS )
718     {
719         goto Cleanup;
720     }
721 
722     pfil->Flags         = pfi1w->Flags;
723     pfil->Size          = pfi1w->Size;
724     pfil->ImageableArea = pfi1w->ImageableArea;
725 
726     if ( Level > 1 )
727     {
728         pfil->pKeyword     = pfi2w->pKeyword;
729         pfil->pMuiDll      = pfi2w->pMuiDll;
730         pfil->pDisplayName = pfi2w->pDisplayName;
731         pfil->StringType   = pfi2w->StringType;
732         pfil->dwResourceId = pfi2w->dwResourceId;
733     }
734 
735     rfi.Size          = pfil->Size;
736     rfi.ImageableArea = pfil->ImageableArea;
737     rfi.Flags         = pfil->Flags;
738 
739     dwErrorCode = RegSetValueExW( hFormsKey, pfil->pName, 0, REG_BINARY, (PBYTE)&rfi, sizeof( rfi ) );
740 
741     BroadcastChange(pHandle);
742 
743 Cleanup:
744     SetLastError(dwErrorCode);
745     return (dwErrorCode == ERROR_SUCCESS);
746 }
747