📄 dlapi.c
字号:
/******************************************************************************
*
*
* Notepad2
*
* Dlapi.c
* Directory Listing APIs used in Notepad2
*
* See Readme.txt for more information about this source code.
* Please send me your comments to this work.
*
* See License.txt for details about distribution and modification.
*
* (c) Florian Balmer 1996-2008
* florian.balmer@gmail.com
* http://www.flos-freeware.ch
*
*
******************************************************************************/
#include <windows.h>
#include <commctrl.h>
#include <shlobj.h>
#include <shlwapi.h>
#include <string.h>
#include "dlapi.h"
//==== Global LPMALLOC instance ===============================================
extern LPMALLOC g_lpMalloc;
//==== DirList ================================================================
//==== DLDATA Structure =======================================================
typedef struct tagDLDATA // dl
{
HWND hwnd; // HWND of ListView Control
UINT cbidl; // Size of pidl
LPITEMIDLIST pidl; // Directory Id
LPSHELLFOLDER lpsf; // IShellFolder Interface to pidl
char szPath[MAX_PATH]; // Pathname to Directory Id
int iDefIconFolder; // Default Folder Icon
int iDefIconFile; // Default File Icon
BOOL bNoFadeHidden; // Flag passed from GetDispInfo()
HANDLE hExitThread; // Flag is set when Icon Thread should terminate
HANDLE hTerminatedThread; // Flag is set when Icon Thread has terminated
} DLDATA, *LPDLDATA;
//==== Property Name ==========================================================
static const char *pDirListProp = "DirListData";
//=============================================================================
//
// DirList_Init()
//
// Initializes the DLDATA structure and sets up the listview control
//
BOOL DirList_Init(HWND hwnd,LPCSTR pszHeader)
{
HIMAGELIST hil;
SHFILEINFO shfi;
LV_COLUMN lvc;
// Allocate DirListData Property
LPDLDATA lpdl = (LPVOID)GlobalAlloc(GPTR,sizeof(DLDATA));
SetProp(hwnd,pDirListProp,(HANDLE)lpdl);
// Setup dl
lpdl->hwnd = hwnd;
lpdl->cbidl = 0;
lpdl->pidl = NULL;
lpdl->lpsf = NULL;
lstrcpy(lpdl->szPath,"");
// Add Imagelists
hil = (HIMAGELIST)SHGetFileInfo("C:\\",0,&shfi,sizeof(SHFILEINFO),
SHGFI_SMALLICON | SHGFI_SYSICONINDEX);
ListView_SetImageList(hwnd,hil,LVSIL_SMALL);
hil = (HIMAGELIST)SHGetFileInfo("C:\\",0,&shfi,sizeof(SHFILEINFO),
SHGFI_LARGEICON | SHGFI_SYSICONINDEX);
ListView_SetImageList(hwnd,hil,LVSIL_NORMAL);
// Initialize default icons - done in DirList_Fill()
//SHGetFileInfo("Icon",FILE_ATTRIBUTE_DIRECTORY,&shfi,sizeof(SHFILEINFO),
// SHGFI_USEFILEATTRIBUTES | SHGFI_SMALLICON | SHGFI_SYSICONINDEX);
//lpdl->iDefIconFolder = shfi.iIcon;
//SHGetFileInfo("Icon",FILE_ATTRIBUTE_NORMAL,&shfi,sizeof(SHFILEINFO),
// SHGFI_USEFILEATTRIBUTES | SHGFI_SMALLICON | SHGFI_SYSICONINDEX);
//lpdl->iDefIconFile = shfi.iIcon;
lpdl->iDefIconFolder = 0;
lpdl->iDefIconFile = 0;
// Icon thread control
lpdl->hExitThread = CreateEvent(NULL,TRUE,FALSE,NULL);
lpdl->hTerminatedThread = CreateEvent(NULL,TRUE,TRUE,NULL);
lvc;
pszHeader;
return TRUE;
}
//=============================================================================
//
// DirList_Destroy()
//
// Free memory used by dl structure
//
BOOL DirList_Destroy(HWND hwnd)
{
//LPMALLOC lpMalloc;
LPDLDATA lpdl = (LPVOID)GetProp(hwnd,pDirListProp);
// Release multithreading objects
DirList_TerminateIconThread(hwnd);
CloseHandle(lpdl->hExitThread);
CloseHandle(lpdl->hTerminatedThread);
//if (NOERROR == SHGetMalloc(&lpMalloc))
//{
if (lpdl->pidl)
g_lpMalloc->lpVtbl->Free(g_lpMalloc,lpdl->pidl);
//lpMalloc->lpVtbl->Release(lpMalloc);
if (lpdl->lpsf)
lpdl->lpsf->lpVtbl->Release(lpdl->lpsf);
//}
// Free DirListData Property
RemoveProp(hwnd,pDirListProp);
GlobalFree(lpdl);
return FALSE;
}
//=============================================================================
//
// DirList_StartIconThread()
//
// Start thread to extract file icons in the background
//
BOOL DirList_StartIconThread(HWND hwnd)
{
DWORD dwtid;
LPDLDATA lpdl = (LPVOID)GetProp(hwnd,pDirListProp);
DirList_TerminateIconThread(hwnd);
ResetEvent(lpdl->hExitThread);
//ResetEvent(lpdl->hTerminatedThread);
CreateThread(NULL,0,DirList_IconThread,(LPVOID)lpdl,0,&dwtid);
return TRUE;
}
//=============================================================================
//
// DirList_TerminateIconThread()
//
// Terminate Icon Thread and reset multithreading control structures
//
BOOL DirList_TerminateIconThread(HWND hwnd)
{
LPDLDATA lpdl = (LPVOID)GetProp(hwnd,pDirListProp);
SetEvent(lpdl->hExitThread);
//WaitForSingleObject(lpdl->hTerminatedThread,INFINITE);
while (WaitForSingleObject(lpdl->hTerminatedThread,0) != WAIT_OBJECT_0)
{
MSG msg;
if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
ResetEvent(lpdl->hExitThread);
SetEvent(lpdl->hTerminatedThread);
return TRUE;
}
//=============================================================================
//
// DirList_Fill()
//
// Snapshots a directory and displays the items in the listview control
//
int DirList_Fill(HWND hwnd,LPCSTR lpszDir,DWORD grfFlags,LPCSTR lpszFileSpec,
BOOL bExcludeFilter,BOOL bNoFadeHidden,
int iSortFlags,BOOL fSortRev)
{
WCHAR wszDir[MAX_PATH];
//LPMALLOC lpMalloc = NULL;
LPSHELLFOLDER lpsfDesktop = NULL;
LPSHELLFOLDER lpsf = NULL;
LPITEMIDLIST pidl = NULL;
LPITEMIDLIST pidlEntry = NULL;
LPENUMIDLIST lpe = NULL;
LV_ITEM lvi;
LPLV_ITEMDATA lplvid;
ULONG chParsed = 0;
ULONG dwAttributes = 0;
DL_FILTER dlf;
SHFILEINFO shfi;
LPDLDATA lpdl = (LPVOID)GetProp(hwnd,pDirListProp);
// Initialize default icons
SHGetFileInfo("Icon",FILE_ATTRIBUTE_DIRECTORY,&shfi,sizeof(SHFILEINFO),
SHGFI_USEFILEATTRIBUTES | SHGFI_SMALLICON | SHGFI_SYSICONINDEX);
lpdl->iDefIconFolder = shfi.iIcon;
SHGetFileInfo("Icon",FILE_ATTRIBUTE_NORMAL,&shfi,sizeof(SHFILEINFO),
SHGFI_USEFILEATTRIBUTES | SHGFI_SMALLICON | SHGFI_SYSICONINDEX);
lpdl->iDefIconFile = shfi.iIcon;
// First of all terminate running icon thread
DirList_TerminateIconThread(hwnd);
// A Directory is strongly required
if (!lpszDir || !*lpszDir)
return(-1);
lstrcpy(lpdl->szPath,lpszDir);
// Init ListView
SendMessage(hwnd,WM_SETREDRAW,0,0);
ListView_DeleteAllItems(hwnd);
// Init Filter
DirList_CreateFilter(&dlf,lpszFileSpec,bExcludeFilter);
// Init lvi
lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;
lvi.iItem = 0;
lvi.iSubItem = 0;
lvi.pszText = LPSTR_TEXTCALLBACK;
lvi.cchTextMax = MAX_PATH;
lvi.iImage = I_IMAGECALLBACK;
// Convert Directory to a UNICODE string
MultiByteToWideChar(CP_ACP,
MB_PRECOMPOSED,
lpszDir,
-1,
wszDir,
MAX_PATH);
// Get Shell's IMalloc Interface
//if (NOERROR == SHGetMalloc(&lpMalloc))
//{
// Get Desktop Folder
if (NOERROR == SHGetDesktopFolder(&lpsfDesktop))
{
// Convert wszDir into a pidl
if (NOERROR == lpsfDesktop->lpVtbl->ParseDisplayName(
lpsfDesktop,
hwnd,
NULL,
wszDir,
&chParsed,
&pidl,
&dwAttributes))
{
// Bind pidl to IShellFolder
if (NOERROR == lpsfDesktop->lpVtbl->BindToObject(
lpsfDesktop,
pidl,
NULL,
&IID_IShellFolder,
&lpsf))
{
// Create an Enumeration object for lpsf
if (NOERROR == lpsf->lpVtbl->EnumObjects(
lpsf,
hwnd,
grfFlags,
&lpe))
{
// Enumerate the contents of lpsf
while (NOERROR == lpe->lpVtbl->Next(
lpe,
1,
&pidlEntry,
NULL))
{
// Add found item to the List
// Check if it's part of the Filesystem
dwAttributes = SFGAO_FILESYSTEM | SFGAO_FOLDER;
lpsf->lpVtbl->GetAttributesOf(
lpsf,
1,
&pidlEntry,
&dwAttributes);
if (dwAttributes & SFGAO_FILESYSTEM)
{
// Check if item matches specified filter
if (DirList_MatchFilter(lpsf,pidlEntry,&dlf))
{
lplvid = g_lpMalloc->lpVtbl->Alloc(
g_lpMalloc,
sizeof(LV_ITEMDATA));
lplvid->pidl = pidlEntry;
lplvid->lpsf = lpsf;
lpsf->lpVtbl->AddRef(lpsf);
lvi.lParam = (LPARAM)lplvid;
// Setup default Icon - Folder or File
lvi.iImage = (dwAttributes & SFGAO_FOLDER) ?
lpdl->iDefIconFolder : lpdl->iDefIconFile;
ListView_InsertItem(hwnd,&lvi);
lvi.iItem++;
}
}
//lpMalloc->lpVtbl->Free(lpMalloc,pidlEntry);
} // IEnumIDList::Next()
lpe->lpVtbl->Release(lpe);
} // IShellFolder::EnumObjects()
} // IShellFolder::BindToObject()
} // IShellFolder::ParseDisplayName()
lpsfDesktop->lpVtbl->Release(lpsfDesktop);
} // SHGetDesktopFolder()
if (lpdl->pidl)
g_lpMalloc->lpVtbl->Free(g_lpMalloc,lpdl->pidl);
if (lpdl->lpsf && lpdl->lpsf->lpVtbl)
lpdl->lpsf->lpVtbl->Release(lpdl->lpsf);
//lpMalloc->lpVtbl->Release(lpMalloc);
//} // SHGetMalloc()
// Set lpdl
lpdl->cbidl = IL_GetSize(pidl);
lpdl->pidl = pidl;
lpdl->lpsf = lpsf;
lpdl->bNoFadeHidden = bNoFadeHidden;
// Set column width to fit window
ListView_SetColumnWidth(hwnd,0,LVSCW_AUTOSIZE_USEHEADER);
// Sort before display is updated
DirList_Sort(hwnd,iSortFlags,fSortRev);
// Redraw Listview
SendMessage(hwnd,WM_SETREDRAW,1,0);
// Return number of items in the control
return (ListView_GetItemCount(hwnd));
}
//=============================================================================
//
// DirList_IconThread()
//
// Thread to extract file icons in the background
//
DWORD WINAPI DirList_IconThread(LPVOID lpParam)
{
HWND hwnd;
LPDLDATA lpdl;
LV_ITEM lvi;
LPLV_ITEMDATA lplvid;
LPMALLOC lpMalloc;
LPSHELLICON lpshi;
int iItem = 0;
int iMaxItem;
lpdl = (LPDLDATA)lpParam;
ResetEvent(lpdl->hTerminatedThread);
// Exit immediately if DirList_Fill() hasn't been called
if (!lpdl->lpsf) {
SetEvent(lpdl->hTerminatedThread);
ExitThread(0);
return(0);
}
hwnd = lpdl->hwnd;
iMaxItem = ListView_GetItemCount(hwnd);
CoInitialize(NULL);
SHGetMalloc(&lpMalloc);
// Get IShellIcon
lpdl->lpsf->lpVtbl->QueryInterface(lpdl->lpsf,&IID_IShellIcon,&lpshi);
while (iItem < iMaxItem && WaitForSingleObject(lpdl->hExitThread,0) != WAIT_OBJECT_0) {
lvi.iItem = iItem;
lvi.mask = LVIF_PARAM;
if (ListView_GetItem(hwnd,&lvi)) {
SHFILEINFO shfi;
LPITEMIDLIST pidl;
DWORD dwAttributes = SFGAO_LINK | SFGAO_SHARE;
lplvid = (LPLV_ITEMDATA)lvi.lParam;
lvi.mask = LVIF_IMAGE;
if (!lpshi || NOERROR != lpshi->lpVtbl->GetIconOf(lpshi,lplvid->pidl,GIL_FORSHELL,&lvi.iImage))
{
pidl = IL_Create(lpMalloc,lpdl->pidl,lpdl->cbidl,lplvid->pidl,0);
SHGetFileInfo((LPCSTR)pidl,0,&shfi,sizeof(SHFILEINFO),SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON);
lpMalloc->lpVtbl->Free(lpMalloc,pidl);
lvi.iImage = shfi.iIcon;
}
// It proved necessary to reset the state bits...
lvi.stateMask = 0;
lvi.state = 0;
// Link and Share Overlay
lplvid->lpsf->lpVtbl->GetAttributesOf(
lplvid->lpsf,
1,&lplvid->pidl,
&dwAttributes);
if (dwAttributes & SFGAO_LINK)
{
lvi.mask |= LVIF_STATE;
lvi.stateMask |= LVIS_OVERLAYMASK;
lvi.state |= INDEXTOOVERLAYMASK(2);
}
if (dwAttributes & SFGAO_SHARE)
{
lvi.mask |= LVIF_STATE;
lvi.stateMask |= LVIS_OVERLAYMASK;
lvi.state |= INDEXTOOVERLAYMASK(1);
}
// Fade hidden/system files
if (!lpdl->bNoFadeHidden)
{
WIN32_FIND_DATA fd;
if (NOERROR == SHGetDataFromIDList(lplvid->lpsf,lplvid->pidl,
SHGDFIL_FINDDATA,&fd,sizeof(WIN32_FIND_DATA)))
{
if ((fd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) ||
(fd.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM))
{
lvi.mask |= LVIF_STATE;
lvi.stateMask |= LVIS_CUT;
lvi.state |= LVIS_CUT;
}
}
}
//MessageBox(NULL,NULL,NULL,MB_ICONWARNING);
lvi.iSubItem = 0;
ListView_SetItem(hwnd,&lvi);
}
iItem++;
}
if (lpshi)
lpshi->lpVtbl->Release(lpshi);
lpMalloc->lpVtbl->Release(lpMalloc);
CoUninitialize();
SetEvent(lpdl->hTerminatedThread);
ExitThread(0);
return(0);
}
//=============================================================================
//
// DirList_GetDispInfo()
//
// Must be called in response to a WM_NOTIFY/LVN_GETDISPINFO message from
// the listview control
//
BOOL DirList_GetDispInfo(HWND hwnd,LPARAM lParam,BOOL bNoFadeHidden)
{
LPDLDATA lpdl = (LPVOID)GetProp(hwnd,pDirListProp);
LV_DISPINFO *lpdi = (LPVOID)lParam;
LPLV_ITEMDATA lplvid = (LPLV_ITEMDATA)lpdi->item.lParam;
// SubItem 0 is handled only
if (lpdi->item.iSubItem != 0)
return FALSE;
// Text
if (lpdi->item.mask & LVIF_TEXT)
IL_GetDisplayName(lplvid->lpsf,lplvid->pidl,SHGDN_INFOLDER,
lpdi->item.pszText,lpdi->item.cchTextMax);
// Image
//if (lpdi->item.mask & LVIF_IMAGE)
//{
// //LPMALLOC lpMalloc;
// SHFILEINFO shfi;
// LPITEMIDLIST pidl;
// DWORD dwAttributes = SFGAO_LINK | SFGAO_SHARE;
// //if (NOERROR == SHGetMalloc(&lpMalloc))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -