1 /*
2  * Implementation of the Printer User Interface Dialogs
3  *
4  * Copyright 2006-2007 Detlef Riekenberg
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #include <stdarg.h>
22 
23 #define COBJMACROS
24 
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winuser.h"
29 #include "winreg.h"
30 #include "winver.h"
31 #include "winnls.h"
32 #include "shellapi.h"
33 
34 #include "wine/debug.h"
35 #include "printui_private.h"
36 
37 WINE_DEFAULT_DEBUG_CHANNEL(printui);
38 
39 /* ################################# */
40 
41 /* Must be in order with OPT_*      */
42 static const WCHAR optionsW[OPT_MAX+1]={'a','b','c','f','h','j','l','m','n','t','r','v',0};
43 
44 /* Must be in order with FLAG_*     */
45 static const WCHAR flagsW[FLAG_MAX+1]={'q','w','y','z','Z',0};
46 
47 
48 /* ################################
49  * get_next_wstr() [Internal]
50  *
51  * Get the next WSTR, when available
52  *
53  */
54 
55 static LPWSTR get_next_wstr(context_t * cx)
56 {
57     LPWSTR  ptr;
58 
59     ptr = cx->pNextCharW;
60     if (ptr && ptr[0]) {
61         cx->pNextCharW = NULL;
62         return ptr;
63     }
64 
65     /* Get the next Parameter, when available */
66     if (cx->next_arg < cx->argc) {
67         ptr = cx->argv[cx->next_arg];
68         cx->next_arg++;
69         cx->pNextCharW = NULL;
70         return ptr;
71     }
72     return NULL;
73 }
74 
75 
76 /* ################################
77  * get_next_wchar() [Internal]
78  *
79  * Get the next WCHAR from the Commandline or from the File (@ Filename)
80  *
81  * ToDo: Support Parameter from a File ( "@Filename" )
82  *
83  */
84 
85 static WCHAR get_next_wchar(context_t * cx, BOOL use_next_parameter)
86 {
87     WCHAR   c;
88 
89     /* Try the next WCHAR in the actual Parameter */
90     if (cx->pNextCharW) {
91         c = *cx->pNextCharW;
92         if (c) {
93             cx->pNextCharW++;
94             return c;
95         }
96         /* We reached the end of the Parameter */
97         cx->pNextCharW = NULL;
98     }
99 
100     /* Get the next Parameter, when available and allowed */
101     if ((cx->pNextCharW == NULL) && (cx->next_arg < cx->argc) && (use_next_parameter)) {
102         cx->pNextCharW = cx->argv[cx->next_arg];
103         cx->next_arg++;
104     }
105 
106     if (cx->pNextCharW) {
107         c = *cx->pNextCharW;
108         if (c) {
109             cx->pNextCharW++;
110         }
111         else
112         {
113             /* We reached the end of the Parameter */
114             cx->pNextCharW = NULL;
115         }
116         return c;
117     }
118     return '\0';
119 }
120 
121 /* ################################ */
122 static BOOL parse_rundll(context_t * cx)
123 {
124     LPWSTR  ptr;
125     DWORD   index;
126     WCHAR   txtW[2];
127     WCHAR   c;
128 
129 
130     c = get_next_wchar(cx, TRUE);
131     txtW[1] = '\0';
132 
133     while (c)
134     {
135 
136         while ( (c == ' ') || (c == '\t'))
137         {
138             c = get_next_wchar(cx, TRUE);
139         }
140         txtW[0] = c;
141 
142         if (c == '@') {
143             /* read commands from a File */
144             ptr = get_next_wstr(cx);
145             FIXME("redir not supported: %s\n", debugstr_w(ptr));
146             return FALSE;
147         }
148         else if (c == '/') {
149             c = get_next_wchar(cx, FALSE);
150             while ( c )
151             {
152                 txtW[0] = c;
153                 ptr = wcschr(optionsW, c);
154                 if (ptr) {
155                     index = ptr - optionsW;
156                     cx->options[index] = get_next_wstr(cx);
157                     TRACE(" opt: %s  %s\n", debugstr_w(txtW), debugstr_w(cx->options[index]));
158                     c = 0;
159                 }
160                 else
161                 {
162                     ptr = wcschr(flagsW, c);
163                     if (ptr) {
164                         index = ptr - flagsW;
165                         cx->flags[index] = TRUE;
166                         TRACE("flag: %s\n", debugstr_w(txtW));
167                     }
168                     else
169                     {
170                         cx->command = c;
171                         cx->subcommand = '\0';
172                         TRACE(" cmd: %s\n", debugstr_w(txtW));
173                     }
174 
175                     /* help has priority over all commands */
176                     if (c == '?') {
177                         return TRUE;
178                     }
179 
180                     c = get_next_wchar(cx, FALSE);
181 
182                     /* Some commands use two wchar */
183                     if ((cx->command == 'd') || (cx->command == 'g') || (cx->command == 'i') ||
184                         (cx->command == 'S') || (cx->command == 'X') ){
185                         cx->subcommand = c;
186                         txtW[0] = c;
187                         TRACE(" sub: %s\n", debugstr_w(txtW));
188                         c = get_next_wchar(cx, FALSE);
189                     }
190                 }
191             }
192             c = get_next_wchar(cx, TRUE);
193 
194         }
195         else
196         {
197             /* The commands 'S' and 'X' have additional Parameter */
198             if ((cx->command == 'S') || (cx->command == 'X')) {
199 
200                 /* the actual WCHAR is the start from the extra Parameter */
201                 cx->pNextCharW--;
202                 TRACE("%d extra Parameter, starting with %s\n", 1 + (cx->argc - cx->next_arg), debugstr_w(cx->pNextCharW));
203                 return TRUE;
204             }
205             FIXME("0x%x: %s is unknown\n", c, debugstr_wn(&c, 1));
206             return FALSE;
207         }
208 
209     }
210     return TRUE;
211 }
212 
213 /*****************************************************
214  *      DllMain
215  */
216 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
217 {
218     TRACE("(%p, %d, %p)\n",hinstDLL, fdwReason, lpvReserved);
219 
220     switch(fdwReason)
221     {
222         case DLL_WINE_PREATTACH:
223             return FALSE;           /* prefer native version */
224 
225         case DLL_PROCESS_ATTACH:
226             DisableThreadLibraryCalls( hinstDLL );
227             break;
228     }
229     return TRUE;
230 }
231 
232 
233 /*****************************************************
234  *  PrintUIEntryW                [printui.@]
235  *  Commandline-Interface for using printui.dll with rundll32.exe
236  *
237  */
238 void WINAPI PrintUIEntryW(HWND hWnd, HINSTANCE hInst, LPCWSTR pCommand, DWORD nCmdShow)
239 {
240     context_t cx;
241     BOOL  res = FALSE;
242 
243     TRACE("(%p, %p, %s, 0x%x)\n", hWnd, hInst, debugstr_w(pCommand), nCmdShow);
244 
245     memset(&cx, 0, sizeof(context_t));
246     cx.hWnd = hWnd;
247     cx.nCmdShow = nCmdShow;
248 
249     if ((pCommand) && (pCommand[0])) {
250         /* result is allocated with GlobalAlloc() */
251         cx.argv = CommandLineToArgvW(pCommand, &cx.argc);
252         TRACE("got %d args at %p\n", cx.argc, cx.argv);
253 
254         res = parse_rundll(&cx);
255     }
256 
257     if (res && cx.command) {
258         switch (cx.command)
259         {
260 
261             default:
262             {
263                 WCHAR   txtW[3];
264                 txtW[0] = cx.command;
265                 txtW[1] = cx.subcommand;
266                 txtW[2] = '\0';
267                 FIXME("command not implemented: %s\n", debugstr_w(txtW));
268             }
269         }
270     }
271 
272     if ((res == FALSE) || (cx.command == '\0')) {
273         FIXME("dialog: Printer / The operation was not successful\n");
274     }
275 
276     GlobalFree(cx.argv);
277 
278 }
279