mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1412 lines
27 KiB
1412 lines
27 KiB
/*++
|
|
|
|
Implements IShellView.
|
|
|
|
--*/
|
|
|
|
#include <windows.h>
|
|
#include <windowsx.h>
|
|
#include <objbase.h>
|
|
#include <shlobj.h>
|
|
|
|
#include <docobj.h>
|
|
#include <shellapi.h>
|
|
|
|
#include "pstore.h"
|
|
|
|
#include "shfolder.h"
|
|
|
|
#include "shview.h"
|
|
#include "guid.h"
|
|
#include "resource.h"
|
|
#include "tools.h"
|
|
|
|
#include "utility.h"
|
|
#include "enumid.h"
|
|
|
|
|
|
#include "listu.h"
|
|
|
|
|
|
extern HINSTANCE g_hInst;
|
|
extern LONG g_DllRefCount;
|
|
|
|
|
|
|
|
BOOL
|
|
AddListItem(
|
|
HWND hWnd,
|
|
DWORD dwType,
|
|
PST_KEY KeyType,
|
|
LPCWSTR szName,
|
|
LPITEMIDLIST pidl
|
|
);
|
|
|
|
|
|
|
|
#define TOOLBAR_ID (L"TBar")
|
|
#define INITIAL_COLUMN_POS 100
|
|
|
|
MYTOOLINFO g_Buttons[] =
|
|
{
|
|
IDM_MESSAGE1, 0, IDS_TB_MESSAGE1, IDS_MI_MESSAGE1, TBSTATE_ENABLED, TBSTYLE_BUTTON,
|
|
IDM_MESSAGE2, 0, IDS_TB_MESSAGE2, IDS_MI_MESSAGE2, TBSTATE_ENABLED, TBSTYLE_BUTTON,
|
|
-1, 0, 0, 0, 0,
|
|
};
|
|
|
|
|
|
CShellView::CShellView(
|
|
CShellFolder *pFolder,
|
|
LPCITEMIDLIST pidl
|
|
)
|
|
{
|
|
|
|
m_hMenu = NULL;
|
|
ZeroMemory(&m_MenuWidths, sizeof(m_MenuWidths));
|
|
|
|
m_nColumn1 = INITIAL_COLUMN_POS;
|
|
m_nColumn2 = INITIAL_COLUMN_POS;
|
|
|
|
m_pSFParent = pFolder;
|
|
if(m_pSFParent)
|
|
m_pSFParent->AddRef();
|
|
|
|
m_pidl = (LPITEMIDLIST)pidl;
|
|
|
|
m_uState = SVUIA_DEACTIVATE;
|
|
|
|
m_ObjRefCount = 1;
|
|
InterlockedIncrement(&g_DllRefCount);
|
|
}
|
|
|
|
|
|
CShellView::~CShellView()
|
|
{
|
|
if(m_pSFParent)
|
|
m_pSFParent->Release();
|
|
|
|
InterlockedDecrement(&g_DllRefCount);
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CShellView::QueryInterface(
|
|
REFIID riid,
|
|
LPVOID *ppReturn
|
|
)
|
|
/*++
|
|
|
|
IUnknown::QueryInterface
|
|
|
|
--*/
|
|
{
|
|
*ppReturn = NULL;
|
|
|
|
if(IsEqualIID(riid, IID_IUnknown))
|
|
*ppReturn = (IUnknown*)(IShellView*)this;
|
|
else if(IsEqualIID(riid, IID_IOleWindow))
|
|
*ppReturn = (IOleWindow*)this;
|
|
else if(IsEqualIID(riid, IID_IShellView))
|
|
*ppReturn = (CShellView*)this;
|
|
else if(IsEqualIID(riid, IID_IOleCommandTarget))
|
|
*ppReturn = (IOleCommandTarget*)this;
|
|
|
|
if(*ppReturn == NULL)
|
|
return E_NOINTERFACE;
|
|
|
|
(*(LPUNKNOWN*)ppReturn)->AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
STDMETHODIMP_(DWORD)
|
|
CShellView::AddRef()
|
|
/*++
|
|
|
|
IUnknown::AddRef
|
|
|
|
--*/
|
|
{
|
|
return InterlockedIncrement(&m_ObjRefCount);
|
|
}
|
|
|
|
|
|
STDMETHODIMP_(DWORD)
|
|
CShellView::Release()
|
|
/*++
|
|
|
|
IUnknown::Release
|
|
|
|
--*/
|
|
{
|
|
LONG lDecremented = InterlockedDecrement(&m_ObjRefCount);
|
|
|
|
if(lDecremented == 0)
|
|
delete this;
|
|
|
|
return lDecremented;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CShellView::GetWindow(
|
|
HWND *phWnd
|
|
)
|
|
/*++
|
|
|
|
IOleWindow::GetWindow
|
|
|
|
--*/
|
|
{
|
|
*phWnd = m_hWnd;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CShellView::ContextSensitiveHelp(
|
|
BOOL fEnterMode
|
|
)
|
|
/*++
|
|
|
|
Inherited from IOleWindow::ContextSensitiveHelp.
|
|
|
|
--*/
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CShellView::QueryStatus(
|
|
const GUID *pguidCmdGroup,
|
|
ULONG cCmds,
|
|
OLECMD prgCmds[],
|
|
OLECMDTEXT *pCmdText
|
|
)
|
|
/*++
|
|
|
|
IOleCommandTarget::QueryStatus
|
|
|
|
--*/
|
|
{
|
|
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 == NULL)
|
|
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_MESSAGE1:
|
|
prgCmds[i].cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED;
|
|
break;
|
|
|
|
case IDM_MESSAGE2:
|
|
prgCmds[i].cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CShellView::Exec(
|
|
const GUID *pguidCmdGroup,
|
|
DWORD nCmdID,
|
|
DWORD nCmdExecOpt,
|
|
VARIANTARG *pvaIn,
|
|
VARIANTARG *pvaOut
|
|
)
|
|
/*++
|
|
|
|
IOleCommandTarget::Exec
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// only process the commands for our command group
|
|
//
|
|
|
|
if(pguidCmdGroup && (*pguidCmdGroup == CLSID_CmdGrp))
|
|
{
|
|
OnCommand(nCmdID, 0, NULL);
|
|
return S_OK;
|
|
}
|
|
|
|
return OLECMDERR_E_UNKNOWNGROUP;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CShellView::TranslateAccelerator(
|
|
LPMSG pMsg
|
|
)
|
|
/*++
|
|
|
|
Same as the IOleInPlaceFrame::TranslateAccelerator, but will be
|
|
never called because we don't support EXEs (i.e., the explorer has
|
|
the message loop). This member function is defined here for possible
|
|
future enhancement.
|
|
|
|
--*/
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CShellView::EnableModeless(
|
|
BOOL fEnable
|
|
)
|
|
/*++
|
|
|
|
Same as the IOleInPlaceFrame::EnableModeless.
|
|
|
|
--*/
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CShellView::UIActivate(
|
|
UINT uState
|
|
)
|
|
/*++
|
|
|
|
IShellView::UIActivate
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// don't do anything if the state isn't really changing
|
|
//
|
|
|
|
if(m_uState == uState)
|
|
return S_OK;
|
|
|
|
//
|
|
// Always do this because we will cause problems if we are going from
|
|
// SVUIA_ACTIVATE_FOCUS to SVUIA_ACTIVATE_NOFOCUS or vice versa.
|
|
//
|
|
|
|
m_uState = SVUIA_DEACTIVATE;
|
|
|
|
m_pShellBrowser->SetMenuSB(NULL, NULL, NULL);
|
|
|
|
if(m_hMenu) {
|
|
DestroyMenu(m_hMenu);
|
|
m_hMenu = NULL;
|
|
}
|
|
|
|
//
|
|
// only do this if we are active
|
|
//
|
|
|
|
if(uState != SVUIA_DEACTIVATE) {
|
|
m_uState = uState;
|
|
|
|
//
|
|
// update the Explorer's menu
|
|
//
|
|
|
|
if(m_hMenu == NULL)
|
|
m_hMenu = CreateMenu();
|
|
|
|
if(m_hMenu) {
|
|
MENUITEMINFO mii;
|
|
TCHAR szText[MAX_PATH];
|
|
|
|
m_pShellBrowser->InsertMenusSB(m_hMenu, &m_MenuWidths);
|
|
|
|
//
|
|
// get the menu item's text
|
|
//
|
|
LoadString(g_hInst, IDS_MI_REGISTRY, szText, sizeof(szText));
|
|
|
|
//
|
|
// build our menu
|
|
//
|
|
|
|
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 = BuildMenu();
|
|
|
|
//
|
|
// insert our menu
|
|
//
|
|
|
|
InsertMenuItem(m_hMenu, FCIDM_MENU_HELP, FALSE, &mii);
|
|
|
|
m_pShellBrowser->SetMenuSB(m_hMenu, NULL, m_hWnd);
|
|
}
|
|
|
|
//
|
|
// TODO: update the status bar
|
|
//
|
|
|
|
/*
|
|
|
|
TCHAR szName[MAX_PATH];
|
|
|
|
LoadString(g_hInst, IDS_PSTORE_TITLE, szName, sizeof(szName));
|
|
|
|
m_pSFParent->GetPidlFullText(m_pidl, szName + lstrlen(szName), sizeof(szName) - lstrlen(szName));
|
|
|
|
LRESULT lResult;
|
|
int nPartArray[1] = {-1};
|
|
|
|
//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);
|
|
|
|
*/
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
HMENU
|
|
CShellView::BuildMenu(
|
|
void
|
|
)
|
|
{
|
|
HMENU hSubMenu = CreatePopupMenu();
|
|
|
|
if(hSubMenu == NULL)
|
|
return NULL;
|
|
|
|
TCHAR szText[MAX_PATH];
|
|
MENUITEMINFO mii;
|
|
int nButtons, i;
|
|
|
|
//
|
|
// get the number of items in our global array
|
|
//
|
|
|
|
for(nButtons = 0; g_Buttons[nButtons].idCommand != -1; nButtons++) {
|
|
;
|
|
}
|
|
|
|
//
|
|
// add the menu items
|
|
//
|
|
|
|
for(i = 0; i < nButtons; i++) {
|
|
|
|
LoadString(g_hInst, g_Buttons[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_Buttons[i].bStyle) {
|
|
|
|
mii.fType = MFT_STRING;
|
|
mii.fState = MFS_ENABLED;
|
|
mii.dwTypeData = szText;
|
|
mii.wID = g_Buttons[i].idCommand;
|
|
} else {
|
|
mii.fType = MFT_SEPARATOR;
|
|
}
|
|
|
|
//
|
|
// tack this item onto the end of the menu
|
|
//
|
|
|
|
InsertMenuItem(hSubMenu, (UINT)-1, TRUE, &mii);
|
|
}
|
|
|
|
//
|
|
// add a couple more that aren't in the button array
|
|
//
|
|
|
|
LoadString(g_hInst, IDS_MI_VIEW_ISTB, szText, sizeof(szText));
|
|
|
|
ZeroMemory(&mii, sizeof(mii));
|
|
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_ISTB;
|
|
|
|
//
|
|
// tack this item onto the end of the menu
|
|
//
|
|
|
|
InsertMenuItem(hSubMenu, (UINT)-1, TRUE, &mii);
|
|
|
|
LoadString(g_hInst, IDS_MI_VIEW_IETB, szText, sizeof(szText));
|
|
|
|
ZeroMemory(&mii, sizeof(mii));
|
|
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_IETB;
|
|
|
|
//
|
|
// tack this item onto the end of the menu
|
|
//
|
|
|
|
InsertMenuItem(hSubMenu, (UINT)-1, TRUE, &mii);
|
|
|
|
return hSubMenu;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CShellView::Refresh(
|
|
void
|
|
)
|
|
/*++
|
|
|
|
IShellView::Refresh
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// empty the list
|
|
//
|
|
|
|
ListView_DeleteAllItems(m_hwndList);
|
|
|
|
//
|
|
// refill the list
|
|
//
|
|
|
|
FillList();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CShellView::CreateViewWindow(
|
|
LPSHELLVIEW pPrevView,
|
|
LPCFOLDERSETTINGS lpfs,
|
|
LPSHELLBROWSER psb,
|
|
LPRECT prcView,
|
|
HWND *phWnd
|
|
)
|
|
/*++
|
|
|
|
CreateViewWindow creates a view window. This can be either the right pane
|
|
of the Explorer or the client window of a folder window.
|
|
|
|
--*/
|
|
{
|
|
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;
|
|
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.ViewMode = lpfs->ViewMode;
|
|
m_FolderSettings.fFlags = lpfs->fFlags;
|
|
|
|
//
|
|
// get our parent window
|
|
//
|
|
|
|
m_pShellBrowser->GetWindow(&m_hwndParent);
|
|
|
|
GetSettings();
|
|
|
|
*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 == NULL)
|
|
return E_FAIL;
|
|
|
|
//
|
|
// addref the IShellBrowser interface to allow communication with Explorer
|
|
//
|
|
|
|
m_pShellBrowser->AddRef();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CShellView::DestroyViewWindow(
|
|
void
|
|
)
|
|
/*++
|
|
|
|
The Explorer calls this method when a folder window or the Explorer
|
|
is being closed.
|
|
|
|
--*/
|
|
{
|
|
if(m_hMenu)
|
|
DestroyMenu(m_hMenu);
|
|
|
|
DestroyWindow(m_hWnd);
|
|
|
|
//
|
|
// release the shell browser object
|
|
//
|
|
|
|
m_pShellBrowser->Release();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CShellView::GetCurrentInfo(
|
|
LPFOLDERSETTINGS lpfs
|
|
)
|
|
/*++
|
|
|
|
The Explorer uses GetCurrentInfo to query the view for standard settings.
|
|
|
|
--*/
|
|
{
|
|
// TODO, check proper approach.
|
|
|
|
*lpfs = m_FolderSettings;
|
|
// lpfs->ViewMode = m_FolderSettings.ViewMode;
|
|
// lpfs->fFlags = m_FolderSettings.fFlags;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CShellView::AddPropertySheetPages(
|
|
DWORD dwReserved,
|
|
LPFNADDPROPSHEETPAGE lpfn,
|
|
LPARAM lParam
|
|
)
|
|
/*++
|
|
The Explorer calls this method when it is opening the View.Options...
|
|
property sheet. Views can add pages by creating them and calling the
|
|
callback function with the page handles.
|
|
--*/
|
|
{
|
|
OutputDebugStringA("IShellView::AddPropertySheetPages\n");
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP
|
|
CShellView::SaveViewState(
|
|
void
|
|
)
|
|
/*++
|
|
|
|
IShellView::SaveViewState
|
|
|
|
--*/
|
|
{
|
|
SaveSettings();
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CShellView::SelectItem(
|
|
LPCITEMIDLIST pidlItem,
|
|
UINT uFlags
|
|
)
|
|
/*++
|
|
|
|
IShellView::SelectItem
|
|
|
|
--*/
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CShellView::GetItemObject(
|
|
UINT uItem,
|
|
REFIID riid,
|
|
LPVOID *ppvOut
|
|
)
|
|
/*++
|
|
|
|
Used by the common dialogs to get the selected items from the view.
|
|
|
|
--*/
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
|
|
LRESULT
|
|
CALLBACK
|
|
CShellView::WndProc(
|
|
HWND hWnd,
|
|
UINT uMessage,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
CShellView *pThis = (CShellView*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
|
|
|
|
switch (uMessage)
|
|
{
|
|
case WM_NCCREATE:
|
|
{
|
|
LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam;
|
|
pThis = (CShellView*)(lpcs->lpCreateParams);
|
|
SetWindowLongPtr(hWnd, GWLP_USERDATA, (LPARAM)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_ACTIVATE:
|
|
return pThis->OnActivate(wParam, lParam);
|
|
|
|
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);
|
|
}
|
|
|
|
return DefWindowProc(hWnd, uMessage, wParam, lParam);
|
|
}
|
|
|
|
|
|
LRESULT
|
|
CShellView::OnSetFocus(
|
|
void
|
|
)
|
|
{
|
|
//
|
|
// tell the browser we got the focus
|
|
//
|
|
|
|
m_pShellBrowser->OnViewWindowActive(this);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
LRESULT
|
|
CShellView::OnActivate(
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
//
|
|
// tell the browser we got the focus
|
|
//
|
|
|
|
if(wParam)
|
|
m_pShellBrowser->OnViewWindowActive(this);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
LRESULT
|
|
CShellView::OnCommand(
|
|
DWORD dwCmdID,
|
|
DWORD dwCmd,
|
|
HWND hwndCmd
|
|
)
|
|
{
|
|
switch(dwCmdID)
|
|
{
|
|
case IDM_MESSAGE1:
|
|
MessageBox(m_hWnd, TEXT("Message 1 was selected"), TEXT("Notice"), MB_OK | MB_ICONEXCLAMATION);
|
|
break;
|
|
|
|
case IDM_MESSAGE2:
|
|
MessageBox(m_hWnd, TEXT("Message 2 was selected"), TEXT("Notice"), MB_OK | MB_ICONEXCLAMATION);
|
|
break;
|
|
|
|
case IDM_VIEW_ISTB:
|
|
m_bShowISTB = ! m_bShowISTB;
|
|
UpdateToolbar();
|
|
break;
|
|
|
|
case IDM_VIEW_IETB:
|
|
m_bShowIETB = ! m_bShowIETB;
|
|
UpdateToolbar();
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CShellView::SaveSettings(
|
|
void
|
|
)
|
|
/*++
|
|
|
|
Called by IShellView::SaveViewState to store the relevant setting data
|
|
to the browser stream.
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr;
|
|
LPSTREAM pStream;
|
|
|
|
hr = m_pShellBrowser->GetViewStateStream(STGM_WRITE, &pStream);
|
|
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
ULONG uWritten;
|
|
|
|
pStream->Write(&m_bShowISTB, sizeof(m_bShowISTB), &uWritten);
|
|
pStream->Write(&m_bShowIETB, sizeof(m_bShowIETB), &uWritten);
|
|
pStream->Write(&m_nColumn1, sizeof(m_nColumn1), &uWritten);
|
|
pStream->Write(&m_nColumn2, sizeof(m_nColumn2), &uWritten);
|
|
|
|
pStream->Release();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CShellView::GetSettings(
|
|
void
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
LPSTREAM pStream;
|
|
|
|
hr = m_pShellBrowser->GetViewStateStream(STGM_READ, &pStream);
|
|
|
|
if(SUCCEEDED(hr)) {
|
|
|
|
ULONG uRead;
|
|
|
|
if(S_OK != pStream->Read(&m_bShowISTB, sizeof(m_bShowISTB), &uRead))
|
|
m_bShowISTB = FALSE;
|
|
|
|
if(S_OK != pStream->Read(&m_bShowIETB, sizeof(m_bShowIETB), &uRead))
|
|
m_bShowIETB = FALSE;
|
|
|
|
if(S_OK != pStream->Read(&m_nColumn1, sizeof(m_nColumn1), &uRead))
|
|
m_nColumn1 = INITIAL_COLUMN_POS;
|
|
|
|
if(S_OK != pStream->Read(&m_nColumn2, sizeof(m_nColumn2), &uRead))
|
|
m_nColumn2 = INITIAL_COLUMN_POS;
|
|
|
|
pStream->Release();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
LRESULT
|
|
CShellView::UpdateMenu(
|
|
HMENU hMenu
|
|
)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
|
|
void
|
|
CShellView::UpdateToolbar()
|
|
{
|
|
// nothing to update yet
|
|
}
|
|
|
|
|
|
LRESULT
|
|
CShellView::OnNotify(
|
|
UINT CtlID,
|
|
LPNMHDR pNotify
|
|
)
|
|
{
|
|
LPNM_LISTVIEW pNotifyLV = (LPNM_LISTVIEW)pNotify;
|
|
LV_DISPINFO *pNotifyDI = (LV_DISPINFO *)pNotify;
|
|
LPTBNOTIFY pNotifyTB = (LPTBNOTIFY)pNotify;
|
|
LPTOOLTIPTEXT pNotifyTT = (LPTOOLTIPTEXT)pNotify;
|
|
|
|
switch(pNotify->code)
|
|
{
|
|
|
|
//
|
|
// HDN_BEGINTRACK
|
|
// HDN_DIVIDERDBLCLICK
|
|
// HDN_ENDTRACK
|
|
// HDN_ITEMCHANGED
|
|
// HDN_ITEMCHANGING
|
|
// HDN_ITEMCLICK
|
|
// HDN_ITEMDBLCLICK
|
|
// HDN_TRACK
|
|
//
|
|
|
|
case HDN_ENDTRACK:
|
|
{
|
|
m_nColumn1 = ListView_GetColumnWidth(m_hwndList, 0);
|
|
m_nColumn2 = ListView_GetColumnWidth(m_hwndList, 1);
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// LVN_BEGINDRAG
|
|
// LVN_BEGINLABELEDIT
|
|
// LVN_BEGINRDRAG
|
|
// LVN_COLUMNCLICK
|
|
// LVN_DELETEALLITEMS
|
|
// LVN_DELETEITEM
|
|
// LVN_ENDLABELEDIT
|
|
// LVN_GETDISPINFO
|
|
// LVN_INSERTITEM
|
|
// LVN_ITEMCHANGED
|
|
// LVN_ITEMCHANGING
|
|
// LVN_KEYDOWN
|
|
// LVN_SETDISPINFO
|
|
//
|
|
|
|
case LVN_DELETEITEM:
|
|
{
|
|
LPITEMIDLIST pidl = (LPITEMIDLIST)(pNotifyLV->lParam);
|
|
|
|
//
|
|
// free the memory for the pidl associated with this item.
|
|
//
|
|
|
|
if(pidl != NULL)
|
|
FreePidl(pidl);
|
|
|
|
break;
|
|
}
|
|
|
|
// NM_CLICK
|
|
// NM_DBLCLK
|
|
// NM_KILLFOCUS
|
|
// NM_LISTVIEW
|
|
// NM_OUTOFMEMORY
|
|
// NM_RCLICK
|
|
// NM_RDBLCLK
|
|
// NM_RETURN
|
|
// NM_SETFOCUS
|
|
// NM_TREEVIEW
|
|
// NM_UPDOWN
|
|
//
|
|
|
|
case NM_RETURN:
|
|
case NM_DBLCLK:
|
|
{
|
|
UINT wFlags = SBSP_RELATIVE | SBSP_DEFMODE;
|
|
int iItem = -1;
|
|
|
|
//
|
|
// if we are in explorer mode, start out in DEFBROWSER mode,
|
|
// otherwise, start in NEWBROWSER mode.
|
|
//
|
|
|
|
HWND hwnd = NULL;
|
|
m_pShellBrowser->GetControlWindow(FCW_TREE, &hwnd);
|
|
|
|
if(hwnd != NULL) {
|
|
wFlags |= SBSP_DEFBROWSER;
|
|
} else {
|
|
wFlags |= SBSP_NEWBROWSER;
|
|
}
|
|
|
|
|
|
//
|
|
// loop through all the selected items.
|
|
// TODO: if more than two are selected, we only get to view
|
|
// two.
|
|
//
|
|
|
|
do {
|
|
LV_ITEM item;
|
|
|
|
iItem = ListView_GetNextItem(m_hwndList, iItem, LVNI_SELECTED | LVNI_ALL);
|
|
ZeroMemory(&item, sizeof(item));
|
|
item.mask = LVIF_PARAM;
|
|
item.iItem = iItem;
|
|
|
|
if(!ListView_GetItem(m_hwndList, &item))
|
|
break;
|
|
|
|
LPCITEMIDLIST pidl = (LPCITEMIDLIST)(item.lParam);
|
|
|
|
if(pidl != NULL) {
|
|
|
|
//
|
|
// don't browse into items.
|
|
//
|
|
|
|
if(GetLastPidlType(pidl) > PIDL_TYPE_SUBTYPE)
|
|
break;
|
|
|
|
m_pShellBrowser->BrowseObject(pidl, wFlags);
|
|
}
|
|
|
|
//
|
|
// if multiple items selected, bring up a new browser
|
|
//
|
|
|
|
wFlags &= ~SBSP_DEFBROWSER;
|
|
wFlags |= SBSP_NEWBROWSER;
|
|
} while (iItem != -1);
|
|
|
|
}
|
|
|
|
//
|
|
// TBN_BEGINADJUST
|
|
// TBN_BEGINDRAG
|
|
// TBN_CUSTHELP
|
|
// TBN_ENDADJUST
|
|
// TBN_ENDDRAG
|
|
// TBN_GETBUTTONINFO
|
|
// TBN_QUERYDELETE
|
|
// TBN_QUERYINSERT
|
|
// TBN_RESET
|
|
// TBN_TOOLBARCHANGE
|
|
//
|
|
|
|
case TBN_BEGINDRAG:
|
|
default:
|
|
return 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
LRESULT
|
|
CShellView::OnCreate(
|
|
void
|
|
)
|
|
{
|
|
//
|
|
// create the ListView
|
|
//
|
|
|
|
if(CreateList())
|
|
{
|
|
if(InitList())
|
|
{
|
|
FillList();
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CShellView::CreateList(
|
|
void
|
|
)
|
|
{
|
|
DWORD dwStyle;
|
|
|
|
//
|
|
// fetch the prior listview style and use
|
|
// that as the new listview style.
|
|
//
|
|
|
|
|
|
switch (m_FolderSettings.ViewMode) {
|
|
case FVM_ICON:
|
|
dwStyle = LVS_ICON;
|
|
break;
|
|
case FVM_SMALLICON:
|
|
dwStyle = LVS_SMALLICON;
|
|
break;
|
|
case FVM_LIST:
|
|
dwStyle = LVS_LIST;
|
|
break;
|
|
case FVM_DETAILS:
|
|
dwStyle = LVS_REPORT;
|
|
break;
|
|
default:
|
|
dwStyle = LVS_ICON;
|
|
break;
|
|
}
|
|
|
|
m_hwndList = CreateWindowEx(
|
|
WS_EX_CLIENTEDGE,
|
|
WC_LISTVIEW,
|
|
NULL,
|
|
WS_TABSTOP |
|
|
WS_VISIBLE |
|
|
WS_CHILD |
|
|
WS_BORDER |
|
|
LVS_SORTASCENDING |
|
|
dwStyle |
|
|
LVS_NOSORTHEADER |
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
m_hWnd,
|
|
(HMENU)ID_LISTVIEW,
|
|
g_hInst,
|
|
NULL
|
|
);
|
|
|
|
return (BOOL)(NULL != m_hwndList);
|
|
}
|
|
|
|
|
|
BOOL
|
|
CShellView::InitList(
|
|
void
|
|
)
|
|
{
|
|
LV_COLUMN lvColumn;
|
|
HIMAGELIST himlSmall;
|
|
HIMAGELIST himlLarge;
|
|
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 = m_nColumn1;
|
|
LoadString(g_hInst, IDS_COLUMN1, szString, sizeof(szString));
|
|
ListView_InsertColumn(m_hwndList, 0, &lvColumn);
|
|
|
|
GetClientRect(m_hWnd, &rc);
|
|
|
|
lvColumn.cx = m_nColumn2;
|
|
LoadString(g_hInst, IDS_COLUMN2, szString, sizeof(szString));
|
|
ListView_InsertColumn(m_hwndList, 1, &lvColumn);
|
|
|
|
int cxSmall;
|
|
int cySmall;
|
|
int cxLarge;
|
|
int cyLarge;
|
|
|
|
SHFILEINFO sfi;
|
|
HIMAGELIST himl;
|
|
|
|
//
|
|
// get large and small icon size info from shell
|
|
//
|
|
|
|
himl = (HIMAGELIST)SHGetFileInfo(
|
|
NULL,
|
|
0,
|
|
&sfi,
|
|
sizeof(sfi),
|
|
SHGFI_LARGEICON | SHGFI_SYSICONINDEX
|
|
);
|
|
|
|
if(!ImageList_GetIconSize(himl, &cxLarge, &cyLarge)) {
|
|
cxLarge = GetSystemMetrics(SM_CXICON);
|
|
cyLarge = GetSystemMetrics(SM_CYICON);
|
|
}
|
|
|
|
himl = (HIMAGELIST)SHGetFileInfo(
|
|
NULL,
|
|
0,
|
|
&sfi,
|
|
sizeof(sfi),
|
|
SHGFI_SMALLICON | SHGFI_SYSICONINDEX
|
|
);
|
|
|
|
if(!ImageList_GetIconSize(himl, &cxSmall, &cySmall)) {
|
|
cxSmall = GetSystemMetrics(SM_CXSMICON);
|
|
cySmall = GetSystemMetrics(SM_CYSMICON);
|
|
}
|
|
|
|
|
|
//
|
|
// Create the full-sized and small icon image lists.
|
|
//
|
|
|
|
himlLarge = ImageList_Create(
|
|
cxLarge,
|
|
cyLarge,
|
|
ILC_COLORDDB | ILC_MASK,
|
|
4, // initial image count
|
|
0
|
|
);
|
|
|
|
himlSmall = ImageList_Create(
|
|
cxSmall,
|
|
cySmall,
|
|
ILC_COLORDDB | ILC_MASK,
|
|
4, // initial image count
|
|
0
|
|
);
|
|
|
|
//
|
|
// Add icons to each image list.
|
|
// TODO cache icons
|
|
//
|
|
|
|
HICON hIconSmall;
|
|
HICON hIconLarge;
|
|
|
|
// icon 0: Provider icon
|
|
|
|
hIconSmall = (HICON)LoadImage(g_hInst, MAKEINTRESOURCE(IDI_PROVIDER), IMAGE_ICON, cxSmall, cySmall, LR_DEFAULTCOLOR | LR_SHARED);
|
|
hIconLarge = (HICON)LoadImage(g_hInst, MAKEINTRESOURCE(IDI_PROVIDER), IMAGE_ICON, cxLarge, cyLarge, LR_DEFAULTCOLOR | LR_SHARED);
|
|
|
|
ImageList_AddIcon(himlSmall, hIconSmall);
|
|
ImageList_AddIcon(himlLarge, hIconLarge);
|
|
|
|
|
|
// icon 1: type icon
|
|
|
|
hIconSmall = (HICON)LoadImage(g_hInst, MAKEINTRESOURCE(IDI_FOLDER), IMAGE_ICON, cxSmall, cySmall, LR_DEFAULTCOLOR | LR_SHARED);
|
|
hIconLarge = (HICON)LoadImage(g_hInst, MAKEINTRESOURCE(IDI_FOLDER), IMAGE_ICON, cxLarge, cyLarge, LR_DEFAULTCOLOR | LR_SHARED);
|
|
|
|
ImageList_AddIcon(himlSmall, hIconSmall);
|
|
ImageList_AddIcon(himlLarge, hIconLarge);
|
|
|
|
// icon 2: item icon
|
|
|
|
hIconSmall = (HICON)LoadImage(g_hInst, MAKEINTRESOURCE(IDI_ITEM), IMAGE_ICON, cxSmall, cySmall, LR_DEFAULTCOLOR | LR_SHARED);
|
|
hIconLarge = (HICON)LoadImage(g_hInst, MAKEINTRESOURCE(IDI_ITEM), IMAGE_ICON, cxLarge, cyLarge, LR_DEFAULTCOLOR | LR_SHARED);
|
|
|
|
ImageList_AddIcon(himlSmall, hIconSmall);
|
|
ImageList_AddIcon(himlLarge, hIconLarge);
|
|
|
|
// icon 3: global type
|
|
|
|
hIconSmall = (HICON)LoadImage(g_hInst, MAKEINTRESOURCE(IDI_GLOBAL), IMAGE_ICON, cxSmall, cySmall, LR_DEFAULTCOLOR | LR_SHARED);
|
|
hIconLarge = (HICON)LoadImage(g_hInst, MAKEINTRESOURCE(IDI_GLOBAL), IMAGE_ICON, cxLarge, cyLarge, LR_DEFAULTCOLOR | LR_SHARED);
|
|
|
|
ImageList_AddIcon(himlSmall, hIconSmall);
|
|
ImageList_AddIcon(himlLarge, hIconLarge);
|
|
|
|
|
|
//
|
|
// Assign the image lists to the list view control.
|
|
//
|
|
|
|
ListView_SetImageList(m_hwndList, himlLarge, LVSIL_NORMAL);
|
|
ListView_SetImageList(m_hwndList, himlSmall, LVSIL_SMALL);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
CShellView::FillList(
|
|
void
|
|
)
|
|
{
|
|
LPENUMIDLIST pEnumIDList;
|
|
ULONG ulFetched;
|
|
LPITEMIDLIST pidl = NULL;
|
|
|
|
pEnumIDList = new CEnumIDList(m_pidl, TRUE);
|
|
if(pEnumIDList == NULL)
|
|
return FALSE;
|
|
|
|
//
|
|
// enumerate the sub folders or items, based on the parent m_pidl.
|
|
// note that storage is allocated for the pidlNew, which is a copy
|
|
// of the current path + pidl - that storage is later freed during
|
|
// the processing of LVN_DELETEITEM
|
|
//
|
|
|
|
while( NOERROR == pEnumIDList->Next(1, &pidl, &ulFetched) ) {
|
|
|
|
LPCWSTR szText = GetPidlText(pidl);
|
|
PST_KEY KeyType = GetPidlKeyType(pidl);
|
|
DWORD dwPidlType = GetPidlType(pidl);
|
|
|
|
//
|
|
// make a fully qualified (absolute) pidl
|
|
//
|
|
|
|
// LPITEMIDLIST pidlNew = CopyCatPidl(m_pidl, pidl);
|
|
|
|
//
|
|
// free pidl associated with Next enumeration
|
|
//
|
|
|
|
// FreePidl(pidl);
|
|
|
|
//
|
|
// add item with absolute pidl to listview
|
|
//
|
|
|
|
AddListItem(m_hwndList, dwPidlType, KeyType, szText, pidl);
|
|
}
|
|
|
|
pEnumIDList->Release();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
AddListItem(
|
|
HWND hWnd,
|
|
DWORD dwType,
|
|
PST_KEY KeyType,
|
|
LPCWSTR szName,
|
|
LPITEMIDLIST pidl
|
|
)
|
|
/*++
|
|
|
|
This function is a temporary hack to support image list add/set data.
|
|
|
|
This will be replaced by an Unicode interface that operates on WinNT and
|
|
Win95 in the near future.
|
|
|
|
--*/
|
|
{
|
|
LVITEM lvItem;
|
|
int nIndex;
|
|
|
|
DWORD dwIconIndex;
|
|
|
|
//
|
|
// determine which icon to use.
|
|
// when PST_KEY is not PST_KEY_LOCAL_MACHINE, use a different folder
|
|
// icon at the type and subtype level.
|
|
//
|
|
|
|
switch(dwType) {
|
|
case PIDL_TYPE_PROVIDER:
|
|
dwIconIndex = 0;
|
|
break;
|
|
case PIDL_TYPE_TYPE:
|
|
case PIDL_TYPE_SUBTYPE:
|
|
if(KeyType == PST_KEY_CURRENT_USER)
|
|
dwIconIndex = 1;
|
|
else
|
|
dwIconIndex = 3; // global (shared) icon
|
|
break;
|
|
case PIDL_TYPE_ITEM:
|
|
dwIconIndex = 2;
|
|
break;
|
|
default:
|
|
dwIconIndex = 0;
|
|
}
|
|
|
|
ZeroMemory(&lvItem, sizeof(lvItem));
|
|
|
|
lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;
|
|
lvItem.iItem = 0;
|
|
lvItem.lParam = (LPARAM)pidl;
|
|
lvItem.pszText = (LPTSTR)szName;
|
|
lvItem.iImage = dwIconIndex; // image index
|
|
|
|
nIndex = ListView_InsertItemU(hWnd, &lvItem);
|
|
|
|
// ListView_SetItemTextU(hWnd, nIndex, 1, (LPWSTR)szValue);
|
|
|
|
return TRUE;
|
|
}
|
|
|