Implemented SHCreateStdEnumFmtEtc.
[wine] / dlls / shell32 / dialogs.c
1 /*
2  *      common shell dialogs
3  *
4  * Copyright 2000 Juergen Schmied
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <string.h>
25 #include <stdio.h>
26 #include "winerror.h"
27 #include "winreg.h"
28 #include "commdlg.h"
29 #include "wine/debug.h"
30
31 #include "shellapi.h"
32 #include "shlobj.h"
33 #include "shell32_main.h"
34 #include "undocshell.h"
35
36 typedef struct
37     {
38         HWND hwndOwner ;
39         HICON hIcon ;
40         LPCSTR lpstrDirectory ;
41         LPCSTR lpstrTitle ;
42         LPCSTR lpstrDescription ;
43         UINT uFlags ;
44     } RUNFILEDLGPARAMS ;
45
46 typedef BOOL (*LPFNOFN) (OPENFILENAMEA *) ;
47
48 WINE_DEFAULT_DEBUG_CHANNEL(shell);
49 BOOL CALLBACK RunDlgProc (HWND, UINT, WPARAM, LPARAM) ;
50 void FillList (HWND, char *) ;
51
52
53 /*************************************************************************
54  * PickIconDlg                                  [SHELL32.62]
55  *
56  */
57 BOOL WINAPI PickIconDlg(
58         HWND hwndOwner,
59         LPSTR lpstrFile,
60         DWORD nMaxFile,
61         LPDWORD lpdwIconIndex)
62 {
63         FIXME("(%08x,%s,%08lx,%p):stub.\n",
64           hwndOwner, lpstrFile, nMaxFile,lpdwIconIndex);
65         return 0xffffffff;
66 }
67
68 /*************************************************************************
69  * RunFileDlg                                   [SHELL32.61]
70  *
71  * NOTES
72  *     Original name: RunFileDlg (exported by ordinal)
73  */
74 void WINAPI RunFileDlg(
75         HWND hwndOwner,
76         HICON hIcon,
77         LPCSTR lpstrDirectory,
78         LPCSTR lpstrTitle,
79         LPCSTR lpstrDescription,
80         UINT uFlags)
81 {
82
83     RUNFILEDLGPARAMS rfdp;
84     HRSRC hRes;
85     LPVOID template;
86     TRACE("\n");
87
88     rfdp.hwndOwner        = hwndOwner;
89     rfdp.hIcon            = hIcon;
90     rfdp.lpstrDirectory   = lpstrDirectory;
91     rfdp.lpstrTitle       = lpstrTitle;
92     rfdp.lpstrDescription = lpstrDescription;
93     rfdp.uFlags           = uFlags;
94
95     if(!(hRes = FindResourceA(shell32_hInstance, "SHELL_RUN_DLG", RT_DIALOGA)))
96         {
97         MessageBoxA (hwndOwner, "Couldn't find dialog.", "Nix", MB_OK) ;
98         return;
99         }
100     if(!(template = (LPVOID)LoadResource(shell32_hInstance, hRes)))
101         {
102         MessageBoxA (hwndOwner, "Couldn't load dialog.", "Nix", MB_OK) ;
103         return;
104         }
105
106     DialogBoxIndirectParamA(GetWindowLongA( hwndOwner, GWL_HINSTANCE ),
107                                       template, hwndOwner, RunDlgProc, (LPARAM)&rfdp);
108
109 }
110
111 /* Dialog procedure for RunFileDlg */
112 BOOL CALLBACK RunDlgProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
113     {
114     int ic ;
115     char *psz, szMsg[256] ;
116     static RUNFILEDLGPARAMS *prfdp = NULL ;
117
118     switch (message)
119         {
120         case WM_INITDIALOG :
121             prfdp = (RUNFILEDLGPARAMS *)lParam ;
122             SetWindowTextA (hwnd, prfdp->lpstrTitle) ;
123             SetClassLongA (hwnd, GCL_HICON, prfdp->hIcon) ;
124             SendMessageA (GetDlgItem (hwnd, 12297), STM_SETICON, (WPARAM)LoadIconA ((HINSTANCE)NULL, IDI_WINLOGOA), 0) ;
125             FillList (GetDlgItem (hwnd, 12298), NULL) ;
126             SetFocus (GetDlgItem (hwnd, 12298)) ;
127             return TRUE ;
128
129         case WM_COMMAND :
130             {
131             STARTUPINFOA si ;
132             PROCESS_INFORMATION pi ;
133
134             si.cb = sizeof (STARTUPINFOA) ;
135             si.lpReserved = NULL ;
136             si.lpDesktop = NULL ;
137             si.lpTitle = NULL ;
138             si.dwX = 0 ;
139             si.dwY = 0 ;
140             si.dwXSize = 0 ;
141             si.dwYSize = 0 ;
142             si.dwXCountChars = 0 ;
143             si.dwYCountChars = 0 ;
144             si.dwFillAttribute = 0 ;
145             si.dwFlags = 0 ;
146             si.cbReserved2 = 0 ;
147             si.lpReserved2 = NULL ;
148
149             switch (LOWORD (wParam))
150                 {
151                 case IDOK :
152                     {
153                     HWND htxt = (HWND)NULL ;
154                     if ((ic = GetWindowTextLengthA (htxt = GetDlgItem (hwnd, 12298))))
155                         {
156                         psz = malloc (ic + 2) ;
157                         GetWindowTextA (htxt, psz, ic + 1) ;
158
159                         if (!CreateProcessA (NULL, psz, NULL, NULL, TRUE,
160                             NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi))
161                             {
162                             char *pszSysMsg = NULL ;
163                             FormatMessageA (
164                                 FORMAT_MESSAGE_ALLOCATE_BUFFER |
165                                 FORMAT_MESSAGE_FROM_SYSTEM |
166                                 FORMAT_MESSAGE_IGNORE_INSERTS,
167                                 NULL, GetLastError (),
168                                 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
169                                 (LPSTR)&pszSysMsg, 0, NULL
170                                 ) ;
171                             sprintf (szMsg, "Error: %s", pszSysMsg) ;
172                             LocalFree ((HLOCAL)pszSysMsg) ;
173                             MessageBoxA (hwnd, szMsg, "Nix", MB_OK | MB_ICONEXCLAMATION) ;
174
175                             free (psz) ;
176                             SendMessageA (htxt, CB_SETEDITSEL, 0, MAKELPARAM (0, -1)) ;
177                             return TRUE ;
178                             }
179                         FillList (htxt, psz) ;
180                         free (psz) ;
181                         EndDialog (hwnd, 0) ;
182                         }
183                     }
184
185                 case IDCANCEL :
186                     EndDialog (hwnd, 0) ;
187                     return TRUE ;
188
189                 case 12288 :
190                     {
191                     HMODULE hComdlg = (HMODULE)NULL ;
192                     LPFNOFN ofnProc = NULL ;
193                     static char szFName[1024] = "", szFileTitle[256] = "", szInitDir[768] = "" ;
194                     static OPENFILENAMEA ofn =
195                         {
196                         sizeof (OPENFILENAMEA),
197                         (HWND)NULL,
198                         (HINSTANCE)NULL,
199                         "Executable Files\0*.exe\0All Files\0*.*\0\0\0\0",
200                         (LPSTR)NULL,
201                         0,
202                         0,
203                         szFName,
204                         1023,
205                         szFileTitle,
206                         255,
207                         (LPCSTR)szInitDir,
208                         "Browse",
209                         OFN_ENABLESIZING | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST,
210                         0,
211                         0,
212                         (LPCSTR)NULL,
213                         0,
214                         (LPOFNHOOKPROC)NULL,
215                         (LPCSTR)NULL
216                         } ;
217
218                     ofn.hwndOwner = hwnd ;
219
220                     if ((HMODULE)NULL == (hComdlg = LoadLibraryExA ("comdlg32", (HANDLE)NULL, 0)))
221                         {
222                         MessageBoxA (hwnd, "Unable to display dialog box (LoadLibraryEx) !", "Nix", MB_OK | MB_ICONEXCLAMATION) ;
223                         return TRUE ;
224                         }
225
226                     if ((LPFNOFN)NULL == (ofnProc = (LPFNOFN)GetProcAddress (hComdlg, "GetOpenFileNameA")))
227                         {
228                         MessageBoxA (hwnd, "Unable to display dialog box (GetProcAddress) !", "Nix", MB_OK | MB_ICONEXCLAMATION) ;
229                         return TRUE ;
230                         }
231
232                     ofnProc (&ofn) ;
233
234                     SetFocus (GetDlgItem (hwnd, IDOK)) ;
235                     SetWindowTextA (GetDlgItem (hwnd, 12298), szFName) ;
236                     SendMessageA (GetDlgItem (hwnd, 12298), CB_SETEDITSEL, 0, MAKELPARAM (0, -1)) ;
237                     SetFocus (GetDlgItem (hwnd, IDOK)) ;
238
239                     FreeLibrary (hComdlg) ;
240
241                     return TRUE ;
242                     }
243                 }
244             return TRUE ;
245             }
246         }
247     return FALSE ;
248     }
249
250 /* This grabs the MRU list from the registry and fills the combo for the "Run" dialog above */
251 void FillList (HWND hCb, char *pszLatest)
252     {
253     HKEY hkey ;
254 /*    char szDbgMsg[256] = "" ; */
255     char *pszList = NULL, *pszCmd = NULL, cMatch = 0, cMax = 0x60, szIndex[2] = "-" ;
256     DWORD icList = 0, icCmd = 0 ;
257     int Nix ;
258
259     SendMessageA (hCb, CB_RESETCONTENT, 0, 0) ;
260
261     if (ERROR_SUCCESS != RegCreateKeyExA (
262         HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\RunMRU",
263         0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL))
264         MessageBoxA (hCb, "Unable to open registry key !", "Nix", MB_OK) ;
265
266     RegQueryValueExA (hkey, "MRUList", NULL, NULL, NULL, &icList) ;
267
268     if (icList > 0)
269         {
270         pszList = malloc (icList) ;
271         if (ERROR_SUCCESS != RegQueryValueExA (hkey, "MRUList", NULL, NULL, pszList, &icList))
272             MessageBoxA (hCb, "Unable to grab MRUList !", "Nix", MB_OK) ;
273         }
274     else
275         {
276         pszList = malloc (icList = 1) ;
277         pszList[0] = 0 ;
278         }
279
280     for (Nix = 0 ; Nix < icList - 1 ; Nix++)
281         {
282         if (pszList[Nix] > cMax)
283             cMax = pszList[Nix] ;
284
285         szIndex[0] = pszList[Nix] ;
286
287         if (ERROR_SUCCESS != RegQueryValueExA (hkey, szIndex, NULL, NULL, NULL, &icCmd))
288             MessageBoxA (hCb, "Unable to grab size of index", "Nix", MB_OK) ;
289         pszCmd = realloc (pszCmd, icCmd) ;
290         if (ERROR_SUCCESS != RegQueryValueExA (hkey, szIndex, NULL, NULL, pszCmd, &icCmd))
291             MessageBoxA (hCb, "Unable to grab index", "Nix", MB_OK) ;
292
293         if (NULL != pszLatest)
294             {
295             if (!strcasecmp (pszCmd, pszLatest))
296                 {
297                 /*
298                 sprintf (szDbgMsg, "Found existing (%d).\n", Nix) ;
299                 MessageBoxA (hCb, szDbgMsg, "Nix", MB_OK) ;
300                 */
301                 SendMessageA (hCb, CB_INSERTSTRING, 0, (LPARAM)pszCmd) ;
302                 SetWindowTextA (hCb, pszCmd) ;
303                 SendMessageA (hCb, CB_SETEDITSEL, 0, MAKELPARAM (0, -1)) ;
304
305                 cMatch = pszList[Nix] ;
306                 memmove (&pszList[1], pszList, Nix) ;
307                 pszList[0] = cMatch ;
308                 continue ;
309                 }
310             }
311
312         if (26 != icList - 1 || icList - 2 != Nix || cMatch || NULL == pszLatest)
313             {
314             /*
315             sprintf (szDbgMsg, "Happily appending (%d).\n", Nix) ;
316             MessageBoxA (hCb, szDbgMsg, "Nix", MB_OK) ;
317             */
318             SendMessageA (hCb, CB_ADDSTRING, 0, (LPARAM)pszCmd) ;
319             if (!Nix)
320                 {
321                 SetWindowTextA (hCb, pszCmd) ;
322                 SendMessageA (hCb, CB_SETEDITSEL, 0, MAKELPARAM (0, -1)) ;
323                 }
324
325             }
326         else
327             {
328             /*
329             sprintf (szDbgMsg, "Doing loop thing.\n") ;
330             MessageBoxA (hCb, szDbgMsg, "Nix", MB_OK) ;
331             */
332             SendMessageA (hCb, CB_INSERTSTRING, 0, (LPARAM)pszLatest) ;
333             SetWindowTextA (hCb, pszLatest) ;
334             SendMessageA (hCb, CB_SETEDITSEL, 0, MAKELPARAM (0, -1)) ;
335
336             cMatch = pszList[Nix] ;
337             memmove (&pszList[1], pszList, Nix) ;
338             pszList[0] = cMatch ;
339             szIndex[0] = cMatch ;
340             RegSetValueExA (hkey, szIndex, 0, REG_SZ, pszLatest, strlen (pszLatest) + 1) ;
341             }
342         }
343
344     if (!cMatch && NULL != pszLatest)
345         {
346         /*
347         sprintf (szDbgMsg, "Simply inserting (increasing list).\n") ;
348         MessageBoxA (hCb, szDbgMsg, "Nix", MB_OK) ;
349         */
350         SendMessageA (hCb, CB_INSERTSTRING, 0, (LPARAM)pszLatest) ;
351         SetWindowTextA (hCb, pszLatest) ;
352         SendMessageA (hCb, CB_SETEDITSEL, 0, MAKELPARAM (0, -1)) ;
353
354         cMatch = ++cMax ;
355         pszList = realloc (pszList, ++icList) ;
356         memmove (&pszList[1], pszList, icList - 1) ;
357         pszList[0] = cMatch ;
358         szIndex[0] = cMatch ;
359         RegSetValueExA (hkey, szIndex, 0, REG_SZ, pszLatest, strlen (pszLatest) + 1) ;
360         }
361
362     RegSetValueExA (hkey, "MRUList", 0, REG_SZ, pszList, strlen (pszList) + 1) ;
363
364     free (pszCmd) ;
365     free (pszList) ;
366     }
367
368 /*************************************************************************
369  * ExitWindowsDialog                            [SHELL32.60]
370  *
371  * NOTES
372  *     exported by ordinal
373  */
374 void WINAPI ExitWindowsDialog (HWND hWndOwner)
375 {
376         TRACE("(0x%08x)\n", hWndOwner);
377         if (MessageBoxA( hWndOwner, "Do you want to exit WINE?", "Shutdown", MB_YESNO|MB_ICONQUESTION) == IDYES)
378         {
379           SendMessageA ( hWndOwner, WM_QUIT, 0, 0);
380         }
381 }