push 8742e928a3d078c1d2cecb5ceee0ffde3118cbb7
[wine/hacks.git] / dlls / shell32 / dialogs.c
blob77eea186bf85fb9f0c7d93b1d9bc62bf3981a96a
1 /*
2 * common shell dialogs
4 * Copyright 2000 Juergen Schmied
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.
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.
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
21 #include "config.h"
22 #include "wine/port.h"
24 #include <string.h>
25 #include <stdarg.h>
26 #include <stdio.h>
27 #include "winerror.h"
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winreg.h"
31 #include "wingdi.h"
32 #include "winuser.h"
33 #include "commdlg.h"
34 #include "wine/debug.h"
36 #include "shellapi.h"
37 #include "shlobj.h"
38 #include "shell32_main.h"
39 #include "shresdef.h"
40 #include "undocshell.h"
42 typedef struct
44 HWND hwndOwner ;
45 HICON hIcon ;
46 LPCWSTR lpstrDirectory ;
47 LPCWSTR lpstrTitle ;
48 LPCWSTR lpstrDescription ;
49 UINT uFlags ;
50 } RUNFILEDLGPARAMS ;
52 typedef BOOL (WINAPI * LPFNOFN) (OPENFILENAMEW *) ;
54 WINE_DEFAULT_DEBUG_CHANNEL(shell);
55 static INT_PTR CALLBACK RunDlgProc (HWND, UINT, WPARAM, LPARAM) ;
56 static void FillList (HWND, char *, BOOL) ;
59 /*************************************************************************
60 * PickIconDlg [SHELL32.62]
63 BOOL WINAPI PickIconDlg(
64 HWND hwndOwner,
65 LPSTR lpstrFile,
66 DWORD nMaxFile,
67 LPDWORD lpdwIconIndex)
69 FIXME("(%p,%s,%08x,%p):stub.\n",
70 hwndOwner, lpstrFile, nMaxFile,lpdwIconIndex);
71 return 0xffffffff;
74 /*************************************************************************
75 * RunFileDlgW [internal]
77 * The Unicode function that is available as ordinal 61 on Windows NT/2000/XP/...
79 * SEE ALSO
80 * RunFileDlgAW
82 void WINAPI RunFileDlgW(
83 HWND hwndOwner,
84 HICON hIcon,
85 LPCWSTR lpstrDirectory,
86 LPCWSTR lpstrTitle,
87 LPCWSTR lpstrDescription,
88 UINT uFlags)
90 static const WCHAR resnameW[] = {'S','H','E','L','L','_','R','U','N','_','D','L','G',0};
91 RUNFILEDLGPARAMS rfdp;
92 HRSRC hRes;
93 LPVOID template;
94 TRACE("\n");
96 rfdp.hwndOwner = hwndOwner;
97 rfdp.hIcon = hIcon;
98 rfdp.lpstrDirectory = lpstrDirectory;
99 rfdp.lpstrTitle = lpstrTitle;
100 rfdp.lpstrDescription = lpstrDescription;
101 rfdp.uFlags = uFlags;
103 if (!(hRes = FindResourceW(shell32_hInstance, resnameW, (LPWSTR)RT_DIALOG)) ||
104 !(template = LoadResource(shell32_hInstance, hRes)))
106 ERR("Couldn't load SHELL_RUN_DLG resource\n");
107 ShellMessageBoxW(shell32_hInstance, hwndOwner, MAKEINTRESOURCEW(IDS_RUNDLG_ERROR), NULL, MB_OK | MB_ICONERROR);
108 return;
111 DialogBoxIndirectParamW(shell32_hInstance,
112 template, hwndOwner, RunDlgProc, (LPARAM)&rfdp);
116 /* Dialog procedure for RunFileDlg */
117 static INT_PTR CALLBACK RunDlgProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
119 RUNFILEDLGPARAMS *prfdp = (RUNFILEDLGPARAMS *)GetWindowLongPtrW(hwnd, DWLP_USER);
121 switch (message)
123 case WM_INITDIALOG :
124 prfdp = (RUNFILEDLGPARAMS *)lParam ;
125 SetWindowLongPtrW(hwnd, DWLP_USER, (LONG_PTR)prfdp);
127 if (prfdp->lpstrTitle)
128 SetWindowTextW(hwnd, prfdp->lpstrTitle);
129 if (prfdp->lpstrDescription)
130 SetWindowTextW(GetDlgItem(hwnd, IDC_RUNDLG_DESCRIPTION), prfdp->lpstrDescription);
131 if (prfdp->uFlags & RFF_NOBROWSE)
133 HWND browse = GetDlgItem(hwnd, IDC_RUNDLG_BROWSE);
134 ShowWindow(browse, SW_HIDE);
135 EnableWindow(browse, FALSE);
137 if (prfdp->uFlags & RFF_NOLABEL)
138 ShowWindow(GetDlgItem(hwnd, IDC_RUNDLG_LABEL), SW_HIDE);
139 if (prfdp->uFlags & RFF_CALCDIRECTORY)
140 FIXME("RFF_CALCDIRECTORY not supported\n");
142 if (prfdp->hIcon == NULL)
143 prfdp->hIcon = LoadIconW(NULL, (LPCWSTR)IDI_WINLOGO);
144 SendMessageW(hwnd, WM_SETICON, ICON_BIG, (LPARAM)prfdp->hIcon);
145 SendMessageW(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)prfdp->hIcon);
146 SendMessageW(GetDlgItem(hwnd, IDC_RUNDLG_ICON), STM_SETICON, (WPARAM)prfdp->hIcon, 0);
148 FillList (GetDlgItem (hwnd, IDC_RUNDLG_EDITPATH), NULL, (prfdp->uFlags & RFF_NODEFAULT) == 0) ;
149 SetFocus (GetDlgItem (hwnd, IDC_RUNDLG_EDITPATH)) ;
150 return TRUE ;
152 case WM_COMMAND :
153 switch (LOWORD (wParam))
155 case IDOK :
157 int ic ;
158 HWND htxt = GetDlgItem (hwnd, IDC_RUNDLG_EDITPATH);
159 if ((ic = GetWindowTextLengthW (htxt)))
161 WCHAR *psz ;
162 psz = HeapAlloc( GetProcessHeap(), 0, (ic + 1)*sizeof(WCHAR) );
163 GetWindowTextW (htxt, psz, ic + 1) ;
165 /* according to http://www.codeproject.com/KB/shell/runfiledlg.aspx we should send a
166 * WM_NOTIFY before execution */
168 if (ShellExecuteW(hwnd, NULL, psz, NULL, prfdp->lpstrDirectory, SW_SHOWNORMAL) < (HINSTANCE)33)
170 char *pszSysMsg = NULL ;
171 char szMsg[256];
172 FormatMessageA (
173 FORMAT_MESSAGE_ALLOCATE_BUFFER |
174 FORMAT_MESSAGE_FROM_SYSTEM |
175 FORMAT_MESSAGE_IGNORE_INSERTS,
176 NULL, GetLastError (),
177 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
178 (LPSTR)&pszSysMsg, 0, NULL
180 sprintf (szMsg, "Error: %s", pszSysMsg) ;
181 LocalFree ((HLOCAL)pszSysMsg) ;
182 MessageBoxA (hwnd, szMsg, "Nix", MB_OK | MB_ICONEXCLAMATION) ;
184 HeapFree(GetProcessHeap(), 0, psz);
185 SendMessageA (htxt, CB_SETEDITSEL, 0, MAKELPARAM (0, -1)) ;
186 return TRUE ;
189 /* FillList is still ANSI */
190 GetWindowTextA (htxt, (LPSTR)psz, ic + 1) ;
191 FillList (htxt, (LPSTR)psz, FALSE) ;
193 HeapFree(GetProcessHeap(), 0, psz);
194 EndDialog (hwnd, 0) ;
198 case IDCANCEL :
199 EndDialog (hwnd, 0) ;
200 return TRUE ;
202 case IDC_RUNDLG_BROWSE :
204 HMODULE hComdlg = NULL ;
205 LPFNOFN ofnProc = NULL ;
206 static const WCHAR comdlg32W[] = {'c','o','m','d','l','g','3','2',0};
207 WCHAR szFName[1024] = {0};
208 WCHAR *pszFilter, szCaption[MAX_PATH];
209 OPENFILENAMEW ofn;
211 LoadStringW(shell32_hInstance, IDS_RUNDLG_BROWSE_FILTER, (LPWSTR)&pszFilter, 0);
212 LoadStringW(shell32_hInstance, IDS_RUNDLG_BROWSE_CAPTION, szCaption, MAX_PATH);
214 ZeroMemory(&ofn, sizeof(ofn));
215 ofn.lStructSize = sizeof(OPENFILENAMEW);
216 ofn.hwndOwner = hwnd;
217 ofn.lpstrFilter = pszFilter;
218 ofn.lpstrFile = szFName;
219 ofn.nMaxFile = 1023;
220 ofn.lpstrTitle = szCaption;
221 ofn.Flags = OFN_ENABLESIZING | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST;
222 ofn.lpstrInitialDir = prfdp->lpstrDirectory;
224 if (NULL == (hComdlg = LoadLibraryExW (comdlg32W, NULL, 0)) ||
225 NULL == (ofnProc = (LPFNOFN)GetProcAddress (hComdlg, "GetOpenFileNameW")))
227 ERR("Couldn't get GetOpenFileName function entry (lib=%p, proc=%p)\n", hComdlg, ofnProc);
228 ShellMessageBoxW(shell32_hInstance, hwnd, MAKEINTRESOURCEW(IDS_RUNDLG_BROWSE_ERROR), NULL, MB_OK | MB_ICONERROR);
229 return TRUE ;
232 if (ofnProc(&ofn))
234 SetFocus (GetDlgItem (hwnd, IDOK)) ;
235 SetWindowTextW (GetDlgItem (hwnd, IDC_RUNDLG_EDITPATH), szFName) ;
236 SendMessageW (GetDlgItem (hwnd, IDC_RUNDLG_EDITPATH), CB_SETEDITSEL, 0, MAKELPARAM (0, -1)) ;
237 SetFocus (GetDlgItem (hwnd, IDOK)) ;
240 FreeLibrary (hComdlg) ;
242 return TRUE ;
245 return TRUE ;
247 return FALSE ;
250 /* This grabs the MRU list from the registry and fills the combo for the "Run" dialog above */
251 /* fShowDefault ignored if pszLatest != NULL */
252 static void FillList (HWND hCb, char *pszLatest, BOOL fShowDefault)
254 HKEY hkey ;
255 /* char szDbgMsg[256] = "" ; */
256 char *pszList = NULL, *pszCmd = NULL, cMatch = 0, cMax = 0x60, szIndex[2] = "-" ;
257 DWORD icList = 0, icCmd = 0 ;
258 UINT Nix ;
260 SendMessageA (hCb, CB_RESETCONTENT, 0, 0) ;
262 if (ERROR_SUCCESS != RegCreateKeyExA (
263 HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\RunMRU",
264 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL))
265 MessageBoxA (hCb, "Unable to open registry key !", "Nix", MB_OK) ;
267 RegQueryValueExA (hkey, "MRUList", NULL, NULL, NULL, &icList) ;
269 if (icList > 0)
271 pszList = HeapAlloc( GetProcessHeap(), 0, icList) ;
272 if (ERROR_SUCCESS != RegQueryValueExA (hkey, "MRUList", NULL, NULL, (LPBYTE)pszList, &icList))
273 MessageBoxA (hCb, "Unable to grab MRUList !", "Nix", MB_OK) ;
275 else
277 icList = 1 ;
278 pszList = HeapAlloc( GetProcessHeap(), 0, icList) ;
279 pszList[0] = 0 ;
282 for (Nix = 0 ; Nix < icList - 1 ; Nix++)
284 if (pszList[Nix] > cMax)
285 cMax = pszList[Nix] ;
287 szIndex[0] = pszList[Nix] ;
289 if (ERROR_SUCCESS != RegQueryValueExA (hkey, szIndex, NULL, NULL, NULL, &icCmd))
290 MessageBoxA (hCb, "Unable to grab size of index", "Nix", MB_OK) ;
291 if( pszCmd )
292 pszCmd = HeapReAlloc(GetProcessHeap(), 0, pszCmd, icCmd) ;
293 else
294 pszCmd = HeapAlloc(GetProcessHeap(), 0, icCmd) ;
295 if (ERROR_SUCCESS != RegQueryValueExA (hkey, szIndex, NULL, NULL, (LPBYTE)pszCmd, &icCmd))
296 MessageBoxA (hCb, "Unable to grab index", "Nix", MB_OK) ;
298 if (NULL != pszLatest)
300 if (!lstrcmpiA(pszCmd, pszLatest))
303 sprintf (szDbgMsg, "Found existing (%d).\n", Nix) ;
304 MessageBoxA (hCb, szDbgMsg, "Nix", MB_OK) ;
306 SendMessageA (hCb, CB_INSERTSTRING, 0, (LPARAM)pszCmd) ;
307 SetWindowTextA (hCb, pszCmd) ;
308 SendMessageA (hCb, CB_SETEDITSEL, 0, MAKELPARAM (0, -1)) ;
310 cMatch = pszList[Nix] ;
311 memmove (&pszList[1], pszList, Nix) ;
312 pszList[0] = cMatch ;
313 continue ;
317 if (26 != icList - 1 || icList - 2 != Nix || cMatch || NULL == pszLatest)
320 sprintf (szDbgMsg, "Happily appending (%d).\n", Nix) ;
321 MessageBoxA (hCb, szDbgMsg, "Nix", MB_OK) ;
323 SendMessageA (hCb, CB_ADDSTRING, 0, (LPARAM)pszCmd) ;
324 if (!Nix && fShowDefault)
326 SetWindowTextA (hCb, pszCmd) ;
327 SendMessageA (hCb, CB_SETEDITSEL, 0, MAKELPARAM (0, -1)) ;
331 else
334 sprintf (szDbgMsg, "Doing loop thing.\n") ;
335 MessageBoxA (hCb, szDbgMsg, "Nix", MB_OK) ;
337 SendMessageA (hCb, CB_INSERTSTRING, 0, (LPARAM)pszLatest) ;
338 SetWindowTextA (hCb, pszLatest) ;
339 SendMessageA (hCb, CB_SETEDITSEL, 0, MAKELPARAM (0, -1)) ;
341 cMatch = pszList[Nix] ;
342 memmove (&pszList[1], pszList, Nix) ;
343 pszList[0] = cMatch ;
344 szIndex[0] = cMatch ;
345 RegSetValueExA (hkey, szIndex, 0, REG_SZ, (LPBYTE)pszLatest, strlen (pszLatest) + 1) ;
349 if (!cMatch && NULL != pszLatest)
352 sprintf (szDbgMsg, "Simply inserting (increasing list).\n") ;
353 MessageBoxA (hCb, szDbgMsg, "Nix", MB_OK) ;
355 SendMessageA (hCb, CB_INSERTSTRING, 0, (LPARAM)pszLatest) ;
356 SetWindowTextA (hCb, pszLatest) ;
357 SendMessageA (hCb, CB_SETEDITSEL, 0, MAKELPARAM (0, -1)) ;
359 cMatch = ++cMax ;
360 if( pszList )
361 pszList = HeapReAlloc(GetProcessHeap(), 0, pszList, ++icList) ;
362 else
363 pszList = HeapAlloc(GetProcessHeap(), 0, ++icList) ;
364 memmove (&pszList[1], pszList, icList - 1) ;
365 pszList[0] = cMatch ;
366 szIndex[0] = cMatch ;
367 RegSetValueExA (hkey, szIndex, 0, REG_SZ, (LPBYTE)pszLatest, strlen (pszLatest) + 1) ;
370 RegSetValueExA (hkey, "MRUList", 0, REG_SZ, (LPBYTE)pszList, strlen (pszList) + 1) ;
372 HeapFree( GetProcessHeap(), 0, pszCmd) ;
373 HeapFree( GetProcessHeap(), 0, pszList) ;
376 /*************************************************************************
377 * RunFileDlgA [internal]
379 * The ANSI function that is available as ordinal 61 on Windows 9x/Me
381 * SEE ALSO
382 * RunFileDlgAW
384 void WINAPI RunFileDlgA(
385 HWND hwndOwner,
386 HICON hIcon,
387 LPCSTR lpstrDirectory,
388 LPCSTR lpstrTitle,
389 LPCSTR lpstrDescription,
390 UINT uFlags)
392 WCHAR title[MAX_PATH]; /* longer string wouldn't be visible in the dialog anyway */
393 WCHAR description[MAX_PATH];
394 WCHAR directory[MAX_PATH];
396 MultiByteToWideChar(CP_ACP, 0, lpstrTitle, -1, title, MAX_PATH);
397 title[MAX_PATH - 1] = 0;
398 MultiByteToWideChar(CP_ACP, 0, lpstrDescription, -1, description, MAX_PATH);
399 description[MAX_PATH - 1] = 0;
400 if (!MultiByteToWideChar(CP_ACP, 0, lpstrDirectory, -1, directory, MAX_PATH))
401 directory[0] = 0;
403 RunFileDlgW(hwndOwner, hIcon,
404 lpstrDirectory ? directory : NULL,
405 lpstrTitle ? title : NULL,
406 lpstrDescription ? description : NULL,
407 uFlags);
410 /*************************************************************************
411 * RunFileDlgAW [SHELL32.61]
413 * An undocumented way to open the Run File dialog. A documented way is to use
414 * CLSID_Shell, IID_IShellDispatch (as of Wine 1.0, not implemented under Wine)
416 * Exported by ordinal. ANSI on Windows 9x and Unicode on Windows NT/2000/XP/etc
419 void WINAPI RunFileDlgAW(
420 HWND hwndOwner,
421 HICON hIcon,
422 LPCVOID lpstrDirectory,
423 LPCVOID lpstrTitle,
424 LPCVOID lpstrDescription,
425 UINT uFlags)
427 if (SHELL_OsIsUnicode())
428 RunFileDlgW(hwndOwner, hIcon, lpstrDirectory, lpstrTitle, lpstrDescription, uFlags);
429 else
430 RunFileDlgA(hwndOwner, hIcon, lpstrDirectory, lpstrTitle, lpstrDescription, uFlags);
434 /*************************************************************************
435 * ConfirmDialog [internal]
437 * Put up a confirm box, return TRUE if the user confirmed
439 static BOOL ConfirmDialog(HWND hWndOwner, UINT PromptId, UINT TitleId)
441 WCHAR Prompt[256];
442 WCHAR Title[256];
444 LoadStringW(shell32_hInstance, PromptId, Prompt, sizeof(Prompt) / sizeof(WCHAR));
445 LoadStringW(shell32_hInstance, TitleId, Title, sizeof(Title) / sizeof(WCHAR));
446 return MessageBoxW(hWndOwner, Prompt, Title, MB_YESNO|MB_ICONQUESTION) == IDYES;
450 /*************************************************************************
451 * RestartDialogEx [SHELL32.730]
454 int WINAPI RestartDialogEx(HWND hWndOwner, LPCWSTR lpwstrReason, DWORD uFlags, DWORD uReason)
456 TRACE("(%p)\n", hWndOwner);
458 /* FIXME: use lpwstrReason */
459 if (ConfirmDialog(hWndOwner, IDS_RESTART_PROMPT, IDS_RESTART_TITLE))
461 HANDLE hToken;
462 TOKEN_PRIVILEGES npr;
464 /* enable the shutdown privilege for the current process */
465 if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
467 LookupPrivilegeValueA(0, "SeShutdownPrivilege", &npr.Privileges[0].Luid);
468 npr.PrivilegeCount = 1;
469 npr.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
470 AdjustTokenPrivileges(hToken, FALSE, &npr, 0, 0, 0);
471 CloseHandle(hToken);
473 ExitWindowsEx(EWX_REBOOT, uReason);
476 return 0;
480 /*************************************************************************
481 * RestartDialog [SHELL32.59]
484 int WINAPI RestartDialog(HWND hWndOwner, LPCWSTR lpstrReason, DWORD uFlags)
486 return RestartDialogEx(hWndOwner, lpstrReason, uFlags, 0);
490 /*************************************************************************
491 * ExitWindowsDialog [SHELL32.60]
493 * NOTES
494 * exported by ordinal
496 void WINAPI ExitWindowsDialog (HWND hWndOwner)
498 TRACE("(%p)\n", hWndOwner);
500 if (ConfirmDialog(hWndOwner, IDS_SHUTDOWN_PROMPT, IDS_SHUTDOWN_TITLE))
502 HANDLE hToken;
503 TOKEN_PRIVILEGES npr;
505 /* enable shutdown privilege for current process */
506 if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
508 LookupPrivilegeValueA(0, "SeShutdownPrivilege", &npr.Privileges[0].Luid);
509 npr.PrivilegeCount = 1;
510 npr.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
511 AdjustTokenPrivileges(hToken, FALSE, &npr, 0, 0, 0);
512 CloseHandle(hToken);
514 ExitWindowsEx(EWX_SHUTDOWN, 0);