[APPWIZ][SHELL32] Improve 'Create Shortcut' dialog (#6550)

Now we can open special folder shortcut, thanks to #6546.
Let's allow users to create various shortcut files.
JIRA issue: CORE-5866
- Remove BIF_RETURNONLYFSDIRS flag because
  the system can open special folder shortcuts now.
- Add LPITEMIDLIST pidlTarget to CREATE_LINK_CONTEXT
  structure.
- Use pidlTarget if the target is a special folder.
- Fix CShellLink::DoOpen for arguments.
This commit is contained in:
Katayama Hirofumi MZ 2024-02-28 15:22:44 +09:00 committed by GitHub
parent 776c3a3495
commit 1d1472c78e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 71 additions and 50 deletions

View file

@ -27,8 +27,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(appwiz);
typedef struct typedef struct
{ {
LPITEMIDLIST pidlTarget;
WCHAR szTarget[2 * MAX_PATH]; WCHAR szTarget[2 * MAX_PATH];
WCHAR szWorkingDirectory[MAX_PATH];
WCHAR szDescription[MAX_PATH]; WCHAR szDescription[MAX_PATH];
WCHAR szArguments[2 * MAX_PATH]; WCHAR szArguments[2 * MAX_PATH];
WCHAR szOrigin[MAX_PATH]; WCHAR szOrigin[MAX_PATH];

View file

@ -84,7 +84,11 @@ CreateShortcut(PCREATE_LINK_CONTEXT pContext)
/* get the extension */ /* get the extension */
lpExtension = PathFindExtensionW(pContext->szTarget); lpExtension = PathFindExtensionW(pContext->szTarget);
if (IsExtensionAShortcut(lpExtension)) if (pContext->pidlTarget)
{
Path[0] = UNICODE_NULL;
}
else if (IsExtensionAShortcut(lpExtension))
{ {
hr = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_ALL, &IID_IShellLinkW, (void**)&pSourceShellLink); hr = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_ALL, &IID_IShellLinkW, (void**)&pSourceShellLink);
@ -126,11 +130,16 @@ CreateShortcut(PCREATE_LINK_CONTEXT pContext)
if (hr != S_OK) if (hr != S_OK)
return FALSE; return FALSE;
pShellLink->lpVtbl->SetPath(pShellLink, Path); if (pContext->pidlTarget)
pShellLink->lpVtbl->SetIDList(pShellLink, pContext->pidlTarget);
else
pShellLink->lpVtbl->SetPath(pShellLink, Path);
if (pContext->szArguments[0]) if (pContext->szArguments[0])
pShellLink->lpVtbl->SetArguments(pShellLink, pContext->szArguments); pShellLink->lpVtbl->SetArguments(pShellLink, pContext->szArguments);
pShellLink->lpVtbl->SetDescription(pShellLink, pContext->szDescription);
pShellLink->lpVtbl->SetWorkingDirectory(pShellLink, pContext->szWorkingDirectory); if (pContext->szDescription[0])
pShellLink->lpVtbl->SetDescription(pShellLink, pContext->szDescription);
hr = IUnknown_QueryInterface(pShellLink, &IID_IPersistFile, (void**)&pPersistFile); hr = IUnknown_QueryInterface(pShellLink, &IID_IPersistFile, (void**)&pPersistFile);
if (hr != S_OK) if (hr != S_OK)
@ -233,9 +242,9 @@ WelcomeDlgProc(HWND hwndDlg,
LPARAM lParam) LPARAM lParam)
{ {
LPPROPSHEETPAGEW ppsp; LPPROPSHEETPAGEW ppsp;
PCREATE_LINK_CONTEXT pContext; PCREATE_LINK_CONTEXT pContext = (PCREATE_LINK_CONTEXT)GetWindowLongPtr(hwndDlg, DWLP_USER);
LPPSHNOTIFY lppsn; LPPSHNOTIFY lppsn;
WCHAR szPath[MAX_PATH * 2]; WCHAR szPath[MAX_PATH * 2], szDisplayName[MAX_PATH];
WCHAR szDesc[100]; WCHAR szDesc[100];
WCHAR szTitle[100]; WCHAR szTitle[100];
BROWSEINFOW brws; BROWSEINFOW brws;
@ -253,54 +262,61 @@ WelcomeDlgProc(HWND hwndDlg,
break; break;
case WM_COMMAND: case WM_COMMAND:
{ {
switch(HIWORD(wParam)) switch (LOWORD(wParam))
{ {
case EN_CHANGE: case IDC_SHORTCUT_LOCATION:
if (SendDlgItemMessage(hwndDlg, IDC_SHORTCUT_LOCATION, WM_GETTEXTLENGTH, 0, 0)) {
if (HIWORD(wParam) == EN_CHANGE)
{ {
PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT); /* The text was changed by user. Invalidate pidlTarget. */
} if (pContext->pidlTarget)
else {
{ CoTaskMemFree(pContext->pidlTarget);
PropSheet_SetWizButtons(GetParent(hwndDlg), 0); pContext->pidlTarget = NULL;
}
if (SendDlgItemMessage(hwndDlg, IDC_SHORTCUT_LOCATION, WM_GETTEXTLENGTH, 0, 0))
PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT);
else
PropSheet_SetWizButtons(GetParent(hwndDlg), 0);
} }
break; break;
} }
switch(LOWORD(wParam))
{
case IDC_SHORTCUT_BROWSE: case IDC_SHORTCUT_BROWSE:
{
LoadStringW(hApplet, IDS_BROWSE_FOR_TARGET, szTitle, _countof(szTitle)); LoadStringW(hApplet, IDS_BROWSE_FOR_TARGET, szTitle, _countof(szTitle));
ZeroMemory(&brws, sizeof(brws)); ZeroMemory(&brws, sizeof(brws));
brws.hwndOwner = hwndDlg; brws.hwndOwner = hwndDlg;
brws.pidlRoot = NULL; brws.pidlRoot = NULL;
brws.pszDisplayName = szPath; brws.pszDisplayName = szDisplayName;
brws.lpszTitle = szTitle; brws.lpszTitle = szTitle;
brws.ulFlags = BIF_BROWSEINCLUDEFILES | BIF_RETURNONLYFSDIRS | brws.ulFlags = BIF_BROWSEINCLUDEFILES | BIF_NEWDIALOGSTYLE | BIF_SHAREABLE;
BIF_NEWDIALOGSTYLE | BIF_SHAREABLE;
brws.lpfn = NULL; brws.lpfn = NULL;
pidllist = SHBrowseForFolderW(&brws); pidllist = SHBrowseForFolderW(&brws);
if (!pidllist) if (!pidllist)
break; break;
if (SHGetPathFromIDListW(pidllist, szPath)) StringCchCopyW(pContext->szDescription, _countof(pContext->szDescription),
{ szDisplayName);
SetDlgItemTextW(hwndDlg, IDC_SHORTCUT_LOCATION, szPath);
SendDlgItemMessageW(hwndDlg, IDC_SHORTCUT_LOCATION, WM_SETFOCUS, 0, 0);
SendDlgItemMessageW(hwndDlg, IDC_SHORTCUT_LOCATION, EM_SETSEL, 0, -1);
}
else
{
SetDlgItemTextW(hwndDlg, IDC_SHORTCUT_LOCATION, NULL);
}
/* Free memory, if possible */ SHGetPathFromIDListW(pidllist, szPath);
CoTaskMemFree(pidllist);
if (PathFileExistsW(szPath) && !PathIsRelativeW(szPath))
SetDlgItemTextW(hwndDlg, IDC_SHORTCUT_LOCATION, szPath);
else
SetDlgItemTextW(hwndDlg, IDC_SHORTCUT_LOCATION, szDisplayName);
SendDlgItemMessageW(hwndDlg, IDC_SHORTCUT_LOCATION, EM_SETSEL, 0, -1);
if (pContext->pidlTarget)
CoTaskMemFree(pContext->pidlTarget);
pContext->pidlTarget = pidllist;
break; break;
}
} }
break; break;
case WM_NOTIFY: case WM_NOTIFY:
lppsn = (LPPSHNOTIFY) lParam; lppsn = (LPPSHNOTIFY) lParam;
pContext = (PCREATE_LINK_CONTEXT)GetWindowLongPtr(hwndDlg, DWLP_USER);
if (lppsn->hdr.code == PSN_SETACTIVE) if (lppsn->hdr.code == PSN_SETACTIVE)
{ {
SetDlgItemTextW(hwndDlg, IDC_SHORTCUT_LOCATION, pContext->szTarget); SetDlgItemTextW(hwndDlg, IDC_SHORTCUT_LOCATION, pContext->szTarget);
@ -316,11 +332,19 @@ WelcomeDlgProc(HWND hwndDlg,
WCHAR szName[128]; WCHAR szName[128];
LoadStringW(hApplet, IDS_NEW_INTERNET_SHORTCUT, szName, _countof(szName)); LoadStringW(hApplet, IDS_NEW_INTERNET_SHORTCUT, szName, _countof(szName));
StringCchCopyW(pContext->szDescription, _countof(pContext->szDescription), szName); StringCchCopyW(pContext->szDescription, _countof(pContext->szDescription), szName);
pContext->szWorkingDirectory[0] = 0;
pContext->szArguments[0] = 0; pContext->szArguments[0] = 0;
return FALSE; return FALSE;
} }
if (pContext->pidlTarget) /* The result of SHBrowseForFolderW */
{
SHGetPathFromIDListW(pContext->pidlTarget, pContext->szTarget);
pContext->szArguments[0] = 0;
return FALSE;
}
/* Otherwise, the target is a command line or pathname */
/* Split and build args */ /* Split and build args */
LPWSTR pszArgs = PathGetArgsW(szPath); LPWSTR pszArgs = PathGetArgsW(szPath);
if (pszArgs && pszArgs > szPath) if (pszArgs && pszArgs > szPath)
@ -334,10 +358,8 @@ WelcomeDlgProc(HWND hwndDlg,
} }
/* Find the file */ /* Find the file */
WCHAR szFound[MAX_PATH]; if (!PathFindOnPathExW(szPath, NULL, WHICH_DEFAULT) &&
StringCchCopyW(szFound, _countof(szFound), szPath); !PathFileExistsW(szPath))
if (!PathFindOnPathExW(szFound, NULL, WHICH_DEFAULT) &&
FindExecutableW(szPath, NULL, szFound) <= (HINSTANCE)(INT_PTR)32)
{ {
/* Not found */ /* Not found */
SendDlgItemMessageW(hwndDlg, IDC_SHORTCUT_LOCATION, EM_SETSEL, 0, -1); SendDlgItemMessageW(hwndDlg, IDC_SHORTCUT_LOCATION, EM_SETSEL, 0, -1);
@ -355,20 +377,17 @@ WelcomeDlgProc(HWND hwndDlg,
} }
/* Rebuild target */ /* Rebuild target */
StringCchCopyW(pContext->szTarget, _countof(pContext->szTarget), szFound); if (PathIsRelativeW(szPath))
GetFullPathNameW(szPath, _countof(pContext->szTarget), pContext->szTarget, NULL);
else
StringCchCopyW(pContext->szTarget, _countof(pContext->szTarget), szPath);
/* Get display name */ /* Get display name */
FileInfo.szDisplayName[0] = 0; FileInfo.szDisplayName[0] = UNICODE_NULL;
if (SHGetFileInfoW(szFound, 0, &FileInfo, sizeof(FileInfo), SHGFI_DISPLAYNAME)) if (SHGetFileInfoW(pContext->szTarget, 0, &FileInfo, sizeof(FileInfo), SHGFI_DISPLAYNAME))
StringCchCopyW(pContext->szDescription, _countof(pContext->szDescription), FileInfo.szDisplayName); StringCchCopyW(pContext->szDescription, _countof(pContext->szDescription), FileInfo.szDisplayName);
/* Set working directory */ break;
StringCchCopyW(pContext->szWorkingDirectory, _countof(pContext->szWorkingDirectory), szFound);
PathRemoveBackslashW(pContext->szWorkingDirectory);
PathRemoveFileSpecW(pContext->szWorkingDirectory);
PathRemoveBackslashW(pContext->szWorkingDirectory);
SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE);
} }
else if (lppsn->hdr.code == PSN_RESET && !lppsn->lParam) else if (lppsn->hdr.code == PSN_RESET && !lppsn->lParam)
{ {
@ -618,6 +637,8 @@ ShowCreateShortcutWizard(HWND hwndCPl, LPCWSTR szPath)
/* Display the wizard */ /* Display the wizard */
PropertySheet(&psh); PropertySheet(&psh);
CoTaskMemFree(pContext->pidlTarget);
HeapFree(GetProcessHeap(), 0, pContext); HeapFree(GetProcessHeap(), 0, pContext);
return TRUE; return TRUE;
} }

View file

@ -2635,8 +2635,8 @@ HRESULT CShellLink::DoOpen(LPCMINVOKECOMMANDINFO lpici)
else else
{ {
sei.lpFile = path; sei.lpFile = path;
sei.lpParameters = args;
} }
sei.lpParameters = args;
sei.lpClass = m_sLinkPath; sei.lpClass = m_sLinkPath;
sei.nShow = m_Header.nShowCommand; sei.nShow = m_Header.nShowCommand;
sei.lpDirectory = m_sWorkDir; sei.lpDirectory = m_sWorkDir;