SHLVIEW.CPP

/************************************************************************** 
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.

Copyright 1997 Microsoft Corporation. All Rights Reserved.
**************************************************************************/

/**************************************************************************

File: ShlView.cpp

Description: Implements IShellView.

**************************************************************************/

/**************************************************************************
#include statements
**************************************************************************/

#include "ShlView.h"
#include "Guid.h"
#include "resource.h"
#include "tools.h"

#define TOOLBAR_ID (L"RegView")

MYTOOLINFO g_Tools[] =
{
IDM_VIEW_KEYS, 0, IDS_TB_VIEW_KEYS, IDS_MI_VIEW_KEYS, 0, TBSTATE_ENABLED, TBSTYLE_BUTTON,
IDM_VIEW_IDW, 0, IDS_TB_VIEW_IDW, IDS_MI_VIEW_IDW, 0, TBSTATE_ENABLED, TBSTYLE_BUTTON,
-1, 0, 0, 0, 0,
};

/**************************************************************************

CShellView::CShellView()

**************************************************************************/

CShellView::CShellView(CShellFolder *pFolder, LPCITEMIDLIST pidl)
{
#ifdef INITCOMMONCONTROLSEX

INITCOMMONCONTROLSEX iccex;
iccex.dwSize = sizeof(INITCOMMONCONTROLSEX);
iccex.dwICC = ICC_LISTVIEW_CLASSES;
InitCommonControlsEx(&iccex);

#else

InitCommonControls();

#endif //INITCOMMONCONTROLSEX

m_hMenu = NULL;
m_pDockingWindow = NULL;

m_pPidlMgr = new CPidlMgr();
if(!m_pPidlMgr)
{
delete this;
return;
}

m_pSFParent = pFolder;
if(m_pSFParent)
m_pSFParent->AddRef();

//get the shell's IMalloc pointer
//we'll keep this until we get destroyed
if(FAILED(SHGetMalloc(&m_pMalloc)))
{
delete this;
return;
}

m_pidl = m_pPidlMgr->Copy(pidl);

m_uState = SVUIA_DEACTIVATE;

m_ObjRefCount = 1;
g_DllRefCount++;
}

/**************************************************************************

CShellView::~CShellView()

**************************************************************************/

CShellView::~CShellView()
{
if(m_pidl)
{
m_pPidlMgr->Delete(m_pidl);
m_pidl = NULL;
}

if(m_pSFParent)
m_pSFParent->Release();

if(m_pMalloc)
{
m_pMalloc->Release();
}

if(m_pPidlMgr)
{
delete m_pPidlMgr;
}

g_DllRefCount--;
}

///////////////////////////////////////////////////////////////////////////
//
// IUnknown Implementation
//

/**************************************************************************

CShellView::QueryInterface

**************************************************************************/

STDMETHODIMP CShellView::QueryInterface(REFIID riid, LPVOID *ppReturn)
{
*ppReturn = NULL;

//IUnknown
if(IsEqualIID(riid, IID_IUnknown))
{
*ppReturn = this;
}

//IOleWindow
else if(IsEqualIID(riid, IID_IOleWindow))
{
*ppReturn = (IOleWindow*)this;
}

//IShellView
else if(IsEqualIID(riid, IID_IShellView))
{
*ppReturn = (IShellView*)this;
}

//IOleCommandTarget
else if(IsEqualIID(riid, IID_IOleCommandTarget))
{
*ppReturn = (IOleCommandTarget*)this;
}

if(*ppReturn)
{
(*(LPUNKNOWN*)ppReturn)->AddRef();
return S_OK;
}

return E_NOINTERFACE;
}

/**************************************************************************

CShellView::AddRef

**************************************************************************/

STDMETHODIMP_(DWORD) CShellView::AddRef()
{
return ++m_ObjRefCount;
}


/**************************************************************************

CShellView::Release

**************************************************************************/

STDMETHODIMP_(DWORD) CShellView::Release()
{
if(--m_ObjRefCount == 0)
{
delete this;
return 0;
}

return m_ObjRefCount;
}

///////////////////////////////////////////////////////////////////////////
//
// IOleWindow Implementation
//

/**************************************************************************

CShellView::GetWindow()

**************************************************************************/

STDMETHODIMP CShellView::GetWindow(HWND *phWnd)
{
*phWnd = m_hWnd;

return S_OK;
}

/**************************************************************************

CShellView::ContextSensitiveHelp()

**************************************************************************/

