mirror of https://github.com/lianthony/NT4.0
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.
4889 lines
148 KiB
4889 lines
148 KiB
#include "shellprv.h"
|
|
#pragma hdrstop
|
|
#include <regstr.h>
|
|
|
|
// Debug
|
|
|
|
// #define FIND_TRACE
|
|
|
|
#define ID_LISTVIEW 1
|
|
|
|
|
|
#define WM_DF_THREADNOTIFY (WM_USER + 42)
|
|
#define WM_DF_FSNOTIFY (WM_USER + 43)
|
|
|
|
#define DF_CURFILEVER 3
|
|
#define DF_MAX_MATCHFILES 10000
|
|
|
|
|
|
#pragma data_seg(".text", "CODE")
|
|
const UINT c_auDFMenuIDs[] = {
|
|
FCIDM_MENU_FILE,
|
|
FCIDM_MENU_EDIT,
|
|
FCIDM_MENU_VIEW,
|
|
IDM_MENU_OPTIONS,
|
|
FCIDM_MENU_HELP
|
|
};
|
|
|
|
ITEMIDLIST s_idlEmpty = {0};
|
|
const WORD s_mkidBlank[3] = {DF_APPENDSIZE, 0, 0}; // Actually one byte wasted..
|
|
|
|
const TCHAR s_szDocFind[]= TEXT("DocFind");
|
|
const TCHAR s_szFlags[] = TEXT("Flags");
|
|
const TCHAR s_szDocSpecMRU[] = REGSTR_PATH_EXPLORER TEXT("\\Doc Find Spec MRU");
|
|
|
|
#ifdef WINNT
|
|
//
|
|
// Unicode descriptor:
|
|
//
|
|
// Structure written at the end of NT-generated find stream serves dual purpose.
|
|
// 1. Contains an NT-specific signature to identify stream as NT-generated.
|
|
// Appears as "NTFF" (NT Find File) in ASCII dump of file.
|
|
// 2. Contains an offset to the unicode-formatted criteria section.
|
|
//
|
|
// The following diagram shows the find criteria/results stream format including
|
|
// the NT-specific unicode criteria and descriptor.
|
|
//
|
|
// +-----------------------------------------+ --------------
|
|
// | DFHEADER structure | . .
|
|
// +-----------------------------------------+ . .
|
|
// | DF Criteria records (ANSI) | Win95 .
|
|
// +-----------------------------------------+ . .
|
|
// | DF Results (PIDL) [optional] | . NT
|
|
// +-----------------------------------------+ ------- .
|
|
// +----->| DF Criteria records (Unicode) [NT only] | .
|
|
// | +-----------------------------------------+ .
|
|
// | | Unicode Descriptor | .
|
|
// | +--------------------+ ----------------------------------
|
|
// | / \
|
|
// | / \
|
|
// | +-----------------+---------+
|
|
// +---| Offset (64-bit) | "NTFF" |
|
|
// +-----------------+---------+
|
|
//
|
|
//
|
|
|
|
const DWORD c_NTsignature = 0x4646544E; // "NTFF" in ASCII file dump.
|
|
|
|
typedef struct _dfc_unicode_desc {
|
|
ULARGE_INTEGER oUnicodeCriteria; // Offset of unicode find criteria.
|
|
DWORD NTsignature; // Signature of NT-generated find file.
|
|
} DFC_UNICODE_DESC;
|
|
|
|
#endif
|
|
|
|
static const DWORD aFindHelpIDs[] = {
|
|
IDD_PAGELIST, NO_HELP,
|
|
IDD_ANIMATE, NO_HELP,
|
|
IDD_STATUS, NO_HELP,
|
|
IDD_START, IDH_FINDFILENAME_FINDNOW,
|
|
IDD_STOP, IDH_FINDFILENAME_STOP,
|
|
IDD_NEWSEARCH, IDH_FINDFILENAME_NEWSEARCH,
|
|
ID_LISTVIEW, IDH_FINDFILENAME_STATUSSCREEN,
|
|
|
|
0, 0
|
|
};
|
|
|
|
#pragma data_seg()
|
|
|
|
//===========================================================================
|
|
// Setup the column number definitions. - This may need to be converted
|
|
// into somethings that is filter related...
|
|
//===========================================================================
|
|
enum
|
|
{
|
|
IDFCOL_NAME = 0,
|
|
IDFCOL_PATH,
|
|
IDFCOL_SIZE,
|
|
IDFCOL_TYPE,
|
|
IDFCOL_MODIFIED,
|
|
IDFCOL_MAX, // Make sure this is the last enum item
|
|
} ;
|
|
|
|
const UINT s_auMapDFColToFSCol[] =
|
|
{0, (UINT)-1, 1, 2, 3, 4, 5, 6}; // More items than are needed but...
|
|
|
|
BOOL Reg_SetStruct(HKEY hkey, LPCTSTR pszSubKey, LPCTSTR pszValue, LPVOID lpData, DWORD cbData);
|
|
BOOL Reg_GetStruct(HKEY hkey, LPCTSTR pszSubKey, LPCTSTR pszValue, LPVOID pData, DWORD *pcbData);
|
|
|
|
BOOL DocFind_ClearSearch(HWND hwndDlg);
|
|
BOOL DocFind_DoFind(HWND hwndDlg);
|
|
|
|
void DocFind_ProcessThreadNotify(HWND hwndDlg, WPARAM wParam, LPARAM lParam);
|
|
DWORD CALLBACK DocFind_ThreadProc(LPVOID lpThreadParameters);
|
|
|
|
|
|
//===========================================================================
|
|
// Forward definition of types and functions.
|
|
//===========================================================================
|
|
typedef struct _CDFFolder FAR* LPDFFOLDER;
|
|
typedef struct _CDFBrowse FAR* LPDFBROWSE;
|
|
|
|
|
|
BOOL DocFind_ReadHeader(LPDFBROWSE pdfb, IStream **ppstm,
|
|
DFHEADER *pdfh);
|
|
BOOL DocFind_ReadCriteriaAndResults(LPDFBROWSE pdfb,
|
|
IStream * pstm, DFHEADER * pdfh);
|
|
|
|
#define DocFind_GetPdfb(hwndDlg) (LPDFBROWSE)GetWindowLong(hwndDlg, DWL_USER)
|
|
void DocFind_UpdateFilter(LPDFBROWSE pdfb);
|
|
void DocFind_ShowResultsWindow(LPDFBROWSE pdfb, BOOL fShow);
|
|
LRESULT _CDFBrowse_OnNotify(HWND hwndDlg, LPNMHDR lpnm);
|
|
|
|
|
|
HRESULT CDFFolder_Create(IDocFindFileFilter * pdfff,
|
|
HWND hwndDlg, LPVOID FAR* ppvOut);
|
|
|
|
|
|
//===========================================================================
|
|
typedef struct _DFInit // dfi
|
|
{
|
|
IDocFindFileFilter * pdfff; // The file filter to use...
|
|
LPCITEMIDLIST pidlStart; // The idlist to start at
|
|
LPCITEMIDLIST pidlSaveFile; // The file that has data in it.
|
|
|
|
} DFINIT, *LPDFINIT;
|
|
|
|
//===========================================================================
|
|
// Each find thread that gets spawned will have an assoc. FINDTHREAD struct
|
|
//===========================================================================
|
|
typedef struct _findthread {
|
|
LPDFBROWSE pdfb; // Ptr back to spawning doc find browse info
|
|
BOOL fContinue; // Termination signal
|
|
UINT iSearchCnt;
|
|
} FINDTHREAD, *PFINDTHREAD;
|
|
|
|
|
|
//===========================================================================
|
|
// Docfind Browser Class definition.
|
|
//===========================================================================
|
|
typedef struct _CDFBrowse // dfb
|
|
{
|
|
IShellBrowser sb;
|
|
UINT cRef; // reference count
|
|
IShellFolder FAR* pdfc; // Doc Find Folder
|
|
IShellView * psv; // current browser object
|
|
|
|
FOLDERSETTINGS fs; // View info for the docfind.
|
|
|
|
HWND hwndDlg; // Top level Dialog
|
|
HWND hwndView; // View window
|
|
|
|
HWND hwndStatus;
|
|
HWND hwndTabs;
|
|
HWND hwndCurPage;
|
|
|
|
HMENU hmenuCur; // Current menu
|
|
HMENU hmenuTemplate; // Menu template (to be merged)
|
|
|
|
PFINDTHREAD pft;
|
|
UINT iSearchCnt;
|
|
|
|
BOOL fDirChanged : 1;
|
|
BOOL fFilesAdded : 1;
|
|
BOOL fDirChangedSinceAdd : 1;// We changed directories since the last add.
|
|
BOOL fDefaultFilter : 1;
|
|
BOOL fNotifyPosted : 1; // Has a notify been posted?
|
|
|
|
// Note: this used to have a :1 but does not match real bools...
|
|
BOOL fContinue; // Signal from primary thread to work thread.
|
|
BOOL fShowResults; // Should we show results?
|
|
int iWaitCount; // Should we show wait cursor
|
|
|
|
// variables associated with the search.
|
|
HDPA hdpaItemsToAdd; // Items to add to dpa.
|
|
HDPA hdpaPrevAdd; // Previous dpa ptr.
|
|
|
|
int cItemsAdded;
|
|
int cItemsSearched;
|
|
int cFldrsSearched;
|
|
DWORD dwLastUpdateTime;
|
|
|
|
// Used by the filter to put progress text into, which we can display
|
|
// to give the user some idea things are happening.
|
|
TCHAR szProgressText[CCHPATHMAX];
|
|
|
|
DWORD dwFlags;
|
|
int SortMode;
|
|
int cyNoResults; // the cy when there are no results;
|
|
LPITEMIDLIST pidlStart; // Were to start search from.
|
|
LPITEMIDLIST pidlSaveFile; // Where to save file to.
|
|
|
|
CRITICAL_SECTION csSearch;
|
|
|
|
// Pointer to docfind filter interface
|
|
IDocFindFileFilter * pdfff; // The file filter to use...
|
|
} CDFBrowse, * LPDFBROWSE;
|
|
|
|
//===========================================================================
|
|
// Docfind Browser vtbl definition
|
|
//===========================================================================
|
|
|
|
|
|
// Forward define all the vtbl entries
|
|
HRESULT STDMETHODCALLTYPE CDFBrowse_QueryInterface(
|
|
IShellBrowser * psb, REFIID riid, LPVOID FAR* ppvObj);
|
|
ULONG STDMETHODCALLTYPE CDFBrowse_AddRef(IShellBrowser * psb);
|
|
ULONG STDMETHODCALLTYPE CDFBrowse_Release(IShellBrowser * psb);
|
|
STDMETHODIMP CDFBrowse_GetWindow(LPSHELLBROWSER psb, HWND FAR* phwnd);
|
|
STDMETHODIMP CDFBrowse_ContextSensitiveHelp(LPSHELLBROWSER psb, BOOL fEnable);
|
|
STDMETHODIMP CDFBrowse_SetStatusText(LPSHELLBROWSER psb, LPCOLESTR pwch);
|
|
STDMETHODIMP CDFBrowse_EnableModeless(LPSHELLBROWSER psb, BOOL fEnable);
|
|
STDMETHODIMP CDFBrowse_TranslateAccelerator(LPSHELLBROWSER psb, LPMSG pmsg, WORD wID);
|
|
STDMETHODIMP CDFBrowse_BrowseObject(LPSHELLBROWSER psb, LPCITEMIDLIST pidl, UINT wFlags);
|
|
STDMETHODIMP CDFBrowse_GetViewStateStream(IShellBrowser * psb, DWORD grfMode, LPSTREAM *pStrm);
|
|
STDMETHODIMP CDFBrowse_GetControlWindow(LPSHELLBROWSER psb,
|
|
UINT id, HWND FAR* lphwnd);
|
|
STDMETHODIMP CDFBrowse_SendControlMsg(LPSHELLBROWSER psb,
|
|
UINT id, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT FAR* pret);
|
|
STDMETHODIMP CDFBrowse_QueryActiveShellView(LPSHELLBROWSER psb, LPSHELLVIEW * ppsv);
|
|
STDMETHODIMP CDFBrowse_OnViewWindowActive(LPSHELLBROWSER psb, LPSHELLVIEW psv);
|
|
STDMETHODIMP CDFBrowse_InsertMenus(LPSHELLBROWSER psb, HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths) ;
|
|
STDMETHODIMP CDFBrowse_SetMenu(LPSHELLBROWSER psb, HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject) ;
|
|
STDMETHODIMP CDFBrowse_RemoveMenus(LPSHELLBROWSER psb, HMENU hmenuShared) ;
|
|
STDMETHODIMP CDFBrowse_SetToolbarItems(IShellBrowser * psb, LPTBBUTTON lpButtons, UINT nButtons, UINT uFlags);
|
|
|
|
|
|
#pragma data_seg(".text", "CODE")
|
|
|
|
IShellBrowserVtbl s_DFBVtbl =
|
|
{
|
|
// *** IUnknown methods ***
|
|
CDFBrowse_QueryInterface,
|
|
CDFBrowse_AddRef,
|
|
CDFBrowse_Release,
|
|
|
|
// *** IShellBrowser methods ***
|
|
CDFBrowse_GetWindow,
|
|
CDFBrowse_ContextSensitiveHelp,
|
|
CDFBrowse_InsertMenus,
|
|
CDFBrowse_SetMenu,
|
|
CDFBrowse_RemoveMenus,
|
|
CDFBrowse_SetStatusText,
|
|
CDFBrowse_EnableModeless,
|
|
CDFBrowse_TranslateAccelerator,
|
|
|
|
CDFBrowse_BrowseObject,
|
|
CDFBrowse_GetViewStateStream,
|
|
CDFBrowse_GetControlWindow,
|
|
CDFBrowse_SendControlMsg,
|
|
CDFBrowse_QueryActiveShellView,
|
|
CDFBrowse_OnViewWindowActive,
|
|
CDFBrowse_SetToolbarItems,
|
|
};
|
|
#pragma data_seg()
|
|
|
|
HRESULT STDMETHODCALLTYPE CDFBrowse_QueryInterface(IShellBrowser * psb, REFIID riid, LPVOID FAR* ppvObj)
|
|
{
|
|
CDFBrowse * this = IToClassN(CDFBrowse, sb, psb);
|
|
if (IsEqualIID(riid, &IID_IShellBrowser) || IsEqualIID(riid, &IID_IUnknown))
|
|
{
|
|
*ppvObj = psb;
|
|
return NOERROR;
|
|
}
|
|
|
|
*ppvObj = NULL;
|
|
return ResultFromScode(E_NOINTERFACE);
|
|
}
|
|
|
|
|
|
ULONG STDMETHODCALLTYPE CDFBrowse_AddRef(IShellBrowser * psb)
|
|
{
|
|
CDFBrowse * this = IToClassN(CDFBrowse, sb, psb);
|
|
InterlockedIncrement(&this->cRef);
|
|
return this->cRef;
|
|
}
|
|
|
|
|
|
ULONG STDMETHODCALLTYPE CDFBrowse_Release(IShellBrowser * psb)
|
|
{
|
|
HICON hIcon;
|
|
CDFBrowse * this = IToClassN(CDFBrowse, sb, psb);
|
|
ULONG tmp;
|
|
|
|
tmp = this->cRef;
|
|
|
|
if (0 != InterlockedDecrement(&this->cRef))
|
|
{
|
|
return tmp - 1;
|
|
}
|
|
|
|
// If we still have a find thread outstanding, tell it to go away
|
|
if (this->pft)
|
|
{
|
|
this->pft->fContinue = FALSE; // Tell the thread to stop
|
|
this->pft = NULL;
|
|
}
|
|
|
|
/* Remove all FSNotifies that are associated with this window */
|
|
SHChangeNotifyDeregisterWindow( this ->hwndDlg);
|
|
|
|
// Free the IDLists if we have any
|
|
ILFree(this->pidlStart);
|
|
ILFree(this->pidlSaveFile);
|
|
|
|
//
|
|
// Destroy the icons
|
|
//
|
|
if (NULL != (hIcon = (HICON)SendMessage(this->hwndDlg, WM_SETICON, FALSE, 0L)))
|
|
DestroyIcon(hIcon);
|
|
if (NULL != (hIcon = (HICON)SendMessage(this->hwndDlg, WM_SETICON, TRUE, 0L)))
|
|
DestroyIcon(hIcon);
|
|
|
|
|
|
if (this->hdpaItemsToAdd)
|
|
DPA_Destroy(this->hdpaItemsToAdd);
|
|
if (this->hdpaPrevAdd)
|
|
DPA_Destroy(this->hdpaPrevAdd);
|
|
|
|
//
|
|
// Release the other guys that depend on us
|
|
//
|
|
|
|
if (this->pdfc)
|
|
this->pdfc->lpVtbl->Release(this->pdfc);
|
|
|
|
if (this->psv)
|
|
{
|
|
this->psv->lpVtbl->UIActivate(this->psv, SVUIA_DEACTIVATE);
|
|
this->psv->lpVtbl->DestroyViewWindow(this->psv);
|
|
this->psv->lpVtbl->Release(this->psv);
|
|
}
|
|
|
|
|
|
if (this->pdfff)
|
|
this->pdfff->lpVtbl->Release(this->pdfff);
|
|
|
|
// Make sure no more messages try to use us!
|
|
SetWindowLong(this->hwndDlg, DWL_USER, (LONG)NULL);
|
|
|
|
// Free up the critical section
|
|
DeleteCriticalSection(&this->csSearch);
|
|
|
|
LocalFree((HLOCAL)this);
|
|
|
|
return 0;
|
|
}
|
|
|
|
STDMETHODIMP CDFBrowse_GetWindow(LPSHELLBROWSER psb, HWND FAR* phwnd)
|
|
{
|
|
CDFBrowse * this = IToClassN(CDFBrowse, sb, psb);
|
|
*phwnd = this->hwndDlg;
|
|
return NOERROR;
|
|
}
|
|
|
|
STDMETHODIMP CDFBrowse_ContextSensitiveHelp(LPSHELLBROWSER psb, BOOL fEnable)
|
|
{
|
|
// BUGBUG: Implement it later!
|
|
return NOERROR;
|
|
}
|
|
|
|
STDMETHODIMP CDFBrowse_SetStatusText(LPSHELLBROWSER psb, LPCOLESTR pwch)
|
|
{
|
|
// We don't have any status bar.
|
|
return NOERROR;
|
|
}
|
|
|
|
STDMETHODIMP CDFBrowse_EnableModeless(LPSHELLBROWSER psb, BOOL fEnable)
|
|
{
|
|
// We don't have any modeless window to be enabled/disabled.
|
|
return NOERROR;
|
|
}
|
|
|
|
STDMETHODIMP CDFBrowse_TranslateAccelerator(LPSHELLBROWSER psb, LPMSG pmsg, WORD wID)
|
|
{
|
|
return ResultFromScode(E_NOTIMPL);
|
|
}
|
|
|
|
STDMETHODIMP CDFBrowse_BrowseObject(LPSHELLBROWSER psb, LPCITEMIDLIST pidl, UINT wFlags)
|
|
{
|
|
// We don't support browsing.
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
STDMETHODIMP CDFBrowse_GetViewStateStream(IShellBrowser * psb, DWORD grfMode,
|
|
LPSTREAM *pStrm)
|
|
{
|
|
return ResultFromScode(E_NOTIMPL);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CDFBrowse_GetControlWindow(LPSHELLBROWSER psb,
|
|
UINT id, HWND FAR* lphwnd)
|
|
{
|
|
// We don't support this member. (at least at this point)
|
|
return NOERROR;
|
|
}
|
|
|
|
// Get the handles of various windows in the File Cabinet
|
|
//
|
|
STDMETHODIMP CDFBrowse_SendControlMsg(LPSHELLBROWSER psb,
|
|
UINT id, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT FAR* pret)
|
|
{
|
|
// We don't support this member.
|
|
return NOERROR;
|
|
}
|
|
|
|
// Get the bounds of various windows in the File Cabinet
|
|
//
|
|
STDMETHODIMP CDFBrowse_QueryActiveShellView(LPSHELLBROWSER psb, LPSHELLVIEW * ppsv)
|
|
{
|
|
CDFBrowse * this = IToClassN(CDFBrowse, sb, psb);
|
|
if (this->psv) {
|
|
*ppsv = this->psv;
|
|
this->psv->lpVtbl->AddRef(this->psv);
|
|
return NOERROR;
|
|
}
|
|
return ResultFromScode(E_NOINTERFACE);
|
|
}
|
|
|
|
STDMETHODIMP CDFBrowse_OnViewWindowActive(LPSHELLBROWSER psb, LPSHELLVIEW psv)
|
|
{
|
|
// No need to process this. Our InsertMenus() does not depend on the focus.
|
|
return NOERROR;
|
|
}
|
|
|
|
STDMETHODIMP CDFBrowse_InsertMenus(LPSHELLBROWSER psb, HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths)
|
|
{
|
|
CDFBrowse * this = IToClassN(CDFBrowse, sb, psb);
|
|
if (hmenuShared)
|
|
{
|
|
// Note that we "copy" submenus.
|
|
Shell_MergeMenus(hmenuShared, this->hmenuTemplate,
|
|
0, 0, FCIDM_BROWSERLAST, 0);
|
|
lpMenuWidths->width[0] = 1; // File
|
|
lpMenuWidths->width[2] = 2; // Edit, Options
|
|
lpMenuWidths->width[4] = 2; // Tools, Help
|
|
|
|
{
|
|
// BUGBUG: Set the menu IDs; we should put this in the RC file
|
|
MENUITEMINFO miiSubMenu;
|
|
int i;
|
|
miiSubMenu.cbSize = SIZEOF(MENUITEMINFO);
|
|
miiSubMenu.fMask = MIIM_ID;
|
|
|
|
for (i = 0; i < ARRAYSIZE(c_auDFMenuIDs); i++)
|
|
{
|
|
miiSubMenu.wID = c_auDFMenuIDs[i];
|
|
if (miiSubMenu.wID != (UINT)-1)
|
|
SetMenuItemInfo(hmenuShared, i, TRUE, &miiSubMenu);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
STDMETHODIMP CDFBrowse_SetMenu(LPSHELLBROWSER psb, HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject)
|
|
{
|
|
HMENU hMenuOld;
|
|
CDFBrowse * this = IToClassN(CDFBrowse, sb, psb);
|
|
if (hmenuShared)
|
|
{
|
|
this->hmenuCur = hmenuShared;
|
|
}
|
|
else
|
|
{
|
|
this->hmenuCur = this->hmenuTemplate;
|
|
}
|
|
hMenuOld = GetMenu(this->hwndDlg);
|
|
if (hMenuOld)
|
|
{
|
|
DestroyMenu(hMenuOld);
|
|
}
|
|
|
|
SetMenu(this->hwndDlg, this->hmenuCur);
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
STDMETHODIMP CDFBrowse_RemoveMenus(LPSHELLBROWSER psb, HMENU hmenuShared)
|
|
{
|
|
// No need to remove them, because we "copied" them in InsertMenu.
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
STDMETHODIMP CDFBrowse_SetToolbarItems(IShellBrowser * psb, LPTBBUTTON lpButtons, UINT nButtons, UINT uFlags)
|
|
{
|
|
// No Toolbar!
|
|
return NOERROR;
|
|
}
|
|
|
|
//===========================================================================
|
|
// CDFFolder: class definition
|
|
//===========================================================================
|
|
|
|
|
|
|
|
typedef struct _CDFFolder // DFC (Doc find Container)
|
|
{
|
|
IShellFolder sf;
|
|
UINT cRef;
|
|
IDocFindFileFilter * pdfff; // Pointer to the FindFileFIlter interface
|
|
HDPA hdpaPidf; // DPA of Folder list items.
|
|
HWND hwndDlg; // handle to top level dialog
|
|
} CDFFolder, FAR* LPDFFOLDER;
|
|
|
|
//===========================================================================
|
|
// CDFFolder : member prototype - Docfind Folder implementation
|
|
//===========================================================================
|
|
ULONG STDMETHODCALLTYPE CDFFolder_AddRef(LPSHELLFOLDER psf);
|
|
ULONG STDMETHODCALLTYPE CDFFolder_Release(LPSHELLFOLDER psf);
|
|
STDMETHODIMP CDFFolder_ParseDisplayName(LPSHELLFOLDER psf, HWND hwndOwner,
|
|
LPBC pbc, LPOLESTR lpszDisplayName,
|
|
ULONG FAR* pchEaten, LPITEMIDLIST * ppidl, ULONG* pdwAttributes);
|
|
STDMETHODIMP CDFFolder_EnumObjects( LPSHELLFOLDER psf, HWND hwndOwner, DWORD grfFlags, LPENUMIDLIST FAR* ppenumUnknown);
|
|
STDMETHODIMP CDFFolder_BindToObject(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, LPBC pbc,
|
|
REFIID riid, LPVOID FAR* ppvOut);
|
|
STDMETHODIMP CDFFolder_CreateViewObject(LPSHELLFOLDER psf, HWND hwnd, REFIID riid, LPVOID FAR* ppvOut);
|
|
STDMETHODIMP CDFFolder_CompareIDs(LPSHELLFOLDER psf, LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2);
|
|
STDMETHODIMP CDFFolder_GetAttributesOf(LPSHELLFOLDER psf, UINT cidl, LPCITEMIDLIST FAR* apidl, ULONG FAR* rgfOut);
|
|
STDMETHODIMP CDFFolder_GetUIObjectOf(LPSHELLFOLDER psf, HWND hwndOwner, UINT cidl, LPCITEMIDLIST FAR* apidl,
|
|
REFIID riid, UINT FAR* prgfInOut, LPVOID FAR* ppvOut);
|
|
STDMETHODIMP CDFFolder_GetDisplayNameOf(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, DWORD dwReserved, LPSTRRET pStrRet);
|
|
STDMETHODIMP CDFFolder_SetNameOf(LPSHELLFOLDER psf, HWND hwndOwner,
|
|
LPCITEMIDLIST pidl, LPCOLESTR lpszName, DWORD dwResesrved,
|
|
LPITEMIDLIST FAR* ppidlOut);
|
|
|
|
//===========================================================================
|
|
// CDFFolder : Vtable
|
|
//===========================================================================
|
|
#pragma data_seg(".text", "CODE")
|
|
IShellFolderVtbl c_DFFolderVtbl =
|
|
{
|
|
CDefShellFolder_QueryInterface,
|
|
CDFFolder_AddRef,
|
|
CDFFolder_Release,
|
|
CDFFolder_ParseDisplayName,
|
|
CDFFolder_EnumObjects,
|
|
CDFFolder_BindToObject,
|
|
CDefShellFolder_BindToStorage,
|
|
CDFFolder_CompareIDs,
|
|
CDFFolder_CreateViewObject,
|
|
CDFFolder_GetAttributesOf,
|
|
CDFFolder_GetUIObjectOf,
|
|
CDFFolder_GetDisplayNameOf,
|
|
CDFFolder_SetNameOf,
|
|
};
|
|
#pragma data_seg()
|
|
|
|
//===========================================================================
|
|
// CDFFolder : Helper Functions
|
|
//===========================================================================
|
|
|
|
void cdecl DocFind_SetStatusText(HWND hwndStatus, int iField, UINT ids,...)
|
|
{
|
|
TCHAR sz1[MAXPATHLEN];
|
|
TCHAR sz2[MAXPATHLEN+32]; // leave slop for message + max path name
|
|
va_list ArgList;
|
|
|
|
if (hwndStatus)
|
|
{
|
|
va_start(ArgList, ids);
|
|
LoadString(HINST_THISDLL, ids, sz1, ARRAYSIZE(sz1));
|
|
#ifdef WINDOWS_ME
|
|
wvsprintf(sz2, sz1, ArgList);
|
|
sz2[0] = sz2[1] = TEXT('\t');
|
|
#else
|
|
wvsprintf(sz2, sz1, ArgList);
|
|
#endif
|
|
va_end(ArgList);
|
|
|
|
if (iField < 0)
|
|
#ifdef WINDOWS_ME
|
|
SendMessage(hwndStatus, SB_SETTEXT, SBT_RTLREADING | SBT_NOBORDERS | 255, (LPARAM)(LPTSTR)sz2);
|
|
#else
|
|
SendMessage(hwndStatus, SB_SETTEXT, SBT_NOBORDERS | 255, (LPARAM)(LPTSTR)sz2);
|
|
#endif
|
|
else
|
|
SendMessage(hwndStatus, SB_SETTEXT, iField, (LPARAM)(LPTSTR)sz2);
|
|
|
|
UpdateWindow(hwndStatus);
|
|
}
|
|
}
|
|
|
|
HRESULT CDFFolder_AddFolderToFolderList(IShellFolder * psf, LPITEMIDLIST pidl,
|
|
LPSHELLFOLDER *ppsf, int * piFolder)
|
|
{
|
|
LPDFFOLDER this = (LPDFFOLDER)psf;
|
|
HRESULT hres = ERROR_SUCCESS;
|
|
int i;
|
|
// For now it is path based, but...
|
|
LPDFFOLDERLISTITEM lpdffli = (LPDFFOLDERLISTITEM)LocalAlloc(LPTR, SIZEOF(DFFolderListItem));
|
|
if (lpdffli == NULL)
|
|
{
|
|
*piFolder = -1;
|
|
return ResultFromScode(E_OUTOFMEMORY);
|
|
}
|
|
|
|
// lpddfli->psf = NULL;
|
|
lpdffli->fValid = TRUE; // The node is valid
|
|
lpdffli->pidl = pidl;
|
|
|
|
// See if Bind is needed!
|
|
if (ppsf != NULL)
|
|
{
|
|
LPSHELLFOLDER psfDesktop = Desktop_GetShellFolder(TRUE);
|
|
// We use the root of evil to bind...
|
|
if (FAILED(hres=psfDesktop->lpVtbl->BindToObject(psfDesktop,
|
|
lpdffli->pidl, NULL, &IID_IShellFolder, &lpdffli->psf)))
|
|
{
|
|
lpdffli->psf = NULL;
|
|
*piFolder = -1;
|
|
return(hres);
|
|
}
|
|
*ppsf = lpdffli->psf;
|
|
}
|
|
|
|
|
|
// Now add this item to our DPA...
|
|
i = DPA_InsertPtr(this->hdpaPidf, 32767, lpdffli);
|
|
|
|
if (i == -1)
|
|
{
|
|
ILFree(lpdffli->pidl);
|
|
LocalFree((HLOCAL)lpdffli);
|
|
hres = ResultFromScode(E_OUTOFMEMORY);
|
|
}
|
|
|
|
*piFolder = i;
|
|
|
|
/* If this is a network ID list then register a path -> pidl mapping, therefore
|
|
/ avoiding having to create simple ID lists, which don't work correctly when
|
|
/ being compared against real ID lists. */
|
|
|
|
if ( CDesktop_IsMyNetwork( pidl ) )
|
|
{
|
|
TCHAR szPath[ MAX_PATH ];
|
|
|
|
SHGetPathFromIDList( pidl, szPath );
|
|
NPTRegisterNameToPidlTranslation( szPath, pidl );
|
|
}
|
|
|
|
return(hres);
|
|
}
|
|
|
|
|
|
void CDFFolder_ClearFolderList(LPDFFOLDER this)
|
|
{
|
|
int i;
|
|
LPDFFOLDERLISTITEM pdffli;
|
|
|
|
if (this->hdpaPidf == NULL)
|
|
return; // Nothing to do
|
|
|
|
for (i = DPA_GetPtrCount(this->hdpaPidf); i-- > 0; )
|
|
{
|
|
pdffli = DPA_FastGetPtr(this->hdpaPidf, i);
|
|
if (pdffli != NULL)
|
|
{
|
|
// Release the IShellFolder if we have one
|
|
if (pdffli->psf != NULL)
|
|
pdffli->psf->lpVtbl->Release(pdffli->psf);
|
|
|
|
// And Free the Id list
|
|
ILFree(pdffli->pidl);
|
|
|
|
// And delete the item
|
|
|
|
if (LocalFree((HLOCAL)pdffli))
|
|
{
|
|
Assert(FALSE); // Something bad happened!
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
DPA_DeleteAllPtrs(this->hdpaPidf);
|
|
}
|
|
|
|
//
|
|
//===========================================================================
|
|
// CDFFolder : Constructor
|
|
//===========================================================================
|
|
HRESULT CDFFolder_Create(
|
|
IDocFindFileFilter * pdfff,
|
|
HWND hwndDlg, LPVOID FAR* ppvOut)
|
|
{
|
|
// We need to allocate this structure now
|
|
LPDFFOLDER pdff = LocalAlloc(LPTR, SIZEOF(*pdff));
|
|
if (pdff)
|
|
{
|
|
// Creation succeeded, so initialize the structure.
|
|
pdff->sf.lpVtbl = &c_DFFolderVtbl;
|
|
pdff->cRef = 1;
|
|
pdff->hwndDlg = hwndDlg;
|
|
pdff->pdfff = pdfff;
|
|
|
|
// Create the heap for the folder lists.
|
|
pdff->hdpaPidf = DPA_CreateEx(64, GetProcessHeap());
|
|
if (pdff->hdpaPidf == NULL)
|
|
{
|
|
LocalFree((HLOCAL)pdff);
|
|
return ResultFromScode(E_OUTOFMEMORY);
|
|
}
|
|
|
|
// Return pointer
|
|
*ppvOut = pdff;
|
|
return NOERROR;
|
|
}
|
|
return ResultFromScode(E_OUTOFMEMORY);
|
|
}
|
|
|
|
//===========================================================================
|
|
// Function to find our signature given a PIDL - was macro now function to
|
|
// handle the junction point cases.
|
|
//===========================================================================
|
|
LPBYTE DF_SIGPTR(LPCITEMIDLIST pidl)
|
|
{
|
|
LPBYTE psig;
|
|
|
|
// If not a junction point simple return
|
|
psig = (LPBYTE)((BYTE*)pidl + ((LPITEMIDLIST)pidl)->mkid.cb - 3);
|
|
if (SIL_GetType(pidl) & SHID_JUNCTION)
|
|
psig -= SIZEOF(CLSID);
|
|
|
|
return(psig);
|
|
}
|
|
|
|
|
|
//===========================================================================
|
|
// CDFFolder : External function to locate a pidl in our list
|
|
//===========================================================================
|
|
LPITEMIDLIST CDFFolder_MapFSPidlToDFPidl(IShellFolder * pisf,
|
|
LPITEMIDLIST pidl, BOOL fMapToReal)
|
|
{
|
|
LPITEMIDLIST pidlT;
|
|
LPITEMIDLIST pidlRet = NULL;
|
|
LPDFFOLDERLISTITEM pdffli;
|
|
LPDFFOLDER this = (LPDFFOLDER)pisf;
|
|
|
|
int i;
|
|
|
|
pidlT = ILClone(pidl);
|
|
if (pidlT == NULL)
|
|
return NULL;
|
|
ILRemoveLastID(pidlT);
|
|
|
|
// Now loop through our DPA list and see if we can find a matach
|
|
for (i = 0; i <DPA_GetPtrCount(this->hdpaPidf); i++ )
|
|
{
|
|
pdffli = DPA_FastGetPtr(this->hdpaPidf, i);
|
|
if (pdffli != NULL)
|
|
{
|
|
if (ILIsEqual(pidlT, pdffli->pidl))
|
|
{
|
|
// We found the right one
|
|
// so no lets transform the ID into one of our own
|
|
// to return. Note: we must catch the case where the
|
|
// original one passed in was a simple pidl and do
|
|
// the appropriate thing.
|
|
//
|
|
LPITEMIDLIST pidlReal = NULL;
|
|
|
|
// If this is not a FS folder, just clone it.
|
|
if (fMapToReal)
|
|
{
|
|
LPSHELLFOLDER psf;
|
|
|
|
// We need to make sure we have an IShellFolder to
|
|
// work with...
|
|
psf = DocFind_GetObjectsIFolder(this->hdpaPidf, pdffli, NULL);
|
|
|
|
if (psf)
|
|
{
|
|
SHGetRealIDL(psf, (LPITEMIDLIST)ILFindLastID(pidl), &pidlReal);
|
|
}
|
|
else
|
|
{
|
|
pidlReal = ILClone((LPITEMIDLIST)ILFindLastID(pidl));
|
|
}
|
|
}
|
|
else
|
|
pidlReal = ILClone((LPITEMIDLIST)ILFindLastID(pidl));
|
|
|
|
if (!pidlReal)
|
|
break;
|
|
|
|
pidlRet = ILCombine(pidlReal, (LPITEMIDLIST)&s_mkidBlank);
|
|
ILFree(pidlReal);
|
|
|
|
if (pidlRet == NULL)
|
|
{
|
|
break; // dont wipe out
|
|
}
|
|
|
|
// now lets muck in our data
|
|
pidlRet->mkid.cb += DF_APPENDSIZE;
|
|
*(DF_SIGPTR(pidlRet)) = DF_TAGSIG;
|
|
*(DF_IFLDRPTR(pidlRet)) = i;
|
|
break; // and exit the loop;
|
|
}
|
|
}
|
|
}
|
|
|
|
ILFree(pidlT); // free our copy of the coppied idlist
|
|
return(pidlRet);
|
|
}
|
|
|
|
//===========================================================================
|
|
// CDFFolder : External function to Save results out to file.
|
|
//===========================================================================
|
|
BOOL CDFFolder_SaveFolderList(IShellFolder * pisf, IStream *pstm)
|
|
{
|
|
// We First searialize all of our PIDLS for each folder in our list
|
|
|
|
LPDFFOLDERLISTITEM pdffli;
|
|
LPDFFOLDER this = (LPDFFOLDER)pisf;
|
|
USHORT cb;
|
|
|
|
int i;
|
|
|
|
// Now loop through our DPA list and see if we can find a matach
|
|
for (i = 0; i <DPA_GetPtrCount(this->hdpaPidf); i++ )
|
|
{
|
|
pdffli = DPA_FastGetPtr(this->hdpaPidf, i);
|
|
if (pdffli == NULL)
|
|
{
|
|
Assert (FALSE); // What happened here?
|
|
return FALSE;
|
|
}
|
|
ILSaveToStream(pstm, pdffli->pidl);
|
|
}
|
|
|
|
// Now out a zero size item..
|
|
cb = 0;
|
|
pstm->lpVtbl->Write(pstm, (TCHAR *)&cb, SIZEOF(cb), NULL);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
//===========================================================================
|
|
// CDFFolder : External function to Restore results out to file.
|
|
//===========================================================================
|
|
BOOL CDFFolder_RestoreFolderList(IShellFolder * pisf, IStream *pstm)
|
|
{
|
|
// We First searialize all of our PIDLS for each folder in our list
|
|
|
|
LPDFFOLDERLISTITEM pdffli;
|
|
LPDFFOLDER this = (LPDFFOLDER)pisf;
|
|
|
|
LPITEMIDLIST pidl;
|
|
int i;
|
|
int iInsert;
|
|
|
|
for (i=0; ; i++)
|
|
{
|
|
pidl = NULL; // it will try to delete previous one!
|
|
if(FAILED(ILLoadFromStream(pstm, &pidl)))
|
|
return(FALSE);
|
|
if (pidl == NULL)
|
|
return(TRUE); // end of the list
|
|
|
|
pdffli = (LPDFFOLDERLISTITEM)LocalAlloc(LPTR, SIZEOF(DFFolderListItem));
|
|
if (pdffli == NULL)
|
|
return(FALSE);
|
|
|
|
pdffli->pidl = pidl;
|
|
iInsert = DPA_InsertPtr(this->hdpaPidf, 32767, pdffli);
|
|
Assert(i == iInsert); // make sure save/restore
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
// CDFFolder : External function to Restore results out to file.
|
|
//===========================================================================
|
|
LPITEMIDLIST CDFolder_GetParentsPIDL(IShellFolder * pisf, LPCITEMIDLIST pidl)
|
|
{
|
|
|
|
LPDFFOLDERLISTITEM pdffli;
|
|
LPDFFOLDER this = (LPDFFOLDER)pisf;
|
|
|
|
// First Validate the pidl that was passed in.
|
|
// is what we expect - cb, Folder number, followed by a mkid
|
|
if (pidl == NULL)
|
|
return(NULL);
|
|
|
|
if ((pidl->mkid.cb < (SIZEOF(ITEMIDLIST) + DF_APPENDSIZE)) ||
|
|
(*DF_SIGPTR(pidl) != DF_TAGSIG))
|
|
{
|
|
Assert(FALSE);
|
|
return(NULL);
|
|
}
|
|
|
|
// Now get to the item associated with that folder out of our dpa.
|
|
pdffli = DPA_FastGetPtr(this->hdpaPidf, *DF_IFLDRPTR(pidl));
|
|
if (pdffli == NULL)
|
|
return(NULL);
|
|
|
|
// Else simply return the id list for the parent folder
|
|
return(pdffli->pidl);
|
|
}
|
|
|
|
//===========================================================================
|
|
// CDFFolder : Members
|
|
//===========================================================================
|
|
//
|
|
// AddRef
|
|
//
|
|
ULONG STDMETHODCALLTYPE CDFFolder_AddRef(LPSHELLFOLDER psf)
|
|
{
|
|
LPDFFOLDER this = IToClass(CDFFolder, sf, psf);
|
|
this->cRef++;
|
|
return this->cRef;
|
|
}
|
|
|
|
//
|
|
// Release
|
|
//
|
|
ULONG STDMETHODCALLTYPE CDFFolder_Release(LPSHELLFOLDER psf)
|
|
{
|
|
LPDFFOLDER this = IToClass(CDFFolder, sf, psf);
|
|
this->cRef--;
|
|
if (this->cRef > 0)
|
|
{
|
|
return this->cRef;
|
|
}
|
|
|
|
// We will need to call our function to Free our items in our
|
|
// Folder list. We will use the same function that we use to
|
|
// clear it when we do a new search
|
|
CDFFolder_ClearFolderList(this);
|
|
|
|
DPA_Destroy(this->hdpaPidf);
|
|
LocalFree((HLOCAL)this);
|
|
return 0;
|
|
}
|
|
|
|
|
|
STDMETHODIMP CDFFolder_ParseDisplayName(LPSHELLFOLDER psf, HWND hwndOwner,
|
|
LPBC pbc, LPOLESTR pwzDisplayName,
|
|
ULONG FAR* pchEaten, LPITEMIDLIST * ppidl, ULONG * pdwAttributes)
|
|
{
|
|
// I don't think we need this to do anything as we are not a container...
|
|
return ResultFromScode(E_NOTIMPL);
|
|
}
|
|
|
|
STDMETHODIMP CDFFolder_EnumObjects(LPSHELLFOLDER psf, HWND hwndOwner, DWORD grfFlags, LPENUMIDLIST *ppenumUnknown)
|
|
{
|
|
//
|
|
// We do not want the def view to enumerate us, instead we
|
|
// will tell defview to call us...
|
|
//
|
|
*ppenumUnknown = NULL; // No enumerator
|
|
return ResultFromScode(S_FALSE); // Indicates no enumerator (not error)
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
// Here is where the big indirection is.
|
|
//
|
|
LPSHELLFOLDER DocFind_GetObjectsIFolder(HDPA hdpaPidf,
|
|
LPDFFOLDERLISTITEM pdffli, LPCITEMIDLIST pidl)
|
|
{
|
|
|
|
// First Validate the pidl that was passed in.
|
|
// is what we expect - cb, Folder number, followed by a mkid
|
|
|
|
if (pdffli == NULL)
|
|
{
|
|
if ((pidl->mkid.cb < (SIZEOF(ITEMIDLIST) + DF_APPENDSIZE)) ||
|
|
(*DF_SIGPTR(pidl) != DF_TAGSIG))
|
|
{
|
|
Assert(FALSE);
|
|
return(NULL);
|
|
}
|
|
|
|
// Now get to the item associated with that folder out of our dpa.
|
|
pdffli = DPA_FastGetPtr(hdpaPidf, *DF_IFLDRPTR(pidl));
|
|
if (pdffli == NULL)
|
|
return(NULL);
|
|
}
|
|
|
|
// Now see if we need to build an IFolder for this object.
|
|
//
|
|
if (pdffli->psf == NULL)
|
|
{
|
|
// We use the root of evil to bind...
|
|
LPSHELLFOLDER psfDesktop = Desktop_GetShellFolder(TRUE);
|
|
if (FAILED(psfDesktop->lpVtbl->BindToObject(psfDesktop,
|
|
pdffli->pidl, NULL, &IID_IShellFolder, &pdffli->psf)))
|
|
{
|
|
pdffli->psf = NULL;
|
|
return(NULL); // handle failure case.
|
|
}
|
|
}
|
|
|
|
return pdffli->psf;
|
|
}
|
|
|
|
|
|
|
|
|
|
STDMETHODIMP CDFFolder_BindToObject(LPSHELLFOLDER psf, LPCITEMIDLIST pidl,
|
|
LPBC pbc, REFIID riid, LPVOID FAR* ppvOut)
|
|
{
|
|
LPDFFOLDER this = IToClass(CDFFolder, sf, psf);
|
|
|
|
LPSHELLFOLDER psfItem;
|
|
|
|
//
|
|
// We need to parse the ID and see which sub-folder it belongs to
|
|
// then we will see if we have an IShellFolder for the object. If not
|
|
// we will construct it and then extract our part off of the IDLIST and
|
|
// then forward it...
|
|
//
|
|
psfItem = DocFind_GetObjectsIFolder(this->hdpaPidf, NULL, pidl);
|
|
|
|
if (psfItem != NULL)
|
|
{
|
|
return psfItem->lpVtbl->BindToObject(psfItem, pidl, pbc,
|
|
riid, ppvOut);
|
|
}
|
|
return ResultFromScode(E_INVALIDARG);
|
|
}
|
|
|
|
|
|
// Little helper function for bellow
|
|
HRESULT _CDFFolder_CompareFolderIndexes(LPDFFOLDER this,
|
|
int iFolder1, int iFolder2)
|
|
{
|
|
TCHAR szPath1[MAXPATHLEN];
|
|
TCHAR szPath2[MAXPATHLEN];
|
|
|
|
LPDFFOLDERLISTITEM pdffli1 = DPA_FastGetPtr(this->hdpaPidf,
|
|
iFolder1);
|
|
LPDFFOLDERLISTITEM pdffli2 = DPA_FastGetPtr(this->hdpaPidf,
|
|
iFolder2);
|
|
|
|
if ((pdffli1 != NULL) && (pdffli2 != NULL))
|
|
{
|
|
SHGetPathFromIDList(pdffli1->pidl, szPath1);
|
|
SHGetPathFromIDList(pdffli2->pidl, szPath2);
|
|
return(ResultFromShort(lstrcmpi(szPath1, szPath2)));
|
|
}
|
|
|
|
// If we got here there is an error!
|
|
return ResultFromScode(E_INVALIDARG);
|
|
}
|
|
|
|
STDMETHODIMP CDFFolder_CompareIDs(LPSHELLFOLDER psf, LPARAM lParam,
|
|
LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
|
|
{
|
|
|
|
HRESULT hres = ResultFromScode(E_INVALIDARG);
|
|
LPDFFOLDER this = IToClass(CDFFolder, sf, psf);
|
|
LPSHELLFOLDER psf1;
|
|
LPITEMIDLIST pidl1Last;
|
|
int iFolder1;
|
|
int iFolder2;
|
|
|
|
// Note there are times in the defview that may call us back looking for
|
|
// a fully qualified pidl in pidl1, so we need to detect this case and
|
|
// only process the last part.
|
|
|
|
pidl1Last = (LPITEMIDLIST)ILFindLastID((LPITEMIDLIST)pidl1);
|
|
iFolder1 = *DF_IFLDRPTR(pidl1Last);
|
|
iFolder2 = *DF_IFLDRPTR(pidl2);
|
|
|
|
|
|
// We need to handle the case our self if the sort is by
|
|
// the containing folder. But otherwise we simply forward the informat
|
|
// to the FSFolders compare function. This will only work if both ids
|
|
// are file system objects, but if this is not the case, then what???
|
|
//
|
|
if (lParam == IDFCOL_PATH)
|
|
{
|
|
if (iFolder1 != iFolder2)
|
|
return _CDFFolder_CompareFolderIndexes(this, iFolder1, iFolder2);
|
|
|
|
//
|
|
// If we get here the paths are the same so set the sort order
|
|
// to name...
|
|
lParam = IDFCOL_NAME;
|
|
}
|
|
|
|
// For know we just forward this to the function the that CFSFolder
|
|
// uses. This is not clean but...
|
|
psf1 = DocFind_GetObjectsIFolder(this->hdpaPidf, NULL, pidl1Last);
|
|
if (psf1)
|
|
{
|
|
hres = psf1->lpVtbl->CompareIDs(psf1, s_auMapDFColToFSCol[lParam], pidl1Last, pidl2);
|
|
|
|
if ((hres == 0) && (lParam == IDFCOL_NAME) && (iFolder1 != iFolder2))
|
|
{
|
|
// They compared the same and by name so make sure truelly the
|
|
// same path as this is used in processing notifications.
|
|
return _CDFFolder_CompareFolderIndexes(this, iFolder1, iFolder2);
|
|
}
|
|
return(hres);
|
|
}
|
|
else
|
|
return ResultFromScode(E_INVALIDARG);
|
|
}
|
|
|
|
|
|
HRESULT CALLBACK CDFFolder_DFMCallBack(LPSHELLFOLDER psf, HWND hwndOwner,
|
|
LPDATAOBJECT pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
|
|
HRESULT CALLBACK DF_FNVCallBack(LPSHELLVIEW psvOuter, LPSHELLFOLDER psf,
|
|
HWND hwndOwner, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
|
|
STDMETHODIMP CDFFolder_CreateViewObject(LPSHELLFOLDER psf, HWND hwnd, REFIID riid, LPVOID FAR* ppvOut)
|
|
{
|
|
LPDFFOLDER this = IToClass(CDFFolder, sf, psf);
|
|
|
|
//
|
|
// We need to parse the ID and see which sub-folder it belongs to
|
|
// then we will see if we have an IShellFolder for the object. If not
|
|
// we will construct it and then extract our part off of the IDLIST and
|
|
// then forward it...
|
|
//
|
|
*ppvOut = NULL; // Clear it in case of error;
|
|
|
|
if (IsEqualIID(riid, &IID_IShellView))
|
|
{
|
|
CSFV csfv = {
|
|
SIZEOF(CSFV), // cbSize
|
|
psf, // pshf
|
|
NULL, // psvOuter
|
|
NULL, // pidl
|
|
0,
|
|
DF_FNVCallBack, // pfnCallback
|
|
0,
|
|
};
|
|
|
|
return SHCreateShellFolderViewEx(&csfv, (LPSHELLVIEW *)ppvOut);
|
|
}
|
|
else if (IsEqualIID(riid, &IID_IShellDetails))
|
|
{
|
|
return(this->pdfff->lpVtbl->CreateDetails(this->pdfff,
|
|
this->hwndDlg, this->hdpaPidf, ppvOut));
|
|
}
|
|
else if (IsEqualIID(riid, &IID_IContextMenu))
|
|
{
|
|
// No, do background menu.
|
|
return(CDefFolderMenu_Create((LPCITEMIDLIST)NULL, hwnd,
|
|
0, NULL, psf, CDFFolder_DFMCallBack,
|
|
NULL, NULL, (LPCONTEXTMENU FAR*)ppvOut));
|
|
}
|
|
|
|
return(ResultFromScode(E_NOINTERFACE));
|
|
}
|
|
|
|
STDMETHODIMP CDFFolder_GetAttributesOf(LPSHELLFOLDER psf, UINT cidl,
|
|
LPCITEMIDLIST FAR* apidl, ULONG FAR* prgfInOut)
|
|
{
|
|
LPDFFOLDER this = IToClass(CDFFolder, sf, psf);
|
|
|
|
//
|
|
// We need to simply forward this to the the IShellfolder of the
|
|
// first one. We will pass him all of them as I know he does not
|
|
// process the others...
|
|
// call off to the containing folder
|
|
if (cidl == 0)
|
|
{
|
|
// They are asking for capabilities, so tell them that we support Rename...
|
|
// Review: See what other ones we need to return.
|
|
*prgfInOut = SFGAO_CANRENAME;
|
|
return NOERROR;
|
|
}
|
|
else
|
|
{
|
|
LPSHELLFOLDER psfItem;
|
|
|
|
psfItem = DocFind_GetObjectsIFolder(this->hdpaPidf, NULL, ILFindLastID(*apidl));
|
|
|
|
if (psfItem == NULL)
|
|
goto Bail;
|
|
|
|
return psfItem->lpVtbl->GetAttributesOf(psfItem, cidl,
|
|
apidl, prgfInOut);
|
|
}
|
|
|
|
// Error case
|
|
Bail:
|
|
return ResultFromScode(E_FAIL);
|
|
|
|
}
|
|
|
|
// Helper function to Map the Sort Id to IColumn
|
|
int DFSortIDToICol(int uCmd)
|
|
{
|
|
switch (uCmd)
|
|
{
|
|
case FSIDM_SORTBYNAME:
|
|
return IDFCOL_NAME;
|
|
case FSIDM_SORTBYLOCATION:
|
|
return IDFCOL_PATH;
|
|
default:
|
|
return uCmd - FSIDM_SORT_FIRST - IDFCOL_NAME + 1; // make room for location
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// To be called back from within CDefFolderMenuE - Currently only used
|
|
//
|
|
HRESULT CALLBACK CDFFolder_DFMCallBack(LPSHELLFOLDER psf, HWND hwndOwner,
|
|
LPDATAOBJECT pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
HRESULT hres = NOERROR;
|
|
LPDFFOLDER this = IToClass(CDFFolder, sf, psf);
|
|
UINT id;
|
|
HMENU hmenu;
|
|
switch(uMsg)
|
|
{
|
|
case DFM_WM_MEASUREITEM:
|
|
#define lpmis ((LPMEASUREITEMSTRUCT)lParam)
|
|
|
|
if (lpmis->itemID == (wParam + FSIDM_SENDTOFIRST)) {
|
|
FileMenu_MeasureItem(NULL, lpmis);
|
|
}
|
|
break;
|
|
#undef lpmis
|
|
|
|
case DFM_WM_DRAWITEM:
|
|
#define lpdis ((LPDRAWITEMSTRUCT)lParam)
|
|
if (lpdis->itemID == (wParam + FSIDM_SENDTOFIRST)) {
|
|
FileMenu_DrawItem(NULL, lpdis);
|
|
}
|
|
break;
|
|
#undef lpdis
|
|
|
|
case DFM_WM_INITMENUPOPUP:
|
|
hmenu = (HMENU)wParam;
|
|
id = GetMenuItemID(hmenu, 0);
|
|
if (id == (UINT)(lParam + FSIDM_SENDTOFIRST))
|
|
InitSendToMenuPopup(hmenu, id);
|
|
break;
|
|
|
|
case DFM_RELEASE:
|
|
ReleaseSendToMenuPopup();
|
|
break;
|
|
case DFM_MERGECONTEXTMENU:
|
|
if (!(wParam & CMF_VERBSONLY))
|
|
{
|
|
LPQCMINFO pqcm = (LPQCMINFO)lParam;
|
|
if (pdtobj)
|
|
{
|
|
if (!(wParam & CMF_DVFILE))
|
|
{
|
|
CDefFolderMenu_MergeMenu(HINST_THISDLL, POPUP_FSVIEW_ITEM, 0, pqcm);
|
|
}
|
|
|
|
if (!(wParam &CMF_DEFAULTONLY))
|
|
InitSendToMenu(pqcm->hmenu, pqcm->idCmdFirst + FSIDM_SENDTOFIRST);
|
|
}
|
|
else
|
|
{
|
|
UINT id;
|
|
|
|
this->pdfff->lpVtbl->GetFolderMergeMenuIndex(this->pdfff, &id);
|
|
CDefFolderMenu_MergeMenu(HINST_THISDLL, 0, id, pqcm);
|
|
DeleteMenu(pqcm->hmenu, SFVIDM_EDIT_PASTE, MF_BYCOMMAND);
|
|
DeleteMenu(pqcm->hmenu, SFVIDM_EDIT_PASTELINK, MF_BYCOMMAND);
|
|
// DeleteMenu(pqcm->hmenu, SFVIDM_EDIT_PASTESPECIAL, MF_BYCOMMAND);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case DFM_INVOKECOMMAND:
|
|
// Check if this is from item context menu
|
|
if (pdtobj)
|
|
{
|
|
switch(wParam)
|
|
{
|
|
case FSIDM_SENDTOFIRST:
|
|
hres = InvokeSendTo(hwndOwner, pdtobj);
|
|
break;
|
|
|
|
case DFM_CMD_LINK:
|
|
hres = SHCreateLinks(hwndOwner, NULL, pdtobj, SHCL_USETEMPLATE | SHCL_USEDESKTOP | SHCL_CONFIRM, NULL);
|
|
break;
|
|
|
|
case DFM_CMD_DELETE:
|
|
hres = CFSFolder_DeleteItems((LPFSFOLDER)psf, hwndOwner,
|
|
pdtobj, SD_USERCONFIRMATION);
|
|
break;
|
|
|
|
case DFM_CMD_PROPERTIES:
|
|
// We need to pass an empty IDlist to combine with.
|
|
hres = CFSFolder_Properties((LPFSFOLDER)psf,
|
|
(LPITEMIDLIST)&s_idlEmpty, pdtobj, (LPCTSTR)lParam);
|
|
break;
|
|
|
|
default:
|
|
// BUGBUG: if GetAttributesOf did not specify the SFGAO_ bit
|
|
// that corresponds to this default DFM_CMD, then we should
|
|
// fail it here instead of returning S_FALSE. Otherwise,
|
|
// accelerator keys (cut/copy/paste/etc) will get here, and
|
|
// defcm tries to do the command with mixed results.
|
|
// BUGBUG: if GetAttributesOf did not specify SFGAO_CANLINK
|
|
// or SFGAO_CANDELETE or SFGAO_HASPROPERTIES, then the above
|
|
// implementations of these DFM_CMD commands are wrong...
|
|
|
|
// Let the defaults happen for this object
|
|
hres = ResultFromScode(S_FALSE);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// No.
|
|
switch(wParam)
|
|
{
|
|
case FSIDM_SORTBYNAME:
|
|
case FSIDM_SORTBYSIZE:
|
|
case FSIDM_SORTBYTYPE:
|
|
case FSIDM_SORTBYDATE:
|
|
case FSIDM_SORTBYLOCATION:
|
|
|
|
ShellFolderView_ReArrange(hwndOwner, DFSortIDToICol(wParam));
|
|
break;
|
|
default:
|
|
// This is one of view menu items, use the default code.
|
|
hres = ResultFromScode(S_FALSE);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
hres = E_NOTIMPL;
|
|
break;
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
// Now define a simple wrapper IContext menu which allows us to catch
|
|
// special things like Create Link...
|
|
//=============================================================================
|
|
// CDefFolderMenu class
|
|
//=============================================================================
|
|
|
|
typedef struct _CDFMenuWrap // deffm
|
|
{
|
|
IContextMenu2 cm; // IContextMenu2 base class
|
|
UINT cRef; // Reference count
|
|
HWND hwndOwner; // Owner window
|
|
|
|
LPDATAOBJECT pdtobj; // Data object
|
|
|
|
IContextMenu *pcmItem; // The contextmenu for the item
|
|
IContextMenu2 *pcm2Item; // The contextmenu for the item
|
|
|
|
} CDFMenuWrap, FAR* LPDFWRAPMENU;
|
|
|
|
|
|
STDMETHODIMP CDFMenuWrap_QueryInterface(IContextMenu2 * pcm, REFIID riid, LPVOID FAR* ppvObj)
|
|
{
|
|
CDFMenuWrap * this = IToClassN(CDFMenuWrap, cm, pcm);
|
|
|
|
if (IsEqualIID(riid, &IID_IContextMenu2))
|
|
{
|
|
// Make sure that one we are wrapping supports this!
|
|
if (this->pcm2Item == NULL)
|
|
{
|
|
HRESULT hres = this->pcmItem->lpVtbl->QueryInterface(
|
|
this->pcmItem, riid, &this->pcm2Item);
|
|
if (FAILED(hres))
|
|
{
|
|
DebugMsg(DM_TRACE, TEXT("dfmw.qi - Wrapped context menu does not support IcontextMenu2"));
|
|
Assert(FALSE);
|
|
*ppvObj = NULL;
|
|
return(hres);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (IsEqualIID(riid, &IID_IContextMenu) ||
|
|
IsEqualIID(riid, &IID_IContextMenu2) ||
|
|
IsEqualIID(riid, &IID_IUnknown))
|
|
{
|
|
*ppvObj = this;
|
|
this->cRef++;
|
|
return NOERROR;
|
|
}
|
|
|
|
DebugMsg(DM_TRACE, TEXT("dfmw.qi - Query interface not implemented"));
|
|
Assert(FALSE);
|
|
*ppvObj = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CDFMenuWrap_AddRef(IContextMenu2 * pcm)
|
|
{
|
|
CDFMenuWrap * this = IToClassN(CDFMenuWrap, cm, pcm);
|
|
|
|
this->cRef++;
|
|
return this->cRef;
|
|
}
|
|
|
|
|
|
STDMETHODIMP_(ULONG) CDFMenuWrap_Release(IContextMenu2 * pcm)
|
|
{
|
|
CDFMenuWrap * this = IToClassN(CDFMenuWrap, cm, pcm);
|
|
|
|
this->cRef--;
|
|
|
|
if (this->cRef > 0)
|
|
{
|
|
return this->cRef;
|
|
}
|
|
|
|
// Release the context menu we are wrapping
|
|
this->pcmItem->lpVtbl->Release(this->pcmItem);
|
|
|
|
if (this->pcm2Item)
|
|
this->pcm2Item->lpVtbl->Release(this->pcm2Item);
|
|
|
|
if (this->pdtobj)
|
|
this->pdtobj->lpVtbl->Release(this->pdtobj);
|
|
|
|
LocalFree((HLOCAL)this);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
STDMETHODIMP CDFMenuWrap_QueryContextMenu(IContextMenu2 * pcm,
|
|
HMENU hmenu, UINT indexMenu,UINT idCmdFirst,UINT idCmdLast,UINT uFlags)
|
|
{
|
|
CDFMenuWrap * this = IToClassN(CDFMenuWrap, cm, pcm);
|
|
|
|
// simply foward this to the one we are wrapping...
|
|
DebugMsg(DM_TRACE, TEXT("dfmw.queryContextMenu, iMenu=%d, iFirst=%d, iLast=%d"),
|
|
indexMenu, idCmdFirst, idCmdLast);
|
|
return(this->pcmItem->lpVtbl->QueryContextMenu(this->pcmItem, hmenu,
|
|
indexMenu, idCmdFirst, idCmdLast, uFlags));
|
|
|
|
}
|
|
|
|
STDMETHODIMP CDFMenuWrap_InvokeCommand(IContextMenu2 * pcm,
|
|
LPCMINVOKECOMMANDINFO lpici)
|
|
{
|
|
CDFMenuWrap * this = IToClassN(CDFMenuWrap, cm, pcm);
|
|
DebugMsg(DM_TRACE, TEXT("dfmw.InvokeCommand, verbstr=%lx"), lpici->lpVerb);
|
|
|
|
// This is sortof Gross, but we will attempt to pickoff the Link command
|
|
// which looks like the pcmitem will be SHARED_FILE_LINK....
|
|
if ((HIWORD(lpici->lpVerb)==0) &&
|
|
(LOWORD((DWORD) lpici->lpVerb) == SHARED_FILE_LINK) &&
|
|
(this->pdtobj != NULL))
|
|
{
|
|
return SHCreateLinks(lpici->hwnd, NULL, this->pdtobj,
|
|
SHCL_USETEMPLATE | SHCL_USEDESKTOP | SHCL_CONFIRM, NULL);
|
|
}
|
|
|
|
return(this->pcmItem->lpVtbl->InvokeCommand(this->pcmItem, lpici));
|
|
}
|
|
|
|
STDMETHODIMP CDFMenuWrap_GetCommandString(
|
|
IContextMenu2 * pcm, UINT idCmd, UINT wFlags, UINT * pmf,
|
|
LPSTR pszName, UINT cchMax)
|
|
{
|
|
CDFMenuWrap * this = IToClassN(CDFMenuWrap, cm, pcm);
|
|
return(this->pcmItem->lpVtbl->GetCommandString(this->pcmItem,
|
|
idCmd, wFlags, pmf, pszName, cchMax));
|
|
}
|
|
|
|
|
|
|
|
|
|
// Note: This member function is for IContextMenu2
|
|
|
|
STDMETHODIMP CDFMenuWrap_HandleMenuMsg(
|
|
IContextMenu2 * pcm, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
CDFMenuWrap * this = IToClassN(CDFMenuWrap, cm, pcm);
|
|
return(this->pcm2Item->lpVtbl->HandleMenuMsg(this->pcm2Item,
|
|
uMsg, wParam, lParam));
|
|
}
|
|
|
|
//=============================================================================
|
|
// CDFMenuWrap : Vtable
|
|
//=============================================================================
|
|
#pragma data_seg(".text", "CODE")
|
|
static const struct IContextMenu2Vtbl c_CDFMenuWrapVtbl = {
|
|
CDFMenuWrap_QueryInterface,
|
|
CDFMenuWrap_AddRef, // no need to thunk it
|
|
CDFMenuWrap_Release,
|
|
CDFMenuWrap_QueryContextMenu,
|
|
CDFMenuWrap_InvokeCommand,
|
|
CDFMenuWrap_GetCommandString,
|
|
CDFMenuWrap_HandleMenuMsg,
|
|
};
|
|
#pragma data_seg()
|
|
|
|
|
|
HRESULT DFWrapIContextMenu(HWND hwndOwner, LPSHELLFOLDER psfItem,
|
|
LPITEMIDLIST pidl, LPVOID *ppvOut)
|
|
{
|
|
HRESULT hres;
|
|
LPDFWRAPMENU pcm = LocalAlloc(LPTR, SIZEOF(CDFMenuWrap));
|
|
|
|
if (pcm == NULL)
|
|
{
|
|
((IContextMenu*)*ppvOut)->lpVtbl->Release(*ppvOut);
|
|
*ppvOut = NULL;
|
|
return ResultFromScode(E_OUTOFMEMORY);
|
|
|
|
}
|
|
|
|
pcm->cm.lpVtbl = &c_CDFMenuWrapVtbl;
|
|
pcm->cRef = 1;
|
|
pcm->hwndOwner = hwndOwner;
|
|
|
|
if (FAILED(hres = psfItem->lpVtbl->GetUIObjectOf(psfItem, hwndOwner,
|
|
1, &pidl, &IID_IDataObject, NULL, &pcm->pdtobj)))
|
|
{
|
|
Assert (FALSE);
|
|
LocalFree((HLOCAL)pcm);
|
|
((IContextMenu*)*ppvOut)->lpVtbl->Release(*ppvOut);
|
|
*ppvOut = NULL;
|
|
return(hres);
|
|
}
|
|
|
|
pcm->pcmItem = (IContextMenu*)*ppvOut;
|
|
*ppvOut = pcm;
|
|
return NOERROR;
|
|
}
|
|
|
|
// helper function to sort the selected ID list by something that
|
|
// makes file operations work reasonably OK, when both an object and it's
|
|
// parent is in the list...
|
|
//
|
|
int CALLBACK CDFFolder_SortForFileOp(LPVOID lp1, LPVOID lp2, LPARAM lparam)
|
|
{
|
|
LPITEMIDLIST pidl1;
|
|
LPITEMIDLIST pidl2;
|
|
|
|
// Since I do recursion, If I get the Folder index number from the
|
|
// last element of each and sort by them such that the higher numbers
|
|
// come first, should solve the problem fine...
|
|
pidl1 = (LPITEMIDLIST)ILFindLastID((LPITEMIDLIST)lp1);
|
|
pidl2 = (LPITEMIDLIST)ILFindLastID((LPITEMIDLIST)lp2);
|
|
|
|
return(*DF_IFLDRPTR(pidl2) - *DF_IFLDRPTR(pidl1));
|
|
|
|
}
|
|
|
|
STDMETHODIMP CDFFolder_GetUIObjectOf(LPSHELLFOLDER psf, HWND hwndOwner,
|
|
UINT cidl, LPCITEMIDLIST FAR* apidl,
|
|
REFIID riid, UINT FAR* prgfInOut, LPVOID FAR* ppvOut)
|
|
{
|
|
LPDFFOLDER this = IToClass(CDFFolder, sf, psf);
|
|
LPSHELLFOLDER psfItem;
|
|
|
|
HRESULT hres=ResultFromScode(E_INVALIDARG);
|
|
|
|
// If Count of items passed in is == 1 simply pass to the appropriate
|
|
// folder
|
|
if (cidl==1)
|
|
{
|
|
LPITEMIDLIST pidl;
|
|
|
|
// Note we may have been passed in a complex item so find the last
|
|
// id.
|
|
|
|
pidl = ILFindLastID(*apidl);
|
|
{
|
|
psfItem = DocFind_GetObjectsIFolder(this->hdpaPidf, NULL, pidl);
|
|
|
|
if (psfItem != NULL)
|
|
{
|
|
hres = psfItem->lpVtbl->GetUIObjectOf(psfItem, hwndOwner, 1,
|
|
&pidl, riid, prgfInOut, ppvOut);
|
|
|
|
// if we are doing context menu, then we will wrap this
|
|
// interface in a wrapper object, that we can then pick
|
|
// off commands like link to process specially
|
|
if (SUCCEEDED(hres) && IsEqualIID(riid, &IID_IContextMenu))
|
|
{
|
|
hres = DFWrapIContextMenu(hwndOwner, psfItem,
|
|
pidl, ppvOut);
|
|
}
|
|
}
|
|
}
|
|
return(hres); // error...
|
|
|
|
}
|
|
|
|
if (IsEqualIID(riid, &IID_IContextMenu))
|
|
{
|
|
// Is there any selection?
|
|
if (cidl==0)
|
|
{
|
|
hres = ResultFromScode(E_INVALIDARG);
|
|
}
|
|
else
|
|
{
|
|
// So we have at least two items in the list.
|
|
|
|
// Try to create a menu object that we process ourself
|
|
// Yes, do context menu.
|
|
HKEY hkeyBaseProgID = NULL;
|
|
HKEY hkeyProgID = NULL;
|
|
|
|
// Get the hkeyProgID and hkeyBaseProgID from the first item.
|
|
SHGetClassKey((LPIDFOLDER)apidl[0], &hkeyProgID, NULL, FALSE);
|
|
SHGetBaseClassKey((LPIDFOLDER)apidl[0], &hkeyBaseProgID);
|
|
|
|
hres = CDefFolderMenu_Create(NULL, hwndOwner,
|
|
cidl, apidl, psf, CDFFolder_DFMCallBack,
|
|
hkeyProgID, hkeyBaseProgID,
|
|
(LPCONTEXTMENU FAR*)ppvOut);
|
|
|
|
SHCloseClassKey(hkeyBaseProgID);
|
|
SHCloseClassKey(hkeyProgID);
|
|
}
|
|
}
|
|
else if (cidl>0 && IsEqualIID(riid, &IID_IDataObject))
|
|
{
|
|
// We need to generate a data object that each item as being
|
|
// fully qualified. This is a pain, but...
|
|
// This is a really gross use of memory!
|
|
HDPA hdpa;
|
|
|
|
UINT i;
|
|
USHORT uNullPidl = 0;
|
|
|
|
hdpa = DPA_Create(0);
|
|
if (!hdpa)
|
|
return(hres);
|
|
|
|
if (!DPA_Grow(hdpa, cidl))
|
|
{
|
|
DPA_Destroy(hdpa);
|
|
return hres;
|
|
}
|
|
for (i=0; i<cidl; i++)
|
|
{
|
|
LPITEMIDLIST pidlParent = CDFolder_GetParentsPIDL(psf,
|
|
apidl[i]);
|
|
|
|
// Need to check failure cases here!
|
|
DPA_InsertPtr(hdpa, i, ILCombine(pidlParent, apidl[i]));
|
|
}
|
|
|
|
// In order to make file manipulation functions work properly we
|
|
// need to sort the elements to make sure if an element and one
|
|
// of it's parents are in the list, that the element comes
|
|
// before it's parents...
|
|
DPA_Sort(hdpa, CDFFolder_SortForFileOp, 0);
|
|
|
|
hres = CIDLData_CreateFromIDArray2(&c_CFSIDLDataVtbl,
|
|
(LPCITEMIDLIST)&uNullPidl, cidl,
|
|
(LPITEMIDLIST*)DPA_GetPtrPtr(hdpa),
|
|
(LPDATAOBJECT FAR*)ppvOut);
|
|
//
|
|
// now to cleanup what we created.
|
|
//
|
|
for (i=0; i<cidl; i++)
|
|
{
|
|
ILFree((LPITEMIDLIST)DPA_FastGetPtr(hdpa, i));
|
|
}
|
|
DPA_Destroy(hdpa);
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
|
|
STDMETHODIMP CDFFolder_GetDisplayNameOf(LPSHELLFOLDER psf,
|
|
LPCITEMIDLIST pidl, DWORD dwReserved, LPSTRRET pStrRet)
|
|
{
|
|
LPDFFOLDER this = IToClass(CDFFolder, sf, psf);
|
|
LPSHELLFOLDER psfItem;
|
|
HRESULT hr;
|
|
|
|
psfItem = DocFind_GetObjectsIFolder(this->hdpaPidf, NULL, pidl);
|
|
|
|
if (psfItem != NULL)
|
|
{
|
|
hr = psfItem->lpVtbl->GetDisplayNameOf(psfItem, pidl, dwReserved, pStrRet);
|
|
|
|
return hr;
|
|
}
|
|
return ResultFromScode(E_INVALIDARG);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CDFFolder_SetNameOf(LPSHELLFOLDER psf, HWND hwndOwner,
|
|
LPCITEMIDLIST pidl, LPCOLESTR lpszName, DWORD dwReserved,
|
|
LPITEMIDLIST FAR* ppidlOut)
|
|
{
|
|
LPDFFOLDER this = IToClass(CDFFolder, sf, psf);
|
|
LPSHELLFOLDER psfItem;
|
|
|
|
// We simply forward this to the folder that owns that object...
|
|
psfItem = DocFind_GetObjectsIFolder(this->hdpaPidf, NULL, pidl);
|
|
|
|
if (psfItem != NULL)
|
|
{
|
|
return psfItem->lpVtbl->SetNameOf(psfItem, hwndOwner, pidl,
|
|
lpszName, dwReserved, ppidlOut);
|
|
}
|
|
return ResultFromScode(E_INVALIDARG);
|
|
}
|
|
|
|
#pragma data_seg(DATASEG_PERINSTANCE)
|
|
DWORD g_dwTlsSlot = 0xffffffff;
|
|
#pragma data_seg()
|
|
|
|
|
|
//==========================================================================
|
|
//
|
|
// Callback function for messages from dialog box below
|
|
//
|
|
//==========================================================================
|
|
LRESULT CALLBACK DocFind_MsgFilter(int nCode, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
|
|
LPDFBROWSE pdfb;
|
|
LPMSG lpmsg;
|
|
NMHDR nmhdr;
|
|
|
|
if (nCode != MSGF_DIALOGBOX)
|
|
return(0); // we did not process it
|
|
|
|
// Now try translate any accelerators that might be needing to be
|
|
// processed.
|
|
if ((g_dwTlsSlot == 0xffffffff) || ((pdfb = TlsGetValue(g_dwTlsSlot)) == NULL))
|
|
return(0); // Not translated.
|
|
|
|
// We have pointer to browser, now see if we have any accelerator
|
|
// tables to process, but only if the view or one of its children
|
|
// have the focus.
|
|
|
|
lpmsg = (LPMSG)lParam;
|
|
|
|
if (!IsChild(pdfb->hwndView, GetFocus()))
|
|
{
|
|
// We are in the property sheet part of it...
|
|
if ((lpmsg->message == WM_KEYDOWN) && (lpmsg->wParam == VK_TAB) &&
|
|
(GetAsyncKeyState(VK_CONTROL) < 0))
|
|
{
|
|
int iCur = TabCtrl_GetCurSel(pdfb->hwndTabs);
|
|
int nPages = TabCtrl_GetItemCount(pdfb->hwndTabs);
|
|
|
|
if (GetAsyncKeyState(VK_SHIFT) < 0)
|
|
iCur += (nPages-1);
|
|
else
|
|
iCur++;
|
|
|
|
iCur %= nPages;
|
|
|
|
// Ok we need to simulate clicking on the tab control...
|
|
nmhdr.hwndFrom=pdfb->hwndTabs;
|
|
nmhdr.idFrom = GetDlgCtrlID(pdfb->hwndTabs);
|
|
nmhdr.code = TCN_SELCHANGING;
|
|
if (!SendMessage(pdfb->hwndDlg, WM_NOTIFY, nmhdr.idFrom,
|
|
(LPARAM)&nmhdr))
|
|
{
|
|
TabCtrl_SetCurSel(pdfb->hwndTabs, iCur);
|
|
nmhdr.code = TCN_SELCHANGE;
|
|
SendMessage(pdfb->hwndDlg, WM_NOTIFY, nmhdr.idFrom,
|
|
(LPARAM)&nmhdr);
|
|
|
|
}
|
|
return(1); // we processed it
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
|
|
if (pdfb->psv && (pdfb->psv->lpVtbl->TranslateAccelerator(pdfb->psv,
|
|
lpmsg) == NOERROR))
|
|
return(1);
|
|
|
|
// If we are in the view part then intercept the return key...
|
|
|
|
if ((lpmsg->message == WM_KEYDOWN) && (lpmsg->wParam == VK_RETURN))
|
|
{
|
|
|
|
// Ok we need to simulate clicking on the tab control...
|
|
nmhdr.hwndFrom=GetDlgItem(pdfb->hwndView, ID_LISTVIEW);
|
|
nmhdr.idFrom = ID_LISTVIEW;
|
|
nmhdr.code = NM_RETURN;
|
|
SendMessage(pdfb->hwndView, WM_NOTIFY, nmhdr.idFrom,
|
|
(LPARAM)&nmhdr);
|
|
return(1);
|
|
}
|
|
|
|
|
|
// Not processed
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
//
|
|
// Create a thread to handle this dialog as there may be operations that
|
|
// eat up a lot of time and we don't want to eat up a lot of cycles on the
|
|
// callers thread is it most likely will be the desktop or tray and we need
|
|
// to keep it responsive.
|
|
//
|
|
//
|
|
DWORD CALLBACK DocFind_MainThreadProc(LPVOID lpThreadParameters)
|
|
{
|
|
|
|
HHOOK hhook;
|
|
|
|
// Passed the two id list items in the thread paramters
|
|
hhook = SetWindowsHookEx(WH_MSGFILTER, (HOOKPROC)DocFind_MsgFilter,
|
|
HINST_THISDLL, GetCurrentThreadId());
|
|
|
|
__try
|
|
{
|
|
|
|
DialogBoxParam(HINST_THISDLL, MAKEINTRESOURCE(DLG_FIND),
|
|
NULL, DocFind_DlgProc, (LPARAM)lpThreadParameters);
|
|
}
|
|
__except(SetErrorMode(SEM_NOGPFAULTERRORBOX),UnhandledExceptionFilter(GetExceptionInformation()))
|
|
{
|
|
// Catch if the main thread blows away!
|
|
LPDFBROWSE pdfb;
|
|
|
|
// Now See if we have a PDFB stored away.
|
|
// processed.
|
|
if ((g_dwTlsSlot != 0xffffffff) && ((pdfb = TlsGetValue(g_dwTlsSlot)) == NULL))
|
|
{
|
|
// We will try to release other information that we are holding
|
|
// onto as to not leave leaks
|
|
if (pdfb->psv)
|
|
{
|
|
// We have circular references so need to decrement.
|
|
pdfb->psv->lpVtbl->Release(pdfb->psv);
|
|
pdfb->psv = NULL;
|
|
}
|
|
pdfb->sb.lpVtbl->Release(&pdfb->sb);
|
|
}
|
|
}
|
|
|
|
UnhookWindowsHookEx(hhook);
|
|
|
|
// Free the data that was passed in.
|
|
LocalFree((HLOCAL)lpThreadParameters);
|
|
return(0);
|
|
}
|
|
|
|
|
|
// this is the same as shfindfiles except without the gross hack
|
|
BOOL RealFindFiles(LPCITEMIDLIST pidlFolder, LPCITEMIDLIST pidlSaveFile)
|
|
{
|
|
// Create the thread that will do the search...
|
|
HANDLE hThread;
|
|
DWORD idThread;
|
|
LPDFINIT pdfi;
|
|
|
|
pdfi = LocalAlloc(LPTR, SIZEOF(DFINIT));
|
|
if (pdfi == NULL)
|
|
return FALSE;
|
|
|
|
if (pidlFolder)
|
|
{
|
|
// We should clone it for our own use.
|
|
pdfi->pidlStart = ILClone(pidlFolder);
|
|
}
|
|
pdfi->pidlSaveFile=pidlSaveFile;
|
|
|
|
pdfi->pdfff = CreateDefaultDocFindFilter();
|
|
|
|
hThread = CreateThread(NULL, 0, DocFind_MainThreadProc, (LPVOID)pdfi, 0, &idThread);
|
|
|
|
if (hThread == NULL) {
|
|
LocalFree((HLOCAL)pdfi);
|
|
return FALSE;
|
|
} else {
|
|
CloseHandle(hThread); // Don't need to hold onto it.
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// This is the main external entry point to start a search. This will
|
|
// create a new thread to process the
|
|
//
|
|
BOOL WINAPI SHFindFiles(LPCITEMIDLIST pidlFolder, LPCITEMIDLIST pidlSaveFile)
|
|
{
|
|
// Have we restricted the user of FindX, if so then bail!
|
|
if ( SHRestricted( REST_NOFIND ) )
|
|
return FALSE;
|
|
|
|
// We Need a hack to allow Find to work for cases like
|
|
// Rest of network and workgroups to map to find computer instead
|
|
// This is rather gross, but what the heck. It is also assumed that
|
|
// the pidl is of the type that we know about (either File or network)
|
|
if (pidlFolder)
|
|
{
|
|
BYTE bType;
|
|
bType = SIL_GetType(ILFindLastID(pidlFolder));
|
|
if ((bType == SHID_NET_NETWORK) ||
|
|
(bType == SHID_NET_RESTOFNET) ||
|
|
(bType == SHID_NET_DOMAIN))
|
|
return SHFindComputer(pidlFolder, pidlSaveFile);
|
|
}
|
|
|
|
return RealFindFiles(pidlFolder, pidlSaveFile);
|
|
}
|
|
|
|
|
|
//==========================================================================
|
|
//
|
|
// This is the main external entry point to start a search. This will
|
|
// create a new thread to process the
|
|
//
|
|
BOOL WINAPI SHFindComputer(LPCITEMIDLIST pidlFolder, LPCITEMIDLIST pidlSaveFile)
|
|
{
|
|
// Create the thread that will do the search...
|
|
HANDLE hThread;
|
|
DWORD idThread;
|
|
|
|
LPDFINIT pdfi = LocalAlloc(LPTR, SIZEOF(DFINIT));
|
|
if (pdfi == NULL)
|
|
return FALSE;
|
|
|
|
if (pidlFolder)
|
|
{
|
|
// We should clone it for our own use.
|
|
pdfi->pidlStart = ILClone(pidlFolder);
|
|
}
|
|
pdfi->pidlSaveFile=pidlSaveFile;
|
|
|
|
pdfi->pdfff = CreateDefaultComputerFindFilter();
|
|
|
|
hThread = CreateThread(NULL, 0, DocFind_MainThreadProc, (LPVOID)pdfi, 0, &idThread);
|
|
|
|
if (hThread == NULL) {
|
|
LocalFree((HLOCAL)pdfi);
|
|
return FALSE;
|
|
} else {
|
|
CloseHandle(hThread); // Don't need to hold onto it.
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
//
|
|
// DocFind_DlgProc - The main dialog procedure for the document find
|
|
// window
|
|
//
|
|
void _CDFBrowse_OnSizing(HWND hwndDlg, UINT code, LPRECT lprc);
|
|
void _CDFBrowse_OnSize(HWND hwndDlg, UINT state, int cx, int cy);
|
|
void _CDFBrowse_OnGetMinMaxInfo(HWND hwnd, LPMINMAXINFO lpMinMaxInfo);
|
|
BOOL _CDFBrowse_OnPaint(HWND hwndDlg);
|
|
BOOL _CDFBrowse_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam);
|
|
void _CDFBrowse_OnInitMenuPopup(HWND hwndDlg, HMENU hmInit, int nIndex, BOOL fSystemMenu);
|
|
LRESULT _CDFBrowse_OnCommand(HWND hwnd, UINT id, HWND hwndCtl, UINT codeNotify);
|
|
void _CDFBrowse_handleFSChange(HWND hwnd, LONG code, LPITEMIDLIST *ppidl);
|
|
BOOL _CDFBrowse_OnMsgFilter(HWND hwnd, MSG FAR* lpmsg, int context);
|
|
void _CDFBrowse_OnClose(HWND hwnd);
|
|
void _CDFBrowse_OnDestroy(HWND hwndDlg);
|
|
LRESULT CDFBrowse_ForwardMsg(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
|
|
|
|
|
|
LRESULT DocFind_DlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch (msg)
|
|
{
|
|
HANDLE_MSG(hwndDlg, WM_PAINT, _CDFBrowse_OnPaint);
|
|
HANDLE_MSG(hwndDlg, WM_INITDIALOG, _CDFBrowse_OnInitDialog);
|
|
HANDLE_MSG(hwndDlg, WM_DESTROY, _CDFBrowse_OnDestroy);
|
|
HANDLE_MSG(hwndDlg, WM_CLOSE, _CDFBrowse_OnClose);
|
|
HANDLE_MSG(hwndDlg, WM_SIZE, _CDFBrowse_OnSize);
|
|
HANDLE_MSG(hwndDlg, WM_GETMINMAXINFO, _CDFBrowse_OnGetMinMaxInfo);
|
|
|
|
case WM_INITMENUPOPUP:
|
|
_CDFBrowse_OnInitMenuPopup(hwndDlg, (HMENU)wParam, LOWORD(lParam), HIWORD(lParam));
|
|
// Fall through!
|
|
|
|
case WM_MENUSELECT:
|
|
case WM_INITMENU:
|
|
case WM_ENTERMENULOOP:
|
|
case WM_EXITMENULOOP:
|
|
case WM_DRAWITEM:
|
|
case WM_MEASUREITEM:
|
|
CDFBrowse_ForwardMsg(hwndDlg, msg, wParam, lParam);
|
|
break;
|
|
|
|
case WM_WININICHANGE:
|
|
case WM_SYSCOLORCHANGE:
|
|
RelayMessageToChildren(hwndDlg, msg, wParam, lParam);
|
|
break;
|
|
|
|
case WM_SIZING:
|
|
_CDFBrowse_OnSizing(hwndDlg, wParam, (LPRECT)lParam);
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
//
|
|
// The WM_COMMAND processing for the Tab control needs to be
|
|
// able to return 0 to imply it is ok to change pages.
|
|
//
|
|
SetWindowLong(hwndDlg, DWL_MSGRESULT,
|
|
_CDFBrowse_OnCommand(hwndDlg, GET_WM_COMMAND_ID(wParam, lParam),
|
|
GET_WM_COMMAND_HWND(wParam, lParam),
|
|
GET_WM_COMMAND_CMD(wParam, lParam)));
|
|
break;
|
|
|
|
case WM_NOTIFY:
|
|
SetWindowLong(hwndDlg, DWL_MSGRESULT,
|
|
_CDFBrowse_OnNotify(hwndDlg, (LPNMHDR)lParam));
|
|
break;
|
|
|
|
case WM_HELP:
|
|
WinHelp((HWND) ((LPHELPINFO) lParam)->hItemHandle, NULL, HELP_WM_HELP,
|
|
(DWORD) (LPTSTR) aFindHelpIDs);
|
|
break;
|
|
|
|
case WM_CONTEXTMENU: // right mouse click
|
|
if ((int)SendMessage(hwndDlg, WM_NCHITTEST, 0, lParam) != HTCLIENT)
|
|
return FALSE; // don't process it
|
|
WinHelp((HWND) wParam, NULL, HELP_CONTEXTMENU,
|
|
(DWORD) (LPTSTR) aFindHelpIDs);
|
|
break;
|
|
|
|
case WM_DF_FSNOTIFY:
|
|
{
|
|
LPSHChangeNotificationLock pshcnl;
|
|
LPITEMIDLIST *ppidl;
|
|
LONG lEvent;
|
|
|
|
pshcnl = SHChangeNotification_Lock((HANDLE)wParam, (DWORD)lParam, &ppidl, &lEvent);
|
|
if (pshcnl)
|
|
{
|
|
_CDFBrowse_handleFSChange(hwndDlg, lEvent, ppidl);
|
|
SHChangeNotification_Unlock(pshcnl);
|
|
}
|
|
}
|
|
break;
|
|
|
|
// Handle any CWM_ messages that are needed to make the
|
|
// docfind act like a folder
|
|
case CWM_GETISHELLBROWSER:
|
|
SetWindowLong(hwndDlg, DWL_MSGRESULT, (LONG)DocFind_GetPdfb(hwndDlg));
|
|
break;
|
|
|
|
case WM_DF_THREADNOTIFY:
|
|
DocFind_ProcessThreadNotify(hwndDlg, wParam, lParam);
|
|
break;
|
|
|
|
case CWM_SETPATH:
|
|
case CWM_COMPAREPIDL:
|
|
case CWM_GETSETCURRENTINFO:
|
|
case CWM_SELECTITEM:
|
|
Assert(FALSE);
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// By default we did not process it. Return false to let the default
|
|
// dialog predure process it.
|
|
return TRUE;
|
|
}
|
|
|
|
void CDFBrowse_CalcViewRect(LPDFBROWSE this, RECT * prc)
|
|
{
|
|
RECT rcTabs;
|
|
RECT rcDlg;
|
|
|
|
// For First approximation, we will assume that the control
|
|
// will be created starting at the same X as the Tab control
|
|
// and a Y below the tab control. This will all be changed
|
|
// when we process of the WM_SIZE message for the top control
|
|
GetClientRect(this->hwndDlg, &rcDlg);
|
|
GetWindowRect(GetDlgItem(this->hwndDlg, IDD_PAGELIST), &rcTabs);
|
|
MapWindowPoints(HWND_DESKTOP, this->hwndDlg, (POINT FAR*)&rcTabs, 2);
|
|
|
|
prc->left = rcTabs.left;
|
|
prc->right = rcDlg.right - rcTabs.left;
|
|
prc->top = rcTabs.bottom + rcTabs.top;
|
|
prc->bottom = rcDlg.bottom - rcTabs.top; // will adjust later
|
|
}
|
|
//==========================================================================
|
|
//
|
|
// _CDFBrowse_OnInitDialog - Process the WM_INITDLG message
|
|
//
|
|
BOOL _CDFBrowse_OnInitDialog(HWND hwndDlg, HWND hwndFocus, LPARAM lParam)
|
|
{
|
|
LPDFINIT pdfi = (LPDFINIT) lParam;
|
|
LPDFBROWSE pdfb;
|
|
HDPA hdpaPaths = NULL;
|
|
HMENU hmenu;
|
|
LPTSTR pszTitle;
|
|
HICON hIconSmall, hIconLarge;
|
|
RECT rcDlg;
|
|
RECT rcView;
|
|
HKEY hkeyExp;
|
|
DWORD cbData;
|
|
IStream *pstmRestore = NULL;
|
|
DFHEADER dfh;
|
|
DECLAREWAITCURSOR;
|
|
|
|
//
|
|
// Make this window foreground.
|
|
//
|
|
SetForegroundWindow(hwndDlg);
|
|
|
|
pdfb = (LPDFBROWSE)LocalAlloc(LPTR, SIZEOF(CDFBrowse));
|
|
if (!pdfb)
|
|
goto ErrorReturn;
|
|
|
|
//
|
|
// Initialize the Vtbl and count
|
|
//
|
|
pdfb->sb.lpVtbl = &s_DFBVtbl;
|
|
pdfb->cRef = 1;
|
|
|
|
|
|
// Create our two dpas that we use
|
|
pdfb->hdpaItemsToAdd = DPA_CreateEx(64, GetProcessHeap());
|
|
pdfb->hdpaPrevAdd = DPA_CreateEx(64, GetProcessHeap());
|
|
|
|
pdfb->hwndDlg = hwndDlg;
|
|
//pdfb->hwndCurPage = NULL;
|
|
pdfb->hwndTabs = GetDlgItem(hwndDlg, IDD_PAGELIST);
|
|
|
|
|
|
// Initialize the menu options from the flags
|
|
//
|
|
// Set the window small & big icons
|
|
//
|
|
pdfb->pdfff = pdfi->pdfff;
|
|
if (pdfb->pdfff == NULL)
|
|
goto Abort;
|
|
pdfb->pdfff->lpVtbl->GetIconsAndMenu(pdfb->pdfff, hwndDlg,
|
|
&hIconSmall, &hIconLarge, &hmenu);
|
|
|
|
SendMessage(hwndDlg, WM_SETICON, FALSE, (LPARAM) hIconSmall);
|
|
SendMessage(hwndDlg, WM_SETICON, TRUE, (LPARAM) hIconLarge);
|
|
|
|
// Set the menu
|
|
Assert(hmenu);
|
|
|
|
{
|
|
HMENU hMenuOld = GetMenu(hwndDlg);
|
|
if (hMenuOld)
|
|
{
|
|
DestroyMenu(hMenuOld);
|
|
}
|
|
}
|
|
|
|
SetMenu(hwndDlg, hmenu);
|
|
pdfb->hmenuTemplate = hmenu;
|
|
|
|
Button_Enable(GetDlgItem(hwndDlg, IDD_STOP), FALSE);
|
|
|
|
//
|
|
// Add a statusbar to the window
|
|
//
|
|
pdfb->hwndStatus = GetDlgItem(hwndDlg, IDD_STATUS);
|
|
{
|
|
int border[3];
|
|
int nParts[3];
|
|
int nInch;
|
|
HDC hdc;
|
|
|
|
border[0] = 0;
|
|
border[1] = -1;
|
|
border[2] = 2;
|
|
SendMessage(pdfb->hwndStatus, SB_SETBORDERS, 0, (LPARAM)(LPINT)border);
|
|
|
|
// BUGBUG::Setup status the same as cabinets. What do we need?
|
|
hdc = GetDC(NULL);
|
|
nInch = GetDeviceCaps(hdc, LOGPIXELSX);
|
|
ReleaseDC(NULL, hdc);
|
|
|
|
nParts[0] = nInch * 9 / 4;
|
|
nParts[1] = nParts[0] + nInch * 7 / 4;
|
|
nParts[2] = nParts[1] + nInch * 5 / 2;
|
|
SendMessage(pdfb->hwndStatus, SB_SETPARTS, 3, (LPARAM)(LPINT)nParts);
|
|
}
|
|
|
|
pdfb->fDirChanged = TRUE; // First time update display...
|
|
// pdfb->fFilesAdded = FALSE; // have any files been added in this time
|
|
// pdfb->dwLastUpdateTime = 0L; // dito
|
|
pdfb->SortMode = -1; // Initially not sorted
|
|
// pdfb->ulNotify = 0; // Start with no notifications...
|
|
|
|
pdfb->pidlStart = (LPITEMIDLIST)pdfi->pidlStart; // Where to start search from;
|
|
pdfb->pidlSaveFile = (LPITEMIDLIST)pdfi->pidlSaveFile; // Save file path information.
|
|
|
|
hkeyExp = GetExplorerHkey(FALSE);
|
|
cbData = SIZEOF(pdfb->dwFlags);
|
|
if (!hkeyExp ||
|
|
!Reg_GetStruct(hkeyExp, s_szDocFind, s_szFlags, &pdfb->dwFlags, &cbData)) {
|
|
pdfb->dwFlags = 0;
|
|
}
|
|
|
|
// pdfb->pft = NULL;
|
|
InitializeCriticalSection(&pdfb->csSearch);
|
|
|
|
// And save away pointer to our structure
|
|
SetWindowLong(hwndDlg, DWL_USER, (LONG)pdfb);
|
|
|
|
if (g_dwTlsSlot == 0xffffffff)
|
|
g_dwTlsSlot = TlsAlloc();
|
|
TlsSetValue(g_dwTlsSlot, pdfb);
|
|
|
|
|
|
SetWaitCursor();
|
|
|
|
// Create a IShellFolder object
|
|
if (FAILED(CDFFolder_Create(pdfb->pdfff, hwndDlg, &pdfb->pdfc)))
|
|
goto Abort;
|
|
|
|
//
|
|
// Also create a view object
|
|
//
|
|
if (FAILED(pdfb->pdfc->lpVtbl->CreateViewObject(pdfb->pdfc, NULL,
|
|
&IID_IShellView, &pdfb->psv)))
|
|
goto Abort;
|
|
|
|
// And the window that corresponds to it.
|
|
// First we need to initialize the view info structure.
|
|
pdfb->fs.ViewMode = FVM_DETAILS;
|
|
pdfb->fs.fFlags = 0;
|
|
|
|
// Now see if there is a restore object that we need to initialize
|
|
// information from...
|
|
//
|
|
// If a path name was passed in, read it in now
|
|
if (pdfb->pidlSaveFile != NULL)
|
|
{
|
|
if (DocFind_ReadHeader(pdfb, &pstmRestore, &dfh))
|
|
{
|
|
pdfb->fs.ViewMode = dfh.ViewMode;
|
|
}
|
|
}
|
|
|
|
|
|
CDFBrowse_CalcViewRect(pdfb, &rcView);
|
|
|
|
if (FAILED(pdfb->psv->lpVtbl->CreateViewWindow(pdfb->psv, NULL,
|
|
&pdfb->fs, &pdfb->sb, &rcView, &pdfb->hwndView)))
|
|
{
|
|
pdfb->hwndView = NULL;
|
|
}
|
|
|
|
//
|
|
// We should activate the view window (always activated).
|
|
// Passing SVUIA_ACTIVATE_FOCUS means "let it behave like it
|
|
// has the focus" (without really switching the focus).
|
|
//
|
|
pdfb->psv->lpVtbl->UIActivate(pdfb->psv, SVUIA_ACTIVATE_FOCUS);
|
|
|
|
//
|
|
// Make sure that the window has tabstop style...
|
|
//
|
|
if (pdfb->hwndView)
|
|
{
|
|
|
|
SetWindowLong(pdfb->hwndView, GWL_STYLE,
|
|
GetWindowLong(pdfb->hwndView, GWL_STYLE) | WS_TABSTOP);
|
|
}
|
|
|
|
// Now lets Initialize the pages in the tab list to those that
|
|
// in the list...
|
|
//
|
|
|
|
// If a path name was passed in, read it in now
|
|
if (pstmRestore != NULL)
|
|
{
|
|
DocFind_ReadCriteriaAndResults(pdfb, pstmRestore, &dfh);
|
|
pstmRestore = NULL;
|
|
}
|
|
|
|
// Now toward the end of the process add in the find pages as to
|
|
// allow us to have our criterias read in before we initialize any
|
|
// of the pages.
|
|
pdfb->pdfff->lpVtbl->AddPages(pdfb->pdfff, pdfb->hwndTabs, pdfb->pidlStart);
|
|
|
|
pdfb->pdfff->lpVtbl->GenerateTitle(pdfb->pdfff, &pszTitle, FALSE);
|
|
if (pszTitle != NULL)
|
|
{
|
|
SetWindowText(pdfb->hwndDlg, pszTitle);
|
|
SHFree(pszTitle); // And free the title string.
|
|
}
|
|
|
|
//
|
|
// If the view is not supposed to be visible resize the dialog
|
|
// to not show the view
|
|
//
|
|
|
|
if (!pdfb->fShowResults)
|
|
{
|
|
HWND hwndAnimate;
|
|
RECT rcAnimate;
|
|
RECT rcTabs;
|
|
GetClientRect(hwndDlg, &rcDlg);
|
|
|
|
GetWindowRect(pdfb->hwndTabs, &rcTabs);
|
|
MapWindowPoints(HWND_DESKTOP, hwndDlg, (POINT FAR*)&rcTabs, 2);
|
|
// Resize the dialog to have enough room for
|
|
// the tabs and status bar.
|
|
SendMessage(pdfb->hwndStatus, WM_SIZE, 0, 0);
|
|
ShowWindow(pdfb->hwndStatus, SW_HIDE); // hide this window for now
|
|
|
|
|
|
// Now calculate the size window we need...
|
|
rcDlg.bottom = rcTabs.bottom + rcTabs.top;
|
|
|
|
// See if the animate item will fit in the small size or not...
|
|
hwndAnimate = GetDlgItem(hwndDlg, IDD_ANIMATE);
|
|
SendMessage(hwndAnimate, WM_PAINT, 0, 0); // Try to get it to size
|
|
GetWindowRect(hwndAnimate, &rcAnimate);
|
|
MapWindowPoints(HWND_DESKTOP, hwndDlg, (POINT FAR*)&rcAnimate, 2);
|
|
if (rcAnimate.bottom > rcDlg.bottom)
|
|
ShowWindow(hwndAnimate, SW_HIDE);
|
|
|
|
// And size the window...
|
|
AdjustWindowRectEx(&rcDlg, GetWindowStyle(hwndDlg), TRUE,
|
|
GetWindowExStyle(hwndDlg));
|
|
|
|
pdfb->cyNoResults = rcDlg.bottom - rcDlg.top;
|
|
SetWindowPos(hwndDlg, NULL, 0, 0, rcDlg.right - rcDlg.left,
|
|
pdfb->cyNoResults,
|
|
SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE);
|
|
|
|
|
|
if (pdfb->hwndCurPage)
|
|
{
|
|
// Find the first window who would like the focus!
|
|
hwndFocus = GetNextDlgTabItem(pdfb->hwndCurPage, NULL, FALSE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// If it is a saved query set the focus on the start button else
|
|
// on the path field.
|
|
hwndFocus = GetDlgItem(hwndDlg, IDD_START);
|
|
}
|
|
|
|
SetFocus(hwndFocus);
|
|
goto Exit;
|
|
|
|
// Failure: Try to clean up
|
|
Abort:
|
|
// We can simply just release the pdfb, which should clean everything
|
|
// else up!
|
|
//
|
|
if (pstmRestore)
|
|
pstmRestore->lpVtbl->Release(pstmRestore);
|
|
|
|
pdfb->sb.lpVtbl->Release(&pdfb->sb);
|
|
ErrorReturn:
|
|
EndDialog(hwndDlg, FALSE);
|
|
|
|
Exit:
|
|
ResetWaitCursor();
|
|
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
|
|
//==========================================================================
|
|
//
|
|
// _CDFBrowse_OnDestry - Process the WM_DESTRY message, by destroying all
|
|
// of the resourcess that were allocated to the find dialog
|
|
//
|
|
void _CDFBrowse_OnDestroy(HWND hwndDlg)
|
|
{
|
|
LPDFBROWSE pdfb;
|
|
|
|
pdfb = DocFind_GetPdfb(hwndDlg);
|
|
|
|
// Simply call the release function for our class
|
|
if (pdfb)
|
|
{
|
|
STDAPI SHFlushClipboard(void);
|
|
SHFlushClipboard();
|
|
|
|
if (pdfb->psv)
|
|
{
|
|
//
|
|
// We need to unmerge the menu before destroying the menu
|
|
// by ourselves.
|
|
//
|
|
pdfb->psv->lpVtbl->UIActivate(pdfb->psv, SVUIA_DEACTIVATE);
|
|
|
|
//
|
|
// We need to release the IShellView explicitly here. Otherwise,
|
|
// neither psv nor pdfb will be freed because they have a reference
|
|
// to each other.
|
|
//
|
|
pdfb->psv->lpVtbl->Release(pdfb->psv);
|
|
pdfb->psv = NULL;
|
|
}
|
|
|
|
if (pdfb->hmenuTemplate!=GetMenu(hwndDlg) && pdfb->hmenuTemplate) {
|
|
DestroyMenu(pdfb->hmenuTemplate);
|
|
pdfb->hmenuTemplate = NULL;
|
|
}
|
|
|
|
pdfb->sb.lpVtbl->Release(&pdfb->sb);
|
|
}
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// _CDFBrowse_OnClose - Process the WM_CLOSE message, by simply ending the
|
|
// dialog
|
|
void _CDFBrowse_OnClose(HWND hwndDlg)
|
|
{
|
|
EndDialog(hwndDlg, FALSE);
|
|
}
|
|
|
|
//
|
|
// BOGUS
|
|
// Remove this for build 48/49
|
|
//
|
|
BOOL _CDFBrowse_OnPaint(HWND hwndDlg)
|
|
{
|
|
LPDFBROWSE pdfb;
|
|
PAINTSTRUCT ps;
|
|
RECT rc;
|
|
|
|
if (!IsIconic(hwndDlg))
|
|
{
|
|
pdfb = DocFind_GetPdfb(hwndDlg);
|
|
BeginPaint(hwndDlg, &ps);
|
|
GetClientRect(hwndDlg, &rc);
|
|
|
|
// Need to draw an edge just below menu...
|
|
// BUGBUG:: need ui designers to review...
|
|
DrawEdge(ps.hdc, &rc, EDGE_ETCHED, BF_TOP);
|
|
EndPaint(hwndDlg, &ps);
|
|
}
|
|
else
|
|
FORWARD_WM_PAINT(hwndDlg, DefWindowProc);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
LRESULT CDFBrowse_ForwardMsg(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
LPDFBROWSE pdfb = DocFind_GetPdfb(hwndDlg);
|
|
return SendMessage(pdfb->hwndView, msg, wParam, lParam);
|
|
}
|
|
|
|
//==========================================================================
|
|
// SHGetIContextMenuForAbsPIDL
|
|
//==========================================================================
|
|
HRESULT SHGetIContextMenuForAbsPIDL(LPITEMIDLIST pidl,
|
|
IContextMenu **ppcm)
|
|
|
|
{
|
|
HRESULT hres;
|
|
LPITEMIDLIST pidlParent;
|
|
IShellFolder *psf;
|
|
IContextMenu *pcm;
|
|
LPSHELLFOLDER psfDesktop = Desktop_GetShellFolder(TRUE);
|
|
|
|
pidlParent = ILClone(pidl);
|
|
if (pidlParent == NULL)
|
|
return ResultFromScode(E_OUTOFMEMORY);
|
|
|
|
if (!ILRemoveLastID(pidlParent))
|
|
{
|
|
ILFree(pidlParent);
|
|
return(ResultFromScode(E_INVALIDARG));
|
|
}
|
|
|
|
// Now bind to IShellFolder
|
|
if (ILIsEmpty(pidlParent))
|
|
{
|
|
psf = psfDesktop;
|
|
psf->lpVtbl->AddRef(psf);
|
|
hres = NOERROR;
|
|
}
|
|
else
|
|
hres = psfDesktop->lpVtbl->BindToObject(psfDesktop,
|
|
pidlParent, NULL, &IID_IShellFolder, &psf);
|
|
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
LPCITEMIDLIST pidlLastID = ILFindLastID(pidl);
|
|
|
|
// Now Get the IContextMenu for the object
|
|
if (SUCCEEDED(hres = psf->lpVtbl->GetUIObjectOf(psf, NULL, 1,
|
|
&pidlLastID, &IID_IContextMenu, NULL, &pcm)))
|
|
{
|
|
*ppcm = pcm; // Return the IContextMenu to caller
|
|
hres = NOERROR;
|
|
}
|
|
|
|
// Free our use of the IShellFolder;
|
|
psf->lpVtbl->Release(psf);
|
|
}
|
|
|
|
// free the id list we allocated
|
|
ILFree(pidlParent);
|
|
return(hres);
|
|
}
|
|
|
|
|
|
//==========================================================================
|
|
//
|
|
// DocFind_HandleOpenContainingFolder - This function will process
|
|
// the Open Containing folder ocmmand, by walking through each
|
|
// of the selected items and calling the open function on the
|
|
// folder that contains the item. We might also try to select
|
|
// the item in the new folder...
|
|
//
|
|
void DocFind_HandleOpenContainingFolder(LPDFBROWSE pdfb)
|
|
{
|
|
|
|
// Ok lets ask the view for the list of selected objects.
|
|
LPITEMIDLIST *ppidls; // pointer to a list of pidls.
|
|
int cpidls; // Count of pidls that were returned.
|
|
int i;
|
|
|
|
cpidls = ShellFolderView_GetSelectedObjects(pdfb->hwndDlg, &ppidls);
|
|
if (cpidls > 0)
|
|
{
|
|
for (i = 0; i < cpidls; i++)
|
|
{
|
|
LPITEMIDLIST pidl;
|
|
IContextMenu *pcm;
|
|
|
|
// See if we have already processed this one.
|
|
if (ppidls[i] == NULL)
|
|
continue;
|
|
|
|
// Now get the parent of it.
|
|
pidl = CDFolder_GetParentsPIDL(pdfb->pdfc, ppidls[i]);
|
|
|
|
// Now attempt to get the IContextMenu for this guy
|
|
if (SUCCEEDED(SHGetIContextMenuForAbsPIDL(pidl, &pcm)))
|
|
{
|
|
HMENU hmenu = CreatePopupMenu();
|
|
HWND hwndCabinet = NULL;
|
|
|
|
if (hmenu)
|
|
{
|
|
UINT idCmd;
|
|
|
|
pcm->lpVtbl->QueryContextMenu(pcm, hmenu, 0, 1, (IDCMD_SYSTEMLAST-1), CMF_DEFAULTONLY);
|
|
|
|
idCmd = GetMenuDefaultItem(hmenu, MF_BYCOMMAND, 0);
|
|
if (idCmd)
|
|
{
|
|
CMINVOKECOMMANDINFO ici = {
|
|
SIZEOF(CMINVOKECOMMANDINFO),
|
|
0L,
|
|
pdfb->hwndDlg,
|
|
(LPSTR)MAKEINTRESOURCE(idCmd - 1),
|
|
NULL, NULL, SW_NORMAL,
|
|
};
|
|
|
|
// Setup to wait ...
|
|
SHWaitForFileToOpen(pidl, WFFO_ADD, 0L);
|
|
|
|
pcm->lpVtbl->InvokeCommand(pcm, &ici);
|
|
|
|
// Now wait for it to open...
|
|
SHWaitForFileToOpen(pidl, WFFO_REMOVE | WFFO_WAIT, WFFO_WAITTIME);
|
|
|
|
hwndCabinet = FindWindow(c_szCabinetClass, NULL);
|
|
}
|
|
|
|
DestroyMenu(hmenu);
|
|
}
|
|
|
|
// Release our use of the context menu
|
|
pcm->lpVtbl->Release(pcm);
|
|
|
|
// See if the above succeeded and found the appropriate
|
|
// window. If so we will try to select the appropariate
|
|
// items.
|
|
//
|
|
if (hwndCabinet)
|
|
{
|
|
HANDLE hidl;
|
|
DWORD dwProcId;
|
|
UINT uidlSize;
|
|
|
|
dwProcId = GetCurrentProcessId();
|
|
uidlSize = ILGetSize(pidl);
|
|
|
|
hidl = SHAllocShared(NULL, SIZEOF(BOOL)+uidlSize, dwProcId);
|
|
|
|
// First make sure we have the right one...
|
|
// May want to create a compare path function...
|
|
if (hidl)
|
|
{
|
|
LPBYTE lpb;
|
|
|
|
lpb = SHLockShared(hidl,dwProcId);
|
|
*(BOOL *)lpb = FALSE; // not a parent comparison
|
|
hmemcpy(lpb+SIZEOF(BOOL),pidl,uidlSize);
|
|
SHUnlockShared(lpb);
|
|
|
|
if (SendMessage(hwndCabinet, CWM_COMPAREPIDL, (WPARAM)dwProcId, (LPARAM)hidl))
|
|
{
|
|
int j;
|
|
|
|
// Need to turn into global memory...
|
|
HANDLE hidl;
|
|
DWORD dwProcId;
|
|
|
|
GetWindowThreadProcessId(hwndCabinet, &dwProcId);
|
|
hidl = SHAllocShared(ppidls[i],ILGetSize(ppidls[i]),dwProcId);
|
|
if (hidl)
|
|
{
|
|
// Receiver is responsible for freeing.
|
|
SendMessage(hwndCabinet, CWM_SELECTITEM,
|
|
SVSI_SELECT | SVSI_DESELECTOTHERS | SVSI_ENSUREVISIBLE,
|
|
(LPARAM)hidl);
|
|
}
|
|
|
|
// Now see if there are any other items selected in
|
|
// this same cabinet. If so we might as well process
|
|
// them here and save the work of trying to open it
|
|
// again and the like!
|
|
for (j=i+1; j < cpidls; j++)
|
|
{
|
|
if (ppidls[j] == NULL)
|
|
continue;
|
|
|
|
// Now see if it has the same parent as we
|
|
// are processing...
|
|
if (CDFolder_GetParentsPIDL(pdfb->pdfc, ppidls[j])
|
|
== pidl)
|
|
{
|
|
hidl = SHAllocShared(ppidls[j],ILGetSize(ppidls[j]),dwProcId);
|
|
if (hidl)
|
|
{
|
|
// Receiver is responsible for freeing.
|
|
SendMessage(hwndCabinet, CWM_SELECTITEM,
|
|
SVSI_SELECT, (LPARAM)hidl);
|
|
}
|
|
ppidls[j] = NULL; // dont process again.
|
|
}
|
|
}
|
|
}
|
|
SHFreeShared(hidl,dwProcId);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Free the memory associated with the item list.
|
|
if (ppidls != NULL)
|
|
LocalFree((HLOCAL)ppidls);
|
|
}
|
|
|
|
|
|
//==========================================================================
|
|
//
|
|
// DocFind_Save
|
|
// Save away the current search to a file on the desktop.
|
|
// For now the name will be automatically generated.
|
|
//
|
|
void DocFind_Save(LPDFBROWSE pdfb)
|
|
{
|
|
TCHAR szFilePath[MAX_PATH];
|
|
IStream * pstm;
|
|
DFHEADER dfh;
|
|
TCHAR szTemp[MAXPATHLEN];
|
|
int i;
|
|
SHORT cb;
|
|
HRESULT hres;
|
|
LPITEMIDLIST pidl;
|
|
LARGE_INTEGER dlibMove = {0, 0};
|
|
ULARGE_INTEGER libCurPos;
|
|
FOLDERSETTINGS fs;
|
|
|
|
|
|
LPCTSTR pszLastPath = c_szNULL; // Null string to begin with.
|
|
|
|
//
|
|
// See if the search already has a file name associated with it. If so
|
|
// we will save it in it, else we will create a new file on the desktop
|
|
if (GetScode(pdfb->pdfff->lpVtbl->FFilterChanged(pdfb->pdfff)))
|
|
{
|
|
if (pdfb->pidlSaveFile)
|
|
{
|
|
// Lets blow away the save file
|
|
ILFree(pdfb->pidlSaveFile);
|
|
pdfb->pidlSaveFile = NULL;
|
|
}
|
|
}
|
|
|
|
// If it still looks like we want to continue to use a save file then
|
|
// continue.
|
|
if (pdfb->pidlSaveFile)
|
|
{
|
|
SHGetPathFromIDList(pdfb->pidlSaveFile, szFilePath);
|
|
pstm = OpenFileStream(szFilePath, OF_CREATE | OF_WRITE | OF_SHARE_DENY_WRITE);
|
|
}
|
|
else
|
|
{
|
|
LPTSTR lpsz;
|
|
LPTSTR pszTitle;
|
|
TCHAR szShortName[12];
|
|
|
|
// First get the path name to the Desktop.
|
|
SHGetSpecialFolderPath(NULL, szFilePath, CSIDL_DESKTOPDIRECTORY, TRUE);
|
|
|
|
// and update the title
|
|
// we now do this before getting a filename because we generate
|
|
// the file name from the title
|
|
|
|
pdfb->pdfff->lpVtbl->GenerateTitle(pdfb->pdfff, &pszTitle, TRUE);
|
|
if (pszTitle)
|
|
{
|
|
// Now add on the extension.
|
|
lstrcpyn(szTemp, pszTitle, MAX_PATH - (lstrlen(szFilePath) + 1 + 4 + 1+3));
|
|
lstrcat(szTemp, TEXT(".fnd"));
|
|
|
|
SHFree(pszTitle); // And free the title string.
|
|
}
|
|
|
|
// *s and ?s are illegal.. replace with @ and !
|
|
for (lpsz = szTemp; NULL != (lpsz = StrChr(lpsz, TEXT(':'))) ; ) *lpsz = TEXT('-');
|
|
for (lpsz = szTemp; NULL != (lpsz = StrChr(lpsz, TEXT('*'))) ; ) *lpsz = TEXT('@');
|
|
for (lpsz = szTemp; NULL != (lpsz = StrChr(lpsz, TEXT('?'))) ; ) *lpsz = TEXT('!');
|
|
|
|
LoadString(HINST_THISDLL, IDS_FIND_SHORT_NAME, szShortName, ARRAYSIZE(szShortName));
|
|
if (!PathYetAnotherMakeUniqueName(szFilePath, szFilePath, szShortName, szTemp))
|
|
return;
|
|
|
|
pstm = OpenFileStream(szFilePath, OF_CREATE | OF_WRITE | OF_SHARE_DENY_WRITE);
|
|
|
|
if (pstm != NULL)
|
|
{
|
|
pdfb->pidlSaveFile = ILCreateFromPath(szFilePath);
|
|
}
|
|
}
|
|
|
|
if (pstm == NULL)
|
|
return;
|
|
|
|
// Now setup and write out header information
|
|
dfh.wSig = DOCFIND_SIG;
|
|
dfh.wVer = DF_CURFILEVER;
|
|
dfh.dwFlags = pdfb->dwFlags;
|
|
dfh.wSortOrder = (WORD)pdfb->SortMode;
|
|
dfh.wcbItem = SIZEOF(DFITEM);
|
|
dfh.oCriteria = SIZEOF(DFHEADER);
|
|
// dfh.cCriteria = sizeof(s_aIndexes) / sizeof(SHORT);
|
|
// dfh.oResults =;
|
|
|
|
// Not used anymore...
|
|
dfh.cResults = -1;
|
|
|
|
//
|
|
// Note: Later we may convert this to DOCFILE where the
|
|
// criteria is stored as properties.
|
|
//
|
|
|
|
// Get the current Folder Settings
|
|
if (SUCCEEDED(pdfb->psv->lpVtbl->GetCurrentInfo(pdfb->psv, &fs)))
|
|
dfh.ViewMode = fs.ViewMode;
|
|
else
|
|
dfh.ViewMode = FVM_DETAILS;
|
|
|
|
//
|
|
// Now call the filter object to save out his own set of criterias
|
|
|
|
dlibMove.LowPart = dfh.oCriteria;
|
|
pstm->lpVtbl->Seek(pstm, dlibMove, STREAM_SEEK_SET, NULL);
|
|
hres = pdfb->pdfff->lpVtbl->SaveCriteria(pdfb->pdfff, pstm, DFC_FMT_ANSI);
|
|
if (SUCCEEDED(hres))
|
|
dfh.cCriteria = GetScode(hres);
|
|
|
|
// Now setup to output the results
|
|
dlibMove.LowPart = 0;
|
|
pstm->lpVtbl->Seek(pstm, dlibMove, STREAM_SEEK_CUR, &libCurPos); // Get current pos
|
|
dfh.oResults = libCurPos.LowPart;
|
|
//
|
|
// Now Let our file folder serialize his results out here also...
|
|
// But only if the option is set to do so...
|
|
//
|
|
cb = 0;
|
|
if (pdfb->dwFlags & DFOO_SAVERESULTS)
|
|
{
|
|
CDFFolder_SaveFolderList(pdfb->pdfc, pstm);
|
|
|
|
// And Save the items that are in the list
|
|
for (i=0;; i++)
|
|
{
|
|
pidl = (LPITEMIDLIST)ShellFolderView_GetObject(pdfb->hwndDlg, i);
|
|
if (pidl == NULL)
|
|
break;
|
|
|
|
ILSaveToStream(pstm, pidl);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Write out a Trailing NULL for Folder list
|
|
pstm->lpVtbl->Write(pstm, &cb, SIZEOF(cb), NULL);
|
|
}
|
|
|
|
// Write out a Trailing NULL size to say end of pidl list...
|
|
pstm->lpVtbl->Write(pstm, &cb, SIZEOF(cb), NULL);
|
|
|
|
#ifdef WINNT
|
|
{
|
|
//
|
|
// See comment at top of file for DFC_UNICODE_DESC.
|
|
//
|
|
DFC_UNICODE_DESC desc;
|
|
|
|
//
|
|
// Get the current location in stream. This is the offset where
|
|
// we'll write the unicode find criteria. Save this
|
|
// value (along with NT-specific signature) in the descriptor
|
|
//
|
|
dlibMove.LowPart = 0;
|
|
pstm->lpVtbl->Seek(pstm, dlibMove, STREAM_SEEK_CUR, &libCurPos);
|
|
|
|
desc.oUnicodeCriteria.QuadPart = libCurPos.QuadPart;
|
|
desc.NTsignature = c_NTsignature;
|
|
|
|
// Append the Unicode version of the find criteria.
|
|
hres = pdfb->pdfff->lpVtbl->SaveCriteria(pdfb->pdfff, pstm, DFC_FMT_UNICODE);
|
|
|
|
// Append the unicode criteria descriptor to the end of the file.
|
|
pstm->lpVtbl->Write(pstm, &desc, SIZEOF(desc), NULL);
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
//
|
|
// Finally output the header information at the start of the file
|
|
// and close the file
|
|
//
|
|
dlibMove.LowPart = 0;
|
|
pstm->lpVtbl->Seek(pstm, dlibMove, STREAM_SEEK_SET, NULL);
|
|
pstm->lpVtbl->Write(pstm, (LPTSTR)&dfh, SIZEOF(dfh), NULL);
|
|
pstm->lpVtbl->Release(pstm);
|
|
|
|
|
|
SHChangeNotify(SHCNE_CREATE, SHCNF_IDLIST, pdfb->pidlSaveFile, NULL);
|
|
SHChangeNotify(SHCNE_FREESPACE, SHCNF_IDLIST, pdfb->pidlSaveFile, NULL);
|
|
}
|
|
|
|
|
|
//==========================================================================
|
|
//
|
|
// DocFind_ReadHeader
|
|
// Opens the save file and reads in the header information, that can
|
|
// be used to restore some of the view state information.
|
|
//
|
|
BOOL DocFind_ReadHeader(LPDFBROWSE pdfb, IStream **ppstm,
|
|
DFHEADER *pdfh)
|
|
{
|
|
|
|
LPTSTR pszLastPath = NULL;
|
|
ULONG cbRead;
|
|
IStream * pstm;
|
|
TCHAR szPathName[MAXPATHLEN];
|
|
LARGE_INTEGER dlibMove = {0, 0};
|
|
|
|
//
|
|
// First try to open the file
|
|
//
|
|
|
|
SHGetPathFromIDList(pdfb->pidlSaveFile, szPathName);
|
|
pstm = OpenFileStream(szPathName, OF_READ);
|
|
*ppstm = pstm;
|
|
if (pstm == NULL)
|
|
return FALSE;
|
|
|
|
// Now Read in the header
|
|
// Note: in theory I should test the size read by the size of the
|
|
// smaller headers, but if the number of bytes read is smaller than
|
|
// the few new things added then there is nothing to restore anyway...
|
|
|
|
if (FAILED(pstm->lpVtbl->Read(pstm, pdfh, SIZEOF(DFHEADER), &cbRead))
|
|
|| (cbRead != SIZEOF(DFHEADER)) || (pdfh->wSig != DOCFIND_SIG)
|
|
|| (pdfh->wVer > DF_CURFILEVER))
|
|
{
|
|
// Not the correct format...
|
|
pstm->lpVtbl->Release(pstm);
|
|
*ppstm = NULL;
|
|
return(FALSE);
|
|
}
|
|
|
|
if (pdfh->wVer < 3)
|
|
{
|
|
// The ViewMode was added in version 3.
|
|
pdfh->ViewMode = FVM_DETAILS;
|
|
}
|
|
return(TRUE);
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// DocFind_ReadCriteriaAndResults
|
|
// Save away the current search to a file on the desktop.
|
|
// For now the name will be automatically generated.
|
|
//
|
|
BOOL DocFind_ReadCriteriaAndResults(LPDFBROWSE pdfb,
|
|
IStream * pstm, DFHEADER * pdfh)
|
|
{
|
|
ULONG cbRead;
|
|
LPITEMIDLIST pidl;
|
|
UINT idsMsg;
|
|
LARGE_INTEGER dlibMove = {0, 0};
|
|
|
|
#ifdef WINNT
|
|
DFC_UNICODE_DESC desc;
|
|
WORD fCharType = 0;
|
|
|
|
//
|
|
// Check the stream's signature to see if it was generated by Win95 or NT.
|
|
//
|
|
dlibMove.QuadPart = 0 - SIZEOF(desc);
|
|
pstm->lpVtbl->Seek(pstm, dlibMove, STREAM_SEEK_END, NULL);
|
|
pstm->lpVtbl->Read(pstm, &desc, SIZEOF(desc), &cbRead);
|
|
if (cbRead > 0 && desc.NTsignature == c_NTsignature)
|
|
{
|
|
//
|
|
// NT-generated stream. Read in Unicode criteria.
|
|
//
|
|
fCharType = DFC_FMT_UNICODE;
|
|
dlibMove.QuadPart = desc.oUnicodeCriteria.QuadPart;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Win95-generated stream. Read in ANSI criteria.
|
|
//
|
|
fCharType = DFC_FMT_ANSI;
|
|
dlibMove.LowPart = pdfh->oCriteria;
|
|
}
|
|
pstm->lpVtbl->Seek(pstm, dlibMove, STREAM_SEEK_SET, NULL);
|
|
pdfb->pdfff->lpVtbl->RestoreCriteria(pdfb->pdfff, pstm, pdfh->cCriteria, fCharType);
|
|
|
|
#else
|
|
//
|
|
// Now Read in the criteria
|
|
//
|
|
dlibMove.LowPart = pdfh->oCriteria;
|
|
pstm->lpVtbl->Seek(pstm, dlibMove, STREAM_SEEK_SET, NULL);
|
|
|
|
pdfb->pdfff->lpVtbl->RestoreCriteria(pdfb->pdfff, pstm, pdfh->cCriteria, DFC_FMT_ANSI);
|
|
#endif
|
|
|
|
// Now read in the results
|
|
dlibMove.LowPart = pdfh->oResults;
|
|
pstm->lpVtbl->Seek(pstm, dlibMove, STREAM_SEEK_SET, NULL);
|
|
|
|
|
|
if (pdfh->wVer > 1)
|
|
{
|
|
// only restore this way if version 2 data....
|
|
// Now Restore away the folder list
|
|
CDFFolder_RestoreFolderList(pdfb->pdfc, pstm);
|
|
|
|
// And the pidls that are associated with the object
|
|
for (; ; )
|
|
{
|
|
pidl = NULL; // don't free previous one
|
|
if (FAILED(ILLoadFromStream(pstm, &pidl)) ||
|
|
(pidl == NULL))
|
|
break;
|
|
|
|
// and add the item to the list
|
|
ShellFolderView_AddObject(pdfb->hwndDlg, pidl);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// and close the file
|
|
//
|
|
pstm->lpVtbl->Release(pstm);
|
|
|
|
// And update the title to match the search criteria
|
|
DocFind_UpdateFilter(pdfb);
|
|
|
|
|
|
//
|
|
// Update status bar with count of files that were restored
|
|
//
|
|
pdfb->pdfff->lpVtbl->GetStatusMessageIndex(pdfb->pdfff, 0, &idsMsg);
|
|
DocFind_SetStatusText(pdfb->hwndStatus, 0, idsMsg,
|
|
cbRead = ShellFolderView_GetObjectCount(pdfb->hwndDlg));
|
|
SendMessage(pdfb->hwndStatus, SB_SIMPLE, 0, 0L);
|
|
|
|
|
|
// Also set the state that we should show the view at this point.
|
|
// If we read in items (we reused cbRead from before)
|
|
if (cbRead > 0)
|
|
pdfb->fShowResults=TRUE;
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
//==========================================================================
|
|
//
|
|
// DocFind_UpdateFilter - Updates the filter information to match what
|
|
// is currently contained in the fields of the dialog box. This is called
|
|
// when the user starts a search, and is also called when we restore a
|
|
// find from s saved search
|
|
|
|
void DocFind_UpdateFilter(LPDFBROWSE pdfb)
|
|
{
|
|
//
|
|
// First We ask the filter object to update the stuff.
|
|
// and ask them to update their parts of the filter
|
|
//
|
|
pdfb->pdfff->lpVtbl->PrepareToEnumObjects(pdfb->pdfff, &pdfb->dwFlags);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//=========================================================================
|
|
// The user has clicked on the tabs. We should let the current window
|
|
// know that they may be about to killed...
|
|
|
|
LRESULT DocFind_PageChanging(LPDFBROWSE pdfb)
|
|
{
|
|
LRESULT lres = 0;
|
|
if (pdfb && pdfb->hwndCurPage)
|
|
lres = SendNotify(pdfb->hwndCurPage, pdfb->hwndDlg, PSN_KILLACTIVE, NULL);
|
|
|
|
return(lres);
|
|
}
|
|
|
|
//=========================================================================
|
|
//
|
|
void DocFind_PageChange(LPDFBROWSE pdfb)
|
|
{
|
|
HWND hwndCurPage;
|
|
int nItem;
|
|
HWND hwndDlg, hwndTabs;
|
|
RECT rc;
|
|
TC_DFITEMEXTRA tie;
|
|
|
|
if (!pdfb)
|
|
{
|
|
return;
|
|
}
|
|
|
|
hwndDlg = pdfb->hwndDlg;
|
|
hwndTabs = pdfb->hwndTabs;
|
|
|
|
// NOTE: the page was already validated (PSN_KILLACTIVE) before
|
|
// the actual page change.
|
|
|
|
nItem = TabCtrl_GetCurSel(hwndTabs);
|
|
if (nItem < 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
tie.tci.mask = TCIF_PARAM;
|
|
|
|
TabCtrl_GetItem(hwndTabs, nItem, &tie.tci);
|
|
hwndCurPage = tie.hwndPage;
|
|
|
|
|
|
if (pdfb->hwndCurPage == hwndCurPage)
|
|
{
|
|
/* we should be done at this point.
|
|
*/
|
|
return;
|
|
}
|
|
|
|
/* Size the dialog and move it to the top of the list before showing
|
|
** it in case there is size specific initializing to be done in the
|
|
** GETACTIVE message.
|
|
*/
|
|
GetClientRect(hwndTabs, &rc);
|
|
MapWindowPoints(hwndTabs, hwndDlg, (LPPOINT)&rc, 2);
|
|
TabCtrl_AdjustRect(hwndTabs, FALSE, &rc);
|
|
|
|
SetWindowPos(hwndCurPage, HWND_TOP, rc.left, rc.top,
|
|
rc.right - rc.left, rc.bottom - rc.top, 0);
|
|
|
|
/* We want to send the SETACTIVE message before the window is visible
|
|
** to minimize on flicker if it needs to update fields.
|
|
*/
|
|
SendNotify(hwndCurPage, hwndDlg, PSN_SETACTIVE, NULL);
|
|
|
|
|
|
/* Disable all erasebkgnd messages that come through because windows
|
|
** are getting shuffled. Note that we need to call ShowWindow (and
|
|
** not show the window in some other way) because DavidDs is counting
|
|
** on the correct parameters to the WM_SHOWWINDOW message, and we may
|
|
** document how to keep your page from flashing.
|
|
*/
|
|
//pdfb->bNoErase = TRUE;
|
|
ShowWindow(hwndCurPage, SW_SHOW);
|
|
|
|
if (pdfb->hwndCurPage)
|
|
{
|
|
ShowWindow(pdfb->hwndCurPage, SW_HIDE);
|
|
}
|
|
//pdfb->bNoErase = FALSE;
|
|
|
|
pdfb->hwndCurPage = hwndCurPage;
|
|
|
|
/* Newly created dialogs seem to steal the focus, so we steal it back
|
|
** to the page list, which must have had the focus to get to this
|
|
** point.
|
|
*/
|
|
SetFocus(hwndTabs);
|
|
|
|
}
|
|
|
|
LRESULT _CDFBrowse_OnNotify(HWND hwndDlg, LPNMHDR lpnm)
|
|
{
|
|
LPDFBROWSE pdfb;
|
|
|
|
pdfb = DocFind_GetPdfb(hwndDlg);
|
|
|
|
switch (lpnm->code) {
|
|
case NM_STARTWAIT:
|
|
case NM_ENDWAIT:
|
|
pdfb->iWaitCount += (lpnm->code == NM_STARTWAIT ? 1 :-1);
|
|
Assert(pdfb->iWaitCount >= 0);
|
|
// what we really want is for user to simulate a mouse move/setcursor
|
|
SetCursor(LoadCursor(NULL, pdfb->iWaitCount ? IDC_APPSTARTING : IDC_ARROW));
|
|
break;
|
|
|
|
case TCN_SELCHANGE:
|
|
DocFind_PageChange(pdfb);
|
|
break;
|
|
case TCN_SELCHANGING:
|
|
return DocFind_PageChanging(pdfb);
|
|
}
|
|
return 0L;
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// _CDFBrowse_OnCommand - Process the WM_COMMAND messages
|
|
//
|
|
LRESULT _CDFBrowse_OnCommand(HWND hwndDlg, UINT id, HWND hwndCtl, UINT code)
|
|
{
|
|
LPDFBROWSE pdfb;
|
|
UINT uToggleBit;
|
|
LRESULT lr = 0;
|
|
|
|
pdfb = DocFind_GetPdfb(hwndDlg);
|
|
|
|
switch (id) {
|
|
case IDOK:
|
|
EndDialog(hwndDlg, id == IDOK);
|
|
break;
|
|
|
|
case IDCANCEL:
|
|
// dont let the view process and get the under construction message, when
|
|
// the user types the ESC key.
|
|
break;
|
|
|
|
case IDD_START:
|
|
if (code == BN_CLICKED)
|
|
{
|
|
LRESULT lres;
|
|
|
|
// We need to let the current page have a chance of
|
|
// validating itself.
|
|
lres = SendNotify(pdfb->hwndCurPage, pdfb->hwndDlg, PSN_KILLACTIVE, NULL);
|
|
if (LOWORD(lres) == 0)
|
|
{
|
|
HWND hwndCtl;
|
|
|
|
DocFind_UpdateFilter(pdfb);
|
|
|
|
hwndCtl = GetDlgItem(hwndDlg, IDD_START);
|
|
Button_Enable(hwndCtl, FALSE);
|
|
Button_SetStyle(hwndCtl, BS_PUSHBUTTON, TRUE);
|
|
|
|
hwndCtl = GetDlgItem(hwndDlg, IDD_STOP);
|
|
Button_Enable(hwndCtl, TRUE);
|
|
Button_SetStyle(hwndCtl, BS_DEFPUSHBUTTON, TRUE);
|
|
|
|
hwndCtl = GetDlgItem(hwndDlg, IDD_ANIMATE);
|
|
Animate_Play(hwndCtl, 0, -1, -1);
|
|
|
|
// Show the results window;
|
|
DocFind_ShowResultsWindow(pdfb, TRUE);
|
|
|
|
// Now tell the filter to disable changes
|
|
pdfb->pdfff->lpVtbl->EnableChanges(pdfb->pdfff, FALSE);
|
|
|
|
UpdateWindow(hwndDlg);
|
|
SetFocus(pdfb->hwndView);
|
|
|
|
DocFind_DoFind(hwndDlg);
|
|
|
|
UpdateWindow(hwndDlg);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IDD_STOP:
|
|
if (code == BN_CLICKED)
|
|
{
|
|
// Try to stop the find
|
|
DocFind_StopFind(hwndDlg);
|
|
}
|
|
break;
|
|
|
|
case IDD_NEWSEARCH:
|
|
if (code == BN_CLICKED)
|
|
{
|
|
// Try to stop the find
|
|
DocFind_ClearSearch(hwndDlg);
|
|
}
|
|
break;
|
|
|
|
|
|
case IDM_OPENCONTAINING:
|
|
DocFind_HandleOpenContainingFolder(pdfb);
|
|
break;
|
|
|
|
|
|
case FSIDM_SORTBYLOCATION:
|
|
case FSIDM_SORTBYNAME:
|
|
case FSIDM_SORTBYTYPE:
|
|
case FSIDM_SORTBYSIZE:
|
|
case FSIDM_SORTBYDATE:
|
|
ShellFolderView_ReArrange(hwndDlg, DFSortIDToICol(id));
|
|
break;
|
|
|
|
case IDM_CLOSE:
|
|
PostMessage(hwndDlg, WM_CLOSE, 0, 0);
|
|
break;
|
|
|
|
case IDM_CASESENSITIVE:
|
|
uToggleBit = DFOO_CASESEN;
|
|
goto ToggleCheckAndSave;
|
|
|
|
#ifdef DOCFIND_RESUPPORT
|
|
case IDM_REGULAREXP:
|
|
uToggleBit = DFOO_REGULAR;
|
|
goto ToggleCheckAndSave;
|
|
#endif
|
|
|
|
case IDM_SAVERESULTS:
|
|
uToggleBit = DFOO_SAVERESULTS;
|
|
|
|
ToggleCheckAndSave:
|
|
pdfb->dwFlags ^= uToggleBit;
|
|
|
|
{
|
|
HKEY hkeyExp;
|
|
hkeyExp = GetExplorerHkey(TRUE);
|
|
if (hkeyExp) {
|
|
Reg_SetStruct(hkeyExp, s_szDocFind, s_szFlags, &pdfb->dwFlags, SIZEOF(pdfb->dwFlags));
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IDM_SAVESEARCH:
|
|
DocFind_Save(pdfb);
|
|
break;
|
|
|
|
case IDM_HELP_FIND:
|
|
{
|
|
TCHAR szHelpFile[MAX_PATH];
|
|
LoadString(HINST_THISDLL, IDS_WINDOWS_HLP, szHelpFile,
|
|
ARRAYSIZE(szHelpFile));
|
|
WinHelp(hwndDlg, szHelpFile, HELP_FINDER, 0);
|
|
}
|
|
break;
|
|
|
|
case IDM_HELP_WHATSTHIS:
|
|
PostMessage(hwndDlg, WM_SYSCOMMAND, SC_CONTEXTHELP, 0);
|
|
break;
|
|
|
|
// Somewhat gross but forward some commnds to the current Prop page
|
|
case IDD_BROWSE:
|
|
FORWARD_WM_COMMAND(pdfb->hwndCurPage, id, hwndCtl, code,
|
|
SendMessage);
|
|
break;
|
|
|
|
default:
|
|
if ((id >= FCIDM_SHVIEWFIRST) && (id <= FCIDM_SHVIEWLAST))
|
|
{
|
|
// Indicating we need to forward this message.
|
|
FORWARD_WM_COMMAND(hwndDlg, id, hwndCtl, code,
|
|
CDFBrowse_ForwardMsg);
|
|
return(0);
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
return(lr);
|
|
}
|
|
|
|
void _CDFBrowse_OnInitMenuPopup(HWND hwndDlg, HMENU hmInit, int nIndex, BOOL fSystemMenu)
|
|
{
|
|
MENUITEMINFO mii;
|
|
LPDFBROWSE pdfb;
|
|
int cpidls; // Count of pidls that were returned.
|
|
int iMI;
|
|
|
|
if (fSystemMenu)
|
|
return; // not intereste;
|
|
|
|
pdfb = DocFind_GetPdfb(hwndDlg);
|
|
|
|
mii.cbSize = SIZEOF(MENUITEMINFO);
|
|
mii.fMask = MIIM_SUBMENU|MIIM_ID;
|
|
mii.cch = 0; // WARNING: we MUST initialize it for MIIM_TYPE!!!
|
|
|
|
if (!GetMenuItemInfo(pdfb->hmenuCur, nIndex, TRUE, &mii) || mii.hSubMenu!=hmInit)
|
|
return;
|
|
|
|
switch (mii.wID)
|
|
{
|
|
case FCIDM_MENU_FILE:
|
|
// See if there are any items selected if so we can enable the open containing
|
|
// folder
|
|
cpidls = ShellFolderView_GetSelectedObjects(pdfb->hwndDlg, NULL);
|
|
EnableMenuItem(hmInit, IDM_OPENCONTAINING, (cpidls > 0) ?
|
|
(MF_ENABLED|MF_BYCOMMAND) : (MF_GRAYED|MF_BYCOMMAND));
|
|
break;
|
|
case FCIDM_MENU_VIEW:
|
|
// See if the first item is a separator if so nuke it.
|
|
mii.fMask = MIIM_TYPE;
|
|
mii.cch = 0; // WARNING: we MUST initialize it for MIIM_TYPE!!!
|
|
if (GetMenuItemInfo(hmInit, 0, TRUE, &mii))
|
|
{
|
|
// If it is a sep. get rid of it
|
|
if (mii.fType & MFT_SEPARATOR)
|
|
DeleteMenu(hmInit, 0, MF_BYPOSITION);
|
|
}
|
|
break;
|
|
case FCIDM_MENU_HELP:
|
|
// Remove the Seperator between help topics and What's this
|
|
for (iMI = GetMenuItemCount(hmInit)-1; iMI >= 0; iMI--)
|
|
{
|
|
mii.fMask = MIIM_TYPE;
|
|
mii.cch = 0; // WARNING: we MUST initialize it for MIIM_TYPE!!!
|
|
if (GetMenuItemInfo(hmInit, iMI, TRUE, &mii))
|
|
{
|
|
// If it is a sep. get rid of it
|
|
if (mii.fType & MFT_SEPARATOR)
|
|
{
|
|
DeleteMenu(hmInit, iMI, MF_BYPOSITION);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case IDM_MENU_OPTIONS:
|
|
//
|
|
// Initialize the states of menu items depending on the state
|
|
//
|
|
CheckMenuItem(hmInit, IDM_CASESENSITIVE, MF_BYCOMMAND |
|
|
((pdfb->dwFlags & DFOO_CASESEN)? MF_CHECKED : MF_UNCHECKED));
|
|
#ifdef DOCFIND_RESUPPORT
|
|
CheckMenuItem(hmInit, IDM_REGULAREXP,MF_BYCOMMAND |
|
|
((pdfb->dwFlags & DFOO_REGULAR)? MF_CHECKED : MF_UNCHECKED));
|
|
#endif
|
|
|
|
CheckMenuItem(hmInit, IDM_SAVERESULTS, MF_BYCOMMAND |
|
|
((pdfb->dwFlags & DFOO_SAVERESULTS)? MF_CHECKED : MF_UNCHECKED));
|
|
}
|
|
}
|
|
|
|
//==========================================================================
|
|
// _CDFBrowse_handleFSChange - Handle File system change notifications
|
|
//==========================================================================
|
|
int CALLBACK _CDFBrowse_UPCF(LPVOID pv1, LPVOID pv2, LPARAM lParam)
|
|
{
|
|
// function that is used below to see if an item is in the list or
|
|
// not...
|
|
HRESULT hres = ((LPSHELLFOLDER)lParam)->lpVtbl->CompareIDs(
|
|
(LPSHELLFOLDER)lParam, 0, pv1, pv2);
|
|
if (FAILED(hres))
|
|
return(-1);
|
|
else
|
|
return(ShortFromResult(hres));
|
|
}
|
|
|
|
void _CDFBrowse_handleUpdateDir(LPDFBROWSE pdfb, LPITEMIDLIST pidl, BOOL fCheckSubDirs)
|
|
{
|
|
// 1. Start walk through list of dirs. stop when find exact match or
|
|
// ancestor. (If exact match) assume iExact is this index.
|
|
// 2. Enum the objects in the folder of the update dir and build a DPA
|
|
// 3. For each of the items in the directory list. See if the item is
|
|
// a child of update and if the dir is in our dpa if not mark it delted
|
|
// 4. Walk our list of total items, if the items folder is iExact, see
|
|
// if it is in the HDPA, if not remove it. If not See if its directory
|
|
// index is marked deleted, if so remove it.
|
|
// 5. Cleanup
|
|
int iPidf;
|
|
int iPidfExact = -1;
|
|
LPDFFOLDERLISTITEM pdffli;
|
|
LPSHELLFOLDER psf = NULL;
|
|
LPENUMIDLIST penum = NULL;
|
|
HDPA hdpaCurrent = NULL;
|
|
LPITEMIDLIST pidlT;
|
|
int cRet;
|
|
int cPidlParts;
|
|
int iItem;
|
|
LPITEMIDLIST pidlX;
|
|
HWND hwnd = pdfb->hwndDlg;
|
|
UINT idsMsg;
|
|
BOOL fItemsRemoved = FALSE;
|
|
#ifdef DEBUG
|
|
TCHAR szPath[MAX_PATH];
|
|
STRRET strret;
|
|
#endif
|
|
|
|
HDPA hdpaPidf = ((LPDFFOLDER)pdfb->pdfc)->hdpaPidf;
|
|
LPSHELLFOLDER psfDesktop = Desktop_GetShellFolder(TRUE);
|
|
|
|
|
|
for (iPidf = 0; iPidf < DPA_GetPtrCount(hdpaPidf); iPidf++ )
|
|
{
|
|
pdffli = DPA_FastGetPtr(hdpaPidf, iPidf);
|
|
if (pdffli != NULL)
|
|
{
|
|
if (ILIsParent(pidl, pdffli->pidl, FALSE))
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (iPidf == DPA_GetPtrCount(hdpaPidf))
|
|
return; // not in our list of items so lets blow out of here...
|
|
|
|
// see if an exact match
|
|
if (ILIsEqual(pidl, pdffli->pidl))
|
|
{
|
|
iPidfExact = iPidf++;
|
|
}
|
|
|
|
|
|
hdpaCurrent = DPA_CreateEx(64, GetProcessHeap());
|
|
if (!hdpaCurrent)
|
|
goto Abort;
|
|
|
|
|
|
// Ok I need to do some work here so lets get an IShellFolder for
|
|
// this directory.
|
|
|
|
if (SUCCEEDED(psfDesktop->lpVtbl->BindToObject(psfDesktop,
|
|
pidl, NULL, &IID_IShellFolder, &psf)))
|
|
{
|
|
|
|
if (SUCCEEDED(psf->lpVtbl->EnumObjects(psf, hwnd,
|
|
SHCONTF_FOLDERS|SHCONTF_NONFOLDERS, &penum)))
|
|
|
|
{
|
|
|
|
while (penum->lpVtbl->Next(penum, 1, &pidlT, &cRet) == NOERROR)
|
|
{
|
|
if (DPA_InsertPtr(hdpaCurrent, 32767, pidlT) == -1)
|
|
{
|
|
ILFree(pidlT);
|
|
break; // Failed to insert it???
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Count the number of parts in the pidl that was passed in.
|
|
for (cPidlParts=0, pidlT = pidl; !ILIsEmpty(pidlT); pidlT = _ILNext(pidlT))
|
|
cPidlParts++;
|
|
|
|
// Now continue through the list of folders to see which ones
|
|
// we may want to mark as not there anymore...
|
|
if (fCheckSubDirs)
|
|
{
|
|
for (; iPidf < DPA_GetPtrCount(hdpaPidf); iPidf++ )
|
|
{
|
|
pdffli = DPA_FastGetPtr(hdpaPidf, iPidf);
|
|
if (pdffli != NULL && pdffli->fValid)
|
|
{
|
|
if (ILIsParent(pidl, pdffli->pidl, FALSE))
|
|
{
|
|
int i;
|
|
// Skip forward through the parts that match
|
|
for (pidlT = pdffli->pidl, i=cPidlParts; i > 0; i--)
|
|
pidlT = _ILNext(pidlT);
|
|
|
|
// Now see if the item is in the DPA
|
|
if (DPA_Search(hdpaCurrent, pidlT, 0, _CDFBrowse_UPCF,
|
|
(LPARAM)psf, 0) == -1)
|
|
{
|
|
#ifdef DEBUG
|
|
SHGetPathFromIDList(pdffli->pidl, szPath);
|
|
DebugMsg(DM_TRACE, TEXT("docfind.c RefreshDir: Mark dir removed(%d) %s"), iPidf, szPath);
|
|
#endif
|
|
|
|
// Item not found so mark it deleted...
|
|
pdffli->fValid = FALSE;
|
|
}
|
|
else
|
|
{
|
|
// Items in this sub-folder may also have been removed so we
|
|
// should check them also...
|
|
_CDFBrowse_handleUpdateDir(pdfb, pdffli->pidl, FALSE);
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Now we need to walk through the whole list and remove any entries
|
|
// that are no longer there...
|
|
//
|
|
for (iItem = ShellFolderView_GetObjectCount(hwnd)-1; iItem >= 0; iItem--)
|
|
{
|
|
WORD iFolder;
|
|
pidlX = (LPITEMIDLIST)ShellFolderView_GetObject(hwnd, iItem);
|
|
if (pidlX == NULL)
|
|
continue;
|
|
iFolder = *DF_IFLDRPTR(pidlX);
|
|
|
|
if (iFolder == (WORD)iPidfExact)
|
|
{
|
|
// Now see if the item is in the DPA
|
|
if (DPA_Search(hdpaCurrent, pidlX, 0, _CDFBrowse_UPCF,
|
|
(LPARAM)psf, 0) == -1)
|
|
{
|
|
#ifdef DEBUG
|
|
|
|
pdfb->pdfc->lpVtbl->GetDisplayNameOf(pdfb->pdfc,
|
|
pidlX, 0, &strret);
|
|
StrRetToStrN(szPath,ARRAYSIZE(szPath),&strret,pidlX);
|
|
DebugMsg(DM_TRACE, TEXT("docfind.c refresh dir: Remove: %s"), szPath);
|
|
#endif
|
|
// Item not found so mark it deleted...
|
|
ShellFolderView_RemoveObject(hwnd, pidlX);
|
|
fItemsRemoved = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pdffli = DPA_FastGetPtr(hdpaPidf, iFolder);
|
|
if (pdffli && !pdffli->fValid)
|
|
{
|
|
#ifdef DEBUG
|
|
|
|
pdfb->pdfc->lpVtbl->GetDisplayNameOf(pdfb->pdfc,
|
|
pidlX, 0, &strret);
|
|
StrRetToStrN(szPath,ARRAYSIZE(szPath),&strret,pidlX);
|
|
DebugMsg(DM_TRACE, TEXT("docfind.c refresh dir: Remove sub(%d): %s"),
|
|
iFolder, szPath);
|
|
#endif
|
|
ShellFolderView_RemoveObject(hwnd, pidlX);
|
|
fItemsRemoved = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Now lets cleanup our dpa...
|
|
for (iItem = DPA_GetPtrCount(hdpaCurrent) -1; iItem >= 0; iItem--)
|
|
ILFree((LPITEMIDLIST)DPA_FastGetPtr(hdpaCurrent, iItem));
|
|
|
|
DPA_Destroy(hdpaCurrent);
|
|
|
|
// Update the count...
|
|
if (fItemsRemoved)
|
|
{
|
|
pdfb->pdfff->lpVtbl->GetStatusMessageIndex(pdfb->pdfff, 0, &idsMsg);
|
|
DocFind_SetStatusText(pdfb->hwndStatus, 0, idsMsg,
|
|
ShellFolderView_GetObjectCount(pdfb->hwndDlg));
|
|
}
|
|
|
|
// This is rather gross, but if we got here and we do not have
|
|
// a penum, then the directory did not exist. so lets remove it
|
|
// also from the list.
|
|
if (penum == NULL)
|
|
{
|
|
_CDFBrowse_handleFSChange(pdfb->hwndDlg, SHCNE_RMDIR, &pidl);
|
|
}
|
|
|
|
Abort:
|
|
if (penum)
|
|
penum->lpVtbl->Release(penum);
|
|
if (psf)
|
|
psf->lpVtbl->Release(psf);
|
|
}
|
|
|
|
|
|
//==========================================================================
|
|
// _CDFBrowse_handleFSChange - Handle File system change notifications
|
|
//==========================================================================
|
|
void _CDFBrowse_handleFSChange(HWND hwndDlg, LONG code,
|
|
LPITEMIDLIST *ppidl)
|
|
{
|
|
LPDFBROWSE pdfb;
|
|
LPITEMIDLIST pidlT;
|
|
UINT idsMsg;
|
|
|
|
pdfb = DocFind_GetPdfb(hwndDlg);
|
|
|
|
|
|
// see if we want to process the notificiation or not.
|
|
switch (code)
|
|
{
|
|
case SHCNE_RENAMEFOLDER: // With trashcan this is what we see...
|
|
case SHCNE_RENAMEITEM: // With trashcan this is what we see...
|
|
case SHCNE_DELETE:
|
|
case SHCNE_RMDIR:
|
|
break;
|
|
case SHCNE_UPDATEDIR:
|
|
{
|
|
|
|
// if the pidlExtra (ppidl[1]) is valid, then it means that we
|
|
// should recurse down through our subdirs.
|
|
BOOL bRecurse = (ppidl[1] != NULL);
|
|
|
|
// this is a lot more fun as such I will process this one
|
|
// separate...
|
|
_CDFBrowse_handleUpdateDir(pdfb, *ppidl, bRecurse);
|
|
}
|
|
return;
|
|
|
|
default:
|
|
return; // we are not interested in this event
|
|
}
|
|
|
|
//
|
|
// Now we need to see if the item might be in our list
|
|
// First we need to extract off the last part of the id list
|
|
// and see if the contained id entry is in our list. If so we
|
|
// need to see if can get the defview find the item and update it.
|
|
//
|
|
|
|
// Now try to find the id in our idlist array.
|
|
// BUGBUG:: should abstract this into our Folder class stuff
|
|
pidlT = CDFFolder_MapFSPidlToDFPidl(pdfb->pdfc, *ppidl, FALSE);
|
|
|
|
if (pidlT != NULL)
|
|
{
|
|
switch (code)
|
|
{
|
|
case SHCNE_RMDIR:
|
|
case SHCNE_DELETE:
|
|
ShellFolderView_RemoveObject(pdfb->hwndDlg, pidlT);
|
|
break;
|
|
|
|
case SHCNE_RENAMEFOLDER:
|
|
case SHCNE_RENAMEITEM:
|
|
{
|
|
LPITEMIDLIST pidl1;
|
|
LPITEMIDLIST pidl2;
|
|
// If the two items dont have the same parent, we will go ahead
|
|
// and remove it...
|
|
pidl1 = CDFolder_GetParentsPIDL(pdfb->pdfc, pidlT);
|
|
pidl2 = ILClone(ppidl[1]);
|
|
if (pidl1 && pidl2)
|
|
{
|
|
ILRemoveLastID(pidl2);
|
|
if (!ILIsEqual(pidl1, pidl2))
|
|
{
|
|
ShellFolderView_RemoveObject(pdfb->hwndDlg, pidlT);
|
|
}
|
|
else
|
|
{
|
|
// The object is in same folder so must be rename...
|
|
LPITEMIDLIST apidl[2];
|
|
apidl[0] = pidlT;
|
|
apidl[1] = CDFFolder_MapFSPidlToDFPidl(
|
|
pdfb->pdfc, ppidl[1], TRUE);
|
|
if (apidl[1] != NULL)
|
|
{
|
|
if ((int)ShellFolderView_UpdateObject(
|
|
pdfb->hwndDlg, apidl) == -1)
|
|
{
|
|
// item not found free our pidl...
|
|
ILFree(apidl[1]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
ILFree(pidl2);
|
|
break;
|
|
}
|
|
|
|
case SHCNE_UPDATEITEM:
|
|
{
|
|
// We need to do a find first and convert to pidl...
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Update the count...
|
|
pdfb->pdfff->lpVtbl->GetStatusMessageIndex(pdfb->pdfff, 0, &idsMsg);
|
|
DocFind_SetStatusText(pdfb->hwndStatus, 0, idsMsg,
|
|
ShellFolderView_GetObjectCount(pdfb->hwndDlg));
|
|
|
|
ILFree(pidlT);
|
|
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// DocFind_DoFind - This function begins the Find operation. It clears out
|
|
// the previous results and then sets up the idle processing, such that the
|
|
// the user can switch out in a timely fashion
|
|
//
|
|
BOOL DocFind_DoFind(HWND hwndDlg)
|
|
{
|
|
LPDFBROWSE pdfb;
|
|
LPTSTR pszTitle;
|
|
DWORD idThread;
|
|
PFINDTHREAD pft;
|
|
|
|
pdfb = DocFind_GetPdfb(hwndDlg);
|
|
if (!pdfb)
|
|
return FALSE;
|
|
|
|
pft = LocalAlloc(LPTR,SIZEOF(*pft));
|
|
if (!pft)
|
|
{
|
|
ShellMessageBox(HINST_THISDLL, pdfb->hwndDlg,
|
|
MAKEINTRESOURCE(IDS_FINDOUTOFMEM),
|
|
MAKEINTRESOURCE(IDS_FINDFILES), MB_OK | MB_SYSTEMMODAL |MB_ICONHAND);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Update the title of the window to the search criteria
|
|
//
|
|
pdfb->pdfff->lpVtbl->GenerateTitle(pdfb->pdfff, &pszTitle, FALSE);
|
|
if (pszTitle != NULL)
|
|
{
|
|
SetWindowText(pdfb->hwndDlg, pszTitle);
|
|
SHFree(pszTitle); // And free the title string.
|
|
}
|
|
|
|
// Tell defview to delete everything.
|
|
ShellFolderView_RemoveObject(pdfb->hwndDlg, NULL);
|
|
|
|
// And cleanup our folderList
|
|
CDFFolder_ClearFolderList((LPDFFOLDER)pdfb->pdfc);
|
|
|
|
/* Remove all FSNotifies that are associated with this window */
|
|
SHChangeNotifyDeregisterWindow(pdfb->hwndDlg);
|
|
|
|
// Also clear the statusbar text at the start as in some cases
|
|
// it might be awhile before something comes back to the user
|
|
SendMessage(pdfb->hwndStatus, SB_SETTEXT, 0, (LPARAM)szNULL);
|
|
SendMessage(pdfb->hwndStatus, SB_SIMPLE, 0, 0L);
|
|
|
|
/* Call out to enable the FS notifys we are interested in - allows us to
|
|
/ correctly support multiple directories. */
|
|
pdfb->pdfff->lpVtbl->DeclareFSNotifyInterest( pdfb ->pdfff, hwndDlg, WM_DF_FSNOTIFY );
|
|
|
|
pft->fContinue = TRUE;
|
|
pft->pdfb = pdfb;
|
|
pdfb->sb.lpVtbl->AddRef(&pdfb->sb);
|
|
|
|
EnterCriticalSection(&pdfb->csSearch);
|
|
pft->iSearchCnt = ++pdfb->iSearchCnt; // Sync thread with search
|
|
pdfb->pft = pft;
|
|
LeaveCriticalSection(&pdfb->csSearch);
|
|
|
|
pdfb->fNotifyPosted = FALSE;
|
|
|
|
|
|
if (DocFind_StartFind(hwndDlg))
|
|
{
|
|
HANDLE hThreadSearch;
|
|
|
|
hThreadSearch = CreateThread(NULL, 0, DocFind_ThreadProc,
|
|
pft, 0, &idThread);
|
|
if (hThreadSearch)
|
|
{
|
|
CloseHandle(hThreadSearch);
|
|
DebugMsg(DM_TRACE, TEXT("docfind.c CreateThread %lx(%d)"),
|
|
(ULONG)hThreadSearch, idThread);
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
// Failed to create thread, free up data
|
|
pdfb->sb.lpVtbl->Release(&pdfb->sb);
|
|
LocalFree(pft);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//==========================================================================
|
|
//
|
|
// DocFind_ThreadProc - This is the main work horse function for the
|
|
// second thrread. It will continuously attempt to find new items to add
|
|
// to the list.
|
|
//
|
|
|
|
DWORD CALLBACK DocFind_ThreadProc(LPVOID lpThreadParameters)
|
|
{
|
|
LPDFBROWSE pdfb;
|
|
PFINDTHREAD pft;
|
|
|
|
HWND hwndCtl;
|
|
|
|
IDFEnum *pdfenum; // Here is my iterator...
|
|
LPITEMIDLIST pidl;
|
|
int cFldrsPrev = 0;
|
|
int state;
|
|
HRESULT hres = 0;
|
|
|
|
LPTSTR pszLastPathAdded = NULL;
|
|
|
|
pft = lpThreadParameters;
|
|
pdfb = pft->pdfb;
|
|
|
|
// Clear out counts;
|
|
pdfb->cItemsAdded = 0;
|
|
pdfb->cItemsSearched = 0;
|
|
pdfb->cFldrsSearched = 0;
|
|
|
|
|
|
// Now Lets construct an iterator to do our work for us
|
|
__try
|
|
{
|
|
if (SUCCEEDED(pdfb->pdfff->lpVtbl->EnumObjects(pdfb->pdfff,
|
|
(LPSHELLFOLDER)pdfb->pdfc, pdfb->dwFlags,
|
|
pdfb->szProgressText, &pdfenum)) )
|
|
{
|
|
// Now lets loop while the next Works! Also check to see if
|
|
// the parent has signalled us to end or if the parent went
|
|
// away then the top level window would also be gone. In
|
|
// this case bail...
|
|
|
|
while( pft->fContinue && IsWindow(pdfb->hwndDlg)
|
|
&& ((hres = pdfenum->lpVtbl->Next(pdfenum, &pidl,
|
|
&pdfb->cItemsSearched,
|
|
&pdfb->cFldrsSearched, &pft->fContinue, &state, pdfb->hwndDlg))==NOERROR))
|
|
{
|
|
|
|
if (state == GNF_DONE) // we ran out of people to search
|
|
break;
|
|
|
|
if (cFldrsPrev != pdfb->cFldrsSearched)
|
|
{
|
|
pdfb->fDirChanged = TRUE;
|
|
cFldrsPrev = pdfb->cFldrsSearched;
|
|
}
|
|
|
|
// See if we should abort
|
|
if (state == GNF_MATCH)
|
|
{
|
|
EnterCriticalSection(&pdfb->csSearch);
|
|
if (!pft->fContinue)
|
|
{
|
|
LeaveCriticalSection(&pdfb->csSearch);
|
|
break;
|
|
}
|
|
DPA_InsertPtr(pdfb->hdpaItemsToAdd, 32767, pidl);
|
|
pdfb->fFilesAdded = TRUE;
|
|
pdfb->cItemsAdded++;
|
|
LeaveCriticalSection(&pdfb->csSearch);
|
|
|
|
// See if we just hit the maximum number of files
|
|
// that we will allow to be returned...
|
|
if (pdfb->cItemsAdded >= DF_MAX_MATCHFILES)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
// See if we should let the other thead know that they
|
|
// should update display
|
|
if (!pdfb->fNotifyPosted &&
|
|
(pdfb->fFilesAdded || pdfb->fDirChanged))
|
|
{
|
|
DWORD dwTimeNow;
|
|
dwTimeNow = GetTickCount();
|
|
if (dwTimeNow > (pdfb->dwLastUpdateTime + 200))
|
|
{
|
|
pdfb->fNotifyPosted = TRUE;
|
|
PostMessage(pdfb->hwndDlg, WM_DF_THREADNOTIFY, pft->iSearchCnt, 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
// And release the iterator
|
|
pdfenum->lpVtbl->Release(pdfenum);
|
|
}
|
|
}
|
|
__except(SetErrorMode(SEM_NOGPFAULTERRORBOX),UnhandledExceptionFilter(GetExceptionInformation()))
|
|
{
|
|
hres = HRESULT_FROM_WIN32(ERROR_EXCEPTION_IN_SERVICE);
|
|
}
|
|
|
|
if (GetScode(hres) == E_OUTOFMEMORY)
|
|
{
|
|
ShellMessageBox(HINST_THISDLL, pdfb->hwndDlg,
|
|
MAKEINTRESOURCE(IDS_FINDOUTOFMEM),
|
|
MAKEINTRESOURCE(IDS_FINDFILES), MB_OK | MB_SYSTEMMODAL |MB_ICONHAND);
|
|
}
|
|
|
|
// Disconnect us from the dialog
|
|
EnterCriticalSection(&pdfb->csSearch);
|
|
if (!pdfb->fContinue)
|
|
{
|
|
// Let other thread know we are done! And let it do most of the
|
|
// manipulation of the windows.
|
|
PostMessage(pdfb->hwndDlg, WM_DF_THREADNOTIFY, pft->iSearchCnt, (LPARAM)-1);
|
|
}
|
|
|
|
pdfb->pft = NULL;
|
|
LeaveCriticalSection(&pdfb->csSearch);
|
|
|
|
// Now free up our FINDTHREAD struct
|
|
pdfb->sb.lpVtbl->Release(&pdfb->sb);
|
|
LocalFree(pft);
|
|
|
|
return(0);
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// DocFind_ProcessThreadNotify - This function processes the notification
|
|
// messages from the secondary thread.
|
|
//
|
|
void DocFind_ProcessThreadNotify(HWND hwndDlg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
LPDFBROWSE pdfb;
|
|
HDPA hdpaItemsToAdd = NULL;
|
|
BOOL fDirChanged;
|
|
|
|
|
|
pdfb = DocFind_GetPdfb(hwndDlg);
|
|
if (!pdfb)
|
|
return;
|
|
|
|
if (wParam != pdfb->iSearchCnt )
|
|
{
|
|
// Stale thread posted old message
|
|
return;
|
|
}
|
|
|
|
//
|
|
// See if we have any items to add to our list or we need
|
|
// to change the status bar
|
|
//
|
|
EnterCriticalSection(&pdfb->csSearch);
|
|
|
|
if (pdfb->fFilesAdded )
|
|
{
|
|
|
|
// Basically switch dpas that the other thread is adding to...
|
|
hdpaItemsToAdd = pdfb->hdpaItemsToAdd;
|
|
pdfb->hdpaItemsToAdd = pdfb->hdpaPrevAdd;
|
|
pdfb->hdpaPrevAdd = hdpaItemsToAdd;
|
|
pdfb->fFilesAdded = FALSE;
|
|
}
|
|
|
|
fDirChanged = pdfb->fDirChanged;
|
|
pdfb->fDirChanged = FALSE;
|
|
|
|
LeaveCriticalSection(&pdfb->csSearch);
|
|
|
|
// Now we can update the display while the other thread is free
|
|
// to do other things.
|
|
|
|
if (hdpaItemsToAdd != NULL)
|
|
{ int i, cItems;
|
|
LPITEMIDLIST pidl;
|
|
HWND hwndDlg;
|
|
|
|
cItems = DPA_GetPtrCount(hdpaItemsToAdd);
|
|
hwndDlg = pdfb->hwndDlg;
|
|
|
|
ShellFolderView_SetRedraw(hwndDlg, FALSE);
|
|
for (i=0; i < cItems; i++)
|
|
{
|
|
pidl = (LPITEMIDLIST)DPA_FastGetPtr(hdpaItemsToAdd, i);
|
|
if (ShellFolderView_AddObject(hwndDlg, pidl) == 0)
|
|
{
|
|
// This is the first item, so lets select it...
|
|
pdfb->psv->lpVtbl->SelectItem(pdfb->psv, pidl,
|
|
SVSI_SELECT|SVSI_FOCUSED);
|
|
}
|
|
}
|
|
ShellFolderView_SetRedraw(hwndDlg, TRUE);
|
|
// FORWARD_WM_SETREDRAW(hwndLV, TRUE, SendMessage);
|
|
DPA_DeleteAllPtrs(hdpaItemsToAdd);
|
|
|
|
}
|
|
|
|
if (fDirChanged)
|
|
{
|
|
DocFind_SetStatusText(pdfb->hwndStatus, -1, IDS_SEARCHING,
|
|
(TCHAR *)pdfb->szProgressText);
|
|
SendMessage(pdfb->hwndStatus, SB_SIMPLE, 1, 0L);
|
|
}
|
|
|
|
|
|
if (lParam == (LPARAM)-1)
|
|
{
|
|
DocFind_StopFind(pdfb->hwndDlg);
|
|
}
|
|
|
|
pdfb->dwLastUpdateTime = GetTickCount();
|
|
pdfb->fNotifyPosted = FALSE;
|
|
}
|
|
|
|
UINT GetControlCharWidth(HWND hwnd)
|
|
{
|
|
SIZE siz;
|
|
HDC hdc = GetDC(HWND_DESKTOP);
|
|
|
|
SelectFont(hdc, FORWARD_WM_GETFONT(hwnd, SendMessage));
|
|
GetTextExtentPoint(hdc, TEXT("0"), 1, &siz);
|
|
|
|
ReleaseDC(HWND_DESKTOP, hdc);
|
|
|
|
return siz.cx;
|
|
}
|
|
|
|
//-------------------------------------------------------------
|
|
void _CDFBrowse_OnSizing(HWND hwndDlg, UINT code, LPRECT lprc)
|
|
{
|
|
// If we are showing the results we can size both directions. Else we
|
|
// can only size horizontally.
|
|
RECT rcDlg;
|
|
LPDFBROWSE pdfb;
|
|
|
|
pdfb = DocFind_GetPdfb(hwndDlg);
|
|
GetWindowRect(hwndDlg, &rcDlg);
|
|
|
|
if (!pdfb->fShowResults)
|
|
{
|
|
lprc->top = rcDlg.top;
|
|
lprc->bottom = rcDlg.bottom;
|
|
}
|
|
}
|
|
|
|
void _CDFBrowse_OnSize(HWND hwndDlg, UINT state, int cx, int cy)
|
|
{
|
|
RECT rcCtl;
|
|
RECT rcTabs;
|
|
int dx, cxChar;
|
|
HWND hwndCtl;
|
|
RECT rcButton;
|
|
RECT rcT;
|
|
RECT rcStatus;
|
|
LPDFBROWSE pdfb;
|
|
int i;
|
|
HDWP hdwp;
|
|
|
|
static int s_aButtonIds[] = {IDD_START, IDD_STOP, IDD_NEWSEARCH};
|
|
|
|
if (state == SIZE_MINIMIZED)
|
|
return; // don't bother when we are minimized...
|
|
|
|
#define CXTABSMIN (cxChar * 30)
|
|
|
|
cxChar = GetControlCharWidth(hwndDlg);
|
|
|
|
// First update the location of the statusbar
|
|
pdfb = DocFind_GetPdfb(hwndDlg);
|
|
if (pdfb == NULL)
|
|
return; // not ready yet
|
|
|
|
// BUGBUG BOBDAY Temp solution for bad painting problem. This
|
|
// needs to be removed once bug18466 is truly fixed (chriswil - 03/06/96).
|
|
#if 1
|
|
{
|
|
DWORD dwStyle;
|
|
dwStyle = GetWindowLong( hwndDlg, GWL_STYLE );
|
|
dwStyle |= WS_CLIPCHILDREN;
|
|
SetWindowLong( hwndDlg, GWL_STYLE, dwStyle );
|
|
}
|
|
#endif
|
|
|
|
// We setup the intial count with some slop, so don't have to worry
|
|
// about allocation failures later.
|
|
hdwp = BeginDeferWindowPos(10);
|
|
if (!hdwp)
|
|
return;
|
|
|
|
if (pdfb->hwndStatus != NULL)
|
|
{
|
|
SendMessage(pdfb->hwndStatus, WM_SIZE, 0, 0);
|
|
GetClientRect(pdfb->hwndStatus, &rcStatus);
|
|
MapWindowPoints(pdfb->hwndStatus, hwndDlg, (POINT FAR*)&rcStatus, 2);
|
|
}
|
|
else
|
|
rcStatus.top = cy;
|
|
|
|
GetWindowRect(pdfb->hwndTabs, &rcTabs);
|
|
MapWindowPoints(HWND_DESKTOP, hwndDlg, (POINT FAR*)&rcTabs, 2);
|
|
GetWindowRect(GetDlgItem(hwndDlg, IDD_START), &rcCtl);
|
|
MapWindowPoints(HWND_DESKTOP, hwndDlg, (POINT FAR*)&rcCtl, 2);
|
|
//
|
|
// Don't let the tabs control get to small.
|
|
//
|
|
dx = max(CXTABSMIN,
|
|
(cx - 3 * rcTabs.left - (rcCtl.right - rcCtl.left)));
|
|
|
|
// Adjust the width of the text & combo boxes
|
|
//
|
|
DeferWindowPos(hdwp, hwndCtl = pdfb->hwndTabs, NULL, 0, 0, dx,
|
|
rcTabs.bottom - rcTabs.top, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
|
|
|
|
//
|
|
// The file list needs to be adjusted in both X and Y directions.
|
|
// Note: for now goes to bottom of window... Also give same gap
|
|
// on both left and right hand sides.
|
|
//
|
|
GetWindowRect(pdfb->hwndView, &rcCtl);
|
|
MapWindowPoints(HWND_DESKTOP, hwndDlg, (POINT *)&rcCtl, 2);
|
|
|
|
// Move the start/stop/browse buttons
|
|
//
|
|
dx += 2 * rcTabs.left;
|
|
|
|
for (i = 0; i < ARRAYSIZE(s_aButtonIds); i++)
|
|
{
|
|
HWND hwnd = GetDlgItem(hwndDlg, s_aButtonIds[i]);
|
|
GetWindowRect(hwnd, &rcButton);
|
|
MapWindowPoints(HWND_DESKTOP, hwndDlg, (POINT FAR*)&rcButton, 2);
|
|
|
|
DeferWindowPos(hdwp, hwnd, NULL, dx, rcButton.top, 0, 0,
|
|
SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
|
|
|
|
if (rcButton.bottom > rcTabs.bottom)
|
|
rcTabs.bottom = rcButton.bottom;
|
|
|
|
}
|
|
|
|
// Need to adjust the animation control
|
|
hwndCtl = GetDlgItem(hwndDlg, IDD_ANIMATE);
|
|
GetWindowRect(hwndCtl, &rcT);
|
|
MapWindowPoints(HWND_DESKTOP, hwndDlg, (POINT FAR*)&rcT, 2);
|
|
DebugMsg(DM_TRACE, TEXT("Position Animation control: dx = br=%d, bl=%d, ar=%d, al=%d, l=%d\n"),
|
|
dx, rcButton.right, rcButton.left, rcT.right, rcT.left,
|
|
dx + ((rcButton.right - rcButton.left) - (rcT.right - rcT.left)) / 2);
|
|
|
|
DeferWindowPos(hdwp, hwndCtl, NULL,
|
|
dx + ((rcButton.right - rcButton.left) - (rcT.right - rcT.left)) / 2,
|
|
rcT.top, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE);
|
|
if (rcT.bottom > rcTabs.bottom)
|
|
rcTabs.bottom = rcT.bottom;
|
|
|
|
// and then set the listview
|
|
|
|
if (pdfb->fShowResults)
|
|
{
|
|
rcCtl.top = rcTabs.bottom + rcTabs.top;
|
|
DeferWindowPos(hdwp, pdfb->hwndView, NULL, 0, rcCtl.top,
|
|
cx,
|
|
rcStatus.top - rcCtl.top,
|
|
SWP_NOZORDER | SWP_NOACTIVATE);
|
|
}
|
|
else
|
|
ShowWindow(pdfb->hwndView, SW_HIDE);
|
|
|
|
// now get them all to reposition now...
|
|
|
|
EndDeferWindowPos(hdwp);
|
|
|
|
//
|
|
// Also if we are displaying a page we need to resize it also.
|
|
//
|
|
|
|
if (pdfb->hwndCurPage)
|
|
{
|
|
HWND hwndCtl = pdfb->hwndTabs;
|
|
GetClientRect(hwndCtl, &rcCtl);
|
|
MapWindowPoints(hwndCtl, hwndDlg, (LPPOINT)&rcCtl, 2);
|
|
TabCtrl_AdjustRect(hwndCtl, FALSE, &rcCtl);
|
|
|
|
SetWindowPos(pdfb->hwndCurPage, HWND_TOP, rcCtl.left, rcCtl.top,
|
|
rcCtl.right - rcCtl.left, rcCtl.bottom - rcCtl.top, SWP_NOZORDER | SWP_NOACTIVATE);
|
|
}
|
|
}
|
|
|
|
//==========================================================================
|
|
// Handle GetMinMax info for cases where we don't want the new find to
|
|
// take over the entire screen...
|
|
//==========================================================================
|
|
void _CDFBrowse_OnGetMinMaxInfo(HWND hwndDlg, LPMINMAXINFO lpMinMaxInfo)
|
|
{
|
|
LPDFBROWSE pdfb;
|
|
RECT rcDlg;
|
|
|
|
pdfb = DocFind_GetPdfb(hwndDlg);
|
|
GetWindowRect(hwndDlg, &rcDlg);
|
|
|
|
if (!pdfb->fShowResults && IsWindowVisible(hwndDlg))
|
|
{
|
|
lpMinMaxInfo->ptMaxSize.y = pdfb->cyNoResults;
|
|
}
|
|
}
|
|
|
|
|
|
//==========================================================================
|
|
//
|
|
// DocFind_StartFind - Called to cleanup after the last search and to
|
|
// begin the new search.
|
|
//
|
|
BOOL DocFind_StartFind(HWND hwndDlg)
|
|
{
|
|
LPDFBROWSE pdfb;
|
|
|
|
pdfb = DocFind_GetPdfb(hwndDlg);
|
|
if (!pdfb)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// DocFind_StopFind - Called to stop a Find operation that is in progress
|
|
//
|
|
BOOL DocFind_StopFind(HWND hwndDlg)
|
|
{
|
|
LPDFBROWSE pdfb;
|
|
int cItems;
|
|
UINT idsMsg;
|
|
HWND hwndCtl;
|
|
|
|
|
|
pdfb = DocFind_GetPdfb(hwndDlg);
|
|
if (!pdfb)
|
|
return FALSE;
|
|
|
|
EnterCriticalSection(&pdfb->csSearch);
|
|
if (pdfb->pft)
|
|
{
|
|
pdfb->pft->fContinue = FALSE;
|
|
pdfb->pft = NULL; // We no longer have a running FindThread
|
|
}
|
|
LeaveCriticalSection(&pdfb->csSearch);
|
|
|
|
//
|
|
// Restore the search buttons, to allow the user to do another
|
|
// search - Bail if the main window is gone.
|
|
//
|
|
if (!IsWindow(pdfb->hwndDlg) || !IsWindowVisible(pdfb->hwndDlg))
|
|
return FALSE;
|
|
|
|
hwndCtl = GetDlgItem(pdfb->hwndDlg, IDD_ANIMATE);
|
|
|
|
if (hwndCtl)
|
|
Animate_Seek(hwndCtl, 0);
|
|
|
|
//
|
|
// Update status bar with count of files that were found
|
|
//
|
|
cItems = ShellFolderView_GetObjectCount(pdfb->hwndDlg);
|
|
pdfb->pdfff->lpVtbl->GetStatusMessageIndex(pdfb->pdfff, 0, &idsMsg);
|
|
DocFind_SetStatusText(pdfb->hwndStatus, 0, idsMsg, cItems);
|
|
SendMessage(pdfb->hwndStatus, SB_SIMPLE, 0, 0L);
|
|
|
|
// If we aborted the search due to number of files, we should
|
|
// show message box now. Do this after we disabled animation...
|
|
if (pdfb->cItemsAdded >= DF_MAX_MATCHFILES)
|
|
{
|
|
ShellMessageBox(HINST_THISDLL, pdfb->hwndDlg,
|
|
MAKEINTRESOURCE(IDS_FINDMAXFILESFOUND),
|
|
MAKEINTRESOURCE(IDS_FINDFILES),
|
|
MB_OK | MB_ICONINFORMATION);
|
|
}
|
|
|
|
// Update the state of the start and stop buttons
|
|
hwndCtl = GetDlgItem(pdfb->hwndDlg, IDD_START);
|
|
if (hwndCtl)
|
|
{
|
|
Button_Enable(hwndCtl, TRUE);
|
|
Button_SetStyle(hwndCtl, BS_DEFPUSHBUTTON, TRUE);
|
|
}
|
|
|
|
hwndCtl = GetDlgItem(pdfb->hwndDlg, IDD_STOP);
|
|
if (hwndCtl)
|
|
{
|
|
Button_Enable(hwndCtl, FALSE);
|
|
Button_SetStyle(hwndCtl, BS_PUSHBUTTON, TRUE);
|
|
}
|
|
|
|
// Now tell the filter to reenable changes
|
|
pdfb->pdfff->lpVtbl->EnableChanges(pdfb->pdfff, TRUE);
|
|
|
|
// If no items were found set the focus back to the search.
|
|
|
|
// BUGBUG - DavePl - since the change to CreatePage, we no longer
|
|
// have the valid HWND pointers to the pages, so this is broken.
|
|
// Investigate after the UNICODE port.
|
|
|
|
#if 0
|
|
if ((cItems == 0) && (pdfb->hwndCurPage))
|
|
SetFocus(GetNextDlgTabItem(pdfb->hwndCurPage, NULL, FALSE));
|
|
#endif
|
|
return TRUE;
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// DocFind_ClearSerach - Clear the search. Will stop the search if the
|
|
// Search is active.
|
|
//
|
|
BOOL DocFind_ClearSearch(HWND hwndDlg)
|
|
{
|
|
LPDFBROWSE pdfb;
|
|
|
|
pdfb = DocFind_GetPdfb(hwndDlg);
|
|
if (!pdfb)
|
|
return FALSE;
|
|
|
|
DocFind_StopFind(hwndDlg); // Stop any previous search
|
|
|
|
// Any active finds have been cleared, so lets reinitialize, but first
|
|
// ask user...
|
|
if (ShellMessageBox(HINST_THISDLL, pdfb->hwndDlg,
|
|
MAKEINTRESOURCE(IDS_FINDRESET),
|
|
MAKEINTRESOURCE(IDS_FINDFILES), MB_OKCANCEL|MB_ICONQUESTION) == IDOK)
|
|
{
|
|
LPTSTR pszTitle;
|
|
|
|
// Hide the results window;
|
|
DocFind_ShowResultsWindow(pdfb, FALSE);
|
|
|
|
// Tell defview to delete everything.
|
|
ShellFolderView_RemoveObject(pdfb->hwndDlg, NULL);
|
|
|
|
// And cleanup our folderList
|
|
CDFFolder_ClearFolderList((LPDFFOLDER)pdfb->pdfc);
|
|
|
|
pdfb->pdfff->lpVtbl->ClearSearchCriteria(pdfb->pdfff);
|
|
|
|
// We also need to to update the title
|
|
pdfb->pdfff->lpVtbl->GenerateTitle(pdfb->pdfff, &pszTitle, FALSE);
|
|
if (pszTitle != NULL)
|
|
{
|
|
SetWindowText(pdfb->hwndDlg, pszTitle);
|
|
SHFree(pszTitle); // And free the title string.
|
|
}
|
|
|
|
// Clear the save file information as this is now a new search
|
|
|
|
ILFree(pdfb->pidlSaveFile);
|
|
pdfb->pidlSaveFile = NULL;
|
|
|
|
|
|
// Also clear the statusbar text
|
|
SendMessage(pdfb->hwndStatus, SB_SETTEXT, 0, (LPARAM)szNULL);
|
|
SendMessage(pdfb->hwndStatus, SB_SIMPLE, 0, 0L);
|
|
SendMessage(hwndDlg, DM_SETDEFID, IDD_START, 0);
|
|
|
|
if (pdfb->hwndCurPage)
|
|
SetFocus(GetNextDlgTabItem(pdfb->hwndCurPage, NULL, FALSE));
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// DocFind_ShowResultsWindow - Called to either show or not show the
|
|
// results window
|
|
//
|
|
void DocFind_ShowResultsWindow(LPDFBROWSE pdfb, BOOL fShow)
|
|
{
|
|
RECT rcView;
|
|
RECT rcDlg;
|
|
RECT rcTabs;
|
|
RECT rcStatus;
|
|
HWND hwndDlg;
|
|
WINDOWPLACEMENT wp;
|
|
RECT rcAnimate;
|
|
HWND hwndAnimate;
|
|
|
|
if (fShow == pdfb->fShowResults)
|
|
return; // Don't need to do anything
|
|
|
|
hwndDlg = pdfb->hwndDlg;
|
|
|
|
pdfb->fShowResults = fShow;
|
|
|
|
GetClientRect(pdfb->hwndView, &rcView);
|
|
|
|
GetClientRect(pdfb->hwndStatus, &rcStatus);
|
|
GetWindowRect(hwndDlg, &rcDlg);
|
|
wp.length = SIZEOF(wp);
|
|
GetWindowPlacement(hwndDlg, &wp);
|
|
|
|
// Get the animation rectangle and Tabs rectangle...
|
|
GetWindowRect(pdfb->hwndTabs, &rcTabs);
|
|
MapWindowPoints(HWND_DESKTOP, hwndDlg, (POINT *)&rcTabs, 2);
|
|
|
|
hwndAnimate = GetDlgItem(hwndDlg, IDD_ANIMATE);
|
|
GetWindowRect(hwndAnimate, &rcAnimate);
|
|
MapWindowPoints(HWND_DESKTOP, hwndDlg, (POINT FAR*)&rcAnimate, 2);
|
|
|
|
// If the animation goes below the view extend the view...
|
|
if (rcTabs.bottom < rcAnimate.bottom)
|
|
rcTabs.bottom = rcAnimate.bottom;
|
|
|
|
if (fShow)
|
|
{
|
|
ShowWindow(pdfb->hwndView, SW_SHOW);
|
|
ShowWindow(pdfb->hwndStatus, SW_SHOW);
|
|
|
|
// Make sure the animate control is visible...
|
|
ShowWindow(GetDlgItem(hwndDlg, IDD_ANIMATE), SW_SHOW);
|
|
if (wp.showCmd == SW_SHOWMAXIMIZED)
|
|
{
|
|
RECT rcWork;
|
|
|
|
SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWork, 0);
|
|
|
|
// Ok we need to size our self around where the work area is...
|
|
// we need to resize the windows to take full screen...
|
|
// And resize the window not to show the results
|
|
SetWindowPos(hwndDlg, NULL, 0, 0, rcDlg.right - rcDlg.left,
|
|
rcWork.bottom - rcDlg.top,
|
|
SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE);
|
|
}
|
|
else
|
|
{
|
|
// And resize the window not to show the results
|
|
GetClientRect(hwndDlg, &rcDlg);
|
|
rcDlg.bottom = rcTabs.bottom + rcTabs.top +
|
|
rcView.bottom + rcStatus.bottom;
|
|
|
|
AdjustWindowRectEx(&rcDlg, GetWindowStyle(hwndDlg), TRUE,
|
|
GetWindowExStyle(hwndDlg));
|
|
|
|
SetWindowPos(hwndDlg, NULL, 0, 0, rcDlg.right - rcDlg.left,
|
|
rcDlg.bottom - rcDlg.top,
|
|
SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RECT rcTabs;
|
|
|
|
ShowWindow(pdfb->hwndView, SW_HIDE);
|
|
ShowWindow(pdfb->hwndStatus, SW_HIDE);
|
|
|
|
GetClientRect(hwndDlg, &rcDlg);
|
|
|
|
GetWindowRect(pdfb->hwndTabs, &rcTabs);
|
|
MapWindowPoints(HWND_DESKTOP, hwndDlg, (POINT FAR*)&rcTabs, 2);
|
|
rcDlg.bottom = rcTabs.bottom + rcTabs.top;
|
|
|
|
// Also see if we should show the animation window when
|
|
// we are small sized...
|
|
if (rcAnimate.bottom > rcDlg.bottom)
|
|
ShowWindow(hwndAnimate, SW_HIDE);
|
|
|
|
// Now calculate the size window we need...
|
|
AdjustWindowRectEx(&rcDlg, GetWindowStyle(hwndDlg), TRUE,
|
|
GetWindowExStyle(hwndDlg));
|
|
|
|
pdfb->cyNoResults = rcDlg.bottom - rcDlg.top;
|
|
SetWindowPos(hwndDlg, NULL, 0, 0, rcDlg.right - rcDlg.left,
|
|
pdfb->cyNoResults,
|
|
SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE);
|
|
|
|
}
|
|
}
|
|
|
|
TCHAR const c_szFindExtensions[] = TEXT("FindExtensions");
|
|
|
|
LPCONTEXTMENU WINAPI SHFind_InitMenuPopup(HMENU hmenu, HWND hwndOwner, UINT idCmdFirst, UINT idCmdLast)
|
|
{
|
|
LPCONTEXTMENU pcm = NULL;
|
|
HKEY hkFind = SHGetExplorerSubHkey(HKEY_LOCAL_MACHINE, c_szFindExtensions, FALSE);
|
|
|
|
if (hkFind) {
|
|
|
|
if (SUCCEEDED(CDefFolderMenu_CreateHKeyMenu(hwndOwner, hkFind, &pcm))) {
|
|
int iItems = GetMenuItemCount(hmenu);
|
|
// nuke all old entries
|
|
while (iItems--) {
|
|
DeleteMenu(hmenu, iItems, MF_BYPOSITION);
|
|
}
|
|
|
|
pcm->lpVtbl->QueryContextMenu(pcm, hmenu, 0, idCmdFirst, idCmdLast, CMF_NODEFAULT|CMF_INCLUDESTATIC);
|
|
iItems = GetMenuItemCount(hmenu);
|
|
if (!iItems) {
|
|
DebugMsg(DM_TRACE, TEXT("no menus in find extension, blowing away context menu"));
|
|
pcm->lpVtbl->Release(pcm);
|
|
pcm = NULL;
|
|
}
|
|
}
|
|
RegCloseKey(hkFind);
|
|
}
|
|
|
|
return pcm;
|
|
}
|
|
|
|
typedef struct _CFindExt // dxi
|
|
{
|
|
IShellExtInit isei;
|
|
IContextMenu icm;
|
|
UINT cRef;
|
|
LPITEMIDLIST pidl;
|
|
|
|
} CShellFindExt, FAR* LPSHELLFINDEXT;
|
|
|
|
HRESULT STDMETHODCALLTYPE CShellFindExt_SEI_QueryInterface(LPSHELLEXTINIT psei, REFIID riid,
|
|
LPVOID FAR* ppvObj)
|
|
{
|
|
LPSHELLFINDEXT this = IToClass(CShellFindExt, isei, psei);
|
|
|
|
if (IsEqualIID(riid, &IID_IContextMenu) )
|
|
{
|
|
*ppvObj = &this->icm;
|
|
this->cRef++;
|
|
return NOERROR;
|
|
} else if (IsEqualIID(riid, &IID_IShellExtInit) ||
|
|
IsEqualIID(riid, &IID_IUnknown))
|
|
{
|
|
*ppvObj = &this->isei;
|
|
this->cRef++;
|
|
return NOERROR;
|
|
}
|
|
|
|
*ppvObj = NULL;
|
|
return(ResultFromScode(E_NOINTERFACE));
|
|
|
|
}
|
|
|
|
ULONG STDMETHODCALLTYPE CShellFindExt_SEI_Release(LPSHELLEXTINIT psei)
|
|
{
|
|
LPSHELLFINDEXT this = IToClass(CShellFindExt, isei, psei);
|
|
this->cRef--;
|
|
if (this->cRef > 0)
|
|
{
|
|
return this->cRef;
|
|
}
|
|
ILFree(this->pidl);
|
|
LocalFree((HLOCAL)this);
|
|
return 0;
|
|
}
|
|
|
|
ULONG STDMETHODCALLTYPE CShellFindExt_SEI_AddRef(LPSHELLEXTINIT psei)
|
|
{
|
|
LPSHELLFINDEXT this = IToClass(CShellFindExt, isei, psei);
|
|
this->cRef++;
|
|
return this->cRef;
|
|
}
|
|
|
|
ULONG STDMETHODCALLTYPE CShellFindExt_SEI_Initialize(LPSHELLEXTINIT psei,
|
|
LPCITEMIDLIST pidlFolder,
|
|
LPDATAOBJECT pdtobj,
|
|
HKEY hkeyProgID)
|
|
{
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
HMENU _LoadPopupMenu(UINT id);
|
|
|
|
STDMETHODIMP CShellFindExt_QueryContextMenu(IContextMenu * pcm,
|
|
HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast,
|
|
UINT uFlags)
|
|
{
|
|
HMENU hmMerge = _LoadPopupMenu(POPUP_FINDEXT_POPUPMERGE);
|
|
int iCommands = 0;
|
|
int idMax = idCmdFirst;
|
|
|
|
if (hmMerge) {
|
|
|
|
MENUITEMINFO mii;
|
|
|
|
mii.cbSize = SIZEOF(MENUITEMINFO);
|
|
mii.fMask = MIIM_DATA;
|
|
mii.dwItemData = Shell_GetCachedImageIndex(c_szShell32Dll, EIRESID(IDI_DOCFIND), 0);
|
|
#ifdef DEBUG
|
|
// setting the icon index
|
|
DebugMsg(DM_TRACE, TEXT("%d is the icon index being set"), mii.dwItemData);
|
|
#endif
|
|
if (mii.dwItemData != -1)
|
|
SetMenuItemInfo(hmMerge, FSIDM_FINDFILES, FALSE, &mii);
|
|
|
|
if (!(GetSystemMetrics(SM_NETWORK) & RNC_NETWORKS)) {
|
|
// Need to remove the Find Computer as we dont have a network
|
|
DeleteMenu(hmMerge, FSIDM_FINDCOMPUTER, MF_BYCOMMAND);
|
|
} else {
|
|
|
|
mii.dwItemData = Shell_GetCachedImageIndex(c_szShell32Dll, EIRESID(IDI_COMPFIND),0);
|
|
if (mii.dwItemData != -1)
|
|
SetMenuItemInfo(hmMerge, FSIDM_FINDCOMPUTER, FALSE, &mii);
|
|
|
|
}
|
|
idMax = Shell_MergeMenus(hmenu, hmMerge, indexMenu,
|
|
idCmdFirst, idCmdLast,
|
|
0);
|
|
DestroyMenu(hmMerge);
|
|
}
|
|
|
|
return ResultFromShort(idMax - idCmdFirst);
|
|
}
|
|
|
|
STDMETHODIMP CShellFindExt_InvokeCommand(LPCONTEXTMENU pcm,
|
|
LPCMINVOKECOMMANDINFO pici)
|
|
{
|
|
LPSHELLFINDEXT this = IToClass(CShellFindExt, icm, pcm);
|
|
LPITEMIDLIST pidl;
|
|
|
|
DebugMsg(DM_TRACE, TEXT("sh - tr - FindExt_invokeCommand %d"), pici->lpVerb);
|
|
|
|
switch ((UINT)pici->lpVerb) {
|
|
case FSIDM_FINDFILES:
|
|
if (pici->lpDirectory)
|
|
{
|
|
#ifdef UNICODE
|
|
WCHAR szDirectory[MAX_PATH];
|
|
LPCWSTR lpDirectory;
|
|
|
|
if (pici->cbSize < SIZEOF(CMINVOKECOMMANDINFOEX)
|
|
|| (pici->fMask & CMIC_MASK_UNICODE) != CMIC_MASK_UNICODE)
|
|
{
|
|
MultiByteToWideChar(CP_ACP, 0,
|
|
pici->lpDirectory, -1,
|
|
szDirectory, ARRAYSIZE(szDirectory));
|
|
}
|
|
else
|
|
{
|
|
lpDirectory = ((LPCMINVOKECOMMANDINFOEX)pici)->lpDirectoryW;
|
|
}
|
|
pidl = ILCreateFromPath(lpDirectory);
|
|
#else
|
|
pidl = ILCreateFromPath(pici->lpDirectory);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
pidl = NULL;
|
|
}
|
|
RealFindFiles(pidl,NULL);
|
|
ILFree(pidl);
|
|
break;
|
|
|
|
case FSIDM_FINDCOMPUTER:
|
|
SHFindComputer(NULL, NULL);
|
|
break;
|
|
}
|
|
return NOERROR;
|
|
}
|
|
|
|
STDMETHODIMP CShellFindExt_GetCommandString(
|
|
IContextMenu * pcm,
|
|
UINT idCmd,
|
|
UINT wFlags,
|
|
UINT * pwReserved,
|
|
LPSTR pszName,
|
|
UINT cchMax)
|
|
{
|
|
DebugMsg(DM_TRACE, TEXT("sh - tr - idCmd = %d"), idCmd);
|
|
|
|
if (wFlags & GCS_HELPTEXTA)
|
|
{
|
|
UINT cch;
|
|
|
|
if ((wFlags & GCS_HELPTEXTW) == GCS_HELPTEXTW)
|
|
cch = LoadStringW(HINST_THISDLL, idCmd + IDS_MH_FSIDM_FIRST,
|
|
(LPWSTR)pszName, cchMax);
|
|
else
|
|
cch = LoadStringA(HINST_THISDLL, idCmd + IDS_MH_FSIDM_FIRST,
|
|
pszName, cchMax);
|
|
if (cch)
|
|
return NOERROR;
|
|
else
|
|
return ResultFromScode(E_OUTOFMEMORY);
|
|
}
|
|
else
|
|
return ResultFromScode(E_NOTIMPL);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CShellFindExt_CM_QueryInterface(LPCONTEXTMENU pcm, REFIID riid,
|
|
LPVOID FAR* ppvObj)
|
|
{
|
|
LPSHELLFINDEXT this = IToClass(CShellFindExt, icm, pcm);
|
|
return CShellFindExt_SEI_QueryInterface(&this->isei, riid, ppvObj);
|
|
}
|
|
|
|
ULONG STDMETHODCALLTYPE CShellFindExt_CM_Release(LPCONTEXTMENU pcm)
|
|
{
|
|
LPSHELLFINDEXT this = IToClass(CShellFindExt, icm, pcm);
|
|
return CShellFindExt_SEI_Release(&this->isei);
|
|
}
|
|
|
|
ULONG STDMETHODCALLTYPE CShellFindExt_CM_AddRef(LPCONTEXTMENU pcm)
|
|
{
|
|
LPSHELLFINDEXT this = IToClass(CShellFindExt, icm, pcm);
|
|
return CShellFindExt_SEI_AddRef(&this->isei);
|
|
}
|
|
|
|
|
|
#pragma data_seg(".text", "CODE")
|
|
IContextMenuVtbl c_CShellFindExtCMVtbl =
|
|
{
|
|
CShellFindExt_CM_QueryInterface,
|
|
CShellFindExt_CM_AddRef,
|
|
CShellFindExt_CM_Release,
|
|
|
|
CShellFindExt_QueryContextMenu,
|
|
CShellFindExt_InvokeCommand,
|
|
CShellFindExt_GetCommandString
|
|
|
|
};
|
|
|
|
IShellExtInitVtbl c_CShellFindExtSEIVtbl =
|
|
{
|
|
CShellFindExt_SEI_QueryInterface,
|
|
CShellFindExt_SEI_AddRef,
|
|
CShellFindExt_SEI_Release,
|
|
|
|
CShellFindExt_SEI_Initialize
|
|
};
|
|
#pragma data_seg()
|
|
|
|
HRESULT CALLBACK CShellFindExt_CreateInstance(LPUNKNOWN punkOuter, REFIID riid, LPVOID * ppvOut)
|
|
{
|
|
LPSHELLFINDEXT psfe;
|
|
HRESULT hres = ResultFromScode(E_OUTOFMEMORY); // assume error;
|
|
|
|
Assert(punkOuter == NULL);
|
|
|
|
psfe = (void*)LocalAlloc(LPTR,SIZEOF(CShellFindExt));
|
|
if (psfe)
|
|
{
|
|
psfe->isei.lpVtbl = &c_CShellFindExtSEIVtbl;
|
|
psfe->icm.lpVtbl = &c_CShellFindExtCMVtbl;
|
|
psfe->cRef = 1;
|
|
hres = CShellFindExt_SEI_QueryInterface(&psfe->isei, riid, ppvOut);
|
|
CShellFindExt_SEI_Release(&psfe->isei);
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
//
|
|
// Callback from SHCreateShellFolderViewEx
|
|
//
|
|
HRESULT CALLBACK DF_FNVCallBack(LPSHELLVIEW psvOuter,
|
|
LPSHELLFOLDER psf,
|
|
HWND hwndOwner,
|
|
UINT uMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
LPDFFOLDER this = IToClass(CDFFolder, sf, psf);
|
|
HRESULT hres = NOERROR; // assume no error
|
|
HMENU hmenu;
|
|
UINT id;
|
|
|
|
switch(uMsg)
|
|
{
|
|
case DVM_MERGEMENU:
|
|
{
|
|
int i;
|
|
|
|
DebugMsg(DM_TRACE, TEXT("sh TR - DF_FSNCallBack DVN_MERGEMENU"));
|
|
|
|
|
|
this->pdfff->lpVtbl->GetFolderMergeMenuIndex(this->pdfff, &id);
|
|
CDefFolderMenu_MergeMenu(HINST_THISDLL, 0, id, (LPQCMINFO)lParam);
|
|
|
|
// Lets remove some menu items that are not useful to us.
|
|
hmenu = ((LPQCMINFO)lParam)->hmenu;
|
|
DeleteMenu(hmenu, SFVIDM_EDIT_PASTE, MF_BYCOMMAND);
|
|
DeleteMenu(hmenu, SFVIDM_EDIT_PASTELINK, MF_BYCOMMAND);
|
|
// DeleteMenu(hmenu, SFVIDM_EDIT_PASTESPECIAL, MF_BYCOMMAND);
|
|
|
|
// This is sortof bogus but if after the merge one of the
|
|
// menus has no items in it, remove the menu.
|
|
|
|
for (i = GetMenuItemCount(hmenu)-1; i >= 0; i--)
|
|
{
|
|
HMENU hmenuSub = GetSubMenu(hmenu, i);
|
|
|
|
if ((hmenuSub) && (GetMenuItemCount(hmenuSub) == 0))
|
|
{
|
|
DeleteMenu(hmenu, i, MF_BYPOSITION);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
|
|
case DVM_GETWORKINGDIR:
|
|
{
|
|
LPITEMIDLIST *ppidls; // pointer to a list of pidls.
|
|
int cpidls; // Count of pidls that were returned.
|
|
cpidls = ShellFolderView_GetSelectedObjects(hwndOwner, &ppidls);
|
|
if (cpidls > 0) {
|
|
LPITEMIDLIST pidl;
|
|
pidl = CDFolder_GetParentsPIDL(psf, ppidls[0]);
|
|
SHGetPathFromIDList(pidl, (LPTSTR)lParam);
|
|
} else
|
|
return ResultFromScode(E_FAIL);
|
|
break;
|
|
}
|
|
|
|
case DVM_INITMENUPOPUP:
|
|
hmenu = (HMENU)lParam;
|
|
id = GetMenuItemID(hmenu, 0);
|
|
DebugMsg(DM_TRACE, TEXT("sh TR - DF_FSNCallBack DVN_INITMENUPOPUP (id=%x)"), wParam);
|
|
break;
|
|
|
|
case DVM_INVOKECOMMAND:
|
|
DebugMsg(DM_TRACE, TEXT("sh TR - DF_FSNCallBack DVN_INVOKECOMMAND (id=%x)"), wParam);
|
|
switch(wParam)
|
|
{
|
|
case FSIDM_SORTBYLOCATION:
|
|
case FSIDM_SORTBYNAME:
|
|
case FSIDM_SORTBYSIZE:
|
|
case FSIDM_SORTBYTYPE:
|
|
case FSIDM_SORTBYDATE:
|
|
ShellFolderView_ReArrange(hwndOwner, DFSortIDToICol(wParam));
|
|
break;
|
|
|
|
}
|
|
break;
|
|
|
|
case DVM_GETHELPTEXT:
|
|
case DVM_SELCHANGE:
|
|
|
|
case DVM_REFRESH:
|
|
case DVM_KILLFOCUS:
|
|
break;
|
|
|
|
case DVM_SETFOCUS:
|
|
break;
|
|
|
|
case DVM_RELEASE:
|
|
break;
|
|
|
|
default:
|
|
hres = ResultFromScode(E_FAIL);
|
|
}
|
|
return hres;
|
|
}
|