2025-11-28 00:35:46 +09:00

726 lines
19 KiB
C++

/**************************************************************************
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 1999 - 2000 Microsoft Corporation. All Rights Reserved.
**************************************************************************/
/**************************************************************************
File: List.cpp
Description:
**************************************************************************/
/**************************************************************************
#include statements
**************************************************************************/
#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>
#include <shlobj.h>
#include <tchar.h>
#include "EnumDesk.h"
#include "resource.h"
/**************************************************************************
function prototypes
**************************************************************************/
void List_EnumObjects(HWND, LPSHELLFOLDER, LPITEMIDLIST);
int CALLBACK List_CompareProc(LPARAM, LPARAM, LPARAM);
void List_DoDefault(HWND hwndListView, int iItem);
/**************************************************************************
global variables and definitions
**************************************************************************/
IShellFolder *g_psfCurFolder = NULL;
LPITEMIDLIST g_pidlCurFQ = NULL;
/******************************************************************************
List_Create
******************************************************************************/
HWND List_Create( HINSTANCE hInstance,
HWND hwndParent,
HIMAGELIST himlLarge,
HIMAGELIST himlSmall)
{
DWORD dwStyle;
HWND hwndListView;
dwStyle = WS_TABSTOP |
WS_CHILD |
WS_BORDER |
WS_VISIBLE |
LVS_AUTOARRANGE |
LVS_LIST |
LVS_SHAREIMAGELISTS |
LVS_SHOWSELALWAYS |
0;
hwndListView = CreateWindowEx( WS_EX_CLIENTEDGE,
WC_LISTVIEW,
NULL,
dwStyle,
0,
0,
0,
0,
hwndParent,
(HMENU)IDC_LISTVIEW,
hInstance,
NULL);
if(hwndListView)
{
//set the image lists
ListView_SetImageList(hwndListView, himlLarge, LVSIL_NORMAL);
ListView_SetImageList(hwndListView, himlSmall, LVSIL_SMALL);
}
return hwndListView;
}
/**************************************************************************
List_ReleaseCurrentFolder()
**************************************************************************/
void List_ReleaseCurrentFolder(void)
{
if(g_psfCurFolder)
{
g_psfCurFolder->Release();
g_psfCurFolder = NULL;
Pidl_Free(g_pidlCurFQ);
g_pidlCurFQ = NULL;
}
}
/**************************************************************************
List_LockCurrentFolder()
**************************************************************************/
void List_LockCurrentFolder(LPITEMINFO pItemInfo)
{
if(pItemInfo && pItemInfo->pParentFolder)
{
pItemInfo->pParentFolder->BindToObject(pItemInfo->pidlRel, NULL, IID_IShellFolder, (LPVOID*)&g_psfCurFolder);
g_pidlCurFQ = Pidl_Copy(pItemInfo->pidlFQ);
}
else
{
SHGetDesktopFolder(&g_psfCurFolder);
if(pItemInfo)
g_pidlCurFQ = Pidl_Copy(pItemInfo->pidlFQ);
}
}
/**************************************************************************
List_DisplayFolder()
**************************************************************************/
HRESULT List_DisplayFolder(HWND hwndListView, LPITEMINFO pItemInfo)
{
if(pItemInfo)
{
List_ReleaseCurrentFolder();
List_LockCurrentFolder(pItemInfo);
}
HRESULT hr = E_FAIL;
ListView_DeleteAllItems(hwndListView);
if(g_psfCurFolder)
{
HCURSOR hCur = LoadCursor(NULL, IDC_WAIT);
hCur = SetCursor(hCur);
//turn redawing off in the ListView. This will speed things up as we add items
SendMessage(hwndListView, WM_SETREDRAW, FALSE, 0);
List_EnumObjects(hwndListView, g_psfCurFolder, g_pidlCurFQ);
ListView_SortItems(hwndListView, List_CompareProc, 0);
//turn redawing back on
SendMessage(hwndListView, WM_SETREDRAW, TRUE, 0);
SetCursor(hCur);
}
return hr;
}
/**************************************************************************
List_Refresh()
**************************************************************************/
HRESULT List_Refresh(HWND hwndListView)
{
return List_DisplayFolder(hwndListView, NULL);
}
/**************************************************************************
List_Notify()
**************************************************************************/
LRESULT List_Notify(HWND hWnd, LPARAM lParam)
{
LPNMHDR pnmh = (LPNMHDR) lParam;
HWND hwndListView = GetDlgItem(hWnd, IDC_LISTVIEW);
switch(pnmh->code)
{
case LVN_GETDISPINFO:
{
NMLVDISPINFO *pdi = (NMLVDISPINFO*)lParam;
LPITEMINFO pItem = (LPITEMINFO)pdi->item.lParam;
//do we need to supply the text?
if(pdi->item.mask & LVIF_TEXT)
{
switch(pdi->item.iSubItem)
{
case 0: //name
{
SHFILEINFO sfi;
//get the display name of the item
if(SHGetFileInfo((LPCTSTR)pItem->pidlFQ, 0, &sfi, sizeof(sfi), SHGFI_PIDL | SHGFI_DISPLAYNAME))
{
_tcsncpy_s(pdi->item.pszText,
pdi->item.cchTextMax,
sfi.szDisplayName,
_TRUNCATE);
}
}
break;
case 1: //size
break;
}
}
//do we need to supply the unselected image?
if(pdi->item.mask & LVIF_IMAGE)
{
SHFILEINFO sfi;
//get the unselected image for this item
if(SHGetFileInfo((LPCTSTR)pItem->pidlFQ, 0, &sfi, sizeof(sfi), SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON | SHGFI_LINKOVERLAY))
{
pdi->item.iImage = sfi.iIcon;
}
}
}
break;
case LVN_DELETEITEM:
{
LPNMLISTVIEW pnmlv = (LPNMLISTVIEW)lParam;
LPITEMINFO pItem = (LPITEMINFO)pnmlv->lParam;
//free up the pidls that we allocated
Pidl_Free(pItem->pidlFQ);
Pidl_Free(pItem->pidlRel);
//this may be NULL if this is the root item
if(pItem->pParentFolder)
pItem->pParentFolder->Release();
GlobalFree((HGLOBAL)pItem);
}
break;
#ifdef LVN_ITEMACTIVATE
case LVN_ITEMACTIVATE:
#else //LVN_ITEMACTIVATE
case NM_DBLCLK:
case NM_RETURN:
#endif //LVN_ITEMACTIVATE
{
//get the item that has the focus
int nItem = ListView_GetNextItem(hwndListView, -1, LVNI_FOCUSED);
if(-1 != nItem)
List_DoDefault(hwndListView, nItem);
}
break;
default:
break;
}
return 0;
}
/**************************************************************************
List_EnumObjects
**************************************************************************/
void List_EnumObjects( HWND hwndListView,
LPSHELLFOLDER pParentFolder,
LPITEMIDLIST pidlParent)
{
LPENUMIDLIST pEnum;
if(SUCCEEDED(pParentFolder->EnumObjects( NULL,
SHCONTF_FOLDERS |
SHCONTF_NONFOLDERS |
SHCONTF_INCLUDEHIDDEN,
&pEnum)))
{
LPITEMIDLIST pidlTemp;
DWORD dwFetched = 1;
LPITEMINFO pItem;
//enumerate the item's PIDLs
while(S_OK == (pEnum->Next(1, &pidlTemp, &dwFetched)) && dwFetched)
{
LVITEM lvItem;
DWORD dwAttr;
ZeroMemory(&lvItem, sizeof(lvItem));
//fill in the TV_ITEM structure for this item
lvItem.mask = LVIF_PARAM | LVIF_TEXT | LVIF_IMAGE | LVIF_STATE;
//AddRef the parent folder so it's pointer stays valid
pParentFolder->AddRef();
//put the private information in the lParam
pItem = (LPITEMINFO)GlobalAlloc(GPTR, sizeof(ITEMINFO));
pItem->pidlRel = pidlTemp;
pItem->pidlFQ = Pidl_Concatenate(pidlParent, pidlTemp);
pItem->pParentFolder = pParentFolder;
lvItem.lParam = (LPARAM)pItem;
//text and images are done on a callback basis
lvItem.pszText = LPSTR_TEXTCALLBACK;
lvItem.iImage = I_IMAGECALLBACK;
//determine if the item is shared
dwAttr = SFGAO_DISPLAYATTRMASK;
pParentFolder->GetAttributesOf(1, (LPCITEMIDLIST*)&pidlTemp, &dwAttr);
if(dwAttr & SFGAO_SHARE)
{
lvItem.mask |= LVIF_STATE;
lvItem.stateMask |= LVIS_OVERLAYMASK;
lvItem.state |= INDEXTOOVERLAYMASK(1); //1 is the index for the shared overlay image
}
if(dwAttr & SFGAO_GHOSTED)
{
lvItem.mask |= LVIF_STATE;
lvItem.stateMask |= LVIS_CUT;
lvItem.state |= LVIS_CUT;
}
ListView_InsertItem(hwndListView, &lvItem);
dwFetched = 0;
}
pEnum->Release();
}
}
/**************************************************************************
List_CompareProc
**************************************************************************/
int CALLBACK List_CompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
UNREFERENCED_PARAMETER(lParamSort);
LPITEMINFO pItem1 = (LPITEMINFO)lParam1;
LPITEMINFO pItem2 = (LPITEMINFO)lParam2;
HRESULT hr;
hr = pItem1->pParentFolder->CompareIDs( 0,
pItem1->pidlRel,
pItem2->pidlRel);
if(FAILED(hr))
return 0;
return (short)SCODE_CODE(GetScode(hr));
}
/**************************************************************************
List_DoItemMenu
**************************************************************************/
void List_DoItemMenu( HWND hwndListView,
LPINT piItems,
UINT cbItems,
LPPOINT pptScreen)
{
LPITEMIDLIST *pPidls;
pPidls = (LPITEMIDLIST*)g_pMalloc->Alloc(sizeof(LPITEMIDLIST) * cbItems);
if(!pPidls)
return;
LVITEM lvItem;
UINT i;
for(i = 0; i < cbItems; i++)
{
ZeroMemory(&lvItem, sizeof(lvItem));
lvItem.mask = LVIF_PARAM;
lvItem.iItem = piItems[i];
if(ListView_GetItem(hwndListView, &lvItem))
{
LPITEMINFO pInfo = (LPITEMINFO)lvItem.lParam;
pPidls[i] = pInfo->pidlRel;
}
}
if(pPidls[0])
{
HRESULT hr;
IContextMenu *pcm;
if(g_psfCurFolder)
{
hr = g_psfCurFolder->GetUIObjectOf( hwndListView,
cbItems,
(LPCITEMIDLIST*)pPidls,
IID_IContextMenu,
NULL,
(LPVOID*)&pcm);
if(SUCCEEDED(hr))
{
HMENU hPopup;
hPopup = CreatePopupMenu();
if(hPopup)
{
hr = pcm->QueryContextMenu(hPopup, 0, 1, 0x7fff, CMF_NORMAL | CMF_EXPLORE);
if(SUCCEEDED(hr))
{
pcm->QueryInterface(IID_IContextMenu2, (LPVOID*)&g_pcm2);
UINT idCmd;
idCmd = TrackPopupMenu( hPopup,
TPM_LEFTALIGN | TPM_RETURNCMD | TPM_RIGHTBUTTON,
pptScreen->x,
pptScreen->y,
0,
GetParent(hwndListView),
NULL);
if(g_pcm2)
{
g_pcm2->Release();
g_pcm2 = NULL;
}
if(idCmd)
{
CMINVOKECOMMANDINFO cmi;
cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
cmi.fMask = 0;
cmi.hwnd = (HWND)GetParent(hwndListView);
cmi.lpVerb = (LPCSTR)(INT_PTR)(idCmd - 1);
cmi.lpParameters = NULL;
cmi.lpDirectory = NULL;
cmi.nShow = SW_SHOWNORMAL;
cmi.dwHotKey = 0;
cmi.hIcon = NULL;
hr = pcm->InvokeCommand(&cmi);
/*
The operation performed by the context menu may have changed
the contents of the folder, so do a refresh.
*/
List_Refresh(hwndListView);
}
}
}
pcm->Release();
}
}
}
g_pMalloc->Free(pPidls);
}
/**************************************************************************
List_DoBackgroundMenu
**************************************************************************/
void List_DoBackgroundMenu(HWND hwndListView, LPPOINT pptScreen)
{
HWND hwndParent = GetParent(hwndListView);
HRESULT hr;
if(g_psfCurFolder)
{
IContextMenu *pcm;
hr = g_psfCurFolder->CreateViewObject( hwndParent,
IID_IContextMenu,
(LPVOID*)&pcm);
if(SUCCEEDED(hr))
{
HMENU hMenu;
hMenu = LoadMenu(g_hInst, MAKEINTRESOURCE(IDM_MAIN_MENU));
if(hMenu)
{
HMENU hPopup;
hPopup = GetSubMenu(hMenu, 1);
if(hPopup)
{
int i;
UINT idCmdFirst;
UINT idCmd;
//find the largest ID in the menu
i = 0;
idCmdFirst = 0;
while((idCmd = GetMenuItemID(hPopup, i)) != (UINT)-1)
{
if(idCmd > idCmdFirst)
idCmdFirst = idCmd;
i++;
}
hr = pcm->QueryContextMenu(hPopup, 0, ++idCmdFirst, (UINT)-1, CMF_NORMAL | CMF_EXPLORE);
if(SUCCEEDED(hr))
{
pcm->QueryInterface(IID_IContextMenu2, (LPVOID*)&g_pcm2);
idCmd = TrackPopupMenu( hPopup,
TPM_LEFTALIGN | TPM_RETURNCMD | TPM_RIGHTBUTTON,
pptScreen->x,
pptScreen->y,
0,
hwndParent,
NULL);
if(g_pcm2)
{
g_pcm2->Release();
g_pcm2 = NULL;
}
if(idCmd)
{
if(idCmd < idCmdFirst)
{
//this is one of our commands
FORWARD_WM_COMMAND(hwndParent, idCmd, NULL, 0, SendMessage);
}
else
{
CMINVOKECOMMANDINFO cmi;
cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
cmi.fMask = 0;
cmi.hwnd = hwndParent;
cmi.lpVerb = (LPCSTR)(INT_PTR)(idCmd - idCmdFirst);
cmi.lpParameters = NULL;
cmi.lpDirectory = NULL;
cmi.nShow = SW_SHOWNORMAL;
cmi.dwHotKey = 0;
cmi.hIcon = NULL;
hr = pcm->InvokeCommand(&cmi);
/*
The operation performed by the context menu may have
changed the contents of the folder, so do a refresh.
*/
List_Refresh(hwndListView);
}
}
}
}
DestroyMenu(hMenu);
}
pcm->Release();
}
}
}
/**************************************************************************
List_DoContextMenu
**************************************************************************/
void List_DoContextMenu(HWND hwndListView, LPPOINT pptScreen)
{
LVHITTESTINFO lvhti;
lvhti.pt = *pptScreen;
ScreenToClient(hwndListView, &lvhti.pt);
lvhti.flags = LVHT_NOWHERE;
ListView_HitTest(hwndListView, &lvhti);
if(LVHT_ONITEM & lvhti.flags)
{
//get the selected items
UINT nItems = ListView_GetSelectedCount(hwndListView);
LPINT pItems = (LPINT)GlobalAlloc(GPTR, sizeof(int) * nItems);
if(pItems)
{
UINT i;
int nCurItem;
//put the item clicked on first in the list
pItems[0] = lvhti.iItem;
for(i = 1, nCurItem = -1; i < nItems; i++)
{
nCurItem = ListView_GetNextItem(hwndListView, nCurItem, LVNI_SELECTED);
if(nCurItem != lvhti.iItem)
pItems[i] = nCurItem;
else
i--;
}
List_DoItemMenu(hwndListView, pItems, nItems, pptScreen);
GlobalFree(pItems);
}
}
else
{
List_DoBackgroundMenu(hwndListView, pptScreen);
}
}
/**************************************************************************
List_DoDefault
**************************************************************************/
void List_DoDefault(HWND hwndListView, int iItem)
{
LVITEM lvItem;
ZeroMemory(&lvItem, sizeof(lvItem));
lvItem.mask = LVIF_PARAM;
lvItem.iItem = iItem;
if(ListView_GetItem(hwndListView, &lvItem))
{
HRESULT hr;
LPITEMINFO pInfo = (LPITEMINFO)lvItem.lParam;
IContextMenu *pcm;
IShellFolder *psfFolder = pInfo->pParentFolder;
if(!psfFolder)
{
SHGetDesktopFolder(&psfFolder);
}
else
{
psfFolder->AddRef();
}
if(psfFolder)
{
hr = psfFolder->GetUIObjectOf( hwndListView,
1,
(LPCITEMIDLIST*)&pInfo->pidlRel,
IID_IContextMenu,
NULL,
(LPVOID*)&pcm);
if(SUCCEEDED(hr))
{
HMENU hPopup;
hPopup = CreatePopupMenu();
if(hPopup)
{
hr = pcm->QueryContextMenu(hPopup, 0, 1, 0x7fff, CMF_DEFAULTONLY | CMF_EXPLORE);
if(SUCCEEDED(hr))
{
UINT idCmd;
idCmd = GetMenuItemID(hPopup, 0);
if(idCmd && (idCmd != (UINT)-1))
{
CMINVOKECOMMANDINFO cmi;
cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
cmi.fMask = 0;
cmi.hwnd = GetParent(hwndListView);
cmi.lpVerb = (LPCSTR)(INT_PTR)(idCmd - 1);
cmi.lpParameters = NULL;
cmi.lpDirectory = NULL;
cmi.nShow = SW_SHOWNORMAL;
cmi.dwHotKey = 0;
cmi.hIcon = NULL;
hr = pcm->InvokeCommand(&cmi);
}
}
}
pcm->Release();
}
psfFolder->Release();
}
}
}