STDMETHODIMP CShellView::ContextSensitiveHelp(BOOL fEnterMode)
{
return E_NOTIMPL;
}

///////////////////////////////////////////////////////////////////////////
//
// IOleCommandTarget Implementation
//

/**************************************************************************

CShellView::QueryStatus()

**************************************************************************/

STDMETHODIMP CShellView::QueryStatus( const GUID *pguidCmdGroup,
ULONG cCmds,
OLECMD prgCmds[],
OLECMDTEXT *pCmdText)
{
ULONG i;

//only process the commands for our command group
if(pguidCmdGroup && (*pguidCmdGroup != CLSID_CmdGrp))
return OLECMDERR_E_UNKNOWNGROUP;

//make sure prgCmds is not NULL
if(!prgCmds)
return E_POINTER;

//run through all of the commands and supply the correct information
for(i = 0; i < cCmds;i++)
{
switch(prgCmds[i].cmdID)
{
case IDM_VIEW_KEYS:
prgCmds[i].cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED;
break;
}
}

return S_OK;
}

/**************************************************************************

CShellView::Exec()

**************************************************************************/

STDMETHODIMP CShellView::Exec( const GUID *pguidCmdGroup,
DWORD nCmdID,
DWORD nCmdExecOpt,
VARIANTARG *pvaIn,
VARIANTARG *pvaOut)
{
//only process the commands for our command group
if(pguidCmdGroup && (*pguidCmdGroup == CLSID_CmdGrp))
{
OnCommand(nCmdID, 0, NULL);
return S_OK;
}

return OLECMDERR_E_UNKNOWNGROUP;
}

///////////////////////////////////////////////////////////////////////////
//
// IShellView Implementation
//

/**************************************************************************

CShellView::TranslateAccelerator()

**************************************************************************/

STDMETHODIMP CShellView::TranslateAccelerator(LPMSG pMsg)
{
return E_NOTIMPL;
}

/**************************************************************************

CShellView::EnableModeless()

**************************************************************************/

STDMETHODIMP CShellView::EnableModeless(BOOL fEnable)
{
return E_NOTIMPL;
}

/**************************************************************************

CShellView::OnActivate()

**************************************************************************/

LRESULT CShellView::OnActivate(UINT uState)
{
//don't do anything if the state isn't really changing
if(m_uState == uState)
return S_OK;

OnDeactivate();

//only do this if we are active
if(uState != SVUIA_DEACTIVATE)
{
//merge the menus
m_hMenu = CreateMenu();

if(m_hMenu)
{
OLEMENUGROUPWIDTHS omw = {0, 0, 0, 0, 0, 0};
MENUITEMINFO mii;
TCHAR szText[MAX_PATH];

m_pShellBrowser->InsertMenusSB(m_hMenu, &omw);

//build the top level menu
//get the menu item's text
LoadString(g_hInst, IDS_MI_REGISTRY, szText, sizeof(szText));

ZeroMemory(&mii, sizeof(mii));
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_SUBMENU | MIIM_TYPE | MIIM_STATE;
mii.fType = MFT_STRING;
mii.fState = MFS_ENABLED;
mii.dwTypeData = szText;
mii.hSubMenu = BuildRegistryMenu();

//insert our menu into the menu bar
if(mii.hSubMenu)
{
InsertMenuItem(m_hMenu, FCIDM_MENU_HELP, FALSE, &mii);
}

//get the view menu so we can merge with it
ZeroMemory(&mii, sizeof(mii));
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_SUBMENU;

if(GetMenuItemInfo(m_hMenu, FCIDM_MENU_VIEW, FALSE, &mii))
{
MergeViewMenu(mii.hSubMenu);
}

//add the items that should only be added if we have the focus
if(SVUIA_ACTIVATE_FOCUS == uState)
{
//get the file menu so we can merge with it
ZeroMemory(&mii, sizeof(mii));
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_SUBMENU;

if(GetMenuItemInfo(m_hMenu, FCIDM_MENU_FILE, FALSE, &mii))
{
MergeFileMenu(mii.hSubMenu);
}
}

m_pShellBrowser->SetMenuSB(m_hMenu, NULL, m_hWnd);
}
}

m_uState = uState;

return 0;
}

/**************************************************************************

CShellView::OnDeactivate()

**************************************************************************/

