//******************************************************************************* // COPYRIGHT NOTES // --------------- // You may use this source code, compile or redistribute it as part of your application // for free. You cannot redistribute it as a part of a software development // library without the agreement of the author. If the sources are // distributed along with the application, you should leave the original // copyright notes in the source code without any changes. // This code can be used WITHOUT ANY WARRANTIES at your own risk. // // For the latest updates to this code, check this site: // http://www.masmex.com // after Sept 2000 // // Copyright(C) 2000 Philip Oldaker //******************************************************************************* // ShellPidl.cpp: implementation of the CShellPidl class. // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "ShellPidl.h" #include "UIMessages.h" #include #include #include #include "ShellContextMenu.h" #include "UICoolMenu.h" #include "cbformats.h" #define SF_DRAGDROP_FLAGS SFGAO_CANCOPY | SFGAO_CANMOVE | SFGAO_CANLINK; UINT CF_IDLIST = RegisterClipboardFormat(CFSTR_SHELLIDLIST); UINT CF_SHELLURL = RegisterClipboardFormat(CFSTR_SHELLURL); #define TPM_FLAGS (TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_NONOTIFY | TPM_RETURNCMD) ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// CShellPidl::CShellPidl() { SHGetMalloc(&m_pMalloc); SHGetDesktopFolder(&m_psfDesktop); ZeroMemory(&m_EmptyPidl,sizeof(ITEMIDLIST)); } CShellPidl::~CShellPidl() { if (m_pMalloc) m_pMalloc->Release(); if (m_psfDesktop) m_psfDesktop->Release(); } IMalloc *CShellPidl::GetMalloc() { return m_pMalloc; } DWORD CShellPidl::GetDragDropAttributes(LPLVITEMDATA plvid) { return GetDragDropAttributes(plvid->lpsfParent,plvid->lpi); } DWORD CShellPidl::GetDragDropAttributes(LPTVITEMDATA ptvid) { return GetDragDropAttributes(ptvid->lpsfParent,ptvid->lpi); } DWORD CShellPidl::GetDragDropAttributes(LPSHELLFOLDER pFolder,LPCITEMIDLIST pidl) { if (pFolder == NULL) pFolder = m_psfDesktop; DWORD dwAttrs=SF_DRAGDROP_FLAGS; HRESULT hr = pFolder->GetAttributesOf(1,(LPCITEMIDLIST*)&pidl,&dwAttrs); if (FAILED(hr)) dwAttrs = SF_DRAGDROP_FLAGS; return dwAttrs; } DWORD CShellPidl::GetDragDropAttributes(COleDataObject *pDataObject) { IDataObject *pDataObj = pDataObject->m_lpDataObject; STGMEDIUM stgm; ZeroMemory(&stgm, sizeof(stgm)); FORMATETC fetc; fetc.cfFormat = CF_IDLIST; fetc.ptd = NULL; fetc.dwAspect = DVASPECT_CONTENT; fetc.lindex = -1; fetc.tymed = TYMED_HGLOBAL; DWORD dwAttrs=DROPEFFECT_COPY | DROPEFFECT_MOVE | DROPEFFECT_LINK; HRESULT hr = pDataObj->QueryGetData(&fetc); if (FAILED(hr)) return dwAttrs; hr = pDataObj->GetData(&fetc, &stgm); if (FAILED(hr)) return dwAttrs; DWORD pData = (DWORD)GlobalLock(stgm.hGlobal); LPIDA pIDList = (LPIDA)pData; UINT nFolderOffset = pIDList->aoffset[0]; TRACE2("PIDL(%u) offfset=%u\n",0,nFolderOffset); DWORD pFolder = pData+nFolderOffset; LPITEMIDLIST pidl = (LPITEMIDLIST)pFolder; LPSHELLFOLDER psfParent = GetFolder(pidl); if (psfParent) { // get attributes for the children TRACE1("PIDL count=%u\n",pIDList->cidl); for(UINT i=1;i < (pIDList->cidl+1);i++) { UINT nListOffset = pIDList->aoffset[i]; TRACE2("PIDL(%u) offfset=%u\n",i,nListOffset); ULONG ulAttrs = SF_DRAGDROP_FLAGS; DWORD dwPidl = pData+nListOffset; LPITEMIDLIST pidlist = (LPITEMIDLIST)dwPidl; psfParent->GetAttributesOf(1,(LPCITEMIDLIST*)&pidlist,&ulAttrs); #ifdef _DEBUG CString sPath; SHPidlToPathEx(pidlist,sPath,psfParent); TRACE2("Drag drop source path=%s Attributes=%u\n",sPath,ulAttrs); #endif if (ulAttrs) dwAttrs = dwAttrs & ulAttrs; } psfParent->Release(); } GlobalUnlock(stgm.hGlobal); ReleaseStgMedium(&stgm); return dwAttrs; } LPCITEMIDLIST CShellPidl::GetEmptyPidl() { return &m_EmptyPidl; } bool CShellPidl::IsDesktopFolder(LPSHELLFOLDER psFolder) { return psFolder == NULL || psFolder == m_psfDesktop; } LPSHELLFOLDER CShellPidl::GetDesktopFolder() { return m_psfDesktop; } LPSHELLFOLDER CShellPidl::GetFolder(LPITEMIDLIST pidl) { if (pidl == NULL || pidl->mkid.cb == 0) return m_psfDesktop; LPSHELLFOLDER pFolder=NULL; if (FAILED(m_psfDesktop->BindToObject(pidl, 0, IID_IShellFolder,(LPVOID*)&pFolder))) return NULL; return pFolder; } // CopyItemID - creates an item identifier list containing the first // item identifier in the specified list. // Returns a PIDL if successful, or NULL if out of memory. LPITEMIDLIST CShellPidl::CopyItemID(LPITEMIDLIST pidl,int n) { // Get the size of the specified item identifier. ASSERT(pidl); if (n == 0) { int cb = pidl->mkid.cb; int nSize = cb + sizeof(pidl->mkid.cb); // Allocate a new item identifier list. LPITEMIDLIST pidlNew = (LPITEMIDLIST)m_pMalloc->Alloc(nSize); ZeroMemory(pidlNew,nSize); if (pidlNew == NULL) return NULL; // Copy the specified item identifier. CopyMemory(pidlNew, pidl, nSize-sizeof(pidl->mkid.cb)); return pidlNew; } else { LPITEMIDLIST pidl_index=NULL; for(int i=0;i < n && pidl->mkid.cb;i++) { pidl_index = pidl; pidl = Next(pidl); } return pidl_index ? CopyItemID(pidl_index,0) : NULL; } return NULL; } // Returns a PIDL if successful, or NULL if out of memory. LPITEMIDLIST CShellPidl::CopyLastItemID(LPITEMIDLIST pidl) { // Get the size of the specified item identifier. ASSERT(pidl); if (pidl == NULL) return NULL; LPITEMIDLIST last_pidl=pidl; while (pidl->mkid.cb) { last_pidl = pidl; pidl = Next(pidl); } if (last_pidl == NULL) return NULL; return CopyItemID(last_pidl); } // copies the absolute pidl up till n LPITEMIDLIST CShellPidl::CopyAbsItemID(LPITEMIDLIST pidl,int n) { // Get the size of the specified item identifier. ASSERT(pidl); if (pidl == NULL) return NULL; LPITEMIDLIST first_pidl=NULL; LPITEMIDLIST abs_pidl=NULL; LPITEMIDLIST new_abs_pidl=NULL; for(int i=0;i < n && pidl && pidl->mkid.cb;i++) { first_pidl = CopyItemID(pidl); new_abs_pidl = ConcatPidl(abs_pidl,first_pidl); if (abs_pidl) { m_pMalloc->Free(abs_pidl); } abs_pidl = new_abs_pidl; if (first_pidl) { m_pMalloc->Free(first_pidl); } pidl = Next(pidl); } return new_abs_pidl; } // Makes a copy of an ITEMIDLIST LPITEMIDLIST CShellPidl::CopyItemIDList(LPITEMIDLIST pidl) { // Allocate a new item identifier list. int nSize = GetSize(pidl); LPITEMIDLIST pidlNew = (LPITEMIDLIST)m_pMalloc->Alloc(nSize); ZeroMemory(pidlNew,nSize); if (pidlNew == NULL) return NULL; // Copy the specified item identifier. CopyMemory(pidlNew, pidl, nSize); return pidlNew; } bool CShellPidl::CompareMemPidls(LPCITEMIDLIST pidl1,LPCITEMIDLIST pidl2) { // Allocate a new item identifier list. if (pidl1 == NULL || pidl2 == NULL) return false; return memcmp(pidl1,pidl2,(size_t)GetSize(pidl1)) == 0; } // Returns true if lists are the same bool CShellPidl::ComparePidls(LPSHELLFOLDER pFolder,LPCITEMIDLIST pidl1,LPCITEMIDLIST pidl2) { // Allocate a new item identifier list. if (pFolder == NULL) pFolder = GetDesktopFolder(); if (pidl1 == NULL || pidl2 == NULL) return false; return (short)pFolder->CompareIDs(0,pidl1,pidl2) == 0; } void CShellPidl::Free(void *pv) { if (m_pMalloc) m_pMalloc->Free(pv); } void CShellPidl::FreePidl(LPITEMIDLIST pidl) { if (m_pMalloc) m_pMalloc->Free(pidl); } UINT CShellPidl::GetCount(LPCITEMIDLIST pidl) { UINT nCount = 0; if (pidl) { while (pidl->mkid.cb) { pidl = Next(pidl); nCount++; } } return nCount; } UINT CShellPidl::GetSize(LPCITEMIDLIST pidl) { UINT cbTotal = 0; if (pidl) { cbTotal += sizeof(pidl->mkid.cb); // Null terminator while (pidl->mkid.cb) { cbTotal += pidl->mkid.cb; pidl = Next(pidl); } } return cbTotal; } LPITEMIDLIST CShellPidl::Next(LPCITEMIDLIST pidl) { LPSTR lpMem=(LPSTR)pidl; lpMem+=pidl->mkid.cb; return (LPITEMIDLIST)lpMem; } LPITEMIDLIST CShellPidl::ConcatPidl(LPITEMIDLIST pidlDest,LPITEMIDLIST pidlSrc) { // Get the size of the specified item identifier. UINT cbDest=0; UINT cbSrc=0; if (pidlDest) //May be NULL cbDest = GetSize(pidlDest) - sizeof(pidlDest->mkid.cb); cbSrc = GetSize(pidlSrc); // Allocate a new item identifier list. LPITEMIDLIST pidlNew = (LPITEMIDLIST)m_pMalloc->Alloc(cbSrc+cbDest); if (pidlNew == NULL) return NULL; ZeroMemory(pidlNew,cbSrc+cbDest); // Copy the specified item identifier. if (pidlDest) CopyMemory(pidlNew, pidlDest, cbDest); CopyMemory(((USHORT*)(((LPBYTE)pidlNew)+cbDest)), pidlSrc, cbSrc); return pidlNew; } int CShellPidl::GetIcon(LPITEMIDLIST lpi, UINT uFlags) { SHFILEINFO sfi; ZeroMemory(&sfi,sizeof(sfi)); if (uFlags == 0) uFlags |= (SHGFI_SYSICONINDEX | SHGFI_SMALLICON); uFlags |= SHGFI_PIDL; SHGetFileInfo((LPCTSTR)lpi, 0, &sfi, sizeof(SHFILEINFO), uFlags); return sfi.iIcon; } STDMETHODIMP CShellPidl::SHPidlToPathEx(LPCITEMIDLIST pidl, CString &sPath, LPSHELLFOLDER pFolder, DWORD dwFlags) { STRRET StrRetFilePath; LPTSTR pszFilePath = NULL; HRESULT hr=E_FAIL; if (pFolder == NULL) pFolder = GetDesktopFolder(); if (pFolder == NULL) return E_FAIL; hr = pFolder->GetDisplayNameOf(pidl, dwFlags, &StrRetFilePath); if (SUCCEEDED(hr)) { StrRetToStr(StrRetFilePath, &pszFilePath, (LPITEMIDLIST)pidl); sPath = pszFilePath; } if (pszFilePath) m_pMalloc->Free(pszFilePath); return hr; } STDMETHODIMP CShellPidl::SHPathToPidlEx(LPCTSTR szPath, LPITEMIDLIST* ppidl, LPSHELLFOLDER pFolder) { OLECHAR wszPath[MAX_PATH] = {0}; ULONG nCharsParsed = 0; LPSHELLFOLDER pShellFolder = NULL; BOOL bFreeOnExit = FALSE; #ifdef UNICODE lstrcpy(wszPath,szPath); #else MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szPath, -1, wszPath, MAX_PATH); #endif // Use the desktop's IShellFolder by default if(pFolder == NULL) { SHGetDesktopFolder(&pShellFolder); bFreeOnExit = TRUE; } else pShellFolder = pFolder; HRESULT hr = pShellFolder->ParseDisplayName(NULL, NULL, wszPath, &nCharsParsed, ppidl, NULL); if(bFreeOnExit) pShellFolder->Release(); return hr; } void CShellPidl::GetTypeName(LPITEMIDLIST lpi,CString &sTypeName) { SHFILEINFO sfi; ZeroMemory(&sfi,sizeof(sfi)); UINT uFlags = SHGFI_PIDL | SHGFI_TYPENAME; SHGetFileInfo((LPCTSTR)lpi, 0, &sfi, sizeof(SHFILEINFO), uFlags); sTypeName = sfi.szTypeName; } void CShellPidl::GetDisplayName(LPITEMIDLIST lpifq,CString &sDisplayName) { SHFILEINFO sfi; ZeroMemory(&sfi,sizeof(sfi)); UINT uFlags = SHGFI_PIDL | SHGFI_DISPLAYNAME; SHGetFileInfo((LPCTSTR)lpifq, 0, &sfi, sizeof(SHFILEINFO), uFlags); sDisplayName = sfi.szDisplayName; } void CShellPidl::GetNormalAndSelectedIcons ( LPITEMIDLIST lpifq, int &iImage, int &iSelectedImage) { // Don't check the return value here. // If IGetIcon() fails, you're in big trouble. iImage = GetIcon (lpifq, SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON); iSelectedImage = GetIcon (lpifq, SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON | SHGFI_OPENICON); return; } BOOL CShellPidl::HandleMenuMsg(HWND hwnd, LPSHELLFOLDER lpsfParent, LPITEMIDLIST lpi, UINT uMsg, WPARAM wParam, LPARAM lParam) { LPCONTEXTMENU lpcm=NULL; HRESULT hr=lpsfParent->GetUIObjectOf(hwnd, 1, // get attributes for this many objects (const struct _ITEMIDLIST **)&lpi, IID_IContextMenu, 0, (LPVOID *)&lpcm); if (SUCCEEDED(hr)) { LPCONTEXTMENU2 lpcm2=NULL; hr = lpcm->QueryInterface(IID_IContextMenu2,(LPVOID*)&lpcm2); lpcm->Release(); if (SUCCEEDED(hr)) { lpcm2->HandleMenuMsg(uMsg,wParam,lParam); lpcm2->Release(); } return TRUE; } return FALSE; } BOOL CShellPidl::PopupTheMenu(HWND hwnd, LPSHELLFOLDER lpsfParent, LPITEMIDLIST *plpi, UINT cidl, LPPOINT lppt) { CMenu menu; menu.CreatePopupMenu(); g_CoolMenuManager.Install(CWnd::FromHandle(hwnd)); CString sPath; if (lpsfParent == NULL) lpsfParent = GetDesktopFolder(); SHPidlToPathEx(*plpi,sPath,lpsfParent); CShellContextMenu shell_menu(hwnd,sPath,plpi,cidl,lpsfParent); shell_menu.SetMenu(&menu); int idCmd = menu.TrackPopupMenu(TPM_FLAGS, lppt->x, lppt->y, CWnd::FromHandle(hwnd)); shell_menu.InvokeCommand(idCmd); g_CoolMenuManager.Uninstall(); return TRUE; } /**************************************************************************** * * FUNCTION: GetName(LPSHELLFOLDER lpsf,LPITEMIDLIST lpi,DWORD dwFlags, * LPSTR lpFriendlyName) * * PURPOSE: Gets the friendly name for the folder * ****************************************************************************/ BOOL CShellPidl::GetName (LPSHELLFOLDER lpsf, LPITEMIDLIST lpi, DWORD dwFlags, CString &sFriendlyName) { BOOL bSuccess=TRUE; STRRET str; if (NOERROR==lpsf->GetDisplayNameOf(lpi,dwFlags, &str)) { switch (str.uType) { case STRRET_WSTR: #ifdef UNICODE _tcscpy(sFriendlyName.GetBuffer(MAX_PATH),str.pOleStr); sFriendlyName.ReleaseBuffer(); #else WideCharToMultiByte( CP_ACP, // code page 0, // dwFlags str.pOleStr, // lpWideCharStr -1, // cchWideCharStr sFriendlyName.GetBuffer(_MAX_PATH), // lpMultiByteStr _MAX_PATH, // cchMultiByte NULL, // lpDefaultChar NULL); // lpUsedDefaultChar #endif sFriendlyName.ReleaseBuffer(); break; case STRRET_OFFSET: sFriendlyName = (LPTSTR)lpi+str.uOffset; break; case STRRET_CSTR: sFriendlyName = (LPTSTR)str.cStr; break; default: bSuccess = FALSE; break; } } else bSuccess = FALSE; return bSuccess; } // // ResolveChannel: Resolves a Channel Shortcut to its URL // STDMETHODIMP CShellPidl::ResolveChannel(IShellFolder* pFolder, LPCITEMIDLIST pidl, LPTSTR* lpszURL) { IShellLink* pShellLink; *lpszURL = NULL; // Assume failure // Get a pointer to the IShellLink interface from the given folder HRESULT hr = pFolder->GetUIObjectOf(NULL, 1, &pidl, IID_IShellLink, NULL, (LPVOID*)&pShellLink); if (SUCCEEDED(hr)) { LPITEMIDLIST pidlChannel; // Convert the IShellLink pointer to a PIDL. hr = pShellLink->GetIDList(&pidlChannel); if (SUCCEEDED(hr)) { IShellFolder* psfDesktop; hr = SHGetDesktopFolder(&psfDesktop); if (SUCCEEDED(hr)) { STRRET strret; hr = psfDesktop->GetDisplayNameOf(pidlChannel, 0, &strret); if (SUCCEEDED(hr)) StrRetToStr(strret, lpszURL, pidlChannel); psfDesktop->Release(); } } pShellLink->Release(); } return hr; } STDMETHODIMP CShellPidl::ResolveHistoryShortcut(LPSHELLFOLDER pFolder,LPCITEMIDLIST *ppidl,CString &sURL) { HRESULT hr=E_FAIL; IDataObject *pObj=NULL; hr = pFolder->GetUIObjectOf(NULL, 1, ppidl, IID_IDataObject, NULL, (LPVOID*)&pObj); if (SUCCEEDED(hr)) { hr = GetURL(pObj,sURL); pObj->Release(); } return hr; } STDMETHODIMP CShellPidl::GetURL(IDataObject *pDataObj,CString &sURL) { sURL.Empty(); STGMEDIUM stgm; ZeroMemory(&stgm, sizeof(stgm)); FORMATETC fetc; fetc.cfFormat = CF_SHELLURL; fetc.ptd = NULL; fetc.dwAspect = DVASPECT_CONTENT; fetc.lindex = -1; fetc.tymed = TYMED_HGLOBAL; HRESULT hr = pDataObj->QueryGetData(&fetc); if (FAILED(hr)) return hr; hr = pDataObj->GetData(&fetc, &stgm); if (FAILED(hr)) return hr; LPCTSTR pData = (LPCTSTR)GlobalLock(stgm.hGlobal); sURL = pData; GlobalUnlock(stgm.hGlobal); ReleaseStgMedium(&stgm); return S_OK; } // // ResolveInternetShortcut: Resolves an Internet Shortcut to its URL // STDMETHODIMP CShellPidl::ResolveInternetShortcut(LPCTSTR lpszLinkFile, LPTSTR* lpszURL) { IUniformResourceLocator* pUrlLink = NULL; *lpszURL=NULL; HRESULT hr = CoCreateInstance(CLSID_InternetShortcut, NULL, CLSCTX_INPROC_SERVER, IID_IUniformResourceLocator, (LPVOID*)&pUrlLink); if (FAILED(hr)) return hr; IPersistFile* pPersistFile = NULL; hr = pUrlLink->QueryInterface(IID_IPersistFile, (LPVOID*)&pPersistFile); if (SUCCEEDED(hr)) { // Ensure that the string is Unicode. WORD wsz[MAX_PATH]; #ifdef UNICODE _tcscpy(wsz,lpszLinkFile); #else MultiByteToWideChar(CP_ACP, 0, lpszLinkFile, -1, wsz, MAX_PATH); #endif // Load the Internet Shortcut from persistent storage. hr = pPersistFile->Load(wsz, STGM_READ); if (SUCCEEDED(hr)) { hr = pUrlLink->GetURL(lpszURL); } pPersistFile->Release(); } pUrlLink->Release(); return hr; } // // ResolveLink: Resolves a Shell Link to its actual folder location // STDMETHODIMP CShellPidl::ResolveLink(HWND hWnd,LPCTSTR lpszLinkFile, LPTSTR* lpszURL) { IShellLink* pShellLink = NULL; *lpszURL = NULL; // Assume failure HRESULT hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&pShellLink); if (SUCCEEDED(hr)) { IPersistFile* pPersistFile = NULL; hr = pShellLink->QueryInterface(IID_IPersistFile, (LPVOID*)&pPersistFile); if (SUCCEEDED(hr)) { // Ensure that the string is Unicode. WORD wsz[MAX_PATH]; #ifdef UNICODE _tcscpy(wsz,lpszLinkFile); #else MultiByteToWideChar(CP_ACP, 0, lpszLinkFile, -1, wsz, MAX_PATH); #endif // Load the shortcut.from persistent storage hr = pPersistFile->Load(wsz, STGM_READ); if (SUCCEEDED(hr)) { WIN32_FIND_DATA wfd; hr = pShellLink->Resolve(hWnd, SLR_NO_UI); if (NOERROR == hr) { // Get the path to the link target. *lpszURL = (LPTSTR)m_pMalloc->Alloc(MAX_PATH); // Must remember to Free later hr = pShellLink->GetPath(*lpszURL, MAX_PATH - 1, (WIN32_FIND_DATA*)&wfd, SLGP_UNCPRIORITY); } } pPersistFile->Release(); } pShellLink->Release(); } return hr; } // // This method converts a STRRET structure to a LPTSTR // #ifdef UNICODE STDMETHODIMP CShellPidl::StrRetToStr(STRRET StrRet, LPTSTR* str, LPITEMIDLIST pidl) { HRESULT hr = S_OK; int cch; LPSTR strOffset; *str = NULL; // Assume failure switch (StrRet.uType) { case STRRET_WSTR: cch = wcslen(StrRet.pOleStr) + 1; // NULL terminator *str = (LPTSTR)m_pMalloc->Alloc(cch * sizeof(TCHAR)); if (*str != NULL) lstrcpyn(*str, StrRet.pOleStr, cch); else hr = E_FAIL; break; case STRRET_OFFSET: strOffset = (((char *) pidl) + StrRet.uOffset); cch = MultiByteToWideChar(CP_OEMCP, 0, strOffset, -1, NULL, 0); *str = (LPTSTR)m_pMalloc->Alloc(cch * sizeof(TCHAR)); if (*str != NULL) MultiByteToWideChar(CP_OEMCP, 0, strOffset, -1, *str, cch); else hr = E_FAIL; break; case STRRET_CSTR: cch = MultiByteToWideChar(CP_OEMCP, 0, StrRet.cStr, -1, NULL, 0); *str = (LPTSTR)m_pMalloc->Alloc(cch * sizeof(TCHAR)); if (*str != NULL) MultiByteToWideChar(CP_OEMCP, 0, StrRet.cStr, -1, *str, cch); else hr = E_FAIL; break; } return hr; } #else // UNICODE not defined STDMETHODIMP CShellPidl::StrRetToStr(STRRET StrRet, LPTSTR* str, LPITEMIDLIST pidl) { HRESULT hr = S_OK; int cch; LPSTR strOffset; *str = NULL; // Assume failure switch (StrRet.uType) { case STRRET_WSTR: cch = WideCharToMultiByte(CP_ACP, 0, StrRet.pOleStr, -1, NULL, 0, NULL, NULL); *str = (LPTSTR)m_pMalloc->Alloc(cch * sizeof(TCHAR)); if (*str != NULL) WideCharToMultiByte(CP_ACP, 0, StrRet.pOleStr, -1, *str, cch, NULL, NULL); else hr = E_FAIL; break; case STRRET_OFFSET: strOffset = (((char *) pidl) + StrRet.uOffset); cch = strlen(strOffset) + 1; // NULL terminator *str = (LPTSTR)m_pMalloc->Alloc(cch * sizeof(TCHAR)); if (*str != NULL) strcpy(*str, strOffset); else hr = E_FAIL; break; case STRRET_CSTR: cch = strlen(StrRet.cStr) + 1; // NULL terminator *str = (LPTSTR)m_pMalloc->Alloc(cch * sizeof(TCHAR)); if (*str != NULL) strcpy(*str, StrRet.cStr); else hr = E_FAIL; break; } return hr; } #endif