home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / winui / shell / regview / shlfldr.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-27  |  16.9 KB  |  680 lines

  1. /**************************************************************************
  2.    THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  3.    ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  4.    THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  5.    PARTICULAR PURPOSE.
  6.  
  7.    Copyright 1997 Microsoft Corporation.  All Rights Reserved.
  8. **************************************************************************/
  9.  
  10. /**************************************************************************
  11.  
  12.    File:          ShlFldr.cpp
  13.    
  14.    Description:   Implements CShellFolder.
  15.  
  16. **************************************************************************/
  17.  
  18. /**************************************************************************
  19.    #include statements
  20. **************************************************************************/
  21.  
  22. #include "ShlFldr.h"
  23. #include "ShlView.h"
  24. #include "InfoTip.h"
  25. #include "ExtrIcon.h"
  26. #include "Guid.h"
  27. #include "resource.h"
  28.  
  29. /**************************************************************************
  30.  
  31.    CShellFolder::CShellFolder()
  32.  
  33. **************************************************************************/
  34.  
  35. CShellFolder::CShellFolder(CShellFolder *pParent, LPCITEMIDLIST pidl)
  36. {
  37. m_hKeyRoot = NULL;
  38. m_lpszSubKey = NULL;
  39.  
  40. m_pSFParent = pParent;
  41. if(m_pSFParent)
  42.    m_pSFParent->AddRef();
  43.  
  44. m_pPidlMgr = new CPidlMgr();
  45. if(!m_pPidlMgr)
  46.    {
  47.    delete this;
  48.    return;
  49.    }
  50.  
  51. //get the shell's IMalloc pointer
  52. //we'll keep this until we get destroyed
  53. if(FAILED(SHGetMalloc(&m_pMalloc)))
  54.    {
  55.    delete this;
  56.    return;
  57.    }
  58.  
  59. m_pidl = m_pPidlMgr->Copy(pidl);
  60.  
  61. if(m_pidl)
  62.    {
  63.    //determine if this PIDL has an HKEY or a sub key string
  64.    if(m_pPidlMgr->IsRootKey(m_pidl))
  65.       {
  66.       //this is a root key
  67.       m_pPidlMgr->GetRootKey(m_pidl, &m_hKeyRoot);
  68.       }
  69.  
  70.    DWORD dwSize = m_pPidlMgr->GetSubKeyText(m_pidl, NULL, 0);
  71.    m_lpszSubKey = new TCHAR[dwSize];
  72.    if(m_lpszSubKey)
  73.       {
  74.       m_pPidlMgr->GetSubKeyText(m_pidl, m_lpszSubKey, dwSize);
  75.       }
  76.    }
  77.  
  78. m_ObjRefCount = 1;
  79.  
  80. g_DllRefCount++;
  81. }
  82.  
  83. /**************************************************************************
  84.  
  85.    CShellFolder::~CShellFolder()
  86.  
  87. **************************************************************************/
  88.  
  89. CShellFolder::~CShellFolder()
  90. {
  91. if(m_pidl)
  92.    {
  93.    m_pPidlMgr->Delete(m_pidl);
  94.    m_pidl = NULL;
  95.    }
  96.  
  97. if(m_lpszSubKey)
  98.    delete m_lpszSubKey;
  99.  
  100. if(m_pSFParent)
  101.    m_pSFParent->Release();
  102.  
  103. if(m_pMalloc)
  104.    {
  105.    m_pMalloc->Release();
  106.    }
  107.  
  108. if(m_pPidlMgr)
  109.    {
  110.    delete m_pPidlMgr;
  111.    }
  112.  
  113. g_DllRefCount--;
  114. }
  115.  
  116. ///////////////////////////////////////////////////////////////////////////
  117. //
  118. // IUnknown Implementation
  119. //
  120.  
  121. /**************************************************************************
  122.  
  123.    CShellFolder::QueryInterface
  124.  
  125. **************************************************************************/
  126.  
  127. STDMETHODIMP CShellFolder::QueryInterface(REFIID riid, LPVOID *ppReturn)
  128. {
  129. *ppReturn = NULL;
  130.  
  131. //IUnknown
  132. if(IsEqualIID(riid, IID_IUnknown))
  133.    {
  134.    *ppReturn = this;
  135.    }
  136.  
  137. //IPersistFolder
  138. else if(IsEqualIID(riid, IID_IPersistFolder))
  139.    {
  140.    *ppReturn = (IPersistFolder*)this;
  141.    }
  142.  
  143. //IShellFolder
  144. else if(IsEqualIID(riid, IID_IShellFolder))
  145.    {
  146.    *ppReturn = (IShellFolder*)this;
  147.    }
  148.  
  149. if(*ppReturn)
  150.    {
  151.    (*(LPUNKNOWN*)ppReturn)->AddRef();
  152.    return S_OK;
  153.    }
  154.  
  155. return E_NOINTERFACE;
  156. }                                             
  157.  
  158. /**************************************************************************
  159.  
  160.    CShellFolder::AddRef
  161.  
  162. **************************************************************************/
  163.  
  164. STDMETHODIMP_(DWORD) CShellFolder::AddRef()
  165. {
  166. return ++m_ObjRefCount;
  167. }
  168.  
  169. /**************************************************************************
  170.  
  171.    CShellFolder::Release
  172.  
  173. **************************************************************************/
  174.  
  175. STDMETHODIMP_(DWORD) CShellFolder::Release()
  176. {
  177. if(--m_ObjRefCount == 0)
  178.    {
  179.    delete this;
  180.    return 0;
  181.    }
  182.    
  183. return m_ObjRefCount;
  184. }
  185.  
  186. ///////////////////////////////////////////////////////////////////////////
  187. //
  188. // IPersist Implementation
  189. //
  190.  
  191. /**************************************************************************
  192.  
  193.    CShellView::GetClassID()
  194.    
  195. **************************************************************************/
  196.  
  197. STDMETHODIMP CShellFolder::GetClassID(LPCLSID lpClassID)
  198. {
  199. *lpClassID = CLSID_RegViewNameSpace;
  200.  
  201. return S_OK;
  202. }
  203.  
  204. ///////////////////////////////////////////////////////////////////////////
  205. //
  206. // IPersistFolder Implementation
  207. //
  208.  
  209. /**************************************************************************
  210.  
  211.    CShellView::Initialize()
  212.    
  213. **************************************************************************/
  214.  
  215. STDMETHODIMP CShellFolder::Initialize(LPCITEMIDLIST pidl)
  216. {
  217. return S_OK;
  218. }
  219.  
  220. ///////////////////////////////////////////////////////////////////////////
  221. //
  222. // IShellFolder Implementation
  223. //
  224.  
  225. /**************************************************************************
  226.  
  227.    CShellFolder::BindToObject()
  228.    
  229. **************************************************************************/
  230.  
  231. STDMETHODIMP CShellFolder::BindToObject(  LPCITEMIDLIST pidl, 
  232.                                           LPBC pbcReserved, 
  233.                                           REFIID riid, 
  234.                                           LPVOID *ppvOut)
  235. {
  236. *ppvOut = NULL;
  237.  
  238. CShellFolder   *pShellFolder = new CShellFolder(this, pidl);
  239. if(!pShellFolder)
  240.    return E_OUTOFMEMORY;
  241.  
  242. HRESULT  hr = pShellFolder->QueryInterface(riid, ppvOut);
  243.  
  244. pShellFolder->Release();
  245.  
  246. return hr;
  247. }
  248.  
  249. /**************************************************************************
  250.  
  251.    CShellFolder::BindToStorage()
  252.    
  253. **************************************************************************/
  254.  
  255. STDMETHODIMP CShellFolder::BindToStorage( LPCITEMIDLIST pidl, 
  256.                                           LPBC pbcReserved, 
  257.                                           REFIID riid, 
  258.                                           LPVOID *ppvOut)
  259. {
  260. *ppvOut = NULL;
  261.  
  262. return E_NOTIMPL;
  263. }
  264.  
  265. /**************************************************************************
  266.  
  267.    CShellFolder::CompareIDs()
  268.    
  269. **************************************************************************/
  270.  
  271. STDMETHODIMP CShellFolder::CompareIDs( LPARAM lParam, 
  272.                                        LPCITEMIDLIST pidl1, 
  273.                                        LPCITEMIDLIST pidl2)
  274. {
  275. TCHAR szString1[MAX_PATH] = TEXT("");
  276. TCHAR szString2[MAX_PATH] = TEXT("");
  277. HKEY  hkey1 = NULL,
  278.       hkey2 = NULL;
  279. int   nReturn;
  280.  
  281. /*
  282. Special case - If one of the items is a key and the other is a value, always 
  283. make the key come before the value.
  284. */
  285. LPCITEMIDLIST  pidlTemp1 = pidl1,
  286.                pidlTemp2 = pidl2;
  287.  
  288. //get the last item in each list
  289. while((m_pPidlMgr->GetNextItem(pidlTemp1))->mkid.cb)
  290.    pidlTemp1 = m_pPidlMgr->GetNextItem(pidlTemp1);
  291. while((m_pPidlMgr->GetNextItem(pidlTemp2))->mkid.cb)
  292.    pidlTemp2 = m_pPidlMgr->GetNextItem(pidlTemp2);
  293.  
  294. //at this point, both pidlTemp1 and pidlTemp2 point to the last item in the list
  295. if(m_pPidlMgr->IsValue(pidlTemp1) != m_pPidlMgr->IsValue(pidlTemp2))
  296.    {
  297.    if(m_pPidlMgr->IsValue(pidlTemp1))
  298.       return 1;
  299.  
  300.    return -1;
  301.    }
  302.  
  303. //get the numeric value of the root key
  304. m_pPidlMgr->GetRootKey(pidl1, &hkey1);
  305. m_pPidlMgr->GetRootKey(pidl2, &hkey2);
  306.  
  307. //compare the root keys
  308. if(hkey1 != hkey2)
  309.    {
  310.    return (int)((DWORD)hkey1 - (DWORD)hkey2);
  311.    }
  312.  
  313. //now compare the subkey strings
  314. m_pPidlMgr->GetSubKeyText( pidl1, 
  315.                            szString1, 
  316.                            sizeof(szString1));
  317. m_pPidlMgr->GetSubKeyText( pidl2, 
  318.                            szString2, 
  319.                            sizeof(szString2));
  320. nReturn = lstrcmpi(szString1, szString2);
  321. if(nReturn)
  322.    return nReturn;
  323.  
  324. //now compare the value strings
  325. m_pPidlMgr->GetValueText(  pidl1, 
  326.                            szString1, 
  327.                            sizeof(szString1));
  328. m_pPidlMgr->GetValueText(  pidl2, 
  329.                            szString2, 
  330.                            sizeof(szString2));
  331. return lstrcmpi(szString1, szString2);
  332. }
  333.  
  334. /**************************************************************************
  335.  
  336.    CShellFolder::CreateViewObject()
  337.    
  338. **************************************************************************/
  339.  
  340. STDMETHODIMP CShellFolder::CreateViewObject( HWND hwndOwner, 
  341.                                              REFIID riid, 
  342.                                              LPVOID *ppvOut)
  343. {
  344. HRESULT     hr;
  345. CShellView  *pShellView;
  346.  
  347. *ppvOut = NULL;
  348.  
  349. pShellView = new CShellView(this, m_pidl);
  350. if(!pShellView)
  351.    return E_OUTOFMEMORY;
  352.  
  353. hr = pShellView->QueryInterface(riid, ppvOut);
  354.  
  355. pShellView->Release();
  356.  
  357. return hr;
  358. }
  359.  
  360. /**************************************************************************
  361.  
  362.    CShellFolder::EnumObjects()
  363.    
  364. **************************************************************************/
  365.  
  366. STDMETHODIMP CShellFolder::EnumObjects(   HWND hwndOwner, 
  367.                                           DWORD dwFlags, 
  368.                                           LPENUMIDLIST *ppEnumIDList)
  369. {
  370. HRESULT  hr;
  371.  
  372. *ppEnumIDList = NULL;
  373.  
  374. *ppEnumIDList = new CEnumIDList(GetRootKey(), m_lpszSubKey, dwFlags, &hr);
  375. if(!*ppEnumIDList)
  376.    return hr;
  377.  
  378. return S_OK;
  379. }
  380.  
  381. /**************************************************************************
  382.  
  383.    CShellFolder::GetAttributesOf()
  384.    
  385. **************************************************************************/
  386.  
  387. STDMETHODIMP CShellFolder::GetAttributesOf(  UINT uCount, 
  388.                                              LPCITEMIDLIST aPidls[], 
  389.                                              LPDWORD pdwAttribs)
  390. {
  391. UINT  i;
  392.  
  393. *pdwAttribs = (DWORD)-1;
  394.  
  395. for(i = 0; i < uCount; i++)
  396.    {
  397.    DWORD dwAttribs = 0;
  398.  
  399.    //flags common to all items
  400.    dwAttribs |= 0;
  401.  
  402.    //is this item a key?
  403.    if(!m_pPidlMgr->IsValue(m_pPidlMgr->GetLastItem(aPidls[i])))
  404.       {
  405.       dwAttribs |= SFGAO_FOLDER;
  406.  
  407.       //does this item have a sub folder?
  408.       if(m_pPidlMgr->HasSubKeys(GetRootKey(), m_lpszSubKey, aPidls[i]))
  409.          dwAttribs |= SFGAO_HASSUBFOLDER;
  410.       }
  411.    
  412.    *pdwAttribs &= dwAttribs;
  413.    }
  414.  
  415. return S_OK;
  416. }
  417.  
  418. /**************************************************************************
  419.  
  420.    CShellFolder::GetUIObjectOf()
  421.    
  422. **************************************************************************/
  423.  
  424. STDMETHODIMP CShellFolder::GetUIObjectOf( HWND hwndOwner, 
  425.                                           UINT uCount, 
  426.                                           LPCITEMIDLIST *pPidl, 
  427.                                           REFIID riid, 
  428.                                           LPUINT puReserved, 
  429.                                           LPVOID *ppvReturn)
  430. {
  431. *ppvReturn = NULL;
  432.  
  433. if(uCount != 1)
  434.    return E_FAIL;
  435.  
  436. if(IsEqualIID(riid, IID_IExtractIcon))
  437.    {
  438.    CExtractIcon   *pei;
  439.    LPITEMIDLIST   pidl;
  440.  
  441.    pidl = m_pPidlMgr->Concatenate(m_pidl, pPidl[0]);
  442.  
  443.    pei = new CExtractIcon(pidl);
  444.  
  445.    /*
  446.    The temp PIDL can be deleted because the new CExtractIcon either failed or 
  447.    made its own copy of it.
  448.    */
  449.    m_pPidlMgr->Delete(pidl);
  450.  
  451.    if(pei)
  452.       {
  453.       *ppvReturn = pei;
  454.       return S_OK;
  455.       }
  456.    
  457.    return E_OUTOFMEMORY;
  458.    }
  459.  
  460. #if (_WIN32_IE >= 0x0400)
  461. if(IsEqualIID(riid, IID_IQueryInfo))
  462.    {
  463.    CQueryInfo     *pqit;
  464.    LPITEMIDLIST   pidl;
  465.  
  466.    pidl = m_pPidlMgr->Concatenate(m_pidl, pPidl[0]);
  467.  
  468.    pqit = new CQueryInfo(pidl);
  469.  
  470.    /*
  471.    The temp PIDL can be deleted because the new CQueryInfo either failed or 
  472.    made its own copy of it.
  473.    */
  474.    m_pPidlMgr->Delete(pidl);
  475.  
  476.    if(pqit)
  477.       {
  478.       *ppvReturn = pqit;
  479.       return S_OK;
  480.       }
  481.    
  482.    return E_OUTOFMEMORY;
  483.    }
  484. #endif   //#if (_WIN32_IE >= 0x0400)
  485.  
  486. return E_NOINTERFACE;
  487. }
  488.  
  489. /**************************************************************************
  490.  
  491.    CShellFolder::GetDisplayNameOf()
  492.    
  493. **************************************************************************/
  494.  
  495. #define GET_SHGDN_FOR(dwFlags)         ((DWORD)dwFlags & (DWORD)0x0000FF00)
  496. #define GET_SHGDN_RELATION(dwFlags)    ((DWORD)dwFlags & (DWORD)0x000000FF)
  497.  
  498. STDMETHODIMP CShellFolder::GetDisplayNameOf( LPCITEMIDLIST pidl, 
  499.                                              DWORD dwFlags, 
  500.                                              LPSTRRET lpName)
  501. {
  502. TCHAR szText[MAX_PATH];
  503. int   cchOleStr;
  504.  
  505. switch(GET_SHGDN_FOR(dwFlags))
  506.    {
  507.    case SHGDN_FORPARSING:
  508.    case SHGDN_FORADDRESSBAR:
  509.    case SHGDN_NORMAL:
  510.       switch(GET_SHGDN_RELATION(dwFlags))
  511.          {
  512.          case SHGDN_NORMAL:
  513.             //get the full name
  514.             m_pPidlMgr->GetPidlPath(pidl, szText, sizeof(szText));
  515.  
  516.             //If the text is NULL and this is a value, get the default item name.
  517.             if(!*szText && m_pPidlMgr->IsValue(m_pPidlMgr->GetLastItem(pidl)))
  518.                {
  519.                LoadString(g_hInst, IDS_DEFAULT, szText, sizeof(szText));
  520.                }
  521.             break;
  522.  
  523.          case SHGDN_INFOLDER:
  524.             {
  525.             LPITEMIDLIST   pidlTemp = m_pPidlMgr->GetLastItem(pidl);
  526.  
  527.             //get the relative name
  528.              m_pPidlMgr->GetItemText(pidlTemp, szText, sizeof(szText));
  529.  
  530.             //If the text is NULL and this is a value, get the default item name.
  531.             if(!*szText && m_pPidlMgr->IsValue(pidlTemp))
  532.                {
  533.                LoadString(g_hInst, IDS_DEFAULT, szText, sizeof(szText));
  534.                }
  535.             }
  536.             break;
  537.  
  538.          default:
  539.             return E_INVALIDARG;
  540.          }
  541.       break;
  542.    
  543.    default:
  544.       return E_INVALIDARG;
  545.    }
  546.  
  547. //get the number of characters required
  548. cchOleStr = lstrlen(szText) + 1;
  549.  
  550. //allocate the wide character string
  551. lpName->pOleStr = (LPWSTR)m_pMalloc->Alloc(cchOleStr * sizeof(WCHAR));
  552. if(!lpName->pOleStr)
  553.    return E_OUTOFMEMORY;
  554.  
  555. lpName->uType = STRRET_WSTR;
  556.  
  557. LocalToWideChar(lpName->pOleStr, szText, cchOleStr);
  558.  
  559. return S_OK;
  560. }
  561.  
  562. /**************************************************************************
  563.  
  564.    CShellFolder::ParseDisplayName()
  565.    
  566. **************************************************************************/
  567.  
  568. STDMETHODIMP CShellFolder::ParseDisplayName( HWND hwndOwner, 
  569.                                              LPBC pbcReserved, 
  570.                                              LPOLESTR lpDisplayName, 
  571.                                              LPDWORD pdwEaten, 
  572.                                              LPITEMIDLIST *pPidlNew, 
  573.                                              LPDWORD pdwAttributes)
  574. {
  575. return E_NOTIMPL;
  576. }
  577.  
  578. /**************************************************************************
  579.  
  580.    CShellFolder::SetNameOf()
  581.    
  582. **************************************************************************/
  583.  
  584. STDMETHODIMP CShellFolder::SetNameOf(  HWND hwndOwner, 
  585.                                        LPCITEMIDLIST pidl, 
  586.                                        LPCOLESTR lpName, 
  587.                                        DWORD dw, 
  588.                                        LPITEMIDLIST *pPidlOut)
  589. {
  590. return E_NOTIMPL;
  591. }
  592.  
  593. /**************************************************************************
  594.  
  595.    CShellFolder::GetFolderPath()
  596.    
  597. **************************************************************************/
  598.  
  599. BOOL CShellFolder::GetFolderPath(LPTSTR lpszOut, DWORD dwOutSize)
  600. {
  601. TCHAR    szTemp[MAX_PATH] = TEXT("");
  602. DWORD    dwSize;
  603.  
  604. if(!lpszOut)
  605.    return FALSE;
  606.  
  607. *lpszOut = 0;
  608.  
  609. //get the text for the root key
  610. GetRootKeyText(m_hKeyRoot, szTemp, sizeof(szTemp));
  611.  
  612. dwSize = lstrlen(szTemp);
  613. if(m_lpszSubKey)
  614.    dwSize += lstrlen(m_lpszSubKey) + 1;
  615.  
  616. //is the output buffer big enough?
  617. if(dwSize > dwOutSize)
  618.    return FALSE;
  619.  
  620. //add the text we already have
  621. lstrcpy(lpszOut, szTemp);
  622.  
  623. //add this folder's text if present
  624. if(m_lpszSubKey && *m_lpszSubKey)
  625.    {
  626.    lstrcat(lpszOut, TEXT("\\"));
  627.    lstrcat(lpszOut, m_lpszSubKey);
  628.    }
  629.  
  630. return TRUE;
  631. }
  632.  
  633. /**************************************************************************
  634.  
  635.    CShellFolder::GetFolderText()
  636.    
  637. **************************************************************************/
  638.  
  639. BOOL CShellFolder::GetFolderText(LPTSTR lpszOut, DWORD dwOutSize)
  640. {
  641. if(!lpszOut)
  642.    return FALSE;
  643.  
  644. *lpszOut = 0;
  645.  
  646. //add this folder's text if present
  647. if(m_lpszSubKey && *m_lpszSubKey)
  648.    {
  649.    lstrcpyn(lpszOut, m_lpszSubKey, dwOutSize);
  650.    }
  651.  
  652. return TRUE;
  653. }
  654.  
  655. /**************************************************************************
  656.  
  657.    CShellFolder::GetRootKey()
  658.    
  659. **************************************************************************/
  660.  
  661. HKEY CShellFolder::GetRootKey(void)
  662. {
  663. HKEY  hkReturn = NULL;
  664. CShellFolder   *pTemp = this;
  665.  
  666. while(pTemp)
  667.    {
  668.    if(pTemp->m_hKeyRoot)
  669.       {
  670.       hkReturn = pTemp->m_hKeyRoot;
  671.       break;
  672.       }
  673.    
  674.    pTemp = pTemp->m_pSFParent;
  675.    }
  676.  
  677. return hkReturn;
  678. }
  679.  
  680.