void CShellView::OnDeactivate(void)
{
if(m_uState != SVUIA_DEACTIVATE)
{
if(m_hMenu)
{
m_pShellBrowser->SetMenuSB(NULL, NULL, NULL);

m_pShellBrowser->RemoveMenusSB(m_hMenu);

DestroyMenu(m_hMenu);

m_hMenu = NULL;
}

m_uState = SVUIA_DEACTIVATE;
}
}

/**************************************************************************

CShellView::UIActivate()

This function activates the view window. Note that activating it
will not change the focus, while setting the focus will activate it.


**************************************************************************/

STDMETHODIMP CShellView::UIActivate(UINT uState)
{
//don't do anything if the state isn't really changing
if(m_uState == uState)
return S_OK;

//OnActivate handles the menu merging and internal state
OnActivate(uState);

//remove the docking window
if(g_bShowIDW)
AddRemoveDockingWindow(FALSE);

//only do this if we are active
if(uState != SVUIA_DEACTIVATE)
{
TCHAR szName[MAX_PATH];
LRESULT lResult;
int nPartArray[1] = {-1};

//update the status bar
LoadString(g_hInst, IDS_REGISTRY_TITLE, szName, sizeof(szName));

m_pSFParent->GetFolderPath(szName + lstrlen(szName), sizeof(szName) - lstrlen(szName));

//set the number of parts
m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETPARTS, 1, (LPARAM)nPartArray, &lResult);

//set the text for the parts
m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETTEXT, 0, (LPARAM)szName, &lResult);

//add the docking window if necessary
if(g_bShowIDW)
AddRemoveDockingWindow(TRUE);
}

return S_OK;
}

/**************************************************************************

CShellView::BuildRegistryMenu()

**************************************************************************/

HMENU CShellView::BuildRegistryMenu(void)
{
HMENU hSubMenu = CreatePopupMenu();

if(hSubMenu)
{
TCHAR szText[MAX_PATH];
MENUITEMINFO mii;
int nTools,
i;
//get the number of items in our global array
for(nTools = 0; g_Tools[nTools].idCommand != -1; nTools++)
{
}

//add the menu items
for(i = 0; i < nTools; i++)
{
LoadString(g_hInst, g_Tools[i].idMenuString, szText, sizeof(szText));

ZeroMemory(&mii, sizeof(mii));
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE;

if(TBSTYLE_SEP != g_Tools[i].bStyle)
{
mii.fType = MFT_STRING;
mii.fState = MFS_ENABLED;
mii.dwTypeData = szText;
mii.wID = g_Tools[i].idCommand;
}
else
{
mii.fType = MFT_SEPARATOR;
}

//tack this item onto the end of the menu
InsertMenuItem(hSubMenu, (UINT)-1, TRUE, &mii);
}
}

return hSubMenu;
}

/**************************************************************************

CShellView::MergeFileMenu()

**************************************************************************/

void CShellView::MergeFileMenu(HMENU hSubMenu)
{
if(hSubMenu)
{
MENUITEMINFO mii;
TCHAR szText[MAX_PATH];

ZeroMemory(&mii, sizeof(mii));

//add a separator
mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE;
mii.fType = MFT_SEPARATOR;
mii.fState = MFS_ENABLED;

//insert this item at the beginning of the menu
InsertMenuItem(hSubMenu, 0, TRUE, &mii);

//add the file menu items
LoadString(g_hInst, IDS_MI_FILEITEM, szText, sizeof(szText));
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE;
mii.fType = MFT_STRING;
mii.fState = MFS_ENABLED;
mii.dwTypeData = szText;
mii.wID = IDM_MYFILEITEM;

//insert this item at the beginning of the menu
InsertMenuItem(hSubMenu, 0, TRUE, &mii);
}
}

/**************************************************************************

CShellView::MergeViewMenu()

**************************************************************************/

void CShellView::MergeViewMenu(HMENU hSubMenu)
{
if(hSubMenu)
{
MENUITEMINFO mii;
TCHAR szText[MAX_PATH];

ZeroMemory(&mii, sizeof(mii));

//add a separator at the correct position in the menu
mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE;
mii.fType = MFT_SEPARATOR;
mii.fState = MFS_ENABLED;
InsertMenuItem(hSubMenu, FCIDM_MENU_VIEW_SEP_OPTIONS, FALSE, &mii);

//add the view menu items at the correct position in the menu
LoadString(g_hInst, IDS_MI_VIEW_KEYS, szText, sizeof(szText));
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE;
mii.fType = MFT_STRING;
mii.fState = MFS_ENABLED;
mii.dwTypeData = szText;
mii.wID = IDM_VIEW_KEYS;
InsertMenuItem(hSubMenu, FCIDM_MENU_VIEW_SEP_OPTIONS, FALSE, &mii);
}
}

