WINE_DEFAULT_DEBUG_CHANNEL(shell);
+/*
+ * Allows to define whether or not Windows-compatible behaviour
+ * should be adopted when setting and retrieving icon location paths.
+ * See CShellLink::SetIconLocation(LPCWSTR pszIconPath, INT iIcon)
+ * for more details.
+ */
+#define ICON_LINK_WINDOWS_COMPAT
+
#define SHLINK_LOCAL 0
#define SHLINK_REMOTE 1
m_bRunAs = FALSE;
m_bDirty = FALSE;
m_pDBList = NULL;
+ m_bInInit = FALSE;
+ m_hIcon = NULL;
m_sLinkPath = NULL;
m_iIdOpen = -1;
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;
}
else
{
UINT len = 0;
- while (p[len] && len < maxlen)
+ while (len < maxlen && p[len])
len++;
UINT wlen = MultiByteToWideChar(CP_ACP, 0, p, len, NULL, 0);
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;
if (!m_sArgs)
return E_OUTOFMEMORY;
}
-
m_bDirty = TRUE;
return S_OK;
/* Clear the cached path */
HeapFree(GetProcessHeap(), 0, m_sPath);
- m_sPath = NULL;
m_sPath = shelllink_get_msi_component_path(component);
if (!m_sPath)
return E_FAIL;
bSuccess = SHGetPathFromIDListW(m_pPidl, buffer);
if (bSuccess && *buffer)
{
- m_sPath = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (wcslen(buffer) + 1) * sizeof(WCHAR));
+ m_sPath = strdupW(buffer);
if (!m_sPath)
return E_OUTOFMEMORY;
- wcscpy(m_sPath, buffer);
-
m_bDirty = TRUE;
}
else
// FIXME: Strange to do that here...
if (!m_sIcoPath && m_sPath)
{
- m_sIcoPath = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (wcslen(m_sPath) + 1) * sizeof(WCHAR));
+ m_sIcoPath = strdupW(m_sPath);
if (!m_sIcoPath)
return E_OUTOFMEMORY;
- wcscpy(m_sIcoPath, m_sPath);
m_Header.nIconIndex = 0;
m_bDirty = TRUE;
TRACE("(%p)->(desc=%s)\n", this, debugstr_w(pszName));
HeapFree(GetProcessHeap(), 0, m_sDescription);
+ m_sDescription = NULL;
+
if (pszName)
{
- m_sDescription = (LPWSTR)HeapAlloc(GetProcessHeap(), 0,
- (wcslen(pszName) + 1) * sizeof(WCHAR));
+ m_sDescription = strdupW(pszName);
if (!m_sDescription)
return E_OUTOFMEMORY;
-
- wcscpy(m_sDescription, pszName);
}
- else
- m_sDescription = NULL;
-
m_bDirty = TRUE;
return S_OK;
TRACE("(%p)->(dir=%s)\n", this, debugstr_w(pszDir));
HeapFree(GetProcessHeap(), 0, m_sWorkDir);
+ m_sWorkDir = NULL;
+
if (pszDir)
{
- m_sWorkDir = (LPWSTR)HeapAlloc(GetProcessHeap(), 0,
- (wcslen(pszDir) + 1) * sizeof(WCHAR));
+ m_sWorkDir = strdupW(pszDir);
if (!m_sWorkDir)
return E_OUTOFMEMORY;
- wcscpy(m_sWorkDir, pszDir);
}
- else
- m_sWorkDir = NULL;
-
m_bDirty = TRUE;
return S_OK;
TRACE("(%p)->(args=%s)\n", this, debugstr_w(pszArgs));
HeapFree(GetProcessHeap(), 0, m_sArgs);
+ m_sArgs = NULL;
+
if (pszArgs)
{
- m_sArgs = (LPWSTR)HeapAlloc(GetProcessHeap(), 0,
- (wcslen(pszArgs) + 1) * sizeof(WCHAR));
+ m_sArgs = strdupW(pszArgs);
if (!m_sArgs)
return E_OUTOFMEMORY;
-
- wcscpy(m_sArgs, pszArgs);
}
- else
- m_sArgs = NULL;
-
m_bDirty = TRUE;
return S_OK;
pInfo = (LPEXP_SZ_LINK)SHFindDataBlock(m_pDBList, EXP_SZ_ICON_SIG);
if (pInfo && (pInfo->cbSize == sizeof(*pInfo)))
{
+ SHExpandEnvironmentStringsW(pInfo->szwTarget, szPath, _countof(szPath));
+
m_Header.dwFlags &= ~SLDF_HAS_ICONLOCATION;
HeapFree(GetProcessHeap(), 0, m_sIcoPath);
- m_sIcoPath = NULL;
- SHExpandEnvironmentStringsW(pInfo->szwTarget, szPath, _countof(szPath));
-
- m_sIcoPath = (LPWSTR)HeapAlloc(GetProcessHeap(), 0,
- (wcslen(szPath) + 1) * sizeof(WCHAR));
+ m_sIcoPath = strdupW(szPath);
if (!m_sIcoPath)
return E_OUTOFMEMORY;
- wcscpy(m_sIcoPath, szPath);
m_Header.dwFlags |= SLDF_HAS_ICONLOCATION;
m_bDirty = TRUE;
HRESULT STDMETHODCALLTYPE CShellLink::GetIconLocation(UINT uFlags, PWSTR pszIconFile, UINT cchMax, int *piIndex, UINT *pwFlags)
{
HRESULT hr;
+
+ pszIconFile[0] = UNICODE_NULL;
+
/*
* It is possible for a shell link to point to another shell link,
* and in particular there is the possibility to point to itself.
*/
uFlags |= GIL_FORSHORTCUT;
- if (m_pPidl || m_sPath)
- {
- /* first look for an icon using the PIDL (if present) */
- if (m_pPidl)
- hr = SHELL_PidlGetIconLocationW(m_pPidl, uFlags, pszIconFile, cchMax, piIndex, pwFlags);
- else
- hr = E_FAIL;
-
-#if 0 // FIXME: Analyse further whether this is needed...
- /* if we couldn't find an icon yet, look for it using the file system path */
- if (FAILED(hr) && m_sPath)
- {
- LPITEMIDLIST pidl;
- CComPtr<IShellFolder> pdsk;
-
- hr = SHGetDesktopFolder(&pdsk);
+ if (uFlags & GIL_DEFAULTICON)
+ return S_FALSE;
- /* LPITEMIDLIST pidl = ILCreateFromPathW(sPath); */
- hr = pdsk->ParseDisplayName(0, NULL, m_sPath, NULL, &pidl, NULL);
- if (SUCCEEDED(hr))
- {
- hr = SHELL_PidlGetIconLocationW(pidl, uFlags, pszIconFile, cchMax, piIndex, pwFlags);
- SHFree(pidl);
- }
- }
-#endif
- return hr;
+ hr = GetIconLocation(pszIconFile, cchMax, piIndex);
+ if (FAILED(hr) || pszIconFile[0] == UNICODE_NULL)
+ {
+ hr = SHELL_PidlGetIconLocationW(m_pPidl, uFlags, pszIconFile, cchMax, piIndex, pwFlags);
+ }
+ else
+ {
+ *pwFlags = GIL_NOTFILENAME | GIL_PERCLASS;
}
- return S_OK;
+ return hr;
}
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
HRESULT STDMETHODCALLTYPE CShellLink::SetIconLocation(LPCWSTR pszIconPath, INT iIcon)
{
HRESULT hr = E_FAIL;
- WCHAR szUnExpIconPath[MAX_PATH];
+ WCHAR szIconPath[MAX_PATH];
TRACE("(%p)->(path=%s iicon=%u)\n", this, debugstr_w(pszIconPath), iIcon);
if (pszIconPath)
{
- /* Try to fully unexpand the icon path */
-
/*
* Check whether the user-given file path contains unexpanded
* environment variables. If so, create a target environment block.
* refer to the same place even if the would-be corresponding
* environment variable could change).
*/
- // FIXME: http://stackoverflow.com/questions/2976489/ishelllinkseticonlocation-translates-my-icon-path-into-program-files-which-i
- // if (PathFullyUnExpandEnvStringsW(pszIconPath, szUnExpIconPath, _countof(szUnExpIconPath)))
- SHExpandEnvironmentStringsW(pszIconPath, szUnExpIconPath, _countof(szUnExpIconPath));
- if (wcscmp(pszIconPath, szUnExpIconPath) != 0)
+#ifdef ICON_LINK_WINDOWS_COMPAT
+ /* Try to fully unexpand the icon path */
+ // if (PathFullyUnExpandEnvStringsW(pszIconPath, szIconPath, _countof(szIconPath)))
+ BOOL bSuccess = PathUnExpandEnvStringsW(pszIconPath, szIconPath, _countof(szIconPath));
+ if (bSuccess && wcscmp(pszIconPath, szIconPath) != 0)
+#else
+ /*
+ * In some situations, described in http://stackoverflow.com/questions/2976489/ishelllinkseticonlocation-translates-my-icon-path-into-program-files-which-i
+ * the result of PathUnExpandEnvStringsW() could be wrong, and instead
+ * one would have to store the actual provided icon location path, while
+ * creating an icon environment block ONLY if that path already contains
+ * environment variables. This is what the present case is trying to implement.
+ */
+ SHExpandEnvironmentStringsW(pszIconPath, szIconPath, _countof(szIconPath));
+ if (wcscmp(pszIconPath, szIconPath) != 0)
+#endif
{
- /* Unexpansion succeeded, so we need an icon environment block */
+ /*
+ * The user-given file path contains unexpanded environment
+ * variables, so we need an icon environment block.
+ */
EXP_SZ_LINK buffer;
LPEXP_SZ_LINK pInfo;
+#ifdef ICON_LINK_WINDOWS_COMPAT
+ /* Make pszIconPath point to the unexpanded path */
+ LPCWSTR pszOrgIconPath = pszIconPath;
+ pszIconPath = szIconPath;
+#endif
pInfo = (LPEXP_SZ_LINK)SHFindDataBlock(m_pDBList, EXP_SZ_ICON_SIG);
if (pInfo)
{
buffer.dwSignature = EXP_SZ_ICON_SIG;
}
- lstrcpynW(pInfo->szwTarget, szUnExpIconPath, _countof(pInfo->szwTarget));
- WideCharToMultiByte(CP_ACP, 0, szUnExpIconPath, -1,
+ lstrcpynW(pInfo->szwTarget, pszIconPath, _countof(pInfo->szwTarget));
+ WideCharToMultiByte(CP_ACP, 0, pszIconPath, -1,
pInfo->szTarget, _countof(pInfo->szTarget), NULL, NULL);
hr = S_OK;
hr = AddDataBlock(pInfo);
if (hr == S_OK)
m_Header.dwFlags |= SLDF_HAS_EXP_ICON_SZ;
+
+#ifdef ICON_LINK_WINDOWS_COMPAT
+ /* Set pszIconPath back to the original one */
+ pszIconPath = pszOrgIconPath;
+#else
+ /* Now, make pszIconPath point to the expanded path */
+ pszIconPath = szIconPath;
+#endif
}
else
{
- /* Unexpansion failed, so we need to remove any icon environment block */
+ /*
+ * The user-given file path does not contain unexpanded environment
+ * variables, so we need to remove any icon environment block.
+ */
m_Header.dwFlags &= ~SLDF_HAS_EXP_ICON_SZ;
RemoveDataBlock(EXP_SZ_ICON_SIG);
+
+ /* pszIconPath points to the user path */
}
}
- /* Store the original icon path location (this one may contain unexpanded environment strings) */
+#ifdef ICON_LINK_WINDOWS_COMPAT
+ /* Store the original icon path location (may contain unexpanded environment strings) */
+#endif
if (pszIconPath)
{
m_Header.dwFlags &= ~SLDF_HAS_ICONLOCATION;
HeapFree(GetProcessHeap(), 0, m_sIcoPath);
- m_sIcoPath = NULL;
- m_sIcoPath = (LPWSTR)HeapAlloc(GetProcessHeap(), 0,
- (wcslen(pszIconPath) + 1) * sizeof(WCHAR));
+ m_sIcoPath = strdupW(pszIconPath);
if (!m_sIcoPath)
return E_OUTOFMEMORY;
- wcscpy(m_sIcoPath, pszIconPath);
m_Header.dwFlags |= SLDF_HAS_ICONLOCATION;
}
TRACE("(%p)->(path=%s %x)\n", this, debugstr_w(pszPathRel), dwReserved);
HeapFree(GetProcessHeap(), 0, m_sPathRel);
+ m_sPathRel = NULL;
+
if (pszPathRel)
{
- m_sPathRel = (LPWSTR)HeapAlloc(GetProcessHeap(), 0,
- (wcslen(pszPathRel) + 1) * sizeof(WCHAR));
+ m_sPathRel = strdupW(pszPathRel);
if (!m_sPathRel)
return E_OUTOFMEMORY;
- wcscpy(m_sPathRel, pszPathRel);
}
- else
- m_sPathRel = NULL;
-
m_bDirty = TRUE;
return ShellLink_UpdatePath(m_sPathRel, m_sPath, m_sWorkDir, &m_sPath);
/* 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)
+ HeapFree(GetProcessHeap(), 0, m_sPath);
+
+ m_sPath = strdupW(pszFile);
if (!m_sPath)
return E_OUTOFMEMORY;
- wcscpy(m_sPath, pszFile);
m_bDirty = TRUE;
return hr;
if (hr == S_OK)
m_Header.dwFlags |= SLDF_HAS_EXP_SZ;
- /* Now, make pszFile point to the expanded buffer */
+ /* Now, make pszFile point to the expanded path */
pszFile = szPath;
}
else
return wszBuf;
}
-/**************************************************************************
- * SH_ShellLinkDlgProc
- *
- * dialog proc of the shortcut property dialog
- */
-
-INT_PTR CALLBACK CShellLink::SH_ShellLinkDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+BOOL CShellLink::OnInitDialog(HWND hwndDlg, HWND hwndFocus, LPARAM lParam)
{
- CShellLink *pThis = reinterpret_cast<CShellLink *>(GetWindowLongPtr(hwndDlg, DWLP_USER));
+ TRACE("CShellLink::OnInitDialog(hwnd %p hwndFocus %p lParam %p)\n", hwndDlg, hwndFocus, lParam);
- switch(uMsg)
+ 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))
{
- case WM_INITDIALOG:
+ 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])
{
- LPPROPSHEETPAGEW ppsp = (LPPROPSHEETPAGEW)lParam;
- if (ppsp == NULL)
- break;
+ StringCchCatW(newpath, _countof(newpath), L" ");
+ StringCchCatW(newpath, _countof(newpath), m_sArgs);
+ }
+ SetDlgItemTextW(hwndDlg, IDC_SHORTCUT_TARGET_TEXT, newpath);
+ }
- TRACE("ShellLink_DlgProc (WM_INITDIALOG hwnd %p lParam %p ppsplParam %x)\n", hwndDlg, lParam, ppsp->lParam);
+ /* Working dir */
+ if (m_sWorkDir)
+ SetDlgItemTextW(hwndDlg, IDC_SHORTCUT_START_IN_EDIT, m_sWorkDir);
- pThis = reinterpret_cast<CShellLink *>(ppsp->lParam);
- SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pThis);
+ /* Description */
+ if (m_sDescription)
+ SetDlgItemTextW(hwndDlg, IDC_SHORTCUT_COMMENT_EDIT, m_sDescription);
- 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);
+ m_bInInit = FALSE;
- /* 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;
- }
+ return TRUE;
+}
- 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);
+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;
- /* Target type */
- if (pThis->m_sPath)
- SetDlgItemTextW(hwndDlg, IDC_SHORTCUT_TYPE_EDIT, SH_GetTargetTypeByPath(pThis->m_sPath));
+ case IDC_SHORTCUT_CHANGE_ICON:
+ {
+ WCHAR wszPath[MAX_PATH] = L"";
+
+ if (m_sIcoPath)
+ wcscpy(wszPath, m_sIcoPath);
+ else
+ FindExecutableW(m_sPath, NULL, wszPath);
- /* Target location */
- if (pThis->m_sPath)
+ INT IconIndex = m_Header.nIconIndex;
+ if (PickIconDlg(hwndDlg, wszPath, _countof(wszPath), &IconIndex))
{
- WCHAR target[MAX_PATH];
- StringCchCopyW(target, _countof(target), pThis->m_sPath);
- PathRemoveFileSpecW(target);
- SetDlgItemTextW(hwndDlg, IDC_SHORTCUT_LOCATION_EDIT, PathFindFileNameW(target));
+ 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;
+ }
- /* Target path */
- if (pThis->m_sPath)
+ 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)
{
- 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])
+ if (m_bRunAs != result)
{
- StringCchCatW(newpath, _countof(newpath), L" ");
- StringCchCatW(newpath, _countof(newpath), pThis->m_sArgs);
+ PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
}
- SetDlgItemTextW(hwndDlg, IDC_SHORTCUT_TARGET_TEXT, newpath);
+
+ m_bRunAs = result;
}
+ return;
+ }
+ }
+ if (codeNotify == EN_CHANGE)
+ {
+ if (!m_bInInit)
+ PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
+ }
+}
- /* Working dir */
- if (pThis->m_sWorkDir)
- SetDlgItemTextW(hwndDlg, IDC_SHORTCUT_START_IN_EDIT, pThis->m_sWorkDir);
+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);
- /* Description */
- if (pThis->m_sDescription)
- SetDlgItemTextW(hwndDlg, IDC_SHORTCUT_COMMENT_EDIT, pThis->m_sDescription);
+ /* 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;
}
- case WM_NOTIFY:
+ if (!PathFileExistsW(unquoted))
{
- 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);
+ // 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");
- 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;
- }
+ HeapFree(GetProcessHeap(), 0, unquoted);
- 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;
- }
+ TRACE("This %p m_sLinkPath %S\n", this, m_sLinkPath);
+ Save(m_sLinkPath, TRUE);
+ SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATHW, m_sLinkPath, NULL);
+ SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR);
+ return TRUE;
+ }
+ return FALSE;
+}
- pThis->SetPath(unquoted);
- if (lpszArgs)
- pThis->SetArguments(lpszArgs);
- else
- pThis->SetArguments(L"\0");
+void CShellLink::OnDestroy(HWND hwndDlg)
+{
+ if (m_hIcon)
+ {
+ DestroyIcon(m_hIcon);
+ m_hIcon = NULL;
+ }
+}
- HeapFree(GetProcessHeap(), 0, unquoted);
+/**************************************************************************
+ * SH_ShellLinkDlgProc
+ *
+ * dialog proc of the shortcut property dialog
+ */
- 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;
- }
+INT_PTR CALLBACK
+CShellLink::SH_ShellLinkDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ LPPROPSHEETPAGEW ppsp;
+ CShellLink *pThis = reinterpret_cast<CShellLink *>(GetWindowLongPtr(hwndDlg, DWLP_USER));
+
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ ppsp = (LPPROPSHEETPAGEW)lParam;
+ if (ppsp == NULL)
+ break;
+
+ pThis = reinterpret_cast<CShellLink *>(ppsp->lParam);
+ SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pThis);
+ return pThis->OnInitDialog(hwndDlg, (HWND)(wParam), lParam);
+
+ case WM_NOTIFY:
+ 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;
-
- 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;
- }
+ pThis->OnCommand(hwndDlg, LOWORD(wParam), (HWND)lParam, HIWORD(wParam));
+ break;
- 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;
}
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;
+}