/* * isshlink.cpp - IShellLink implementation for Intshcut class. */ #include "priv.h" #include "ishcut.h" #include "resource.h" #include /* 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) { hres = StringCchCopy(pszActualUrlBuf, cchActualUrlBuf, rgpropvar[1].pwszVal); } } 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; }