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
27 LPCWSTR lpstrDirectory
;
29 LPCWSTR lpstrDescription
;
33 typedef BOOL (WINAPI
* LPFNOFN
) (OPENFILENAMEW
*);
35 WINE_DEFAULT_DEBUG_CHANNEL(shell
);
36 static INT_PTR CALLBACK
RunDlgProc(HWND
, UINT
, WPARAM
, LPARAM
);
37 static void FillList(HWND
, LPWSTR
, UINT
, BOOL
);
40 /*************************************************************************
41 * PickIconDlg [SHELL32.62]
49 WCHAR szName
[MAX_PATH
];
51 } PICK_ICON_CONTEXT
, *PPICK_ICON_CONTEXT
;
53 BOOL CALLBACK
EnumPickIconResourceProc(HMODULE hModule
,
62 HWND hDlgCtrl
= (HWND
)lParam
;
64 if (IS_INTRESOURCE(lpszName
))
65 swprintf(szName
, L
"%u", (DWORD
)lpszName
);
67 StringCbCopyW(szName
, sizeof(szName
), lpszName
);
69 hIcon
= LoadIconW(hModule
, lpszName
);
73 index
= SendMessageW(hDlgCtrl
, LB_ADDSTRING
, 0, (LPARAM
)szName
);
75 SendMessageW(hDlgCtrl
, LB_SETITEMDATA
, index
, (LPARAM
)hIcon
);
81 DestroyIconList(HWND hDlgCtrl
)
86 count
= SendMessageW(hDlgCtrl
, LB_GETCOUNT
, 0, 0);
90 for(index
= 0; index
< count
; index
++)
92 HICON hIcon
= (HICON
)SendMessageW(hDlgCtrl
, LB_GETITEMDATA
, index
, 0);
97 INT_PTR CALLBACK
PickIconProc(HWND hwndDlg
,
103 LPMEASUREITEMSTRUCT lpmis
;
104 LPDRAWITEMSTRUCT lpdis
;
107 WCHAR szText
[MAX_PATH
], szTitle
[100], szFilter
[100];
108 OPENFILENAMEW ofn
= {0};
110 PPICK_ICON_CONTEXT pIconContext
= (PPICK_ICON_CONTEXT
)GetWindowLongPtr(hwndDlg
, DWLP_USER
);
115 pIconContext
= (PPICK_ICON_CONTEXT
)lParam
;
116 SetWindowLongPtr(hwndDlg
, DWLP_USER
, (LONG
)pIconContext
);
117 pIconContext
->hDlgCtrl
= GetDlgItem(hwndDlg
, IDC_PICKICON_LIST
);
118 SendMessageW(pIconContext
->hDlgCtrl
, LB_SETCOLUMNWIDTH
, 32, 0);
119 EnumResourceNamesW(pIconContext
->hLibrary
, RT_ICON
, EnumPickIconResourceProc
, (LPARAM
)pIconContext
->hDlgCtrl
);
120 if (ExpandEnvironmentStringsW(pIconContext
->szName
, szText
, MAX_PATH
))
121 SetDlgItemTextW(hwndDlg
, IDC_EDIT_PATH
, szText
);
123 SetDlgItemTextW(hwndDlg
, IDC_EDIT_PATH
, pIconContext
->szName
);
125 count
= SendMessageW(pIconContext
->hDlgCtrl
, LB_GETCOUNT
, 0, 0);
128 if (count
> pIconContext
->Index
)
129 SendMessageW(pIconContext
->hDlgCtrl
, LB_SETCURSEL
, pIconContext
->Index
, 0);
131 SendMessageW(pIconContext
->hDlgCtrl
, LB_SETCURSEL
, 0, 0);
135 switch(LOWORD(wParam
))
138 index
= SendMessageW(pIconContext
->hDlgCtrl
, LB_GETCURSEL
, 0, 0);
139 pIconContext
->Index
= index
;
140 GetDlgItemTextW(hwndDlg
, IDC_EDIT_PATH
, pIconContext
->szName
, MAX_PATH
);
141 DestroyIconList(pIconContext
->hDlgCtrl
);
142 EndDialog(hwndDlg
, 1);
145 DestroyIconList(pIconContext
->hDlgCtrl
);
146 EndDialog(hwndDlg
, 0);
148 case IDC_PICKICON_LIST
:
149 if (HIWORD(wParam
) == LBN_SELCHANGE
)
150 InvalidateRect((HWND
)lParam
, NULL
, TRUE
); // FIXME USE UPDATE RECT
152 case IDC_BUTTON_PATH
:
156 ofn
.lStructSize
= sizeof(ofn
);
157 ofn
.hwndOwner
= hwndDlg
;
158 ofn
.lpstrFile
= szText
;
159 ofn
.nMaxFile
= MAX_PATH
;
160 LoadStringW(shell32_hInstance
, IDS_PICK_ICON_TITLE
, szTitle
, sizeof(szTitle
) / sizeof(WCHAR
));
161 ofn
.lpstrTitle
= szTitle
;
162 LoadStringW(shell32_hInstance
, IDS_PICK_ICON_FILTER
, szFilter
, sizeof(szFilter
) / sizeof(WCHAR
));
163 ofn
.lpstrFilter
= szFilter
;
164 if (GetOpenFileNameW(&ofn
))
168 if (!wcsicmp(pIconContext
->szName
, szText
))
171 DestroyIconList(pIconContext
->hDlgCtrl
);
173 hLibrary
= LoadLibraryExW(szText
, NULL
, LOAD_LIBRARY_AS_DATAFILE
| LOAD_LIBRARY_AS_IMAGE_RESOURCE
);
174 if (hLibrary
== NULL
)
176 FreeLibrary(pIconContext
->hLibrary
);
177 pIconContext
->hLibrary
= hLibrary
;
178 wcscpy(pIconContext
->szName
, szText
);
179 EnumResourceNamesW(pIconContext
->hLibrary
, RT_ICON
, EnumPickIconResourceProc
, (LPARAM
)pIconContext
->hDlgCtrl
);
180 if (ExpandEnvironmentStringsW(pIconContext
->szName
, szText
, MAX_PATH
))
181 SetDlgItemTextW(hwndDlg
, IDC_EDIT_PATH
, szText
);
183 SetDlgItemTextW(hwndDlg
, IDC_EDIT_PATH
, pIconContext
->szName
);
185 SendMessageW(pIconContext
->hDlgCtrl
, LB_SETCURSEL
, 0, 0);
191 lpmis
= (LPMEASUREITEMSTRUCT
) lParam
;
192 lpmis
->itemHeight
= 32;
193 lpmis
->itemWidth
= 64;
196 lpdis
= (LPDRAWITEMSTRUCT
) lParam
;
197 if (lpdis
->itemID
== (UINT
)-1)
201 switch (lpdis
->itemAction
)
205 index
= SendMessageW(pIconContext
->hDlgCtrl
, LB_GETCURSEL
, 0, 0);
206 hIcon
= (HICON
)SendMessageW(lpdis
->hwndItem
, LB_GETITEMDATA
, lpdis
->itemID
, 0);
208 if (lpdis
->itemID
== (UINT
)index
)
209 FillRect(lpdis
->hDC
, &lpdis
->rcItem
, (HBRUSH
)(COLOR_HIGHLIGHT
+ 1));
211 FillRect(lpdis
->hDC
, &lpdis
->rcItem
, (HBRUSH
)(COLOR_WINDOW
+ 1));
213 DrawIconEx(lpdis
->hDC
, lpdis
->rcItem
.left
,lpdis
->rcItem
.top
, hIcon
,
214 0, 0, 0, NULL
, DI_NORMAL
);
223 BOOL WINAPI
PickIconDlg(
231 PICK_ICON_CONTEXT IconContext
;
233 hLibrary
= LoadLibraryExW(lpstrFile
, NULL
, LOAD_LIBRARY_AS_DATAFILE
| LOAD_LIBRARY_AS_IMAGE_RESOURCE
);
234 IconContext
.hLibrary
= hLibrary
;
235 IconContext
.Index
= *lpdwIconIndex
;
236 StringCchCopyNW(IconContext
.szName
, _countof(IconContext
.szName
), lpstrFile
, nMaxFile
);
238 res
= DialogBoxParamW(shell32_hInstance
, MAKEINTRESOURCEW(IDD_PICK_ICON
), hWndOwner
, PickIconProc
, (LPARAM
)&IconContext
);
241 StringCchCopyNW(lpstrFile
, nMaxFile
, IconContext
.szName
, _countof(IconContext
.szName
));
242 *lpdwIconIndex
= IconContext
.Index
;
245 FreeLibrary(hLibrary
);
249 /*************************************************************************
250 * RunFileDlg [internal]
252 * The Unicode function that is available as ordinal 61 on Windows NT/2000/XP/...
254 void WINAPI
RunFileDlg(
257 LPCWSTR lpstrDirectory
,
259 LPCWSTR lpstrDescription
,
264 RUNFILEDLGPARAMS rfdp
;
265 rfdp
.hwndOwner
= hWndOwner
;
267 rfdp
.lpstrDirectory
= lpstrDirectory
;
268 rfdp
.lpstrTitle
= lpstrTitle
;
269 rfdp
.lpstrDescription
= lpstrDescription
;
270 rfdp
.uFlags
= uFlags
;
272 DialogBoxParamW(shell32_hInstance
, MAKEINTRESOURCEW(IDD_RUN
), hWndOwner
, RunDlgProc
, (LPARAM
)&rfdp
);
276 /* find the directory that contains the file being run */
277 static LPWSTR
RunDlg_GetParentDir(LPCWSTR cmdline
)
280 WCHAR
*dest
, *result
, *result_end
=NULL
;
281 static const WCHAR dotexeW
[] = L
".exe";
283 result
= (WCHAR
*)HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR
)*(strlenW(cmdline
)+5));
287 TRACE("HeapAlloc couldn't allocate %d bytes\n", sizeof(WCHAR
)*(strlenW(cmdline
)+5));
297 while (*src
&& *src
!= '"')
310 if (INVALID_FILE_ATTRIBUTES
!= GetFileAttributesW(result
))
312 strcatW(dest
, dotexeW
);
313 if (INVALID_FILE_ATTRIBUTES
!= GetFileAttributesW(result
))
316 else if (*src
== '\\')
329 HeapFree(GetProcessHeap(), 0, result
);
334 static void EnableOkButtonFromEditContents(HWND hwnd
)
338 HWND Edit
= GetDlgItem(hwnd
, IDC_RUNDLG_EDITPATH
);
339 Length
= GetWindowTextLengthW(Edit
);
342 PWCHAR psz
= (PWCHAR
)HeapAlloc(GetProcessHeap(), 0, (Length
+ 1) * sizeof(WCHAR
));
345 GetWindowTextW(Edit
, psz
, Length
+ 1);
346 for (n
= 0; n
< Length
&& !Enable
; ++n
)
347 Enable
= psz
[n
] != ' ';
348 HeapFree(GetProcessHeap(), 0, psz
);
353 EnableWindow(GetDlgItem(hwnd
, IDOK
), Enable
);
356 /* Dialog procedure for RunFileDlg */
357 static INT_PTR CALLBACK
RunDlgProc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
359 RUNFILEDLGPARAMS
*prfdp
= (RUNFILEDLGPARAMS
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
364 prfdp
= (RUNFILEDLGPARAMS
*)lParam
;
365 SetWindowLongPtrW(hwnd
, DWLP_USER
, (LONG_PTR
)prfdp
);
367 if (prfdp
->lpstrTitle
)
368 SetWindowTextW(hwnd
, prfdp
->lpstrTitle
);
369 if (prfdp
->lpstrDescription
)
370 SetWindowTextW(GetDlgItem(hwnd
, IDC_RUNDLG_DESCRIPTION
), prfdp
->lpstrDescription
);
371 if (prfdp
->uFlags
& RFF_NOBROWSE
)
373 HWND browse
= GetDlgItem(hwnd
, IDC_RUNDLG_BROWSE
);
374 ShowWindow(browse
, SW_HIDE
);
375 EnableWindow(browse
, FALSE
);
377 if (prfdp
->uFlags
& RFF_NOLABEL
)
378 ShowWindow(GetDlgItem(hwnd
, IDC_RUNDLG_LABEL
), SW_HIDE
);
379 if (prfdp
->uFlags
& RFF_NOSEPARATEMEM
)
381 FIXME("RFF_NOSEPARATEMEM not supported\n");
384 /* Use the default Shell Run icon if no one is specified */
385 if (prfdp
->hIcon
== NULL
)
386 prfdp
->hIcon
= LoadIconW(shell32_hInstance
, MAKEINTRESOURCEW(IDI_SHELL_RUN
));
388 * NOTE: Starting Windows Vista, the "Run File" dialog gets a
389 * title icon that remains the same as the default one, even if
390 * the user specifies a custom icon.
391 * Since we currently imitate Windows 2003, therefore do not show
394 // SendMessageW(hwnd, WM_SETICON, ICON_BIG, (LPARAM)prfdp->hIcon);
395 // SendMessageW(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)prfdp->hIcon);
396 SendMessageW(GetDlgItem(hwnd
, IDC_RUNDLG_ICON
), STM_SETICON
, (WPARAM
)prfdp
->hIcon
, 0);
398 FillList(GetDlgItem(hwnd
, IDC_RUNDLG_EDITPATH
), NULL
, 0, (prfdp
->uFlags
& RFF_NODEFAULT
) == 0);
399 EnableOkButtonFromEditContents(hwnd
);
400 SetFocus(GetDlgItem(hwnd
, IDC_RUNDLG_EDITPATH
));
404 switch (LOWORD(wParam
))
409 HWND htxt
= GetDlgItem(hwnd
, IDC_RUNDLG_EDITPATH
);
411 WCHAR
*psz
, *parent
= NULL
;
412 SHELLEXECUTEINFOW sei
;
415 ic
= GetWindowTextLengthW(htxt
);
418 EndDialog(hwnd
, IDCANCEL
);
422 ZeroMemory(&sei
, sizeof(sei
));
423 sei
.cbSize
= sizeof(sei
);
426 * Allocate a new MRU entry, we need to add two characters
427 * for the terminating "\\1" part, then the NULL character.
429 psz
= (WCHAR
*)HeapAlloc(GetProcessHeap(), 0, (ic
+ 2 + 1)*sizeof(WCHAR
));
432 EndDialog(hwnd
, IDCANCEL
);
436 GetWindowTextW(htxt
, psz
, ic
+ 1);
439 sei
.nShow
= SW_SHOWNORMAL
;
443 * The precedence is the following: first the user-given
444 * current directory is used; if there is none, a current
445 * directory is computed if the RFF_CALCDIRECTORY is set,
446 * otherwise no current directory is defined.
448 if (prfdp
->lpstrDirectory
)
449 sei
.lpDirectory
= prfdp
->lpstrDirectory
;
450 else if (prfdp
->uFlags
& RFF_CALCDIRECTORY
)
451 sei
.lpDirectory
= parent
= RunDlg_GetParentDir(sei
.lpFile
);
453 sei
.lpDirectory
= NULL
;
455 /* Hide the dialog for now on, we will show it up in case of retry */
456 ShowWindow(hwnd
, SW_HIDE
);
459 * As shown by manual tests on Windows, modifying the contents
460 * of the notification structure will not modify what the
461 * Run-Dialog will use for the nShow parameter. However the
462 * lpFile and lpDirectory pointers are set to the buffers used
463 * by the Run-Dialog, as a consequence they can be modified by
464 * the notification receiver, as long as it respects the lengths
465 * of the buffers (to avoid buffer overflows).
467 nmrfd
.hdr
.code
= RFN_VALIDATE
;
468 nmrfd
.hdr
.hwndFrom
= hwnd
;
469 nmrfd
.hdr
.idFrom
= 0;
470 nmrfd
.lpFile
= sei
.lpFile
;
471 nmrfd
.lpDirectory
= sei
.lpDirectory
;
472 nmrfd
.nShow
= sei
.nShow
;
474 lRet
= SendMessageW(prfdp
->hwndOwner
, WM_NOTIFY
, 0, (LPARAM
)&nmrfd
.hdr
);
479 EndDialog(hwnd
, IDCANCEL
);
483 if (ShellExecuteExW(&sei
))
485 /* Call again GetWindowText in case the contents of the edit box has changed? */
486 GetWindowTextW(htxt
, psz
, ic
+ 1);
487 FillList(htxt
, psz
, ic
+ 2 + 1, FALSE
);
488 EndDialog(hwnd
, IDOK
);
495 SendMessageW(htxt
, CB_SETEDITSEL
, 0, MAKELPARAM (0, -1));
496 /* Show back the dialog */
497 ShowWindow(hwnd
, SW_SHOW
);
501 HeapFree(GetProcessHeap(), 0, parent
);
502 HeapFree(GetProcessHeap(), 0, psz
);
507 EndDialog(hwnd
, IDCANCEL
);
510 case IDC_RUNDLG_BROWSE
:
512 HMODULE hComdlg
= NULL
;
513 LPFNOFN ofnProc
= NULL
;
514 WCHAR szFName
[1024] = {0};
515 WCHAR filter
[MAX_PATH
], szCaption
[MAX_PATH
];
518 LoadStringW(shell32_hInstance
, IDS_RUNDLG_BROWSE_FILTER
, filter
, MAX_PATH
);
519 LoadStringW(shell32_hInstance
, IDS_RUNDLG_BROWSE_CAPTION
, szCaption
, MAX_PATH
);
521 ZeroMemory(&ofn
, sizeof(ofn
));
522 ofn
.lStructSize
= sizeof(ofn
);
523 ofn
.hwndOwner
= hwnd
;
524 ofn
.lpstrFilter
= filter
;
525 ofn
.lpstrFile
= szFName
;
526 ofn
.nMaxFile
= _countof(szFName
) - 1;
527 ofn
.lpstrTitle
= szCaption
;
528 ofn
.Flags
= OFN_ENABLESIZING
| OFN_FILEMUSTEXIST
| OFN_HIDEREADONLY
| OFN_PATHMUSTEXIST
;
529 ofn
.lpstrInitialDir
= prfdp
->lpstrDirectory
;
531 if (NULL
== (hComdlg
= LoadLibraryExW(L
"comdlg32", NULL
, 0)) ||
532 NULL
== (ofnProc
= (LPFNOFN
)GetProcAddress(hComdlg
, "GetOpenFileNameW")))
534 ERR("Couldn't get GetOpenFileName function entry (lib=%p, proc=%p)\n", hComdlg
, ofnProc
);
535 ShellMessageBoxW(shell32_hInstance
, hwnd
, MAKEINTRESOURCEW(IDS_RUNDLG_BROWSE_ERROR
), NULL
, MB_OK
| MB_ICONERROR
);
541 SetFocus(GetDlgItem(hwnd
, IDOK
));
542 SetWindowTextW(GetDlgItem(hwnd
, IDC_RUNDLG_EDITPATH
), szFName
);
543 SendMessageW(GetDlgItem(hwnd
, IDC_RUNDLG_EDITPATH
), CB_SETEDITSEL
, 0, MAKELPARAM(0, -1));
544 EnableOkButtonFromEditContents(hwnd
);
545 SetFocus(GetDlgItem(hwnd
, IDOK
));
548 FreeLibrary(hComdlg
);
552 case IDC_RUNDLG_EDITPATH
:
554 if (HIWORD(wParam
) == CBN_EDITCHANGE
)
556 EnableOkButtonFromEditContents(hwnd
);
567 * This function grabs the MRU list from the registry and fills the combo-list
568 * for the "Run" dialog above. fShowDefault is ignored if pszLatest != NULL.
570 // FIXME: Part of this code should be part of some MRUList API,
571 // that is scattered amongst shell32, comctl32 (?!) and comdlg32.
572 static void FillList(HWND hCb
, LPWSTR pszLatest
, UINT cchStr
, BOOL fShowDefault
)
575 WCHAR
*pszList
= NULL
, *pszCmd
= NULL
, *pszTmp
= NULL
, cMatch
= 0, cMax
= 0x60;
576 WCHAR szIndex
[2] = L
"-";
578 DWORD dwType
, icList
= 0, icCmd
= 0;
583 * Retrieve the string length of pszLatest and check whether its buffer size
584 * (cchStr in number of characters) is large enough to add the terminating "\\1"
585 * (and the NULL character).
589 cchLatest
= wcslen(pszLatest
);
590 if (cchStr
< cchLatest
+ 2 + 1)
592 TRACE("pszLatest buffer is not large enough (%d) to hold the MRU terminator.\n", cchStr
);
601 SendMessageW(hCb
, CB_RESETCONTENT
, 0, 0);
603 lRet
= RegCreateKeyExW(HKEY_CURRENT_USER
,
604 L
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\RunMRU",
605 0, NULL
, REG_OPTION_NON_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
606 if (lRet
!= ERROR_SUCCESS
)
608 TRACE("Unable to open or create the RunMRU key, error %d\n", GetLastError());
612 lRet
= RegQueryValueExW(hkey
, L
"MRUList", NULL
, &dwType
, NULL
, &icList
);
613 if (lRet
== ERROR_SUCCESS
&& dwType
== REG_SZ
&& icList
> sizeof(WCHAR
))
615 pszList
= (WCHAR
*)HeapAlloc(GetProcessHeap(), 0, icList
);
618 TRACE("HeapAlloc failed to allocate %d bytes\n", icList
);
623 lRet
= RegQueryValueExW(hkey
, L
"MRUList", NULL
, NULL
, (LPBYTE
)pszList
, &icList
);
624 if (lRet
!= ERROR_SUCCESS
)
626 TRACE("Unable to grab MRUList, error %d\n", GetLastError());
633 icList
= sizeof(WCHAR
);
634 pszList
= (WCHAR
*)HeapAlloc(GetProcessHeap(), 0, icList
);
637 TRACE("HeapAlloc failed to allocate %d bytes\n", icList
);
644 /* Convert the number of bytes from MRUList into number of characters (== number of indices) */
645 icList
/= sizeof(WCHAR
);
647 for (Nix
= 0; Nix
< icList
- 1; Nix
++)
649 if (pszList
[Nix
] > cMax
)
652 szIndex
[0] = pszList
[Nix
];
654 lRet
= RegQueryValueExW(hkey
, szIndex
, NULL
, &dwType
, NULL
, &icCmd
);
655 if (lRet
!= ERROR_SUCCESS
|| dwType
!= REG_SZ
)
657 TRACE("Unable to grab size of index, error %d\n", GetLastError());
663 pszTmp
= (WCHAR
*)HeapReAlloc(GetProcessHeap(), 0, pszCmd
, icCmd
);
666 TRACE("HeapReAlloc failed to reallocate %d bytes\n", icCmd
);
673 pszCmd
= (WCHAR
*)HeapAlloc(GetProcessHeap(), 0, icCmd
);
676 TRACE("HeapAlloc failed to allocate %d bytes\n", icCmd
);
681 lRet
= RegQueryValueExW(hkey
, szIndex
, NULL
, NULL
, (LPBYTE
)pszCmd
, &icCmd
);
682 if (lRet
!= ERROR_SUCCESS
)
684 TRACE("Unable to grab index, error %d\n", GetLastError());
689 * Generally the command string will end up with "\\1".
690 * Find the last backslash in the string and NULL-terminate.
691 * Windows does not seem to check for what comes next, so that
692 * a command of the form:
693 * c:\\my_dir\\myfile.exe
694 * will be cut just after "my_dir", whereas a command of the form:
695 * c:\\my_dir\\myfile.exe\\1
696 * will be cut just after "myfile.exe".
698 pszTmp
= wcsrchr(pszCmd
, L
'\\');
703 * In the following we try to add pszLatest to the MRU list.
704 * We suppose that our caller has already correctly allocated
705 * the string with enough space for us to append a "\\1".
707 * FIXME: TODO! (At the moment we don't append it!)
712 if (wcsicmp(pszCmd
, pszLatest
) == 0)
714 SendMessageW(hCb
, CB_INSERTSTRING
, 0, (LPARAM
)pszCmd
);
715 SetWindowTextW(hCb
, pszCmd
);
716 SendMessageW(hCb
, CB_SETEDITSEL
, 0, MAKELPARAM(0, -1));
718 cMatch
= pszList
[Nix
];
719 memmove(&pszList
[1], pszList
, Nix
* sizeof(WCHAR
));
725 if (icList
- 1 != 26 || icList
- 2 != Nix
|| cMatch
|| pszLatest
== NULL
)
727 SendMessageW(hCb
, CB_ADDSTRING
, 0, (LPARAM
)pszCmd
);
728 if (!Nix
&& fShowDefault
)
730 SetWindowTextW(hCb
, pszCmd
);
731 SendMessageW(hCb
, CB_SETEDITSEL
, 0, MAKELPARAM(0, -1));
736 SendMessageW(hCb
, CB_INSERTSTRING
, 0, (LPARAM
)pszLatest
);
737 SetWindowTextW(hCb
, pszLatest
);
738 SendMessageW(hCb
, CB_SETEDITSEL
, 0, MAKELPARAM(0, -1));
740 cMatch
= pszList
[Nix
];
741 memmove(&pszList
[1], pszList
, Nix
* sizeof(WCHAR
));
745 wcscpy(&pszLatest
[cchLatest
], L
"\\1");
746 RegSetValueExW(hkey
, szIndex
, 0, REG_SZ
, (LPBYTE
)pszLatest
, (cchLatest
+ 2 + 1) * sizeof(WCHAR
));
747 pszLatest
[cchLatest
] = L
'\0';
751 if (!cMatch
&& pszLatest
!= NULL
)
753 SendMessageW(hCb
, CB_INSERTSTRING
, 0, (LPARAM
)pszLatest
);
754 SetWindowTextW(hCb
, pszLatest
);
755 SendMessageW(hCb
, CB_SETEDITSEL
, 0, MAKELPARAM (0, -1));
761 pszTmp
= (WCHAR
*)HeapReAlloc(GetProcessHeap(), 0, pszList
, (++icList
) * sizeof(WCHAR
));
764 TRACE("HeapReAlloc failed to reallocate enough bytes\n");
771 pszList
= (WCHAR
*)HeapAlloc(GetProcessHeap(), 0, (++icList
) * sizeof(WCHAR
));
774 TRACE("HeapAlloc failed to allocate enough bytes\n");
779 memmove(&pszList
[1], pszList
, (icList
- 1) * sizeof(WCHAR
));
783 wcscpy(&pszLatest
[cchLatest
], L
"\\1");
784 RegSetValueExW(hkey
, szIndex
, 0, REG_SZ
, (LPBYTE
)pszLatest
, (cchLatest
+ 2 + 1) * sizeof(WCHAR
));
785 pszLatest
[cchLatest
] = L
'\0';
789 RegSetValueExW(hkey
, L
"MRUList", 0, REG_SZ
, (LPBYTE
)pszList
, (wcslen(pszList
) + 1) * sizeof(WCHAR
));
791 HeapFree(GetProcessHeap(), 0, pszCmd
);
792 HeapFree(GetProcessHeap(), 0, pszList
);
798 /*************************************************************************
799 * ConfirmDialog [internal]
801 * Put up a confirm box, return TRUE if the user confirmed
803 static BOOL
ConfirmDialog(HWND hWndOwner
, UINT PromptId
, UINT TitleId
)
808 LoadStringW(shell32_hInstance
, PromptId
, Prompt
, _countof(Prompt
));
809 LoadStringW(shell32_hInstance
, TitleId
, Title
, _countof(Title
));
810 return MessageBoxW(hWndOwner
, Prompt
, Title
, MB_YESNO
| MB_ICONQUESTION
) == IDYES
;
813 typedef HRESULT (WINAPI
*tShellDimScreen
)(IUnknown
** Unknown
, HWND
* hWindow
);
816 CallShellDimScreen(IUnknown
** pUnknown
, HWND
* hWindow
)
818 static tShellDimScreen ShellDimScreen
;
819 static BOOL Initialized
= FALSE
;
822 HMODULE mod
= LoadLibraryW(L
"msgina.dll");
823 ShellDimScreen
= (tShellDimScreen
)GetProcAddress(mod
, (LPCSTR
)16);
829 hr
= ShellDimScreen(pUnknown
, hWindow
);
830 return SUCCEEDED(hr
);
834 /* Used to get the shutdown privilege */
836 EnablePrivilege(LPCWSTR lpszPrivilegeName
, BOOL bEnablePrivilege
)
842 Success
= OpenProcessToken(GetCurrentProcess(),
843 TOKEN_ADJUST_PRIVILEGES
,
845 if (!Success
) return Success
;
847 Success
= LookupPrivilegeValueW(NULL
,
849 &tp
.Privileges
[0].Luid
);
850 if (!Success
) goto Quit
;
852 tp
.PrivilegeCount
= 1;
853 tp
.Privileges
[0].Attributes
= (bEnablePrivilege
? SE_PRIVILEGE_ENABLED
: 0);
855 Success
= AdjustTokenPrivileges(hToken
, FALSE
, &tp
, 0, NULL
, NULL
);
862 /*************************************************************************
863 * RestartDialogEx [SHELL32.730]
866 int WINAPI
RestartDialogEx(HWND hWndOwner
, LPCWSTR lpwstrReason
, DWORD uFlags
, DWORD uReason
)
868 TRACE("(%p)\n", hWndOwner
);
870 CComPtr
<IUnknown
> fadeHandler
;
873 if (!CallShellDimScreen(&fadeHandler
, &parent
))
876 /* FIXME: use lpwstrReason */
877 if (ConfirmDialog(parent
, IDS_RESTART_PROMPT
, IDS_RESTART_TITLE
))
879 EnablePrivilege(L
"SeShutdownPrivilege", TRUE
);
880 ExitWindowsEx(EWX_REBOOT
, uReason
);
881 EnablePrivilege(L
"SeShutdownPrivilege", FALSE
);
887 /*************************************************************************
890 * NOTES: Used to make the Log Off dialog work
892 INT_PTR CALLBACK
LogOffDialogProc(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
900 EndDialog(hwnd
, IDCANCEL
);
906 if (LOWORD(wParam
) == WA_INACTIVE
)
913 switch (LOWORD(wParam
))
916 ExitWindowsEx(EWX_LOGOFF
, 0);
920 EndDialog(hwnd
, IDCANCEL
);
931 /*************************************************************************
932 * LogoffWindowsDialog [SHELL32.54]
935 EXTERN_C
int WINAPI
LogoffWindowsDialog(HWND hWndOwner
)
937 CComPtr
<IUnknown
> fadeHandler
;
940 if (!CallShellDimScreen(&fadeHandler
, &parent
))
943 DialogBoxW(shell32_hInstance
, MAKEINTRESOURCEW(IDD_LOG_OFF
), parent
, LogOffDialogProc
);
947 /*************************************************************************
948 * RestartDialog [SHELL32.59]
951 int WINAPI
RestartDialog(HWND hWndOwner
, LPCWSTR lpstrReason
, DWORD uFlags
)
953 return RestartDialogEx(hWndOwner
, lpstrReason
, uFlags
, 0);
956 /*************************************************************************
957 * ExitWindowsDialog_backup
960 * Used as a backup solution to shutdown the OS in case msgina.dll
961 * somehow cannot be found.
963 VOID
ExitWindowsDialog_backup(HWND hWndOwner
)
965 TRACE("(%p)\n", hWndOwner
);
967 if (ConfirmDialog(hWndOwner
, IDS_SHUTDOWN_PROMPT
, IDS_SHUTDOWN_TITLE
))
969 EnablePrivilege(L
"SeShutdownPrivilege", TRUE
);
970 ExitWindowsEx(EWX_SHUTDOWN
, 0);
971 EnablePrivilege(L
"SeShutdownPrivilege", FALSE
);
975 /*************************************************************************
976 * ExitWindowsDialog [SHELL32.60]
979 * exported by ordinal
983 * - Implement the ability to show either the Welcome Screen or the classic dialog boxes based upon the
984 * registry value: SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\LogonType.
986 void WINAPI
ExitWindowsDialog(HWND hWndOwner
)
988 typedef DWORD (WINAPI
*ShellShFunc
)(HWND hParent
, WCHAR
*Username
, BOOL bHideLogoff
);
989 HINSTANCE msginaDll
= LoadLibraryW(L
"msgina.dll");
991 TRACE("(%p)\n", hWndOwner
);
993 CComPtr
<IUnknown
> fadeHandler
;
995 if (!CallShellDimScreen(&fadeHandler
, &parent
))
998 /* If the DLL cannot be found for any reason, then it simply uses a
999 dialog box to ask if the user wants to shut down the computer. */
1002 TRACE("Unable to load msgina.dll.\n");
1003 ExitWindowsDialog_backup(parent
);
1007 ShellShFunc pShellShutdownDialog
= (ShellShFunc
)GetProcAddress(msginaDll
, "ShellShutdownDialog");
1009 if (pShellShutdownDialog
)
1011 /* Actually call the function */
1012 DWORD returnValue
= pShellShutdownDialog(parent
, NULL
, FALSE
);
1014 switch (returnValue
)
1016 case 0x01: /* Log off user */
1018 ExitWindowsEx(EWX_LOGOFF
, 0);
1021 case 0x02: /* Shut down */
1023 EnablePrivilege(L
"SeShutdownPrivilege", TRUE
);
1024 ExitWindowsEx(EWX_SHUTDOWN
, 0);
1025 EnablePrivilege(L
"SeShutdownPrivilege", FALSE
);
1028 case 0x03: /* Install Updates/Shutdown (?) */
1032 case 0x04: /* Reboot */
1034 EnablePrivilege(L
"SeShutdownPrivilege", TRUE
);
1035 ExitWindowsEx(EWX_REBOOT
, 0);
1036 EnablePrivilege(L
"SeShutdownPrivilege", FALSE
);
1039 case 0x10: /* Sleep */
1041 if (IsPwrSuspendAllowed())
1043 EnablePrivilege(L
"SeShutdownPrivilege", TRUE
);
1044 SetSuspendState(FALSE
, FALSE
, FALSE
);
1045 EnablePrivilege(L
"SeShutdownPrivilege", FALSE
);
1049 case 0x40: /* Hibernate */
1051 if (IsPwrHibernateAllowed())
1053 EnablePrivilege(L
"SeShutdownPrivilege", TRUE
);
1054 SetSuspendState(TRUE
, FALSE
, TRUE
);
1055 EnablePrivilege(L
"SeShutdownPrivilege", FALSE
);
1059 /* If the option is any other value */
1066 /* If the function cannot be found, then revert to using the backup solution */
1067 TRACE("Unable to find the 'ShellShutdownDialog' function");
1068 ExitWindowsDialog_backup(parent
);
1071 FreeLibrary(msginaDll
);