atlshellext.h
上传用户:hy_wanghao
上传日期:2007-01-08
资源大小:279k
文件大小:49k
源码类别:

Shell编程

开发平台:

Visual C++

  1. //
  2. // Written by Bjarke Viksoe (bjarke@viksoe.dk)
  3. // Copyright (c) 2001 Bjarke Viksoe.
  4. //
  5. // This code may be used in compiled form in any way you desire. This
  6. // file may be redistributed by any means PROVIDING it is 
  7. // not sold for profit without the authors written consent, and 
  8. // providing that this notice and the authors name is included. 
  9. //
  10. // This file is provided "as is" with no expressed or implied warranty.
  11. // The author accepts no liability if it causes any damage to you or your
  12. // computer whatsoever. It's free, so don't hassle me about it.
  13. //
  14. // Beware of bugs.
  15. #ifndef __ATLSHELLEXT_H__
  16. #define __ATLSHELLEXT_H__
  17. #pragma once
  18. #ifndef __ATLSHELLEXTBASE_H__
  19.    #error atlshellext.h requires atlshellbase.h to be included first
  20. #endif
  21. #include <atlwin.h>
  22. #include <prsht.h>
  23. #include "resource.h"
  24. //////////////////////////////////////////////////////////////////////////////
  25. // CPidl
  26. class CPidl
  27. {
  28. public:
  29.    LPITEMIDLIST m_pidl;
  30. public:
  31.    CPidl() : m_pidl(NULL)
  32.    {
  33.    }
  34.    virtual ~CPidl()
  35.    {
  36.       Delete();
  37.    }
  38.    BOOL IsEmpty()
  39.    {
  40.       return _IsEmpty(m_pidl);
  41.    }
  42.    operator LPITEMIDLIST() const
  43.    {
  44.       return m_pidl;
  45.    }
  46.    LPITEMIDLIST* operator&()
  47.    {
  48.       ATLASSERT(m_pidl==NULL);
  49.       return &m_pidl;
  50.    }
  51.    void Attach(LPITEMIDLIST pSrc)
  52.    {
  53.       Delete();
  54.       m_pidl = pSrc;
  55.    }
  56.    LPITEMIDLIST Detach()
  57.    {
  58.       LPITEMIDLIST pidl = m_pidl;
  59.       m_pidl = NULL;
  60.       return pidl;
  61.    }
  62.    DWORD GetByteSize() 
  63.    { 
  64.       return _GetByteSize(m_pidl);
  65.    }
  66.    UINT GetCount()
  67.    { 
  68.       return _GetCount(m_pidl);
  69.    }
  70.    LPCITEMIDLIST GetNextItem()
  71.    { 
  72.       return _GetNextItem(m_pidl);
  73.    }
  74.    LPCITEMIDLIST GetLastItem()
  75.    { 
  76.       return _GetLastItem(m_pidl);
  77.    }
  78.    LPITEMIDLIST CopyFirstItem()
  79.    { 
  80.       return _CopyFirstItem(m_pidl);
  81.    }
  82.   
  83.    LPITEMIDLIST Copy()
  84.    { 
  85.       return _Copy(m_pidl);
  86.    }
  87.    void Delete()
  88.    { 
  89.       _Delete(m_pidl);
  90.       m_pidl = NULL;
  91.    }
  92.    void Copy(LPCITEMIDLIST pidlSource) 
  93.    { 
  94.       Delete();
  95.       m_pidl = _Copy(pidlSource);
  96.    }  
  97.    void Concatenate(LPCITEMIDLIST pidl2)
  98.    {
  99.       if( (m_pidl==NULL) && (pidl2==NULL) ) return;
  100.       if( m_pidl==NULL ) {
  101.          m_pidl = _Copy(pidl2);
  102.          return;
  103.       }
  104.       if( pidl2==NULL ) return;
  105.       DWORD cb1, cb2;
  106.       cb1 = GetByteSize() - sizeof(ITEMIDLIST);
  107.       cb2 = _GetByteSize(pidl2);
  108.       LPITEMIDLIST pidlNew = (LPITEMIDLIST)_Module.m_Allocator.Alloc(cb1 + cb2);
  109.       if( pidlNew!=NULL ) {
  110.          ::CopyMemory( pidlNew, m_pidl, cb1 );
  111.          ::CopyMemory( ((LPBYTE)pidlNew) + cb1, pidl2, cb2 );
  112.       }
  113.       Attach(pidlNew);
  114.    }
  115.    void RemoveLast()
  116.    {
  117.       LPITEMIDLIST pidlLast = const_cast<LPITEMIDLIST>(_GetLastItem(m_pidl));
  118.       if( pidlLast!=NULL ) pidlLast->mkid.cb = 0;
  119.    }
  120.    inline static BOOL _IsEmpty(LPCITEMIDLIST pidl)
  121.    {
  122.       return pidl==NULL || pidl->mkid.cb==0;
  123.    }
  124.    static LPCITEMIDLIST _GetLastItem(LPCITEMIDLIST pidl) 
  125.    { 
  126.       // Get the PIDL of the last item in the list 
  127.       LPCITEMIDLIST pidlLast = NULL;  
  128.       if( pidl!=NULL ) {    
  129.          while( pidl->mkid.cb > 0 ) { 
  130.             pidlLast = pidl;
  131.             pidl = _GetNextItem(pidl);       
  132.          }      
  133.       }  
  134.       return pidlLast; 
  135.    } 
  136.    inline static LPITEMIDLIST _GetNextItem(LPCITEMIDLIST pidl) 
  137.    { 
  138.       return pidl==NULL ? NULL : (LPITEMIDLIST)(LPBYTE)(((LPBYTE)pidl) + pidl->mkid.cb);
  139.    }  
  140.    static UINT _GetCount(LPCITEMIDLIST pidlSource)
  141.    {
  142.       UINT cbTotal = 0; 
  143.       if( pidlSource!=NULL ) {    
  144.          while( pidlSource->mkid.cb > 0 ) {
  145.             cbTotal++;
  146.             pidlSource = _GetNextItem(pidlSource); 
  147.          }       
  148.       }  
  149.       return cbTotal; 
  150.    }
  151.    static DWORD _GetByteSize(LPCITEMIDLIST pidlSource)
  152.    { 
  153.       DWORD cbTotal = 0; 
  154.       if( pidlSource!=NULL ) {
  155.          while( pidlSource->mkid.cb > 0 ) {
  156.             cbTotal += pidlSource->mkid.cb;       
  157.             pidlSource = _GetNextItem(pidlSource);       
  158.          }       
  159.          // Add the size of the NULL terminating ITEMIDLIST    
  160.          cbTotal += sizeof(ITEMIDLIST);    
  161.       }  
  162.       return cbTotal; 
  163.    }
  164.    static void _Delete(LPITEMIDLIST pidlSource)
  165.    {
  166.       if( pidlSource==NULL ) return;
  167.       _Module.m_Allocator.Free( pidlSource ); 
  168.    }
  169.    static LPITEMIDLIST _Copy(LPCITEMIDLIST pidlSource) 
  170.    { 
  171.       LPITEMIDLIST pidlTarget = NULL; 
  172.       DWORD cbSource = 0;  
  173.       if( NULL==pidlSource ) return NULL;  
  174.       // Allocate the new pidl 
  175.       cbSource = _GetByteSize(pidlSource); 
  176.       pidlTarget = (LPITEMIDLIST)_Module.m_Allocator.Alloc(cbSource); 
  177.       if( pidlTarget==NULL ) return NULL;  // Copy the source to the target 
  178.       ::CopyMemory( pidlTarget, pidlSource, cbSource );
  179.       return pidlTarget; 
  180.    }
  181.    static LPITEMIDLIST _CopyFirstItem(LPCITEMIDLIST pidlSource) 
  182.    { 
  183.       LPITEMIDLIST pidlTarget = NULL; 
  184.       DWORD cbSource = 0;  
  185.       if( NULL==pidlSource ) return NULL;  
  186.       // Allocate the new pidl 
  187.       cbSource = pidlSource->mkid.cb + sizeof(ITEMIDLIST); 
  188.       pidlTarget = (LPITEMIDLIST)_Module.m_Allocator.Alloc(cbSource); 
  189.       if( pidlTarget==NULL ) return NULL;  // Copy the source to the target 
  190.       ::CopyMemory( pidlTarget, pidlSource, cbSource );
  191.       // Terminate the IDList 
  192.       *(WORD *)(((LPBYTE)pidlTarget)+pidlTarget->mkid.cb) = 0;  
  193.       return pidlTarget;
  194.    }
  195. };
  196. /////////////////////////////////////////////////////////////////////////////
  197. // CPidlList
  198. class CPidlList
  199. {
  200. public:
  201.    CPidlList()
  202.    {
  203.       m_pidls = NULL;
  204.       m_nCount = 0;
  205.       m_bOwner = false;
  206.    }
  207.    
  208.    CPidlList(HWND hwndList, DWORD dwListViewMask=LVNI_SELECTED)
  209.    {
  210.       ATLASSERT(::IsWindow(hwndList));
  211.       m_pidls = NULL;
  212.       m_nCount = 0;
  213.       UINT nCount = ( dwListViewMask==LVNI_SELECTED ? ListView_GetSelectedCount(hwndList) : ListView_GetItemCount(hwndList) );
  214.       if( nCount==0 ) return;
  215.       LPITEMIDLIST *pidls = (LPITEMIDLIST *)_Module.m_Allocator.Alloc(nCount * sizeof(LPITEMIDLIST));   
  216.       if( pidls==NULL ) return;
  217.    
  218.       int nItem = -1;
  219.       UINT i = 0;
  220.       while( (nItem = ListView_GetNextItem(hwndList, nItem, dwListViewMask))!=-1 )
  221.       {
  222.          LVITEM lvi = { 0 };
  223.          lvi.mask = LVIF_PARAM;
  224.          lvi.iItem = nItem;
  225.          ListView_GetItem(hwndList, &lvi);
  226.          pidls[i++] = (LPITEMIDLIST)lvi.lParam;
  227.       }
  228.       m_pidls = pidls;
  229.       m_nCount = i;
  230.       m_bOwner = false;
  231.    }
  232.    
  233.    virtual ~CPidlList()
  234.    {
  235.       Delete();
  236.    }
  237.    operator LPCITEMIDLIST *() const 
  238.    { 
  239.       return const_cast<LPCITEMIDLIST *>(m_pidls); 
  240.    }
  241.    UINT GetCount() const 
  242.    { 
  243.       return m_nCount; 
  244.    }
  245.    LPITEMIDLIST *Detach()
  246.    {
  247.       LPITEMIDLIST *pidls = m_pidls;
  248.       m_pidls = NULL;
  249.       m_nCount = 0;
  250.       m_bOwner = false;
  251.       return pidls;
  252.    }
  253.    
  254.    HRESULT Attach(LPITEMIDLIST *pidlSource, UINT nCount, BOOL bOwnItems=FALSE)
  255.    {
  256.       Delete();
  257.       m_pidls = pidlSource;
  258.       m_nCount = nCount;
  259.       m_bOwner = (bOwnItems==TRUE);
  260.       return S_OK;
  261.    }
  262.    
  263.    HRESULT Copy(LPCITEMIDLIST *pidlSource, UINT nCount, BOOL bOwnItems=FALSE)
  264.    {
  265.       ATLASSERT(pidlSource);
  266.       ATLASSERT(nCount>0);
  267.       if( (pidlSource==NULL) || (nCount==0) ) return E_INVALIDARG;
  268.       Delete();
  269.       m_pidls = (LPITEMIDLIST *)_Module.m_Allocator.Alloc(nCount * sizeof(LPITEMIDLIST));
  270.       if( m_pidls==NULL ) return E_OUTOFMEMORY;
  271.       m_nCount = nCount;
  272.       // If requested, we'll make a copy of each PIDL structure too, otherwise
  273.       // simply copy memory (weak reference).
  274.       if( bOwnItems ) {
  275.          for( UINT i=0; i<nCount; i++ ) m_pidls[i] = CPidl::_Copy(pidlSource[i]);
  276.          m_bOwner = true;
  277.       }
  278.       else {
  279.          ::CopyMemory(m_pidls, pidlSource, nCount * sizeof(LPITEMIDLIST));
  280.          m_bOwner = false;
  281.       }
  282.       return S_OK;
  283.    }
  284.    
  285.    void Delete()
  286.    {
  287.       if( m_pidls!=NULL ) {
  288.          if( m_bOwner ) for( UINT i=0; i<m_nCount; i++ ) _Module.m_Allocator.Free((LPVOID)m_pidls[i]);
  289.          _Module.m_Allocator.Free(m_pidls);
  290.          m_pidls = NULL;
  291.          m_nCount = 0;
  292.          m_bOwner = false;
  293.       }
  294.    }
  295.    HRESULT Filter(IShellFolder *pFolder, DWORD dwItemMask)
  296.    {
  297.       ATLASSERT(pFolder);
  298.       ATLASSERT(dwItemMask!=0);
  299.       ATLASSERT(!m_bOwner);
  300.       if( m_nCount==0 ) return S_OK;
  301.       LPITEMIDLIST *pidls = (LPITEMIDLIST *)_Module.m_Allocator.Alloc(m_nCount * sizeof(LPITEMIDLIST));
  302.       if( pidls==NULL ) return E_OUTOFMEMORY;
  303.       UINT nCount=0;
  304.       for( UINT i=0; i<m_nCount; i++ ) {
  305.          DWORD dwAttr = dwItemMask;
  306.          LPCITEMIDLIST pidl = m_pidls[i];
  307.          pFolder->GetAttributesOf(1, &pidl, &dwAttr);
  308.          if( (dwAttr & dwItemMask)==dwItemMask ) {
  309.             pidls[nCount] = m_pidls[i];
  310.             nCount++;
  311.          }
  312.       }
  313.       // We've recreated a new PIDL list.
  314.       // The allocated memory for the list may actually be too large, but
  315.       // it doesn't matter for the PIDL functions.
  316.       return Attach(pidls, nCount, FALSE);
  317.    }
  318.    LPITEMIDLIST *m_pidls;
  319.    UINT m_nCount;
  320.    bool m_bOwner;
  321. };
  322. #ifdef __ATLCOM_H__
  323. /////////////////////////////////////////////////////////////////////////////
  324. // CPidlEnum
  325. class ATL_NO_VTABLE CPidlEnum : 
  326.    public CComObjectRootEx<CComSingleThreadModel>,
  327.    public IEnumIDList
  328. {
  329. public:
  330.    HRESULT FinalConstruct()
  331.    {
  332.       m_iCount = 0;
  333.       m_iPos = 0;
  334.       return S_OK;
  335.    }
  336. DECLARE_NO_REGISTRY()
  337. DECLARE_NOT_AGGREGATABLE(CPidlEnum)
  338. DECLARE_PROTECT_FINAL_CONSTRUCT()
  339. BEGIN_COM_MAP(CPidlEnum)
  340.    COM_INTERFACE_ENTRY_IID(IID_IEnumIDList,IEnumIDList)
  341. END_COM_MAP()
  342. public:
  343.    HRESULT _Init(LPCITEMIDLIST pPidlArray, UINT nCount)
  344.    {      
  345.       m_pidl.Copy(pPidlArray);
  346.       m_iCount = nCount;
  347.       Reset();
  348.       return S_OK;
  349.    }
  350.    STDMETHOD(Next)(ULONG /*celt*/, LPITEMIDLIST *rgelt, ULONG *pceltFetched)
  351.    { 
  352.       ATLTRACE2(atlTraceCOM, 0, _T("IEnumIDList::Nextn"));
  353.       *rgelt = NULL; 
  354.       if( pceltFetched ) *pceltFetched = 0;
  355.       if( m_pidl.IsEmpty() ) return S_FALSE;
  356.       m_iPos++;
  357.       if( m_iPos > m_iCount ) return S_FALSE;
  358.       *rgelt = CPidl::_CopyFirstItem(m_pCur);
  359.       m_pCur = CPidl::_GetNextItem(m_pCur);
  360.       if( (*rgelt!=NULL)  && ((*rgelt)->mkid.cb!=0) ) { 
  361.           if( pceltFetched!=NULL ) *pceltFetched = 1; 
  362.           return S_OK; 
  363.       }
  364.       return E_OUTOFMEMORY; 
  365.    }   
  366.    STDMETHOD(Reset)(void)
  367.    { 
  368.       ATLTRACE2(atlTraceCOM, 0, _T("IEnumIDList::Resetn"));
  369.       m_iPos = 0;
  370.       m_pCur = m_pidl;
  371.       return S_OK; 
  372.    }
  373.    STDMETHOD(Skip)(ULONG /*celt*/)
  374.    {
  375.       ATLTRACENOTIMPL(_T("IEnumIDList::Skip"));
  376.    }
  377.    STDMETHOD(Clone)(IEnumIDList ** /*ppEnum*/)
  378.    {
  379.       ATLTRACENOTIMPL(_T("IEnumIDList::Clone"));
  380.    }
  381. public:
  382.    CPidl m_pidl;
  383.    LPCITEMIDLIST m_pCur;
  384.    UINT m_iCount; 
  385.    UINT m_iPos;
  386. };
  387. //////////////////////////////////////////////////////////////////////////////
  388. // IShellFolderImpl
  389. #define GET_SHGDN_FOR(dwFlags)         ((DWORD)dwFlags & (DWORD)0x0000FF00)
  390. #define GET_SHGDN_RELATION(dwFlags)    ((DWORD)dwFlags & (DWORD)0x000000FF)
  391. template <class T, typename DataStruct>
  392. class ATL_NO_VTABLE IShellFolderImpl : 
  393.    public IShellFolder,
  394.    public IPersistFolder,
  395.    public CPidl
  396. {
  397. public:
  398.    // IPersistFolder
  399.    STDMETHOD(GetClassID)(CLSID *pClassID)
  400.    {
  401.       ATLTRACE2(atlTraceCOM, 0, _T("IPersistFolder::GetClassIDn"));
  402.       ATLASSERT(pClassID);
  403.       if( pClassID==NULL ) return E_POINTER;
  404.       *pClassID = T::GetObjectCLSID();
  405.       return S_OK;
  406.    }
  407.   
  408.    STDMETHOD(Initialize)(LPCITEMIDLIST pList)
  409.    {
  410.       ATLTRACE2(atlTraceCOM, 0, _T("IPersistFolder::Initializen"));
  411.       ATLASSERT(pList);
  412.       if( pList==NULL ) return E_INVALIDARG;
  413.       Copy(pList);
  414.       return S_OK;
  415.    }
  416.    // IShellFolder
  417.    STDMETHOD(EnumObjects)(HWND, DWORD, LPENUMIDLIST *ppRetVal)
  418.    {
  419.       ATLTRACE2(atlTraceCOM, 0, _T("IShellFolder::EnumObjectsn"));
  420.       ATLASSERT(ppRetVal);
  421.       // Return empty collection
  422.       DataStruct v[1];
  423.       v[0].cb = 0;
  424.       HRESULT Hr;
  425.       CComObject<CPidlEnum> *pEnum;
  426.       Hr = CComObject<CPidlEnum>::CreateInstance(&pEnum);
  427.       if( FAILED(Hr) ) return Hr;
  428.       Hr = pEnum->_Init((LPITEMIDLIST)v, 1);
  429.       if( FAILED(Hr) ) return Hr;
  430.       Hr = pEnum->QueryInterface(IID_IEnumIDList,(LPVOID *)ppRetVal);
  431.       if( FAILED(Hr) ) return Hr;
  432.       return S_OK;
  433.    }
  434.    STDMETHOD(BindToObject)(LPCITEMIDLIST /*pidl*/, LPBC, REFIID /*riid*/, LPVOID *ppRetVal)
  435.    {
  436.       // Subfolders not implemented
  437.       *ppRetVal = NULL;
  438.       ATLTRACENOTIMPL(_T("IShellFolder::BindToObject"));
  439.    }
  440.    STDMETHOD(BindToStorage)(LPCITEMIDLIST, LPBC, REFIID, LPVOID *ppRetVal)
  441.    {
  442.       *ppRetVal = NULL;
  443.       ATLTRACENOTIMPL(_T("IShellFolder::BindToStorage"));
  444.    }
  445.    STDMETHOD(CreateViewObject)(HWND /*hwndOwner*/, REFIID riid, LPVOID *ppRetVal )
  446.    {
  447.       ATLTRACE2(atlTraceCOM, 0, _T("IShellFolder::CreateViewObjectn"));
  448.       ATLASSERT(::IsBadReadPtr(&riid,sizeof(IID))==FALSE);
  449.       if( riid != IID_IShellView ) return E_NOINTERFACE;
  450.       T *pT = static_cast<T*>(this);
  451.       return pT->_CreateShellFolderView(ppRetVal);
  452.    }
  453.    STDMETHOD(GetUIObjectOf)(HWND, UINT, LPCITEMIDLIST*, REFIID, LPUINT, LPVOID*)
  454.    {
  455.       ATLTRACE2(atlTraceCOM, 0, _T("IShellFolder::GetUIObjectOfn"));
  456.       return E_NOINTERFACE;
  457.    }
  458.    STDMETHOD(GetDisplayNameOf)(LPCITEMIDLIST, DWORD, LPSTRRET)
  459.    {
  460.       ATLTRACENOTIMPL(_T("IShellFolder::GetDisplayNameOf"));
  461.    }
  462.    STDMETHOD(GetAttributesOf)(UINT, LPCITEMIDLIST*, LPDWORD rgfInOut)
  463.    {
  464.       ATLTRACE2(atlTraceCOM, 0, _T("IShellFolder::GetAttributesOfn"));      
  465.       *rgfInOut = 0;
  466.       return S_OK;
  467.    }
  468.    STDMETHOD(ParseDisplayName)(HWND, LPBC, LPOLESTR, LPDWORD, LPITEMIDLIST*, LPDWORD /*ppRetVal*/)
  469.    {
  470.       ATLTRACENOTIMPL(_T("IShellFolder::ParseDisplayName"));
  471.    }
  472.    STDMETHOD(SetNameOf)(HWND, LPCITEMIDLIST, LPCOLESTR, DWORD, LPITEMIDLIST*)
  473.    {
  474.       ATLTRACENOTIMPL(_T("IShellFolder::SetNameOf"));
  475.    }
  476.    STDMETHOD(CompareIDs)(LPARAM, LPCITEMIDLIST, LPCITEMIDLIST)
  477.    {
  478.       ATLTRACENOTIMPL(_T("IShellFolder::CompareIDs"));
  479.    }
  480.    HRESULT _CreateShellFolderView(LPVOID *ppvObj)
  481.    {
  482.       ATLTRACENOTIMPL(_T("IShellFolder::_CreateShellFolderView"));
  483.    }
  484. };
  485. //////////////////////////////////////////////////////////////////////////////
  486. // IShellViewImpl
  487. template <class T>
  488. class ATL_NO_VTABLE IShellViewImpl : 
  489.    public IShellView2
  490. {
  491. public:
  492.    enum { IDC_LISTVIEW = 123 };
  493.    BEGIN_MSG_MAP(IShellViewImpl<T>)
  494.       MESSAGE_HANDLER(WM_CREATE, OnCreate)
  495.       MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
  496.       MESSAGE_HANDLER(WM_KILLFOCUS, OnKillFocus)
  497.       MESSAGE_HANDLER(WM_SIZE, OnSize)
  498.       MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange)
  499.       MESSAGE_HANDLER(WM_INITMENUPOPUP, OnInitMenu)
  500.       MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
  501.       NOTIFY_CODE_HANDLER(NM_SETFOCUS, OnNotifySetFocus)
  502.       NOTIFY_CODE_HANDLER(NM_KILLFOCUS, OnNotifyKillFocus)
  503.    END_MSG_MAP()
  504.    IShellViewImpl() :
  505.       m_pShellBrowser(NULL), m_uState(SVUIA_DEACTIVATE), m_hWnd(NULL), m_hwndList(NULL)
  506.    {
  507.       ZeroMemory(&m_ShellFlags,sizeof(m_ShellFlags));
  508.       m_dwListViewStyle = WS_TABSTOP | 
  509.                           WS_VISIBLE |
  510.                           WS_CHILD | 
  511.                           WS_BORDER | 
  512.                           LVS_REPORT | 
  513.                           LVS_NOSORTHEADER |
  514.                           LVS_SHAREIMAGELISTS;
  515.    }
  516. public:
  517.    const MSG *m_pCurrentMsg;
  518.    HWND m_hWnd;
  519.    HWND m_hwndList;
  520.    DWORD m_dwListViewStyle;
  521.    //
  522.    FOLDERSETTINGS m_FolderSettings;
  523.    SHELLFLAGSTATE m_ShellFlags;
  524.    LPSHELLBROWSER m_pShellBrowser;
  525.    UINT m_uState;
  526. public:
  527.    // IOleWindow
  528.    
  529.    STDMETHOD(GetWindow)(HWND *phWnd)
  530.    {
  531.       ATLTRACE2(atlTraceCOM, 0, _T("IOleWindow::GetWindown"));
  532.       ATLASSERT(phWnd);
  533.       ATLASSERT(::IsWindow(m_hWnd));
  534.       *phWnd = m_hWnd;
  535.       return S_OK;
  536.    }
  537.    STDMETHOD(ContextSensitiveHelp)(BOOL)
  538.    {
  539.       ATLTRACENOTIMPL(_T("IOleWindow::ContextSesitiveHelp"));
  540.    }
  541.    // IShellView
  542.    STDMETHOD(TranslateAccelerator)(LPMSG /*lpmsg*/)
  543.    {
  544.       return E_NOTIMPL;
  545.    }
  546.    STDMETHOD(Refresh)(void)
  547.    {
  548.       ATLTRACE2(atlTraceCOM, 0, _T("IShellView::Refreshn"));
  549.       ATLASSERT(::IsWindow(m_hwndList));
  550.       // Empty the list
  551.       ListView_DeleteAllItems(m_hwndList);
  552.       // Refill the list
  553.       T *pT = static_cast<T*>(this);
  554.       pT->_FillListView();
  555.       return S_OK;
  556.    }
  557.    STDMETHOD(AddPropertySheetPages)(
  558.       DWORD /*dwReserved*/,
  559.       LPFNADDPROPSHEETPAGE /*lpfn*/, 
  560.       LPARAM /*lParam*/)
  561.    {
  562.       ATLTRACENOTIMPL(_T("IShellView::AddPropertySheetPages"));
  563.    }
  564.    STDMETHOD(SelectItem)(LPCITEMIDLIST /*pidlItem*/, UINT /*uFlags*/)
  565.    {
  566.       ATLTRACENOTIMPL(_T("IShellView::SelectItem"));
  567.    }
  568.    STDMETHOD(GetItemObject)(UINT /*uItem*/, REFIID /*riid*/, LPVOID * ppRetVal)
  569.    {
  570.       ATLASSERT(ppRetVal);
  571.       ppRetVal;
  572.       ATLTRACENOTIMPL(_T("IShellView::GetItemObject"));
  573.    }
  574.    STDMETHOD(EnableModeless)(BOOL /*fEnable*/)
  575.    {
  576.       ATLTRACENOTIMPL(_T("IShellView::EnableModeless"));
  577.    }
  578.    STDMETHOD(GetCurrentInfo)(LPFOLDERSETTINGS lpFS)
  579.    {
  580.       ATLTRACE2(atlTraceCOM, 0, _T("IShellView::GetCurrentInfon"));
  581.       ATLASSERT(lpFS);
  582.       *lpFS = m_FolderSettings;
  583.       return S_OK;
  584.    }
  585.    STDMETHOD(UIActivate)(UINT uState)
  586.    {
  587.       ATLTRACE2(atlTraceCOM, 0, _T("IShellView::UIActivate (%d)n"), uState);
  588.       ATLASSERT(m_pShellBrowser);
  589.       // Only do this if we are active
  590.       if( m_uState==uState ) return S_OK;      
  591.       // _ViewActivate() handles merging of menus etc
  592.       T *pT = static_cast<T*>(this);
  593.       if( SVUIA_ACTIVATE_FOCUS==uState ) ::SetFocus(m_hwndList);
  594.       pT->_ViewActivate(uState);
  595.       if( uState != SVUIA_DEACTIVATE) {
  596.          // Update the status bar: set 'parts' and change text
  597.          LRESULT lResult;
  598.          int nPartArray[1] = { -1 };
  599.          m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETPARTS, 1, (LPARAM)nPartArray, &lResult);
  600.          // Set the statusbar text to the default description.
  601.          // The string resource IDS_DESCRIPTION must be defined!
  602.          TCHAR szName[128];
  603.          ::LoadString(_Module.GetResourceInstance(), IDS_DESCRIPTION, szName, sizeof(szName)/sizeof(TCHAR));
  604.          m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETTEXT, 0, (LPARAM)szName, &lResult);
  605.       }
  606.       return S_OK;
  607.    }
  608.    STDMETHOD(CreateViewWindow)(
  609.       IShellView * /*lpPrevView*/,
  610.       LPCFOLDERSETTINGS pFS, 
  611.       IShellBrowser *pSB,
  612.       RECT *prcView, 
  613.       HWND *phWnd)
  614.    {
  615.       ATLTRACE2(atlTraceCOM, 0, _T("IShellView::CreateViewWindown"));
  616.       ATLASSERT(prcView);
  617.       ATLASSERT(pSB);
  618.       ATLASSERT(pFS);
  619.       ATLASSERT(phWnd);
  620.       // Register the ClassName.
  621.       // The ClassName comes from the string resource IDS_CLASSNAME!
  622.       TCHAR szClassName[64];
  623.       ::LoadString(_Module.GetResourceInstance(), IDS_CLASSNAME, szClassName, sizeof(szClassName)/sizeof(TCHAR));
  624.       WNDCLASS wc = { 0 };
  625.       *phWnd = NULL;
  626.       // If our window class has not been registered, then do so
  627.       if( !::GetClassInfo(_Module.GetModuleInstance(), szClassName, &wc) ) {
  628.          wc.style          = 0;
  629.          wc.lpfnWndProc    = (WNDPROC)WndProc;
  630.          wc.cbClsExtra     = 0;
  631.          wc.cbWndExtra     = 0;
  632.          wc.hInstance      = _Module.GetModuleInstance();
  633.          wc.hIcon          = NULL;
  634.          wc.hCursor        = ::LoadCursor(NULL, IDC_ARROW);
  635.          wc.hbrBackground  = (HBRUSH)(COLOR_WINDOW + 1);
  636.          wc.lpszMenuName   = NULL;
  637.          wc.lpszClassName  = szClassName; 
  638.          if( !::RegisterClass(&wc) ) return E_FAIL;
  639.       }
  640.       // Set up the member variables
  641.       m_pShellBrowser = pSB;
  642.       m_FolderSettings = *pFS;
  643.       m_ShellFlags.fWin95Classic = TRUE;
  644.       m_ShellFlags.fShowAllObjects = TRUE;
  645.       m_ShellFlags.fShowAttribCol = TRUE;
  646.       // Get our parent window
  647.       HWND hwndShell;
  648.       m_pShellBrowser->GetWindow(&hwndShell);
  649.       // Create host window
  650.       T *pT = static_cast<T*>(this);
  651.       *phWnd = ::CreateWindowEx(WS_EX_CONTROLPARENT,
  652.                                 szClassName,
  653.                                 NULL,
  654.                                 WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_TABSTOP,
  655.                                 prcView->left,
  656.                                 prcView->top,
  657.                                 prcView->right - prcView->left,
  658.                                 prcView->bottom - prcView->top,
  659.                                 hwndShell,
  660.                                 NULL,
  661.                                 _Module.GetModuleInstance(),
  662.                                 (LPVOID)pT);
  663.       if(!*phWnd) return E_FAIL;
  664.       pT->_MergeToolbar(SVUIA_ACTIVATE_FOCUS);
  665.       m_pShellBrowser->AddRef();
  666.       return S_OK;
  667.    }
  668.    STDMETHOD(DestroyViewWindow)(void)
  669.    {
  670.       ATLTRACE2(atlTraceCOM, 0, _T("IShellView::DestroyViewWindown"));
  671.       ATLASSERT(m_pShellBrowser);
  672.       // Make absolutely sure all our UI is cleaned up.
  673.       UIActivate(SVUIA_DEACTIVATE);
  674.       ::DestroyWindow(m_hWnd);
  675.       // Release the shell browser object
  676.       m_pShellBrowser->Release();
  677.       return S_OK;
  678.    }
  679.    STDMETHOD(SaveViewState)(void)
  680.    {
  681.       return S_OK;
  682.    }
  683.    // IShellView2
  684.    STDMETHOD(CreateViewWindow2)(LPSV2CVW2_PARAMS lpParams) 
  685.    {
  686.       ATLTRACE2(atlTraceCOM, 0, _T("IShellView::CreateViewWindow2n"));
  687.       return CreateViewWindow(lpParams->psvPrev, lpParams->pfs, lpParams->psbOwner, lpParams->prcView, &lpParams->hwndView);
  688.    }
  689.    
  690.    STDMETHOD(GetView)(SHELLVIEWID * /*pvid*/, ULONG /*uView*/) 
  691.    {
  692.       ATLTRACENOTIMPL(_T("IShellView2::GetView"));
  693.    }
  694.    
  695.    STDMETHOD(HandleRename)(LPCITEMIDLIST /*pidlNew*/) 
  696.    {
  697.       ATLTRACENOTIMPL(_T("IShellView2::HandleRename"));
  698.    }
  699.    
  700.    STDMETHOD(SelectAndPositionItem)(LPCITEMIDLIST /*pidlItem*/, UINT /*uFlags*/, POINT * /*point*/) 
  701.    {
  702.       ATLTRACENOTIMPL(_T("IShellView2::SelectAndPositionItem"));
  703.    }
  704.    // View handlers
  705.    LRESULT _ViewActivate(UINT uState)
  706.    {
  707.       ATLTRACE2(atlTraceCOM, 0, _T("IShellView::_ViewActivate %dn"), uState);
  708.       // Don't do anything if the state isn't really changing
  709.       if( m_uState==uState ) return S_OK;
  710.       T *pT = static_cast<T*>(this);
  711.       pT->_ViewDeactivate();
  712.       // Only do this if we are active
  713.       if( uState!=SVUIA_DEACTIVATE ) {
  714.          pT->_MergeMenus(uState);
  715.          pT->_UpdateToolbar();
  716.       }
  717.       m_uState = uState;
  718.       return 0;
  719.    }
  720.    LRESULT _ViewDeactivate(void)
  721.    {
  722.       ATLTRACE2(atlTraceCOM, 0, _T("IShellView::_ViewDeactivaten"));
  723.       //if( m_uState != SVUIA_DEACTIVATE ) {
  724.          T *pT = static_cast<T*>(this);
  725.          m_uState = SVUIA_DEACTIVATE;
  726.          pT->_MergeMenus(m_uState);
  727.          pT->_MergeToolbar(m_uState);
  728.       //}
  729.       return 0;
  730.    }
  731.    // Since ::SHGetSettings() is not implemented in all versions of the shell, get the 
  732.    // function address manually at run time. This allows the extension to run on all 
  733.    // platforms.
  734.    void _GetShellSettings(SHELLFLAGSTATE &sfs, DWORD dwMask)
  735.    {
  736.       typedef void (WINAPI *PFNSHGETSETTINGSPROC)(LPSHELLFLAGSTATE lpsfs, DWORD dwMask);
  737.       HINSTANCE hinstShell32;
  738.       hinstShell32 = ::LoadLibrary(TEXT("shell32.dll"));
  739.       if( hinstShell32!=NULL ){
  740.          PFNSHGETSETTINGSPROC pfnSHGetSettings = (PFNSHGETSETTINGSPROC) ::GetProcAddress(hinstShell32, "SHGetSettings");
  741.          if(pfnSHGetSettings) (*pfnSHGetSettings)(&sfs, dwMask);
  742.          ::FreeLibrary(hinstShell32);
  743.       }
  744.    }
  745.    // A helper function which will take care of some of
  746.    // the fancy new Win98 settings...
  747.    void _UpdateShellSettings(void)
  748.    {
  749.       // Update the m_ShellFlags state
  750.       _GetShellSettings(m_ShellFlags, 
  751.          SSF_DESKTOPHTML | 
  752.          SSF_NOCONFIRMRECYCLE | 
  753.          SSF_SHOWALLOBJECTS | 
  754.          SSF_SHOWATTRIBCOL | 
  755.          SSF_DOUBLECLICKINWEBVIEW | 
  756.          SSF_SHOWCOMPCOLOR |
  757.          SSF_WIN95CLASSIC);
  758.       
  759.       // Update the ListView control accordingly
  760.       DWORD dwExStyles = 0;
  761.       if( !m_ShellFlags.fWin95Classic && !m_ShellFlags.fDoubleClickInWebView ) {
  762.          dwExStyles |= LVS_EX_ONECLICKACTIVATE | 
  763.                        LVS_EX_TRACKSELECT | 
  764.                        LVS_EX_UNDERLINEHOT;
  765.       }
  766.       ListView_SetExtendedListViewStyle(m_hwndList, dwExStyles);
  767.    }
  768.    LRESULT DefWindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
  769.    {
  770. #ifdef STRICT
  771.       return ::DefWindowProc(m_hWnd, uMsg, wParam, lParam);
  772. #else
  773.       return ::DefWindowProc(m_hWnd, uMsg, wParam, lParam);
  774. #endif
  775.    }
  776.    static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
  777.    {
  778.       T *pT = (T*)::GetWindowLong(hWnd, GWL_USERDATA);
  779.       if(uMessage == WM_NCCREATE) {
  780.          LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam;
  781.          pT = (T*)(lpcs->lpCreateParams);
  782.          ::SetWindowLong(hWnd, GWL_USERDATA, (LONG)pT);
  783.          // Set the window handle
  784.          pT->m_hWnd = hWnd;
  785.          return 1;
  786.       }
  787.       ATLASSERT(pT);
  788.       MSG msg = { pT->m_hWnd, uMessage, wParam, lParam, 0, { 0, 0 } };
  789.       const MSG *pOldMsg = pT->m_pCurrentMsg;
  790.       pT->m_pCurrentMsg = &msg;
  791.       // pass to the message map to process
  792.       LRESULT lRes;
  793.       BOOL bRet = pT->ProcessWindowMessage(pT->m_hWnd, uMessage, wParam, lParam, lRes, 0);
  794.       // restore saved value for the current message
  795.       ATLASSERT(pT->m_pCurrentMsg == &msg);
  796.       pT->m_pCurrentMsg = pOldMsg;
  797.       if(!bRet) lRes = pT->DefWindowProc(uMessage, wParam, lParam);
  798.       return lRes;
  799.    }
  800.    // Message handlers
  801.    LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  802.    {
  803.       ATLTRACE2(atlTraceWindowing, 0, _T("IShellView::OnSetFocusn"));
  804.       ::SetFocus(m_hwndList);
  805.       return 0;
  806.    }
  807.    LRESULT OnKillFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  808.    {
  809.       ATLTRACE2(atlTraceWindowing, 0, _T("IShellView::OnKillFocusn"));
  810.       return 0;
  811.    }
  812.    LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  813.    {
  814.       T *pT = static_cast<T*>(this);
  815.       pT->_UpdateShellSettings();
  816.       return 0;
  817.    }
  818.    LRESULT OnNotifySetFocus(UINT /*CtlID*/, LPNMHDR /*lpnmh*/, BOOL &/*bHandled*/)
  819.    {
  820.       ATLTRACE2(atlTraceWindowing, 0, _T("IShellView::OnNotifySetFocusn"));
  821.       ATLASSERT(m_pShellBrowser);
  822.       // Tell the browser one of our windows has received the focus. This should always 
  823.       // be done before merging menus (_ViewActivate() merges the menus) if one of our 
  824.       // windows has the focus.
  825.       T *pT = static_cast<T*>(this);
  826.       m_pShellBrowser->OnViewWindowActive((IShellView *)pT);
  827.       pT->_ViewActivate(SVUIA_ACTIVATE_FOCUS);
  828.       return 0;
  829.    }
  830.    LRESULT OnNotifyKillFocus(UINT /*CtlID*/, LPNMHDR /*lpnmh*/, BOOL &/*bHandled*/)
  831.    {
  832.       ATLTRACE2(atlTraceWindowing, 0, _T("IShellView::OnNotifyKillFocusn"));
  833.       T *pT = static_cast<T*>(this);
  834.       pT->_ViewActivate(SVUIA_ACTIVATE_NOFOCUS);
  835.       return 0;
  836.    }
  837.    LRESULT OnInitMenu(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  838.    {
  839.       T *pT = static_cast<T*>(this);
  840.       pT->_UpdateMenu((HMENU)wParam);
  841.       return 0;
  842.    }
  843.    LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
  844.    {
  845.       // Resize the ListView to fit our window
  846.       if(m_hwndList) ::MoveWindow(m_hwndList, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
  847.       return 0;
  848.    }
  849.    LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  850.    {
  851.       return 1; // avoid flicker
  852.    }
  853.    LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  854.    {
  855.       // Create the ListView
  856.       T *pT = static_cast<T*>(this);
  857.       if( pT->_CreateListView() )
  858.          if( pT->_InitListView() )
  859.             pT->_FillListView();
  860.       return 0;
  861.    }
  862.    // Operations
  863.    typedef enum {
  864.       TBI_STD = 0,
  865.       TBI_VIEW,
  866.       TBI_LOCAL
  867.    } TOOLBARITEM;
  868.    typedef struct
  869.    {
  870.       TOOLBARITEM nType;
  871.       TBBUTTON tb;
  872.    } NS_TOOLBUTTONINFO, *PNS_TOOLBUTTONINFO;
  873.    BOOL _AppendToolbarItems(
  874.       PNS_TOOLBUTTONINFO pButtons, 
  875.       int nCount, 
  876.       LPARAM lOffsetFile, 
  877.       LPARAM lOffsetView, 
  878.       LPARAM lOffsetCustom)
  879.    {
  880.       ATLASSERT(nCount>0);
  881.       ATLASSERT(!::IsBadReadPtr(pButtons, nCount*sizeof(NS_TOOLBUTTONINFO)));
  882.       ATLASSERT(m_pShellBrowser);
  883.       LPTBBUTTON ptbb = (LPTBBUTTON)::GlobalAlloc(GPTR, sizeof(TBBUTTON)*nCount);
  884.       if( ptbb==NULL ) return FALSE;
  885.       for( int j=0; j<nCount; j++ ) {
  886.          switch( pButtons[j].nType ) {
  887.          case TBI_STD:
  888.             (ptbb + j)->iBitmap = lOffsetFile + pButtons[j].tb.iBitmap;
  889.             break;
  890.          case TBI_VIEW:
  891.             (ptbb + j)->iBitmap = lOffsetView + pButtons[j].tb.iBitmap;
  892.             break;
  893.          case TBI_LOCAL:
  894.             (ptbb + j)->iBitmap = lOffsetCustom + pButtons[j].tb.iBitmap;
  895.             break;
  896.          }
  897.          (ptbb + j)->idCommand = pButtons[j].tb.idCommand;
  898.          (ptbb + j)->fsState = pButtons[j].tb.fsState;
  899.          (ptbb + j)->fsStyle = pButtons[j].tb.fsStyle;
  900.          (ptbb + j)->dwData = pButtons[j].tb.dwData;
  901.          (ptbb + j)->iString = pButtons[j].tb.iString;
  902.       }
  903.       m_pShellBrowser->SetToolbarItems(ptbb, nCount, FCT_MERGE);
  904.       ::GlobalFree((HGLOBAL)ptbb);
  905.       return TRUE;
  906.    }
  907.    UINT _GetMenuPosFromID(HMENU hMenu, UINT ID) const
  908.    {
  909.       UINT nCount = ::GetMenuItemCount(hMenu);
  910.       for( UINT i=0; i<nCount; i++ ) {
  911.          if( ::GetMenuItemID(hMenu, i)==ID ) return i;
  912.       }
  913.       return (UINT)-1;
  914.    }
  915.    BOOL _AppendMenu(HMENU hMenu, HMENU hMenuSource, UINT nPosition)
  916.    {
  917.       ATLASSERT(::IsMenu(hMenu));
  918.       ATLASSERT(::IsMenu(hMenuSource));
  919.       // Get the HMENU of the popup
  920.       if( hMenu==NULL ) return FALSE;
  921.       if( hMenuSource==NULL ) return FALSE;
  922.       // Make sure that we start with only one separator menu-item
  923.       int iStartPos = 0;
  924.       if( ::GetMenuState(hMenuSource, 0, MF_BYPOSITION) & MF_SEPARATOR ) {
  925.          if( (nPosition==0) || 
  926.              (::GetMenuState(hMenu, nPosition-1, MF_BYPOSITION) & MF_SEPARATOR) ) {
  927.             iStartPos++;
  928.          }
  929.       }
  930.       // Go...
  931.       int nMenuItems = ::GetMenuItemCount(hMenuSource);
  932.       for( int i=iStartPos; i<nMenuItems; i++ ) {
  933.          // Get state information
  934.          UINT state = ::GetMenuState(hMenuSource, i, MF_BYPOSITION);
  935.          TCHAR szItemText[256];
  936.          int nLen = ::GetMenuString(hMenuSource, i, szItemText, sizeof(szItemText)/sizeof(TCHAR), MF_BYPOSITION);
  937.          // Is this a separator?
  938.          if( state & MF_SEPARATOR ) {
  939.             ::InsertMenu(hMenu, nPosition++, state | MF_STRING | MF_BYPOSITION, 0, _T(""));
  940.          }
  941.          else if( state & MF_POPUP ) {
  942.             // Strip the HIBYTE because it contains a count of items
  943.             state = LOBYTE(state) | MF_POPUP;
  944.             // Then create the new submenu by using recursive call
  945.             HMENU hSubMenu = ::CreateMenu();
  946.             _AppendMenu(hSubMenu, ::GetSubMenu(hMenuSource, i), 0);
  947.             ATLASSERT(::GetMenuItemCount(hSubMenu)>0);
  948.             // Non-empty popup -- add it to the shared menu bar
  949.             ::InsertMenu(hMenu, nPosition++, state | MF_BYPOSITION, (UINT)hSubMenu, szItemText);
  950.          }
  951.          else if( nLen>0 ) {
  952.             // Only non-empty items should be added
  953.             ATLASSERT(szItemText[0]!=_T(''));
  954.             ATLASSERT(::GetMenuItemID(hMenuSource, i)>FCIDM_SHVIEWFIRST && ::GetMenuItemID(hMenuSource, i)<FCIDM_SHVIEWLAST);
  955.             // Here the state does not contain a count in the HIBYTE
  956.             ::InsertMenu(hMenu, nPosition++, state | MF_BYPOSITION, ::GetMenuItemID(hMenuSource, i), szItemText);
  957.          }
  958.       }
  959.       return TRUE;
  960.    }
  961.    BOOL _IsExplorerMode() const
  962.    {
  963.       ATLASSERT(m_pShellBrowser);
  964.       HWND hwndTree = NULL;
  965.       return( SUCCEEDED(m_pShellBrowser->GetControlWindow(FCW_TREE, &hwndTree)) && hwndTree );
  966.    }
  967.    // Overridables
  968.    BOOL _CreateListView(void)
  969.    {
  970.       // Initialize and create the actual List View control
  971.       ATLASSERT((m_dwListViewStyle & (WS_VISIBLE|WS_CHILD))==(WS_VISIBLE|WS_CHILD));
  972.       m_dwListViewStyle &= ~LVS_TYPEMASK;
  973.       switch( m_FolderSettings.ViewMode ) {
  974.       case FVM_ICON:
  975.          m_dwListViewStyle |= LVS_ICON;
  976.          break;
  977.       case FVM_SMALLICON:
  978.          m_dwListViewStyle |= LVS_SMALLICON;
  979.          break;
  980.       case FVM_LIST:
  981.          m_dwListViewStyle |= LVS_LIST;
  982.          break;
  983.       case FVM_DETAILS:
  984.          m_dwListViewStyle |= LVS_REPORT;
  985.          break;
  986.       }
  987.       if( FWF_AUTOARRANGE & m_FolderSettings.fFlags ) m_dwListViewStyle |= LVS_AUTOARRANGE;
  988. #if (_WIN32_IE >= 0x0500)
  989.       if( FWF_SHOWSELALWAYS & m_FolderSettings.fFlags ) m_dwListViewStyle |= LVS_SHOWSELALWAYS;
  990. #endif
  991.       if( FWF_ALIGNLEFT & m_FolderSettings.fFlags ) m_dwListViewStyle |= LVS_ALIGNLEFT;
  992.       // Go on,.. create ListView control
  993.       m_hwndList = ::CreateWindowEx( FWF_NOCLIENTEDGE & m_FolderSettings.fFlags ? 0 : WS_EX_CLIENTEDGE,
  994.                                      WC_LISTVIEW,
  995.                                      NULL,
  996.                                      m_dwListViewStyle,
  997.                                      0,0,0,0,
  998.                                      m_hWnd,
  999.                                      (HMENU)IDC_LISTVIEW,
  1000.                                      _Module.GetModuleInstance(),
  1001.                                      NULL);
  1002.       if( m_hwndList==NULL ) return FALSE;
  1003.       T *pT = static_cast<T*>(this);
  1004.       pT->_UpdateShellSettings();
  1005.       return TRUE;
  1006.    }
  1007.    BOOL _InitListView(void) { return TRUE; };
  1008.    BOOL _FillListView(void) { return TRUE; };
  1009.    BOOL _MergeToolbar(UINT uState) { return TRUE; };
  1010.    BOOL _MergeMenus(UINT uState) { return TRUE; };
  1011.    BOOL _UpdateToolbar() { return TRUE; };
  1012.    BOOL _UpdateMenu(HMENU hMenu) { return TRUE; };
  1013. };
  1014. //////////////////////////////////////////////////////////////////////////////
  1015. // CShellPropertyPage
  1016. template <class T>
  1017. class ATL_NO_VTABLE CShellPropertyPage :
  1018.    public IShellPropSheetExt,
  1019.    public IShellExtInit,
  1020.    public CWindow
  1021. {
  1022. public:
  1023.    TCHAR m_szFileName[MAX_PATH];
  1024.    const MSG *m_pCurrentMsg;
  1025.    CShellPropertyPage()
  1026.    {
  1027.       m_szFileName[0]=_T('');
  1028.    }
  1029.    // IShellPropSheetExt
  1030.    STDMETHOD(AddPages)(LPFNADDPROPSHEETPAGE pfnAddPage, LPARAM lParam)
  1031.    {
  1032.       T* pT = static_cast<T*>(this);
  1033.       TCHAR szCaption[40];
  1034.       ::LoadString(_Module.GetResourceInstance(), T::IDS_TABCAPTION, szCaption, sizeof(szCaption)/sizeof(TCHAR));
  1035.       PROPSHEETPAGE psp = { 0 };
  1036.       psp.dwSize        = sizeof(psp);
  1037.       psp.dwFlags       = PSP_USETITLE | PSP_USECALLBACK;
  1038.       psp.hInstance     = _Module.GetResourceInstance();
  1039.       psp.pszTemplate   = MAKEINTRESOURCE(T::IDD);
  1040.       psp.hIcon         = 0;
  1041.       psp.pszTitle      = szCaption;
  1042.       psp.pfnDlgProc    = (DLGPROC)T::PageDlgProc;
  1043.       psp.pcRefParent   = NULL;
  1044.       psp.pfnCallback   = T::PropSheetPageProc;
  1045.       psp.lParam        = (LPARAM)pT;
  1046.       HPROPSHEETPAGE hPage = ::CreatePropertySheetPage(&psp);            
  1047.       if( hPage==NULL ) return E_OUTOFMEMORY;
  1048.       if( pfnAddPage(hPage, lParam)==FALSE ) {
  1049.          ::DestroyPropertySheetPage(hPage);
  1050.          return E_FAIL;
  1051.       }
  1052.       pT->AddRef(); // This reference is release by the callback
  1053.       return MAKE_HRESULT(SEVERITY_SUCCESS, 0, T::ID_TAB_INDEX); // COMCTRL Ver 4.71 allows us to set the initial page index
  1054.    }
  1055.    STDMETHOD(ReplacePage)(UINT /*uPageID*/, LPFNADDPROPSHEETPAGE /*lpfnReplaceWith*/, LPARAM /*lParam*/) 
  1056.    {
  1057.       // The Shell doesn't call this for file class Property Sheets
  1058.       ATLTRACENOTIMPL(_T("IShellPropSheetExt::ReplacePage"));
  1059.    }
  1060.    // IShellExtInit
  1061.    STDMETHOD(Initialize)(LPCITEMIDLIST /*pidlFolder*/, IDataObject *lpDataObject, HKEY /*hkeyProgID*/) 
  1062.    {
  1063.       ATLASSERT(lpDataObject);
  1064.       STGMEDIUM medium;
  1065.       FORMATETC fe = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  1066.       if( SUCCEEDED(lpDataObject->GetData(&fe, &medium)) ) {
  1067.          // Get the file name from the CF_HDROP.
  1068.          UINT uCount = ::DragQueryFile((HDROP)medium.hGlobal, (UINT)-1, NULL, 0);
  1069.          if(uCount>0) ::DragQueryFile((HDROP)medium.hGlobal, 0, m_szFileName, sizeof(m_szFileName)/sizeof(TCHAR));
  1070.          ::ReleaseStgMedium(&medium);
  1071.       }
  1072.       return S_OK;
  1073.    }
  1074.    // Callbacks
  1075.    static UINT CALLBACK PropSheetPageProc(HWND /*hwnd*/, UINT uMsg, LPPROPSHEETPAGE ppsp)
  1076.    {
  1077.       switch( uMsg ) {
  1078.       case PSPCB_CREATE:
  1079.          return 1; // Allow dialog creation
  1080.       case PSPCB_RELEASE:
  1081.          T *pT = (T *)ppsp->lParam;
  1082.          ATLASSERT(pT);
  1083.          pT->Release();
  1084.          break;
  1085.       }
  1086.       return 0;
  1087.    }
  1088.    void SetModified(BOOL bChanged=TRUE)
  1089.    {
  1090.       ATLASSERT(::IsWindow(m_hWnd));
  1091.       ATLASSERT(GetParent()!=NULL);
  1092.       ::SendMessage(GetParent(), bChanged ? PSM_CHANGED : PSM_UNCHANGED, (WPARAM)m_hWnd, 0L);
  1093.    }
  1094.    static int CALLBACK PageDlgProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
  1095.    {    
  1096.       T *pT = (T *)::GetWindowLong(hWnd, GWL_USERDATA);
  1097.       LRESULT lRes = 0;
  1098.       if( uMessage==WM_INITDIALOG ) {
  1099.          pT = (T *)((LPPROPSHEETPAGE)lParam)->lParam;
  1100.          ::SetWindowLong(hWnd, GWL_USERDATA, (LONG)pT);
  1101.          // Set the window handle
  1102.          pT->m_hWnd = hWnd;
  1103.          lRes = 1;
  1104.       }
  1105.       if( pT==NULL ) {
  1106.          // The first message is WM_SETFONT, not WM_INITDIALOG...
  1107.          return FALSE;
  1108.       }
  1109.       MSG msg = { pT->m_hWnd, uMessage, wParam, lParam, 0, { 0, 0 } };
  1110.       const MSG *pOldMsg = pT->m_pCurrentMsg;
  1111.       pT->m_pCurrentMsg = &msg;
  1112.       // pass to the message map to process
  1113.       BOOL bRet = pT->ProcessWindowMessage(pT->m_hWnd, uMessage, wParam, lParam, lRes, 0);
  1114.       // restore saved value for the current message
  1115.       ATLASSERT(pT->m_pCurrentMsg == &msg);
  1116.       pT->m_pCurrentMsg = pOldMsg;
  1117.       // set result if message was handled
  1118.       if(bRet) {
  1119.          switch (uMessage) {
  1120.          case WM_COMPAREITEM:
  1121.          case WM_VKEYTOITEM:
  1122.          case WM_CHARTOITEM:
  1123.          case WM_INITDIALOG:
  1124.          case WM_QUERYDRAGICON:
  1125.          case WM_CTLCOLORMSGBOX:
  1126.          case WM_CTLCOLOREDIT:
  1127.          case WM_CTLCOLORLISTBOX:
  1128.          case WM_CTLCOLORBTN:
  1129.          case WM_CTLCOLORDLG:
  1130.          case WM_CTLCOLORSCROLLBAR:
  1131.          case WM_CTLCOLORSTATIC:
  1132.             return lRes;
  1133.          }
  1134.          ::SetWindowLong(pT->m_hWnd, DWL_MSGRESULT, lRes);
  1135.          return TRUE;
  1136.       }
  1137.       if( uMessage==WM_NCDESTROY ) {
  1138.          // clear out window handle
  1139.          pT->m_hWnd = NULL;
  1140.       }
  1141.       return FALSE;
  1142.    }
  1143. };
  1144. //////////////////////////////////////////////////////////////////////////////
  1145. // CExtractFileIcon
  1146. template< class T >
  1147. class ATL_NO_VTABLE CExtractFileIcon : 
  1148.    public CComObjectRootEx<CComSingleThreadModel>,
  1149.    public IExtractIcon
  1150. {
  1151. public:
  1152. DECLARE_NOT_AGGREGATABLE(CExtractFileIcon)
  1153. BEGIN_COM_MAP(CExtractFileIcon)
  1154.    COM_INTERFACE_ENTRY_IID(IID_IExtractIcon,IExtractIcon)
  1155. END_COM_MAP()
  1156. public:
  1157.    CPidl m_pidl;
  1158. public:
  1159.    void Init(LPCITEMIDLIST pidl)
  1160.    {
  1161.       m_pidl.Copy(pidl);
  1162.    }
  1163.    // IExtractIcon
  1164.    STDMETHOD(GetIconLocation)(UINT uFlags, 
  1165.                               LPTSTR /*szIconFile*/, 
  1166.                               UINT /*cchMax*/, 
  1167.                               LPINT piIndex, 
  1168.                               LPUINT puFlags)
  1169.    {
  1170.       ATLASSERT(piIndex);
  1171.       ATLASSERT(puFlags);
  1172.       if( m_pidl.IsEmpty() ) return E_FAIL;
  1173.       LPCITEMIDLIST pidlLast = CPidl::_GetLastItem(m_pidl);
  1174.       T *pData = (T *)pidlLast;
  1175.       if( pData!=NULL ) {
  1176.          switch( pData->type ) {
  1177.          case 0:
  1178.             *piIndex = 0;
  1179.             *puFlags = GIL_NOTFILENAME;
  1180.             break;
  1181.          case 1:
  1182.             *piIndex = 1;
  1183.             *puFlags = GIL_NOTFILENAME;
  1184.             break;
  1185.          default:
  1186.             *piIndex = 0;
  1187.             *puFlags = GIL_SIMULATEDOC;
  1188.             break;
  1189.          }
  1190.       }
  1191.       return S_OK;
  1192.    }
  1193.    STDMETHOD(Extract)(LPCTSTR pszFile, 
  1194.                       UINT nIconIndex, 
  1195.                       HICON *phiconLarge, 
  1196.                       HICON *phiconSmall, 
  1197.                       UINT nIconSize)
  1198.    {
  1199.       ATLASSERT(phiconLarge);
  1200.       ATLASSERT(phiconSmall);
  1201.       if( m_pidl.IsEmpty() ) return E_FAIL;
  1202.       LPCITEMIDLIST pidlLast = CPidl::_GetLastItem(m_pidl);
  1203.       T *pData = (T *)pidlLast;
  1204.       if( pData!=NULL ) {
  1205.          switch( pData->type ) {
  1206.          case 0:
  1207.             {
  1208.                *phiconLarge = ImageList_GetIcon(_Module.m_ImageLists.m_hImageListLarge, 0, ILD_TRANSPARENT);
  1209.                *phiconSmall = ImageList_GetIcon(_Module.m_ImageLists.m_hImageListSmall, 0, ILD_TRANSPARENT);
  1210.             }
  1211.             break;
  1212.          case 1:
  1213.             {
  1214.                *phiconLarge = ImageList_GetIcon(_Module.m_ImageLists.m_hImageListLarge, 1, ILD_TRANSPARENT);
  1215.                *phiconSmall = ImageList_GetIcon(_Module.m_ImageLists.m_hImageListSmall, 1, ILD_TRANSPARENT);
  1216.             }
  1217.             break;
  1218.          case 2:
  1219.             {
  1220.                TCHAR szPath[MAX_PATH];
  1221.                TCHAR szExt[MAX_PATH];
  1222.                _tcscpy( szPath, pData->ffd.cFileName );
  1223.                LPTSTR psz = _tcschr(szPath, _T('.'));
  1224.                szExt[0] = _T('');
  1225.                if( psz!=NULL ) _tcscpy(szExt, psz);
  1226.                SHFILEINFO sfi = { 0 };
  1227.                HIMAGELIST hImageListLarge = (HIMAGELIST) ::SHGetFileInfo(szExt, 
  1228.                                              FILE_ATTRIBUTE_NORMAL,
  1229.                                              &sfi, sizeof(sfi), 
  1230.                                              SHGFI_USEFILEATTRIBUTES|SHGFI_ICON|SHGFI_SYSICONINDEX);
  1231.                if (hImageListLarge) *phiconLarge = ImageList_GetIcon(hImageListLarge, sfi.iIcon, ILD_TRANSPARENT);
  1232.                HIMAGELIST hImageListSmall = (HIMAGELIST) ::SHGetFileInfo(szExt, 
  1233.                                              FILE_ATTRIBUTE_NORMAL,
  1234.                                              &sfi, sizeof(sfi), 
  1235.                                              SHGFI_USEFILEATTRIBUTES|SHGFI_ICON|SHGFI_SMALLICON|SHGFI_SYSICONINDEX);
  1236.                if (hImageListSmall) *phiconSmall = ImageList_GetIcon(hImageListSmall, sfi.iIcon, ILD_TRANSPARENT);
  1237.             }
  1238.             break;
  1239.          }
  1240.       }
  1241.       return S_OK;
  1242.    }
  1243. };
  1244. //////////////////////////////////////////////////////////////////////////////
  1245. // CContextMenuImpl
  1246. template <class T>
  1247. struct _ATL_CTXMENU_ENTRY
  1248. {
  1249.   UINT id;
  1250.   UINT desc;
  1251.   void (__stdcall T::*pfn)(); // method to invoke
  1252. };
  1253. #define BEGIN_CONTEXTMENU_MAP(theClass) 
  1254.    static const _ATL_CTXMENU_ENTRY<theClass>* _GetCtxMap()
  1255.    {
  1256.       typedef theClass _atl_event_classtype;
  1257.       static const _ATL_CTXMENU_ENTRY<_atl_event_classtype> _ctxmap[] = {
  1258. #define CONTEXTMENU_HANDLER(id, desc, func) 
  1259.     {id, desc, (void (__stdcall _atl_event_classtype::*)())func},
  1260. #define END_CONTEXTMENU_MAP() {0,0,NULL}}; return _ctxmap;}
  1261. template <class T>
  1262. class ATL_NO_VTABLE CShellContextMenu : 
  1263.    public IContextMenu,
  1264.    public IShellExtInit
  1265. {
  1266. public:
  1267.    CRegKey m_regClass;
  1268.    CSimpleArray<CComBSTR> m_arrFiles;
  1269. // IShellExtInit
  1270. public:
  1271.    STDMETHOD(Initialize)(LPCITEMIDLIST pidlFolder,
  1272.                          IDataObject *lpDataObj, 
  1273.                          HKEY hkeyProgID)
  1274.    {
  1275.       ATLTRACE(_T("CShellContextMenu::Initializen"));
  1276.       // Get file class
  1277.       m_regClass.Open(hkeyProgID,NULL);
  1278.       // Get files
  1279.       if( lpDataObj ) {
  1280.          CComPtr<IDataObject> spDataObj(lpDataObj);
  1281.          STGMEDIUM medium;
  1282.          FORMATETC fe = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
  1283.          if( SUCCEEDED(spDataObj->GetData(&fe, &medium)) ) {
  1284.             // Get the filenames from the CF_HDROP.
  1285.             UINT uCount = ::DragQueryFile((HDROP)medium.hGlobal, (UINT)-1, NULL, 0);
  1286.             for( UINT i=0; i<uCount; i++ ) {
  1287.                TCHAR szFileName[MAX_PATH];    
  1288.                ::DragQueryFile((HDROP)medium.hGlobal, i, szFileName, sizeof(szFileName)/sizeof(TCHAR));
  1289.                m_arrFiles.Add(CComBSTR(szFileName));
  1290.             }
  1291.             ::ReleaseStgMedium(&medium);
  1292.          }
  1293.       }    
  1294.       return S_OK;
  1295.     }
  1296. // IContextMenu
  1297. public:
  1298.    STDMETHOD(QueryContextMenu)(HMENU hMenu,
  1299.                                UINT iIndexMenu,
  1300.                                UINT idCmdFirst,
  1301.                                UINT idCmdLast,
  1302.                                UINT uFlags)
  1303.    {
  1304.       ATLTRACE(_T("CShellContextMenu::QueryContextMenun"));
  1305.       const _ATL_CTXMENU_ENTRY<T>* pMap = T::_GetCtxMap();
  1306.       UINT i=0;
  1307.       while( pMap->pfn!=NULL ) {  
  1308.         if( pMap->id==0 ) {
  1309.           ::InsertMenu(hMenu, iIndexMenu++, MF_SEPARATOR | MF_STRING | MF_BYPOSITION, 0, _T(""));
  1310.         }
  1311.         else {
  1312.           TCHAR szText[128];
  1313.           ::LoadString(_Module.GetResourceInstance(), pMap->id, szText, sizeof(szText)/sizeof(TCHAR));
  1314.           ::InsertMenu(hMenu, iIndexMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + i, szText);
  1315.         }
  1316.         i++;
  1317.         pMap++;
  1318.       }
  1319.       T *pT = static_cast<T*>(this);
  1320.       pT->UpdateMenu(hMenu, idCmdFirst);
  1321.       return MAKE_HRESULT(SEVERITY_SUCCESS, 0, i + 1);
  1322.    }
  1323.    STDMETHOD(InvokeCommand)(LPCMINVOKECOMMANDINFO lpcmi)
  1324.    {
  1325.       ATLTRACE(_T("CShellContextMenu::InvokeCommandn"));
  1326.       if( HIWORD(lpcmi->lpVerb) ) return NOERROR; // The command is being sent via a verb
  1327.       UINT idxCmd = LOWORD(lpcmi->lpVerb);
  1328.       const _ATL_CTXMENU_ENTRY<T>* pMap = T::_GetCtxMap();
  1329.       UINT i=0;
  1330.       while( pMap->pfn!=NULL ) {
  1331.          if( i==idxCmd ) {
  1332.             T *pT = static_cast<T*>(this);
  1333.             CComStdCallThunk<T> thunk;
  1334.             thunk.Init(pMap->pfn, pT);
  1335.             VARIANT vRes;
  1336.             ::VariantInit(&vRes);
  1337.             return DispCallFunc(
  1338.                &thunk,
  1339.                0,
  1340.                CC_STDCALL,
  1341.                VT_EMPTY, // this is how DispCallFunc() represents void
  1342.                0,
  1343.                NULL,
  1344.                NULL,
  1345.                &vRes);
  1346.          }
  1347.          pMap++;
  1348.          i++;
  1349.       }
  1350.       return E_INVALIDARG;
  1351.    }
  1352.    STDMETHOD(GetCommandString)(UINT idCmd, UINT uFlags, LPUINT, LPSTR pszName, UINT cchMax)
  1353.    {
  1354.       ATLTRACE(_T("CContextMenu::GetCommandStringn"));
  1355.       switch( uFlags ) {
  1356.       case GCS_HELPTEXTA:
  1357.       case GCS_HELPTEXTW:
  1358.          {
  1359.             const _ATL_CTXMENU_ENTRY<T>* pMap = T::_GetCtxMap();
  1360.             UINT i=0;
  1361.             while( pMap->pfn!=NULL ) {
  1362.               if( i==idCmd ) {
  1363.                 if( uFlags==GCS_HELPTEXTA ) {
  1364.                    ::LoadStringA(_Module.GetResourceInstance(), pMap->desc, pszName, cchMax);
  1365.                 }
  1366.                 else {
  1367.                    // BUG: LoadStringW() is not supported on Win95
  1368.                    ::LoadStringW(_Module.GetResourceInstance(), pMap->desc, (LPWSTR)pszName, cchMax);
  1369.                 } 
  1370.                 return S_OK;
  1371.               }
  1372.               pMap++;
  1373.               i++;
  1374.             }
  1375.          }
  1376.          return E_FAIL;
  1377.       case GCS_VERBA:
  1378.       case GCS_VERBW:
  1379.          return E_FAIL;
  1380.       case GCS_VALIDATE:
  1381.          return NOERROR;
  1382.       default:
  1383.          return E_NOTIMPL;
  1384.       }
  1385.    }
  1386.    void UpdateMenu(HMENU hMenu, UINT iCmdFirst) { };
  1387. };
  1388. #endif // __ATLCOM_H__
  1389. //////////////////////////////////////////////////////////////////////////////
  1390. // ::SHGetPathFromIDList() wrapper
  1391. class CShellPidlPath
  1392. {
  1393. public:
  1394.    CShellPidlPath(LPCITEMIDLIST pidl)
  1395.    {
  1396.       ATLASSERT(pidl);     
  1397.       if( ::SHGetPathFromIDList(pidl, m_szPath)==FALSE ) m_szPath[0]=_T('');
  1398.    }
  1399.    operator LPCTSTR() const { return m_szPath; };
  1400.    TCHAR m_szPath[MAX_PATH];
  1401. };
  1402. //////////////////////////////////////////////////////////////////////////////
  1403. // Shell Helper Functions
  1404. inline LPITEMIDLIST ShellGetFileNamePidl(LPOLESTR pstrFileName)
  1405. {
  1406.    LPSHELLFOLDER pDesktopFolder;
  1407.    if( FAILED(::SHGetDesktopFolder(&pDesktopFolder)) ) return NULL;
  1408.    LPITEMIDLIST pidl;
  1409.    ULONG dwEaten;
  1410.    ULONG dwAttribs;
  1411.    if( FAILED( pDesktopFolder->ParseDisplayName(NULL, NULL, pstrFileName, &dwEaten, &pidl, &dwAttribs) ) ) {
  1412.       pidl = NULL;
  1413.    }
  1414.    pDesktopFolder->Release();
  1415.    return pidl; 
  1416. }
  1417. #endif // __ATLSHELLEXT_H__