/**************************************************************************

CShellView::Refresh()

**************************************************************************/

STDMETHODIMP CShellView::Refresh(void)
{
//empty the list
ListView_DeleteAllItems(m_hwndList);

//refill the list
FillList();

return S_OK;
}

/**************************************************************************

CShellView::CreateViewWindow()

**************************************************************************/

STDMETHODIMP CShellView::CreateViewWindow( LPSHELLVIEW pPrevView,
LPCFOLDERSETTINGS lpfs,
LPSHELLBROWSER psb,
LPRECT prcView,
HWND *phWnd)
{
WNDCLASS wc;

*phWnd = NULL;

//if our window class has not been registered, then do so
if(!GetClassInfo(g_hInst, NS_CLASS_NAME, &wc))
{
ZeroMemory(&wc, sizeof(wc));
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = g_hInst;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = NS_CLASS_NAME;

if(!RegisterClass(&wc))
return E_FAIL;
}

//set up the member variables
m_pShellBrowser = psb;
m_FolderSettings = *lpfs;

//get our parent window
m_pShellBrowser->GetWindow(&m_hwndParent);

*phWnd = CreateWindowEx( 0,
NS_CLASS_NAME,
NULL,
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS,
prcView->left,
prcView->top,
prcView->right - prcView->left,
prcView->bottom - prcView->top,
m_hwndParent,
NULL,
g_hInst,
(LPVOID)this);

if(!*phWnd)
return E_FAIL;

m_pShellBrowser->AddRef();

return S_OK;
}

/**************************************************************************

CShellView::DestroyViewWindow()

**************************************************************************/

STDMETHODIMP CShellView::DestroyViewWindow(void)
{
//Make absolutely sure all our UI is cleaned up.
UIActivate(SVUIA_DEACTIVATE);

if(m_hMenu)
DestroyMenu(m_hMenu);

DestroyWindow(m_hWnd);

//release the shell browser object
m_pShellBrowser->Release();

return S_OK;
}

/**************************************************************************

CShellView::GetCurrentInfo()

**************************************************************************/

STDMETHODIMP CShellView::GetCurrentInfo(LPFOLDERSETTINGS lpfs)
{
*lpfs = m_FolderSettings;

return S_OK;
}

/**************************************************************************

CShellView::AddPropertySheetPages()

**************************************************************************/

STDMETHODIMP CShellView::AddPropertySheetPages( DWORD dwReserved,
LPFNADDPROPSHEETPAGE lpfn,
LPARAM lParam)
{
return E_NOTIMPL;
}

/**************************************************************************

CShellView::SaveViewState()

**************************************************************************/

STDMETHODIMP CShellView::SaveViewState(void)
{
return S_OK;
}

/**************************************************************************

CShellView::SelectItem()

**************************************************************************/

STDMETHODIMP CShellView::SelectItem(LPCITEMIDLIST pidlItem, UINT uFlags)
{
return E_NOTIMPL;
}

/**************************************************************************

CShellView::GetItemObject()

**************************************************************************/

STDMETHODIMP CShellView::GetItemObject(UINT uItem, REFIID riid, LPVOID *ppvOut)
{
*ppvOut = NULL;

return E_NOTIMPL;
}


/**************************************************************************

CShellView::WndProc()

**************************************************************************/

LRESULT CALLBACK CShellView::WndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
{
CShellView *pThis = (CShellView*)GetWindowLong(hWnd, GWL_USERDATA);

switch (uMessage)
{
case WM_NCCREATE:
{
LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam;
pThis = (CShellView*)(lpcs->lpCreateParams);
SetWindowLong(hWnd, GWL_USERDATA, (LONG)pThis);

//set the window handle
pThis->m_hWnd = hWnd;
}
break;

case WM_SIZE:
return pThis->OnSize(LOWORD(lParam), HIWORD(lParam));

case WM_CREATE:
return pThis->OnCreate();

case WM_SETFOCUS:
return pThis->OnSetFocus();

case WM_KILLFOCUS:
return pThis->OnKillFocus();

case WM_ACTIVATE:
return pThis->OnActivate(SVUIA_ACTIVATE_FOCUS);

case WM_COMMAND:
return pThis->OnCommand( GET_WM_COMMAND_ID(wParam, lParam),
GET_WM_COMMAND_CMD(wParam, lParam),
GET_WM_COMMAND_HWND(wParam, lParam));

case WM_INITMENUPOPUP:
return pThis->UpdateMenu((HMENU)wParam);

case WM_NOTIFY:
return pThis->OnNotify((UINT)wParam, (LPNMHDR)lParam);

case WM_SETTINGCHANGE:
return pThis->OnSettingChange((LPCTSTR)lParam);
}

return DefWindowProc(hWnd, uMessage, wParam, lParam);
}

