Figure 4 Registry Keys
HKEY_CLASSES_ROOT\CLSID\{CLSID}\InProcServer32\(default)= path\filename.dll
HKEY_CLASSES_ROOT\CLSID\{CLSID}\InProcServer32\"ThreadingModel" = "Apartment"
HKEY_CLASSES_ROOT\CLSID\{CLSID}\DefaultIcon\(default)="path\filename.dll", IconIndex ; Icon to use for the name space data file itself (i.e. .CAB file)
HKEY_CLASSES_ROOT\CLSID\{CLSID}\Shell\Open\Command\(default) = c:\windows\Explorer.exe /root,%1
HKEY_CLASSES_ROOT\CLSID\{CLSID}\Shell\Explore\Command\(default) = c:\windows\Explorer.exe /e,/root,%1
HKEY_CLASSES_ROOT\CLSID\{CLSID}\ShellFolder\Attributes = 00 00 00 00 ; i.e. IShellFolder::GetAttributes() ; optional
Figure 9 CAB File Viewer Source Files
File(s) | Contents | Description |
THISDLL.H, THISDLL.CPP | IClassFactory | Generic OLE DLL routines |
FOLDER.H, FOLDER.CPP | IPersistFolder and IShellFolder | Implementation file for CCabFolder |
SFVWND.H, SFVWND.CPP | IShellView and IDropSource | Implementation file for CSFVDropSource and CSFViewDlg |
MENU.H, MENU.CPP | IContextMenu | Implementation file for CCabItemMenu |
ICON.H, ICON.CPP | IExtractIcon | Implementation file for CCabItemIcon |
ENUM.H, ENUM.CPP | IEnumIDList | Implementation for CEnumCabObjs |
DATAOBJ.H, DATAOBJ.CPP | IDataObject, IEnumFORMATETC | Implementation file for CObjFormats and CCabObj |
File(s) | Description |
DEBUG.H, DEBUG.C | Debugging routines |
XICON.H, XICON.CPP | Implementation file for CIconTemp and CXIcon |
VIEW.H, VIEW.CPP | Implementation file for CCabView |
UNKNOWN.H, UNKNOWN.CPP | Custom CUnknown implementations |
STRINGS.H, STRINGS.C | DBCS-aware string routines |
SFVIEW.H, SFVIEW.CPP | Implementation file for CSFView |
PATH.H, PATH.C | Useful path manipulation routines |
OS.H, OS.CPP | Implementation file for CFileTime |
DLG.H, DLG.CPP | Implementation file for CDlg, CFileDlg and CPropPage |
CABITMS.H, CABITMS.CPP | Implementation file for CMemFile, CCabEnum and CCabExtract |
SFVMENU.CPP | Implementation file for CSFView menu related methods |
IUTIL.C | Implementation of Shell_MergeMenus and some other useful routines |
DA.C | Implementation of dynamic pointer arrays (DPAs) |
FDI.LIB, FDI.H | Header and corresponding library for the File Decompression Interface |
THISGUID.H | Definition of GUID for ThisDll |
PCH.H | Common precompiled header file |
DPDA.H | Definitions of dynamic pointer array routines |
Figure 10 CAB File Viewer Source Excerpts
ThisDll.h
//***********************************************************************
// Generic OLE header file
// Copyright (c) 1994 - 1996 Microsoft Corporation. All rights reserved
//***********************************************************************
.
.
.
class CWaitCursor
{
public:
CWaitCursor() {m_cOld=SetCursor(LoadCursor(NULL, IDC_WAIT));}
~CWaitCursor() {SetCursor(m_cOld);}
private:
HCURSOR m_cOld;
} ;
class CRefCount
{
public:
CRefCount() : m_cRef(0) {};
UINT AddRef() {return(++m_cRef);}
UINT Release() {return(--m_cRef);}
UINT GetRef() {return( m_cRef);}
private:
UINT m_cRef;
} ;
class CThisDll
{
public:
CThisDll() {
m_hInst=NULL;
}
// Make no destructor for global classes (requires CRT stuff)
void SetInstance(HINSTANCE hInst) {m_hInst=hInst;}
HINSTANCE GetInstance() {return(m_hInst);}
CRefCount m_cRef;
CRefCount m_cLock;
private:
HINSTANCE m_hInst;
} ;
.
.
.
ThisDll.cpp
// ******************************************************************
// Generic OLE DLL routines
// Copyright (c) 1994 - 1996 Microsoft Corporation. All rights reserved
// ******************************************************************
.
.
.
// ******************************************************************
// DllMain
STDAPI_(BOOL) APIENTRY DllMain(
HINSTANCE hDll,
DWORD dwReason,
LPVOID lpReserved)
{
switch(dwReason)
{
case DLL_PROCESS_ATTACH:
g_ThisDll.SetInstance(hDll);
// Initialize the various modules.
//
break;
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
default:
break;
} // switch
return(TRUE);
}
// DllCanUnloadNow
STDAPI DllCanUnloadNow()
{
HRESULT retval = (HRESULT)((g_ThisDll.m_cRef.GetRef() == 0)
&& (g_ThisDll.m_cLock.GetRef() == 0) ? S_OK : S_FALSE);
return(retval);
}
.
.
.
class CThisDllClassFactory : public IClassFactory
{
public:
// *** IUnknown methods ***
STDMETHODIMP QueryInterface(REFIID riid,
LPVOID FAR* ppvObj);
STDMETHODIMP_(ULONG) AddRef(void);
STDMETHODIMP_(ULONG) Release(void);
// *** IClassFactory methods ***
STDMETHODIMP CreateInstance(LPUNKNOWN pUnkOuter,
REFIID riid,
LPVOID FAR* ppvObject);
STDMETHODIMP LockServer(BOOL fLock);
private:
CRefDll m_cRefDll;
CRefCount m_cRef;
};
// DllGetClassObject
STDAPI DllGetClassObject(
REFCLSID rclsid,
REFIID riid,
LPVOID FAR* ppvObj)
{
*ppvObj = NULL;
if(! (rclsid == CLSID_ThisDll))
{
return(E_FAIL);
}
CThisDllClassFactory *pcf = new CThisDllClassFactory;
if (!pcf)
{
return(E_OUTOFMEMORY);
}
// Note if the QueryInterface fails, the Release will delete the object
pcf->AddRef();
HRESULT hRes = pcf->QueryInterface(riid, ppvObj);
pcf->Release();
return(hRes);
}
// CImpIClassFactory member functions
// *** IUnknown methods ***
STDMETHODIMP CThisDllClassFactory::QueryInterface(REFIID riid,
LPVOID FAR* ppvObj)
{
*ppvObj = NULL;
// Any interface on this object is the object pointer
if((riid == IID_IUnknown) || (riid == IID_IClassFactory))
{
*ppvObj = (LPVOID)(IClassFactory *)this;
}
if(*ppvObj)
{
((LPUNKNOWN)*ppvObj)->AddRef();
return NOERROR;
}
return(E_NOINTERFACE);
}
STDMETHODIMP_(ULONG) CThisDllClassFactory::AddRef(void)
{
return(m_cRef.AddRef());
}
STDMETHODIMP_(ULONG) CThisDllClassFactory::Release(void)
{
if (!m_cRef.Release())
{
delete this;
return(0);
}
return(m_cRef.GetRef());
}
// *** IClassFactory methods ***
STDMETHODIMP CThisDllClassFactory::CreateInstance(LPUNKNOWN pUnkOuter,
REFIID riid,
LPVOID FAR* ppvObj)
{
// we do not support aggregation
if(pUnkOuter)
{
return(CLASS_E_NOAGGREGATION);
}
return(::CreateInstance(riid, ppvObj));
}
STDMETHODIMP CThisDllClassFactory::LockServer(BOOL fLock)
{
if(fLock)
{
g_ThisDll.m_cLock.AddRef();
}
else
{
g_ThisDll.m_cLock.Release();
}
return(NOERROR);
}
.
.
.
Folder.h
// ******************************************************************
// Definitions of CCabFolder and CCabItemList
// Copyright (c) 1994 - 1996 Microsoft Corporation. All rights reserved
// ******************************************************************
.
.
.
class CCabFolder : public IPersistFolder, public IShellFolder
{
public:
CCabFolder() : m_pidlHere(0), m_lItems(1024/sizeof(LPVOID)) {}
~CCabFolder()
{
if (m_pidlHere)
{
ILFree(m_pidlHere);
}
}
// *** IUnknown methods ***
STDMETHODIMP QueryInterface(
REFIID riid,
LPVOID FAR* ppvObj);
STDMETHODIMP_(ULONG) AddRef(void);
STDMETHODIMP_(ULONG) Release(void);
// *** IParseDisplayName method ***
STDMETHODIMP ParseDisplayName(
HWND hwndOwner,
LPBC pbc,
LPOLESTR lpszDisplayName,
ULONG FAR* pchEaten,
LPITEMIDLIST * ppidl,
ULONG *pdwAttributes);
//
// *** IOleContainer methods ***
//
STDMETHODIMP EnumObjects(
HWND hwndOwner,
DWORD grfFlags,
LPENUMIDLIST * ppenumIDList);
//
// *** IShellFolder methods ***
//
STDMETHODIMP BindToObject(
LPCITEMIDLIST pidl,
LPBC pbc,
REFIID riid,
LPVOID FAR* ppvObj);
STDMETHODIMP BindToStorage(
LPCITEMIDLIST pidl,
LPBC pbc,
REFIID riid,
LPVOID FAR* ppvObj);
STDMETHODIMP CompareIDs(
LPARAM lParam,
LPCITEMIDLIST pidl1,
LPCITEMIDLIST pidl2);
STDMETHODIMP CreateViewObject(
HWND hwndOwner,
REFIID riid,
LPVOID FAR* ppvObj);
STDMETHODIMP GetAttributesOf(
UINT cidl,
LPCITEMIDLIST FAR* apidl,
ULONG FAR* rgfInOut);
STDMETHODIMP GetUIObjectOf(
HWND hwndOwner,
UINT cidl,
LPCITEMIDLIST FAR* apidl,
REFIID riid,
UINT FAR* prgfInOut,
LPVOID FAR* ppvObj);
STDMETHODIMP GetDisplayNameOf(
LPCITEMIDLIST pidl,
DWORD dwReserved,
LPSTRRET lpName);
STDMETHODIMP SetNameOf(
HWND hwndOwner,
LPCITEMIDLIST pidl,
LPCOLESTR lpszName,
DWORD dwReserved,
LPITEMIDLIST FAR* ppidlOut);
//
// *** IPersist methods ***
//
STDMETHODIMP GetClassID(
LPCLSID lpClassID);
//
// *** IPersistFolder methods ***
//
STDMETHODIMP Initialize(
LPCITEMIDLIST pidl);
public:
static LPITEMIDLIST CreateIDList(LPCSTR pszName, DWORD dwFileSize,
UINT uFileDate, UINT uFileTime, UINT uFileAttribs);
static void GetNameOf(LPCABITEM pit, LPSTRRET lpName);
static void GetTypeOf(LPCABITEM pit, LPSTRRET lpName);
BOOL GetPath(LPSTR szPath);
private:
static void CALLBACK EnumToList(LPCSTR pszFile, DWORD dwSize, UINT date,
UINT time, UINT attribs, LPARAM lParam);
HRESULT InitItems();
private:
CRefDll m_cRefDll;
CRefCount m_cRef;
LPITEMIDLIST m_pidlHere; // maintains the current pidl
CCabItemList m_lItems;
friend class CEnumCabObjs;
} ;
.
.
.
folder.cpp
// ******************************************************************
// CAB Files Shell Extension
// Copyright (c) 1994 - 1996 Microsoft Corporation. All rights reserved
// ******************************************************************
.
.
.
// *** IUnknown methods ***
STDMETHODIMP CCabFolder::QueryInterface(
REFIID riid,
LPVOID FAR* ppvObj)
{
*ppvObj = NULL;
LPVOID pObj;
if (riid == IID_IUnknown)
{
pObj = (IUnknown*)((IShellFolder*)this);
// The (IShellFolder*) ^^^ up there is to disambiguate the reference
}
else if (riid == IID_IShellFolder)
{
pObj = (IShellFolder*)this;
}
else if (riid == IID_IPersistFolder)
{
pObj = (IPersistFolder*)this;
}
else
{
return(E_NOINTERFACE);
}
((LPUNKNOWN)pObj)->AddRef();
*ppvObj = pObj;
return(NOERROR);
}
STDMETHODIMP_(ULONG) CCabFolder::AddRef(void)
{
return(m_cRef.AddRef());
}
STDMETHODIMP_(ULONG) CCabFolder::Release(void)
{
if (!m_cRef.Release())
{
delete this;
return(0);
}
return(m_cRef.GetRef());
}
// *** IParseDisplayName method ***
STDMETHODIMP CCabFolder::ParseDisplayName(
HWND hwndOwner,
LPBC pbc,
LPOLESTR lpszDisplayName,
ULONG FAR* pchEaten,
LPITEMIDLIST * ppidl,
ULONG *pdwAttributes)
{
return(E_NOTIMPL);
}
// *** IOleContainer methods ***
//**********************************************************************
// CCabFolder::EnumObjects
// Purpose:
// Creates an item enumeration object
// (an IEnumIDList interface) that can be used to
// enumerate the contents of a folder.
// Parameters:
// HWND hwndOwner - handle to the owner window
// DWORD grFlags - flags about which items to include
// LPENUMIDLIST *ppenumIDList - address that receives IEnumIDList
// interface pointer
//********************************************************************
STDMETHODIMP CCabFolder::EnumObjects(
HWND hwndOwner,
DWORD grfFlags,
LPENUMIDLIST * ppenumIDList) // LPENUMUNKNOWN FAR* ppenumUnknown)
{
CEnumCabObjs *pce = new CEnumCabObjs(this, grfFlags);
if (!pce)
{
return(E_OUTOFMEMORY);
}
pce->AddRef();
HRESULT hRes = pce->QueryInterface(IID_IEnumIDList, (LPVOID*)ppenumIDList);
pce->Release();
return(hRes);
}
// *** IShellFolder methods ***
// subfolders not implemented
STDMETHODIMP CCabFolder::BindToObject(
LPCITEMIDLIST pidl,
LPBC pbc,
REFIID riid,
LPVOID FAR* ppvObj)
{
return(E_NOTIMPL);
}
STDMETHODIMP CCabFolder::BindToStorage(
LPCITEMIDLIST pidl,
LPBC pbc,
REFIID riid,
LPVOID FAR* ppvObj)
{
return(E_NOTIMPL);
}
//**********************************************************************
// CCabFolder::CompareIDs
// Purpose:
// Determines the relative ordering of two file
// objects or folders, given their item identifier lists
// Parameters:
// LPARAM lParam - type of comparison
// LPCITEMIDLIST pidl1 - address to ITEMIDLIST
// LPCITEMIDLIST pidl2 - address to ITEMIDLIST
//********************************************************************
STDMETHODIMP CCabFolder::CompareIDs(
LPARAM lParam,
LPCITEMIDLIST pidl1,
LPCITEMIDLIST pidl2)
{
LPCABITEM pit1 = (LPCABITEM)pidl1;
LPCABITEM pit2 = (LPCABITEM)pidl2;
short nCmp = 0;
switch (lParam)
{
case CV_COL_NAME:
break;
case CV_COL_SIZE:
if (pit1->dwFileSize < pit2->dwFileSize)
{
nCmp = -1;
}
else if (pit1->dwFileSize > pit2->dwFileSize)
{
nCmp = 1;
}
break;
case CV_COL_TYPE:
{
STRRET srName1, srName2;
GetTypeOf(pit1, &srName1);
GetTypeOf(pit2, &srName2);
nCmp = (SHORT)lstrcmp(srName1.cStr, srName2.cStr);
break;
}
case CV_COL_MODIFIED:
FILETIME ft1, ft2;
DosDateTimeToFileTime(pit1->uFileDate, pit1->uFileTime, &ft1);
DosDateTimeToFileTime(pit2->uFileDate, pit2->uFileTime, &ft2);
nCmp = (SHORT)CompareFileTime(&ft1, &ft2);
break;
default:
break;
}
if (nCmp != 0)
{
return(ResultFromShort(nCmp));
}
return(ResultFromShort(lstrcmpi(pit1->szName, pit2->szName)));
}
//**********************************************************************
// CCabFolder::CreateViewObject
// Purpose:
// IShellbrowser calls this to create a ShellView object
// Parameters:
// HWND hwndOwner -
// REFIID riid - interface ID
// LPVOID * ppvObj - pointer to the Shellview object
// Return Value:
// NOERROR
// E_OUTOFMEMORY
// E_NOINTERFACE
// Comments:
// ShellBrowser interface calls this to request the ShellFolder
// to create a ShellView object
//********************************************************************
STDMETHODIMP CCabFolder::CreateViewObject(
HWND hwndOwner,
REFIID riid,
LPVOID FAR* ppvObj)
{
IUnknown *pObj = NULL;
if (riid == IID_IShellView)
{
// Create a call back for the ShellView
IShellFolderViewCallback *pcb;
HRESULT hRes = CabView_CreateCallback(&pcb);
hRes = CreateShellFolderView(this, pcb, (LPSHELLVIEW FAR*)&pObj);
if (pcb)
{
// The ShellFolderView should have AddRef'ed if it needed it.
pcb->Release();
}
if (FAILED(hRes))
{
return(hRes);
}
}
else
{
return(E_NOINTERFACE);
}
if (!pObj)
{
return(E_OUTOFMEMORY);
}
// The ref count is already 1
HRESULT hRes = pObj->QueryInterface(riid, ppvObj);
pObj->Release();
return(NOERROR);
}
// ***************************************************************************
// CCabFolder::GetAttributesOf
// Purpose: Retrieves attributes of one of more file objects
// Parameters:
// UINT cidl - number of file objects
// LPCITEMIDLIST *apidl - pointer to array of ITEMIDLIST
// ULONG *rgfInOut - array of values that specify file object
// attributes
// Return Value:
// NOERROR
//********************************************************************
STDMETHODIMP CCabFolder::GetAttributesOf(
UINT cidl,
LPCITEMIDLIST FAR* apidl,
ULONG FAR* rgfInOut)
{
*rgfInOut &= SFGAO_CANCOPY;
return(NOERROR);
}
//********************************************************************
// CCabFolder::GetUIObjectOf
// Purpose: Returns an interface that can be used to carry out actions on
// the specified file objects or folders
// Parameters:
// HWND hwndOwner - handle of the Owner window
// UINT cidl - Number of file objects
// LPCITEMIDLIST *apidl - array of file object pidls
// REFIID - Identifier of interface to return
// UINT * prgfInOut - reserved
// LPVOID *ppvObj - address that receives interface pointer
// Return Value:
// E_INVALIDARG
// E_NOINTERFACE
// E_OUTOFMEMORY
// **********************************************************************
STDMETHODIMP CCabFolder::GetUIObjectOf(
HWND hwndOwner,
UINT cidl,
LPCITEMIDLIST FAR* apidl,
REFIID riid,
UINT FAR* prgfInOut,
LPVOID FAR* ppvObj)
{
LPUNKNOWN pObj = NULL;
if (riid == IID_IExtractIcon)
{
if (cidl != 1)
{
return(E_INVALIDARG);
}
LPCABITEM pci = (LPCABITEM)*apidl;
pObj = (LPUNKNOWN)(IExtractIcon *)(new CCabItemIcon(pci->szName));
}
else if (riid == IID_IContextMenu)
{
if (cidl < 1)
{
return(E_INVALIDARG);
}
pObj = (LPUNKNOWN)(IContextMenu *)(new CCabItemMenu(hwndOwner, this,
(LPCABITEM *)apidl, cidl));
}
else if (riid == IID_IDataObject)
{
if (cidl < 1)
{
return(E_INVALIDARG);
}
pObj = (LPUNKNOWN)(IDataObject *)(new CCabObj(hwndOwner, this,
(LPCABITEM *)apidl, cidl));
}
else
{
return(E_NOINTERFACE);
}
if (!pObj)
{
return(E_OUTOFMEMORY);
}
pObj->AddRef();
HRESULT hRes = pObj->QueryInterface(riid, ppvObj);
pObj->Release();
return(hRes);
}
// **********************************************************************
// CCabFolder::GetDisplayNameOf
// Purpose: Retrieves the display name for the specified file object or
// subfolder.
// Parameters:
// LPCITEMIDLIST pidl - pidl of the file object
// DWORD dwReserved - Value of the type of display name to
// return
// LPSTRRET lpName - address holding the name returned
// **********************************************************************
STDMETHODIMP CCabFolder::GetDisplayNameOf(
LPCITEMIDLIST pidl,
DWORD dwReserved,
LPSTRRET lpName)
{
LPCABITEM pit = (LPCABITEM)pidl;
GetNameOf(pit, lpName);
return(NOERROR);
}
STDMETHODIMP CCabFolder::SetNameOf(
HWND hwndOwner,
LPCITEMIDLIST pidl,
LPCOLESTR lpszName,
DWORD dwReserved,
LPITEMIDLIST FAR* ppidlOut)
{
return(E_NOTIMPL);
}
// *** IPersist methods ***
//**********************************************************************
// CCabFolder::GetClassID
// Purpose: Return the class id
// Parameters:
// LPCLSID lpClassID - pointer to the ClassID member
// Return Value:
// NOERROR
// Comments:
// This routine returns the Class ID for the DLL
//********************************************************************
STDMETHODIMP CCabFolder::GetClassID(
LPCLSID lpClassID)
{
*lpClassID = CLSID_ThisDll;
return NOERROR;
}
// *** IPersistFolder methods ***
//**********************************************************************
// CCabFolder::Initialize folder
// Purpose: Explorer calls this while initializing the ShellFolder
// object
// Parameters:
// LPCITEMIDLIST pidl - pidl passed by IShellBrowser
// Return Value:
// S_OK
// Comments:
// This routine is called by Explorer during initialization
//**********************************************************************
STDMETHODIMP CCabFolder::Initialize(
LPCITEMIDLIST pidl)
{
if (m_pidlHere)
{
ILFree(m_pidlHere);
}
// Clone the pidl passed by the explorer
m_pidlHere = ILClone(pidl);
if (!m_pidlHere)
{
return(E_OUTOFMEMORY);
}
return(S_OK);
}
// **********************************************************************
// CCabFolder::CreateIDList
// Purpose: Creates an item identifier list for the objects in the namespace
// **********************************************************************
LPITEMIDLIST CCabFolder::CreateIDList(LPCSTR pszName, DWORD dwFileSize,
UINT uFileDate, UINT uFileTime, UINT uFileAttribs)
{
// We'll assume no name is longer than MAX_PATH
// Note the terminating NULL is already in the sizeof(CABITEM)
BYTE bBuf[sizeof(CABITEM) + MAX_PATH + sizeof(WORD)];
LPCABITEM pci = (LPCABITEM)bBuf;
UINT uNameLen = lstrlen(pszName);
if (uNameLen >= MAX_PATH)
{
uNameLen = MAX_PATH;
}
pci->wSize = (WORD)(sizeof(CABITEM) + uNameLen);
pci->dwFileSize = dwFileSize;
pci->uFileDate = (USHORT)uFileDate;
pci->uFileTime = (USHORT)uFileTime;
pci->uFileAttribs = (USHORT)uFileAttribs;
lstrcpyn(pci->szName, pszName, uNameLen+1);
// Terminate the IDList
*(WORD *)(((LPSTR)pci)+pci->wSize) = 0;
return(ILClone((LPCITEMIDLIST)pci));
}
// **********************************************************************
// CCabFolder::GetPath
// Purpose: Get the Path for the current pidl
// Parameters:
// LPSTR szPath - return pointer for path string
// **********************************************************************
BOOL CCabFolder::GetPath(LPSTR szPath)
{
if (!m_pidlHere || !SHGetPathFromIDList(m_pidlHere, szPath))
{
*szPath = '\0';
return(FALSE);
}
return(TRUE);
}
void CCabFolder::GetNameOf(LPCABITEM pit, LPSTRRET lpName)
{
lpName->uType = STRRET_OFFSET;
lpName->uOffset = FIELDOFFSET(CABITEM, szName);
SHFILEINFO sfi;
if (SHGetFileInfo(pit->szName, 0, &sfi, sizeof(sfi),
SHGFI_USEFILEATTRIBUTES | SHGFI_DISPLAYNAME)
&& lstrcmp(sfi.szDisplayName, pit->szName) != 0)
{
lpName->uType = STRRET_CSTR;
lstrcpy(lpName->cStr, sfi.szDisplayName);
}
}
void CCabFolder::GetTypeOf(LPCABITEM pit, LPSTRRET lpName)
{
lpName->uType = STRRET_CSTR;
lpName->cStr[0] = '\0';
SHFILEINFO sfi;
if (SHGetFileInfo(pit->szName, 0, &sfi, sizeof(sfi),
SHGFI_USEFILEATTRIBUTES | SHGFI_TYPENAME))
{
lstrcpy(lpName->cStr, sfi.szTypeName);
}
}
// **********************************************************************
// CCabFolder::EnumToList
// Purpose: This notify callback is called by the FDI routines. It adds the
// file object from the cab file to the list.
// **********************************************************************
void CALLBACK CCabFolder::EnumToList(LPCSTR pszFile, DWORD dwSize, UINT date,
UINT time, UINT attribs, LPARAM lParam)
{
CCabFolder *pThis = (CCabFolder *)lParam;
pThis->m_lItems.AddItem(pszFile, dwSize, date, time, attribs);
}
HRESULT CCabFolder::InitItems()
{
switch (m_lItems.GetState())
{
case CCabItemList::State_Init:
return(NOERROR);
case CCabItemList::State_OutOfMem:
return(E_OUTOFMEMORY);
case CCabItemList::State_UnInit:
default:
break;
}
// Force the list to initialize
m_lItems.InitList();
char szHere[MAX_PATH];
// the m_pidl has been set to current dir
// get the path to the current directory
if (!GetPath(szHere))
{
return(E_UNEXPECTED);
}
CCabItems ciHere(szHere);
if (!ciHere.EnumItems(EnumToList, (LPARAM)this))
{
return(E_UNEXPECTED);
}
return(NOERROR);
}
// **********************************************************************
// CreateInstance
// Purpose: Create a CCabFolder object and returns it
// Parameters:
// REFIID riid - a reference to the interface that is
// being queried
// LPVOID *ppvObj - an out parameter to return a pointer to
// interface being queried
// **********************************************************************
HRESULT CreateInstance(REFIID riid, LPVOID *ppvObj)
{ IUnknown *pObj = NULL;
*ppvObj = NULL;
if(riid == IID_IPersistFolder)
{
pObj = (IUnknown *)(IPersistFolder *)(new CCabFolder);
}
else if(riid == IID_IShellFolder)
{
pObj = (IUnknown *)(IShellFolder *)(new CCabFolder);
}
else
{
return(E_NOINTERFACE);
}
if (!pObj)
{
return(E_OUTOFMEMORY);
}
pObj->AddRef();
HRESULT hRes = pObj->QueryInterface(riid, ppvObj);
pObj->Release();
return(hRes);
}
.
.
.
Enum.h
// **********************************************************************
//
// Definition of CEnumCabObjs
//
// Copyright (c) 1994 - 1996 Microsoft Corporation. All rights reserved
//
// **********************************************************************
.
.
.
// Enumeration object for the CabFolder
class CEnumCabObjs : public IEnumIDList
{
public:
CEnumCabObjs(CCabFolder *pcf, DWORD uFlags) : m_iCount(0)
{
m_uFlags = uFlags;
m_pcfThis=pcf;
pcf->AddRef();
}
~CEnumCabObjs()
{
m_pcfThis->Release();
}
// *** IUnknown methods ***
STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppvObj);
STDMETHODIMP_(ULONG) AddRef();
STDMETHODIMP_(ULONG) Release();
// *** IEnumIDList methods ***
STDMETHODIMP Next(ULONG celt,
LPITEMIDLIST *rgelt,
ULONG *pceltFetched);
STDMETHODIMP Skip(ULONG celt);
STDMETHODIMP Reset();
STDMETHODIMP Clone(IEnumIDList **ppenum);
private:
CRefDll m_cRefDll;
CRefCount m_cRef;
CCabFolder *m_pcfThis;
UINT m_iCount;
DWORD m_uFlags;
} ;
.
.
.
Enum.cpp
// **********************************************************************
// Implementation for CEnumCabObjs
// Copyright (c) 1994 - 1996 Microsoft Corporation. All rights reserved
// **********************************************************************
.
.
.
// *** IUnknown methods ***
STDMETHODIMP CEnumCabObjs::QueryInterface(
REFIID riid,
LPVOID FAR* ppvObj)
{
*ppvObj = NULL;
LPUNKNOWN pObj;
if (riid == IID_IUnknown)
{
pObj = (IUnknown*)((IEnumIDList*)this);
}
else if (riid == IID_IEnumIDList)
{
pObj = (IUnknown*)((IEnumIDList*)this);
}
else
{
return(E_NOINTERFACE);
}
pObj->AddRef();
*ppvObj = pObj;
return(NOERROR);
}
STDMETHODIMP_(ULONG) CEnumCabObjs::AddRef(void)
{
return(m_cRef.AddRef());
}
STDMETHODIMP_(ULONG) CEnumCabObjs::Release(void)
{
if (!m_cRef.Release())
{
delete this;
return(0);
}
return(m_cRef.GetRef());
}
// *** IEnumIDList methods ***
STDMETHODIMP CEnumCabObjs::Next(ULONG celt,
LPITEMIDLIST *rgelt,
ULONG *pceltFetched)
{
*rgelt = NULL;
if (pceltFetched)
{
*pceltFetched = 0;
}
HRESULT hRes = m_pcfThis->InitItems();
if (FAILED(hRes))
{
return(hRes);
}
for ( ; ; ++m_iCount)
{
if (m_iCount >= m_pcfThis->m_lItems.GetCount())
{
return(S_FALSE);
}
LPCABITEM pit = m_pcfThis->m_lItems[m_iCount];
if ((m_uFlags&(SHCONTF_FOLDERS|SHCONTF_NONFOLDERS))
!= (SHCONTF_FOLDERS|SHCONTF_NONFOLDERS))
{
DWORD gfInOut = SFGAO_FOLDER;
if (FAILED(m_pcfThis->GetAttributesOf(1, (LPCITEMIDLIST *)&pit,
&gfInOut)))
{
continue;
}
if (!(m_uFlags&SHCONTF_FOLDERS) && (gfInOut&SFGAO_FOLDER))
{
continue;
}
if ((m_uFlags&SHCONTF_FOLDERS) && !(gfInOut&SFGAO_FOLDER))
{
continue;
}
}
if (!(m_uFlags&SHCONTF_INCLUDEHIDDEN)
&& (pit->uFileAttribs&
(FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)))
{
continue;
}
break;
}
*rgelt = ILClone((LPCITEMIDLIST)m_pcfThis->m_lItems[m_iCount]);
++m_iCount;
if (*rgelt)
{
if (pceltFetched)
{
*pceltFetched = 1;
}
return(S_OK);
}
return(E_OUTOFMEMORY);
}
STDMETHODIMP CEnumCabObjs::Skip(ULONG celt)
{
return(E_NOTIMPL);
}
STDMETHODIMP CEnumCabObjs::Reset()
{
m_iCount = 0;
return(NOERROR);
}
STDMETHODIMP CEnumCabObjs::Clone(IEnumIDList **ppenum)
{
return(E_NOTIMPL);
}
.
.
.
SFWnd.h
//**********************************************************************
// Definitions of CListView, CSFViewDlg, CAccelerator, CSFView
// Copyright (c) 1994 - 1996 Microsoft Corporation. All rights reserved
//**********************************************************************
.
.
.
#define IDC_ARRANGE_BY (FCIDM_SHVIEWFIRST + 0x100)
.
.
.
#define SFV_CONTEXT_FIRST (FCIDM_SHVIEWFIRST + 0x1000)
#define SFV_CONTEXT_LAST (FCIDM_SHVIEWFIRST + 0x2000)
BOOL StrRetToStr(LPSTR szOut, UINT uszOut, LPSTRRET pStrRet, LPCITEMIDLIST pidl);
class CListView
{
public:
CListView() {}
~CListView() {}
operator HWND() const {return(m_hwndList);}
void Init(HWND hwndList, HWND hwndLB, UINT idiDef)
{
m_hwndList = hwndList;
m_cxi.Init(hwndLB, idiDef);
ListView_SetImageList(hwndList, m_cxi.GetIML(TRUE), LVSIL_NORMAL);
ListView_SetImageList(hwndList, m_cxi.GetIML(FALSE), LVSIL_SMALL);
}
int InsertItem(LV_ITEM *pItem)
{
return(ListView_InsertItem(m_hwndList, pItem));
}
void DeleteAllItems() {ListView_DeleteAllItems(m_hwndList);}
enum
{
AI_LARGE = CXIcon::AI_LARGE,
AI_SMALL = CXIcon::AI_SMALL,
} ;
int GetIcon(IShellFolder *psf, LPCITEMIDLIST pidl)
{
return(m_cxi.GetIcon(psf, pidl));
}
private:
HWND m_hwndList;
CXIcon m_cxi;
} ;
.
.
.
// CSFView - IShellView implementation
class CSFView : public CUnknown, public IShellView
{
public:
CSFView(LPSHELLFOLDER psf, IShellFolderViewCallback *psfvcb);
virtual ~CSFView();
STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppvObj);
STDMETHODIMP_(ULONG) AddRef();
STDMETHODIMP_(ULONG) Release();
// *** IOleWindow methods ***
STDMETHODIMP GetWindow(HWND * lphwnd);
STDMETHODIMP ContextSensitiveHelp(BOOL fEnterMode);
// *** IShellView methods ***
STDMETHODIMP TranslateAccelerator(LPMSG lpmsg);
STDMETHODIMP EnableModeless(BOOL fEnable);
STDMETHODIMP UIActivate(UINT uState);
STDMETHODIMP Refresh();
STDMETHODIMP CreateViewWindow(IShellView *lpPrevView,
LPCFOLDERSETTINGS lpfs, IShellBrowser * psb,
RECT * prcView, HWND *phWnd);
STDMETHODIMP DestroyViewWindow();
STDMETHODIMP GetCurrentInfo(LPFOLDERSETTINGS lpfs);
STDMETHODIMP AddPropertySheetPages(DWORD dwReserved,
LPFNADDPROPSHEETPAGE lpfn,
LPARAM lparam);
STDMETHODIMP SaveViewState();
STDMETHODIMP SelectItem(LPCITEMIDLIST pidlItem, UINT uFlags);
STDMETHODIMP GetItemObject(UINT uItem, REFIID riid, LPVOID *ppv);
private:
static int CALLBACK CSFView::CompareIDs(LPVOID p1, LPVOID p2,
LPARAM lParam);
void AddColumns();
BOOL SaveColumns(LPSTREAM pstm);
void RestoreColumns(LPSTREAM pstm, int nCols);
void RestoreViewState();
void ColumnClick(int iCol)
{
m_sfState.lParamSort = (LPARAM)DPA_GetPtr(m_aParamSort, iCol);
m_cView.SortItems(CompareIDs);
}
HRESULT CallCB(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
return(m_psfvcb ? m_psfvcb->Message(uMsg, wParam,
lParam) : E_NOTIMPL);
}
int GetMenuIDFromViewMode();
BOOL IsInCommDlg() {return(m_pCDB != NULL);}
HRESULT IncludeObject(LPCITEMIDLIST pidl)
{
return(IsInCommDlg() ? m_pCDB->IncludeObject(this, pidl) : S_OK);
}
HRESULT OnDefaultCommand()
{
return(IsInCommDlg() ? m_pCDB->OnDefaultCommand(this) : S_FALSE);
}
HRESULT OnStateChange(UINT uFlags)
{
return(IsInCommDlg() ? m_pCDB->OnStateChange(this, uFlags) : S_FALSE);
}
void InitFileMenu(HMENU hmInit);
void InitEditMenu(HMENU hmInit);
void InitViewMenu(HMENU hmInit);
int AddObject(LPCITEMIDLIST pidl);
HRESULT FillList(BOOL bInteractive);
BOOL ShowAllObjects() {return(TRUE);}
void MergeArrangeMenu(HMENU hmView);
void MergeViewMenu(HMENU hmenu, HMENU hmMerge);
BOOL OnActivate(UINT uState);
BOOL OnDeactivate();
IContextMenu * GetSelContextMenu();
void ReleaseSelContextMenu();
BOOL OnInitMenuPopup(HMENU hmInit, int nIndex, BOOL fSystemMenu);
void OnCommand(IContextMenu *pcm, WPARAM wParam, LPARAM lParam);
void CheckToolbar();
void MergeToolBar();
BOOL GetArrangeText(int iCol, UINT idFmt, LPSTR pszText, UINT cText);
void GetCommandHelpText(UINT id, LPSTR pszText, UINT cchText, BOOL bToolTip);
LRESULT OnMenuSelect(UINT idCmd, UINT uFlags, HMENU hmenu);
LPSHELLFOLDER m_psf; // ShellFolder pointer
ICommDlgBrowser *m_pCDB; // ICommdlgBrowser
IShellFolderViewCallback *m_psfvcb; // pointer to ShellFolderView
// callback
CEnsureRelease m_erFolder;
CEnsureRelease m_erCB;
CSFViewDlg m_cView; // ViewDlg which contains the
// listview in the right pane
HWND m_hwndMain;
FOLDERSETTINGS m_fs;
IShellBrowser *m_psb;
SFSTATE m_sfState;
CMenuTemp m_cmCur;
UINT m_uState;
IContextMenu *m_pcmSel;
HDPA m_aParamSort; // maintains a sorted list of
// items in a DPA
CAccelerator m_cAccel;
CSafeMalloc m_cMalloc;
friend class CSFViewDlg;
} ;
.
.
.
Sfview.cpp
// **********************************************************************
// Implementation file for CSFView
// Copyright (c) 1994 - 1996 Microsoft Corporation. All rights reserved
// **********************************************************************
.
.
.
CSFView::CSFView(LPSHELLFOLDER psf, IShellFolderViewCallback *psfvcb) :
m_psf(psf), m_erFolder(psf), m_erCB(psfvcb), m_pCDB(NULL), m_cView(this),
m_uState(SVUIA_DEACTIVATE), m_pcmSel(NULL), m_cAccel(IDA_MAIN)
{
m_psfvcb = psfvcb;
if (psfvcb)
{
psfvcb->AddRef();
}
psf->AddRef();
m_aParamSort = DPA_Create(4);
m_sfState.lParamSort = 0;
}
.
.
.
CSFView::~CSFView()
{
ReleaseSelContextMenu();
}
STDMETHODIMP CSFView::QueryInterface(REFIID riid, LPVOID * ppvObj)
{
static const IID *apiid[] = { &IID_IShellView, NULL };
LPUNKNOWN aobj[] = { (IShellView *)this };
return(QIHelper(riid, ppvObj, apiid, aobj));
}
STDMETHODIMP_(ULONG) CSFView::AddRef()
{
return(AddRefHelper());
}
STDMETHODIMP_(ULONG) CSFView::Release()
{
return(ReleaseHelper());
}
STDMETHODIMP CSFView::GetWindow(HWND * lphwnd)
{
return(E_NOTIMPL);
}
STDMETHODIMP CSFView::ContextSensitiveHelp(BOOL fEnterMode)
{
return(E_NOTIMPL);
}
// **********************************************************************
// CSFView::TranslateAccelerator
// Purpose: Handle the accelerator keystrokes
// Parameters:
// LPMSG lpmsg - message structure
// **********************************************************************
STDMETHODIMP CSFView::TranslateAccelerator(LPMSG lpmsg)
{
return(m_cAccel.TranslateAccelerator(m_cView, lpmsg) ? S_OK : S_FALSE);
}
STDMETHODIMP CSFView::EnableModeless(BOOL fEnable)
{
return(E_NOTIMPL);
}
// **********************************************************************
// CSFView:UIActivate
// Purpose: The explorer calls this member function whenever the activation
// state of the view window is changed by a certain event that is
// NOT caused by the shell view itself.
// Parameters:
// UINT uState - UI activate flag
// **********************************************************************
STDMETHODIMP CSFView::UIActivate(UINT uState)
{
if (uState)
{
OnActivate(uState);
}
else
{
OnDeactivate();
}
return S_OK;
}
STDMETHODIMP CSFView::Refresh()
{
return(E_NOTIMPL);
}
// **********************************************************************
// CSFView::CreateViewWindow
// Purpose: Called by IShellBrowser to create a contents pane window
// Parameters:
// IShellView *lpPrevView - previous view
// LPCFOLDERSETTINGS lpfs - folder settings for the view
// IShellBrowser *psb - pointer to the shell browser
// RECT * prcView - view Rectangle
// HWND * phWnd - pointer to Window handle
// **********************************************************************
STDMETHODIMP CSFView::CreateViewWindow(IShellView *lpPrevView,
LPCFOLDERSETTINGS lpfs,
IShellBrowser * psb, RECT * prcView,
HWND *phWnd)
{
*phWnd = NULL;
if ((HWND)m_cView)
{
return(E_UNEXPECTED);
}
m_fs = *lpfs;
m_psb = psb;
// get the main window handle from shell browser
psb->GetWindow(&m_hwndMain);
// bring up the contents pane
if (!m_cView.DoModeless(IDD_VIEW, m_hwndMain))
{
return(E_OUTOFMEMORY);
}
*phWnd = m_cView;
// map the current view mode into menu id and set the contents pane
// view mode accordingly
OnCommand(NULL, GET_WM_COMMAND_MPS(GetMenuIDFromViewMode(), 0, 0));
AddColumns();
RestoreViewState();
// size the contents pane
SetWindowPos(m_cView, NULL, prcView->left, prcView->top,
prcView->right-prcView->left, prcView->bottom-prcView->top,
SWP_NOZORDER|SWP_SHOWWINDOW);
FillList(TRUE);
return(NOERROR);
}
STDMETHODIMP CSFView::DestroyViewWindow()
{
if (!(HWND)m_cView)
{
return(E_UNEXPECTED);
}
m_cView.DestroyWindow();
return(NOERROR);
}
STDMETHODIMP CSFView::GetCurrentInfo(LPFOLDERSETTINGS lpfs)
{
*lpfs = m_fs;
return(NOERROR);
}
STDMETHODIMP CSFView::AddPropertySheetPages(DWORD dwReserved,
LPFNADDPROPSHEETPAGE lpfn,
LPARAM lparam)
{
return(E_NOTIMPL);
}
STDMETHODIMP CSFView::SaveViewState()
{
SFSTATE_HDR hdr;
LPSTREAM pstm;
HRESULT hres = m_psb->GetViewStateStream(STGM_WRITE, &pstm);
if (FAILED(hres))
{
return(hres);
}
CEnsureRelease erStr(pstm);
pstm->Write(&hdr, sizeof(hdr), NULL);
hdr.clsThis = CLSID_ThisDll;
hdr.sfState = m_sfState;
hdr.nCols = SaveColumns(pstm);
ULARGE_INTEGER libCurPosition;
LARGE_INTEGER dlibMove;
dlibMove.HighPart = 0;
dlibMove.LowPart = 0;
pstm->Seek(dlibMove, STREAM_SEEK_SET, &libCurPosition);
hres = pstm->Write(&hdr, sizeof(hdr), NULL);
return(hres);
}
STDMETHODIMP CSFView::SelectItem(LPCITEMIDLIST pidlItem, UINT uFlags)
{
return(E_NOTIMPL);
}
STDMETHODIMP CSFView::GetItemObject(UINT uItem, REFIID riid,
LPVOID *ppv)
{
return(E_NOTIMPL);
}
int CSFView::AddObject(LPCITEMIDLIST pidl)
{
// Check the commdlg hook to see if we should include this
// object.
if (IncludeObject(pidl) != S_OK)
{
return(-1);
}
return(m_cView.AddObject(pidl));
}
int CALLBACK CSFView::CompareIDs(LPVOID p1, LPVOID p2, LPARAM lParam)
{
PFNDPACOMPARE pfnCheckAPI = CompareIDs;
CSFView *pThis = (CSFView *)lParam;
HRESULT hres = pThis->m_psf->CompareIDs(pThis->m_sfState.lParamSort,
(LPITEMIDLIST)p1, (LPITEMIDLIST)p2);
return (hres);
}
// **********************************************************************
// CSFView::FillList
// Purpose: Enumerates the objects in the namespace and fills up the
// data structures
// **********************************************************************
HRESULT CSFView::FillList(BOOL bInteractive)
{
m_cView.DeleteAllItems();
// Setup the enum flags.
DWORD dwEnumFlags = SHCONTF_NONFOLDERS;
if (ShowAllObjects())
{
dwEnumFlags |= SHCONTF_INCLUDEHIDDEN ;
}
if (!(m_fs.fFlags & FWF_NOSUBFOLDERS))
{
dwEnumFlags |= SHCONTF_FOLDERS;
}
// Create an enum object and get the IEnumIDList ptr
LPENUMIDLIST peIDL;
HRESULT hres = m_psf->EnumObjects(bInteractive ? m_hwndMain : NULL,
dwEnumFlags, &peIDL);
// Note the return may be S_FALSE which indicates no enumerator.
// That's why we shouldn't use if (FAILED(hres))
if (hres != S_OK)
{
if (hres == S_FALSE)
{
return(NOERROR);
}
return(hres);
}
CEnsureRelease erEnum(peIDL);
HDPA hdpaNew = DPA_Create(16);
if (!hdpaNew)
{
return(E_OUTOFMEMORY);
}
LPITEMIDLIST pidl;
ULONG celt;
// Enumerate the idlist and insert into the DPA
while (peIDL->Next(1, &pidl, &celt) == S_OK)
{
if (DPA_InsertPtr(hdpaNew, 0x7fff, pidl) == -1)
{
m_cMalloc.Free(pidl);
}
}
DPA_Sort(hdpaNew, CompareIDs, (LPARAM)this);
int cNew = DPA_GetPtrCount(hdpaNew);
for (int i=0; i<cNew; ++i)
{
LPITEMIDLIST pidl = (LPITEMIDLIST)DPA_GetPtr(hdpaNew, i);
if (AddObject(pidl) < 0)
{
m_cMalloc.Free(pidl);
}
}
return(NOERROR);
}
// **********************************************************************
// CSFView::AddColumns
// Purpose: Adds columns to the contents pane listview
// **********************************************************************
void CSFView::AddColumns()
{
UINT cxChar = m_cView.CharWidth();
// add columns to the listview in the contents pane
for (int i=0; ; ++i)
{
SFVCB_GETDETAILSOF_DATA gdo;
gdo.pidl = NULL;
// get the first column
HRESULT hres = CallCB(SFVCB_GETDETAILSOF, i, (LPARAM)&gdo);
if (hres != S_OK)
{
if (i != 0)
{
break;
}
// If there is no first column, fake one up
gdo.fmt = LVCFMT_LEFT;
gdo.cChar = 40;
gdo.lParamSort = 0;
gdo.str.uType = STRRET_CSTR;
LoadString(g_ThisDll.GetInstance(), IDS_NAME, gdo.str.cStr,
sizeof(gdo.str.cStr));
}
char szText[MAX_PATH];
// init the column info for the details view ...
LV_COLUMN col;
col.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
col.fmt = gdo.fmt;
col.cx = gdo.cChar * cxChar;
col.pszText = szText;
col.cchTextMax = sizeof(szText);
col.iSubItem = i;
StrRetToStr(szText, sizeof(szText), &gdo.str, NULL);
// insert the column into the list view
if (m_cView.InsertColumn(i, &col)>=0 && m_aParamSort)
{
DPA_InsertPtr(m_aParamSort, 0x7fff, (LPVOID)gdo.lParamSort);
}
if (hres != S_OK)
{
break;
}
}
}
// Save (and check) column header information
// Returns TRUE if the columns are the default width, FALSE otherwise
// Side effect: the stream pointer is left right after the last column
BOOL CSFView::SaveColumns(LPSTREAM pstm)
{
UINT cxChar = m_cView.CharWidth();
BOOL bDefaultCols = TRUE;
for (int i=0; ; ++i)
{
SFVCB_GETDETAILSOF_DATA gdo;
gdo.pidl = NULL;
if (CallCB(SFVCB_GETDETAILSOF, i, (LPARAM)&gdo) != S_OK)
{
break;
}
LV_COLUMN col;
col.mask = LVCF_WIDTH;
if (!m_cView.GetColumn(i, &col))
{
// There is some problem, so just assume
// default column widths
bDefaultCols = TRUE;
break;
}
if (col.cx != (int)(gdo.cChar * cxChar))
{
bDefaultCols = FALSE;
}
// HACK: I don't really care about column widths larger
// than 64K
if (FAILED(pstm->Write(&col.cx, sizeof(USHORT), NULL)))
{
// There is some problem, so just assume
// default column widths
bDefaultCols = TRUE;
break;
}
}
return(bDefaultCols ? 0 : i);
}
void CSFView::RestoreColumns(LPSTREAM pstm, int nCols)
{
for (int i=0; i<nCols; ++i)
{
LV_COLUMN col;
col.mask = LVCF_WIDTH;
if (FAILED(pstm->Read(&col.cx, sizeof(USHORT), NULL)))
{
break;
}
m_cView.SetColumn(i, &col);
}
}
void CSFView::RestoreViewState()
{
SFSTATE_HDR hdr;
LPSTREAM pstm;
// get the stream for storing view specific info
if (FAILED(m_psb->GetViewStateStream(STGM_READ, &pstm)))
{
return;
}
CEnsureRelease erStr(pstm);
if (FAILED(pstm->Read(&hdr, sizeof(hdr), NULL)))
{
return;
}
// Validate the header
if (hdr.clsThis != CLSID_ThisDll)
{
return;
}
m_sfState = hdr.sfState;
RestoreColumns(pstm, hdr.nCols);
MergeToolBar();
}
void CSFView::CheckToolbar()
{
UINT idCmdCurView = GetMenuIDFromViewMode();
for (UINT idCmd=IDC_VIEW_ICON; idCmd<=IDC_VIEW_DETAILS; ++idCmd)
{
m_psb->SendControlMsg(FCW_TOOLBAR, TB_CHECKBUTTON, idCmd,
(LPARAM)(idCmd == idCmdCurView), NULL);
}
}
void CSFView::MergeToolBar()
{
enum
{
IN_STD_BMP = 0x4000,
IN_VIEW_BMP = 0x8000,
} ;
static const TBBUTTON c_tbDefault[] =
{
{ STD_COPY | IN_STD_BMP, IDC_EDIT_COPY, TBSTATE_ENABLED,
TBSTYLE_BUTTON, {0,0}, 0, -1},
{ 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, {0,0}, 0, -1 },
// the bitmap indexes here are relative to the view bitmap
{ VIEW_LARGEICONS | IN_VIEW_BMP, IDC_VIEW_ICON,
TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0L, -1 },
{ VIEW_SMALLICONS | IN_VIEW_BMP, IDC_VIEW_SMALLICON,
TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0L, -1 },
{ VIEW_LIST | IN_VIEW_BMP, IDC_VIEW_LIST, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0L, -1 },
{ VIEW_DETAILS | IN_VIEW_BMP, IDC_VIEW_DETAILS, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0L, -1 },
} ;
LRESULT iStdBMOffset;
LRESULT iViewBMOffset;
TBADDBITMAP ab;
ab.hInst = HINST_COMMCTRL; // hinstCommctrl
ab.nID = IDB_STD_SMALL_COLOR; // std bitmaps
m_psb->SendControlMsg(FCW_TOOLBAR, TB_ADDBITMAP, 8, (LPARAM)&ab, &iStdBMOffset);
ab.nID = IDB_VIEW_SMALL_COLOR; // std view bitmaps
m_psb->SendControlMsg(FCW_TOOLBAR, TB_ADDBITMAP, 8, (LPARAM)&ab, &iViewBMOffset);
TBBUTTON tbActual[ARRAYSIZE(c_tbDefault)];
for (int i=0; i<ARRAYSIZE(c_tbDefault); ++i)
{
tbActual[i] = c_tbDefault[i];
if (!(tbActual[i].fsStyle & TBSTYLE_SEP))
{
if (tbActual[i].iBitmap & IN_VIEW_BMP)
{
tbActual[i].iBitmap = (tbActual[i].iBitmap & ~IN_VIEW_BMP) + iViewBMOffset;
}
else if (tbActual[i].iBitmap & IN_STD_BMP)
{
tbActual[i].iBitmap = (tbActual[i].iBitmap & ~IN_STD_BMP) + iStdBMOffset;
}
}
}
m_psb->SetToolbarItems(tbActual, ARRAYSIZE(c_tbDefault), FCT_MERGE);
CheckToolbar();
}
HRESULT CreateShellFolderView(LPSHELLFOLDER psf,
IShellFolderViewCallback *psfvcb,
LPSHELLVIEW * ppsv)
{
CSFView *pSFView = new CSFView(psf, psfvcb);
if (!pSFView)
{
return(E_OUTOFMEMORY);
}
pSFView->AddRef();
HRESULT hRes = pSFView->QueryInterface(IID_IShellView, (LPVOID *)ppsv);
pSFView->Release();
return(hRes);
}
.
.
.