Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

2388 lines
66 KiB

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1995
//
// File: find.cpp
//
// Contents: OLE-DB - based Find Dialog and Summary Catalog viewer
//
// Classes: COLEDBFindExt
// CCatalogBrowser
// CCatalogFolder
// CCatalogMenuWrap
//
// Functions:
//
// History: 23-Aug-95 JonBe Created
//
//----------------------------------------------------------------------------
#include "precomp.h"
#include "uastrfnc.h" // This is in shellprv.h. Why do I need to explicitly
// include it?
#include <dsys.h>
#include "find.h"
// BUGBUG: #pragma data_seg(".text", "CODE") ?
const UINT c_auDFMenuIDs[] = {
FCIDM_MENU_FILE,
FCIDM_MENU_EDIT,
FCIDM_MENU_VIEW,
IDM_MENU_OPTIONS,
FCIDM_MENU_HELP
};
// #pragma data_seg() ?
enum
{
ICATALOGCOL_NAME = 0,
ICATALOGCOL_PATH,
ICATALOGCOL_SIZE,
ICATALOGCOL_TYPE,
ICATALOGCOL_MODIFIED,
ICATALOGCOL_MAX, // Make sure this is the last enum item
} ;
// BUGBUG: Do we need this pragma?
#pragma data_seg(DATASEG_PERINSTANCE)
DWORD g_dwTlsSlot = 0xffffffff;
#pragma data_seg()
ITEMIDLIST s_idlEmpty = {0};
// The header for my 'extra info' itemid. It's a mkid with cb, a special
// signature, and then a string (the path of the item).
#define CATALOG_ITEM_HEADER_SIZE (SIZEOF(CATALOG_ID))
#define CATALOG_SIGNATURE_BYTE (BYTE)0x6A
class CATALOG_ID
{
public:
USHORT cb;
BYTE bSignature;
WCHAR awchPath[1];
};
//
// The maximum number of rows fetched at once through pRowset->GetData()
//
#define MAX_FETCHED_AT_ONCE 100
GUID guidSystem2 = PSGUID_STORAGE;
//
// Buffer into which we read data from the rowsets
//
typedef WCHAR NAMEBUF[MAX_PATH]; // Longest allowable NT filesystem path
typedef WCHAR SNAMEBUF[13]; // 8+1+3+1 => 8.3 name plus NULL
struct SRowBuf
{
FILETIME ftLastWriteTime;
LONGLONG llFileSize;
DWORD dwFileAttributes;
NAMEBUF awchName;
SNAMEBUF awchShortName;
NAMEBUF awchPath;
};
#define guidZero { (ULONG) 0, (USHORT) 0, (USHORT) 0, { 0, 0, 0, 0, 0, 0, 0, 0 } }
DBBINDING aCatalogOutColumns[] =
{
{ DBCOLUMNPART_VALUE, 0, 0, VT_FILETIME, NULL, NULL, offsetof(SRowBuf, ftLastWriteTime), SIZEOF(FILETIME), 0, guidZero, 0, 0 },
{ DBCOLUMNPART_VALUE, 0, 0, DBTYPE_I8, NULL, NULL, offsetof(SRowBuf, llFileSize), SIZEOF(LONGLONG), 0, guidZero, 0, 0 },
{ DBCOLUMNPART_VALUE, 0, 0, DBTYPE_I4, NULL, NULL, offsetof(SRowBuf, dwFileAttributes), SIZEOF(DWORD), 0, guidZero, 0, 0 },
{ DBCOLUMNPART_VALUE, 0, 0, DBTYPE_WSTR, NULL, NULL, offsetof(SRowBuf, awchName[0]), SIZEOF(NAMEBUF), 0, guidZero, 0, 0 },
{ DBCOLUMNPART_VALUE, 0, 0, DBTYPE_WSTR, NULL, NULL, offsetof(SRowBuf, awchShortName[0]), SIZEOF(SNAMEBUF), 0, guidZero, 0, 0 },
{ DBCOLUMNPART_VALUE, 0, 0, DBTYPE_WSTR, NULL, NULL, offsetof(SRowBuf, awchPath[0]), SIZEOF(NAMEBUF), 0, guidZero, 0, 0 }
};
const int cCatalogOutColumns = ARRAYSIZE(aCatalogOutColumns);
extern "C"
HRESULT CALLBACK COLEDBFindExt_CreateInstance(IUnknown* punkOuter, REFIID riid, LPVOID* ppvOut)
{
HRESULT hr = E_OUTOFMEMORY;
Assert(punkOuter == NULL); // BUGBUG: Check in retail code too?
// NULL the OUT ptr in case of error
*ppvOut = NULL;
COLEDBFindExt* pOLEDBFindExt = new COLEDBFindExt;
if (pOLEDBFindExt)
{
hr = pOLEDBFindExt->QueryInterface(riid, ppvOut);
pOLEDBFindExt->Release();
}
return hr;
}
//
// Constructor
//
COLEDBFindExt::COLEDBFindExt()
{
m_cRefs = 1;
}
//
// AddRef
//
STDMETHODIMP_(ULONG) COLEDBFindExt::AddRef()
{
InterlockedIncrement((LONG *) &m_cRefs);
return m_cRefs;
}
//
// Release
//
STDMETHODIMP_(ULONG) COLEDBFindExt::Release()
{
ULONG tmp = m_cRefs;
if (0 == InterlockedDecrement((LONG *) &m_cRefs))
{
delete this;
return 0;
}
else
{
return tmp - 1;
}
}
//
// QueryInterface
//
STDMETHODIMP COLEDBFindExt::QueryInterface(REFIID riid, LPVOID * ppvObj)
{
HRESULT hr;
if(IsEqualIID(riid, IID_IUnknown))
{
*ppvObj = this;
}
else if (IsEqualIID(riid, IID_IShellExtInit))
{
*ppvObj = (IShellExtInit*)this;
}
else if (IsEqualIID(riid, IID_IContextMenu))
{
*ppvObj = (IContextMenu*)this;
}
else
{
dprintf(TEXT("COLEDBFindExt::QueryInterface for unsupported interface\n"));
*ppvObj = NULL;
hr = E_NOINTERFACE;
}
if (SUCCEEDED(hr))
{
AddRef();
hr = NOERROR;
}
return hr;
}
STDMETHODIMP COLEDBFindExt::Initialize(LPCITEMIDLIST pidlFolder,
LPDATAOBJECT lpdobj,
HKEY hkeyProgID)
{
return NOERROR;
}
STDMETHODIMP COLEDBFindExt::QueryContextMenu(HMENU hMenu,
UINT indexMenu,
UINT idCmdFirst,
UINT idCmdLast,
UINT uFlags)
{
UINT idCmd = idCmdFirst;
if ((uFlags & 0x0007) == CMF_NORMAL) // Check == here, since CMF_NORMAL=0
{
// BUGBUG: Add icon, and load from resource
InsertMenu(hMenu,
indexMenu++,
MF_STRING|MF_BYPOSITION,
idCmd++,
L"Files or Folders using &OLE-DB...");
InsertMenu(hMenu,
indexMenu++,
MF_STRING|MF_BYPOSITION,
idCmd++,
L"Items in the &Global Catalog...");
// Give the catalog viewer its own icon
MENUITEMINFO mii;
mii.cbSize = SIZEOF(MENUITEMINFO);
mii.fMask = MIIM_DATA;
mii.dwItemData = Shell_GetCachedImageIndex(c_szShell32Dll, EIRESID(IDI_CATALOG), 0);
if (mii.dwItemData != -1)
{
SetMenuItemInfo(hMenu, indexMenu - 1, TRUE, &mii);
}
return ResultFromShort(idCmd - idCmdFirst);
}
return NOERROR;
}
STDMETHODIMP COLEDBFindExt::InvokeCommand(LPCMINVOKECOMMANDINFO lpici)
{
if (0 == HIWORD(lpici->lpVerb))
{
// Assert(lpici->lpVerb == 0)
switch (LOWORD(lpici->lpVerb))
{
case 0:
DoFindFiles();
break;
case 1:
DoCatalogViewer();
break;
default:
dprintf(TEXT("COLEDBFindExt::InvokeCommand - Unknown lpici->lpVerb\n"));
break;
}
}
return NOERROR;
}
STDMETHODIMP COLEDBFindExt::GetCommandString(UINT idCmd,
UINT uType,
UINT* pwReserved,
LPSTR pszName,
UINT cchMax)
{
dprintf(TEXT("Hit unimplemented COLEDBFindExt::GetCommandString\n"));
return E_NOTIMPL;
}
//
// Private methods
//
void COLEDBFindExt::DoFindFiles(void)
{
HANDLE hThread;
DWORD dwThreadID;
hThread = CreateThread(NULL,
0,
OLEDBFind_MainThreadProc,
NULL,
NULL,
&dwThreadID);
if (NULL != hThread)
{
CloseHandle(hThread);
}
else
{
dprintf(TEXT("COLEDBFindExt::DoFindFiles - CreateThread failed\n"));
}
}
void COLEDBFindExt::DoCatalogViewer(void)
{
HANDLE hThread;
DWORD dwThreadID;
hThread = CreateThread(NULL,
0,
Catalog_MainThreadProc,
NULL,
NULL,
&dwThreadID);
if (NULL != hThread)
{
CloseHandle(hThread);
}
else
{
dprintf(TEXT("COLEDBFindExt::DoFindFiles - CreateThread failed\n"));
}
}
DWORD CALLBACK OLEDBFind_MainThreadProc(LPVOID lpThreadParameters)
{
DialogBoxParam(HINST_THISDLL,
MAKEINTRESOURCE(DLG_OLEDBFIND),
NULL,
OLEDBFind_DlgProc,
NULL); // (LPARAM)lpThreadParameters);
return(0);
}
BOOL CALLBACK OLEDBFind_DlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_INITDIALOG:
break;
case WM_CLOSE:
EndDialog(hwndDlg, FALSE);
break;
default:
return FALSE;
}
return TRUE;
}
DWORD CALLBACK Catalog_MainThreadProc(LPVOID lpThreadParameters)
{
__try
{
DialogBoxParam(HINST_THISDLL,
MAKEINTRESOURCE(DLG_CATALOG),
NULL,
Catalog_DlgProc,
NULL); // (LPARAM)lpThreadParameters);
}
__except(SetErrorMode(SEM_NOGPFAULTERRORBOX),UnhandledExceptionFilter(GetExceptionInformation()))
{
// Catch if the main thread blows away!
CCatalogBrowser* pBrowser;
// Now See if we have a browser pointer stored away.
if ((g_dwTlsSlot != 0xffffffff) &&
((pBrowser = (CCatalogBrowser*)TlsGetValue(g_dwTlsSlot)) == NULL))
{
pBrowser->Release();
}
}
return(0);
}
BOOL CALLBACK Catalog_DlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
HANDLE_MSG(hwndDlg, WM_INITDIALOG, _CatalogBrowse_OnInitDialog);
HANDLE_MSG(hwndDlg, WM_DESTROY, _CatalogBrowse_OnDestroy);
HANDLE_MSG(hwndDlg, WM_SIZE, _CatalogBrowse_OnSize);
case WM_CLOSE:
EndDialog(hwndDlg, FALSE);
break;
case WM_INITMENUPOPUP:
_CatalogBrowse_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:
_CatalogBrowse_ForwardMsgToView(hwndDlg, msg, wParam, lParam);
break;
case WM_WININICHANGE:
case WM_SYSCOLORCHANGE:
RelayMessageToChildren(hwndDlg, msg, wParam, 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,
_CatalogBrowse_OnCommand(hwndDlg, GET_WM_COMMAND_ID(wParam, lParam),
GET_WM_COMMAND_HWND(wParam, lParam),
GET_WM_COMMAND_CMD(wParam, lParam)));
break;
default:
return FALSE;
}
return TRUE;
}
BOOL _CatalogBrowse_OnInitDialog(HWND hwndDlg, HWND hwndFocus, LPARAM lParam)
{
HICON hiconSmall;
HICON hiconLarge;
HMENU hmenu;
// Make this window foreground.
SetForegroundWindow(hwndDlg);
// Instantiate a catalog browser
CCatalogBrowser* pBrowser = new CCatalogBrowser(hwndDlg);
if (NULL == pBrowser)
{
goto ErrorReturn;
}
// Set the window icons. It's OK if this fails -- the destructor
// handles it
// BUGBUG Make this different between catalogs & find!
hiconSmall = (HICON)LoadImage(HINST_THISDLL, MAKEINTRESOURCE(IDI_CATALOG),
IMAGE_ICON, g_cxSmIcon, g_cySmIcon, LR_DEFAULTCOLOR);
hiconLarge = LoadIcon(HINST_THISDLL, MAKEINTRESOURCE(IDI_CATALOG));
SendMessage(hwndDlg, WM_SETICON, FALSE, MAKELONG(hiconSmall, 0));
SendMessage(hwndDlg, WM_SETICON, TRUE, MAKELONG(hiconLarge, 0));
// Set the menu
// BUGBUG Make this different between catalogs & find, too!
hmenu = LoadMenu(HINST_THISDLL, MAKEINTRESOURCE(MENU_CATALOG));
if (NULL != hmenu)
{
HMENU hMenuOld = GetMenu(hwndDlg);
if (hMenuOld)
{
DestroyMenu(hMenuOld);
}
SetMenu(hwndDlg, hmenu);
pBrowser->m_hmenuTemplate = hmenu;
}
// And save away pointer to our structure
SetWindowLong(hwndDlg, DWL_USER, (LONG)pBrowser);
if (g_dwTlsSlot == 0xffffffff)
g_dwTlsSlot = TlsAlloc();
TlsSetValue(g_dwTlsSlot, pBrowser);
// Instantiate a catalog folder
pBrowser->m_pFolder = new CCatalogFolder();
if (NULL == pBrowser->m_pFolder)
{
goto Abort;
}
// Create a view
if (FAILED(pBrowser->m_pFolder->CreateViewObject(NULL,
IID_IShellView,
(void**)&pBrowser->m_pView)))
{
goto Abort;
}
// And the window that corresponds to it.
// First we need to initialize the view info structure.
pBrowser->m_fs.ViewMode = FVM_DETAILS;
pBrowser->m_fs.fFlags = 0;
// BUGBUG TODO: Read from view state
RECT rcView;
GetClientRect(hwndDlg, &rcView);
if (FAILED(pBrowser->m_pView->CreateViewWindow(NULL, // lpPrevView
&pBrowser->m_fs,
pBrowser,
&rcView,
&pBrowser->m_hwndView)))
{
goto Abort;
}
goto Exit;
Abort:
pBrowser->Release();
ErrorReturn:
EndDialog(hwndDlg, FALSE);
Exit:
return FALSE;
}
void _CatalogBrowse_OnDestroy(HWND hwndDlg)
{
CCatalogBrowser* pBrowser = (CCatalogBrowser*)GetWindowLong(hwndDlg, DWL_USER);
if (pBrowser)
{
pBrowser->Release();
}
}
void _CatalogBrowse_OnSize(HWND hwndDlg, UINT state, int cx, int cy)
{
CCatalogBrowser* pBrowser = (CCatalogBrowser*)GetWindowLong(hwndDlg, DWL_USER);
if (pBrowser)
{
SetWindowPos(pBrowser->m_hwndView, HWND_TOP, 0, 0, cx, cy, NULL);
}
}
void _CatalogBrowse_OnInitMenuPopup(HWND hwndDlg, HMENU hmInit, int nIndex, BOOL fSystemMenu)
{
MENUITEMINFO mii;
CCatalogBrowser* pBrowser = (CCatalogBrowser*)GetWindowLong(hwndDlg, DWL_USER);
// BUGBUG To do: more menu massaging, once we decide what the menu
// structure should really look like.
if (fSystemMenu)
{
return; // not interested
}
mii.cbSize = SIZEOF(MENUITEMINFO);
mii.fMask = MIIM_SUBMENU|MIIM_ID;
mii.cch = 0;
if (!GetMenuItemInfo(pBrowser->m_hmenuCurrent, nIndex, TRUE, &mii) || mii.hSubMenu != hmInit)
{
return;
}
switch (mii.wID)
{
case FCIDM_MENU_FILE:
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:
break;
}
}
LRESULT _CatalogBrowse_OnCommand(HWND hwndDlg, UINT id, HWND hwndCtl, UINT codeNotify)
{
// BUGBUG To do: complete this case statement
switch (id) {
case IDM_CLOSE:
PostMessage(hwndDlg, WM_CLOSE, 0, 0);
break;
case IDCANCEL:
// Don't let ESC close the window. Hmm -- bug or feature?
break;
#ifndef NO_HELP_YET
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;
#endif
default:
if ((id >= FCIDM_SHVIEWFIRST) && (id <= FCIDM_SHVIEWLAST))
{
// Indicating we need to forward this message.
FORWARD_WM_COMMAND(hwndDlg, id, hwndCtl, codeNotify,
_CatalogBrowse_ForwardMsgToView);
return 0;
}
break;
}
return 0;
}
LRESULT _CatalogBrowse_ForwardMsgToView(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
CCatalogBrowser* pBrowser = (CCatalogBrowser*)GetWindowLong(hwndDlg, DWL_USER);
return SendMessage(pBrowser->m_hwndView, msg, wParam, lParam);
}
//
// CCatalogBrowser constructor
//
CCatalogBrowser::CCatalogBrowser(HWND hwndDlg)
{
m_cRefs = 1;
m_pView = NULL;
m_pFolder = NULL;
m_hwndDlg = hwndDlg;
m_hmenuTemplate = NULL;
m_hmenuCurrent = NULL;
}
//
// Destructor
//
CCatalogBrowser::~CCatalogBrowser()
{
HICON hIcon;
//
// Destroy the icons
//
if (hIcon = (HICON)SendMessage(m_hwndDlg, WM_SETICON, FALSE, 0L))
{
DestroyIcon(hIcon);
}
if (hIcon = (HICON)SendMessage(m_hwndDlg, WM_SETICON, TRUE, 0L))
{
DestroyIcon(hIcon);
}
//
// Release the other guys that depend on us
//
if (m_pFolder)
m_pFolder->Release();
if (m_pView)
{
m_pView->UIActivate(SVUIA_DEACTIVATE);
m_pView->DestroyViewWindow();
m_pView->Release();
}
// Don't destroy the menu until after we've given the view
// a chance to unmerge its menu items above
if (m_hmenuTemplate != GetMenu(m_hwndDlg) && m_hmenuTemplate)
{
DestroyMenu(m_hmenuTemplate);
// m_hmenuTemplate = NULL; //BUGBUG Necessary?
}
// Make sure no more messages try to use us!
SetWindowLong(m_hwndDlg, DWL_USER, (LONG)NULL);
}
//
// AddRef
//
STDMETHODIMP_(ULONG) CCatalogBrowser::AddRef()
{
InterlockedIncrement((LONG *) &m_cRefs);
return m_cRefs;
}
//
// Release
//
STDMETHODIMP_(ULONG) CCatalogBrowser::Release()
{
ULONG tmp = m_cRefs;
if (0 == InterlockedDecrement((LONG *) &m_cRefs))
{
delete this;
return 0;
}
else
{
return tmp - 1;
}
}
//
// QueryInterface
//
STDMETHODIMP CCatalogBrowser::QueryInterface(REFIID riid, LPVOID * ppvObj)
{
HRESULT hr;
if(IsEqualIID(riid, IID_IUnknown))
{
*ppvObj = this;
}
else if (IsEqualIID(riid, IID_IShellBrowser))
{
*ppvObj = (IShellBrowser*)this;
}
else
{
dprintf(TEXT("CCatalogBrowser::QueryInterface for unsupported interface\n"));
*ppvObj = NULL;
hr = E_NOINTERFACE;
}
if (SUCCEEDED(hr))
{
AddRef();
hr = NOERROR;
}
return hr;
}
//
// IShellBrowser
//
STDMETHODIMP CCatalogBrowser::GetWindow(HWND * lphwnd)
{
*lphwnd = m_hwndDlg;
return S_OK;
}
STDMETHODIMP CCatalogBrowser::ContextSensitiveHelp(BOOL fEnterMode)
{
dprintf(TEXT("Unimplemented CCatalogBrowser::ContextSensitiveHelp called\n"));
return E_NOTIMPL;
}
STDMETHODIMP CCatalogBrowser::InsertMenusSB(HMENU hmenuShared,
LPOLEMENUGROUPWIDTHS lpMenuWidths)
{
if (hmenuShared)
{
// Note that we "copy" submenus.
Shell_MergeMenus(hmenuShared, m_hmenuTemplate,
0, 0, FCIDM_BROWSERLAST, 0);
// BUGBUG I don't see where these menuwidths ever get used!
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 CCatalogBrowser::SetMenuSB(HMENU hmenuShared,
HOLEMENU holemenuReserved,
HWND hwndActiveObject)
{
HMENU hMenuOld;
if (hmenuShared)
{
m_hmenuCurrent = hmenuShared;
}
else
{
m_hmenuCurrent = m_hmenuTemplate;
}
hMenuOld = GetMenu(m_hwndDlg);
if (hMenuOld)
{
DestroyMenu(hMenuOld);
}
SetMenu(m_hwndDlg, m_hmenuCurrent);
return NOERROR;
}
STDMETHODIMP CCatalogBrowser::RemoveMenusSB(HMENU hmenuShared)
{
// No need to remove them, because we "copied" them in InsertMenu.
return NOERROR;
}
STDMETHODIMP CCatalogBrowser::SetStatusTextSB(LPCOLESTR lpszStatusText)
{
dprintf(TEXT("Unimplemented CCatalogBrowser::SetStatusBarTextSB called\n"));
return E_NOTIMPL;
}
STDMETHODIMP CCatalogBrowser::EnableModelessSB(BOOL fEnable)
{
dprintf(TEXT("Unimplemented CCatalogBrowser::EnableModelessSB called\n"));
return E_NOTIMPL;
}
STDMETHODIMP CCatalogBrowser::TranslateAcceleratorSB(LPMSG lpmsg, WORD wID)
{
dprintf(TEXT("Unimplemented CCatalogBrowser::TranslateAcceleratorSB called\n"));
return E_NOTIMPL;
}
STDMETHODIMP CCatalogBrowser::BrowseObject(LPCITEMIDLIST pidl, UINT wFlags)
{
dprintf(TEXT("Unimplemented CCatalogBrowser::BrowseObject called\n"));
return E_NOTIMPL;
}
STDMETHODIMP CCatalogBrowser::GetViewStateStream(DWORD grfMode, LPSTREAM *ppStrm)
{
return E_NOTIMPL;
}
STDMETHODIMP CCatalogBrowser::GetControlWindow(UINT id, HWND * lphwnd)
{
return S_OK;
}
STDMETHODIMP CCatalogBrowser::SendControlMsg(UINT id,
UINT uMsg,
WPARAM wParam,
LPARAM lParam,
LRESULT * pret)
{
return S_OK;
}
STDMETHODIMP CCatalogBrowser::QueryActiveShellView(IShellView ** ppshv)
{
dprintf(TEXT("Unimplemented CCatalogBrowser::QueryActiveShellView called\n"));
return E_NOTIMPL;
}
STDMETHODIMP CCatalogBrowser::OnViewWindowActive(IShellView * ppshv)
{
// No need to process this. Our InsertMenus() does not depend on the focus.
return NOERROR;
}
STDMETHODIMP CCatalogBrowser::SetToolbarItems(LPTBBUTTON lpButtons,
UINT nButtons,
UINT uFlags)
{
// No Toolbar!
return NOERROR;
}
//
// Constructor/Destructor
//
CCatalogFolder::CCatalogFolder()
{
m_cRefs = 1;
}
CCatalogFolder::~CCatalogFolder()
{
}
//
// QueryInterface
//
STDMETHODIMP CCatalogFolder::QueryInterface(REFIID riid, LPVOID * ppvObj)
{
HRESULT hr;
if(IsEqualIID(riid, IID_IUnknown))
{
*ppvObj = this;
}
else if (IsEqualIID(riid, IID_IShellFolder))
{
*ppvObj = (IShellFolder*)this;
}
else
{
dprintf(TEXT("CCatalogFolder::QueryInterface for unsupported interface\n"));
*ppvObj = NULL;
hr = E_NOINTERFACE;
}
if (SUCCEEDED(hr))
{
AddRef();
hr = NOERROR;
}
return hr;
}
//
// AddRef
//
STDMETHODIMP_(ULONG) CCatalogFolder::AddRef()
{
InterlockedIncrement((LONG *) &m_cRefs);
return m_cRefs;
}
//
// Release
//
STDMETHODIMP_(ULONG) CCatalogFolder::Release()
{
ULONG tmp = m_cRefs;
if (0 == InterlockedDecrement((LONG *) &m_cRefs))
{
delete this;
return 0;
}
else
{
return tmp - 1;
}
}
//
// IShellFolder methods
//
STDMETHODIMP CCatalogFolder::ParseDisplayName(HWND hwnd,
LPBC pbcReserved,
LPOLESTR lpszDisplayName,
ULONG * pchEaten,
LPITEMIDLIST * ppidl,
ULONG *pdwAttributes)
{
dprintf(TEXT("Unimplemented CCatalogFolder::ParseDisplayName called\n"));
return E_NOTIMPL;
}
STDMETHODIMP CCatalogFolder::EnumObjects(HWND hwndOwner,
DWORD grfFlags,
LPENUMIDLIST * ppenumIDList)
{
HRESULT hr;
TCHAR szFolder[MAX_PATH];
CEnumOLEDB * pEnumOLEDB = new CEnumOLEDB;
if (NULL == pEnumOLEDB)
{
return E_OUTOFMEMORY;
}
hr = pEnumOLEDB->InitInstance();
if (FAILED(hr))
{
delete pEnumOLEDB;
return hr;
}
// BUGBUG TODO Set scope correctly
lstrcpy(szFolder, TEXT("e:\\mycat\\allfiles.sc"));
// lstrcpy(szFolder, TEXT("d:\\temp"));
hr = _SynchronousQuery(szFolder, grfFlags, pEnumOLEDB);
//
// If successful, set the out pointer. If anything failed along the way,
// release the enumerator
//
if (SUCCEEDED(hr))
{
*ppenumIDList = pEnumOLEDB;
// Lie to DefView_FillObjects, which will only call your enumerator
// if you return exactly S_OK (and no other success HRESULTs)
// (JonBe, 8/11/95)
hr = S_OK;
}
else
{
delete pEnumOLEDB;
}
return hr;
}
STDMETHODIMP CCatalogFolder::BindToObject(LPCITEMIDLIST pidl,
LPBC pbcReserved,
REFIID riid,
LPVOID * ppvOut)
{
dprintf(TEXT("Unimplemented CCatalogFolder::BindToObject called\n"));
return E_NOTIMPL;
}
STDMETHODIMP CCatalogFolder::BindToStorage(LPCITEMIDLIST pidl,
LPBC pbcReserved,
REFIID riid,
LPVOID * ppvObj)
{
dprintf(TEXT("Unimplemented CCatalogFolder::BindToStorage called\n"));
return E_NOTIMPL;
}
STDMETHODIMP CCatalogFolder::CompareIDs(LPARAM lParam,
LPCITEMIDLIST pidl1,
LPCITEMIDLIST pidl2)
{
// BUGBUG: Need defview v2 changes so CompareIDs isn't commonly called.
// DefView_FindItem calls CompareIDs with the stripped idl as pidl1
// and the full catalog pidl as pidl2. lParam is always 0 in this case.
CATALOG_ID* pid1 = (CATALOG_ID*)pidl1;
CATALOG_ID* pid2 = (CATALOG_ID*)pidl2;
if ((lParam == 0) &&
(pid2->bSignature == CATALOG_SIGNATURE_BYTE) &&
(pid1->bSignature != CATALOG_SIGNATURE_BYTE))
{
LPSHELLFOLDER psf;
HRESULT hr;
hr = _GetObjectsShellFolder(pidl2, &psf);
if (SUCCEEDED(hr))
{
return psf->CompareIDs(lParam, pidl1, _ILNext(pidl2));
}
else
{
dprintf(TEXT("CCatalogFolder::CompareIDs (%lx)\n"), hr);
// Fall through to returning not-equal ('1')
}
}
return 1;
}
STDMETHODIMP CCatalogFolder::CreateViewObject(HWND hwnd,
REFIID riid,
LPVOID * ppvOut)
{
*ppvOut = NULL; // Clear it in case of error
if (IsEqualIID(riid, IID_IShellView))
{
CSFV csfv = {
SIZEOF(CSFV), // cbSize
(LPSHELLFOLDER)this, // pshf
NULL, // psvOuter
NULL, // pidl
0,
Catalog_FNVCallBack, // pfnCallback
(FOLDERVIEWMODE) 0,
};
return SHCreateShellFolderViewEx(&csfv, (LPSHELLVIEW *)ppvOut);
}
else if (IsEqualIID(riid, IID_IContextMenu))
{
// No, do background menu.
return CDefFolderMenu_Create((LPCITEMIDLIST)NULL,
hwnd,
0,
NULL,
(LPSHELLFOLDER)this,
Catalog_DFMCallBack,
NULL,
NULL,
(LPCONTEXTMENU FAR*)ppvOut);
}
dprintf(TEXT("CCatalogFolder::CreateViewObject - Unknown interface requested\n"));
return(ResultFromScode(E_NOINTERFACE));
}
STDMETHODIMP CCatalogFolder::GetAttributesOf(UINT cidl,
LPCITEMIDLIST * apidl,
ULONG * prgfInOut)
{
HRESULT hr;
UINT i;
IShellFolder* psfItem;
//
// 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...
if (cidl == 0)
{
// BUGBUG: What is this used for? What should be returned?
*prgfInOut = 0;
return NOERROR;
}
// We need to construct a new pidl array (with the catalog info stripped off)
// to hand off to the appropriate shell folder implementation
LPITEMIDLIST* apidlFS;
apidlFS = (LPITEMIDLIST*)SHAlloc(cidl * SIZEOF(LPITEMIDLIST));
if (NULL == apidlFS)
{
hr = E_OUTOFMEMORY;
goto Error;
}
for (i = 0; i < cidl; i++)
{
apidlFS[i] = ILClone(_ILNext(apidl[i]));
if (NULL == apidlFS[i])
{
hr = E_OUTOFMEMORY;
goto Error;
}
}
// The IShellFolder of the first item handles them all.
// Don't know if this is right, but docfind does it that way...
hr = _GetObjectsShellFolder(*apidl, &psfItem);
if (FAILED(hr))
{
goto Error;
}
hr = psfItem->GetAttributesOf(cidl, (LPCITEMIDLIST*)apidlFS, prgfInOut);
if (FAILED(hr))
{
dprintf(TEXT("CCatalogFolder::GetAttributesOf (%lx)\n"), hr);
}
Cleanup:
// 'i' is equal to cidl (normal execution) or less (if there was
// an allocation failure). Count down now to free only those pidls
// that were cloned successfully.
for (; i != 0; i--)
{
ILFree(apidlFS[i - 1]);
}
if (apidlFS)
{
SHFree(apidlFS);
}
if (psfItem)
{
psfItem->Release();
}
return hr;
Error:
dprintf(TEXT("CCatalogViewer::GetAttributesOf (%lx)\n"), hr);
goto Cleanup;
}
STDMETHODIMP CCatalogFolder::GetUIObjectOf(HWND hwndOwner,
UINT cidl,
LPCITEMIDLIST * apidl,
REFIID riid,
UINT * prgfInOut,
LPVOID * ppvOut)
{
LPSHELLFOLDER psfItem;
HRESULT hres = E_INVALIDARG;
// If Count of items passed in is == 1 simply pass to the appropriate
// folder
if (cidl==1)
{
LPCITEMIDLIST pidl;
// Note we may have been passed in a complex item so find the last
// id.
pidl = ILFindLastID(*apidl);
{
hres = _GetObjectsShellFolder(*apidl, &psfItem);
if (SUCCEEDED(hres))
{
hres = psfItem->GetUIObjectOf(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 = _WrapIContextMenu(hwndOwner, psfItem,
pidl, ppvOut);
}
psfItem->Release();
}
else
{
dprintf(TEXT("CCatalogFolder::GetUIObjectOf (%lx)\n"), hres);
}
}
return(hres);
}
if (IsEqualIID(riid, IID_IContextMenu))
{
// Is there anything selected?
if (cidl == 0)
{
dprintf(TEXT("CCatalogFolder::GetUIObjectOf - someone asked for IContextMenu w/ cidl = 0!\n"));
hres = E_INVALIDARG;
}
else
{
// So we have at least two items in the list.
// Try to create a menu object that we process ourself
HKEY hkeyBaseProgID = NULL;
HKEY hkeyProgID = NULL;
// Get the hkeyProgID and hkeyBaseProgID from the first item.
SHGetClassKey((LPIDFOLDER)apidl[0], &hkeyProgID, FALSE);
SHGetBaseClassKey((LPIDFOLDER)apidl[0], &hkeyBaseProgID);
// BUGBUG Investigate: As far as I can see, the apidl is only used
// to ask this same folder for an IDataObject to pass to the DFMCallBack.
// If this is correct, then I don't need to strip off the catalog info
// and create a new (FS idl) idl array here -- I can wait and do that
// in the IDataObject case only.
hres = CDefFolderMenu_Create(NULL, hwndOwner,
cidl, apidl, this, Catalog_DFMCallBack,
hkeyProgID, hkeyBaseProgID,
(LPCONTEXTMENU*)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 = _GetParentsPIDL(apidl[i]);
// Need to check failure cases here!
DPA_InsertPtr(hdpa, i, ILCombine(pidlParent, _ILNext(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, Catalog_SortForFileOp, 0);
hres = CIDLData_CreateFromIDArray2(&c_CFSIDLDataVtbl,
(LPCITEMIDLIST)&uNullPidl, cidl,
(LPCITEMIDLIST*)DPA_GetPtrPtr(hdpa),
(LPDATAOBJECT*)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 CCatalogFolder::GetDisplayNameOf(LPCITEMIDLIST pidl,
DWORD uFlags,
LPSTRRET lpName)
{
LPSHELLFOLDER psfItem;
HRESULT hr;
hr = _GetObjectsShellFolder(pidl, &psfItem);
if (SUCCEEDED(hr))
{
STRRET strret;
LPITEMIDLIST pidlLast = ILFindLastID(pidl);
hr = psfItem->GetDisplayNameOf(pidlLast, uFlags, &strret);
if (SUCCEEDED(hr))
{
if ((strret.uType == STRRET_OFFSETA) || (strret.uType == STRRET_OFFSETW))
{
StrRetToStrN(lpName->cStrW, MAX_PATH, &strret, pidlLast);
lpName->uType = STRRET_CSTR;
}
else
{
*lpName = strret;
}
}
else
{
dprintf(TEXT("CCatalogFolder::GetDisplayNameOf - delegated method (%lx)\n"), hr);
}
psfItem->Release();
}
else
{
dprintf(TEXT("CCatalogFolder::GetDisplayNameOf - (%lx)\n"), hr);
}
return hr;
}
STDMETHODIMP CCatalogFolder::SetNameOf(HWND hwnd,
LPCITEMIDLIST pidl,
LPCOLESTR lpszName,
DWORD uFlags,
LPITEMIDLIST * ppidlOut)
{
dprintf(TEXT("Unimplemented CCatalogFolder::SetNameOf called\n"));
return E_NOTIMPL;
}
HRESULT CCatalogFolder::_InstantiateIQuery(LPCWSTR pszFolder,
LPVOID* ppQueryOut)
{
HRESULT hr;
IMoniker* pmk;
hr = CreateFileMoniker(pszFolder, &pmk);
if (SUCCEEDED(hr))
{
IBindCtx* pbc;
hr = CreateBindCtx(0, &pbc);
if (SUCCEEDED(hr))
{
BIND_OPTS opts;
opts.cbStruct = SIZEOF(opts);
hr = pbc->GetBindOptions(&opts);
if (SUCCEEDED(hr))
{
opts.grfMode = STGM_READ | STGM_SHARE_DENY_NONE;
hr = pbc->SetBindOptions(&opts);
if (SUCCEEDED(hr))
{
IConfigSummaryCatalog* pcsc;
hr = pmk->BindToObject(pbc, NULL, IID_IConfigSummaryCatalog, (void**)&pcsc);
if (SUCCEEDED(hr))
{
hr = pcsc->QueryInterface(IID_IOldQuery, ppQueryOut);
if (FAILED(hr))
{
dprintf(TEXT("CCatalogFolder::_InstantiateIQuery -- QueryInterface (%lx)\n"), hr);
}
pcsc->Release();
}
else
{
dprintf(TEXT("CCatalogFolder::_InstantiateIQuery -- BindToObject (%lx)\n"), hr);
}
}
else
{
dprintf(TEXT("CCatalogFolder::_InstantiateIQuery -- SetBindOptions (%lx)\n"), hr);
}
}
else
{
dprintf(TEXT("CCatalogFolder::_InstantiateIQuery -- GetBindOptions (%lx)\n"), hr);
}
pbc->Release();
}
else
{
dprintf(TEXT("CCatalogFolder::_InstantiateIQuery -- CreateBindCtx (%lx)\n"), hr);
}
pmk->Release();
}
else
{
dprintf(TEXT("CCatalogFolder::_InstantiateIQuery -- CreateFileMoniker (%lx)\n"), hr);
}
return hr;
}
HRESULT CCatalogFolder::_SynchronousQuery(LPCWSTR pszFolder,
DWORD grfFlags,
CEnumOLEDB* pEnumOLEDB)
{
HRESULT hr = NOERROR;
CPropertyRestriction * prst = NULL;
IOldQuery * pQuery = NULL;
IRowset * pRowset = NULL;
IAccessor * pIAccessor = NULL;
IColumnsInfo * pIColumnsInfo = NULL;
HACCESSOR hAccessor = NULL;
ULONG cHiddenFiles = 0; // Count of hidden files. Used to update
// folder's count at end of enumeration
DWORD dwSize = 0; // Total size of files enumerated. Used to
// update folder's size at end of enumeration
TRY
{
const DBID dbcolLastWriteTime = {PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR)PID_STG_WRITETIME};
const DBID dbcolSize = {PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR)PID_STG_SIZE};
const DBID dbcolAttributes = {PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR)PID_STG_ATTRIBUTES};
const DBID dbcolName = {PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR)PID_STG_NAME};
const DBID dbcolShortName = {PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR)PID_STG_SHORTNAME};
const DBID dbcolPath = {PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR)PID_STG_PATH};
CFullPropSpec psWriteTime (guidSystem2, PID_STG_WRITETIME);
CFullPropSpec psSize (guidSystem2, PID_STG_SIZE);
CFullPropSpec psAttributes(guidSystem2, PID_STG_ATTRIBUTES);
CFullPropSpec psName (guidSystem2, PID_STG_NAME);
CFullPropSpec psShortName (guidSystem2, PID_STG_SHORTNAME);
CFullPropSpec psPath (guidSystem2, PID_STG_PATH);
CRestriction *prstQuery = 0;
#ifndef USE_SC_IQUERY
pQuery = EvalQuery4(pszFolder, 0);
if (NULL == pQuery)
{
hr = E_FAIL;
dprintf(TEXT("CCatalogFolder::_SynchronousQuery - EvalQuery4 failed\n"));
LEAVE;
}
#else
// BUGBUG Choose real location for CoInit/CoUninit carefully
CoInitialize(NULL);
hr = _InstantiateIQuery(pszFolder, (void**)&pQuery);
CoUninitialize();
if (FAILED(hr))
{
LEAVE;
}
#endif
//
// Columns returned by the query
//
CColumns cols(cCatalogOutColumns);
VERIFY( cols.Add(psWriteTime, 0) );
VERIFY( cols.Add(psSize, 1) );
VERIFY( cols.Add(psAttributes, 2) );
VERIFY( cols.Add(psName, 3) );
VERIFY( cols.Add(psShortName, 4) );
VERIFY( cols.Add(psPath, 5) );
//
// Make a restriction
//
prst = new CPropertyRestriction();
if (NULL == prst)
{
hr = E_OUTOFMEMORY;
LEAVE;
}
prstQuery = prst;
prst->SetRelation( PRRE );
prst->SetProperty( psName );
prst->SetValue ( L"*" );
hr = pQuery->ExecuteQuery(QUERY_DEEP, // Depth
prstQuery->CastToStruct(), // Restriction
cols.CastToStruct(), // Output
0, // Sort
eSequentialCursor, // Flags
IID_IRowset, // IID for i/f to return
(IUnknown **)&pRowset ); // Return interface
LEAVE_IF( FAILED(hr) );
// map the column ids from guid form to column numbers needed to
// create the accessor
DBID aDbCols[cCatalogOutColumns];
aDbCols[0] = dbcolLastWriteTime;
aDbCols[1] = dbcolSize;
aDbCols[2] = dbcolAttributes;
aDbCols[3] = dbcolName;
aDbCols[4] = dbcolShortName;
aDbCols[5] = dbcolPath;
hr = pRowset->QueryInterface(IID_IColumnsInfo, (void**)&pIColumnsInfo);
LEAVE_IF( FAILED(hr) );
hr = pRowset->QueryInterface(IID_IAccessor, (void**)&pIAccessor);
LEAVE_IF( FAILED(hr) );
LONG aColIds[cCatalogOutColumns];
hr = pIColumnsInfo->MapColumnIDs(cCatalogOutColumns,aDbCols,aColIds);
LEAVE_IF( FAILED(hr) );
for (ULONG c = 0; c < cCatalogOutColumns; c++)
{
aCatalogOutColumns[c].iColumn = aColIds[c];
}
hr = pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA,
cCatalogOutColumns,
aCatalogOutColumns,
0,
0,
&hAccessor);
LEAVE_IF( FAILED(hr) );
// Now go through the whole rowset and put those items that match our
// criteria (as determined by grfFlags) in the enumerator ptr array
ULONG cFetched = 0;
while ((0 != cFetched) ||
(DB_S_ENDOFROWSET != hr))
{
ULONG cThisTime = MAX_FETCHED_AT_ONCE;
HROW aHRows[MAX_FETCHED_AT_ONCE],*pHRows = aHRows;
hr = pRowset->GetNextRows(DB_INVALID_HCHAPTER, // no chapter
0, // no offset
cThisTime, // # requested
&cFetched, // # fetched
&pHRows); // put them here
if (0 != cFetched)
{
for (ULONG x = 0; x < cFetched; x++)
{
SRowBuf Row;
if (FAILED(hr = pRowset->GetData(aHRows[x],hAccessor,&Row)))
{
ASSERT( 0 && "pRowset->GetData failed" );
continue;
}
BOOL fFound = FALSE;
WIN32_FIND_DATA finddata;
//
// Fill out the WIN32_FIND_DATA structure from the data we got back in the row buffer
//
ZeroMemory(&finddata, sizeof(finddata));
finddata.dwFileAttributes = Row.dwFileAttributes;
// Note that ftLastAccess and ftCreate are not used by fstreex.c
finddata.ftLastWriteTime.dwLowDateTime = Row.ftLastWriteTime.dwLowDateTime;
finddata.ftLastWriteTime.dwHighDateTime = Row.ftLastWriteTime.dwHighDateTime;
finddata.nFileSizeHigh = (ULONG) (Row.llFileSize >> 32);
finddata.nFileSizeLow = (ULONG) (Row.llFileSize & 0xFFFFFFFF);
finddata.dwReserved0 = 0;
finddata.dwReserved1 = 0;
lstrcpynW(finddata.cFileName, Row.awchName, MAX_PATH);
lstrcpynW(finddata.cAlternateFileName, Row.awchShortName, ARRAYSIZE(Row.awchShortName));
//
// BUGBUG Overflow problems here
//
dwSize += finddata.nFileSizeLow;
//
// Object is a folder, but we aren't looking for folders, so skip it
//
if (finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
if (0 == (grfFlags & SHCONTF_FOLDERS))
{
cHiddenFiles++;
continue;
}
}
else
{
//
// Object is a non-folder, but we are not enumerating for
// non-folders
//
if (0 == (grfFlags & SHCONTF_NONFOLDERS))
{
cHiddenFiles++;
continue;
}
}
if (0 == (grfFlags & SHCONTF_INCLUDEHIDDEN))
{
//
// If object is hidden, but we aren't looking for hidden
// objects, skip it
//
if (finddata.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
{
cHiddenFiles++;
continue;
}
//
// If we are looking in the recent docs dir, but we can't
// find this item in the recent docs MRU, skip it
//
if (grfFlags & SHCONTF_RECENTDOCSDIR)
{
if (FALSE == FindLinkInRecentDocsMRU(finddata.cFileName))
{
cHiddenFiles++;
continue;
}
}
//
// If this is a non-folder object, and is one of the types
// (based on its extension) that we are hiding, skip it
//
if (0 == (finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
&& _SHFindExcludeExt(finddata.cFileName) >= 0)
{
cHiddenFiles++;
continue;
}
}
//
// Object matches all of our criteria for one that should be
// displayed in this view, so we can stop looking
//
fFound = TRUE;
//
// We are done looking. If we found an object to be displayed, create
// an IDList and hand it back. Otherwise, we have looked at all of
// the objects in this folder, and we are done. We take that
// opportunity to update the hidden count and size summation in the
// folder itself.
//
if (fFound)
{
// Prepend my own itemid to the fs idl. For now, my itemid
// contains the path to the containing folder of the object
LPITEMIDLIST pidl;
PathRemoveFileSpec(Row.awchPath);
// CATALOG_ITEM_HEADER_SIZE include one WCHAR
// already, so I don't add one for the NULL at the
// end of the path.
UINT cb2 = CATALOG_ITEM_HEADER_SIZE + lstrlen(Row.awchPath) * SIZEOF(TCHAR);
cb2 += SIZEOF(USHORT); // For NULL itemid at end
CATALOG_ID* pid = (CATALOG_ID*)(_ILCreate(cb2));
pid->cb = cb2 - SIZEOF(USHORT); // For NULL itemid at end
pid->bSignature = CATALOG_SIGNATURE_BYTE;
// BUGBUG make unaligned?
lstrcpy((LPWSTR)(pid->awchPath), Row.awchPath);
LPIDFOLDER pidf = CFSFolder_FillIDFolder(&finddata,
NULL, // pszParentFolder
0L);
if (pidf)
{
LPITEMIDLIST pidlComposite = ILAppendID((LPITEMIDLIST)pid, (LPSHITEMID)pidf, TRUE);
if (NULL == pidlComposite)
{
dprintf(TEXT("CCatalogFolder::_SynchronousQuery -- ILAppendID failed\n"));
ILFree((LPITEMIDLIST)pid);
hr = E_OUTOFMEMORY;
LEAVE;
}
ILFree((LPITEMIDLIST)pidf);
hr = pEnumOLEDB->AddElement(pidlComposite);
if (FAILED(hr))
{
dprintf(TEXT("CCatalogFolder::_SynchronousQuery -- pEnumOLEDB->AddElement (%lx)\n"), hr);
VERIFY(SUCCEEDED( pRowset->ReleaseRows(cFetched, aHRows, 0, 0) ));
LEAVE;
}
}
else
{
dprintf(TEXT("CCatalogFolder::_SynchronousQuery -- CFSFolder_FillIDFolder failed\n"));
VERIFY(SUCCEEDED( pRowset->ReleaseRows(cFetched, aHRows, 0, 0) ));
LEAVE;
}
}
}
VERIFY(SUCCEEDED( pRowset->ReleaseRows(cFetched, aHRows, 0, 0) ));
}
}
}
FINALLY
{
//
// Normal cleanup
//
if (pIColumnsInfo)
{
pIColumnsInfo->Release();
}
if (pIAccessor)
{
if (hAccessor)
{
VERIFY(SUCCEEDED( pIAccessor->ReleaseAccessor(hAccessor) ));
}
pIAccessor->Release();
}
if (pRowset)
{
pRowset->Release();
}
if (grfFlags & SHCONTF_RECENTDOCSDIR)
{
CloseRecentDocMRU();
}
if (pQuery)
{
pQuery->Release();
}
delete prst;
//
// Only update folders hidden count and size if the enum was successful
//
if (FAILED(hr))
{
dprintf(TEXT("OLEDBSHL: Abnormal Exit from CCatalogFolder::_SynchronousQuery, hr = %lx\n"), hr);
}
return hr;
}
}
HRESULT CALLBACK Catalog_DFMCallBack(LPSHELLFOLDER psf, HWND hwndOwner,
LPDATAOBJECT pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
HRESULT hres = NOERROR;
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
{
#ifdef ORGCODE
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);
#else
UINT id = POPUP_DOCFIND_POPUPMERGE; //BUGBUG Change
CDefFolderMenu_MergeMenu(HINST_THISDLL, 0, id, pqcm);
DeleteMenu(pqcm->hmenu, SFVIDM_EDIT_CUT, MF_BYCOMMAND);
DeleteMenu(pqcm->hmenu, SFVIDM_EDIT_PASTE, MF_BYCOMMAND);
DeleteMenu(pqcm->hmenu, SFVIDM_EDIT_PASTELINK, MF_BYCOMMAND);
DeleteMenu(pqcm->hmenu, SFVIDM_FILE_RENAME, MF_BYCOMMAND);
DeleteMenu(pqcm->hmenu, SFVIDM_FILE_DELETE, MF_BYCOMMAND);
#endif
}
}
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:
#ifdef ORGCODE
hres = CFSFolder_DeleteItems((LPFSFOLDER)psf, hwndOwner,
pdtobj, SD_USERCONFIRMATION);
#else
dprintf(TEXT("Catalog_DFMCallBack: DFM_CMD_DELETE invoked. Shouldn't be able to!\n"));
#endif
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:
#ifdef ORGCODE
ShellFolderView_ReArrange(hwndOwner, DFSortIDToICol(wParam));
#else
dprintf(TEXT("Catalog_DFMCallBack - need to implement sort IDs!\n"));
#endif
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;
}
//
// Callback from SHCreateShellFolderViewEx
//
HRESULT CALLBACK Catalog_FNVCallBack(LPSHELLVIEW psvOuter,
LPSHELLFOLDER psf,
HWND hwndOwner,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
HRESULT hres = NOERROR; // assume no error
HMENU hmenu;
UINT id;
switch(uMsg)
{
case DVM_MERGEMENU:
{
int i;
#ifdef ORGCODE
this->pdfff->lpVtbl->GetFolderMergeMenuIndex(this->pdfff, &id);
#else
id = POPUP_DOCFIND_POPUPMERGE; //BUGBUG Change
#endif
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_CUT, MF_BYCOMMAND);
DeleteMenu(hmenu, SFVIDM_EDIT_PASTE, MF_BYCOMMAND);
DeleteMenu(hmenu, SFVIDM_EDIT_PASTELINK, MF_BYCOMMAND);
DeleteMenu(hmenu, SFVIDM_FILE_DELETE, MF_BYCOMMAND);
DeleteMenu(hmenu, SFVIDM_FILE_RENAME, 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;
if ((hmenuSub = GetSubMenu(hmenu, i)) &&
(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)
{
CATALOG_ID* pid = (CATALOG_ID*)(ppidls[0]);
Assert(pid->bSignature == CATALOG_SIGNATURE_BYTE);
ualstrcpy((LPTSTR)lParam, pid->awchPath);
}
else
{
return E_FAIL;
}
break;
}
case DVM_INITMENUPOPUP:
hmenu = (HMENU)lParam;
id = GetMenuItemID(hmenu, 0);
break;
case DVM_INVOKECOMMAND:
switch(wParam)
{
case FSIDM_SORTBYLOCATION:
case FSIDM_SORTBYNAME:
case FSIDM_SORTBYSIZE:
case FSIDM_SORTBYTYPE:
case FSIDM_SORTBYDATE:
#ifdef ORGCODE
ShellFolderView_ReArrange(hwndOwner, DFSortIDToICol(wParam));
#else
dprintf(TEXT("Catalog_FNVCallBack - need to implement sort IDs!\n"));
#endif
break;
}
break;
case DVM_GETDETAILSOF:
#define pdi ((DETAILSINFO *)lParam)
return(Catalog_GetDetailsOf(pdi->pidl, wParam, (LPSHELLDETAILS)&pdi->fmt));
#undef pdi
break;
case DVM_GETHELPTEXT:
case DVM_SELCHANGE:
case DVM_REFRESH:
case DVM_KILLFOCUS:
case DVM_SETFOCUS:
case DVM_RELEASE:
break;
default:
hres = E_FAIL;
}
return hres;
}
const UINT s_auMapCatalogColToFSCol[] =
{0, (UINT)-1, 1, 2, 3, 4, 5, 6}; // More items than are needed but...
#pragma data_seg(DATASEG_READONLY)
const COL_DATA s_catalog_cols[] = {
{ICATALOGCOL_NAME, IDS_NAME_COL, 20, LVCFMT_LEFT},
{ICATALOGCOL_PATH, IDS_PATH_COL, 20, LVCFMT_LEFT},
{ICATALOGCOL_SIZE, IDS_SIZE_COL, 9, LVCFMT_RIGHT},
{ICATALOGCOL_TYPE, IDS_TYPE_COL, 20, LVCFMT_LEFT},
{ICATALOGCOL_MODIFIED, IDS_MODIFIED_COL, 25, LVCFMT_LEFT},
};
HRESULT Catalog_GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn,
LPSHELLDETAILS lpDetails)
{
if (iColumn >= ICATALOGCOL_MAX)
{
return E_NOTIMPL;
}
lpDetails->str.uType = STRRET_CSTR;
lpDetails->str.STRRET_Char[0] = TEXT('\0');
if (!pidl)
{
LoadString(HINST_THISDLL, s_catalog_cols[iColumn].ids,
lpDetails->str.STRRET_Char, ARRAYSIZE(lpDetails->str.STRRET_Char));
lpDetails->fmt = s_catalog_cols[iColumn].iFmt;
lpDetails->cxChar = s_catalog_cols[iColumn].cchCol;
return NOERROR;
}
CATALOG_ID* pid = (CATALOG_ID*)pidl;
Assert(pid->bSignature == CATALOG_SIGNATURE_BYTE);
if (iColumn == ICATALOGCOL_PATH)
{
lstrcpy(lpDetails->str.STRRET_Char, pid->awchPath);
return NOERROR;
}
else
{
// Let the file system function do it for us...
return FS_GetDetailsOf(_ILNext(pidl), s_auMapCatalogColToFSCol[iColumn], lpDetails);
}
}
HRESULT CCatalogFolder::_GetObjectsShellFolder(LPCITEMIDLIST pidl, LPSHELLFOLDER* ppsf)
{
HRESULT hr;
IShellFolder* psfDesktop;
LPITEMIDLIST pidlExtra;
// This function has no way to return failure!
psfDesktop = Desktop_GetShellFolder(TRUE);
// Create a folder ID out of the path in the Catalog ID.
CATALOG_ID* pid = (CATALOG_ID*)pidl;
pidlExtra = SHSimpleIDListFromPath(pid->awchPath);
if (NULL != pidlExtra)
{
// Bind to only the path part, since you can't get IShellFolder on non-containers
hr = psfDesktop->BindToObject(pidlExtra, NULL, IID_IShellFolder, (LPVOID*)ppsf);
if (FAILED(hr))
{
dprintf(TEXT("CCatalogFolder::_GetObjectsShellFolder - BindToObject failed (%lx)\n"), hr);
}
ILFree(pidlExtra);
}
else
{
dprintf(TEXT("CCatalogFolder::_GetObjectsShellFolder - SHSimpleIDListFromPath failed\n"));
hr = E_OUTOFMEMORY;
}
return hr;
}
LPITEMIDLIST _GetParentsPIDL(LPCITEMIDLIST pidl)
{
CATALOG_ID* pid = (CATALOG_ID*)pidl;
Assert(pid->bSignature == CATALOG_SIGNATURE_BYTE);
return SHSimpleIDListFromPath(pid->awchPath);
}
// 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 Catalog_SortForFileOp(LPVOID lp1, LPVOID lp2, LPARAM lparam)
{
LPITEMIDLIST pidl1 = (LPITEMIDLIST)lp1;
LPITEMIDLIST pidl2 = (LPITEMIDLIST)lp2;
if (ILIsParent(pidl1, pidl2, FALSE))
{
return -1;
}
else
{
return 0;
}
}
HRESULT CCatalogFolder::_WrapIContextMenu(HWND hwndOwner,
LPSHELLFOLDER psfItem,
LPCITEMIDLIST pidl,
LPVOID *ppvOut)
{
HRESULT hres;
CCatalogMenuWrap* pcm = new CCatalogMenuWrap;
if (NULL == pcm)
{
((IContextMenu*)*ppvOut)->Release();
*ppvOut = NULL;
return E_OUTOFMEMORY;
}
pcm->m_hwndOwner = hwndOwner;
if (FAILED(hres = psfItem->GetUIObjectOf(hwndOwner,
1, &pidl, IID_IDataObject, NULL, (LPVOID*)&pcm->m_pdtobj)))
{
dprintf(TEXT("CCatalogFolder::_WrapIContextMenu() - GetUIObjectOf failed (%lx)\n"), hres);
delete pcm;
((IContextMenu*)*ppvOut)->Release();
*ppvOut = NULL;
return(hres);
}
pcm->m_pcmItem = (IContextMenu*)*ppvOut;
*ppvOut = pcm;
return NOERROR;
}
CCatalogMenuWrap::CCatalogMenuWrap()
{
m_cRefs = 1;
m_hwndOwner = NULL;
m_pdtobj = NULL;
m_pcmItem = NULL;
m_pcm2Item = NULL;
}
CCatalogMenuWrap::~CCatalogMenuWrap()
{
Assert(m_pcmItem);
m_pcmItem->Release();
if (m_pcm2Item)
{
m_pcm2Item->Release();
}
if (m_pdtobj)
{
m_pdtobj->Release();
}
}
//
// AddRef
//
STDMETHODIMP_(ULONG) CCatalogMenuWrap::AddRef()
{
InterlockedIncrement((LONG *) &m_cRefs);
return m_cRefs;
}
//
// Release
//
STDMETHODIMP_(ULONG) CCatalogMenuWrap::Release()
{
ULONG tmp = m_cRefs;
if (0 == InterlockedDecrement((LONG *) &m_cRefs))
{
delete this;
return 0;
}
else
{
return tmp - 1;
}
}
STDMETHODIMP CCatalogMenuWrap::QueryInterface(REFIID riid, LPVOID* ppvObj)
{
if (IsEqualIID(riid, IID_IContextMenu2))
{
// Make sure that one we are wrapping supports this!
if (m_pcm2Item == NULL)
{
HRESULT hres = m_pcmItem->QueryInterface(riid, (LPVOID*)&m_pcm2Item);
if (FAILED(hres))
{
dprintf(TEXT("CCatalogMenuWrap::QueryInterface - Wrapped context menu does not support IContextMenu2\n"));
*ppvObj = NULL;
return(hres);
}
}
*ppvObj = (IContextMenu2*)this;
m_cRefs++;
return NOERROR;
}
if (IsEqualIID(riid, IID_IContextMenu))
{
*ppvObj = (IUnknown*)this;
m_cRefs++;
return NOERROR;
}
else if (IsEqualIID(riid, IID_IUnknown))
{
*ppvObj = (IContextMenu*)this;
m_cRefs++;
return NOERROR;
}
dprintf(TEXT("CCatalogMenuWrap::QueryInterface - QI for unknown interface\n"));
*ppvObj = NULL;
return E_NOINTERFACE;
}
STDMETHODIMP CCatalogMenuWrap::QueryContextMenu(HMENU hmenu, UINT indexMenu,
UINT idCmdFirst,UINT idCmdLast,UINT uFlags)
{
// simply foward this to the one we are wrapping...
return(m_pcmItem->QueryContextMenu(hmenu,
indexMenu, idCmdFirst, idCmdLast, uFlags));
}
STDMETHODIMP CCatalogMenuWrap::InvokeCommand(LPCMINVOKECOMMANDINFO lpici)
{
// This is sort of 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(lpici->lpVerb) == SHARED_FILE_LINK) &&
(m_pdtobj != NULL))
{
return SHCreateLinks(lpici->hwnd, NULL, m_pdtobj,
SHCL_USETEMPLATE | SHCL_USEDESKTOP | SHCL_CONFIRM, NULL);
}
return(m_pcmItem->InvokeCommand(lpici));
}
STDMETHODIMP CCatalogMenuWrap::GetCommandString(UINT idCmd, UINT wFlags, UINT * pmf,
LPSTR pszName, UINT cchMax)
{
return(m_pcmItem->GetCommandString(idCmd, wFlags, pmf, pszName, cchMax));
}
STDMETHODIMP CCatalogMenuWrap::HandleMenuMsg(UINT uMsg, WPARAM wParam,
LPARAM lParam)
{
return(m_pcm2Item->HandleMenuMsg(uMsg, wParam, lParam));
}