From 96c0ef42094e067800e0806267ffb539e017df19 Mon Sep 17 00:00:00 2001 From: Katayama Hirofumi MZ Date: Sun, 8 Jul 2018 23:45:40 +0900 Subject: [PATCH] [SHELL32] Improve CShellLink a little (#651) Improve the display and UI in the shortcut dialog. CORE-11407 --- dll/win32/shell32/CShellLink.cpp | 602 +++++++++++++++++++------------ dll/win32/shell32/CShellLink.h | 8 + 2 files changed, 373 insertions(+), 237 deletions(-) diff --git a/dll/win32/shell32/CShellLink.cpp b/dll/win32/shell32/CShellLink.cpp index ddabd189495..1bbb2e11112 100644 --- a/dll/win32/shell32/CShellLink.cpp +++ b/dll/win32/shell32/CShellLink.cpp @@ -268,6 +268,8 @@ CShellLink::CShellLink() m_bRunAs = FALSE; m_bDirty = FALSE; m_pDBList = NULL; + m_bInInit = FALSE; + m_hIcon = NULL; m_sLinkPath = NULL; m_iIdOpen = -1; @@ -347,12 +349,13 @@ HRESULT STDMETHODCALLTYPE CShellLink::Save(LPCOLESTR pszFileName, BOOL fRemember if (SUCCEEDED(hr)) { - if (m_sLinkPath) - HeapFree(GetProcessHeap(), 0, m_sLinkPath); + if (pszFileName != m_sLinkPath) + { + if (m_sLinkPath) + HeapFree(GetProcessHeap(), 0, m_sLinkPath); - m_sLinkPath = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (wcslen(pszFileName) + 1) * sizeof(WCHAR)); - if (m_sLinkPath) - wcscpy(m_sLinkPath, pszFileName); + m_sLinkPath = strdupW(pszFileName); + } m_bDirty = FALSE; } @@ -1033,11 +1036,9 @@ static HRESULT ShellLink_UpdatePath(LPCWSTR sPathRel, LPCWSTR path, LPCWSTR sWor if (!*abs_path) wcscpy(abs_path, sPathRel); - *psPath = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (wcslen(abs_path) + 1) * sizeof(WCHAR)); + *psPath = strdupW(abs_path); if (!*psPath) return E_OUTOFMEMORY; - - wcscpy(*psPath, abs_path); } return S_OK; @@ -1415,11 +1416,12 @@ HRESULT STDMETHODCALLTYPE CShellLink::Resolve(HWND hwnd, DWORD fFlags) bSuccess = SHGetPathFromIDListW(m_pPidl, buffer); if (bSuccess && *buffer) { - m_sPath = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (wcslen(buffer) + 1) * sizeof(WCHAR)); - if (!m_sPath) - return E_OUTOFMEMORY; - - wcscpy(m_sPath, buffer); + if (buffer != m_sPath) + { + m_sPath = strdupW(buffer); + if (!m_sPath) + return E_OUTOFMEMORY; + } m_bDirty = TRUE; } @@ -1432,11 +1434,13 @@ HRESULT STDMETHODCALLTYPE CShellLink::Resolve(HWND hwnd, DWORD fFlags) // FIXME: Strange to do that here... if (!m_sIcoPath && m_sPath) { - m_sIcoPath = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (wcslen(m_sPath) + 1) * sizeof(WCHAR)); - if (!m_sIcoPath) - return E_OUTOFMEMORY; + if (m_sIcoPath != m_sPath) + { + m_sIcoPath = strdupW(m_sPath); + if (!m_sIcoPath) + return E_OUTOFMEMORY; + } - wcscpy(m_sIcoPath, m_sPath); m_Header.nIconIndex = 0; m_bDirty = TRUE; @@ -1561,12 +1565,12 @@ HRESULT STDMETHODCALLTYPE CShellLink::SetDescription(LPCWSTR pszName) HeapFree(GetProcessHeap(), 0, m_sDescription); if (pszName) { - m_sDescription = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, - (wcslen(pszName) + 1) * sizeof(WCHAR)); - if (!m_sDescription) - return E_OUTOFMEMORY; - - wcscpy(m_sDescription, pszName); + if (m_sDescription != pszName) + { + m_sDescription = strdupW(pszName); + if (!m_sDescription) + return E_OUTOFMEMORY; + } } else m_sDescription = NULL; @@ -1596,11 +1600,12 @@ HRESULT STDMETHODCALLTYPE CShellLink::SetWorkingDirectory(LPCWSTR pszDir) HeapFree(GetProcessHeap(), 0, m_sWorkDir); if (pszDir) { - m_sWorkDir = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, - (wcslen(pszDir) + 1) * sizeof(WCHAR)); - if (!m_sWorkDir) - return E_OUTOFMEMORY; - wcscpy(m_sWorkDir, pszDir); + if (m_sWorkDir != pszDir) + { + m_sWorkDir = strdupW(pszDir); + if (!m_sWorkDir) + return E_OUTOFMEMORY; + } } else m_sWorkDir = NULL; @@ -1630,12 +1635,12 @@ HRESULT STDMETHODCALLTYPE CShellLink::SetArguments(LPCWSTR pszArgs) HeapFree(GetProcessHeap(), 0, m_sArgs); if (pszArgs) { - m_sArgs = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, - (wcslen(pszArgs) + 1) * sizeof(WCHAR)); - if (!m_sArgs) - return E_OUTOFMEMORY; - - wcscpy(m_sArgs, pszArgs); + if (m_sArgs != pszArgs) + { + m_sArgs = strdupW(pszArgs); + if (!m_sArgs) + return E_OUTOFMEMORY; + } } else m_sArgs = NULL; @@ -1670,12 +1675,13 @@ HRESULT STDMETHODCALLTYPE CShellLink::GetIconLocation(LPWSTR pszIconPath, INT cc SHExpandEnvironmentStringsW(pInfo->szwTarget, szPath, _countof(szPath)); - m_sIcoPath = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, - (wcslen(szPath) + 1) * sizeof(WCHAR)); - if (!m_sIcoPath) - return E_OUTOFMEMORY; + if (m_sIcoPath != szPath) + { + m_sIcoPath = strdupW(szPath); + if (!m_sIcoPath) + return E_OUTOFMEMORY; + } - wcscpy(m_sIcoPath, szPath); m_Header.dwFlags |= SLDF_HAS_ICONLOCATION; m_bDirty = TRUE; @@ -1768,27 +1774,42 @@ HRESULT STDMETHODCALLTYPE CShellLink::GetIconLocation(UINT uFlags, PWSTR pszIcon HRESULT STDMETHODCALLTYPE CShellLink::Extract(PCWSTR pszFile, UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize) { - SHFILEINFOW info; + HRESULT hr = NOERROR; + UINT cxyLarge = LOWORD(nIconSize), cxySmall = HIWORD(nIconSize); if (phiconLarge) { - SHGetFileInfoW(pszFile, 0, &info, sizeof(info), - SHGFI_ICON | SHGFI_LARGEICON | SHGFI_LINKOVERLAY); - *phiconLarge = info.hIcon; - if (!info.hIcon) - return E_FAIL; + *phiconLarge = NULL; + PrivateExtractIconsW(pszFile, nIconIndex, cxyLarge, cxyLarge, phiconLarge, NULL, 1, 0); + + if (*phiconLarge == NULL) + hr = S_FALSE; } if (phiconSmall) { - SHGetFileInfoW(pszFile, 0, &info, sizeof(info), - SHGFI_ICON | SHGFI_SMALLICON | SHGFI_LINKOVERLAY); - *phiconSmall = info.hIcon; - if (!info.hIcon) - return E_FAIL; + *phiconSmall = NULL; + PrivateExtractIconsW(pszFile, nIconIndex, cxySmall, cxySmall, phiconSmall, NULL, 1, 0); + + if (*phiconSmall == NULL) + hr = S_FALSE; } - return S_OK; + if (hr == S_FALSE) + { + if (phiconLarge && *phiconLarge) + { + DestroyIcon(*phiconLarge); + *phiconLarge = NULL; + } + if (phiconSmall && *phiconSmall) + { + DestroyIcon(*phiconSmall); + *phiconSmall = NULL; + } + } + + return hr; } #if 0 @@ -1945,12 +1966,13 @@ HRESULT STDMETHODCALLTYPE CShellLink::SetIconLocation(LPCWSTR pszIconPath, INT i HeapFree(GetProcessHeap(), 0, m_sIcoPath); m_sIcoPath = NULL; - m_sIcoPath = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, - (wcslen(pszIconPath) + 1) * sizeof(WCHAR)); - if (!m_sIcoPath) - return E_OUTOFMEMORY; + if (m_sIcoPath != pszIconPath) + { + m_sIcoPath = strdupW(pszIconPath); + if (!m_sIcoPath) + return E_OUTOFMEMORY; + } - wcscpy(m_sIcoPath, pszIconPath); m_Header.dwFlags |= SLDF_HAS_ICONLOCATION; } @@ -1969,11 +1991,12 @@ HRESULT STDMETHODCALLTYPE CShellLink::SetRelativePath(LPCWSTR pszPathRel, DWORD HeapFree(GetProcessHeap(), 0, m_sPathRel); if (pszPathRel) { - m_sPathRel = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, - (wcslen(pszPathRel) + 1) * sizeof(WCHAR)); - if (!m_sPathRel) - return E_OUTOFMEMORY; - wcscpy(m_sPathRel, pszPathRel); + if (m_sPathRel != pszPathRel) + { + m_sPathRel = strdupW(pszPathRel); + if (!m_sPathRel) + return E_OUTOFMEMORY; + } } else m_sPathRel = NULL; @@ -2315,11 +2338,13 @@ HRESULT CShellLink::SetTargetFromPIDLOrPath(LPCITEMIDLIST pidl, LPCWSTR pszFile) /* Update the cached path (for link info) */ ShellLink_GetVolumeInfo(pszFile, &volume); - m_sPath = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, - (wcslen(pszFile) + 1) * sizeof(WCHAR)); - if (!m_sPath) - return E_OUTOFMEMORY; - wcscpy(m_sPath, pszFile); + + if (m_sPath != pszFile) + { + m_sPath = strdupW(pszFile); + if (!m_sPath) + return E_OUTOFMEMORY; + } m_bDirty = TRUE; return hr; @@ -2756,203 +2781,245 @@ LPWSTR SH_GetTargetTypeByPath(LPCWSTR lpcwFullPath) return wszBuf; } +BOOL CShellLink::OnInitDialog(HWND hwndDlg, HWND hwndFocus, LPARAM lParam) +{ + TRACE("CShellLink::OnInitDialog(hwnd %p hwndFocus %p lParam %p)\n", hwndDlg, hwndFocus, lParam); + + TRACE("m_sArgs: %S sComponent: %S m_sDescription: %S m_sIcoPath: %S m_sPath: %S m_sPathRel: %S sProduct: %S m_sWorkDir: %S\n", m_sArgs, sComponent, m_sDescription, + m_sIcoPath, m_sPath, m_sPathRel, sProduct, m_sWorkDir); + + m_bInInit = TRUE; + + /* Get file information */ + // FIXME! FIXME! Shouldn't we use m_sIcoPath, m_Header.nIconIndex instead??? + SHFILEINFOW fi; + if (!SHGetFileInfoW(m_sLinkPath, 0, &fi, sizeof(fi), SHGFI_TYPENAME | SHGFI_ICON)) + { + ERR("SHGetFileInfoW failed for %ls (%lu)\n", m_sLinkPath, GetLastError()); + fi.szTypeName[0] = L'\0'; + fi.hIcon = NULL; + } + + if (fi.hIcon) + { + if (m_hIcon) + DestroyIcon(m_hIcon); + m_hIcon = fi.hIcon; + SendDlgItemMessageW(hwndDlg, IDC_SHORTCUT_ICON, STM_SETICON, (WPARAM)m_hIcon, 0); + } + else + ERR("ExtractIconW failed %ls %u\n", m_sIcoPath, m_Header.nIconIndex); + + /* Target type */ + if (m_sPath) + SetDlgItemTextW(hwndDlg, IDC_SHORTCUT_TYPE_EDIT, SH_GetTargetTypeByPath(m_sPath)); + + /* Target location */ + if (m_sPath) + { + WCHAR target[MAX_PATH]; + StringCchCopyW(target, _countof(target), m_sPath); + PathRemoveFileSpecW(target); + SetDlgItemTextW(hwndDlg, IDC_SHORTCUT_LOCATION_EDIT, PathFindFileNameW(target)); + } + + /* Target path */ + if (m_sPath) + { + WCHAR newpath[2*MAX_PATH] = L"\0"; + if (wcschr(m_sPath, ' ')) + StringCchPrintfExW(newpath, _countof(newpath), NULL, NULL, 0, L"\"%ls\"", m_sPath); + else + StringCchCopyExW(newpath, _countof(newpath), m_sPath, NULL, NULL, 0); + + if (m_sArgs && m_sArgs[0]) + { + StringCchCatW(newpath, _countof(newpath), L" "); + StringCchCatW(newpath, _countof(newpath), m_sArgs); + } + SetDlgItemTextW(hwndDlg, IDC_SHORTCUT_TARGET_TEXT, newpath); + } + + /* Working dir */ + if (m_sWorkDir) + SetDlgItemTextW(hwndDlg, IDC_SHORTCUT_START_IN_EDIT, m_sWorkDir); + + /* Description */ + if (m_sDescription) + SetDlgItemTextW(hwndDlg, IDC_SHORTCUT_COMMENT_EDIT, m_sDescription); + + m_bInInit = FALSE; + + return TRUE; +} + +void CShellLink::OnCommand(HWND hwndDlg, int id, HWND hwndCtl, UINT codeNotify) +{ + switch (id) + { + case IDC_SHORTCUT_FIND: + SHOpenFolderAndSelectItems(m_pPidl, 0, NULL, 0); + /// + /// FIXME + /// open target directory + /// + return; + + case IDC_SHORTCUT_CHANGE_ICON: + { + WCHAR wszPath[MAX_PATH] = L""; + + if (m_sIcoPath) + wcscpy(wszPath, m_sIcoPath); + else + FindExecutableW(m_sPath, NULL, wszPath); + + INT IconIndex = m_Header.nIconIndex; + if (PickIconDlg(hwndDlg, wszPath, _countof(wszPath), &IconIndex)) + { + SetIconLocation(wszPath, IconIndex); + PropSheet_Changed(GetParent(hwndDlg), hwndDlg); + + HICON hIconLarge = CreateShortcutIcon(wszPath, IconIndex); + if (hIconLarge) + { + if (m_hIcon) + DestroyIcon(m_hIcon); + m_hIcon = hIconLarge; + SendDlgItemMessageW(hwndDlg, IDC_SHORTCUT_ICON, STM_SETICON, (WPARAM)m_hIcon, 0); + } + } + return; + } + + case IDC_SHORTCUT_ADVANCED: + { + INT_PTR result = DialogBoxParamW(shell32_hInstance, MAKEINTRESOURCEW(IDD_SHORTCUT_EXTENDED_PROPERTIES), hwndDlg, ExtendedShortcutProc, (LPARAM)m_bRunAs); + if (result == 1 || result == 0) + { + if (m_bRunAs != result) + { + PropSheet_Changed(GetParent(hwndDlg), hwndDlg); + } + + m_bRunAs = result; + } + return; + } + } + if (codeNotify == EN_CHANGE) + { + if (!m_bInInit) + PropSheet_Changed(GetParent(hwndDlg), hwndDlg); + } +} + +LRESULT CShellLink::OnNotify(HWND hwndDlg, int idFrom, LPNMHDR pnmhdr) +{ + WCHAR wszBuf[MAX_PATH]; + LPPSHNOTIFY lppsn = (LPPSHNOTIFY)pnmhdr; + + if (lppsn->hdr.code == PSN_APPLY) + { + /* set working directory */ + GetDlgItemTextW(hwndDlg, IDC_SHORTCUT_START_IN_EDIT, wszBuf, _countof(wszBuf)); + SetWorkingDirectory(wszBuf); + + /* set link destination */ + GetDlgItemTextW(hwndDlg, IDC_SHORTCUT_TARGET_TEXT, wszBuf, _countof(wszBuf)); + LPWSTR lpszArgs = NULL; + LPWSTR unquoted = strdupW(wszBuf); + StrTrimW(unquoted, L" "); + + if (!PathFileExistsW(unquoted)) + { + lpszArgs = PathGetArgsW(unquoted); + PathRemoveArgsW(unquoted); + StrTrimW(lpszArgs, L" "); + } + if (unquoted[0] == '"' && unquoted[wcslen(unquoted) - 1] == '"') + PathUnquoteSpacesW(unquoted); + + WCHAR *pwszExt = PathFindExtensionW(unquoted); + if (!wcsicmp(pwszExt, L".lnk")) + { + // FIXME load localized error msg + MessageBoxW(hwndDlg, L"You cannot create a link to a shortcut", L"Error", MB_ICONERROR); + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE); + return TRUE; + } + + if (!PathFileExistsW(unquoted)) + { + // FIXME load localized error msg + MessageBoxW(hwndDlg, L"The specified file name in the target box is invalid", L"Error", MB_ICONERROR); + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE); + return TRUE; + } + + SetPath(unquoted); + if (lpszArgs) + SetArguments(lpszArgs); + else + SetArguments(L"\0"); + + HeapFree(GetProcessHeap(), 0, unquoted); + + TRACE("This %p m_sLinkPath %S\n", this, m_sLinkPath); + Save(m_sLinkPath, TRUE); + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); + return TRUE; + } + return FALSE; +} + +void CShellLink::OnDestroy(HWND hwndDlg) +{ + if (m_hIcon) + { + DestroyIcon(m_hIcon); + m_hIcon = NULL; + } +} + /************************************************************************** * SH_ShellLinkDlgProc * * dialog proc of the shortcut property dialog */ -INT_PTR CALLBACK CShellLink::SH_ShellLinkDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +INT_PTR CALLBACK +CShellLink::SH_ShellLinkDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { + LPPROPSHEETPAGEW ppsp; CShellLink *pThis = reinterpret_cast(GetWindowLongPtr(hwndDlg, DWLP_USER)); - switch(uMsg) + switch (uMsg) { case WM_INITDIALOG: - { - LPPROPSHEETPAGEW ppsp = (LPPROPSHEETPAGEW)lParam; + ppsp = (LPPROPSHEETPAGEW)lParam; if (ppsp == NULL) break; - TRACE("ShellLink_DlgProc (WM_INITDIALOG hwnd %p lParam %p ppsplParam %x)\n", hwndDlg, lParam, ppsp->lParam); - pThis = reinterpret_cast(ppsp->lParam); SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pThis); - - TRACE("m_sArgs: %S sComponent: %S m_sDescription: %S m_sIcoPath: %S m_sPath: %S m_sPathRel: %S sProduct: %S m_sWorkDir: %S\n", pThis->m_sArgs, pThis->sComponent, pThis->m_sDescription, - pThis->m_sIcoPath, pThis->m_sPath, pThis->m_sPathRel, pThis->sProduct, pThis->m_sWorkDir); - - /* Get file information */ - // FIXME! FIXME! Shouldn't we use pThis->m_sIcoPath, pThis->m_Header.nIconIndex instead??? - SHFILEINFOW fi; - if (!SHGetFileInfoW(pThis->m_sLinkPath, 0, &fi, sizeof(fi), SHGFI_TYPENAME | SHGFI_ICON)) - { - ERR("SHGetFileInfoW failed for %ls (%lu)\n", pThis->m_sLinkPath, GetLastError()); - fi.szTypeName[0] = L'\0'; - fi.hIcon = NULL; - } - - if (fi.hIcon) // TODO: destroy icon - SendDlgItemMessageW(hwndDlg, IDC_SHORTCUT_ICON, STM_SETICON, (WPARAM)fi.hIcon, 0); - else - ERR("ExtractIconW failed %ls %u\n", pThis->m_sIcoPath, pThis->m_Header.nIconIndex); - - /* Target type */ - if (pThis->m_sPath) - SetDlgItemTextW(hwndDlg, IDC_SHORTCUT_TYPE_EDIT, SH_GetTargetTypeByPath(pThis->m_sPath)); - - /* Target location */ - if (pThis->m_sPath) - { - WCHAR target[MAX_PATH]; - StringCchCopyW(target, _countof(target), pThis->m_sPath); - PathRemoveFileSpecW(target); - SetDlgItemTextW(hwndDlg, IDC_SHORTCUT_LOCATION_EDIT, PathFindFileNameW(target)); - } - - /* Target path */ - if (pThis->m_sPath) - { - WCHAR newpath[2*MAX_PATH] = L"\0"; - if (wcschr(pThis->m_sPath, ' ')) - StringCchPrintfExW(newpath, _countof(newpath), NULL, NULL, 0, L"\"%ls\"", pThis->m_sPath); - else - StringCchCopyExW(newpath, _countof(newpath), pThis->m_sPath, NULL, NULL, 0); - - if (pThis->m_sArgs && pThis->m_sArgs[0]) - { - StringCchCatW(newpath, _countof(newpath), L" "); - StringCchCatW(newpath, _countof(newpath), pThis->m_sArgs); - } - SetDlgItemTextW(hwndDlg, IDC_SHORTCUT_TARGET_TEXT, newpath); - } - - /* Working dir */ - if (pThis->m_sWorkDir) - SetDlgItemTextW(hwndDlg, IDC_SHORTCUT_START_IN_EDIT, pThis->m_sWorkDir); - - /* Description */ - if (pThis->m_sDescription) - SetDlgItemTextW(hwndDlg, IDC_SHORTCUT_COMMENT_EDIT, pThis->m_sDescription); - - return TRUE; - } + return pThis->OnInitDialog(hwndDlg, (HWND)(wParam), lParam); case WM_NOTIFY: - { - LPPSHNOTIFY lppsn = (LPPSHNOTIFY)lParam; - if (lppsn->hdr.code == PSN_APPLY) - { - WCHAR wszBuf[MAX_PATH]; - /* set working directory */ - GetDlgItemTextW(hwndDlg, IDC_SHORTCUT_START_IN_EDIT, wszBuf, _countof(wszBuf)); - pThis->SetWorkingDirectory(wszBuf); - /* set link destination */ - GetDlgItemTextW(hwndDlg, IDC_SHORTCUT_TARGET_TEXT, wszBuf, _countof(wszBuf)); - LPWSTR lpszArgs = NULL; - LPWSTR unquoted = strdupW(wszBuf); - StrTrimW(unquoted, L" "); - if (!PathFileExistsW(unquoted)) - { - lpszArgs = PathGetArgsW(unquoted); - PathRemoveArgsW(unquoted); - StrTrimW(lpszArgs, L" "); - } - if (unquoted[0] == '"' && unquoted[wcslen(unquoted)-1] == '"') - PathUnquoteSpacesW(unquoted); - - - WCHAR *pwszExt = PathFindExtensionW(unquoted); - if (!wcsicmp(pwszExt, L".lnk")) - { - // FIXME load localized error msg - MessageBoxW(hwndDlg, L"You cannot create a link to a shortcut", L"Error", MB_ICONERROR); - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE); - return TRUE; - } - - if (!PathFileExistsW(unquoted)) - { - // FIXME load localized error msg - MessageBoxW(hwndDlg, L"The specified file name in the target box is invalid", L"Error", MB_ICONERROR); - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE); - return TRUE; - } - - pThis->SetPath(unquoted); - if (lpszArgs) - pThis->SetArguments(lpszArgs); - else - pThis->SetArguments(L"\0"); - - HeapFree(GetProcessHeap(), 0, unquoted); - - TRACE("This %p m_sLinkPath %S\n", pThis, pThis->m_sLinkPath); - pThis->Save(pThis->m_sLinkPath, TRUE); - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); - return TRUE; - } - break; - } + return pThis->OnNotify(hwndDlg, (int)wParam, (NMHDR *)lParam); case WM_COMMAND: - switch(LOWORD(wParam)) - { - case IDC_SHORTCUT_FIND: - SHOpenFolderAndSelectItems(pThis->m_pPidl, 0, NULL, 0); - /// - /// FIXME - /// open target directory - /// - return TRUE; + pThis->OnCommand(hwndDlg, LOWORD(wParam), (HWND)lParam, HIWORD(wParam)); + break; - case IDC_SHORTCUT_CHANGE_ICON: - { - WCHAR wszPath[MAX_PATH] = L""; - - if (pThis->m_sIcoPath) - wcscpy(wszPath, pThis->m_sIcoPath); - else - FindExecutableW(pThis->m_sPath, NULL, wszPath); - - INT IconIndex = pThis->m_Header.nIconIndex; - if (PickIconDlg(hwndDlg, wszPath, _countof(wszPath), &IconIndex)) - { - pThis->SetIconLocation(wszPath, IconIndex); - - HICON hIconLarge = NULL; - if (S_OK == pThis->Extract(wszPath, IconIndex, &hIconLarge, NULL, 0)) - { - HICON hIconOld = (HICON)SendDlgItemMessageW(hwndDlg, IDC_SHORTCUT_ICON, STM_GETICON, 0, 0); - SendDlgItemMessageW(hwndDlg, IDC_SHORTCUT_ICON, STM_SETICON, (WPARAM)hIconLarge, 0); - DestroyIcon(hIconOld); - } - } - return TRUE; - } - - case IDC_SHORTCUT_ADVANCED: - { - INT_PTR result = DialogBoxParamW(shell32_hInstance, MAKEINTRESOURCEW(IDD_SHORTCUT_EXTENDED_PROPERTIES), hwndDlg, ExtendedShortcutProc, (LPARAM)pThis->m_bRunAs); - if (result == 1 || result == 0) - { - if (pThis->m_bRunAs != result) - { - PropSheet_Changed(GetParent(hwndDlg), hwndDlg); - } - - pThis->m_bRunAs = result; - } - return TRUE; - } - } - if (HIWORD(wParam) == EN_CHANGE) - PropSheet_Changed(GetParent(hwndDlg), hwndDlg); + case WM_DESTROY: + pThis->OnDestroy(hwndDlg); break; default: break; } + return FALSE; } @@ -3083,3 +3150,64 @@ HRESULT WINAPI IShellLink_ConstructFromFile(IShellFolder * psf, LPCITEMIDLIST pi return IShellLink_ConstructFromPath(path, riid, ppv); } + +HICON CShellLink::CreateShortcutIcon(LPCWSTR wszIconPath, INT IconIndex) +{ + const INT cx = GetSystemMetrics(SM_CXICON), cy = GetSystemMetrics(SM_CYICON); + const COLORREF crMask = GetSysColor(COLOR_3DFACE); + HDC hDC; + HIMAGELIST himl = ImageList_Create(cx, cy, ILC_COLOR32 | ILC_MASK, 1, 1); + HICON hIcon = NULL, hNewIcon = NULL; + HICON hShortcut = (HICON)LoadImageW(shell32_hInstance, MAKEINTRESOURCE(IDI_SHELL_SHORTCUT), + IMAGE_ICON, cx, cy, 0); + + ::ExtractIconExW(wszIconPath, IconIndex, &hIcon, NULL, 1); + if (!hIcon || !hShortcut || !himl) + goto cleanup; + + hDC = CreateCompatibleDC(NULL); + if (hDC) + { + // create 32bpp bitmap + BITMAPINFO bi; + ZeroMemory(&bi, sizeof(bi)); + bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bi.bmiHeader.biWidth = cx; + bi.bmiHeader.biHeight = cy; + bi.bmiHeader.biPlanes = 1; + bi.bmiHeader.biBitCount = 32; + LPVOID pvBits; + HBITMAP hbm = CreateDIBSection(hDC, &bi, DIB_RGB_COLORS, &pvBits, NULL, 0); + if (hbm) + { + // draw the icon image + HGDIOBJ hbmOld = SelectObject(hDC, hbm); + { + HBRUSH hbr = CreateSolidBrush(crMask); + RECT rc = { 0, 0, cx, cy }; + FillRect(hDC, &rc, hbr); + DeleteObject(hbr); + + DrawIconEx(hDC, 0, 0, hIcon, cx, cy, 0, NULL, DI_NORMAL); + DrawIconEx(hDC, 0, 0, hShortcut, cx, cy, 0, NULL, DI_NORMAL); + } + SelectObject(hDC, hbmOld); + + INT iAdded = ImageList_AddMasked(himl, hbm, crMask); + hNewIcon = ImageList_GetIcon(himl, iAdded, ILD_NORMAL | ILD_TRANSPARENT); + + DeleteObject(hbm); + } + DeleteDC(hDC); + } + +cleanup: + if (hIcon) + DestroyIcon(hIcon); + if (hShortcut) + DestroyIcon(hShortcut); + if (himl) + ImageList_Destroy(himl); + + return hNewIcon; +} diff --git a/dll/win32/shell32/CShellLink.h b/dll/win32/shell32/CShellLink.h index c8ce27efadf..3380a526c38 100644 --- a/dll/win32/shell32/CShellLink.h +++ b/dll/win32/shell32/CShellLink.h @@ -81,6 +81,8 @@ private: BOOL m_bRunAs; BOOL m_bDirty; LPDBLIST m_pDBList; /* Optional data block list (in the extra data section) */ + BOOL m_bInInit; // in initialization or not + HICON m_hIcon; /* Pointers to strings inside Logo3/Darwin info blocks, cached for debug info purposes only */ LPWSTR sProduct; @@ -98,12 +100,18 @@ private: HRESULT SetAdvertiseInfo(LPCWSTR str); HRESULT WriteAdvertiseInfo(LPCWSTR string, DWORD dwSig); HRESULT SetTargetFromPIDLOrPath(LPCITEMIDLIST pidl, LPCWSTR pszFile); + HICON CreateShortcutIcon(LPCWSTR wszIconPath, INT IconIndex); public: CShellLink(); ~CShellLink(); static INT_PTR CALLBACK SH_ShellLinkDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); + BOOL OnInitDialog(HWND hwndDlg, HWND hwndFocus, LPARAM lParam); + void OnCommand(HWND hwndDlg, int id, HWND hwndCtl, UINT codeNotify); + LRESULT OnNotify(HWND hwndDlg, int idFrom, LPNMHDR pnmhdr); + void OnDestroy(HWND hwndDlg); + // IPersistFile virtual HRESULT STDMETHODCALLTYPE GetClassID(CLSID *pclsid); virtual HRESULT STDMETHODCALLTYPE IsDirty();