976 lines
24 KiB
C++
976 lines
24 KiB
C++
|
/*
|
||
|
* isshlink.cpp - IShellLink implementation for Intshcut class.
|
||
|
*/
|
||
|
|
||
|
|
||
|
|
||
|
#include "priv.h"
|
||
|
#include "ishcut.h"
|
||
|
#include "resource.h"
|
||
|
|
||
|
|
||
|
#include <mluisupp.h>
|
||
|
|
||
|
/* Types
|
||
|
********/
|
||
|
|
||
|
typedef enum isl_getpath_flags
|
||
|
{
|
||
|
// flag combinations
|
||
|
|
||
|
ALL_ISL_GETPATH_FLAGS = (SLGP_SHORTPATH |
|
||
|
SLGP_UNCPRIORITY)
|
||
|
}
|
||
|
ISL_GETPATH_FLAGS;
|
||
|
|
||
|
typedef enum isl_resolve_flags
|
||
|
{
|
||
|
// flag combinations
|
||
|
|
||
|
ALL_ISL_RESOLVE_FLAGS = (SLR_NO_UI |
|
||
|
SLR_ANY_MATCH |
|
||
|
SLR_UPDATE)
|
||
|
}
|
||
|
ISL_RESOLVE_FLAGS;
|
||
|
|
||
|
|
||
|
/********************************** Methods **********************************/
|
||
|
|
||
|
|
||
|
/*----------------------------------------------------------
|
||
|
Purpose: IShellLink::SetPath method for Intshcut
|
||
|
|
||
|
Note:
|
||
|
1. SetURL clears the internal pidl.
|
||
|
|
||
|
*/
|
||
|
STDMETHODIMP
|
||
|
Intshcut::SetPath(
|
||
|
LPCTSTR pcszPath)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut));
|
||
|
ASSERT(IS_VALID_STRING_PTR(pcszPath, -1));
|
||
|
|
||
|
// Treat path as literal URL.
|
||
|
|
||
|
hr = SetURL(pcszPath, 0);
|
||
|
|
||
|
return(hr);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*----------------------------------------------------------
|
||
|
Purpose: IShellLink::GetPath handler for Intshcut
|
||
|
|
||
|
*/
|
||
|
STDMETHODIMP
|
||
|
Intshcut::GetPath(
|
||
|
IN LPTSTR pszBuf,
|
||
|
IN int cchBuf,
|
||
|
OUT PWIN32_FIND_DATA pwfd, OPTIONAL
|
||
|
IN DWORD dwFlags)
|
||
|
{
|
||
|
HRESULT hres = E_FAIL;
|
||
|
|
||
|
// We make no distinction between raw paths and cooked paths
|
||
|
dwFlags &= ~SLGP_RAWPATH;
|
||
|
|
||
|
ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut));
|
||
|
ASSERT(IS_VALID_WRITE_BUFFER(pszBuf, TCHAR, cchBuf));
|
||
|
ASSERT(NULL == pwfd || IS_VALID_WRITE_PTR(pwfd, WIN32_FIND_DATA));
|
||
|
ASSERT(FLAGS_ARE_VALID(dwFlags, ALL_ISL_GETPATH_FLAGS));
|
||
|
|
||
|
// Init to default values
|
||
|
if (pwfd)
|
||
|
ZeroMemory(pwfd, SIZEOF(*pwfd));
|
||
|
|
||
|
if (cchBuf > 0)
|
||
|
*pszBuf = '\0';
|
||
|
|
||
|
// Ignore dwFlags.
|
||
|
|
||
|
hres = InitProp();
|
||
|
if (SUCCEEDED(hres))
|
||
|
hres = m_pprop->GetProp(PID_IS_URL, pszBuf, cchBuf);
|
||
|
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*----------------------------------------------------------
|
||
|
Purpose: IShellLink::SetRelativePath method for Intshcut
|
||
|
|
||
|
*/
|
||
|
STDMETHODIMP Intshcut::SetRelativePath(LPCTSTR pcszRelativePath, DWORD dwReserved)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
// dwReserved may be any value.
|
||
|
|
||
|
ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut));
|
||
|
ASSERT(IS_VALID_STRING_PTR(pcszRelativePath, -1));
|
||
|
|
||
|
hr = E_NOTIMPL;
|
||
|
|
||
|
ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut));
|
||
|
|
||
|
return(hr);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*----------------------------------------------------------
|
||
|
Purpose: IShellLink::SetIDList method for Intshcut
|
||
|
|
||
|
Note:
|
||
|
1. SetIDList also does SetPath implicitly to update the path (URL)
|
||
|
to match the pidl.
|
||
|
2. SetPath only clears the pidl to NULL, so internally we know
|
||
|
if we really have a pidl for the shortcut. Although GetIDList
|
||
|
will generate a pidl from path (URL) if we don't have a pidl.
|
||
|
|
||
|
*/
|
||
|
STDMETHODIMP Intshcut::SetIDList(LPCITEMIDLIST pcidl)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut));
|
||
|
ASSERT(IS_VALID_READ_PTR(pcidl, ITEMIDLIST));
|
||
|
|
||
|
hr = InitProp();
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = m_pprop->SetIDListProp(pcidl);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
// if the pidl was set successfully, update the path.
|
||
|
TCHAR szURL[INTERNET_MAX_URL_LENGTH];
|
||
|
|
||
|
hr = IEGetDisplayName(pcidl, szURL, SHGDN_FORPARSING);
|
||
|
if (SUCCEEDED(hr))
|
||
|
m_pprop->SetURLProp(szURL, 0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut));
|
||
|
|
||
|
return(hr);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*----------------------------------------------------------
|
||
|
Purpose: Get the original pidl set by SetIDList.
|
||
|
|
||
|
Note:
|
||
|
1. Do not generate a pidl from path if we don't have a pidl.
|
||
|
2. Return S_OK if we have a pidl, caller must NOT check for
|
||
|
SUCCEEDED() return.
|
||
|
|
||
|
*/
|
||
|
STDMETHODIMP Intshcut::GetIDListInternal(LPITEMIDLIST *ppidl)
|
||
|
{
|
||
|
HRESULT hres = InitProp();
|
||
|
if (SUCCEEDED(hres))
|
||
|
{
|
||
|
IStream *pStream;
|
||
|
hres = m_pprop->GetProp(PID_IS_IDLIST, &pStream);
|
||
|
if ((hres == S_OK) && pStream)
|
||
|
{
|
||
|
const LARGE_INTEGER li = {0, 0};
|
||
|
// reset the seek pointer
|
||
|
hres = pStream->Seek(li, STREAM_SEEK_SET, NULL);
|
||
|
if (SUCCEEDED(hres))
|
||
|
hres = ILLoadFromStream(pStream, ppidl);
|
||
|
|
||
|
pStream->Release();
|
||
|
}
|
||
|
}
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*----------------------------------------------------------
|
||
|
Purpose: IShellLink::GetIDList method for Intshcut
|
||
|
|
||
|
Note:
|
||
|
1. If we don't have a pidl from SetIDList, generate a pidl
|
||
|
from path.
|
||
|
|
||
|
*/
|
||
|
STDMETHODIMP Intshcut::GetIDList(LPITEMIDLIST *ppidl)
|
||
|
{
|
||
|
HRESULT hres;
|
||
|
ASSERT(IS_VALID_WRITE_PTR(ppidl, LPITEMIDLIST));
|
||
|
|
||
|
if (!ppidl)
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
*ppidl = NULL;
|
||
|
|
||
|
hres = InitProp();
|
||
|
if (SUCCEEDED(hres))
|
||
|
{
|
||
|
// check if it already as a pidl.
|
||
|
hres = GetIDListInternal(ppidl);
|
||
|
if (hres != S_OK)
|
||
|
{
|
||
|
// it doesn't have a pidl, get the URL and make a pidl.
|
||
|
TCHAR szURL[INTERNET_MAX_URL_LENGTH];
|
||
|
|
||
|
hres = m_pprop->GetProp(PID_IS_URL, szURL, ARRAYSIZE(szURL));
|
||
|
if (SUCCEEDED(hres))
|
||
|
{
|
||
|
hres = IECreateFromPath(szURL, ppidl);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*----------------------------------------------------------
|
||
|
Purpose: IShellLink::SetDescription method for Intshcut
|
||
|
|
||
|
*/
|
||
|
STDMETHODIMP Intshcut::SetDescription(LPCTSTR pcszDescription)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
BOOL bDifferent;
|
||
|
|
||
|
ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut));
|
||
|
ASSERT(IS_VALID_STRING_PTR(pcszDescription, -1));
|
||
|
|
||
|
// Set m_pszFile to description.
|
||
|
|
||
|
bDifferent = (! m_pszDescription ||
|
||
|
StrCmp(pcszDescription, m_pszDescription) != 0);
|
||
|
|
||
|
if (Str_SetPtr(&m_pszDescription, pcszDescription))
|
||
|
{
|
||
|
if (bDifferent)
|
||
|
Dirty(TRUE);
|
||
|
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
else
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
|
||
|
ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut));
|
||
|
|
||
|
return(hr);
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP Intshcut::_ComputeDescription()
|
||
|
{
|
||
|
HRESULT hres;
|
||
|
BSTR bstrTitle = NULL;
|
||
|
|
||
|
if (_punkSite)
|
||
|
{
|
||
|
// Get the title element
|
||
|
IWebBrowser *pwb;
|
||
|
hres = _punkSite->QueryInterface(IID_IWebBrowser, (void **)&pwb);
|
||
|
if (S_OK == hres)
|
||
|
{
|
||
|
IDispatch *pDisp;
|
||
|
hres = pwb->get_Document(&pDisp);
|
||
|
if (S_OK == hres)
|
||
|
{
|
||
|
IHTMLDocument2 *pDoc;
|
||
|
hres = pDisp->QueryInterface(IID_IHTMLDocument2, (void **)&pDoc);
|
||
|
if (S_OK == hres)
|
||
|
{
|
||
|
hres = pDoc->get_title(&bstrTitle);
|
||
|
pDoc->Release();
|
||
|
}
|
||
|
pDisp->Release();
|
||
|
}
|
||
|
pwb->Release();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TCHAR *pszUrl; // The url for this shortcut
|
||
|
hres = GetURL(&pszUrl);
|
||
|
if (S_OK == hres)
|
||
|
{
|
||
|
TCHAR szDescription[MAX_PATH] = TEXT("");
|
||
|
|
||
|
// We gamble that the URL will always have displayable characters.
|
||
|
// This is a bad assumption but if this assumption is violated then
|
||
|
// there is a good chance that the URL probably cannot even
|
||
|
// be navigated to
|
||
|
|
||
|
// This description is used as the name of the file verbatim
|
||
|
// during drag drop - hence it should look like a .url file name
|
||
|
|
||
|
GetShortcutFileName(pszUrl, bstrTitle, NULL, szDescription, ARRAYSIZE(szDescription));
|
||
|
//PathYetAnotherMakeUniqueName(szTempFileName, szTempFileName, NULL, NULL);
|
||
|
PathCleanupSpec(NULL, szDescription);
|
||
|
|
||
|
// Sometimes PathCleanupSpec can end up simply mangling the description if
|
||
|
// it cannot properly convert the title to ANSI
|
||
|
// hence we check that we have a proper description
|
||
|
|
||
|
|
||
|
|
||
|
if((0 == *szDescription) || (0 == StrCmp(szDescription,TEXT(".url"))))
|
||
|
{
|
||
|
// recompute the description without the title
|
||
|
GetShortcutFileName(pszUrl, NULL, NULL, szDescription, ARRAYSIZE(szDescription));
|
||
|
PathCleanupSpec(NULL, szDescription);
|
||
|
}
|
||
|
hres = SetDescription(szDescription);
|
||
|
SHFree(pszUrl);
|
||
|
}
|
||
|
|
||
|
|
||
|
SysFreeString(bstrTitle);
|
||
|
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
// IShellLink::GetDescription method for Intshcut
|
||
|
STDMETHODIMP Intshcut::GetDescription(LPTSTR pszDescription, int cchBuf)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut));
|
||
|
ASSERT(IS_VALID_WRITE_BUFFER(pszDescription, TCHAR, cchBuf));
|
||
|
|
||
|
// Get description from m_pszDescription.
|
||
|
|
||
|
if (NULL == m_pszDescription)
|
||
|
{
|
||
|
_ComputeDescription();
|
||
|
}
|
||
|
|
||
|
if (m_pszDescription)
|
||
|
StrCpyN(pszDescription, m_pszDescription, cchBuf);
|
||
|
else if (m_pszFile)
|
||
|
{
|
||
|
StrCpyN(pszDescription, m_pszFile, cchBuf);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// use default shortcut name
|
||
|
MLLoadString(IDS_NEW_INTSHCUT, pszDescription, cchBuf);
|
||
|
}
|
||
|
|
||
|
hr = S_OK;
|
||
|
|
||
|
ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut));
|
||
|
ASSERT(hr == S_OK &&
|
||
|
(cchBuf <= 0 ||
|
||
|
(IS_VALID_STRING_PTR(pszDescription, -1) &&
|
||
|
EVAL(lstrlen(pszDescription) < cchBuf))));
|
||
|
|
||
|
return(hr);
|
||
|
}
|
||
|
|
||
|
|
||
|
// IShellLink::SetArguments method for Intshcut
|
||
|
STDMETHODIMP Intshcut::SetArguments(LPCTSTR pcszArgs)
|
||
|
{
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
// IShellLink::GetArguments for Intshcut
|
||
|
STDMETHODIMP Intshcut::GetArguments(LPTSTR pszArgs, int cchBuf)
|
||
|
{
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
|
||
|
// IShellLink::SetWorkingDirectory handler for Intshcut
|
||
|
STDMETHODIMP Intshcut::SetWorkingDirectory(LPCTSTR pcszWorkingDirectory)
|
||
|
{
|
||
|
HRESULT hres = S_OK;
|
||
|
TCHAR rgchNewPath[MAX_PATH];
|
||
|
BOOL bChanged = FALSE;
|
||
|
|
||
|
ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut));
|
||
|
ASSERT(! pcszWorkingDirectory ||
|
||
|
IS_VALID_STRING_PTR(pcszWorkingDirectory, -1));
|
||
|
|
||
|
if (! AnyMeat(pcszWorkingDirectory))
|
||
|
pcszWorkingDirectory = NULL;
|
||
|
|
||
|
if (pcszWorkingDirectory)
|
||
|
{
|
||
|
LPTSTR pszFileName;
|
||
|
|
||
|
if (GetFullPathName(pcszWorkingDirectory, SIZECHARS(rgchNewPath),
|
||
|
rgchNewPath, &pszFileName) > 0)
|
||
|
pcszWorkingDirectory = rgchNewPath;
|
||
|
else
|
||
|
hres = E_PATH_NOT_FOUND;
|
||
|
}
|
||
|
|
||
|
if (hres == S_OK)
|
||
|
{
|
||
|
TCHAR szDir[MAX_PATH];
|
||
|
|
||
|
hres = InitProp();
|
||
|
if (SUCCEEDED(hres))
|
||
|
{
|
||
|
hres = m_pprop->GetProp(PID_IS_WORKINGDIR, szDir, SIZECHARS(szDir));
|
||
|
|
||
|
bChanged = ! ((! pcszWorkingDirectory && S_FALSE == hres) ||
|
||
|
(pcszWorkingDirectory && S_OK == hres &&
|
||
|
! StrCmp(pcszWorkingDirectory, szDir)));
|
||
|
|
||
|
hres = S_OK;
|
||
|
if (bChanged)
|
||
|
{
|
||
|
hres = m_pprop->SetProp(PID_IS_WORKINGDIR, pcszWorkingDirectory);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut));
|
||
|
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*----------------------------------------------------------
|
||
|
Purpose: IShellLink::GetWorkingDirectory handler for Intshcut
|
||
|
|
||
|
*/
|
||
|
STDMETHODIMP
|
||
|
Intshcut::GetWorkingDirectory(
|
||
|
IN LPTSTR pszBuf,
|
||
|
IN int cchBuf)
|
||
|
{
|
||
|
HRESULT hres;
|
||
|
|
||
|
ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut));
|
||
|
ASSERT(IS_VALID_WRITE_BUFFER(pszBuf, TCHAR, cchBuf));
|
||
|
|
||
|
if (cchBuf > 0)
|
||
|
*pszBuf = '\0';
|
||
|
|
||
|
hres = InitProp();
|
||
|
if (SUCCEEDED(hres))
|
||
|
hres = m_pprop->GetProp(PID_IS_WORKINGDIR, pszBuf, cchBuf);
|
||
|
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*----------------------------------------------------------
|
||
|
Purpose: IShellLink::SetHotkey handler for Intshcut
|
||
|
|
||
|
*/
|
||
|
STDMETHODIMP
|
||
|
Intshcut::SetHotkey(
|
||
|
IN WORD wHotkey)
|
||
|
{
|
||
|
HRESULT hres;
|
||
|
|
||
|
ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut));
|
||
|
|
||
|
hres = InitProp();
|
||
|
if (SUCCEEDED(hres))
|
||
|
hres = m_pprop->SetProp(PID_IS_HOTKEY, wHotkey);
|
||
|
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*----------------------------------------------------------
|
||
|
Purpose: IShellLink::GetHotkey handler for Intshcut
|
||
|
|
||
|
*/
|
||
|
STDMETHODIMP
|
||
|
Intshcut::GetHotkey(
|
||
|
PWORD pwHotkey)
|
||
|
{
|
||
|
HRESULT hres;
|
||
|
|
||
|
ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut));
|
||
|
ASSERT(IS_VALID_WRITE_PTR(pwHotkey, WORD));
|
||
|
|
||
|
hres = InitProp();
|
||
|
if (SUCCEEDED(hres))
|
||
|
{
|
||
|
m_pprop->GetProp(PID_IS_HOTKEY, pwHotkey);
|
||
|
hres = S_OK;
|
||
|
}
|
||
|
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*----------------------------------------------------------
|
||
|
Purpose: IShellLink::SetShowCmd handler for Intshcut
|
||
|
|
||
|
*/
|
||
|
STDMETHODIMP
|
||
|
Intshcut::SetShowCmd(
|
||
|
IN int nShowCmd)
|
||
|
{
|
||
|
HRESULT hres;
|
||
|
|
||
|
ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut));
|
||
|
ASSERT(IsValidShowCmd(nShowCmd));
|
||
|
|
||
|
hres = InitProp();
|
||
|
if (SUCCEEDED(hres))
|
||
|
hres = m_pprop->SetProp(PID_IS_SHOWCMD, nShowCmd);
|
||
|
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*----------------------------------------------------------
|
||
|
Purpose: IShellLink::GetShowCmd handler for Intshcut
|
||
|
|
||
|
*/
|
||
|
STDMETHODIMP
|
||
|
Intshcut::GetShowCmd(
|
||
|
OUT int *pnShowCmd)
|
||
|
{
|
||
|
HRESULT hres;
|
||
|
|
||
|
ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut));
|
||
|
ASSERT(IS_VALID_WRITE_PTR(pnShowCmd, INT));
|
||
|
|
||
|
hres = InitProp();
|
||
|
if (SUCCEEDED(hres))
|
||
|
{
|
||
|
hres = m_pprop->GetProp(PID_IS_SHOWCMD, pnShowCmd);
|
||
|
if (S_OK != hres)
|
||
|
*pnShowCmd = SW_NORMAL;
|
||
|
hres = S_OK;
|
||
|
}
|
||
|
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*----------------------------------------------------------
|
||
|
Purpose: IShellLink::SetIconLocation handler for Intshcut
|
||
|
|
||
|
*/
|
||
|
STDMETHODIMP
|
||
|
Intshcut::SetIconLocation(
|
||
|
IN LPCTSTR pszFile,
|
||
|
IN int niIcon)
|
||
|
{
|
||
|
HRESULT hres = S_OK;
|
||
|
BOOL bNewMeat;
|
||
|
TCHAR szNewPath[MAX_PATH];
|
||
|
|
||
|
ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut));
|
||
|
ASSERT(IsValidIconIndex(pszFile ? S_OK : S_FALSE, pszFile, MAX_PATH, niIcon));
|
||
|
|
||
|
bNewMeat = AnyMeat(pszFile);
|
||
|
|
||
|
if (bNewMeat)
|
||
|
{
|
||
|
if (PathSearchAndQualify(pszFile, szNewPath, SIZECHARS(szNewPath)))
|
||
|
{
|
||
|
hres = S_OK;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hres = E_FILE_NOT_FOUND;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (hres == S_OK)
|
||
|
{
|
||
|
TCHAR szOldPath[MAX_PATH];
|
||
|
int niOldIcon;
|
||
|
UINT uFlags;
|
||
|
|
||
|
hres = GetIconLocation(0, szOldPath, SIZECHARS(szOldPath), &niOldIcon,
|
||
|
&uFlags);
|
||
|
|
||
|
if (SUCCEEDED(hres))
|
||
|
{
|
||
|
BOOL bOldMeat;
|
||
|
BOOL bChanged = FALSE;
|
||
|
|
||
|
bOldMeat = AnyMeat(szOldPath);
|
||
|
|
||
|
ASSERT(! *szOldPath ||
|
||
|
bOldMeat);
|
||
|
|
||
|
bChanged = ((! bOldMeat && bNewMeat) ||
|
||
|
(bOldMeat && ! bNewMeat) ||
|
||
|
(bOldMeat && bNewMeat &&
|
||
|
(StrCmp(szOldPath, szNewPath) != 0 ||
|
||
|
niIcon != niOldIcon)));
|
||
|
|
||
|
hres = S_OK;
|
||
|
if (bChanged && bNewMeat)
|
||
|
{
|
||
|
hres = InitProp();
|
||
|
if (SUCCEEDED(hres))
|
||
|
{
|
||
|
hres = m_pprop->SetProp(PID_IS_ICONFILE, szNewPath);
|
||
|
if (SUCCEEDED(hres))
|
||
|
hres = m_pprop->SetProp(PID_IS_ICONINDEX, niIcon);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
VOID UrlMunge(
|
||
|
TCHAR *lpszSrc,
|
||
|
TCHAR *lpszDest,
|
||
|
UINT cchDestBufSize,
|
||
|
BOOL fRecentlyChanged)
|
||
|
{
|
||
|
TCHAR *lpszTemp = lpszSrc;
|
||
|
|
||
|
if(fRecentlyChanged)
|
||
|
cchDestBufSize--; // Save up a character
|
||
|
|
||
|
while(*lpszTemp != TEXT('\0') && (cchDestBufSize > 1)) // not End of line and save up one char for \0 in munged string
|
||
|
{
|
||
|
if(TEXT('/') == *lpszTemp)
|
||
|
{
|
||
|
*lpszDest = TEXT('\1');
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*lpszDest = *lpszTemp;
|
||
|
}
|
||
|
lpszDest++;
|
||
|
lpszTemp++;
|
||
|
cchDestBufSize--;
|
||
|
}
|
||
|
if(fRecentlyChanged)
|
||
|
{
|
||
|
*lpszDest = TEXT('\2');
|
||
|
lpszDest++;
|
||
|
}
|
||
|
*lpszDest = TEXT('\0');
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT HelperForReadIconInfoFromPropStg(
|
||
|
IN LPTSTR pszBuf,
|
||
|
IN int cchBuf,
|
||
|
OUT int * pniIcon,
|
||
|
IPropertyStorage *pPropStg,
|
||
|
PROPSPEC *ppropspec,
|
||
|
IN LPTSTR pszActualUrlBuf,
|
||
|
IN INT cchActualUrlBuf,
|
||
|
BOOL fRecentlyChanged)
|
||
|
{
|
||
|
|
||
|
HRESULT hres;
|
||
|
PROPVARIANT rgpropvar[2];
|
||
|
|
||
|
|
||
|
ASSERT((0 == pszActualUrlBuf) || (cchActualUrlBuf >= MAX_URL_STRING));
|
||
|
|
||
|
if(pszActualUrlBuf)
|
||
|
*pszActualUrlBuf = TEXT('\0');
|
||
|
|
||
|
// Init to default values
|
||
|
*pniIcon = 0;
|
||
|
if (cchBuf > 0)
|
||
|
*pszBuf = TEXT('\0');
|
||
|
|
||
|
|
||
|
|
||
|
hres = pPropStg->ReadMultiple(2, ppropspec, rgpropvar);
|
||
|
if (SUCCEEDED(hres))
|
||
|
{
|
||
|
if (VT_LPWSTR == rgpropvar[1].vt)
|
||
|
{
|
||
|
if(FALSE == PathFileExistsW(rgpropvar[1].pwszVal))
|
||
|
{
|
||
|
UrlMunge(rgpropvar[1].pwszVal, pszBuf, cchBuf, fRecentlyChanged);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// We will just send the icon file and index back with no attempt
|
||
|
// to hash it or fill out the URL field
|
||
|
if(lstrlenW(rgpropvar[1].pwszVal) >= cchBuf)
|
||
|
{
|
||
|
// need a larger buf - simply fail it
|
||
|
hres = E_FAIL;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
StrCpyN(pszBuf, rgpropvar[1].pwszVal, cchBuf);
|
||
|
}
|
||
|
}
|
||
|
if(SUCCEEDED(hres) && pszActualUrlBuf)
|
||
|
{
|
||
|
StrCpyN(pszActualUrlBuf, rgpropvar[1].pwszVal, cchActualUrlBuf);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (VT_I4 == rgpropvar[0].vt)
|
||
|
*pniIcon = rgpropvar[0].lVal;
|
||
|
|
||
|
FreePropVariantArray(ARRAYSIZE(rgpropvar), rgpropvar);
|
||
|
}
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Functions from isexicon.cpp
|
||
|
//
|
||
|
|
||
|
/*----------------------------------------------------------
|
||
|
*
|
||
|
*
|
||
|
Purpose: IShellLink::GetIconLocation handler for Intshcut
|
||
|
*
|
||
|
*----------------------------------------------------------*/
|
||
|
STDMETHODIMP
|
||
|
Intshcut::_GetIconLocationWithURLHelper(
|
||
|
IN LPTSTR pszBuf,
|
||
|
IN int cchBuf,
|
||
|
OUT int * pniIcon,
|
||
|
IN LPTSTR pszActualUrl,
|
||
|
UINT cchActualUrlBuf,
|
||
|
BOOL fRecentlyChanged)
|
||
|
{
|
||
|
HRESULT hres;
|
||
|
PROPSPEC rgpropspec[2];
|
||
|
|
||
|
ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut));
|
||
|
ASSERT(IS_VALID_WRITE_BUFFER(pszBuf, TCHAR, cchBuf));
|
||
|
ASSERT(IS_VALID_WRITE_PTR(pniIcon, int));
|
||
|
|
||
|
if(!pszBuf)
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
rgpropspec[0].ulKind = PRSPEC_PROPID;
|
||
|
rgpropspec[1].ulKind = PRSPEC_PROPID;
|
||
|
|
||
|
|
||
|
if(pszActualUrl)
|
||
|
*pszActualUrl = TEXT('\0');
|
||
|
|
||
|
*pszBuf = TEXT('\0');
|
||
|
|
||
|
hres = InitProp();
|
||
|
if (SUCCEEDED(hres))
|
||
|
{
|
||
|
rgpropspec[0].propid = PID_IS_ICONINDEX;
|
||
|
rgpropspec[1].propid = PID_IS_ICONFILE;
|
||
|
hres = HelperForReadIconInfoFromPropStg(
|
||
|
pszBuf, cchBuf, pniIcon, m_pprop,
|
||
|
rgpropspec, pszActualUrl, cchActualUrlBuf,
|
||
|
fRecentlyChanged);
|
||
|
|
||
|
}
|
||
|
|
||
|
if(TEXT('\0') == *pszBuf)
|
||
|
{
|
||
|
// Didn't find it in the shortcut itself
|
||
|
// Poke around the intsite database and if it is there,
|
||
|
// simply stuff it into the shortcut file if you do find
|
||
|
// one
|
||
|
IPropertyStorage *ppropstg = NULL;
|
||
|
hres = Open(FMTID_InternetSite, STGM_READWRITE, &ppropstg);
|
||
|
if(S_OK == hres)
|
||
|
{
|
||
|
// Look for an icon for this specific url
|
||
|
ASSERT(ppropstg);
|
||
|
rgpropspec[0].propid = PID_INTSITE_ICONINDEX;
|
||
|
rgpropspec[1].propid = PID_INTSITE_ICONFILE;
|
||
|
hres = HelperForReadIconInfoFromPropStg(pszBuf, cchBuf, pniIcon,
|
||
|
ppropstg, rgpropspec, pszActualUrl,
|
||
|
cchActualUrlBuf, fRecentlyChanged);
|
||
|
|
||
|
|
||
|
ppropstg->Release();
|
||
|
}
|
||
|
|
||
|
if((S_OK == hres) && (*pszBuf) && pszActualUrl && (*pszActualUrl))
|
||
|
{
|
||
|
// Write this info to the shortcut file
|
||
|
WCHAR *pwszTempBuf;
|
||
|
pwszTempBuf = pszActualUrl;
|
||
|
PROPVARIANT var = {0};
|
||
|
|
||
|
ASSERT(1 == *pniIcon);
|
||
|
|
||
|
var.vt = VT_BSTR;
|
||
|
var.bstrVal = SysAllocString(pwszTempBuf);
|
||
|
|
||
|
if(var.bstrVal)
|
||
|
{
|
||
|
hres = WritePropertyNPB(ISHCUT_INISTRING_SECTIONW, ISHCUT_INISTRING_ICONFILEW,
|
||
|
&var);
|
||
|
|
||
|
SysFreeString(var.bstrVal);
|
||
|
if(S_OK == hres)
|
||
|
{
|
||
|
var.bstrVal = SysAllocString(L"1");
|
||
|
if(var.bstrVal)
|
||
|
{
|
||
|
hres = WritePropertyNPB(ISHCUT_INISTRING_SECTIONW, ISHCUT_INISTRING_ICONINDEXW,
|
||
|
&var);
|
||
|
SysFreeString(var.bstrVal);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
hres = S_OK; // retun OK if you found icon and could not write out for whatever reason
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
// IShellLink::GetIconLocation handler for Intshcut
|
||
|
STDMETHODIMP Intshcut::GetIconLocation(LPTSTR pszBuf, int cchBuf, int *pniIcon)
|
||
|
{
|
||
|
UINT uTmp;
|
||
|
return GetIconLocation(0, pszBuf, cchBuf, pniIcon, &uTmp);
|
||
|
}
|
||
|
|
||
|
// IShellLink::Resolve method for Intshcut
|
||
|
STDMETHODIMP Intshcut::Resolve(HWND hwnd, DWORD dwFlags)
|
||
|
{
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
//====================================================================================
|
||
|
// Now the A or W functions that depend on unicode or ansi machines...
|
||
|
// Will setup forwarders to the native one for the OS...
|
||
|
//----------------------------------------------------------
|
||
|
STDMETHODIMP Intshcut::SetPath(LPCSTR pcszPath)
|
||
|
{
|
||
|
WCHAR wszT[INTERNET_MAX_URL_LENGTH];
|
||
|
|
||
|
if (!pcszPath)
|
||
|
return SetPath((LPCWSTR)NULL);
|
||
|
|
||
|
SHAnsiToUnicode(pcszPath, wszT, ARRAYSIZE(wszT));
|
||
|
return SetPath(wszT);
|
||
|
}
|
||
|
|
||
|
|
||
|
STDMETHODIMP Intshcut::GetPath(LPSTR pszBuf, int cchBuf, PWIN32_FIND_DATAA pwfd, DWORD dwFlags)
|
||
|
{
|
||
|
WCHAR wszT[INTERNET_MAX_URL_LENGTH];
|
||
|
HRESULT hres;
|
||
|
|
||
|
// Init to default values (Note pwfd is not actually set so don't worry about thunking...
|
||
|
if (pwfd)
|
||
|
ZeroMemory(pwfd, SIZEOF(*pwfd));
|
||
|
|
||
|
hres = GetPath(wszT, ARRAYSIZE(wszT), NULL, dwFlags);
|
||
|
if (SUCCEEDED(hres))
|
||
|
SHUnicodeToAnsi(wszT, pszBuf, cchBuf);
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
|
||
|
STDMETHODIMP Intshcut::SetRelativePath(LPCSTR pcszRelativePath, DWORD dwReserved)
|
||
|
{
|
||
|
WCHAR wszT[MAX_PATH];
|
||
|
if (!pcszRelativePath)
|
||
|
return SetRelativePath((LPCWSTR)NULL, dwReserved);
|
||
|
|
||
|
SHAnsiToUnicode(pcszRelativePath, wszT, ARRAYSIZE(wszT));
|
||
|
return SetRelativePath(wszT, dwReserved);
|
||
|
}
|
||
|
|
||
|
|
||
|
STDMETHODIMP Intshcut::SetDescription(LPCSTR pcszDescription)
|
||
|
{
|
||
|
WCHAR wszT[MAX_PATH];
|
||
|
if (!pcszDescription)
|
||
|
return SetDescription((LPCWSTR)NULL);
|
||
|
|
||
|
SHAnsiToUnicode(pcszDescription, wszT, ARRAYSIZE(wszT));
|
||
|
return SetDescription(wszT);
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP Intshcut::GetDescription(LPSTR pszDescription,int cchBuf)
|
||
|
{
|
||
|
WCHAR wszT[MAX_PATH];
|
||
|
HRESULT hres;
|
||
|
|
||
|
hres = GetDescription(wszT, ARRAYSIZE(wszT));
|
||
|
if (SUCCEEDED(hres))
|
||
|
SHUnicodeToAnsi(wszT, pszDescription, cchBuf);
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP Intshcut::SetArguments(LPCSTR pcszArgs)
|
||
|
{
|
||
|
WCHAR wszT[2*MAX_PATH];
|
||
|
if (!pcszArgs)
|
||
|
return SetArguments((LPCWSTR)NULL);
|
||
|
|
||
|
SHAnsiToUnicode(pcszArgs, wszT, ARRAYSIZE(wszT));
|
||
|
return SetArguments(wszT);
|
||
|
}
|
||
|
|
||
|
|
||
|
STDMETHODIMP Intshcut::GetArguments(LPSTR pszArgs,int cchBuf)
|
||
|
{
|
||
|
WCHAR wszT[2*MAX_PATH];
|
||
|
HRESULT hres;
|
||
|
|
||
|
hres = GetArguments(wszT, ARRAYSIZE(wszT));
|
||
|
if (SUCCEEDED(hres))
|
||
|
SHUnicodeToAnsi(wszT, pszArgs, cchBuf);
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP Intshcut::SetWorkingDirectory(LPCSTR pcszWorkingDirectory)
|
||
|
{
|
||
|
WCHAR wszT[MAX_PATH];
|
||
|
|
||
|
if (!pcszWorkingDirectory)
|
||
|
return SetWorkingDirectory((LPCWSTR)NULL);
|
||
|
|
||
|
SHAnsiToUnicode(pcszWorkingDirectory, wszT, ARRAYSIZE(wszT));
|
||
|
return SetWorkingDirectory(wszT);
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP Intshcut::GetWorkingDirectory(LPSTR pszBuf, int cchBuf)
|
||
|
{
|
||
|
WCHAR wszT[MAX_PATH];
|
||
|
HRESULT hres;
|
||
|
|
||
|
hres = GetWorkingDirectory(wszT, ARRAYSIZE(wszT));
|
||
|
if (SUCCEEDED(hres))
|
||
|
SHUnicodeToAnsi(wszT, pszBuf, cchBuf);
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP Intshcut::SetIconLocation(LPCSTR pszFile, int niIcon)
|
||
|
{
|
||
|
WCHAR wszT[MAX_PATH];
|
||
|
|
||
|
if (!pszFile)
|
||
|
return SetIconLocation((LPCWSTR)NULL, niIcon);
|
||
|
|
||
|
SHAnsiToUnicode(pszFile, wszT, ARRAYSIZE(wszT));
|
||
|
return SetIconLocation(wszT, niIcon);
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP Intshcut::GetIconLocation(LPSTR pszBuf, int cchBuf, int *pniIcon)
|
||
|
{
|
||
|
WCHAR wszT[MAX_PATH];
|
||
|
HRESULT hres;
|
||
|
|
||
|
hres = GetIconLocation(wszT, ARRAYSIZE(wszT), pniIcon);
|
||
|
if (SUCCEEDED(hres))
|
||
|
SHUnicodeToAnsi(wszT, pszBuf, cchBuf);
|
||
|
return hres;
|
||
|
}
|