|
|
#include "pch.h"
#include "stddef.h"
#pragma hdrstop
// class that implements the query UI
class CDsQuery : public IQueryHandler, IQueryForm, IObjectWithSite, IDsQueryHandler, IShellFolder { public: CDsQuery(); ~CDsQuery();
// IUnknown
STDMETHOD(QueryInterface)(REFIID riid, void **ppvObject); STDMETHOD_(ULONG, AddRef)(); STDMETHOD_(ULONG, Release)();
// IQueryForms
STDMETHOD(Initialize)(HKEY hkForm); STDMETHOD(AddForms)(LPCQADDFORMSPROC pAddFormsProc, LPARAM lParam); STDMETHOD(AddPages)(LPCQADDPAGESPROC pAddPagesProc, LPARAM lParam);
// IQueryHandler
STDMETHOD(Initialize)(IQueryFrame* pQueryFrame, DWORD dwOQWFlags, LPVOID pParameters); STDMETHOD(GetViewInfo)(LPCQVIEWINFO pViewInfo); STDMETHOD(AddScopes)(); STDMETHOD(BrowseForScope)(HWND hwndParent, LPCQSCOPE pCurrentScope, LPCQSCOPE* ppScope); STDMETHOD(CreateResultView)(HWND hwndParent, HWND* phWndView); STDMETHOD(ActivateView)(UINT uState, WPARAM wParam, LPARAM lParam); STDMETHOD(InvokeCommand)(HWND hwndParent, UINT uID); STDMETHOD(GetCommandString)(UINT uID, DWORD dwFlags, LPTSTR pBuffer, INT cchBuffer); STDMETHOD(IssueQuery)(LPCQPARAMS pQueryParams); STDMETHOD(StopQuery)(); STDMETHOD(GetViewObject)(UINT uScope, REFIID riid, void **ppvOut); STDMETHOD(LoadQuery)(IPersistQuery* pPersistQuery); STDMETHOD(SaveQuery)(IPersistQuery* pPersistQuery, LPCQSCOPE pScope);
// IObjectWithSite
STDMETHODIMP SetSite(IUnknown* punk); STDMETHODIMP GetSite(REFIID riid, void **ppv);
// IDsQueryHandler
STDMETHOD(UpdateView)(DWORD dwType, LPDSOBJECTNAMES pdon);
// IShellFolder
STDMETHOD(ParseDisplayName)(HWND hwnd, LPBC pbc, LPOLESTR pszName, ULONG * pchEaten, LPITEMIDLIST * ppidl, ULONG *pdwAttributes) { return E_NOTIMPL; } STDMETHOD(EnumObjects)(HWND hwndOwner, DWORD grfFlags, LPENUMIDLIST * ppEnumIDList) { return E_NOTIMPL; } STDMETHOD(BindToObject)(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, void **ppv) { return E_NOTIMPL; } STDMETHOD(BindToStorage)(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, void **ppv) { return E_NOTIMPL; } STDMETHOD(CompareIDs)(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2) { return E_NOTIMPL; } STDMETHOD(CreateViewObject)(HWND hwndOwner, REFIID riid, void **ppv) { return E_NOTIMPL; } STDMETHOD(GetAttributesOf)(UINT cidl, LPCITEMIDLIST * apidl, ULONG * rgfInOut) { *rgfInOut &= SFGAO_HASPROPSHEET; return S_OK; } STDMETHOD(GetUIObjectOf)(HWND hwndOwner, UINT cidl, LPCITEMIDLIST * apidl, REFIID riid, UINT * prgfInOut, void **ppv) { return GetViewObject(0x0, riid, ppv); } STDMETHOD(GetDisplayNameOf)(LPCITEMIDLIST pidl, DWORD uFlags, LPSTRRET pName) { return E_NOTIMPL; } STDMETHOD(SetNameOf)(HWND hwndOwner, LPCITEMIDLIST pidl, LPCOLESTR pszName, DWORD uFlags, LPITEMIDLIST* ppidlOut) { return E_NOTIMPL; } private: LRESULT OnSize(INT cx, INT cy); LRESULT OnNotify(HWND hWnd, WPARAM wParam, LPARAM lParam); HRESULT OnAddResults(DWORD dwQueryReference, HDPA hdpaResults); LRESULT OnContextMenu(HWND hwndMenu, LPARAM lParam); HRESULT OnFileProperties(VOID); HRESULT OnFileSaveQuery(VOID); HRESULT OnEditSelectAll(VOID); HRESULT OnEditInvertSelection(VOID); HRESULT OnPickColumns(HWND hwndParent);
static int s_BrowseForScopeCB(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData); static LRESULT s_ResultViewWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); static LRESULT s_BannerWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
HRESULT _SetDataObjectData(IDataObject* pDataObject, UINT cf, LPVOID pData, DWORD cbSize); HRESULT _SetDispSpecOptions(IDataObject *pdo); HRESULT _InitNewQuery(LPDSQUERYPARAMS pDsQueryParams, BOOL fRefreshColumnTable); HRESULT _GetFilterValue(INT iColumn, HD_ITEM* pitem); HRESULT _FilterView(BOOL fCheck); HRESULT _PopulateView(INT iFirstItem, INT iLast); VOID _FreeResults(VOID); DWORD _SetViewMode(INT uID); VOID _SortResults(INT iColumn); VOID _SetFilter(BOOL fFilter); VOID _ShowBanner(UINT flags, UINT idPrompt); VOID _InitViewMenuItems(HMENU hMenu); HRESULT _GetQueryFormKey(REFCLSID clsidForm, HKEY* phKey); HRESULT _GetColumnTable(REFCLSID clsidForm, LPDSQUERYPARAMS pDsQueryParams, HDSA* pHDSA, BOOL fSetInView); VOID _SaveColumnTable(VOID); HRESULT _SaveColumnTable(REFCLSID clsidForm, HDSA hdsaColumns); HRESULT _AddResultToDataObject(HDSA hdsa, INT i); HRESULT _GetDataObjectFromSelection(BOOL fGetAll, IDataObject **pdo); HRESULT _GetContextMenu(); VOID _GetContextMenuVerbs(HMENU hMenu, DWORD dwFlags); HRESULT _CopyCredentials(LPWSTR *ppszUserName, LPWSTR *ppszPassword, LPWSTR *ppszServer); VOID _DeleteViewItems(LPDSOBJECTNAMES pdon);
private: LONG _cRef; // lifetime
IQueryFrame* _pqf; // our parent window
IUnknown* _punkSite; // site object
IContextMenu* _pcm; // Curerntly displayed context menu / == NULL if none
DWORD _dwOQWFlags; // flags passed to OpenQueryWindow
DWORD _dwFlags; // flags as part of the ds query parameters
LPWSTR _pDefaultScope; // default scope passed
LPWSTR _pDefaultSaveLocation; // directory to save queries into by default
LPTSTR _pDefaultSaveName; // default save name (from the query form)
LPWSTR _pServer; // server to target
LPWSTR _pUserName; // user name and password to authenticate with
LPWSTR _pPassword;
BOOL _fNoSelection:1; // the IContextMenu was from no selection
BOOL _fColumnsModified:1; // settings of the view modified
BOOL _fSortDescending:1; // sort the results descending
BOOL _fFilter:1; // filter enabled
BOOL _fFilterSupported:1; // is the filter available, eg: comctl32 > 5.0
INT _idViewMode; // default view mode
INT _iSortColumn; // sort column
HWND _hwnd; // container window
HWND _hwndView; // listview window (child of parent)
HWND _hwndBanner; // banner window which is a child of the list view
DWORD _dwQueryReference; // reference value passed to query
HANDLE _hThread; // worker thread handle
DWORD _dwThreadId; // thread ID for the Query processing thread
CLSID _clsidForm; // form being used for column table
HDSA _hdsaColumns; // column information (size, filters, etc)
HDPA _hdpaResults; // results for tr the query we have issued
LPTSTR _pFilter; // current filter
HMENU _hFrameMenuBar; // stored frame menu bar, stored from activate
HMENU _hFileMenu; // added to the frames view menu
HMENU _hEditMenu; // inserted into the menu bar
HMENU _hViewMenu; // inserted into the menu bar
HMENU _hHelpMenu; // inserted into the menu bar
};
//
// Window classes we create to show the results
//
#define VIEW_CLASS TEXT("ActiveDsQueryView")
#define BANNER_CLASS TEXT("ActiveDsQueryBanner")
//
// Registry values used for the settings
//
#define VIEW_SETTINGS_VALUE TEXT("ViewSettings")
#define ADMIN_VIEW_SETTINGS_VALUE TEXT("AdminViewSettings");
//
// When filtering we populate the view using PostMessage, doing so many items
// at a time
//
#define FILTER_UPDATE_COUNT 128
//
// All items within the list view contain the following LPARAM structure used
// for storing the magic properties we are interested in.
//
#define ENABLE_MENU_ITEM(hMenu, id, fEnabled) \
EnableMenuItem(hMenu, id, (fEnabled) ? (MF_BYCOMMAND|MF_ENABLED):(MF_BYCOMMAND|MF_GRAYED))
//
// Persisted column data, this is stored in the registry under the CLSID for the
// form we are interested in.
//
typedef struct { DWORD cbSize; // offset to the next column / == 0 if none
DWORD dwFlags; // flags
DWORD offsetProperty; // offset to property name (UNICODE)
DWORD offsetHeading; // offset to column heading
INT cx; // pixel width of the column
INT fmt; // format of the column
} SAVEDCOLUMN, * LPSAVEDCOLUMN;
//
// Table to map property types to useful information
//
struct { LPCTSTR pMenuName; INT idOperator; INT hdft; } property_type_table[] = { 0, 0, 0, MAKEINTRESOURCE(IDR_OP_STRING), FILTER_CONTAINS, HDFT_ISSTRING, MAKEINTRESOURCE(IDR_OP_STRING), FILTER_CONTAINS, HDFT_ISSTRING, MAKEINTRESOURCE(IDR_OP_NUMBER), FILTER_IS, HDFT_ISNUMBER, MAKEINTRESOURCE(IDR_OP_NUMBER), FILTER_IS, HDFT_ISNUMBER, // PROPERTY_ISBOOL
};
//
// Help information for the frame and the control
//
static DWORD const aHelpIDs[] = { CQID_LOOKFORLABEL, IDH_FIND, CQID_LOOKFOR, IDH_FIND, CQID_LOOKINLABEL, IDH_IN, CQID_LOOKIN, IDH_IN, CQID_BROWSE, IDH_BROWSE, CQID_FINDNOW, IDH_FIND_NOW, CQID_STOP, IDH_STOP, CQID_CLEARALL, IDH_CLEAR_ALL, IDC_RESULTS, IDH_RESULTS, IDC_STATUS, IDH_NO_HELP, 0, 0, };
static DWORD const aBrowseHelpIDs[] = { DSBID_BANNER, (DWORD)-1, DSBID_CONTAINERLIST, IDH_BROWSE_CONTAINER, 0, 0, };
// Query object
CDsQuery::CDsQuery() : _cRef(1), _fNoSelection(TRUE), _iSortColumn(-1), _idViewMode(DSQH_VIEW_DETAILS) { if ( CheckDsPolicy(NULL, c_szEnableFilter) ) { TraceMsg("QuickFilter enabled in policy"); _fFilter = TRUE; } DllAddRef(); }
CDsQuery::~CDsQuery() { // persist the column information if we need to
if ( _hdsaColumns ) { if ( _fColumnsModified ) { _SaveColumnTable(_clsidForm, _hdsaColumns); _fColumnsModified = FALSE; }
_SaveColumnTable(); }
// discard all the other random state we have
LocalFreeStringW(&_pDefaultScope); LocalFreeStringW(&_pDefaultSaveLocation); LocalFreeString(&_pDefaultSaveName);
LocalFreeStringW(&_pUserName); LocalFreeStringW(&_pPassword); LocalFreeStringW(&_pServer);
if ( IsWindow(_hwnd) ) DestroyWindow(_hwnd);
if ( IsMenu(_hFileMenu) ) DestroyMenu(_hFileMenu); if ( IsMenu(_hEditMenu) ) DestroyMenu(_hEditMenu); if ( IsMenu(_hViewMenu) ) DestroyMenu(_hViewMenu); if ( IsMenu(_hHelpMenu) ) DestroyMenu(_hHelpMenu);
// tell the thread its time to die
if ( _hThread ) { PostThreadMessage(_dwThreadId, RVTM_STOPQUERY, 0, 0); PostThreadMessage(_dwThreadId, WM_QUIT, 0, 0); CloseHandle(_hThread); }
DoRelease(_pqf); DoRelease(_punkSite); DoRelease(_pcm);
DllRelease(); }
// IUnknown bits
ULONG CDsQuery::AddRef() { return InterlockedIncrement(&_cRef); }
ULONG CDsQuery::Release() { if (InterlockedDecrement(&_cRef)) return _cRef;
delete this; return 0; }
HRESULT CDsQuery::QueryInterface(REFIID riid, void **ppv) { static const QITAB qit[] = { QITABENT(CDsQuery, IQueryForm), // IID_IQueryForm
QITABENT(CDsQuery, IQueryHandler), // IID_IQueryHandler
QITABENT(CDsQuery, IObjectWithSite), // IID_IObjectWIthSite
QITABENT(CDsQuery, IDsQueryHandler), // IID_IDsQueryHandler
QITABENT(CDsQuery, IShellFolder), // IID_IShellFolder
{0, 0 }, }; return QISearch(this, qit, riid, ppv); }
//
// Handle creating an instance of CLSID_DsQuery
//
STDAPI CDsQuery_CreateInstance(IUnknown* punkOuter, IUnknown** ppunk, LPCOBJECTINFO poi) { CDsQuery *pdq = new CDsQuery(); if ( !pdq ) return E_OUTOFMEMORY;
HRESULT hres = pdq->QueryInterface(IID_IUnknown, (void **)ppunk); pdq->Release(); return hres; }
/// IQueryForm
STDMETHODIMP CDsQuery::Initialize(HKEY hkForm) { return S_OK; }
// query forms exposed from this object
struct { CLSID const * clsidForm; INT idsTitle; DWORD dwFlags; } forms[] = { &CLSID_DsFindPeople, IDS_FINDUSER, 0, &CLSID_DsFindComputer, IDS_FINDCOMPUTER, 0, &CLSID_DsFindPrinter, IDS_FINDPRINTERS, 0, &CLSID_DsFindVolume, IDS_FINDSHAREDFOLDERS, 0, &CLSID_DsFindContainer, IDS_FINDOU, 0, &CLSID_DsFindAdvanced, IDS_CUSTOMSEARCH, CQFF_NOGLOBALPAGES,
&CLSID_DsFindDomainController, IDS_FINDDOMCTL, CQFF_ISNEVERLISTED|CQFF_NOGLOBALPAGES, &CLSID_DsFindFrsMembers, IDS_FINDFRSMEMBER, CQFF_ISNEVERLISTED|CQFF_NOGLOBALPAGES, };
STDMETHODIMP CDsQuery::AddForms(LPCQADDFORMSPROC pAddFormsProc, LPARAM lParam) { HRESULT hres; TCHAR szBuffer[MAX_PATH]; INT i;
TraceEnter(TRACE_FORMS, "CDsQuery::AddForms");
if ( !pAddFormsProc ) ExitGracefully(hres, E_INVALIDARG, "No AddFormsProc");
for ( i = 0; i < ARRAYSIZE(forms); i++ ) { CQFORM qf = { 0 };
qf.cbStruct = SIZEOF(qf); qf.dwFlags = forms[i].dwFlags; qf.clsid = *forms[i].clsidForm; qf.pszTitle = szBuffer;
LoadString(GLOBAL_HINSTANCE, forms[i].idsTitle, szBuffer, ARRAYSIZE(szBuffer));
hres = (*pAddFormsProc)(lParam, &qf); FailGracefully(hres, "Failed to add form (calling pAddFormsFunc)"); }
hres = S_OK; // success
exit_gracefully:
TraceLeaveResult(hres); }
// page information for this object
struct { CLSID const * clisdForm; LPCQPAGEPROC pPageProc; DLGPROC pDlgProc; INT idPageTemplate; INT idPageName; DWORD dwFlags; } pages[] = { //
// Page list for the default forms that we add
//
&CLSID_DsFindPeople, PageProc_User, DlgProc_User, IDD_FINDUSER, IDS_FINDUSER, 0, &CLSID_DsFindComputer, PageProc_Computer, DlgProc_Computer, IDD_FINDCOMPUTER, IDS_FINDCOMPUTER, 0, &CLSID_DsFindPrinter, PageProc_Printers, DlgProc_Printers, IDD_FINDPRINT1, IDS_FINDPRINTERS, 0, &CLSID_DsFindPrinter, PageProc_PrintersMore, DlgProc_PrintersMore, IDD_FINDPRINT2, IDS_MORECHOICES, 0, &CLSID_DsFindVolume, PageProc_Volume, DlgProc_Volume, IDD_FINDVOLUME, IDS_FINDSHAREDFOLDERS, 0, &CLSID_DsFindContainer, PageProc_Container, DlgProc_Container, IDD_FINDCONTAINER, IDS_FINDOU, 0, &CLSID_DsFindAdvanced, PageProc_PropertyWell, DlgProc_PropertyWell, IDD_PROPERTYWELL, IDS_CUSTOMSEARCH, 0, &CLSID_DsFindAdvanced, PageProc_RawLDAP, DlgProc_RawLDAP, IDD_FINDUSINGLDAP, IDS_ADVANCED, 0, &CLSID_DsFindDomainController, PageProc_DomainController, DlgProc_DomainController, IDD_FINDDOMCTL, IDS_FINDDOMCTL, 0, &CLSID_DsFindFrsMembers, PageProc_FrsMember, DlgProc_FrsMember, IDD_FINDFRSMEMBER, IDS_FINDFRSMEMBER, 0,
//
// Make the property well available on all pages (using the magic CQPF_ADDTOALLFORMS bit)
//
&CLSID_DsFindAdvanced, PageProc_PropertyWell, DlgProc_PropertyWell, IDD_PROPERTYWELL, IDS_ADVANCED, CQPF_ISGLOBAL, };
STDMETHODIMP CDsQuery::AddPages(LPCQADDPAGESPROC pAddPagesProc, LPARAM lParam) { HRESULT hres; INT i;
TraceEnter(TRACE_FORMS, "CDsQuery::AddPages");
if ( !pAddPagesProc ) ExitGracefully(hres, E_INVALIDARG, "No AddPagesProc");
for ( i = 0 ; i < ARRAYSIZE(pages) ; i++ ) { CQPAGE qp = { 0 };
qp.cbStruct = SIZEOF(qp); qp.dwFlags = pages[i].dwFlags; qp.pPageProc = pages[i].pPageProc; qp.hInstance = GLOBAL_HINSTANCE; qp.idPageName = pages[i].idPageName; qp.idPageTemplate = pages[i].idPageTemplate; qp.pDlgProc = pages[i].pDlgProc;
hres = (*pAddPagesProc)(lParam, *pages[i].clisdForm, &qp); FailGracefully(hres, "Failed to add page (calling pAddPagesFunc)"); }
hres = S_OK;
exit_gracefully:
TraceLeaveResult(S_OK); }
// IQueryHandler
STDMETHODIMP CDsQuery::Initialize(IQueryFrame* pQueryFrame, DWORD dwOQWFlags, LPVOID pParameters) { HRESULT hres; LPDSQUERYINITPARAMS pDsQueryInitParams = (LPDSQUERYINITPARAMS)pParameters; TCHAR szGUID[GUIDSTR_MAX]; TCHAR szBuffer[MAX_PATH]; HINSTANCE hInstanceComCtl32 = NULL; USES_CONVERSION; TraceEnter(TRACE_HANDLER, "CDsQuery::Initialize");
// Keep the IQueryFrame interface, we need it for menu negotiation and other
// view -> frame interactions.
_pqf = pQueryFrame; _pqf->AddRef();
_dwOQWFlags = dwOQWFlags;
// If we have a parameter block then lets take copies of the interesting
// fields from there.
if ( pDsQueryInitParams ) { _dwFlags = pDsQueryInitParams->dwFlags;
// did the user specify a default scope?
if ( pDsQueryInitParams->pDefaultScope && pDsQueryInitParams->pDefaultScope[0] ) { Trace(TEXT("Default scope:"), W2T(pDsQueryInitParams->pDefaultScope)); hres = LocalAllocStringW(&_pDefaultScope, pDsQueryInitParams->pDefaultScope); FailGracefully(hres, "Failed to cope default scope"); }
// default save location?
if ( (_dwFlags & DSQPF_SAVELOCATION) && pDsQueryInitParams->pDefaultSaveLocation ) { Trace(TEXT("Default save location:"), W2T(pDsQueryInitParams->pDefaultSaveLocation)); hres = LocalAllocStringW(&_pDefaultSaveLocation, pDsQueryInitParams->pDefaultSaveLocation); FailGracefully(hres, "Failed to copy save location"); }
// do we have credential information?
if ( _dwFlags & DSQPF_HASCREDENTIALS ) { TraceMsg("Copying credential/server information from init params");
if ( pDsQueryInitParams->pUserName ) { hres = LocalAllocStringW(&_pUserName, pDsQueryInitParams->pUserName); FailGracefully(hres, "Failed to copy user name"); }
if ( pDsQueryInitParams->pPassword ) { hres = LocalAllocStringW(&_pPassword, pDsQueryInitParams->pPassword); FailGracefully(hres, "Failed to copy password"); }
if ( pDsQueryInitParams->pServer ) { hres = LocalAllocStringW(&_pServer, pDsQueryInitParams->pServer); FailGracefully(hres, "Failed to copy server"); }
Trace(TEXT("_pUserName : %s"), _pUserName ? W2T(_pUserName):TEXT("<not specified>")); Trace(TEXT("_pPassword : %s"), _pPassword ? W2T(_pPassword):TEXT("<not specified>")); Trace(TEXT("_pServer : %s"), _pServer ? W2T(_pServer):TEXT("<not specified>")); } }
// Finally load the must structures that we are going to use, then modify them
// based on the flags that the caller gave us.
//
// NB: removes the last two items from the file menu assumed to be the
// "save" and its seperator
_hFileMenu = LoadMenu(GLOBAL_HINSTANCE, MAKEINTRESOURCE(IDR_MENU_FILE)); _hEditMenu = LoadMenu(GLOBAL_HINSTANCE, MAKEINTRESOURCE(IDR_MENU_EDIT)); _hViewMenu = LoadMenu(GLOBAL_HINSTANCE, MAKEINTRESOURCE(IDR_MENU_VIEW)); _hHelpMenu = LoadMenu(GLOBAL_HINSTANCE, MAKEINTRESOURCE(IDR_MENU_HELP));
if ( !_hFileMenu || !_hEditMenu || !_hViewMenu || !_hHelpMenu ) ExitGracefully(hres, E_FAIL, "Failed to load resources for menus");
if ( _dwFlags & DSQPF_NOSAVE ) { HMENU hFileMenu = GetSubMenu(_hFileMenu, 0); INT i = GetMenuItemCount(hFileMenu);
DeleteMenu(hFileMenu, i-1, MF_BYPOSITION); DeleteMenu(hFileMenu, i-2, MF_BYPOSITION); }
// Init ComCtl32, including checking to see if we can use the filter control or not,
// the filter control was added to the WC_HEADER32 in IE5, so check the DLL version
// to see which we are using.
InitCommonControls();
hInstanceComCtl32 = GetModuleHandle(TEXT("comctl32")); TraceAssert(hInstanceComCtl32);
if ( hInstanceComCtl32 ) { DLLVERSIONINFO dllVersionInfo = { 0 }; DLLGETVERSIONPROC pfnDllGetVersion = (DLLGETVERSIONPROC)GetProcAddress(hInstanceComCtl32, "DllGetVersion"); TraceAssert(pfnDllGetVersion);
dllVersionInfo.cbSize = SIZEOF(dllVersionInfo);
if ( pfnDllGetVersion && SUCCEEDED(pfnDllGetVersion(&dllVersionInfo)) ) { Trace(TEXT("DllGetVersion succeeded on ComCtl32, dwMajorVersion %08x"), dllVersionInfo.dwMajorVersion); _fFilterSupported = dllVersionInfo.dwMajorVersion >= 5; } } Trace(TEXT("_fFilterSupported is %d"), _fFilterSupported);
hres = S_OK; // success
exit_gracefully:
TraceLeaveResult(hres); }
/*---------------------------------------------------------------------------*/
STDMETHODIMP CDsQuery::GetViewInfo(LPCQVIEWINFO pViewInfo) { HICON hIcon;
TraceEnter(TRACE_HANDLER, "CDsQuery::GetViewInfo");
pViewInfo->dwFlags = 0; pViewInfo->hInstance = GLOBAL_HINSTANCE; pViewInfo->idLargeIcon = IDI_FINDDS; pViewInfo->idSmallIcon = IDI_FINDDS; pViewInfo->idTitle = IDS_WINDOWTITLE; pViewInfo->idAnimation = IDR_DSFINDANIMATION;
TraceLeaveResult(S_OK); }
/*---------------------------------------------------------------------------*/
STDMETHODIMP CDsQuery::AddScopes() { HRESULT hres; DWORD dwThreadId; HANDLE hThread; LPSCOPETHREADDATA pstd = NULL; USES_CONVERSION;
TraceEnter(TRACE_HANDLER, "CDsQuery::AddScopes");
// Enumerate the rest of the scopes on a seperate thread to gather the
// scopes we are interested in.
pstd = (LPSCOPETHREADDATA)LocalAlloc(LPTR, SIZEOF(SCOPETHREADDATA)); TraceAssert(pstd);
if ( !pstd ) ExitGracefully(hres, E_OUTOFMEMORY, "Failed to allocate scope data structure");
_pqf->GetWindow(&pstd->hwndFrame); // pstd->pDefaultScope = NULL;
// pstd->pServer = NULL; // no credential stuff currently
// pstd->pUserName = NULL;
// pstd->pPassword = NULL;
if ( _pDefaultScope ) { hres = LocalAllocStringW(&pstd->pDefaultScope, _pDefaultScope); FailGracefully(hres, "Failed to copy the default scope"); }
hres = _CopyCredentials(&pstd->pUserName, &pstd->pPassword, &pstd->pServer); FailGracefully(hres, "Failed to copy credentails");
DllAddRef();
hThread = CreateThread(NULL, 0, AddScopesThread, pstd, 0, &dwThreadId); TraceAssert(hThread);
if ( !hThread ) { DllRelease(); ExitGracefully(hres, E_FAIL, "Failed to create background thread to enum scopes - BAD!"); }
CloseHandle(hThread);
hres = S_OK;
exit_gracefully:
if ( FAILED(hres) && pstd ) { LocalFreeStringW(&pstd->pDefaultScope); LocalFree((HLOCAL)pstd); }
TraceLeaveResult(hres); }
/*---------------------------------------------------------------------------*/
typedef struct { IADsPathname *padp; WCHAR szGcPath[MAX_PATH]; } BROWSEFORSCOPE;
int CALLBACK CDsQuery::s_BrowseForScopeCB(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData) { HRESULT hres; INT iResult = 0; BROWSEFORSCOPE *pbfs = (BROWSEFORSCOPE*)lpData; LPTSTR pDirectoryName = NULL; USES_CONVERSION;
TraceEnter(TRACE_HANDLER, "CDsQuery::s_BrowseForScopeCB");
switch ( uMsg ) { case DSBM_QUERYINSERT: { PDSBITEM pItem = (PDSBITEM)lParam; TraceAssert(pItem);
// We are interested in modifying the root item of the tree, therefore
// lets check for that being inserted, if it is then we change the
// display name and the icon being shown.
if ( pItem->dwState & DSBS_ROOT ) { GetModuleFileName(GLOBAL_HINSTANCE, pItem->szIconLocation, ARRAYSIZE(pItem->szIconLocation)); pItem->iIconResID = -IDI_GLOBALCATALOG;
if ( SUCCEEDED(FormatDirectoryName(&pDirectoryName, GLOBAL_HINSTANCE, IDS_GLOBALCATALOG)) ) { StrCpyN(pItem->szDisplayName, pDirectoryName, DSB_MAX_DISPLAYNAME_CHARS); LocalFreeString(&pDirectoryName); }
pItem->dwMask |= DSBF_DISPLAYNAME|DSBF_ICONLOCATION; iResult = TRUE; }
break; }
case BFFM_SELCHANGED: { BOOL fEnableOK = TRUE; LPWSTR pszPath = (LPWSTR)lParam; LONG nElements = 0;
// The user changes the selection in the browse dialog, therefore
// lets see if we should be enabling the OK button. If the user
// selects GC, but we don't have a GC then we disable it.
if ( SUCCEEDED(pbfs->padp->Set(pszPath, ADS_SETTYPE_FULL)) ) { pbfs->padp->GetNumElements(&nElements); Trace(TEXT("nElements on exit from GetNumElements %d"), nElements); }
if ( !nElements && !pbfs->szGcPath[0] ) { TraceMsg("'entire directory' selected with NO GC!"); fEnableOK = FALSE; }
SendMessage(hwnd, BFFM_ENABLEOK, (WPARAM)fEnableOK, 0L); break; }
case DSBM_HELP: { WinHelp((HWND)((LPHELPINFO)lParam)->hItemHandle, DSQUERY_HELPFILE, HELP_WM_HELP, (DWORD_PTR)aBrowseHelpIDs); break; }
case DSBM_CONTEXTMENU: { WinHelp((HWND)lParam, DSQUERY_HELPFILE, HELP_CONTEXTMENU, (DWORD_PTR)aBrowseHelpIDs); break; } }
TraceLeaveValue(iResult); }
STDMETHODIMP CDsQuery::BrowseForScope(HWND hwndParent, LPCQSCOPE pCurrentScope, LPCQSCOPE* ppScope) { HRESULT hres; LPDSQUERYSCOPE pDsQueryScope = (LPDSQUERYSCOPE)pCurrentScope; BROWSEFORSCOPE bfs = { 0 }; DSBROWSEINFO dsbi = { 0 }; INT iResult; WCHAR szPath[2048]; WCHAR szRoot[MAX_PATH+10]; // LDAP://
WCHAR szObjectClass[64]; LONG nElements; USES_CONVERSION; TraceEnter(TRACE_HANDLER, "CDsQuery::BrowseForScope"); Trace(TEXT("hwndParent %08x, pCurrentScope %08x, ppScope %08x"), hwndParent, pCurrentScope, ppScope);
*ppScope = NULL; // nothing yet!
if ( SUCCEEDED(GetGlobalCatalogPath(_pServer, bfs.szGcPath, ARRAYSIZE(bfs.szGcPath))) ) Trace(TEXT("GC path is: %s"), W2T(bfs.szGcPath));
hres = CoCreateInstance(CLSID_Pathname, NULL, CLSCTX_INPROC_SERVER, IID_IADsPathname, (void **)&bfs.padp); FailGracefully(hres, "Failed to get the IADsPathname interface");
// Fill out the browse info structure to display the object picker, if we have
// enabled admin features then lets make all objects visible, otherwise
// just the standard features.
dsbi.cbStruct = SIZEOF(dsbi); dsbi.hwndOwner = hwndParent; dsbi.pszRoot = szRoot; dsbi.pszPath = szPath; dsbi.cchPath = ARRAYSIZE(szPath); dsbi.dwFlags = (DSBI_RETURNOBJECTCLASS|DSBI_EXPANDONOPEN|DSBI_ENTIREDIRECTORY) & ~DSBI_NOROOT; dsbi.pfnCallback = s_BrowseForScopeCB; dsbi.lParam = (LPARAM)&bfs; dsbi.pszObjectClass = szObjectClass; dsbi.cchObjectClass = ARRAYSIZE(szObjectClass);
if ( _dwFlags & DSQPF_SHOWHIDDENOBJECTS ) dsbi.dwFlags |= DSBI_INCLUDEHIDDEN;
FormatMsgResource((LPTSTR*)&dsbi.pszTitle, GLOBAL_HINSTANCE, IDS_BROWSEPROMPT);
StrCpyW(szRoot, c_szLDAP);
if ( _pServer ) { if ( lstrlenW(_pServer) > MAX_PATH ) ExitGracefully(hres, E_INVALIDARG, "_pServer is too big");
StrCatW(szRoot, L"//"); StrCatW(szRoot, _pServer); }
if ( pDsQueryScope ) { StrCpyNW(szPath, OBJECT_NAME_FROM_SCOPE(pDsQueryScope), ARRAYSIZE(szPath)); Trace(TEXT("pDsQueryScope: %s"), W2T(szPath)); }
// copy the credential information if needed
if ( _dwFlags & DSQPF_HASCREDENTIALS ) { TraceMsg("Setting credentails information"); dsbi.pUserName = _pUserName; dsbi.pPassword = _pPassword; dsbi.dwFlags |= DSBI_HASCREDENTIALS; }
iResult = DsBrowseForContainer(&dsbi); Trace(TEXT("DsBrowseForContainer returns %d"), iResult);
// iResult == IDOK if something was selected (szPath),
// if it is -VE if the call failed and we should error
if ( iResult == IDOK ) { LPWSTR pszScope = szPath; LPWSTR pszObjectClass = szObjectClass; LONG nElements = 0;
Trace(TEXT("Path on exit from DsBrowseForContainer: %s"), W2T(szPath));
// does this look like the GC? If so then default to it, as DsBrowseForContainer
// will return us iffy looking information
if ( SUCCEEDED(bfs.padp->Set(szPath, ADS_SETTYPE_FULL)) ) { bfs.padp->GetNumElements(&nElements); Trace(TEXT("nElements on exit from GetNumElements %d"), nElements); }
if ( !nElements ) { TraceMsg("nElements = 0, so defaulting to GC"); pszScope = bfs.szGcPath; pszObjectClass = GC_OBJECTCLASS; }
Trace(TEXT("Scope selected is: %s, Object class: %s"), W2T(pszScope), W2T(pszObjectClass));
hres = AllocScope(ppScope, 0, pszScope, pszObjectClass); FailGracefully(hres, "Failed converting the DS path to a scope"); } else if ( iResult == IDCANCEL ) { hres = S_FALSE; // nothing selected, returning S_FALSE;
} else if ( iResult < 0 ) { ExitGracefully(hres, E_FAIL, "DsBrowseForContainer failed"); }
exit_gracefully:
LocalFreeString((LPTSTR*)&dsbi.pszTitle); Trace(TEXT("*ppScope == %08x"), *ppScope);
DoRelease(bfs.padp);
TraceLeaveResult(hres); }
/*---------------------------------------------------------------------------*/
//
// WndProc for the banner window
//
LRESULT CALLBACK CDsQuery::s_BannerWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { LRESULT lResult = 0;
switch ( uMsg ) { case WM_SIZE: InvalidateRect(hwnd, NULL, FALSE); break;
case WM_ERASEBKGND: break;
case WM_PAINT: { TCHAR szBuffer[MAX_PATH]; HFONT hFont, hOldFont; SIZE szText; RECT rcClient; INT len; PAINTSTRUCT paint; COLORREF oldFgColor, oldBkColor; BeginPaint(hwnd, &paint);
hFont = (HFONT)SendMessage(GetParent(hwnd), WM_GETFONT, 0, 0L); hOldFont = (HFONT)SelectObject(paint.hdc, hFont);
if ( hOldFont ) { oldFgColor = SetTextColor(paint.hdc, GetSysColor(COLOR_WINDOWTEXT)); oldBkColor = SetBkColor(paint.hdc, ListView_GetBkColor(GetParent(hwnd)));
len = GetWindowText(hwnd, szBuffer, ARRAYSIZE(szBuffer));
GetTextExtentPoint32(paint.hdc, szBuffer, len, &szText); GetClientRect(GetParent(hwnd), &rcClient); ExtTextOut(paint.hdc, (rcClient.right - szText.cx) / 2, GetSystemMetrics(SM_CYBORDER)*4, ETO_CLIPPED|ETO_OPAQUE, &rcClient, szBuffer, len, NULL);
SetTextColor(paint.hdc, oldFgColor); SetBkColor(paint.hdc, oldBkColor);
SelectObject(paint.hdc, hOldFont); }
EndPaint(hwnd, &paint);
break; }
case WM_SETTEXT: { InvalidateRect(hwnd, NULL, FALSE); //break; // deliberate drop through..
}
default: lResult = DefWindowProc(hwnd, uMsg, wParam, lParam); break; }
return lResult; }
//
// WndProc for the bg window (lives behind list view, used by rest of the world)
//
LRESULT CALLBACK CDsQuery::s_ResultViewWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { LRESULT lResult = 0; CDsQuery* pDsQuery = NULL;
if ( uMsg == WM_CREATE ) { pDsQuery = (CDsQuery*)((LPCREATESTRUCT)lParam)->lpCreateParams; SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pDsQuery); } else { pDsQuery = (CDsQuery*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
switch ( uMsg ) { case WM_SIZE: pDsQuery->OnSize(LOWORD(lParam), HIWORD(lParam)); return(0);
case WM_DESTROY: pDsQuery->_hwndView = NULL; // view is gone!
break;
case WM_NOTIFY: return(pDsQuery->OnNotify(hwnd, wParam, lParam));
case WM_SETFOCUS: SetFocus(pDsQuery->_hwndView); break;
case WM_GETDLGCODE: return ((LRESULT)(DLGC_WANTARROWS | DLGC_WANTCHARS));
case WM_CONTEXTMENU: pDsQuery->OnContextMenu(NULL, lParam); return TRUE; case DSQVM_ADDRESULTS: return SUCCEEDED(pDsQuery->OnAddResults((DWORD)wParam, (HDPA)lParam)); case DSQVM_FINISHED: if ( (DWORD)wParam == pDsQuery->_dwQueryReference ) { // the references match so lets finish the query, and display
// the "too many results" prompt if the user did a really
// big query and we chopped them off
pDsQuery->StopQuery();
if ( lParam ) // == 0 then we are OK!
{ HWND hwndFrame; pDsQuery->_pqf->GetWindow(&hwndFrame); FormatMsgBox(GetParent(hwndFrame), GLOBAL_HINSTANCE, IDS_WINDOWTITLE, IDS_ERR_MAXRESULT, MB_OK|MB_ICONERROR); } } SetFocus(pDsQuery->_hwndView); return(1); } }
return DefWindowProc(hwnd, uMsg, wParam, lParam); }
STDMETHODIMP CDsQuery::CreateResultView(HWND hwndParent, HWND* phWndView) { HRESULT hres; WNDCLASS wc; HWND hwndFilter, hwndFilterOld; HIMAGELIST himlSmall, himlLarge; DWORD dwLVStyle = LVS_AUTOARRANGE|LVS_SHAREIMAGELISTS|LVS_SHOWSELALWAYS|LVS_REPORT; RECT rc;
TraceEnter(TRACE_HANDLER, "CDsQuery::CreateResultView");
if ( IsWindow(_hwnd) ) ExitGracefully(hres, E_FAIL, "Can only create one view at a time");
// Create our result viewer, this is the parent window to the ListView
// that we attach when we issue the query.
ZeroMemory(&wc, SIZEOF(wc)); wc.lpfnWndProc = s_ResultViewWndProc; wc.hInstance = GLOBAL_HINSTANCE; wc.lpszClassName = VIEW_CLASS; RegisterClass(&wc);
_hwnd = CreateWindow(VIEW_CLASS, NULL, WS_TABSTOP|WS_CLIPCHILDREN|WS_CHILD|WS_VISIBLE, 0, 0, 0, 0, hwndParent, NULL, GLOBAL_HINSTANCE, this); if ( !_hwnd ) ExitGracefully(hres, E_FAIL, "Failed to create view parent window");
// Now register the window classes we are using.
ZeroMemory(&wc, SIZEOF(wc)); wc.lpfnWndProc = s_BannerWndProc; wc.hInstance = GLOBAL_HINSTANCE; wc.lpszClassName = BANNER_CLASS; RegisterClass(&wc);
if ( _dwOQWFlags & OQWF_SINGLESELECT ) dwLVStyle |= LVS_SINGLESEL;
GetClientRect(_hwnd, &rc); _hwndView = CreateWindowEx(WS_EX_CLIENTEDGE, WC_LISTVIEW, NULL, WS_TABSTOP|WS_CLIPCHILDREN|WS_CHILD|WS_VISIBLE|dwLVStyle, 0, 0, rc.right, rc.bottom, _hwnd, (HMENU)IDC_RESULTS, GLOBAL_HINSTANCE, NULL); if ( !_hwndView ) ExitGracefully(hres, E_FAIL, "Failed to create the view window");
ListView_SetExtendedListViewStyle(_hwndView, LVS_EX_FULLROWSELECT|LVS_EX_LABELTIP); Shell_GetImageLists(&himlLarge, &himlSmall); ListView_SetImageList(_hwndView, himlLarge, LVSIL_NORMAL); ListView_SetImageList(_hwndView, himlSmall, LVSIL_SMALL); // Create the banner window, this is a child of the ListView, it is used to display
// information about the query being issued
_hwndBanner = CreateWindow(BANNER_CLASS, NULL, WS_CHILD, 0, 0, 0, 0, // nb: size fixed later
_hwndView, (HMENU)IDC_STATUS, GLOBAL_HINSTANCE, NULL); if ( !_hwndBanner ) ExitGracefully(hres, E_FAIL, "Failed to create the static banner window");
_SetFilter(_fFilter); _SetViewMode(_idViewMode); _ShowBanner(SWP_SHOWWINDOW, IDS_INITALIZING);
hres = S_OK; // success
exit_gracefully: if ( SUCCEEDED(hres) ) *phWndView = _hwnd;
TraceLeaveResult(hres); }
/*---------------------------------------------------------------------------*/
#define MGW_EDIT 2
STDMETHODIMP CDsQuery::ActivateView(UINT uState, WPARAM wParam, LPARAM lParam) { HRESULT hres; HWND hwnd; INT i; TraceEnter(TRACE_HANDLER, "CDsQuery::ActivateView");
switch ( uState ) { case CQRVA_ACTIVATE: { HMENU hMenu; OLEMENUGROUPWIDTHS omgw = { 0, 0, 0, 0, 0, 0 };
// Allow the cframe to merge its menus into our menu bar before we
// add ours to it.
if ( !(hMenu = CreateMenu()) ) ExitGracefully(hres, E_FAIL, "Failed to create a base menu bar to be used");
hres = _pqf->InsertMenus(hMenu, &omgw); FailGracefully(hres, "Failed when calling CQueryFrame::InsertMenus");
Shell_MergeMenus(GetSubMenu(hMenu, 0), GetSubMenu(_hFileMenu, 0), 0x0, 0x0, 0x7fff, 0);
MergeMenu(hMenu, _hEditMenu, omgw.width[0]); MergeMenu(hMenu, _hViewMenu, omgw.width[0]+1); MergeMenu(hMenu, _hHelpMenu, omgw.width[0]+MGW_EDIT+omgw.width[2]+omgw.width[4]);
if ( _dwOQWFlags & OQWF_SINGLESELECT ) { ENABLE_MENU_ITEM(hMenu, DSQH_EDIT_SELECTALL, FALSE); ENABLE_MENU_ITEM(hMenu, DSQH_EDIT_INVERTSELECTION, FALSE); }
hres = _pqf->SetMenu(hMenu, NULL); // set the frames menu bar
FailGracefully(hres, "Failed when calling CQueryFrame::SetMenu");
break; }
case CQRVA_INITMENUBAR: { // we recieve a CQRVA_INITMENUBAR before the popup so that we can store the
// menu bar information, and invalidate an interface pointers we maybe holding
// onto.
Trace(TEXT("Received an CQRVA_INITMENUBAR, hMenu %08x"), wParam);
_hFrameMenuBar = (HMENU)wParam; DoRelease(_pcm);
break; }
case CQRVA_INITMENUBARPOPUP: { HMENU hFileMenu; BOOL fDeleteItems = FALSE;
TraceMsg("Received an CQRVA_INITMENUBARPOPUP");
hFileMenu = GetSubMenu(_hFrameMenuBar, 0);
// if we have a view then lets try and collect the selection from it,
// having done that we can merge the verbs for that selection into the
// views "File" menu.
if ( (hFileMenu == (HMENU)wParam) && !_pcm ) { _fNoSelection = TRUE; // no selection currenlty
if ( IsWindow(_hwndView) ) { for ( i = GetMenuItemCount(hFileMenu) - 1; i >= 0 ; i-- ) { if ( !fDeleteItems && (GetMenuItemID(hFileMenu, i) == DSQH_FILE_PROPERTIES) ) { Trace(TEXT("Setting fDeleteItems true on index %d"), i); fDeleteItems = TRUE; } else { if ( fDeleteItems ) DeleteMenu(hFileMenu, i, MF_BYPOSITION); } }
// Collect the selection, and using that construct an IContextMenu interface, if that works
// then we can merge in the verbs that relate to this object.
hres = _GetContextMenu(); FailGracefully(hres, "Failed when calling _GetAndViewObject");
if ( ListView_GetSelectedCount(_hwndView) > 0 ) { _GetContextMenuVerbs(hFileMenu, CMF_VERBSONLY); _fNoSelection = FALSE; } }
ENABLE_MENU_ITEM(hFileMenu, DSQH_FILE_PROPERTIES, !_fNoSelection); }
// 211991 11/6/00 JonN and DavidDv
// choose columns is disabled if there are no columns to show/the user has marked for disabled
ENABLE_MENU_ITEM(_hFrameMenuBar, DSQH_VIEW_PICKCOLUMNS, IsWindow(_hwndView) && _hdsaColumns && (!(_dwFlags & DSQPF_NOCHOOSECOLUMNS)));
ENABLE_MENU_ITEM(_hFrameMenuBar, DSQH_VIEW_REFRESH, IsWindow(_hwndView) && _dwThreadId); _InitViewMenuItems(_hFrameMenuBar); break; }
case CQRVA_FORMCHANGED: { // we receieve a form change, we store the form name as we will use it
// as the default name for saved queries authored by the user.
Trace(TEXT("Form '%s' selected"), (LPTSTR)lParam);
LocalFreeString(&_pDefaultSaveName); hres = LocalAllocString(&_pDefaultSaveName, (LPCTSTR)lParam); FailGracefully(hres, "Failed to set the default save name");
break; }
case CQRVA_STARTQUERY: { Trace(TEXT("Query is: %s"), wParam ? TEXT("starting"):TEXT("stopping")); break; }
case CQRVA_HELP: { LPHELPINFO pHelpInfo = (LPHELPINFO)lParam; TraceAssert(pHelpInfo)
TraceMsg("Invoking help on the objects in the windows"); WinHelp((HWND)pHelpInfo->hItemHandle, DSQUERY_HELPFILE, HELP_WM_HELP, (DWORD_PTR)aHelpIDs);
break; }
case CQRVA_CONTEXTMENU: { HWND hwndForHelp = (HWND)wParam; Trace(TEXT("CQRVA_CONTEXTMENU recieved on the bg of the frame %d"), GetDlgCtrlID(hwndForHelp)); WinHelp(hwndForHelp, DSQUERY_HELPFILE, HELP_CONTEXTMENU, (DWORD_PTR)aHelpIDs); break; } } hres = S_OK;
exit_gracefully:
TraceLeaveResult(hres); }
/*---------------------------------------------------------------------------*/
STDMETHODIMP CDsQuery::InvokeCommand(HWND hwndParent, UINT uID) { HRESULT hres = S_OK; HWND hwndFrame; DECLAREWAITCURSOR;
TraceEnter(TRACE_HANDLER, "CDsQuery::InvokeCommand"); Trace(TEXT("hwndParent %08x, uID %d"), hwndParent, uID);
SetWaitCursor();
switch ( uID ) { case DSQH_BG_SELECT: SendMessage(hwndParent, WM_COMMAND, IDOK, 0); break;
case DSQH_FILE_PROPERTIES: hres = OnFileProperties(); break;
case DSQH_FILE_SAVEQUERY: hres = OnFileSaveQuery(); break;
case DSQH_EDIT_SELECTALL: hres = OnEditSelectAll(); break;
case DSQH_EDIT_INVERTSELECTION: hres = OnEditInvertSelection(); break;
case DSQH_VIEW_FILTER: _SetFilter(!_fFilter); break;
case DSQH_VIEW_LARGEICONS: case DSQH_VIEW_SMALLICONS: case DSQH_VIEW_LIST: case DSQH_VIEW_DETAILS: _SetViewMode(uID); break; case DSQH_VIEW_REFRESH: { if ( IsWindow(_hwndView) && _dwThreadId ) { _InitNewQuery(NULL, FALSE); PostThreadMessage(_dwThreadId, RVTM_REFRESH, _dwQueryReference, 0L); } break; }
case DSQH_VIEW_PICKCOLUMNS: { TraceAssert(_hdsaColumns); OnPickColumns(hwndParent); break; }
case DSQH_HELP_CONTENTS: { TraceMsg("Calling for to display help topics"); _pqf->GetWindow(&hwndFrame); _pqf->CallForm(NULL, DSQPM_HELPTOPICS, 0, (LPARAM)hwndFrame); break; }
case DSQH_HELP_WHATISTHIS: _pqf->GetWindow(&hwndFrame); SendMessage(hwndFrame, WM_SYSCOMMAND, SC_CONTEXTHELP, MAKELPARAM(0,0)); break; default: { // if it looks like a sort request then lets handle it, otherwise attempt
// to send to the context menu handler we may have at htis poiunt.
if ( (uID >= DSQH_VIEW_ARRANGEFIRST) && (uID < DSQH_VIEW_ARRANGELAST) ) { TraceAssert(_hdsaColumns); if ( _hdsaColumns ) { Trace(TEXT("Calling _SortResults for column %d"), uID - DSQH_VIEW_ARRANGEFIRST); _SortResults(uID - DSQH_VIEW_ARRANGEFIRST); } } else if ( _pcm ) { CMINVOKECOMMANDINFO ici;
ici.cbSize = SIZEOF(ici); ici.fMask = 0; _pqf->GetWindow(&ici.hwnd); ici.lpVerb = (LPCSTR)IntToPtr(uID - DSQH_FILE_CONTEXT_FIRST); ici.lpParameters = NULL; ici.lpDirectory = NULL; ici.nShow = SW_NORMAL; ici.dwHotKey = 0; ici.hIcon = NULL;
hres = _pcm->InvokeCommand(&ici); FailGracefully(hres, "Failed when calling IContextMenu::InvokeCommand");
DoRelease(_pcm); // no longer needed
}
break; } }
exit_gracefully:
ResetWaitCursor();
TraceLeaveResult(hres); }
/*---------------------------------------------------------------------------*/
STDMETHODIMP CDsQuery::GetCommandString(UINT uID, DWORD dwFlags, LPTSTR pBuffer, INT cchBuffer) { HRESULT hres; TCHAR szBuffer[MAX_PATH];
TraceEnter(TRACE_HANDLER, "CDsQuery::GetCommandString"); Trace(TEXT("uID %08x, dwFlags %08x, pBuffer %08x, cchBuffer %d"), uID, dwFlags, pBuffer, cchBuffer);
if ( (uID >= DSQH_FILE_CONTEXT_FIRST) && (uID < DSQH_FILE_CONTEXT_LAST) ) { if ( _pcm ) { TraceMsg("Trying the IContextMenu::GetCommandString");
hres = _pcm->GetCommandString((uID - DSQH_FILE_CONTEXT_FIRST), GCS_HELPTEXT, NULL, (LPSTR)pBuffer, cchBuffer); #if UNICODE
// we build UNICODE, therefore if we failed then try and pick up the ANSI string from
// the handler, if that works then we convert the multi-byte string to UNICODE
// and hand that back to the caller.
if ( FAILED(hres) ) { CHAR szBuffer[MAX_PATH]; hres = _pcm->GetCommandString((uID - DSQH_FILE_CONTEXT_FIRST), GCS_HELPTEXTA, NULL, szBuffer, ARRAYSIZE(szBuffer));
if ( SUCCEEDED(hres) ) { TraceMsg("Handler provided an ANSI string"); MultiByteToWideChar(CP_ACP, 0, szBuffer, -1, pBuffer, cchBuffer); } } #endif
FailGracefully(hres, "Failed when asking for help text from IContextMenu iface"); } } else { if ( (uID >= DSQH_VIEW_ARRANGEFIRST) && (uID < DSQH_VIEW_ARRANGELAST) ) { INT iColumn = uID-DSQH_VIEW_ARRANGEFIRST; TCHAR szFmt[MAX_PATH];
Trace(TEXT("Get command text for column %d"), iColumn);
if ( _hdsaColumns && (iColumn < DSA_GetItemCount(_hdsaColumns)) ) { LPCOLUMN pColumn = (LPCOLUMN)DSA_GetItemPtr(_hdsaColumns, iColumn); TraceAssert(pColumn);
LoadString(GLOBAL_HINSTANCE, IDS_ARRANGEBY_HELP, szFmt, ARRAYSIZE(szFmt)); wsprintf(pBuffer, szFmt, pColumn->pHeading);
Trace(TEXT("Resulting string is: %s"), pBuffer); } } else { if ( !LoadString(GLOBAL_HINSTANCE, uID, pBuffer, cchBuffer) ) ExitGracefully(hres, E_FAIL, "Failed to load the command text for this verb"); } }
hres = S_OK;
exit_gracefully:
TraceLeaveResult(hres); }
/*---------------------------------------------------------------------------*/
STDMETHODIMP CDsQuery::IssueQuery(LPCQPARAMS pQueryParams) { HRESULT hres; LPTHREADINITDATA ptid = NULL; LPDSQUERYSCOPE pDsQueryScope = (LPDSQUERYSCOPE)pQueryParams->pQueryScope; LPDSQUERYPARAMS pDsQueryParams = (LPDSQUERYPARAMS)pQueryParams->pQueryParameters; LPTSTR pBuffer = NULL; MSG msg;
TraceEnter(TRACE_HANDLER, "CDsQuery::IssueQuery"); Trace(TEXT("pQueryParams %08x, pDsQueryScope %08x, pDsQueryParams %08x"), pQueryParams, pDsQueryScope, pDsQueryParams);
// Persist the existing column information if there was some, then
// get the new column table initialized and the columns added to the
// view
if ( _hdsaColumns ) { if ( _fColumnsModified ) { _SaveColumnTable(_clsidForm, _hdsaColumns); _fColumnsModified = FALSE; }
_SaveColumnTable(); }
// Initialize the view with items
_clsidForm = pQueryParams->clsidForm; // keep the form ID (for persistance)
hres = _InitNewQuery(pDsQueryParams, TRUE); FailGracefully(hres, "Failed to initialize the new query");
// Now build the thread information needed to get the thread
// up and running.
ptid = (LPTHREADINITDATA)LocalAlloc(LPTR, SIZEOF(THREADINITDATA)); TraceAssert(ptid);
if ( !ptid ) ExitGracefully(hres, E_OUTOFMEMORY, "Failed to allocate THREADINITDATA");
ptid->dwReference = _dwQueryReference; //ptid->hwndView = NULL;
//ptid->pQuery = NULL;
//ptid->pScope = NULL;
//ptid->hdsaColumns = NULL;
//ptid->fShowHidden = FALSE;
//ptid->pServer = NULL;
//ptid->pUserName = NULL;
//ptid->pPassword = NULL;
Trace(TEXT("_dwFlags %08x (& DSQPF_SHOWHIDDENOBJECTS)"), _dwFlags, _dwFlags & DSQPF_SHOWHIDDENOBJECTS);
ptid->fShowHidden = (_dwFlags & DSQPF_SHOWHIDDENOBJECTS) ? 1:0; ptid->hwndView = _hwndView;
hres = _GetColumnTable(_clsidForm, pDsQueryParams, &ptid->hdsaColumns, FALSE); FailGracefully(hres, "Failed to create column DSA");
hres = LocalAllocStringW(&ptid->pQuery, (LPWSTR)ByteOffset(pDsQueryParams, pDsQueryParams->offsetQuery)); FailGracefully(hres, "Failed to copy query filter string");
hres = LocalAllocStringW(&ptid->pScope, OBJECT_NAME_FROM_SCOPE(pDsQueryScope)); FailGracefully(hres, "Failed to copy scope to thread init data");
hres = _CopyCredentials(&ptid->pUserName, &ptid->pPassword, &ptid->pServer); FailGracefully(hres, "Failed to copy credentails");
// now create the thread that is going to perform the query, this includes
// telling the previous one that it needs to close down
if ( _hThread && _dwThreadId ) { Trace(TEXT("Killing old query thread %08x, ID %d"), _hThread, _dwThreadId);
PostThreadMessage(_dwThreadId, RVTM_STOPQUERY, 0, 0); PostThreadMessage(_dwThreadId, WM_QUIT, 0, 0);
CloseHandle(_hThread);
_hThread = NULL; _dwThreadId = 0; }
DllAddRef();
_hThread = CreateThread(NULL, 0, QueryThread, ptid, 0, &_dwThreadId); TraceAssert(_hThread);
if ( !_hThread ) { DllRelease(); ExitGracefully(hres, E_FAIL, "Failed to create background thread - BAD!"); }
hres = S_OK; // success
exit_gracefully:
if ( SUCCEEDED(hres) && IsWindow(_hwndView) ) SetFocus(_hwndView);
if ( FAILED(hres) ) { QueryThread_FreeThreadInitData(&ptid); _pqf->StartQuery(FALSE); }
TraceLeaveResult(hres); }
/*---------------------------------------------------------------------------*/
STDMETHODIMP CDsQuery::StopQuery() { HRESULT hres; INT cResults = _hdpaResults ? DPA_GetPtrCount(_hdpaResults):0; LPTSTR pBuffer;
TraceEnter(TRACE_HANDLER, "CDsQuery::StopQuery");
if ( !IsWindow(_hwndView) ) ExitGracefully(hres, E_FAIL, "View not initalized yet");
// we are stopping the query, we are going to tidy up the UI now
// and we just want the thread to closedown cleanly, therefore lets
// do so, increasing our query reference
_pqf->StartQuery(FALSE); _dwQueryReference++;
_PopulateView(-1, -1); // update status bar etc
if ( _dwThreadId ) PostThreadMessage(_dwThreadId, RVTM_STOPQUERY, 0, 0);
hres = S_OK; // success
exit_gracefully:
TraceLeaveResult(hres); }
/*---------------------------------------------------------------------------*/
HRESULT CDsQuery::_SetDataObjectData(IDataObject* pDataObject, UINT cf, LPVOID pData, DWORD cbSize) { FORMATETC fmte = {(CLIPFORMAT)cf, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; STGMEDIUM medium = { TYMED_NULL, NULL, NULL }; LPVOID pAlloc;
HRESULT hr = AllocStorageMedium(&fmte, &medium, cbSize, &pAlloc); if (SUCCEEDED(hr)) { CopyMemory(pAlloc, pData, cbSize); hr = pDataObject->SetData(&fmte, &medium, TRUE); ReleaseStgMedium(&medium); // were done, so release the storage medium
}
return hr; }
HRESULT CDsQuery::_SetDispSpecOptions(IDataObject *pdo) { CLIPFORMAT cfDsDispSpecOptions = (CLIPFORMAT)RegisterClipboardFormat(CFSTR_DSDISPLAYSPECOPTIONS); FORMATETC fmte = {cfDsDispSpecOptions, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; STGMEDIUM medium = { TYMED_NULL, NULL, NULL }; DSDISPLAYSPECOPTIONS *pddso; LPWSTR pAttribPrefix = DS_PROP_SHELL_PREFIX;
// are we in admin mode? if so then lets fix the property prefix for reading things
// from the display specifiers
if (_dwFlags & DSQPF_ENABLEADMINFEATURES) pAttribPrefix = DS_PROP_ADMIN_PREFIX;
// include all the string data into the allocation size (these are stored after the
// structure)
DWORD cbStruct = SIZEOF(DSDISPLAYSPECOPTIONS); cbStruct += StringByteSizeW(pAttribPrefix); cbStruct += StringByteSizeW(_pUserName); cbStruct += StringByteSizeW(_pPassword); cbStruct += StringByteSizeW(_pServer);
// allocate and fill...
HRESULT hr = AllocStorageMedium(&fmte, &medium, cbStruct, (void **)&pddso); if (SUCCEEDED(hr)) { DWORD offsetStrings = SIZEOF(DSDISPLAYSPECOPTIONS);
pddso->dwSize = SIZEOF(DSDISPLAYSPECOPTIONS); pddso->dwFlags = DSDSOF_HASUSERANDSERVERINFO|DSDSOF_DSAVAILABLE;
//pddso->offsetAttribPrefix = 0x0;
//pddso->offsetUserName = 0x0;
//pddso->offsetPassword = 0x0;
//pddso->offsetServer = 0x0;
//pddso->offsetServerConfigPath = 0x0;
pddso->offsetAttribPrefix = offsetStrings; StringByteCopyW(pddso, offsetStrings, pAttribPrefix); offsetStrings += StringByteSizeW(pAttribPrefix);
if ( _pUserName ) { pddso->offsetUserName = offsetStrings; StringByteCopyW(pddso, offsetStrings, _pUserName); offsetStrings += StringByteSizeW(_pUserName); }
if ( _pPassword ) { pddso->offsetPassword = offsetStrings; StringByteCopyW(pddso, offsetStrings, _pPassword); offsetStrings += StringByteSizeW(_pPassword); }
if ( _pServer ) { pddso->offsetServer = offsetStrings; StringByteCopyW(pddso, offsetStrings, _pServer); offsetStrings += StringByteSizeW(_pServer); }
// lets set into the IDataObject
hr = pdo->SetData(&fmte, &medium, TRUE); ReleaseStgMedium(&medium); }
return hr; }
STDMETHODIMP CDsQuery::GetViewObject(UINT uScope, REFIID riid, void **ppvOut) { HRESULT hres; IDataObject* pDataObject = NULL; LPDSQUERYPARAMS pDsQueryParams = NULL; LPDSQUERYSCOPE pDsQueryScope = NULL; UINT cfDsQueryParams = RegisterClipboardFormat(CFSTR_DSQUERYPARAMS); UINT cfDsQueryScope = RegisterClipboardFormat(CFSTR_DSQUERYSCOPE); BOOL fJustSelection = !(_dwFlags & DSQPF_RETURNALLRESULTS);
TraceEnter(TRACE_HANDLER, "CDsQuery::GetViewObject");
// We only support returning the selection as an IDataObject
DECLAREWAITCURSOR; SetWaitCursor();
if ( !ppvOut && ((uScope & CQRVS_MASK) != CQRVS_SELECTION) ) ExitGracefully(hres, E_INVALIDARG, "Bad arguments to GetViewObject");
if ( !IsEqualIID(riid, IID_IDataObject) ) ExitGracefully(hres, E_NOINTERFACE, "Object IID supported");
//
// write the extra data we have into the IDataObject:
//
// - query parameters (filter)
// - scope
// - attribute prefix information
//
hres = _GetDataObjectFromSelection(fJustSelection, &pDataObject); FailGracefully(hres, "Failed to get the IDataObject from the namespace");
if ( SUCCEEDED(_pqf->CallForm(NULL, CQPM_GETPARAMETERS, 0, (LPARAM)&pDsQueryParams)) ) { if ( pDsQueryParams ) { hres = _SetDataObjectData(pDataObject, cfDsQueryParams, pDsQueryParams, pDsQueryParams->cbStruct); FailGracefully(hres, "Failed set the DSQUERYPARAMS into the data object"); } }
if ( SUCCEEDED(_pqf->GetScope((LPCQSCOPE*)&pDsQueryScope)) ) { if ( pDsQueryScope ) { LPWSTR pScope = OBJECT_NAME_FROM_SCOPE(pDsQueryScope); TraceAssert(pScope);
hres = _SetDataObjectData(pDataObject, cfDsQueryScope, pScope, StringByteSizeW(pScope)); FailGracefully(hres, "Failed set the DSQUERYSCOPE into the data object"); } }
// success, so lets pass out the IDataObject.
pDataObject->AddRef(); *ppvOut = (LPVOID)pDataObject;
hres = S_OK;
exit_gracefully:
DoRelease(pDataObject); if ( pDsQueryParams ) CoTaskMemFree(pDsQueryParams);
if ( pDsQueryScope ) CoTaskMemFree(pDsQueryScope);
ResetWaitCursor();
TraceLeaveResult(hres); }
/*---------------------------------------------------------------------------*/
STDMETHODIMP CDsQuery::LoadQuery(IPersistQuery* pPersistQuery) { HRESULT hres; WCHAR szBuffer[MAX_PATH]; IADs *pDsObject = NULL; BSTR bstrObjectClass = NULL; INT iFilter; LPCQSCOPE pScope = NULL; INT cbScope; USES_CONVERSION;
TraceEnter(TRACE_HANDLER, "CDsQuery::LoadQuery"); if ( !pPersistQuery ) ExitGracefully(hres, E_INVALIDARG, "No IPersistQuery object");
if ( SUCCEEDED(pPersistQuery->ReadInt(c_szDsQuery, c_szScopeSize, &cbScope)) && (cbScope < SIZEOF(szBuffer)) && SUCCEEDED(pPersistQuery->ReadStruct(c_szDsQuery, c_szScope, szBuffer, cbScope)) ) { Trace(TEXT("Selected scope from file is %s"), W2T(szBuffer));
// get the object class from the file - this should be written to the file
hres = ADsOpenObject(szBuffer, _pUserName, _pPassword, ADS_SECURE_AUTHENTICATION, IID_IADs, (void **)&pDsObject); FailGracefully(hres, "Failed to bind to the specified object");
hres = pDsObject->get_Class(&bstrObjectClass); FailGracefully(hres, "Failed to get the object class");
// allocate a new scope
if ( SUCCEEDED(AllocScope(&pScope, 0, szBuffer, bstrObjectClass)) ) { hres = _pqf->AddScope(pScope, 0x0, TRUE); FailGracefully(hres, "Failed to add scope to list"); } }
// Read the remainder of the view state
if ( SUCCEEDED(pPersistQuery->ReadInt(c_szDsQuery, c_szViewMode, &_idViewMode)) ) { Trace(TEXT("View mode is: %0x8"), _idViewMode); _SetViewMode(_idViewMode); }
if ( SUCCEEDED(pPersistQuery->ReadInt(c_szDsQuery, c_szEnableFilter, &iFilter)) ) { Trace(TEXT("Filter mode set to %d"), _fFilter); _SetFilter(iFilter); }
hres = S_OK;
exit_gracefully:
if ( pScope ) CoTaskMemFree(pScope);
DoRelease(pDsObject); SysFreeString(bstrObjectClass);
TraceLeaveResult(hres); }
/*---------------------------------------------------------------------------*/
STDMETHODIMP CDsQuery::SaveQuery(IPersistQuery* pPersistQuery, LPCQSCOPE pScope) { HRESULT hres; LPDSQUERYSCOPE pDsQueryScope = (LPDSQUERYSCOPE)pScope; LPWSTR pScopePath = OBJECT_NAME_FROM_SCOPE(pDsQueryScope); WCHAR szGcPath[MAX_PATH]; TraceEnter(TRACE_HANDLER, "CDsQuery::SaveQuery");
if ( !pPersistQuery || !pScope ) ExitGracefully(hres, E_INVALIDARG, "No IPersistQuery/pScope object");
if ( SUCCEEDED(GetGlobalCatalogPath(_pServer, szGcPath, ARRAYSIZE(szGcPath))) && StrCmpW(pScopePath, szGcPath) ) { // if this is not the GC then persist
TraceMsg("GC path differs from scope, so persisting");
hres = pPersistQuery->WriteInt(c_szDsQuery, c_szScopeSize, StringByteSizeW(pScopePath)); FailGracefully(hres, "Failed to write the scope size");
hres = pPersistQuery->WriteStruct(c_szDsQuery, c_szScope, pScopePath, StringByteSizeW(pScopePath)); FailGracefully(hres, "Failed to write scope"); }
hres = pPersistQuery->WriteInt(c_szDsQuery, c_szViewMode, _idViewMode); FailGracefully(hres, "Failed to write view mode");
hres = pPersistQuery->WriteInt(c_szDsQuery, c_szEnableFilter, _fFilter); FailGracefully(hres, "Failed to write filter state");
hres = S_OK;
exit_gracefully:
TraceLeaveResult(hres); }
/*----------------------------------------------------------------------------
/ IObjectWithSite /----------------------------------------------------------------------------*/
STDMETHODIMP CDsQuery::SetSite(IUnknown* punk) { HRESULT hres = S_OK;
TraceEnter(TRACE_HANDLER, "CDsQuery::SetSite");
DoRelease(_punkSite);
if ( punk ) { TraceMsg("QIing for IUnknown from the site object");
hres = punk->QueryInterface(IID_IUnknown, (void **)&_punkSite); FailGracefully(hres, "Failed to get IUnknown from the site object"); }
exit_gracefully:
TraceLeaveResult(hres); }
STDMETHODIMP CDsQuery::GetSite(REFIID riid, void **ppv) { HRESULT hres; TraceEnter(TRACE_HANDLER, "CDsQuery::GetSite");
if ( !_punkSite ) ExitGracefully(hres, E_NOINTERFACE, "No site to QI from");
hres = _punkSite->QueryInterface(riid, ppv); FailGracefully(hres, "QI failed on the site unknown object");
exit_gracefully:
TraceLeaveResult(hres); }
/*----------------------------------------------------------------------------
/ IDsQueryHandler /----------------------------------------------------------------------------*/
VOID CDsQuery::_DeleteViewItems(LPDSOBJECTNAMES pdon) { INT iResult; DWORD iItem; USES_CONVERSION;
TraceEnter(TRACE_HANDLER, "CDsQuery::_DeleteObjectNames");
if ( pdon->cItems ) { // walk through all the items in the view deleting as required.
for ( iItem = 0 ; iItem != pdon->cItems ; iItem++ ) { // do we have an item to delete?
if ( pdon->aObjects[iItem].offsetName ) { LPCWSTR pwszName = (LPCWSTR)ByteOffset(pdon, pdon->aObjects[iItem].offsetName); Trace(TEXT("pwszName to delete: %s"), W2CT(pwszName));
// walk all the results in the view deleting them as we go.
for ( iResult = 0 ; iResult < DPA_GetPtrCount(_hdpaResults); iResult++ ) { LPQUERYRESULT pResult = (LPQUERYRESULT)DPA_GetPtr(_hdpaResults, iResult); TraceAssert(pResult);
// if we match the item we want to delete then remove it, if the view
// is not filtered then remove ite from the list, otherwise leave the
// view update until we have finished deleting
if ( !StrCmpW(pwszName, pResult->pPath) ) { Trace(TEXT("Item maps to result %d in the list"), iResult); FreeQueryResult(pResult, DSA_GetItemCount(_hdsaColumns)); DPA_DeletePtr(_hdpaResults, iResult); if ( !_fFilter ) { TraceMsg("Deleting the item from the view"); ListView_DeleteItem(_hwndView, iResult); } } } } }
// the view was filtered, so lets repopulate with the items
if ( _fFilter ) { TraceMsg("View is filter, therefore just forcing a refresh"); _FilterView(FALSE); } }
TraceLeave(); }
STDMETHODIMP CDsQuery::UpdateView(DWORD dwType, LPDSOBJECTNAMES pdon) { HRESULT hres;
TraceEnter(TRACE_HANDLER, "CDsQuery::UpdateView");
switch ( dwType & DSQRVF_OPMASK ) { case DSQRVF_ITEMSDELETED: { if ( !pdon ) ExitGracefully(hres, E_INVALIDARG, "Invlaidate pdon specified for refresh");
_DeleteViewItems(pdon); break; }
default: ExitGracefully(hres, E_INVALIDARG, "Invalidate refresh type speciifed"); }
hres = S_OK;
exit_gracefully:
TraceLeaveResult(hres); }
/*-----------------------------------------------------------------------------
/ Message/Command Handlers /----------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------
/ CDsQuery::OnSize / ---------------- / Result viewer is being sized, so ensure that our children have their / sizes correctly addjusted. / / In: / cx, cy = new size of the parent window / / Out: / - /----------------------------------------------------------------------------*/ LRESULT CDsQuery::OnSize(INT cx, INT cy) { TraceEnter(TRACE_VIEW, "CDsQuery::OnSize");
SetWindowPos(_hwndView, NULL, 0, 0, cx, cy, SWP_NOZORDER|SWP_NOMOVE); _ShowBanner(0, 0);
TraceLeaveValue(0); }
/*-----------------------------------------------------------------------------
/ CDsQuery::OnNotify / ------------------ / Notify message being recieved by the view, so try and handle it as best / we can. / / In: / hWnd = window handle of the notify / wParam, lParam = parameters for the notify event / / Out: / LRESULT /----------------------------------------------------------------------------*/ LRESULT CDsQuery::OnNotify(HWND hWnd, WPARAM wParam, LPARAM lParam) { HRESULT hres; LRESULT lr = 0; DECLAREWAITCURSOR = GetCursor(); USES_CONVERSION;
TraceEnter(TRACE_VIEW, "CDsQuery::OnNotify");
switch ( ((LPNMHDR)lParam)->code ) { case HDN_FILTERCHANGE: _FilterView(TRUE); break;
case HDN_FILTERBTNCLICK: { NMHDFILTERBTNCLICK* pNotify = (NMHDFILTERBTNCLICK*)lParam; HMENU hMenu; POINT pt; HD_ITEM hdi; UINT uID; if ( _hdsaColumns && (pNotify->iItem < DSA_GetItemCount(_hdsaColumns)) ) { LPCOLUMN pColumn = (LPCOLUMN)DSA_GetItemPtr(_hdsaColumns, pNotify->iItem);
if (pColumn) { hMenu = LoadMenu(GLOBAL_HINSTANCE, property_type_table[pColumn->iPropertyType].pMenuName); TraceAssert(hMenu);
if ( hMenu ) { pt.x = pNotify->rc.right; pt.y = pNotify->rc.bottom; MapWindowPoints(pNotify->hdr.hwndFrom, NULL, &pt, 1);
CheckMenuRadioItem(GetSubMenu(hMenu, 0), FILTER_FIRST, FILTER_LAST, pColumn->idOperator, MF_BYCOMMAND);
uID = TrackPopupMenu(GetSubMenu(hMenu, 0), TPM_RIGHTALIGN|TPM_RETURNCMD, pt.x, pt.y, 0, pNotify->hdr.hwndFrom, NULL); switch ( uID ) { case DSQH_CLEARFILTER: Header_ClearFilter(ListView_GetHeader(_hwndView), pNotify->iItem); break;
case DSQH_CLEARALLFILTERS: Header_ClearAllFilters(ListView_GetHeader(_hwndView)); break; default: { if ( uID && (uID != pColumn->idOperator) ) { // update the filter string based on the new operator
pColumn->idOperator = uID; _GetFilterValue(pNotify->iItem, NULL); lr = TRUE; } break; } }
DestroyMenu(hMenu); } } }
break; }
case HDN_ITEMCHANGED: { HD_NOTIFY* pNotify = (HD_NOTIFY*)lParam; HD_ITEM* pitem = (HD_ITEM*)pNotify->pitem; if ( _hdsaColumns && (pNotify->iItem < DSA_GetItemCount(_hdsaColumns)) ) { LPCOLUMN pColumn = (LPCOLUMN)DSA_GetItemPtr(_hdsaColumns, pNotify->iItem); TraceAssert(pColumn);
// store the new column width information in the column structure and
// mark the column table as dirty
if ( pitem->mask & HDI_WIDTH ) { Trace(TEXT("Column %d, cx %d (marking state as dirty)"), pNotify->iItem, pitem->cxy); pColumn->cx = pitem->cxy; _fColumnsModified = TRUE; } if ( pitem->mask & HDI_FILTER ) { Trace(TEXT("Filter for column %d has been changed"), pNotify->iItem); _GetFilterValue(pNotify->iItem, pitem); } }
break; }
case LVN_GETDISPINFO: { LV_DISPINFO* pNotify = (LV_DISPINFO*)lParam; TraceAssert(pNotify);
if ( pNotify && (pNotify->item.mask & LVIF_TEXT) && pNotify->item.lParam ) { LPQUERYRESULT pResult = (LPQUERYRESULT)pNotify->item.lParam; INT iColumn = pNotify->item.iSubItem;
pNotify->item.pszText[0] = TEXT('\0'); // nothing to display yet
switch ( pResult->aColumn[iColumn].iPropertyType ) { case PROPERTY_ISUNDEFINED: break;
case PROPERTY_ISUNKNOWN: case PROPERTY_ISSTRING: { if ( pResult->aColumn[iColumn].pszText ) StrCpyN(pNotify->item.pszText, pResult->aColumn[iColumn].pszText, pNotify->item.cchTextMax);
break; } case PROPERTY_ISNUMBER: case PROPERTY_ISBOOL: wsprintf(pNotify->item.pszText, TEXT("%d"), pResult->aColumn[iColumn].iValue); break; }
lr = TRUE; // we formatted a value
}
break; }
case LVN_ITEMACTIVATE: { LPNMHDR pNotify = (LPNMHDR)lParam; DWORD dwFlags = CMF_NORMAL; HWND hwndFrame; HMENU hMenu; UINT uID;
// convert the current selection to IDLITs and an IContextMenu interface
// that we can then get the default verb from.
SetWaitCursor();
hres = _GetContextMenu(); FailGracefully(hres, "Failed when calling _GetContextMenu");
_fNoSelection = !ListView_GetSelectedCount(_hwndView);
if ( !_fNoSelection ) { // create a popup menu pickup the context menu for the current selection
// and then pass it down to the invoke command handler.
hMenu = CreatePopupMenu(); TraceAssert(hMenu);
if ( hMenu ) { if ( GetKeyState(VK_SHIFT) < 0 ) dwFlags |= CMF_EXPLORE; // SHIFT + dblclick does a Explore by default
_GetContextMenuVerbs(hMenu, dwFlags);
uID = GetMenuDefaultItem(hMenu, MF_BYCOMMAND, 0); Trace(TEXT("Default uID after double click %08x"), uID);
if ( uID != -1 ) { _pqf->GetWindow(&hwndFrame); InvokeCommand(hwndFrame, uID); }
DoRelease(_pcm); // no longer needed
DestroyMenu(hMenu); } }
break; }
case LVN_COLUMNCLICK: { NM_LISTVIEW* pNotify = (NM_LISTVIEW*)lParam; TraceAssert(pNotify); _SortResults(pNotify->iSubItem); break; }
default: lr = DefWindowProc(hWnd, WM_NOTIFY, wParam, lParam); break; }
exit_gracefully:
ResetWaitCursor();
TraceLeaveValue(lr); }
/*-----------------------------------------------------------------------------
/ CDsQuery::OnAddResults / ---------------------- / The background thread has sent us some results, so lets add them to / the DPA of results, discarding the ones we don't add because we cannot / grow the DPA. / / dwQueryReference conatins the reference ID for this query, only add / results where these match. / / In: / dwQueryReference = reference that this block is for / hdpaResults = DPA containing the results to add / / Out: / HRESULT /----------------------------------------------------------------------------*/ HRESULT CDsQuery::OnAddResults(DWORD dwQueryReference, HDPA hdpaResults) { HRESULT hres; INT i, iPopulateFrom;
TraceEnter(TRACE_VIEW, "CDsQuery::OnAddResults");
if ( (dwQueryReference != _dwQueryReference) || !hdpaResults ) ExitGracefully(hres, E_FAIL, "Failed to add results, bad DPA/reference ID");
// the caller gives us a DPA then we add them to our result DPA, we then
// update the view populating from the first item we added.
iPopulateFrom = DPA_GetPtrCount(_hdpaResults);
for ( i = DPA_GetPtrCount(hdpaResults); --i >= 0 ; ) { LPQUERYRESULT pResult = (LPQUERYRESULT)DPA_GetPtr(hdpaResults, i); TraceAssert(pResult);
// add the result to the main DPA, if that fails then ensure we nuke
// this result blob!
if ( -1 == DPA_AppendPtr(_hdpaResults, pResult) ) FreeQueryResult(pResult, DSA_GetItemCount(_hdsaColumns));
DPA_DeletePtr(hdpaResults, i); // remove from result DPA
}
_PopulateView(iPopulateFrom, DPA_GetPtrCount(_hdpaResults));
TraceAssert(DPA_GetPtrCount(hdpaResults) == 0); DPA_Destroy(hdpaResults);
hres = S_OK;
exit_gracefully:
TraceLeaveResult(hres); }
/*-----------------------------------------------------------------------------
/ CDsQuery::OnContextMenu / ----------------------- / The user has right clicked in the result view, therefore we must attempt / to display the context menu for those objects / / In: / hwndMenu = window that that the user menued over / pt = point to show the context menu / / Out: / - /----------------------------------------------------------------------------*/ LRESULT CDsQuery::OnContextMenu(HWND hwndMenu, LPARAM lParam) { HRESULT hres; HMENU hMenu = NULL; POINT pt = { 0, 0 }; INT i; RECT rc; HWND hwndFrame;
TraceEnter(TRACE_VIEW, "CDsQuery::OnContextMenu");
// Collect the selection, obtaining a IContextMenu interface pointer, or a HR == S_FALSE
// if there is no selection for us to be using.
hres = _GetContextMenu(); FailGracefully(hres, "Failed when calling _GetContextMenu()");
_fNoSelection = !ListView_GetSelectedCount(_hwndView);
if ( !(hMenu = CreatePopupMenu()) ) ExitGracefully(hres, E_FAIL, "Failed to create the popup menu");
if ( !_fNoSelection ) { // pick up the context menu that maps tot he current selection, including fixing
// the "select" verb if we need one.
_GetContextMenuVerbs(hMenu, CMF_NORMAL); } else { // There is no selection so lets pick up the view bg menu, this contains
// some useful helpers for modifying the view state.
HMENU hBgMenu = LoadMenu(GLOBAL_HINSTANCE, MAKEINTRESOURCE(IDR_VIEWBACKGROUND));
if ( !hBgMenu ) ExitGracefully(hres, E_FAIL, "Failed to load pop-up menu for the background");
Shell_MergeMenus(hMenu, GetSubMenu(hBgMenu, 0), 0, 0, CQID_MAXHANDLERMENUID, 0x0); DestroyMenu(hBgMenu);
_InitViewMenuItems(hMenu); }
// if lParam == -1 then we know that the user hit the "context menu" key
// so lets set the co-ordinates of the item.
if ( lParam == (DWORD)-1 ) { i = ListView_GetNextItem(_hwndView, -1, LVNI_FOCUSED|LVNI_SELECTED); Trace(TEXT("Item with focus + selection: %d"), i);
if ( i == -1 ) { i = ListView_GetNextItem(_hwndView, -1, LVNI_SELECTED); Trace(TEXT("1st selected item: %D"), i); }
if ( i != -1 ) { TraceMsg("We have an item, so getting bounds of the icon for position"); ListView_GetItemRect(_hwndView, i, &rc, LVIR_ICON); pt.x = (rc.left+rc.right)/2; pt.y = (rc.top+rc.bottom)/2; }
MapWindowPoints(_hwndView, HWND_DESKTOP, &pt, 1); // they are in client co-ordinates
} else { pt.x = GET_X_LPARAM(lParam); pt.y = GET_Y_LPARAM(lParam); } // we have the position so lets use it
_pqf->GetWindow(&hwndFrame); TrackPopupMenu(hMenu, TPM_LEFTALIGN, pt.x, pt.y, 0, hwndFrame, NULL);
exit_gracefully:
if ( hMenu ) DestroyMenu(hMenu);
TraceLeaveValue(0); }
/*-----------------------------------------------------------------------------
/ CDsQuery::OnFileProperties / -------------------------- / Show properties for the given selection. To do this we CoCreate / IDsFolderProperties on the IDsFolder implementation and that / we can invoke properties using. / / In: / Out: / HRESULT /----------------------------------------------------------------------------*/ HRESULT CDsQuery::OnFileProperties(VOID) { HRESULT hres; IDataObject* pDataObject = NULL; IDsFolderProperties* pDsFolderProperties = NULL;
TraceEnter(TRACE_VIEW, "CDsQuery::OnFileProperties");
hres = GetViewObject(CQRVS_SELECTION, IID_IDataObject, (void **)&pDataObject); FailGracefully(hres, "Failed to get IDataObject for shortcut creation");
hres = CoCreateInstance(CLSID_DsFolderProperties, NULL, CLSCTX_INPROC_SERVER, IID_IDsFolderProperties, (void **)&pDsFolderProperties); FailGracefully(hres, "Failed to get IDsFolderProperties for the desktop object");
hres = pDsFolderProperties->ShowProperties(_hwnd, pDataObject); FailGracefully(hres, "Failed to invoke property UI for the given selection");
// hres = S_OK; // success
exit_gracefully: DoRelease(pDataObject); DoRelease(pDsFolderProperties);
TraceLeaveResult(hres); }
/*-----------------------------------------------------------------------------
/ CDsQuery::OnFileSaveQuery / ------------------------- / Allow the user to choose a location to save the query (initial directory / is nethood). Having done that we then start the save process by passing / the frame object a IQueryIO object that allows them to persist the / query into. / / In: / Out: / HRESULT /----------------------------------------------------------------------------*/ HRESULT CDsQuery::OnFileSaveQuery(VOID) { HRESULT hres; OPENFILENAME ofn; TCHAR szFilename[MAX_PATH]; TCHAR szDirectory[MAX_PATH]; TCHAR szFilter[64]; TCHAR szTitle[64]; LPTSTR pFilter; IPersistQuery *ppq = NULL; USES_CONVERSION;
TraceEnter(TRACE_VIEW, "CDsQuery::OnFileSaveQuery");
// Load the default strings and fix up the filter string as it needs
// NULL's seperating the various resource sections.
LoadString(GLOBAL_HINSTANCE, IDS_SAVETITLE, szTitle, ARRAYSIZE(szTitle)); StrCpy(szFilename, _pDefaultSaveName); LoadString(GLOBAL_HINSTANCE, IDS_SAVEFILTER, szFilter, ARRAYSIZE(szFilter));
for ( pFilter = szFilter ; *pFilter ; pFilter++ ) { if ( *pFilter == TEXT('\n') ) *pFilter = TEXT('\0'); }
// fix the open filename structure ready to do our save....
ZeroMemory(&ofn, SIZEOF(ofn));
ofn.lStructSize = SIZEOF(ofn); _pqf->GetWindow(&ofn.hwndOwner); ofn.hInstance = GLOBAL_HINSTANCE; ofn.lpstrFilter = szFilter; ofn.lpstrFile = szFilename; ofn.nMaxFile = ARRAYSIZE(szFilename);
if ( _pDefaultSaveLocation ) { Trace(TEXT("Saving into: %s"), W2T(_pDefaultSaveLocation)); StrCpy(szDirectory, W2T(_pDefaultSaveLocation)); ofn.lpstrInitialDir = szDirectory; }
ofn.lpstrTitle = szTitle; ofn.Flags = OFN_EXPLORER|OFN_NOCHANGEDIR|OFN_OVERWRITEPROMPT|OFN_PATHMUSTEXIST|OFN_HIDEREADONLY; ofn.lpstrDefExt = TEXT("dsq");
// If we get a save filename then lets ensure that we delete the previous
// query saved there (if there is one) and then we can create an IPersistQuery
// object that will save to that location.
if ( GetSaveFileName(&ofn) ) { Trace(TEXT("Saving query as: %s"), szFilename);
if ( !DeleteFile(szFilename) && (GetLastError() != ERROR_FILE_NOT_FOUND) ) ExitGracefully(hres, E_FAIL, "Failed to delete previous query");
hres = CPersistQuery_CreateInstance(szFilename, &ppq); FailGracefully(hres, "Failed to create the peristance object");
hres = _pqf->SaveQuery(ppq); FailGracefully(hres, "Failed when calling IQueryFrame::SaveSearch"); }
hres = S_OK;
exit_gracefully:
DoRelease(ppq);
TraceLeaveResult(hres); }
/*-----------------------------------------------------------------------------
/ CDsQuery::OnEditSelectAll / ------------------------- / Walk all the items in the view setting their selected state. / / In: / Out: / HRESULT /----------------------------------------------------------------------------*/ HRESULT CDsQuery::OnEditSelectAll(VOID) { TraceEnter(TRACE_VIEW, "CDsQuery::OnEditSelectAll");
for ( INT i = ListView_GetItemCount(_hwndView) ; --i >= 0 ; ) { ListView_SetItemState(_hwndView, i, LVIS_SELECTED, LVIS_SELECTED); }
TraceLeaveResult(S_OK); }
/*-----------------------------------------------------------------------------
/ CDsQuery::OnEditInvertSelection / ------------------------------- / Walk all the items in the view and invert their selected state. / / In: / Out: / HRESULT /----------------------------------------------------------------------------*/ HRESULT CDsQuery::OnEditInvertSelection(VOID) { TraceEnter(TRACE_VIEW, "CDsQuery::OnEditInvertSelection");
for ( INT i = ListView_GetItemCount(_hwndView) ; --i >= 0 ; ) { DWORD dwState = ListView_GetItemState(_hwndView, i, LVIS_SELECTED); ListView_SetItemState(_hwndView, i, dwState ^ LVIS_SELECTED, LVIS_SELECTED); }
TraceLeaveResult(S_OK); }
/*-----------------------------------------------------------------------------
/ CDsQuery::_InitNewQuery / ---------------------- / Initialize the view ready for a new query, including setting the frame / into a query running state. / / In: / pDsQueryParams = DSQUERYPARAMs structure used to issue the query. / fRefreshColumnTable = re-read the column table from the params/registry etc / / Out: / HRESULT /----------------------------------------------------------------------------*/ HRESULT CDsQuery::_InitNewQuery(LPDSQUERYPARAMS pDsQueryParams, BOOL fRefreshColumnTable) { HRESULT hres; LPTSTR pBuffer;
TraceEnter(TRACE_VIEW, "CDsQuery::_InitNewQuery");
hres = _pqf->StartQuery(TRUE); TraceAssert(SUCCEEDED(hres));
// Claim the cached DS object for this window
// if refreshing the column table then _GetColumnTable handles this all for us,
// otherwise lets just nuke the result set ourselves.
if ( fRefreshColumnTable ) { _SaveColumnTable();
hres = _GetColumnTable(_clsidForm, pDsQueryParams, &_hdsaColumns, TRUE); FailGracefully(hres, "Failed to create column DSA"); } else { _FreeResults(); }
// initialize the view to start the query running, display the prompt banner and
// initialize the result DPA.
_ShowBanner(SWP_SHOWWINDOW, IDS_SEARCHING); // we are now searching
if ( SUCCEEDED(FormatMsgResource(&pBuffer, GLOBAL_HINSTANCE, IDS_SEARCHING)) ) { _pqf->SetStatusText(pBuffer); LocalFreeString(&pBuffer); }
TraceAssert(_hdpaResults==NULL); // should never catch
_hdpaResults = DPA_Create(16); TraceAssert(_hdpaResults);
if ( !_hdpaResults ) ExitGracefully(hres, E_OUTOFMEMORY, "Failed to allocate result DPA");
_dwQueryReference++;
exit_gracefully:
TraceLeaveResult(hres); }
/*-----------------------------------------------------------------------------
/ CDsQuery::_GetFilterValue / ------------------------ / Given a column index collect the filter value from it, note that / when doing this / / In: / i = column to retrieve / pitem -> HD_ITEM structure for the current filter / == NULL then read from header / / Out: / HRESULT /----------------------------------------------------------------------------*/ HRESULT CDsQuery::_GetFilterValue(INT i, HD_ITEM* pitem) { HRESULT hres; HD_ITEM hdi; HD_TEXTFILTER textFilter; TCHAR szBuffer[MAX_PATH]; INT iValue; UINT cchFilter = 0; LPCOLUMN pColumn = (LPCOLUMN)DSA_GetItemPtr(_hdsaColumns, i);
if (!pColumn) ExitGracefully(hres, E_FAIL, "Failed to get the column");
TraceEnter(TRACE_VIEW, "CDsQuery::_GetFilterValue");
// if pitem == NULL then lets pick up the filter value from the
// header control, using the stored property type (the filter one
// has already been nuked) to defined which filter we want.
if ( !pitem ) { hdi.mask = HDI_FILTER;
switch ( pColumn->iPropertyType ) { case PROPERTY_ISUNKNOWN: case PROPERTY_ISSTRING: { hdi.type = HDFT_ISSTRING; hdi.pvFilter = &textFilter; textFilter.pszText = szBuffer; textFilter.cchTextMax = ARRAYSIZE(szBuffer); break; }
case PROPERTY_ISNUMBER: case PROPERTY_ISBOOL: { hdi.type = HDFT_ISNUMBER; hdi.pvFilter = &iValue; break; } }
if ( !Header_GetItem(ListView_GetHeader(_hwndView), i, &hdi) ) ExitGracefully(hres, E_FAIL, "Failed to get the filter string");
pitem = &hdi; }
// discard the previous filter value and lets read from the
// structure the information we need to cache our filter information
FreeColumnValue(&pColumn->filter);
if ( !(pitem->type & HDFT_HASNOVALUE) && pitem->pvFilter ) { switch ( pitem->type & HDFT_ISMASK ) { case HDFT_ISSTRING: { LPHD_TEXTFILTER ptextFilter = (LPHD_TEXTFILTER)pitem->pvFilter; TraceAssert(ptextFilter);
pColumn->filter.iPropertyType = PROPERTY_ISSTRING;
// text filters are stored in their wildcarded state, therefore
// filtering doesn't require converting from the text form
// to something more elobrate each pass through. the down
// side is when the operator changes we must rebuild the
// filter string for that column (small price)
GetPatternString(NULL, &cchFilter, pColumn->idOperator, ptextFilter->pszText); TraceAssert(cchFilter != 0);
if ( cchFilter ) { hres = LocalAllocStringLen(&pColumn->filter.pszText, cchFilter); FailGracefully(hres, "Failed to allocate buffer to read string into");
GetPatternString(pColumn->filter.pszText, &cchFilter, pColumn->idOperator, ptextFilter->pszText); Trace(TEXT("Filter (with pattern info): %s"), pColumn->filter.pszText);
LCMapString(0x0, LCMAP_UPPERCASE, pColumn->filter.pszText, -1, pColumn->filter.pszText, cchFilter+1); Trace(TEXT("After converting to uppercase (LCMapString): %s"), pColumn->filter.pszText); }
break; }
case HDFT_ISNUMBER: { INT* piFilter = (INT*)pitem->pvFilter; TraceAssert(piFilter);
pColumn->filter.iPropertyType = PROPERTY_ISNUMBER; pColumn->filter.iValue = *piFilter; Trace(TEXT("Filter: %d"), pColumn->filter.iValue);
break; } } }
hres = S_OK;
exit_gracefully:
TraceLeaveResult(hres); }
/*-----------------------------------------------------------------------------
/ CDsQuery::_FilterView / -------------------- / Filter the result set populating the view again with the changes / / In: / fCheck / / Out: / HRESULT /----------------------------------------------------------------------------*/
UINT _GetFilter(HDSA hdsaColumns, LPTSTR pBuffer, UINT* pcchBuffer) { INT i; TCHAR szBuffer[MAX_PATH];
TraceEnter(TRACE_VIEW, "_GetFilter"); TraceAssert(hdsaColumns && pcchBuffer);
*pcchBuffer = 0;
// form the string containin [operatorID]value pairs for each of the
// filter columns that is defined.
for ( i = 0 ; i < DSA_GetItemCount(hdsaColumns); i++ ) { LPCOLUMN pColumn = (LPCOLUMN)DSA_GetItemPtr(hdsaColumns, i); TraceAssert(pColumn);
if ( pColumn->filter.iPropertyType != PROPERTY_ISUNDEFINED ) { wsprintf(szBuffer, TEXT("[%d]"), pColumn->idOperator); PutStringElement(pBuffer, pcchBuffer, szBuffer);
switch ( pColumn->filter.iPropertyType ) { case PROPERTY_ISUNDEFINED: break;
case PROPERTY_ISUNKNOWN: case PROPERTY_ISSTRING: PutStringElement(pBuffer, pcchBuffer, pColumn->filter.pszText); break;
case PROPERTY_ISNUMBER: case PROPERTY_ISBOOL: wsprintf(szBuffer, TEXT("%d"), pColumn->filter.iValue); PutStringElement(pBuffer, pcchBuffer, szBuffer); break; } } }
Trace(TEXT("pBuffer contains: %s (%d)"), pBuffer ? pBuffer:TEXT("<NULL>"), *pcchBuffer);
TraceLeaveValue(*pcchBuffer); }
HRESULT CDsQuery::_FilterView(BOOL fCheck) { HRESULT hres = S_OK; LPTSTR pFilter = NULL; UINT cchFilter; BOOL fSetCursor = FALSE;
TraceEnter(TRACE_VIEW, "CDsQuery::_FilterView"); if ( !_hdpaResults ) ExitGracefully(hres, S_OK, "FitlerView bailing, no results");
DECLAREWAITCURSOR; SetWaitCursor(); // this could take some time
fSetCursor = TRUE; // get the current filter string, this consists of the filter
// information from all the columns
if ( _GetFilter(_hdsaColumns, NULL, &cchFilter) ) { hres = LocalAllocStringLen(&pFilter, cchFilter); FailGracefully(hres, "Failed to allocate filter string");
_GetFilter(_hdsaColumns, pFilter, &cchFilter); }
// if the filters don't match then re-populate the view,
// as the criteria for the results has changed
if ( !fCheck || (!pFilter || !_pFilter) || (pFilter && _pFilter && StrCmpI(pFilter, _pFilter)) ) { LPTSTR pBuffer;
TraceMsg("Filtering the view, filters differ");
ListView_DeleteAllItems(_hwndView); _ShowBanner(SWP_SHOWWINDOW, IDS_FILTERING);
if ( SUCCEEDED(FormatMsgResource(&pBuffer, GLOBAL_HINSTANCE, IDS_FILTERING)) ) { _pqf->SetStatusText(pBuffer); LocalFreeString(&pBuffer); } _PopulateView(0, DPA_GetPtrCount(_hdpaResults)); }
// ensure we hang onto the new filter, discarding the previous one
LocalFreeString(&_pFilter); _pFilter = pFilter;
exit_gracefully:
if (fSetCursor) ResetWaitCursor();
TraceLeaveResult(hres); }
/*-----------------------------------------------------------------------------
/ CDsQuery::_PopulateView / ---------------------- / Add items from the result DPA to the view filtering as required. The / caller gives us the start index (0 if all) and we walk the results / adding them to the view. / / In: / iItem = first item to add / == 0 first / == -1 then add none, just update status / iLast = last item to be updated / / Out: / HRESULT /----------------------------------------------------------------------------*/ HRESULT CDsQuery::_PopulateView(INT iItem, INT iLast) { HRESULT hres; BOOL fBannerShown = IsWindowVisible(_hwndBanner); LPTSTR pBuffer = NULL; LV_ITEM lvi; INT iColumn, i; INT iVisible = 0; INT iHidden = 0; BOOL fIncludeItem; MSG msg; USES_CONVERSION;
TraceEnter(TRACE_VIEW, "CDsQuery::_PopulateView"); Trace(TEXT("Range %d to %d"), iItem, iLast);
if ( iItem > -1 ) { Trace(TEXT("Adding items %d to %d"), iItem, DPA_GetPtrCount(_hdpaResults));
lvi.mask = LVIF_TEXT|LVIF_PARAM|LVIF_IMAGE; lvi.iItem = 0x7fffffff; lvi.iSubItem = 0; lvi.pszText = LPSTR_TEXTCALLBACK;
// Walk the results in the range we need to add and add them to the view
// applying the filter to remove items we are not interested in.
for ( i = 0; iItem < iLast ; i++, iItem++ ) { LPQUERYRESULT pResult = (LPQUERYRESULT)DPA_GetPtr(_hdpaResults, iItem);
if (!pResult) continue;
fIncludeItem = TRUE; // new items always get included
// if the filter is visilbe then lets walk it removing items from the list
// of results. fIncludeItem starts as TRUE and after the filter
// loop should become either TRUE/FALSE. All columns are ANDed together
// therefore the logic is quite simple.
if ( _fFilter ) { for ( iColumn = 0 ; fIncludeItem && (iColumn < DSA_GetItemCount(_hdsaColumns)); iColumn++ ) { LPCOLUMN pColumn = (LPCOLUMN)DSA_GetItemPtr(_hdsaColumns, iColumn); TraceAssert(pColumn);
// if the column has a filter defined (!PROPERTY_ISUNDEFINED) then
// check that the properties match, if they don't then skip the
// itmer otherwise lets try applying the filter based on
// the type.
if ( pColumn->filter.iPropertyType == PROPERTY_ISUNDEFINED ) continue;
if ( pResult->aColumn[iColumn].iPropertyType == PROPERTY_ISUNDEFINED ) { // column is undefined therefore lets ignore it, it won't
// match the criteria
fIncludeItem = FALSE; } else { switch ( pColumn->filter.iPropertyType ) { case PROPERTY_ISUNDEFINED: break;
case PROPERTY_ISUNKNOWN: case PROPERTY_ISSTRING: { TCHAR szBuffer[MAX_PATH]; LPTSTR pszBuffer = NULL; LPTSTR pszValue = pResult->aColumn[iColumn].pszText; INT cchValue = lstrlen(pszValue); LPTSTR pszValueUC = szBuffer;
// the filter value is stored in uppercase, so to ensure we are case insensitive
// we must convert the string to uppercase. We have a buffer we will use,
// however, if the value is too large we will allocate a buffer we can use.
if ( cchValue > ARRAYSIZE(szBuffer) ) { TraceMsg("Value too big for our static buffer, so allocating"); if ( FAILED(LocalAllocStringLen(&pszBuffer, cchValue)) ) { TraceMsg("Failed to allocate a buffer for the string, so ignoring it!"); fIncludeItem = FALSE; break; }
pszValueUC = pszBuffer; // fix the pointer to the new string
}
LCMapString(0x0, LCMAP_UPPERCASE, pszValue, -1, pszValueUC, cchValue+1); Trace(TEXT("After converting to uppercase (LCMapString): %s"), pszValueUC);
// string properties need to be compared using the match filter
// function, this code is given the filter and the result
// and we must compare, in return we get TRUE/FALSE, therefore
// catch the NOT cases specificly.
switch ( pColumn->idOperator ) { case FILTER_CONTAINS: case FILTER_STARTSWITH: case FILTER_ENDSWITH: case FILTER_IS: fIncludeItem = MatchPattern(pszValueUC, pColumn->filter.pszText); break;
case FILTER_NOTCONTAINS: case FILTER_ISNOT: fIncludeItem = !MatchPattern(pszValueUC, pColumn->filter.pszText); break; }
LocalFreeString(&pszBuffer); // ensure we don't leak, in thise case it would be costly!
break; }
case PROPERTY_ISBOOL: case PROPERTY_ISNUMBER: { // numeric properties are handled only as ints, therefore
// lets compare the numeric value we have
switch ( pColumn->idOperator ) { case FILTER_IS: fIncludeItem = (pColumn->filter.iValue == pResult->aColumn[iColumn].iValue); break;
case FILTER_ISNOT: fIncludeItem = (pColumn->filter.iValue != pResult->aColumn[iColumn].iValue); break;
case FILTER_GREATEREQUAL: fIncludeItem = (pColumn->filter.iValue <= pResult->aColumn[iColumn].iValue); break;
case FILTER_LESSEQUAL: fIncludeItem = (pColumn->filter.iValue >= pResult->aColumn[iColumn].iValue); break; }
break; } } } } } Trace(TEXT("fInclude item is %d"), fIncludeItem);
if ( fIncludeItem ) { // we are going to add the item to the view, so lets hide the banner
// if it is shown, then add a list view item. The list view
// item has text-callback and the lParam -> pResult structure
// we are using.
//
// also, if the view hasn't had the image list set then lets
// take care of that now
if ( fBannerShown ) { TraceMsg("Adding an item and banner visible, therefore hiding"); _ShowBanner(SWP_HIDEWINDOW, 0); // hide the banner
fBannerShown = FALSE; }
lvi.lParam = (LPARAM)pResult; lvi.iImage = pResult->iImage; ListView_InsertItem(_hwndView, &lvi);
if ( i % FILTER_UPDATE_COUNT ) UpdateWindow(_hwndView); } } }
// lets update the status bar to reflect the world around us
TraceAssert(_hdpaResults);
if ( _hdpaResults ) { iVisible = ListView_GetItemCount(_hwndView); iHidden = DPA_GetPtrCount(_hdpaResults)-iVisible; }
if ( iVisible <= 0 ) { _ShowBanner(SWP_SHOWWINDOW, IDS_NOTHINGFOUND); } else { // ensure that at least one item in the view has focus
if ( -1 == ListView_GetNextItem(_hwndView, -1, LVNI_FOCUSED) ) ListView_SetItemState(_hwndView, 0, LVIS_FOCUSED, LVIS_FOCUSED); } if ( SUCCEEDED(FormatMsgResource(&pBuffer, GLOBAL_HINSTANCE, iHidden ? IDS_FOUNDITEMSHIDDEN:IDS_FOUNDITEMS, iVisible, iHidden)) ) { Trace(TEXT("Setting status text to: %s"), pBuffer); _pqf->SetStatusText(pBuffer); LocalFreeString(&pBuffer); }
_iSortColumn = -1; // sort is no longer valid!
TraceLeaveResult(S_OK); }
/*-----------------------------------------------------------------------------
/ CDsQuery::_FreeResults / --------------------- / Do the tidy up to release the results from the view. This includes / destroying the DPA and removing the items from the list view. / / In: / Out: / - /----------------------------------------------------------------------------*/ VOID CDsQuery::_FreeResults(VOID) { TraceEnter(TRACE_VIEW, "CDsQuery::_FreeResults");
if ( IsWindow(_hwndView) ) ListView_DeleteAllItems(_hwndView);
if ( _hdpaResults ) { DPA_DestroyCallback(_hdpaResults, FreeQueryResultCB, IntToPtr(DSA_GetItemCount(_hdsaColumns))); _hdpaResults = NULL; }
LocalFreeString(&_pFilter);
TraceLeave(); }
/*-----------------------------------------------------------------------------
/ CDsQuery::_SetViewMode / --------------------- / Convert the command ID of the view mode into a LVS_ style bit that can / then we applied to the view. / / In: / uID = view mode to be selected / / Out: / DWORD = LVS_ style for this view mode /----------------------------------------------------------------------------*/ DWORD CDsQuery::_SetViewMode(INT uID) { const DWORD dwIdToStyle[] = { LVS_ICON, LVS_SMALLICON, LVS_LIST, LVS_REPORT }; DWORD dwResult = 0; DWORD dwStyle; TraceEnter(TRACE_HANDLER|TRACE_VIEW, "CDsQuery::_SetViewMode"); Trace(TEXT("Setting view mode to %08x"), uID);
_idViewMode = uID; uID -= DSQH_VIEW_LARGEICONS;
if ( uID < ARRAYSIZE(dwIdToStyle ) ) { dwResult = dwIdToStyle[uID];
if ( IsWindow(_hwndView) ) { dwStyle = GetWindowLong(_hwndView, GWL_STYLE);
if ( ( dwStyle & LVS_TYPEMASK ) != dwResult ) { TraceMsg("Changing view style to reflect new mode"); SetWindowLong(_hwndView, GWL_STYLE, (dwStyle & ~LVS_TYPEMASK)|dwResult); } } }
_ShowBanner(0, 0);
TraceLeaveValue(dwResult); }
/*-----------------------------------------------------------------------------
/ CDsQuery::_SetFilter / ------------------- / Sets the visible state of the filter, refreshing the view as required. / / NB: To ensure that the ListView correctly refrehes its contents we first / remove the header from the view, then toggle the filter state / and re-enable the banner. / In: / fFilter = flag indicating the filter state / / Out: / VOID /----------------------------------------------------------------------------*/ VOID CDsQuery::_SetFilter(BOOL fFilter) { TraceEnter(TRACE_HANDLER|TRACE_VIEW, "CDsQuery::_SetFilter");
_fFilter = fFilter; // store the new filter value
if ( IsWindow(_hwndView) ) { HWND hwndHeader = ListView_GetHeader(_hwndView); DWORD dwStyle = GetWindowLong(hwndHeader, GWL_STYLE) & ~(HDS_FILTERBAR|WS_TABSTOP);
SetWindowLong(_hwndView, GWL_STYLE, GetWindowLong(_hwndView, GWL_STYLE) | LVS_NOCOLUMNHEADER);
if ( _fFilter ) dwStyle |= HDS_FILTERBAR|WS_TABSTOP;
SetWindowLong(hwndHeader, GWL_STYLE, dwStyle); SetWindowLong(_hwndView, GWL_STYLE, GetWindowLong(_hwndView, GWL_STYLE) & ~LVS_NOCOLUMNHEADER);
_ShowBanner(0, 0);
if ( _hdpaResults ) { if ( (_fFilter && _pFilter) || (!_fFilter && (DPA_GetPtrCount(_hdpaResults) != ListView_GetItemCount(_hwndView))) ) { _FilterView(FALSE); } } } TraceLeave(); }
/*-----------------------------------------------------------------------------
/ CDsQuery::_SortResults / --------------------- / Sort the view given a column, handles either being clicked or / invoked on from an API. / / In: / iColumn = column to sort on / / Out: / - /----------------------------------------------------------------------------*/
INT _ResultSortCB(LPARAM lParam1, LPARAM lParam2, LPARAM lParam) { LPQUERYRESULT pResult1, pResult2; INT iColumn = LOWORD(lParam);
// if lParam != 0 then we are reverse sorting, therefore swap
// over the object pointers
if ( !HIWORD(lParam) ) { pResult1 = (LPQUERYRESULT)lParam1; pResult2 = (LPQUERYRESULT)lParam2; } else { pResult2 = (LPQUERYRESULT)lParam1; pResult1 = (LPQUERYRESULT)lParam2; }
if ( pResult1 && pResult2 ) { LPCOLUMNVALUE pColumn1 = (LPCOLUMNVALUE)&pResult1->aColumn[iColumn]; LPCOLUMNVALUE pColumn2 = (LPCOLUMNVALUE)&pResult2->aColumn[iColumn]; BOOL fHasColumn1 = pColumn1->iPropertyType != PROPERTY_ISUNDEFINED; BOOL fHasColumn2 = pColumn2->iPropertyType != PROPERTY_ISUNDEFINED;
// check that both properties are defined, if they are not then return the
// comparison based on that field. then we check that the properties
// are the same type, if that matches then lets compare based on the
// type.
if ( !fHasColumn1 || !fHasColumn2 ) { return fHasColumn1 ? -1:+1; } else { TraceAssert(pColumn1->iPropertyType == pColumn2->iPropertyType);
switch ( pColumn1->iPropertyType ) { case PROPERTY_ISUNDEFINED: break;
case PROPERTY_ISUNKNOWN: case PROPERTY_ISSTRING: return StrCmpI(pColumn1->pszText, pColumn2->pszText);
case PROPERTY_ISBOOL: case PROPERTY_ISNUMBER: return pColumn1->iValue - pColumn2->iValue; } } } return 0; }
VOID CDsQuery::_SortResults(INT iColumn) { DECLAREWAITCURSOR; TraceEnter(TRACE_VIEW, "CDsQuery::_SortResults"); Trace(TEXT("iColumn %d"), iColumn);
if ( (iColumn >= 0) && (iColumn < DSA_GetItemCount(_hdsaColumns)) ) { // if we have already hit the column then lets invert the sort order,
// there is no indicator to worry about so this should just work out
// fine. if we haven't used this column before then default oto
// ascending, then do the sort!
//
// ensure that the focused item is visible when the sort has completed
if ( _iSortColumn == iColumn ) _fSortDescending = !_fSortDescending; else _fSortDescending = FALSE;
_iSortColumn = iColumn;
Trace(TEXT("Sorting on column %d, %s"), _iSortColumn, _fSortDescending ? TEXT("(descending)"):TEXT("(ascending)"));
SetWaitCursor(); ListView_SortItems(_hwndView, _ResultSortCB, MAKELPARAM(_iSortColumn, _fSortDescending)); ResetWaitCursor(); }
TraceLeave(); }
/*-----------------------------------------------------------------------------
/ CDsQuery::_ShowBanner / -------------------- / Show the views banner, including sizing it to obscure only the top section / of the window. / / In: / uFlags = flags to combine when calling SetWindowPos / idPrompt = resource ID of prompt text ot be displayed / / Out: / - /----------------------------------------------------------------------------*/ VOID CDsQuery::_ShowBanner(UINT uFlags, UINT idPrompt) { HRESULT hres; WINDOWPOS wpos; RECT rcClient; HD_LAYOUT hdl; TCHAR szBuffer[MAX_PATH];
TraceEnter(TRACE_VIEW, "CDsQuery::_ShowBanner");
// if we have a resource id then lets load the string and
// set the window text to have it
if ( idPrompt ) { LoadString(GLOBAL_HINSTANCE, idPrompt, szBuffer, ARRAYSIZE(szBuffer)); SetWindowText(_hwndBanner, szBuffer); }
// now position the window back to real location, this we need to
// talk to the listview/header control to work out exactly where it
// should be living
GetClientRect(_hwndView, &rcClient);
if ( (GetWindowLong(_hwndView, GWL_STYLE) & LVS_TYPEMASK) == LVS_REPORT ) { TraceMsg("Calling header for layout information");
wpos.hwnd = ListView_GetHeader(_hwndView); wpos.hwndInsertAfter = NULL; wpos.x = 0; wpos.y = 0; wpos.cx = rcClient.right; wpos.cy = rcClient.bottom; wpos.flags = SWP_NOZORDER;
hdl.prc = &rcClient; hdl.pwpos = &wpos;
if ( !Header_Layout(wpos.hwnd, &hdl) ) ExitGracefully(hres, E_FAIL, "Failed to get the layout information (HDM_LAYOUT)"); }
SetWindowPos(_hwndBanner, HWND_TOP, rcClient.left, rcClient.top, rcClient.right - rcClient.left, 100, uFlags);
exit_gracefully:
TraceLeave(); }
/*-----------------------------------------------------------------------------
/ CDsQuery::_InitViewMenuItems / --------------------------- / Setup the view menu based on the given view mode and the filter state, enabled / disable the items as required. / / In: / hMenu = menu to set the menu items on / / Out: / - /----------------------------------------------------------------------------*/ VOID CDsQuery::_InitViewMenuItems(HMENU hMenu) { MENUITEMINFO mii; HMENU hArrangeMenu; BOOL fHaveView = IsWindow(_hwndView); INT i;
TraceEnter(TRACE_HANDLER|TRACE_VIEW, "CDsQuery::_InitViewMenuItems");
CheckMenuItem(hMenu, DSQH_VIEW_FILTER, MF_BYCOMMAND| (_fFilter ? MF_CHECKED:0) ); ENABLE_MENU_ITEM(hMenu, DSQH_VIEW_FILTER, fHaveView && _fFilterSupported && (_idViewMode == DSQH_VIEW_DETAILS));
CheckMenuRadioItem(hMenu, DSQH_VIEW_LARGEICONS, DSQH_VIEW_DETAILS, _idViewMode, MF_BYCOMMAND);
// construct the arrange menu, add it to the view menu that we have been given.
hArrangeMenu = CreatePopupMenu(); TraceAssert(hArrangeMenu);
if ( _hdsaColumns && DSA_GetItemCount(_hdsaColumns) ) { TCHAR szFmt[32]; TCHAR szBuffer[MAX_PATH]; hArrangeMenu = CreatePopupMenu(); TraceAssert(hArrangeMenu);
LoadString(GLOBAL_HINSTANCE, IDS_ARRANGEBY, szFmt, ARRAYSIZE(szFmt));
if ( hArrangeMenu ) { for ( i = 0 ; i < DSA_GetItemCount(_hdsaColumns); i++ ) { LPCOLUMN pColumn = (LPCOLUMN)DSA_GetItemPtr(_hdsaColumns, i); TraceAssert(pColumn);
wsprintf(szBuffer, szFmt, pColumn->pHeading); InsertMenu(hArrangeMenu, i, MF_STRING|MF_BYPOSITION, DSQH_VIEW_ARRANGEFIRST+i, szBuffer); }
} }
// now place the arrange menu into the view and ungrey as required.
ZeroMemory(&mii, SIZEOF(mii)); mii.cbSize = SIZEOF(mii); mii.fMask = MIIM_SUBMENU|MIIM_ID; mii.hSubMenu = hArrangeMenu; mii.wID = DSQH_VIEW_ARRANGEICONS; if ( SetMenuItemInfo(hMenu, DSQH_VIEW_ARRANGEICONS, FALSE, &mii) ) { ENABLE_MENU_ITEM(hMenu, DSQH_VIEW_ARRANGEICONS, fHaveView && GetMenuItemCount(hArrangeMenu)); hArrangeMenu = NULL; }
if ( hArrangeMenu ) DestroyMenu(hArrangeMenu);
TraceLeave(); }
/*-----------------------------------------------------------------------------
/ CDsQuery::_GetQueryFormKey / -------------------------- / Given the CLSID for the query form we are interested in, get the / forms key for it, note that these settings are stored per-user. / / In: / clsidForm = CLSID of form to pick up / phKey -> recevies the HKEY of the form we are intersted in. / / Out: / HRESULT /----------------------------------------------------------------------------*/ HRESULT CDsQuery::_GetQueryFormKey(REFCLSID clsidForm, HKEY* phKey) { HRESULT hres; TCHAR szGUID[GUIDSTR_MAX]; TCHAR szBuffer[MAX_PATH];
TraceEnter(TRACE_VIEW, "CDsQuery::_GetQueryFormKey");
GetStringFromGUID(clsidForm, szGUID, ARRAYSIZE(szGUID)); wsprintf(szBuffer, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Directory UI\\QueryForms\\%s"), szGUID); Trace(TEXT("Settings key is: %s"), szBuffer);
if ( ERROR_SUCCESS != RegCreateKey(HKEY_CURRENT_USER, szBuffer, phKey) ) ExitGracefully(hres, E_FAIL, "Failed to open settings key");
hres = S_OK;
exit_gracefully:
TraceLeaveResult(hres); }
/*-----------------------------------------------------------------------------
/ CDsQuery::_GetColumnTable / ------------------------ / Build the column table for the view we are about to display. The column / table is constructed from either the query parameters or the persisted / column settings stored in the registry. / / In: / clsidForm = clisd of the form to be used / pDsQueryParams -> query parameter structure to be used / pHDSA -> DSA to recieve the column table (sorted by visible order) / fSetInView = Set the columns into the view / / Out: / HRESULT /----------------------------------------------------------------------------*/ HRESULT CDsQuery::_GetColumnTable(REFCLSID clsidForm, LPDSQUERYPARAMS pDsQueryParams, HDSA* pHDSA, BOOL fSetInView) { HRESULT hres; HKEY hKey = NULL; BOOL fDefaultSettings = TRUE; LPSAVEDCOLUMN aSavedColumn = NULL; LPTSTR pSettingsValue = VIEW_SETTINGS_VALUE; BOOL fHaveSizeInfo = FALSE; LPWSTR pProperty; DWORD dwType, cbSize; LV_COLUMN lvc; SIZE sz; INT i, iNewColumn; HD_ITEM hdi; IDsDisplaySpecifier *pdds = NULL; USES_CONVERSION;
TraceEnter(TRACE_VIEW, "CDsQuery::_GetColumnTable"); TraceGUID("clsidForm ", clsidForm); Trace(TEXT("pDsQueryParams %08x, pHDSA %08x"), pDsQueryParams, pHDSA);
DECLAREWAITCURSOR; SetWaitCursor();
if ( !pHDSA ) ExitGracefully(hres, E_INVALIDARG, "Bad pDsQueryParams / pHDSA");
// construct the column DSA then attempt to look up the view settings stored in
// the registry for the current form.
*pHDSA = DSA_Create(SIZEOF(COLUMN), 16); TraceAssert(*pHDSA);
if ( !*pHDSA ) ExitGracefully(hres, E_OUTOFMEMORY, "Failed to construct the column DSA");
// If invoked for admin UI then we look at the admin view settings, this way
// the admin can have one set of columns, and the user can have another.
if ( _dwFlags & DSQPF_ENABLEADMINFEATURES ) pSettingsValue = ADMIN_VIEW_SETTINGS_VALUE;
Trace(TEXT("View settings value: %s"), pSettingsValue);
if ( SUCCEEDED(_GetQueryFormKey(clsidForm, &hKey)) ) { // we have the handle to the forms sub-key table, now lets check and
// see what size the view settings stream is.
if ( (ERROR_SUCCESS == RegQueryValueEx(hKey, pSettingsValue, NULL, &dwType, NULL, &cbSize)) && (dwType == REG_BINARY) && (cbSize > SIZEOF(SAVEDCOLUMN)) ) { Trace(TEXT("Reading view settings from registry (size %d)"), cbSize); aSavedColumn = (LPSAVEDCOLUMN)LocalAlloc(LPTR, cbSize); TraceAssert(aSavedColumn);
if ( aSavedColumn && (ERROR_SUCCESS == RegQueryValueEx(hKey, pSettingsValue, NULL, NULL, (LPBYTE)aSavedColumn, &cbSize)) ) { // compute the size of the table from the values that we have
// read from the registry and now lets allocate a table for it
for ( i = 0; aSavedColumn[i].cbSize; i++ ) { COLUMN column = { 0 }; LPCWSTR pProperty = (LPCWSTR)ByteOffset(aSavedColumn, aSavedColumn[i].offsetProperty); LPCTSTR pHeading = (LPCTSTR)ByteOffset(aSavedColumn, aSavedColumn[i].offsetHeading);
hres = LocalAllocStringW(&column.pProperty, pProperty); FailGracefully(hres, "Failed to allocate property name");
hres = LocalAllocString(&column.pHeading, pHeading); FailGracefully(hres, "Failed to allocate column heading");
//column.fHasColumnProvider = FALSE;
column.cx = aSavedColumn[i].cx; column.fmt = aSavedColumn[i].fmt; column.iPropertyType = PROPERTY_ISUNKNOWN; //column.idOperator = 0;
//column.clsidColumnHandler = { 0 };
//column.pColumnHandler = NULL;
ZeroMemory(&column.filter, SIZEOF(column.filter)); column.filter.iPropertyType = PROPERTY_ISUNDEFINED;
Trace(TEXT("pProperty: '%s', pHeading: '%s', cx %d, fmt %08x"), W2T(column.pProperty), column.pHeading, column.cx, column.fmt);
if ( -1 == DSA_AppendItem(*pHDSA, &column) ) ExitGracefully(hres, E_OUTOFMEMORY, "Failed to add column to the DSA"); }
fDefaultSettings = FALSE; // success we have a table
} } }
if ( fDefaultSettings ) { // unable to read the settings from the registy, therefore defaulting to
// those defined in the query parameters block.
if ( !pDsQueryParams ) ExitGracefully(hres, E_INVALIDARG, "No DSQUERYPARAMs to default using");
for ( i = 0 ; i < pDsQueryParams->iColumns; i++ ) { COLUMN column = { 0 };
switch ( pDsQueryParams->aColumns[i].offsetProperty ) { case DSCOLUMNPROP_ADSPATH: pProperty = c_szADsPathCH; break; case DSCOLUMNPROP_OBJECTCLASS: pProperty = c_szObjectClassCH; break;
default: pProperty = (LPWSTR)ByteOffset(pDsQueryParams, pDsQueryParams->aColumns[i].offsetProperty); break; }
hres = LocalAllocStringW(&column.pProperty, pProperty); FailGracefully(hres, "Failed to allocate property name");
hres = FormatMsgResource(&column.pHeading, pDsQueryParams->hInstance, pDsQueryParams->aColumns[i].idsName); FailGracefully(hres, "Failed to allocate column heading");
//column.fHasColumnProvider = FALSE;
column.cx = pDsQueryParams->aColumns[i].cx; column.fmt = pDsQueryParams->aColumns[i].fmt; column.iPropertyType = PROPERTY_ISUNKNOWN; //column.idOperator = 0;
//column.clsidColumnHandler = { 0 };
//column.pColumnHandler = NULL;
ZeroMemory(&column.filter, SIZEOF(column.filter)); column.filter.iPropertyType = PROPERTY_ISUNDEFINED;
// Now fix the width of the column we are about to specify, this
// value has the following meaning:
//
// == 0 => use default width
// > 0 => user 'n' magic characters
// < 0 => pixel width
// FEATURE: -ve should be % of the view
if ( column.cx < 0 ) { TraceMsg("Column width specified in pixels"); column.cx = -column.cx; } else { // Default the size if it is == 0, then having done this
// lets grab the font we want to use before moving on
// to create a DC and measure the character we need.
if ( !column.cx ) column.cx = DEFAULT_WIDTH;
sz.cx = 10; // random default value.
if ( !fHaveSizeInfo ) { HDC hDC; LOGFONT lf; HFONT hFont, hOldFont;
SystemParametersInfo(SPI_GETICONTITLELOGFONT, SIZEOF(lf), &lf, FALSE);
hFont = CreateFontIndirect(&lf); // icon title font
if (hFont) { hDC = CreateCompatibleDC(NULL); // screen compatible DC
if (hDC) { hOldFont = (HFONT)SelectObject(hDC, hFont); GetTextExtentPoint(hDC, TEXT("0"), 1, &sz); SelectObject(hDC, hOldFont); DeleteDC(hDC); } DeleteFont(hFont); }
fHaveSizeInfo = TRUE; }
column.cx = column.cx*sz.cx; // n chars width
}
Trace(TEXT("pProperty: '%s', pHeading: '%s', cx %d, fmt %08x"), W2T(column.pProperty), column.pHeading, column.cx, column.fmt);
if ( -1 == DSA_AppendItem(*pHDSA, &column) ) ExitGracefully(hres, E_OUTOFMEMORY, "Failed to add column to the DSA"); } }
// Scan the column list getting both the property name and the CLSID for the
// column handler (if there is one).
hres = CoCreateInstance(CLSID_DsDisplaySpecifier, NULL, CLSCTX_INPROC_SERVER, IID_IDsDisplaySpecifier, (void **)&pdds); FailGracefully(hres, "Failed to get the IDsDisplaySpecifier interface");
if ( _dwFlags & DSQPF_HASCREDENTIALS ) { hres = pdds->SetServer(_pServer, _pUserName, _pPassword, DSSSF_DSAVAILABLE); FailGracefully(hres, "Failed to server information"); }
for ( i = 0 ; i < DSA_GetItemCount(*pHDSA) ; i++ ) { LPCOLUMN pColumn = (LPCOLUMN)DSA_GetItemPtr(*pHDSA, i); TraceAssert(pColumn);
Trace(TEXT("Property for column %d, %s"), i, W2T(pColumn->pProperty));
// lets get the property type, column handler and the default operator for it.
hres = GetColumnHandlerFromProperty(pColumn, NULL); FailGracefully(hres, "Failed to get the column handler from property string");
if ( pColumn->fHasColumnHandler ) { TraceMsg("Has a column handler, therefore property is now a string"); pColumn->iPropertyType = PROPERTY_ISSTRING; } else { pColumn->iPropertyType = PropertyIsFromAttribute(pColumn->pProperty, pdds); }
pColumn->idOperator = property_type_table[pColumn->iPropertyType].idOperator; }
// Set the columns up in the view (remove all items first) to allow us
// to add/remove columns as required.
if ( fSetInView ) { for ( i = Header_GetItemCount(ListView_GetHeader(_hwndView)); --i >= 0 ; ) ListView_DeleteColumn(_hwndView, i);
// add the columns to the view, then having done that set
// the type of the filter to reflect the property being
// shown.
for ( i = 0 ; i < DSA_GetItemCount(_hdsaColumns); i++ ) { LPCOLUMN pColumn = (LPCOLUMN)DSA_GetItemPtr(_hdsaColumns, i); TraceAssert(pColumn); lvc.mask = LVCF_TEXT|LVCF_WIDTH|LVCF_FMT; lvc.fmt = pColumn->fmt; lvc.cx = pColumn->cx; lvc.pszText = pColumn->pHeading; iNewColumn = ListView_InsertColumn(_hwndView, i, &lvc); TraceAssert(iNewColumn != -1);
if ( iNewColumn != i ) ExitGracefully(hres, E_FAIL, "Failed to add the column to the view");
hdi.mask = HDI_FILTER; hdi.type = property_type_table[pColumn->iPropertyType].hdft|HDFT_HASNOVALUE; hdi.pvFilter = NULL;
Trace(TEXT("iPropertyType %d, hdi.type %08x"), pColumn->iPropertyType, hdi.type);
if ( !Header_SetItem(ListView_GetHeader(_hwndView), iNewColumn, &hdi) ) ExitGracefully(hres, E_FAIL, "Failed to set the filter type into the view"); } }
hres = S_OK; // success
exit_gracefully:
if ( hKey ) RegCloseKey(hKey);
if ( aSavedColumn ) LocalFree((HLOCAL)aSavedColumn);
DoRelease(pdds); ResetWaitCursor();
TraceLeaveResult(hres); }
/*-----------------------------------------------------------------------------
/ CDsQuery::_SaveColumnTable / ------------------------- / Free the column table stored in a DSA. This code released all the / allocated memory stored with the table. / / In: / Out: / - /----------------------------------------------------------------------------*/ VOID CDsQuery::_SaveColumnTable(VOID) { TraceEnter(TRACE_VIEW, "CDsQuery::_SaveColumnTable");
_FreeResults();
if ( _hdsaColumns ) { DSA_DestroyCallback(_hdsaColumns, FreeColumnCB, NULL); _hdsaColumns = NULL; }
_iSortColumn = -1; _fSortDescending = FALSE;
TraceLeave(); }
/*-----------------------------------------------------------------------------
/ CDsQuery::_SaveColumnTable / ------------------------- / Save the current column table from the DPA into the registry so / we can restore it the next time the user uses this query form. / / In: / clsidForm = form ID to store it under / hdsaColumns -> DSA to destory / / Out: / HRESULT /----------------------------------------------------------------------------*/ HRESULT CDsQuery::_SaveColumnTable(REFCLSID clsidForm, HDSA hdsaColumns) { HRESULT hres; LPWSTR pProperty; LPSAVEDCOLUMN aSavedColumn = NULL; DWORD cbData, offset; HKEY hKey = NULL; LPTSTR pSettingsValue = VIEW_SETTINGS_VALUE; INT i; USES_CONVERSION; TraceEnter(TRACE_VIEW, "CDsQuery::_SaveColumnTable"); TraceGUID("clsidForm ", clsidForm); if ( !hdsaColumns ) ExitGracefully(hres, E_FAIL, "No column data to save");
// first compute the size of the blob we are going to store into
// the registry, whilst doing this compute the offset to
// the start of the string data.
offset = SIZEOF(SAVEDCOLUMN); cbData = SIZEOF(SAVEDCOLUMN);
for ( i = 0 ; i < DSA_GetItemCount(hdsaColumns); i++ ) { LPCOLUMN pColumn = (LPCOLUMN)DSA_GetItemPtr(hdsaColumns, i); TraceAssert(pColumn);
offset += SIZEOF(SAVEDCOLUMN); cbData += SIZEOF(SAVEDCOLUMN); cbData += StringByteSizeW(pColumn->pProperty);
// this is a potential problem, must be kept in sync with GetPropertyFromColumn
if ( pColumn->fHasColumnHandler ) cbData += SIZEOF(WCHAR)*(GUIDSTR_MAX + 1); // nb+1 for seperator (,} + string is UNICODE
cbData += StringByteSize(pColumn->pHeading); }
Trace(TEXT("offset %d, cbData %d"), offset, cbData);
// Allocate the structure and lets place all the data into it,
// again running over the data blocks, append the string data
// to the end of the blob in a single go.
aSavedColumn = (LPSAVEDCOLUMN)LocalAlloc(LPTR, cbData); TraceAssert(aSavedColumn);
if ( !aSavedColumn ) ExitGracefully(hres, E_OUTOFMEMORY, "Failed to allocate settings data");
Trace(TEXT("Building data blob at %08x"), aSavedColumn);
for ( i = 0 ; i < DSA_GetItemCount(hdsaColumns); i++ ) { LPCOLUMN pColumn = (LPCOLUMN)DSA_GetItemPtr(hdsaColumns, i); TraceAssert(pColumn); hres = GetPropertyFromColumn(&pProperty, pColumn); FailGracefully(hres, "Failed to allocate property from column");
aSavedColumn[i].cbSize = SIZEOF(SAVEDCOLUMN); aSavedColumn[i].dwFlags = 0; aSavedColumn[i].offsetProperty = offset; aSavedColumn[i].offsetHeading = offset + StringByteSizeW(pProperty); aSavedColumn[i].cx = pColumn->cx; aSavedColumn[i].fmt = pColumn->fmt; StringByteCopyW(aSavedColumn, aSavedColumn[i].offsetProperty, pProperty); offset += StringByteSizeW(pProperty);
StringByteCopy(aSavedColumn, aSavedColumn[i].offsetHeading, pColumn->pHeading); offset += StringByteSize(pColumn->pHeading);
LocalFreeStringW(&pProperty); }
aSavedColumn[i].cbSize = 0; // terminate the list of columns with a NULL
Trace(TEXT("offset %d, cbData %d"), offset, cbData); TraceAssert(offset == cbData);
// now put the data into the registry filed under the key for the query for that
// it maps to.
hres = _GetQueryFormKey(clsidForm, &hKey); FailGracefully(hres, "Failed to get settings sub-key");
// If invoked for admin UI then we look at the admin view settings, this way
// the admin can have one set of columns, and the user can have another.
if ( _dwFlags & DSQPF_ENABLEADMINFEATURES ) pSettingsValue = ADMIN_VIEW_SETTINGS_VALUE;
Trace(TEXT("View settings value: %s"), pSettingsValue);
if ( ERROR_SUCCESS != RegSetValueEx(hKey, pSettingsValue, 0, REG_BINARY, (LPBYTE)aSavedColumn, cbData) ) ExitGracefully(hres, E_FAIL, "Failed to write setting into the view");
hres = S_OK;
exit_gracefully:
if ( aSavedColumn ) LocalFree((HLOCAL)aSavedColumn);
if ( hKey ) RegCloseKey(hKey);
TraceLeaveResult(hres); }
// retrieve the context menu object
HRESULT _FolderCFMCallback(LPSHELLFOLDER psf, HWND hwndView, LPDATAOBJECT pDataObject, UINT uMsg, WPARAM wParam, LPARAM lParam) { Trace(TEXT("uMsg %d, wParam %08x, lParam %08x"), uMsg, wParam, lParam); switch ( uMsg ) { case DFM_MERGECONTEXTMENU: return S_OK;
case DFM_INVOKECOMMAND: switch (wParam) { case (WPARAM)DFM_CMD_PROPERTIES: TraceMsg("ShowProperties"); return ShowObjectProperties(hwndView, pDataObject);
default: return S_FALSE; } break;
case DFM_GETDEFSTATICID: *((WPARAM*)lParam) = (WPARAM)DFM_CMD_PROPERTIES; return NOERROR; } return E_NOTIMPL; }
HRESULT CDsQuery::_GetContextMenu() { ITEMIDLIST idl = {0}; LPITEMIDLIST *aidl = NULL; HKEY aKeys[UIKEY_MAX] = { 0 };
int cItems = ListView_GetSelectedCount(_hwndView); if (cItems != 0) { // try to get the selected item (there is one, so first we try the focused, then the selected)
int i = ListView_GetNextItem(_hwndView, -1, LVNI_FOCUSED|LVNI_SELECTED); if (i == -1) i = ListView_GetNextItem(_hwndView, -1, LVNI_SELECTED);
// given the item lets get the result object so that we can create the menu based on
// the right class information
LV_ITEM lvi = { 0 }; lvi.mask = LVIF_PARAM; lvi.iItem = i;
if (ListView_GetItem(_hwndView, &lvi)) { LPQUERYRESULT pResult = (LPQUERYRESULT)lvi.lParam; GetKeysForClass(pResult->pObjectClass, pResult->fIsContainer, ARRAYSIZE(aKeys), aKeys); } aidl = (LPITEMIDLIST*)LocalAlloc(LPTR, sizeof(LPITEMIDLIST)*cItems); }
// given that we probably have the keys we are interested in,
// lets now create the context menu.
DoRelease(_pcm); // release the previous context menu
HRESULT hr = E_OUTOFMEMORY; if (!cItems|| (cItems && aidl)) { // fake up the array of IDLISTs so that they can be cloned correctly from
// the view.
for (int i= 0 ; i < cItems ; i++) aidl[i] = &idl;
hr = CDefFolderMenu_Create2(&idl, _hwnd, cItems, (LPCITEMIDLIST*)aidl, this, _FolderCFMCallback, ARRAYSIZE(aKeys), aKeys, &_pcm); }
if (aidl) LocalFree(aidl);
if (FAILED(hr)) TidyKeys(ARRAYSIZE(aKeys), aKeys);
return hr; }
/*-----------------------------------------------------------------------------
/ CDsQuery::_GetContextMenuVerbs / ----------------------------- / Do the query context menu handling the case where we have been invoked / modally. / / In: / hMenu = menu handle to merge into / dwFlags = flags for QueryContextMenu / / Out: / VOID /----------------------------------------------------------------------------*/ VOID CDsQuery::_GetContextMenuVerbs(HMENU hMenu, DWORD dwFlags) { TCHAR szBuffer[MAX_PATH];
TraceEnter(TRACE_VIEW, "CDsQuery::_GetContextMenuVerbs");
_pcm->QueryContextMenu(hMenu, 0, DSQH_FILE_CONTEXT_FIRST, DSQH_FILE_CONTEXT_LAST, dwFlags); Trace(TEXT("Menu item count after QueryContextMenu %d (%08x)"), GetMenuItemCount(hMenu), hMenu);
if ( (_dwOQWFlags & OQWF_OKCANCEL) && LoadString(GLOBAL_HINSTANCE, IDS_SELECT, szBuffer, ARRAYSIZE(szBuffer)) ) { InsertMenu(hMenu, 0, MF_BYPOSITION|MF_STRING, DSQH_BG_SELECT, szBuffer); InsertMenu(hMenu, 1, MF_BYPOSITION|MF_SEPARATOR, 0, NULL); SetMenuDefaultItem(hMenu, DSQH_BG_SELECT, FALSE); }
TraceLeave(); }
// get the items in the view into a IDataObject, the caller can request either the
// selection or all the items
HRESULT CDsQuery::_AddResultToDataObject(HDSA hdsa, INT i) { LV_ITEM lvi = { 0 }; lvi.mask = LVIF_PARAM; lvi.iItem = i;
HRESULT hr = E_FAIL; if (ListView_GetItem(_hwndView, &lvi)) { QUERYRESULT *pResult = (QUERYRESULT*)lvi.lParam; DATAOBJECTITEM doi = {0}; // copy the strings for the item into the structure
hr = LocalAllocStringW(&doi.pszPath, pResult->pPath); if (SUCCEEDED(hr) && pResult->pObjectClass) hr = LocalAllocStringW(&doi.pszObjectClass, pResult->pObjectClass);
// copy the rest of the state
doi.fIsContainer = pResult->fIsContainer;
// append to the DSA.
if (SUCCEEDED(hr)) { if (-1 == DSA_AppendItem(hdsa, &doi)) { LocalFreeStringW(&doi.pszPath); LocalFreeStringW(&doi.pszObjectClass); hr = E_OUTOFMEMORY; } else { hr = S_OK; } } }
return hr; }
HRESULT CDsQuery::_GetDataObjectFromSelection(BOOL fGetAll, IDataObject **ppdo) { HRESULT hr = S_OK;
HDSA hdsa = DSA_Create(SIZEOF(DATAOBJECTITEM), 16); if (hdsa) { // focused item always come first (primary selection rulz).
int iFocused = ListView_GetNextItem(_hwndView, -1, LVNI_ALL|LVNI_SELECTED|LVNI_FOCUSED); if (iFocused > -1) { hr = _AddResultToDataObject(hdsa, iFocused); }
// now walk all the items in the view collecting the selection and adding
// those items to the DPA - we must skip the item which is focused as we
// have already added it.
if (SUCCEEDED(hr)) { int i = -1; do { i = ListView_GetNextItem(_hwndView, i, LVNI_ALL|LVNI_SELECTED); if ( (i >= 0) && (i != iFocused)) { hr = _AddResultToDataObject(hdsa, i); } } while (SUCCEEDED(hr) && (i != -1)); }
// given the DPA lets build an IDataObject using it.
hr = CDataObject_CreateInstance(hdsa, (_dwFlags & DSQPF_ENABLEADVANCEDFEATURES), IID_IDataObject, (void**)ppdo); if (SUCCEEDED(hr)) hr = _SetDispSpecOptions(*ppdo); } else { hr = E_OUTOFMEMORY; }
if (FAILED(hr) && hdsa) FreeDataObjectDSA(hdsa); // data object failed to construct, lets kill the DSA
return hr; }
/*-----------------------------------------------------------------------------
/ CDsQuery::_CopyCredentials / -------------------------- / Copy the user name, password and server as required. / / In: / ppszUserName, psszPassword & ppszServer => destinations / / Out: / HRESULT /----------------------------------------------------------------------------*/ HRESULT CDsQuery::_CopyCredentials(LPWSTR *ppszUserName, LPWSTR *ppszPassword, LPWSTR *ppszServer) { HRESULT hres;
TraceEnter(TRACE_VIEW, "CDsQuery::_CopyCredentials");
hres = LocalAllocStringW(ppszUserName, _pUserName); FailGracefully(hres, "Failed to copy the user name");
hres = LocalAllocStringW(ppszPassword, _pPassword); FailGracefully(hres, "Failed to copy the password");
hres = LocalAllocStringW(ppszServer, _pServer); FailGracefully(hres, "Failed to copy the server name");
exit_gracefully:
TraceLeaveResult(hres); }
/*-----------------------------------------------------------------------------
/ CDsQuery::OnPickColumns /----------------------------------------------------------------------------*/
typedef struct { LPWSTR pProperty; LPTSTR pHeading; BOOL fIsColumn; // item is column and added to column list box on init
INT cx; // pixel width of column
INT fmt; // formatting information of column
} PICKERITEM, * LPPICKERITEM;
typedef struct { HDPA hdpaItems; // all the items in the view
HDSA hdsaColumns; // column table generated by this dialog
HWND hwndProperties; // hwnd's for the columns/property tables
HWND hwndColumns; } PICKERSTATE, * LPPICKERSTATE;
VOID _PickerMoveColumn(HWND hwndDest, HWND hwndSrc, BOOL fInsert); HRESULT _Picker_GetColumnTable(HWND hwndColumns, HDSA* pHDSA); INT_PTR _PickerDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); INT _PickerItemFreeCB(LPVOID pData, LPVOID lParam); INT _PickerItemCmpCB(LPVOID p1, LPVOID p2, LPARAM lParam);
//
// Help ID mappings
//
static DWORD const aPickColumnsHelpIDs[] = { IDC_LBPROPERTIES, IDH_COLUMNS_AVAILABLE, IDC_LBCOLUMNS, IDH_COLUMNS_SHOWN, IDC_ADD, IDH_ADD_COLUMNS, IDC_REMOVE, IDH_REMOVE_COLUMNS, 0, 0 };
/*-----------------------------------------------------------------------------
/ _PickerMoveColumn / ----------------- / Move the selected item in one list box to another, we assume that the / item data points to a PICKERITEM structure, we transfer the selection / and / / In: / hwndSrc, hwndState = windows to move selection within / fInsert = insert at selection point in destionation, or add the string (sorted) / / Out: / VOID /----------------------------------------------------------------------------*/ VOID _PickerMoveColumn(HWND hwndDest, HWND hwndSrc, BOOL fInsert) { INT iSelection, i; LPPICKERITEM pItem; USES_CONVERSION;
TraceEnter(TRACE_FIELDCHOOSER, "_PickerMoveColumn");
iSelection = ListBox_GetCurSel(hwndSrc); TraceAssert(iSelection >= 0 );
if ( iSelection >= 0 ) { LPPICKERITEM pItem = (LPPICKERITEM)ListBox_GetItemData(hwndSrc, iSelection); TraceAssert(pItem); TraceAssert(pItem->pHeading);
// Add the new item to the view (if this it the properties)
// then this will result in the list being sorted and select
// it to allow the user to remove/add another
if ( fInsert ) { Trace(TEXT("Inserting the item at index %d"), ListBox_GetCurSel(hwndDest)+1); i = ListBox_InsertString(hwndDest, ListBox_GetCurSel(hwndDest)+1, pItem->pHeading); } else { TraceMsg("Adding string to listbox"); i = ListBox_AddString(hwndDest, pItem->pHeading); }
TraceAssert(i != -1);
ListBox_SetItemData(hwndDest, i, (LPARAM)pItem); ListBox_SetCurSel(hwndDest, i);
// remove the item from the source, ensuring that the
// selection stays visually at the same place (nb
// cope with removing the last item).
ListBox_DeleteString(hwndSrc, iSelection);
if ( iSelection >= ListBox_GetCount(hwndSrc) ) iSelection = ListBox_GetCount(hwndSrc)-1; if ( iSelection >= 0 ) ListBox_SetCurSel(hwndSrc, iSelection); }
TraceLeave(); }
/*-----------------------------------------------------------------------------
/ _Picker_GetColumnTable / --------------------- / The user has hit OK, therefore we must build a new column table, this / code walks the items in the columns ListBox and generates the / column DSA that we should be using. / / In: / hwndColumns -> ListBox containing the columns / pHDSA -> DSA to receive the columnt able / / Out: / HRESULT /----------------------------------------------------------------------------*/ HRESULT _Picker_GetColumnTable(HWND hwndColumns, HDSA* pHDSA) { HRESULT hres; HDSA hdsaColumns = NULL; INT i; INT cxColumn = 0;
TraceEnter(TRACE_FIELDCHOOSER, "_Picker_GetColumnTable");
// Construct a DSA to store the column table in
hdsaColumns = DSA_Create(SIZEOF(COLUMN), 4); TraceAssert(hdsaColumns);
if ( !hdsaColumns ) ExitGracefully(hres, E_OUTOFMEMORY, "Failed to create the column DSA");
// For each entry in the ListBox add an item to the DSA that contains
// the relevant column information
for ( i = 0 ; i < ListBox_GetCount(hwndColumns) ; i++ ) { COLUMN column = { 0 }; LPPICKERITEM pItem = (LPPICKERITEM)ListBox_GetItemData(hwndColumns, i); TraceAssert(pItem);
// column.fHasColumnHandler = FALSE;
column.pProperty = NULL; column.pHeading = NULL; //column.cx = 0;
//column.fmt = 0;
column.iPropertyType = PROPERTY_ISUNKNOWN; column.idOperator = 0; // column.clsidColumnHandler = { 0 };
// column.pColumnHandler = NULL;
// fIsColumn indicates that the entry was originally a column therefore
// has extra state information, ensure that we copy this over, otherwise
// just pick sensible defaults. Having done that we can allocate the
// strings, add the item and continue...
if ( pItem->fIsColumn ) { column.cx = pItem->cx; column.fmt = pItem->fmt; } else { // Have we cached the column width yet? If not then lets do
// so and apply it to all the columns which are using the
// default width (as they have not yet been sized)
if ( !cxColumn ) { HDC hDC; LOGFONT lf; HFONT hFont, hOldFont; SIZE sz;
sz.cx = 10; // random default value.
SystemParametersInfo(SPI_GETICONTITLELOGFONT, SIZEOF(lf), &lf, FALSE);
hFont = CreateFontIndirect(&lf); // icon title font
if (hFont) { hDC = CreateCompatibleDC(NULL); // screen compatible DC
if (hDC) { hOldFont = (HFONT)SelectObject(hDC, hFont); GetTextExtentPoint(hDC, TEXT("0"), 1, &sz); SelectObject(hDC, hOldFont); DeleteDC(hDC); } DeleteObject(hFont); }
cxColumn = DEFAULT_WIDTH * sz.cx; }
column.cx = cxColumn; column.fmt = 0; }
if ( FAILED(GetColumnHandlerFromProperty(&column, pItem->pProperty)) || FAILED(LocalAllocString(&column.pHeading, pItem->pHeading)) || (-1 == DSA_AppendItem(hdsaColumns, &column)) ) { LocalFreeStringW(&column.pProperty); LocalFreeString(&column.pHeading); ExitGracefully(hres, E_OUTOFMEMORY, "Failed to construct the column entry"); } }
Trace(TEXT("New column table contains %d items"), DSA_GetItemCount(hdsaColumns)); hres = S_OK;
exit_gracefully:
if ( FAILED(hres) && hdsaColumns ) { DSA_DestroyCallback(hdsaColumns, FreeColumnCB, NULL); hdsaColumns = NULL; }
*pHDSA = hdsaColumns;
TraceLeaveResult(hres); }
/*-----------------------------------------------------------------------------
/ _PickerDlgProc / -------------- / Dialog proc for handling the dialog messages (there is a suprise) / / In: / hwnd, uMsg, wParam, lParam = message information / DWL_USER => LPPICKERSTATE structure / / Out: / INT_PTR /----------------------------------------------------------------------------*/
#define SET_BTN_STYLE(hwnd, idc, style) \
SendDlgItemMessage(hwnd, idc, BM_SETSTYLE, MAKEWPARAM(style, 0), MAKELPARAM(TRUE, 0));
INT_PTR _PickerDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { USES_CONVERSION; INT_PTR fResult = FALSE; LPPICKERSTATE pState = NULL; BOOL fUpdateButtonState = TRUE; PICKERITEM item; INT i, j;
if ( uMsg == WM_INITDIALOG ) { pState = (LPPICKERSTATE)lParam; TraceAssert(pState);
SetWindowLongPtr(hwnd, DWLP_USER, lParam);
pState->hwndProperties = GetDlgItem(hwnd, IDC_LBPROPERTIES); pState->hwndColumns = GetDlgItem(hwnd, IDC_LBCOLUMNS);
// pState->hdsaColumns contains the currently visible column table, this is
// the table being used by the current view, therefore we must not modify
// it, just treat it as read only. Add the columns to the ListBox
// marking the visible items in the properties DPA, then add those
// items not already shown to the properties list box.
for ( i = 0 ; i < DSA_GetItemCount(pState->hdsaColumns) ; i++ ) { LPCOLUMN pColumn = (LPCOLUMN)DSA_GetItemPtr(pState->hdsaColumns, i); TraceAssert(pColumn);
if ( SUCCEEDED(GetPropertyFromColumn(&item.pProperty, pColumn)) ) { j = DPA_Search(pState->hdpaItems, &item, 0, _PickerItemCmpCB, NULL, DPAS_SORTED);
Trace(TEXT("Searching for %s yielded %d"), W2T(item.pProperty), j);
if ( j >= 0 ) { LPPICKERITEM pItem = (LPPICKERITEM)DPA_GetPtr(pState->hdpaItems, j); TraceAssert(pItem);
ListBox_SetItemData(pState->hwndColumns, ListBox_AddString(pState->hwndColumns, pItem->pHeading), (LPARAM)pItem); } LocalFreeStringW(&item.pProperty); } }
for ( i = 0 ; i < DPA_GetPtrCount(pState->hdpaItems) ; i++ ) { LPPICKERITEM pItem = (LPPICKERITEM)DPA_GetPtr(pState->hdpaItems, i); TraceAssert(pItem && pItem->pHeading);
if ( !pItem->fIsColumn ) { ListBox_SetItemData(pState->hwndProperties, ListBox_AddString(pState->hwndProperties, pItem->pHeading), (LPARAM)pItem); } }
// Ensure we default select the top items of each list
ListBox_SetCurSel(pState->hwndProperties, 0); ListBox_SetCurSel(pState->hwndColumns, 0); } else { pState = (LPPICKERSTATE)GetWindowLongPtr(hwnd, DWLP_USER); TraceAssert(pState);
switch ( uMsg ) { case WM_HELP: { LPHELPINFO pHelpInfo = (LPHELPINFO)lParam; WinHelp((HWND)pHelpInfo->hItemHandle, DSQUERY_HELPFILE, HELP_WM_HELP, (DWORD_PTR)aPickColumnsHelpIDs); break; }
case WM_CONTEXTMENU: WinHelp((HWND)wParam, DSQUERY_HELPFILE, HELP_CONTEXTMENU, (DWORD_PTR)aPickColumnsHelpIDs); fResult = TRUE; break;
case WM_COMMAND: { switch ( LOWORD(wParam) ) { case IDOK: { _Picker_GetColumnTable(pState->hwndColumns, &pState->hdsaColumns); EndDialog(hwnd, IDOK); break; }
case IDCANCEL: EndDialog(hwnd, IDCANCEL); break;
case IDC_ADD: _PickerMoveColumn(pState->hwndColumns, pState->hwndProperties, TRUE); break;
case IDC_REMOVE: _PickerMoveColumn(pState->hwndProperties, pState->hwndColumns, FALSE); break;
case IDC_LBPROPERTIES: { if ( ListBox_GetCount(pState->hwndProperties) > 0 ) { if ( HIWORD(wParam) == LBN_DBLCLK ) _PickerMoveColumn(pState->hwndColumns, pState->hwndProperties, TRUE); }
break; }
case IDC_LBCOLUMNS: { if ( ListBox_GetCount(pState->hwndColumns) > 1 ) { if ( HIWORD(wParam) == LBN_DBLCLK ) _PickerMoveColumn(pState->hwndProperties, pState->hwndColumns, FALSE); }
break; }
default: fUpdateButtonState = FALSE; break; }
break; }
default: fUpdateButtonState = FALSE; break; }
}
// if the selections state change, or something which would cause
// us to refresh the add/remove buttons state then lets do it.
// each button is enabled only if there is a selection and the
// number of items is > the min value.
if ( pState && fUpdateButtonState ) { BOOL fEnableAdd = FALSE; BOOL fEnableRemove = FALSE; DWORD dwButtonStyle;
if ( (ListBox_GetCount(pState->hwndProperties) > 0) ) { fEnableAdd = TRUE; }
if ( (ListBox_GetCount(pState->hwndColumns) > 1) ) { fEnableRemove = TRUE; }
// Make sure the DefButton is an enabled button
// FEATURE: Need to add an SHSetDefID() export to shlwapi
// which is simply a SetDefID that "does the right thing"
// wrt disabled buttons.
if ( (!fEnableRemove) && (!fEnableAdd) ) { SET_BTN_STYLE(hwnd, IDC_ADD, BS_PUSHBUTTON); SET_BTN_STYLE(hwnd, IDC_REMOVE, BS_PUSHBUTTON);
SendMessage(hwnd, DM_SETDEFID, IDOK, 0); SET_BTN_STYLE(hwnd, IDOK, BS_DEFPUSHBUTTON); SetFocus(GetDlgItem(hwnd, IDOK)); } else if ( !fEnableAdd ) { dwButtonStyle = (DWORD)GetWindowLong(GetDlgItem(hwnd, IDC_ADD), GWL_STYLE); if ( dwButtonStyle & BS_DEFPUSHBUTTON ) { SET_BTN_STYLE(hwnd, IDC_ADD, BS_PUSHBUTTON); SendMessage(hwnd, DM_SETDEFID, IDC_REMOVE, 0);
SET_BTN_STYLE(hwnd, IDC_REMOVE, BS_DEFPUSHBUTTON); SetFocus(GetDlgItem(hwnd, IDC_REMOVE)); } } else if ( !fEnableRemove ) { dwButtonStyle = (DWORD) GetWindowLong(GetDlgItem(hwnd, IDC_REMOVE), GWL_STYLE); if ( dwButtonStyle & BS_DEFPUSHBUTTON ) { SET_BTN_STYLE(hwnd, IDC_REMOVE, BS_PUSHBUTTON); SendMessage(hwnd, DM_SETDEFID, IDC_ADD, 0); SET_BTN_STYLE(hwnd, IDC_ADD, BS_DEFPUSHBUTTON); SetFocus(GetDlgItem(hwnd, IDC_ADD)); } }
Button_Enable(GetDlgItem(hwnd, IDC_ADD), fEnableAdd); Button_Enable(GetDlgItem(hwnd, IDC_REMOVE), fEnableRemove);
}
return fResult; }
/*-----------------------------------------------------------------------------
/ CDsQuery::OnPickColumns / ----------------------- / Handle picking the columns that should be displayed in the result view, / if the user selects new columns and hits OK then we refresh the / view and the internal table of visible columns. / / In: / hwndParent = parent for the dialog / / Out: / HRESULT /----------------------------------------------------------------------------*/
INT _PickerItemFreeCB(LPVOID pData, LPVOID lParam) { LPPICKERITEM pItem = (LPPICKERITEM)pData; LocalFreeStringW(&pItem->pProperty); LocalFreeString(&pItem->pHeading); LocalFree(pItem); return 1; }
INT _PickerItemCmpCB(LPVOID p1, LPVOID p2, LPARAM lParam) { USES_CONVERSION; LPPICKERITEM pEntry1 = (LPPICKERITEM)p1; LPPICKERITEM pEntry2 = (LPPICKERITEM)p2; INT nResult = -1; if ( pEntry1 && pEntry2 ) nResult = StrCmpW(pEntry1->pProperty, pEntry2->pProperty);
return nResult; }
typedef struct { PICKERSTATE *pps; HDPA hdpaProperties; // attributes to be appeneded.
} PICKERENUMATTRIB;
HRESULT CALLBACK _PickerEnumAttribCB(LPARAM lParam, LPCWSTR pAttributeName, LPCWSTR pDisplayName, DWORD dwFlags) { HRESULT hres; PICKERENUMATTRIB *ppea = (PICKERENUMATTRIB*)lParam; PICKERITEM item; INT j; USES_CONVERSION;
TraceEnter(TRACE_FIELDCHOOSER, "_PickerEnumAttribCB");
// fix casting
item.pProperty = (LPWSTR)pAttributeName;
j = DPA_Search(ppea->pps->hdpaItems, &item, 0, _PickerItemCmpCB, NULL, DPAS_SORTED); if ( j == -1 ) { Trace(TEXT("Property not already in list: %s"), W2CT(pAttributeName));
hres = StringDPA_AppendStringW(ppea->hdpaProperties, pAttributeName, NULL); FailGracefully(hres, "Failed to add unique property to DPA"); }
hres = S_OK;
exit_gracefully:
TraceLeaveResult(hres); }
HRESULT CDsQuery::OnPickColumns(HWND hwndParent) { USES_CONVERSION; HRESULT hres; HDPA hdpaProperties = NULL; PICKERSTATE state; PICKERENUMATTRIB pea = { 0 }; INT i, j, iProperty, iColumn; LPDSQUERYCLASSLIST pDsQueryClassList = NULL; IDsDisplaySpecifier* pdds = NULL;
TraceEnter(TRACE_FIELDCHOOSER, "CDsQuery::OnPickColumns"); Trace(TEXT("Column count %d"), DSA_GetItemCount(_hdsaColumns));
state.hdpaItems = NULL; state.hdsaColumns = _hdsaColumns; state.hwndProperties = NULL; state.hwndColumns = NULL;
// Build a list of unique properties sorted and remove the ones
// which match the currently displayed property set.
state.hdpaItems = DPA_Create(16); TraceAssert(state.hdpaItems);
if ( !state.hdpaItems ) ExitGracefully(hres, E_OUTOFMEMORY, "Failed to create property DPA");
//
// attempt to get the IDsDisplaySpecifier object
//
hres = CoCreateInstance(CLSID_DsDisplaySpecifier, NULL, CLSCTX_INPROC_SERVER, IID_IDsDisplaySpecifier, (void **)&pdds); FailGracefully(hres, "Failed to get the IDsDisplaySpecifier interface");
hres = pdds->SetServer(_pServer, _pUserName, _pPassword, DSSSF_DSAVAILABLE); FailGracefully(hres, "Failed to server information");
// add the columns properties to the the list, marking them as active columns
// storing their size and other information.
for ( i = 0 ; i < DPA_GetPtrCount(_hdsaColumns); i++ ) { LPCOLUMN pColumn = (LPCOLUMN)DSA_GetItemPtr(_hdsaColumns, i); TraceAssert(pColumn);
LPPICKERITEM pItem = (LPPICKERITEM)LocalAlloc(LPTR, SIZEOF(PICKERITEM)); TraceAssert(pItem);
if ( pItem ) { pItem->pProperty = NULL; pItem->pHeading = NULL; pItem->fIsColumn = TRUE; pItem->cx = pColumn->cx; pItem->fmt = pColumn->fmt;
hres = GetPropertyFromColumn(&pItem->pProperty, pColumn); TraceAssert(SUCCEEDED(hres));
if ( SUCCEEDED(hres) ) { hres = LocalAllocString(&pItem->pHeading, pColumn->pHeading); TraceAssert(SUCCEEDED(hres)); }
Trace(TEXT("Adding column %d, with property %s"), i, W2T(pItem->pProperty));
if ( FAILED(hres) || (-1 == DPA_AppendPtr(state.hdpaItems, pItem)) ) { TraceMsg("Failed to add property to the DPA"); hres = E_FAIL; } if ( FAILED(hres) ) _PickerItemFreeCB(pItem, NULL); } }
DPA_Sort(state.hdpaItems, _PickerItemCmpCB, NULL); // sort the DPA now we have all the elements
// for all the classes we have loop through and build the unique
// list, sorted as we go.
hres = _pqf->CallForm(&_clsidForm, DSQPM_GETCLASSLIST, 0, (LPARAM)&pDsQueryClassList); FailGracefully(hres, "Failed to get the class list");
if ( !pDsQueryClassList ) ExitGracefully(hres, E_FAIL, "Failed to get the class list");
Trace(TEXT("Classes returned from DSQPM_GETCLASSLIST %d"), pDsQueryClassList->cClasses);
for ( i = 0 ; i < pDsQueryClassList->cClasses ; i++ ) { LPWSTR pObjectClass = (LPWSTR)ByteOffset(pDsQueryClassList, pDsQueryClassList->offsetClass[i]); TraceAssert(pObjectClass);
Trace(TEXT("Adding class '%s' to the property DPA"), W2T(pObjectClass));
// allocate a DPA to be filed with items
StringDPA_Destroy(&pea.hdpaProperties);
pea.pps = &state; pea.hdpaProperties = DPA_Create(16);
if ( !pea.hdpaProperties ) ExitGracefully(hres, E_OUTOFMEMORY, "Failed to allocate string DPA");
if ( SUCCEEDED(EnumClassAttributes(pdds, pObjectClass, _PickerEnumAttribCB, (LPARAM)&pea)) ) { Trace(TEXT("Unique property list has %d entries"), DPA_GetPtrCount(pea.hdpaProperties));
// Having constructed the unique list of properties for this class lets now
// add them to the item data list and allocate real structures for them.
for ( iProperty = 0 ; iProperty < DPA_GetPtrCount(pea.hdpaProperties); iProperty++ ) { LPWSTR pProperty = StringDPA_GetStringW(pea.hdpaProperties, iProperty); TraceAssert(pProperty != NULL);
LPPICKERITEM pItem = (LPPICKERITEM)LocalAlloc(LPTR, SIZEOF(PICKERITEM)); TraceAssert(pItem);
if ( pItem ) { WCHAR szBuffer[MAX_PATH];
GetFriendlyAttributeName(pdds, pObjectClass, pProperty, szBuffer, ARRAYSIZE(szBuffer));
pItem->pProperty = NULL; pItem->pHeading = NULL; pItem->fIsColumn = FALSE; pItem->cx = 0; pItem->fmt = 0; hres = LocalAllocStringW(&pItem->pProperty, pProperty); TraceAssert(SUCCEEDED(hres));
if ( SUCCEEDED(hres) ) { hres = LocalAllocStringW2T(&pItem->pHeading, szBuffer); TraceAssert(SUCCEEDED(hres)); }
if ( FAILED(hres) || (-1 == DPA_AppendPtr(state.hdpaItems, pItem)) ) { TraceMsg("Failed to add property to the DPA"); hres = E_FAIL; } if ( FAILED(hres) ) _PickerItemFreeCB(pItem, NULL); }
DPA_Sort(state.hdpaItems, _PickerItemCmpCB, NULL); // sort the DPA now we have all the elements
} } }
Trace(TEXT("Property table is %d items in size"), DPA_GetPtrCount(state.hdpaItems));
// If the user selects OK then the DlgProc will have generated a new column
// table stored in the PICKERSTATE structure, we should persist this, then
// load it ready to refresh the result viewer.
i = (int)DialogBoxParam(GLOBAL_HINSTANCE, MAKEINTRESOURCE(IDD_PICKCOLUMNS), hwndParent, _PickerDlgProc, (LPARAM)&state); if ( i == IDOK ) { hres = _SaveColumnTable(_clsidForm, state.hdsaColumns); FailGracefully(hres, "Failed to write column table");
hres = _InitNewQuery(NULL, TRUE); // initialize the view
FailGracefully(hres, "Failed when starting new query");
TraceAssert(_dwThreadId); PostThreadMessage(_dwThreadId, RVTM_SETCOLUMNTABLE, _dwQueryReference, (LPARAM)state.hdsaColumns);
_fColumnsModified = FALSE; } hres = S_OK;
exit_gracefully:
StringDPA_Destroy(&pea.hdpaProperties);
if ( state.hdpaItems ) DPA_DestroyCallback(state.hdpaItems, _PickerItemFreeCB, NULL);
if ( pDsQueryClassList ) CoTaskMemFree(pDsQueryClassList);
DoRelease(pdds);
TraceLeaveValue(hres); }
// persistance object
class CDsPersistQuery : public IPersistQuery { private: LONG _cRef; TCHAR m_szFilename[MAX_PATH];
public: CDsPersistQuery(LPCTSTR pFilename);; ~CDsPersistQuery();
// IUnknown
STDMETHOD(QueryInterface)(REFIID riid, LPVOID* ppvObject); STDMETHOD_(ULONG, AddRef)(); STDMETHOD_(ULONG, Release)();
// IPersist
STDMETHOD(GetClassID)(CLSID* pClassID) { return E_NOTIMPL; }
// IPersistQuery
STDMETHOD(WriteString)(LPCTSTR pSection, LPCTSTR pValueName, LPCTSTR pValue); STDMETHOD(ReadString)(LPCTSTR pSection, LPCTSTR pValueName, LPTSTR pBuffer, INT cchBuffer); STDMETHOD(WriteInt)(LPCTSTR pSection, LPCTSTR pValueName, INT value); STDMETHOD(ReadInt)(LPCTSTR pSection, LPCTSTR pValueName, LPINT pValue); STDMETHOD(WriteStruct)(LPCTSTR pSection, LPCTSTR pValueName, LPVOID pStruct, DWORD cbStruct); STDMETHOD(ReadStruct)(LPCTSTR pSection, LPCTSTR pValueName, LPVOID pStruct, DWORD cbStruct); STDMETHOD(Clear)() { return S_OK; } };
#define STRING_SIZE TEXT("%sLength")
#define STRING_VALUE TEXT("%sValue")
CDsPersistQuery::CDsPersistQuery(LPCTSTR pFilename) : _cRef(1) { StrCpy(m_szFilename, pFilename); // copy the filename
DllAddRef(); }
CDsPersistQuery::~CDsPersistQuery() { DllRelease(); }
// IUnknown
ULONG CDsPersistQuery::AddRef() { return InterlockedIncrement(&_cRef); }
ULONG CDsPersistQuery::Release() { if (InterlockedDecrement(&_cRef)) return _cRef;
delete this; return 0; }
HRESULT CDsPersistQuery::QueryInterface(REFIID riid, void **ppv) { static const QITAB qit[] = { QITABENTMULTI(CDsPersistQuery, IPersist, IPersistQuery), // IID_IPersist
QITABENT(CDsPersistQuery, IPersistQuery), // IID_IPersistQuery
{0, 0 }, }; return QISearch(this, qit, riid, ppv); }
STDAPI CPersistQuery_CreateInstance(LPTSTR pszPath, IPersistQuery **pppq) { CDsPersistQuery *ppq = new CDsPersistQuery(pszPath); if (!ppq) return E_OUTOFMEMORY;
HRESULT hr = ppq->QueryInterface(IID_IPersistQuery, (void **)pppq); ppq->Release(); return hr; }
// IPersistQuery
STDMETHODIMP CDsPersistQuery::WriteString(LPCTSTR pSection, LPCTSTR pKey, LPCTSTR pValue) { HRESULT hr = S_OK; TCHAR szBuffer[MAX_PATH];
if ( !pSection || !pKey || !pValue ) return E_INVALIDARG;
// Write the string into the stream as a UNICODE string. If we are built for UNICODE
// then we can simply WriteProfileStruct, otherwise we must attempt to convert it
// from a multi-byte string.
// Write the string size
wsprintf(szBuffer, STRING_SIZE, pKey);
INT cchValue = 1+lstrlen(pValue); if ( !WritePrivateProfileStruct(pSection, szBuffer, &cchValue, SIZEOF(cchValue), m_szFilename) ) ExitGracefully(hr, E_FAIL, "Failed to write string size to stream");
wsprintf(szBuffer, STRING_VALUE, pKey); if ( !WritePrivateProfileStruct(pSection, szBuffer, (LPVOID)pValue, SIZEOF(WCHAR)*cchValue, m_szFilename) ) ExitGracefully(hr, E_FAIL, "Failed to write string to stream");
hr = S_OK;
exit_gracefully:
TraceLeaveResult(hr); }
STDMETHODIMP CDsPersistQuery::ReadString(LPCTSTR pSection, LPCTSTR pKey, LPTSTR pBuffer, INT cchBuffer) { HRESULT hr; TCHAR szBuffer[MAX_PATH]; INT cchValue;
TraceEnter(TRACE_IO, "CDsPersistQuery::ReadString");
if ( !pSection || !pKey || !pBuffer ) ExitGracefully(hr, E_INVALIDARG, "Nothing to read (or into)");
pBuffer[0] = TEXT('\0'); // terminate the buffer
Trace(TEXT("pSection: %s, pKey: %s"), pSection, pKey);
// Read the length of the string, checking to see if its fits in the the buffer
// we have, if it does then read and convert as requried.
wsprintf(szBuffer, STRING_SIZE, pKey); // <key name>Length
Trace(TEXT("Opening key: %s"), szBuffer); if ( !GetPrivateProfileStruct(pSection, szBuffer, &cchValue, SIZEOF(cchValue), m_szFilename) ) ExitGracefully(hr, E_FAIL, "Failed to read string size");
Trace(TEXT("cchValue %d"), cchValue);
if ( cchValue > cchBuffer ) ExitGracefully(hr, E_FAIL, "Buffer too small for string in stream");
if ( cchValue > 0 ) { wsprintf(szBuffer, STRING_VALUE, pKey); if ( !GetPrivateProfileStruct(pSection, szBuffer, pBuffer, SIZEOF(WCHAR)*cchValue, m_szFilename) ) ExitGracefully(hr, E_FAIL, "Failed to read string data"); }
Trace(TEXT("Value is: %s"), pBuffer); hr = S_OK;
exit_gracefully:
TraceLeaveResult(hr); }
STDMETHODIMP CDsPersistQuery::WriteInt(LPCTSTR pSection, LPCTSTR pKey, INT value) { HRESULT hr;
TraceEnter(TRACE_IO, "CDsPersistQuery::WriteInt");
if ( !pSection || !pKey ) ExitGracefully(hr, E_INVALIDARG, "Nothing to write");
Trace(TEXT("pSection: %s, pKey: %s, value: %d"), pSection, pKey, value);
if ( !WritePrivateProfileStruct(pSection, pKey, &value, SIZEOF(value), m_szFilename) ) ExitGracefully(hr, E_FAIL, "Failed to write value");
hr = S_OK;
exit_gracefully:
TraceLeaveResult(hr); }
STDMETHODIMP CDsPersistQuery::ReadInt(LPCTSTR pSection, LPCTSTR pKey, LPINT pValue) { HRESULT hr;
TraceEnter(TRACE_IO, "CDsPersistQuery::ReadInt");
if ( !pSection || !pKey || !pValue ) ExitGracefully(hr, E_INVALIDARG, "Nothing to read");
Trace(TEXT("pSection: %s, pKey: %s, pValue: %08x"), pSection, pKey, pValue);
if ( !GetPrivateProfileStruct(pSection, pKey, pValue, SIZEOF(*pValue), m_szFilename) ) ExitGracefully(hr, E_FAIL, "Failed to read value");
hr = S_OK;
exit_gracefully:
TraceLeaveResult(hr); }
STDMETHODIMP CDsPersistQuery::WriteStruct(LPCTSTR pSection, LPCTSTR pKey, LPVOID pStruct, DWORD cbStruct) { HRESULT hr;
TraceEnter(TRACE_IO, "CDsPersistQuery::WriteStruct");
if ( !pSection || !pKey || !pStruct ) ExitGracefully(hr, E_INVALIDARG, "Nothing to write");
Trace(TEXT("pSection: %s, pKey: %s, pStruct: %08x, cbStruct: %d"), pSection, pKey, pStruct, cbStruct);
if ( !WritePrivateProfileStruct(pSection, pKey, pStruct, cbStruct, m_szFilename) ) ExitGracefully(hr, E_FAIL, "Failed to write struct");
hr = S_OK;
exit_gracefully:
TraceLeaveResult(hr); }
STDMETHODIMP CDsPersistQuery::ReadStruct(LPCTSTR pSection, LPCTSTR pKey, LPVOID pStruct, DWORD cbStruct) { HRESULT hr;
TraceEnter(TRACE_IO, "CDsPersistQuery::ReadStruct");
if ( !pSection || !pKey || !pStruct ) ExitGracefully(hr, E_INVALIDARG, "Nothing to read");
Trace(TEXT("pSection: %s, pKey: %s, pStruct: %08x, cbStruct: %d"), pSection, pKey, pStruct, cbStruct);
if ( !GetPrivateProfileStruct(pSection, pKey, pStruct, cbStruct, m_szFilename) ) ExitGracefully(hr, E_FAIL, "Failed to read struct");
hr = S_OK;
exit_gracefully:
TraceLeaveResult(hr); }
|