/**************************************************************************

CShellView::OnSetFocus()

**************************************************************************/

LRESULT CShellView::OnSetFocus(void)
{
/*
Tell the browser one of our windows has received the focus. This should always
be done before merging menus (OnActivate merges the menus) if one of our
windows has the focus.
*/
m_pShellBrowser->OnViewWindowActive(this);

OnActivate(SVUIA_ACTIVATE_FOCUS);

return 0;
}

/**************************************************************************

CShellView::OnKillFocus()

**************************************************************************/

LRESULT CShellView::OnKillFocus(void)
{
OnActivate(SVUIA_ACTIVATE_NOFOCUS);

return 0;
}

/**************************************************************************

CShellView::OnCommand()

**************************************************************************/

LRESULT CShellView::OnCommand(DWORD dwCmdID, DWORD dwCmd, HWND hwndCmd)
{
switch(dwCmdID)
{
case IDM_VIEW_KEYS:
g_bViewKeys = ! g_bViewKeys;
Refresh();
break;

case IDM_VIEW_IDW:
g_bShowIDW = ! g_bShowIDW;
AddRemoveDockingWindow(g_bShowIDW);
break;

case IDM_MYFILEITEM:
MessageBeep(MB_OK);
break;
}

return 0;
}

/**************************************************************************

CShellView::UpdateMenu()

**************************************************************************/

LRESULT CShellView::UpdateMenu(HMENU hMenu)
{
CheckMenuItem(hMenu, IDM_VIEW_KEYS, MF_BYCOMMAND | (g_bViewKeys ? MF_CHECKED: MF_UNCHECKED));

if(CanDoIDockingWindow())
{
EnableMenuItem(hMenu, IDM_VIEW_IDW, MF_BYCOMMAND | MF_ENABLED);
CheckMenuItem(hMenu, IDM_VIEW_IDW, MF_BYCOMMAND | (g_bShowIDW ? MF_CHECKED: MF_UNCHECKED));
}
else
{
EnableMenuItem(hMenu, IDM_VIEW_IDW, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
CheckMenuItem(hMenu, IDM_VIEW_IDW, MF_BYCOMMAND | MF_UNCHECKED);
}

return 0;
}

/**************************************************************************

CShellView::OnNotify()

**************************************************************************/

#define MENU_OFFSET 1
#define MENU_MAX 100

LRESULT CShellView::OnNotify(UINT CtlID, LPNMHDR lpnmh)
{
switch(lpnmh->code)
{
case NM_SETFOCUS:
OnSetFocus();
break;

case NM_KILLFOCUS:
OnDeactivate();
break;

case HDN_ENDTRACK:
{
g_nColumn1 = ListView_GetColumnWidth(m_hwndList, 0);
g_nColumn2 = ListView_GetColumnWidth(m_hwndList, 1);
}
return 0;

case LVN_DELETEITEM:
{
NM_LISTVIEW *lpnmlv = (NM_LISTVIEW*)lpnmh;

//delete the pidl because we made a copy of it
m_pPidlMgr->Delete((LPITEMIDLIST)lpnmlv->lParam);
}
break;

#ifdef LVN_ITEMACTIVATE

case LVN_ITEMACTIVATE:

#else //LVN_ITEMACTIVATE

case NM_DBLCLK:
case NM_RETURN:

#endif //LVN_ITEMACTIVATE

DoContextMenu(0, 0, TRUE);
return 0;

case LVN_GETDISPINFO:
{
LV_DISPINFO *lpdi = (LV_DISPINFO *)lpnmh;
LPITEMIDLIST pidl = (LPITEMIDLIST)lpdi->item.lParam;

//is the sub-item information being requested?
if(lpdi->item.iSubItem)
{
//is the text being requested?
if(lpdi->item.mask & LVIF_TEXT)
{
//is this a value or a key?
if(m_pPidlMgr->IsValue(pidl))
{
//get the item's value text
m_pPidlMgr->GetDataText(m_pidl, pidl, lpdi->item.pszText, lpdi->item.cchTextMax);

//if the data text is NULL, get the no value string
if(!*lpdi->item.pszText)
LoadString(g_hInst, IDS_NODATA, lpdi->item.pszText, lpdi->item.cchTextMax);
}
//its a key
else
{
LoadString(g_hInst, IDS_KEY, lpdi->item.pszText, lpdi->item.cchTextMax);
}
}
}
//the item text is being requested
else
{
//is the text being requested?
if(lpdi->item.mask & LVIF_TEXT)
{
STRRET str;

if(SUCCEEDED(m_pSFParent->GetDisplayNameOf(pidl, SHGDN_NORMAL | SHGDN_INFOLDER, &str)))
{
if(STRRET_WSTR == str.uType)
{
WideCharToLocal(lpdi->item.pszText, str.pOleStr, lpdi->item.cchTextMax);

//delete the string buffer
m_pMalloc->Free(str.pOleStr);
}
}
}

//is the image being requested?
if(lpdi->item.mask & LVIF_IMAGE)
{
IExtractIcon *pei;

if(SUCCEEDED(m_pSFParent->GetUIObjectOf(m_hWnd, 1, (LPCITEMIDLIST*)&pidl, IID_IExtractIcon, NULL, (LPVOID*)&pei)))
{
UINT uFlags;

//GetIconLoaction will give us the index into our image list
pei->GetIconLocation(GIL_FORSHELL, NULL, 0, &lpdi->item.iImage, &uFlags);

pei->Release();
}
}
}
}
return 0;

case NM_RCLICK:
{
DWORD dwCursor = GetMessagePos();
DoContextMenu(LOWORD(dwCursor), HIWORD(dwCursor), FALSE);
}
return 0;
}

return 0;
}

/**************************************************************************

CShellView::OnSize()

**************************************************************************/

LRESULT CShellView::OnSize(WORD wWidth, WORD wHeight)
{
//resize the ListView to fit our window
if(m_hwndList)
{
MoveWindow(m_hwndList, 0, 0, wWidth, wHeight, TRUE);
}

return 0;
}

/**************************************************************************

CShellView::OnCreate()

**************************************************************************/

LRESULT CShellView::OnCreate(void)
{
//create the ListView
if(CreateList())
{
if(InitList())
{
FillList();
}
}

return 0;
}


/**************************************************************************

CShellView::CreateList()

**************************************************************************/

BOOL CShellView::CreateList(void)
{
DWORD dwStyle;

dwStyle = WS_TABSTOP |
WS_VISIBLE |
WS_CHILD |
WS_BORDER |
LVS_REPORT |
LVS_NOSORTHEADER |
LVS_SHAREIMAGELISTS;

m_hwndList = CreateWindowEx( WS_EX_CLIENTEDGE,
WC_LISTVIEW,
NULL,
dwStyle,
0,
0,
0,
0,
m_hWnd,
(HMENU)ID_LISTVIEW,
g_hInst,
NULL);

if(!m_hwndList)
return FALSE;

UpdateShellSettings();

return TRUE;
}

/**************************************************************************

CShellView::InitList()

**************************************************************************/

BOOL CShellView::InitList(void)
{
LV_COLUMN lvColumn;
RECT rc;
TCHAR szString[MAX_PATH];

//empty the list
ListView_DeleteAllItems(m_hwndList);

//initialize the columns

lvColumn.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; 
lvColumn.fmt = LVCFMT_LEFT;
lvColumn.pszText = szString;

lvColumn.cx = g_nColumn1;
LoadString(g_hInst, IDS_COLUMN1, szString, sizeof(szString));
ListView_InsertColumn(m_hwndList, 0, &lvColumn);

GetClientRect(m_hWnd, &rc);

lvColumn.cx = g_nColumn2;
LoadString(g_hInst, IDS_COLUMN2, szString, sizeof(szString));
ListView_InsertColumn(m_hwndList, 1, &lvColumn);

ListView_SetImageList(m_hwndList, g_himlSmall, LVSIL_SMALL);

return TRUE;
}

/**************************************************************************

CShellView::FillList()

**************************************************************************/

void CShellView::FillList(void)
{
LPENUMIDLIST pEnumIDList;

if(SUCCEEDED(m_pSFParent->EnumObjects(m_hWnd, SHCONTF_NONFOLDERS | (g_bViewKeys ? SHCONTF_FOLDERS : 0), &pEnumIDList)))
{
LPITEMIDLIST pidl;
DWORD dwFetched;

//turn the listview's redrawing off
SendMessage(m_hwndList, WM_SETREDRAW, FALSE, 0);

while((S_OK == pEnumIDList->Next(1, &pidl, &dwFetched)) && dwFetched)
{
LV_ITEM lvItem;

ZeroMemory(&lvItem, sizeof(lvItem));

//set the mask
lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;

//add the item to the end of the list
lvItem.iItem = ListView_GetItemCount(m_hwndList);

//set the item's data
lvItem.lParam = (LPARAM)m_pPidlMgr->Copy(pidl);

//get text on a callback basis
lvItem.pszText = LPSTR_TEXTCALLBACK;

//get the image on a callback basis
lvItem.iImage = I_IMAGECALLBACK;

//add the item
ListView_InsertItem(m_hwndList, &lvItem);
}

//sort the items
ListView_SortItems(m_hwndList, CompareItems, (LPARAM)m_pSFParent);

//turn the listview's redrawing back on and force it to draw
SendMessage(m_hwndList, WM_SETREDRAW, TRUE, 0);
InvalidateRect(m_hwndList, NULL, TRUE);
UpdateWindow(m_hwndList);

pEnumIDList->Release();
}
}

/**************************************************************************

CShellView::CanDoIDockingWindow()

**************************************************************************/

BOOL CShellView::CanDoIDockingWindow(void)
{
#if (_WIN32_IE < 0x0400)

return FALSE;

#else //(_WIN32_IE >= 0x0400)

BOOL bReturn = FALSE;
HRESULT hr;
IServiceProvider *pSP;

//get the browser's IServiceProvider
hr = m_pShellBrowser->QueryInterface((REFIID)IID_IServiceProvider, (LPVOID*)&pSP);
if(SUCCEEDED(hr))
{
IDockingWindowFrame *pFrame;

//get the IDockingWindowFrame
hr = pSP->QueryService(SID_SShellBrowser, IID_IDockingWindowFrame, (LPVOID*)&pFrame);
if(SUCCEEDED(hr))
{
bReturn = TRUE;

pFrame->Release();
}

pSP->Release();
}

return bReturn;
#endif //(_WIN32_IE >= 0x0400)
}

/**************************************************************************

CShellView::AddRemoveDockingWindow()

**************************************************************************/

BOOL CShellView::AddRemoveDockingWindow(BOOL bAdd)
{
#if (_WIN32_IE < 0x0400)

return FALSE;

#else //(_WIN32_IE < 0x0400)

BOOL bReturn = FALSE;
HRESULT hr;
IServiceProvider *pSP;

//get the browser's IServiceProvider
hr = m_pShellBrowser->QueryInterface((REFIID)IID_IServiceProvider, (LPVOID*)&pSP);
if(SUCCEEDED(hr))
{
IDockingWindowFrame *pFrame;

//get the IDockingWindowFrame pointer
hr = pSP->QueryService(SID_SShellBrowser, IID_IDockingWindowFrame, (LPVOID*)&pFrame);
if(SUCCEEDED(hr))
{
if(bAdd)
{
hr = S_OK;
if(!m_pDockingWindow)
{
//create the toolbar object
m_pDockingWindow = new CDockingWindow(this, m_hWnd);
}

if(m_pDockingWindow)
{
//add the toolbar object
hr = pFrame->AddToolbar((IDockingWindow*)m_pDockingWindow, TOOLBAR_ID, 0);

if(SUCCEEDED(hr))
{
bReturn = TRUE;
}
}
}
else
{
if(m_pDockingWindow)
{
hr = pFrame->RemoveToolbar((IDockingWindow*)m_pDockingWindow, DWFRF_NORMAL);

if(SUCCEEDED(hr))
{
/*
RemoveToolbar should release the toolbar object which will cause
it to destroy itself. Our toolbar object is no longer valid at
this point.
*/
m_pDockingWindow = NULL;
bReturn = TRUE;
}
}
}
pFrame->Release();
}
pSP->Release();
}

return bReturn;
#endif //(_WIN32_IE < 0x0400)
}

/**************************************************************************

CShellView::UpdateShellSettings()

**************************************************************************/

typedef void (WINAPI *PFNSHGETSETTINGSPROC)(LPSHELLFLAGSTATE lpsfs, DWORD dwMask);

void CShellView::UpdateShellSettings(void)
{
#if (_WIN32_IE >= 0x0400)
SHELLFLAGSTATE sfs;
HINSTANCE hinstShell32;

/*
Since SHGetSettings is not implemented in all versions of the shell, get the
function address manually at run time. This allows the extension to run on all
platforms.
*/

ZeroMemory(&sfs, sizeof(sfs));

/*
The default, in case any of the following steps fails, is classic Windows 95
style.
*/
sfs.fWin95Classic = TRUE;

hinstShell32 = LoadLibrary(TEXT("shell32.dll"));
if(hinstShell32)
{
PFNSHGETSETTINGSPROC pfnSHGetSettings;

pfnSHGetSettings = (PFNSHGETSETTINGSPROC)GetProcAddress(hinstShell32, TEXT("SHGetSettings"));
if(pfnSHGetSettings)
{
(*pfnSHGetSettings)(&sfs, SSF_DOUBLECLICKINWEBVIEW | SSF_WIN95CLASSIC);
}
FreeLibrary(hinstShell32);
}

DWORD dwExStyles = 0;

if(!sfs.fWin95Classic && !sfs.fDoubleClickInWebView)
dwExStyles |= LVS_EX_ONECLICKACTIVATE |
LVS_EX_TRACKSELECT |
LVS_EX_UNDERLINEHOT;

ListView_SetExtendedListViewStyle(m_hwndList, dwExStyles);

#endif //(_WIN32_IE >= 0x0400)
}

/**************************************************************************

CShellView::OnSettingChange()

**************************************************************************/

LRESULT CShellView::OnSettingChange(LPCTSTR lpszSection)
{
//if(0 == lstrcmpi(lpszSection, TEXT("ShellState")))
{
UpdateShellSettings();
return 0;
}

return 0;
}

/**************************************************************************

CShellView::DoContextMenu()

**************************************************************************/

void CShellView::DoContextMenu(WORD x, WORD y, BOOL fDefault)
{
UINT uSelected = ListView_GetSelectedCount(m_hwndList);
LPITEMIDLIST *aSelectedItems;

aSelectedItems = (LPITEMIDLIST*)m_pMalloc->Alloc(uSelected * sizeof(LPITEMIDLIST));

if(aSelectedItems)
{
UINT i;
LPCONTEXTMENU pContextMenu = NULL;
LVITEM lvItem;

ZeroMemory(&lvItem, sizeof(lvItem));
lvItem.mask = LVIF_STATE | LVIF_PARAM;
lvItem.stateMask = LVIS_SELECTED;
lvItem.iItem = 0;

i = 0;

while(ListView_GetItem(m_hwndList, &lvItem) && (i < uSelected))
{
if(lvItem.state & LVIS_SELECTED)
{
aSelectedItems[i] = (LPITEMIDLIST)lvItem.lParam;
i++;
}
lvItem.iItem++;
}

m_pSFParent->GetUIObjectOf( m_hwndParent,
uSelected,
(LPCITEMIDLIST*)aSelectedItems,
IID_IContextMenu,
NULL,
(LPVOID*)&pContextMenu);

if(pContextMenu)
{
HMENU hMenu = CreatePopupMenu();

if(hMenu && SUCCEEDED(pContextMenu->QueryContextMenu( hMenu,
0,
MENU_OFFSET,
MENU_MAX,
CMF_NORMAL)))
{
UINT uCommand;

if(fDefault)
{
MENUITEMINFO mii;
int nMenuIndex;

uCommand = 0;

ZeroMemory(&mii, sizeof(mii));
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_STATE | MIIM_ID;

nMenuIndex = 0;

//find the default item in the menu
while(GetMenuItemInfo(hMenu, nMenuIndex, TRUE, &mii))
{
if(mii.fState & MFS_DEFAULT)
{
uCommand = mii.wID;
}

nMenuIndex++;
}
}
else
{
uCommand = TrackPopupMenu( hMenu,
TPM_LEFTALIGN | TPM_RETURNCMD,
x,
y,
0,
m_hWnd,
NULL);
}

if(uCommand > 0)
{
CMINVOKECOMMANDINFO cmi;

ZeroMemory(&cmi, sizeof(cmi));
cmi.cbSize = sizeof(cmi);
cmi.hwnd = m_hwndParent;
cmi.lpVerb = MAKEINTRESOURCE(uCommand - MENU_OFFSET);

pContextMenu->InvokeCommand(&cmi);
}

DestroyMenu(hMenu);
}
}

m_pMalloc->Free(aSelectedItems);
}
}