windows-nt/Source/XPSP1/NT/shell/ext/dsui/dsquery/frame.cpp

4101 lines
130 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
#include "pch.h"
#include "uxtheme.h"
#pragma hdrstop
/*-----------------------------------------------------------------------------
/ Private data and helper functions
/----------------------------------------------------------------------------*/
//
// ICommonQuery stuff
//
class CCommonQuery : public ICommonQuery, IObjectWithSite
{
private:
LONG _cRef;
IUnknown* _punkSite;
public:
CCommonQuery();
~CCommonQuery();
// IUnknown
STDMETHOD(QueryInterface)(REFIID riid, LPVOID* ppvObject);
STDMETHOD_(ULONG, AddRef)();
STDMETHOD_(ULONG, Release)();
// ICommonQuery
STDMETHOD(OpenQueryWindow)(THIS_ HWND hwndParent, LPOPENQUERYWINDOW pOpenQueryWnd, IDataObject** ppDataObject);
// IObjectWithSite
STDMETHODIMP SetSite(IUnknown* punk);
STDMETHODIMP GetSite(REFIID riid, void **ppv);
};
//
// View layout constants used by our dialogs
//
#define VIEWER_DEFAULT_CY 200
#define COMBOEX_IMAGE_CX 16
#define COMBOEX_IMAGE_CY 16
typedef struct
{
HDSA hdsaPages; // DSA containing page entries
DWORD dwFlags; // flags
CLSID clsidForm; // CLSID identifier for this form
LPTSTR pTitle; // title used for drop down / title bar
HICON hIcon; // hIcon passed by caller
INT iImage; // image list index of icon
INT iForm; // visible index of form in control
INT iPage; // currently selected page on form
} QUERYFORM, * LPQUERYFORM;
typedef struct
{
CLSID clsidForm; // CLSID to associate this form with
LPCQPAGE pPage; // CQPAGE structures
LPCQPAGEPROC pPageProc; // PageProc's used by thunking layer
LPARAM lParam; // PAGEPROC lParam
HWND hwndPage; // hWnd of page dialog // = NULL if none
} QUERYFORMPAGE, * LPQUERYFORMPAGE;
typedef struct
{
LPCQSCOPE pScope;
INT iImage;
} QUERYSCOPE, * LPQUERYSCOPE;
class CQueryFrame : public IQueryFrame
{
friend INT QueryWnd_MessageProc(HWND hwnd, LPMSG pMsg);
friend INT_PTR CALLBACK QueryWnd_DlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
public:
CQueryFrame(IUnknown* punkSite, LPOPENQUERYWINDOW pOpenQueryWindow, IDataObject** ppDataObject);
~CQueryFrame();
// IUnknown
STDMETHOD(QueryInterface)(REFIID riid, LPVOID* ppvObject);
STDMETHOD_(ULONG, AddRef)();
STDMETHOD_(ULONG, Release)();
// Internal helper functions
STDMETHOD(DoModal)(HWND hwndParent);
// IQueryFrame
STDMETHOD(AddScope)(THIS_ LPCQSCOPE pScope, INT i, BOOL fSelect);
STDMETHOD(GetWindow)(THIS_ HWND* phWnd);
STDMETHOD(InsertMenus)(THIS_ HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidth);
STDMETHOD(RemoveMenus)(THIS_ HMENU hmenuShared);
STDMETHOD(SetMenu)(THIS_ HMENU hmenuShared, HOLEMENU holereservedMenu);
STDMETHOD(SetStatusText)(THIS_ LPCTSTR pszStatusText);
STDMETHOD(StartQuery)(THIS_ BOOL fStarting);
STDMETHOD(LoadQuery)(THIS_ IPersistQuery* pPersistQuery);
STDMETHOD(SaveQuery)(THIS_ IPersistQuery* pPersistQuery);
STDMETHOD(CallForm)(THIS_ LPCLSID pclsidForm, UINT uMsg, WPARAM wParam, LPARAM lParam);
STDMETHOD(GetScope)(THIS_ LPCQSCOPE* ppScope);
STDMETHOD(GetHandler)(THIS_ REFIID riid, void **ppv);
protected:
// Helper functions
VOID CloseQueryFrame(HRESULT hres);
INT FrameMessageBox(LPCTSTR pPrompt, UINT uType);
// Message handlers
HRESULT OnInitDialog(HWND hwnd);
VOID DoEnableControls(VOID);
LRESULT OnNotify(INT idCtrl, LPNMHDR pNotify);
VOID OnSize(INT cx, INT cy);
VOID OnGetMinMaxInfo(LPMINMAXINFO lpmmi);
VOID OnCommand(WPARAM wParam, LPARAM lParam);
VOID OnInitMenu(HMENU hMenu);
VOID OnEnterMenuLoop(BOOL fEntering);
VOID OnMenuSelect(HMENU hMenu, UINT uID);
HRESULT OnFindNow(VOID);
BOOL OnNewQuery(BOOL fAlwaysPrompt);
HRESULT OnBrowse(VOID);
HRESULT OnHelp(LPHELPINFO pHelpInfo);
// Form/Scope helper fucntions
HRESULT InsertScopeIntoList(LPCQSCOPE pScope, INT i, BOOL fAddToControl);
HRESULT AddScopeToControl(LPQUERYSCOPE pQueryScope, INT i);
HRESULT PopulateScopeControl(VOID);
HRESULT GetSelectedScope(LPQUERYSCOPE* ppQueryScope);
HRESULT AddFromIQueryForm(IQueryForm* pQueryForm, HKEY hkeyForm);
HRESULT GatherForms(VOID);
HRESULT GetForms(HKEY hKeyForms, LPTSTR pName);
HRESULT PopulateFormControl(BOOL fIncludeHidden);
HRESULT SelectForm(REFCLSID clsidForm);
VOID SelectFormPage(LPQUERYFORM pQueryForm, INT iPage);
HRESULT CallFormPages(LPQUERYFORM pQueryForm, UINT uMsg, WPARAM wParam, LPARAM lParam);
LPQUERYFORM FindQueryForm(REFCLSID clsidForm);
private:
LONG _cRef; // reference count for the object
IUnknown* _punkSite; // site object we need to pass through
IQueryHandler* _pQueryHandler; // IQueryHandler object we need to interact with
LPOPENQUERYWINDOW _pOpenQueryWnd; // copy of initial parameters provided by caller
IDataObject** _ppDataObject; // receives the resulting data object from handler
DWORD _dwHandlerViewFlags; // flags from the handler
BOOL _fQueryRunning:1; // = 1 => query has been started, via IQueryFrame::StartQuery(TRUE)
BOOL _fExitModalLoop:1; // = 1 => must leave modal loop
BOOL _fScopesPopulated:1; // = 1 => scope control has been populated
BOOL _fTrackingMenuBar:1; // = 1 => then we are tracking the menu bar, therefore send activates etc
BOOL _fAddScopesNYI:1; // = 1 => did AddScopes return E_NOTIMPL
BOOL _fScopesAddedAsync:1; // = 1 => scopes added async by the handler
BOOL _fScopeImageListSet:1; // = 1 => scope image list has been set
BOOL _fFormFirstEnable:1; // = 1 => enabling controls for first item, so ensure we set focus
HRESULT _hResult; // result value stored by CloseQueryFrame
HKEY _hkHandler; // registry key for the handler
HWND _hwnd; // main window handle
HWND _hwndResults; // result viewer
HWND _hwndStatus; // status bar
HWND _hwndFrame; // Query Pages tab control
HWND _hwndLookForLabel; // "Find:"
HWND _hwndLookFor; // Form combo
HWND _hwndLookInLabel; // "In:"
HWND _hwndLookIn; // Scope combo
HWND _hwndBrowse; // "Browse"
HWND _hwndFindNow; // "Find now"
HWND _hwndStop; // "Stop"
HWND _hwndNewQuery; // "New Query"
HWND _hwndOK; // "OK"
HWND _hwndCancel; // "Cancel"
HWND _hwndFindAnimation; // Query issued animation
HICON _hiconSmall; // large/small app icons
HICON _hiconLarge;
HMENU _hmenuFile; // handle of the frames menu bar
HIMAGELIST _himlForms; // image list for query form objects
SIZE _szMinTrack; // minimum track size of the window
INT _dxFormAreaLeft; // offset to left edge of form area (from window left)
INT _dxFormAreaRight; // offset to right edge of form area (from window right)
INT _dxButtonsLeft; // offset to left edge of buttons (from window right)
INT _dxAnimationLeft; // offset to left edge of aniimation (from window right)
INT _dyResultsTop; // offset to top of results (from top of window)
INT _dyOKTop; // offset to top of "OK" buttom (from results top)
INT _dxGap; // gap between OK + Cancel / LookIn + Browse
INT _dyGap; // gap between bottom of OK,Cancel and the frame.
INT _cyStatus; // height of the status bar
HDSA _hdsaForms; // forms DSA
HDSA _hdsaPages; // pages DSA
SIZE _szForm; // size of the (current form we are displaying)
HDSA _hdsaScopes; // scopes DSA
INT _iDefaultScope; // index of the defualt scope to select (into DSA)
LPQUERYFORM _pCurrentForm; // == NULL if none / else -> form structure
LPQUERYFORMPAGE _pCurrentFormPage; // == NULL if none / else -> page structure
};
//
// Helper functions
//
INT_PTR CALLBACK QueryWnd_DlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
INT QueryWnd_MessageProc(HWND hwnd, LPMSG pMsg);
HRESULT _CallScopeProc(LPQUERYSCOPE pQueryScope, UINT uMsg, LPVOID pVoid);
INT _FreeScope(LPQUERYSCOPE pQueryScope);
INT _FreeScopeCB(LPVOID pItem, LPVOID pData);
HRESULT _CallPageProc(LPQUERYFORMPAGE pQueryFormPage, UINT uMsg, WPARAM wParam, LPARAM lParam);
INT _FreeQueryFormCB(LPVOID pItem, LPVOID pData);
INT _FreeQueryForm(LPQUERYFORM pQueryForm);
INT _FreeQueryFormPageCB(LPVOID pItem, LPVOID pData);
INT _FreeQueryFormPage(LPQUERYFORMPAGE pQueryFormPage);
HRESULT _AddFormsProc(LPARAM lParam, LPCQFORM pForm);
HRESULT _AddPagesProc(LPARAM lParam, REFCLSID clsidForm, LPCQPAGE pPage);
//
// Help stuff
//
#define HELP_FILE (NULL)
static DWORD const aHelpIDs[] =
{
0, 0
};
//
// constant strings
//
TCHAR const c_szCLSID[] = TEXT("CLSID");
TCHAR const c_szForms[] = TEXT("Forms");
TCHAR const c_szFlags[] = TEXT("Flags");
TCHAR const c_szCommonQuery[] = TEXT("CommonQuery");
TCHAR const c_szHandlerIs[] = TEXT("Handler");
TCHAR const c_szFormIs[] = TEXT("Form");
TCHAR const c_szSearchPaneHidden[] = TEXT("SearchPaneHidden");
/*-----------------------------------------------------------------------------
/ CCommonQuery
/----------------------------------------------------------------------------*/
CCommonQuery::CCommonQuery() :
_punkSite(NULL), _cRef(1)
{
DllAddRef();
}
CCommonQuery::~CCommonQuery()
{
DoRelease(_punkSite);
DllRelease();
}
// QI handling
ULONG CCommonQuery::AddRef()
{
return InterlockedIncrement(&_cRef);
}
ULONG CCommonQuery::Release()
{
if (InterlockedDecrement(&_cRef))
return _cRef;
delete this;
return 0;
}
HRESULT CCommonQuery::QueryInterface(REFIID riid, void **ppv)
{
static const QITAB qit[] =
{
QITABENT(CCommonQuery, ICommonQuery), // IID_ICommonQuery
QITABENT(CCommonQuery, IObjectWithSite), // IID_IObjectWithSite
{0, 0 },
};
return QISearch(this, qit, riid, ppv);
}
STDAPI CCommonQuery_CreateInstance(IUnknown* punkOuter, IUnknown** ppunk, LPCOBJECTINFO poi)
{
CCommonQuery *pcq = new CCommonQuery;
if (!pcq)
return E_OUTOFMEMORY;
HRESULT hres = pcq->QueryInterface(IID_IUnknown, (void **)ppunk);
pcq->Release();
return hres;
}
// ICommonQuery methods
STDMETHODIMP CCommonQuery::OpenQueryWindow(THIS_ HWND hwndParent, LPOPENQUERYWINDOW pOpenQueryWnd, IDataObject** ppDataObject)
{
HRESULT hres;
CQueryFrame* pQueryFrame = NULL;
TraceEnter(TRACE_QUERY, "CCommonQuery::OpenQueryWindow");
if (!pOpenQueryWnd || (hwndParent && !IsWindow(hwndParent)))
ExitGracefully(hres, E_INVALIDARG, "Bad parameters");
if (ppDataObject)
*(ppDataObject) = NULL;
pQueryFrame = new CQueryFrame(_punkSite, pOpenQueryWnd, ppDataObject);
TraceAssert(pQueryFrame);
if (!pQueryFrame)
ExitGracefully(hres, E_OUTOFMEMORY, "Failed to construct the query window object");
hres = pQueryFrame->DoModal(hwndParent); // don't bother fail gracefully etc
FailGracefully(hres, "Failed on calling DoModal");
exit_gracefully:
DoRelease(pQueryFrame);
TraceLeaveResult(hres);
}
// IObjectWithSite
STDMETHODIMP CCommonQuery::SetSite(IUnknown* punk)
{
HRESULT hres = S_OK;
TraceEnter(TRACE_QUERY, "CCommonQuery::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 CCommonQuery::GetSite(REFIID riid, void **ppv)
{
HRESULT hres;
TraceEnter(TRACE_QUERY, "CCommonQuery::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);
}
// IQueryFrame stuff
CQueryFrame::CQueryFrame(IUnknown *punkSite, LPOPENQUERYWINDOW pOpenQueryWindow, IDataObject** ppDataObject) :
_cRef(1), _punkSite(punkSite), _pOpenQueryWnd(pOpenQueryWindow),
_ppDataObject(ppDataObject), _hiconLarge(NULL), _hiconSmall(NULL)
{
if (_punkSite)
_punkSite->AddRef();
DllAddRef();
}
CQueryFrame::~CQueryFrame()
{
DoRelease(_punkSite);
if (_hiconLarge)
DestroyIcon(_hiconLarge);
if (_hiconSmall)
DestroyIcon(_hiconSmall);
if (_hkHandler)
RegCloseKey(_hkHandler);
if (_hmenuFile)
DestroyMenu(_hmenuFile);
if (_himlForms)
ImageList_Destroy(_himlForms);
if (_hdsaForms)
{
Trace(TEXT("Destroying QUERYFORM DSA (%d)"), DSA_GetItemCount(_hdsaForms));
DSA_DestroyCallback(_hdsaForms, _FreeQueryFormCB, NULL);
_hdsaForms = NULL;
}
if (_hdsaPages)
{
Trace(TEXT("Destroying QUERYFORMPAGE DSA (%d)"), DSA_GetItemCount(_hdsaPages));
DSA_DestroyCallback(_hdsaPages, _FreeQueryFormPageCB, NULL);
_hdsaPages = NULL;
}
if (_hdsaScopes)
{
Trace(TEXT("Destroying QUERYSCOPE DSA (%d)"), DSA_GetItemCount(_hdsaScopes));
DSA_DestroyCallback(_hdsaScopes, _FreeScopeCB, NULL);
_hdsaScopes = NULL;
}
_pCurrentForm = NULL;
_pCurrentFormPage = NULL;
// Now discard the handler and its window (if we have one), if
// we don't do this they will never kill their objects
if (_hwndResults)
{
DestroyWindow(_hwndResults);
_hwndResults = NULL;
}
DllRelease();
}
// QI handling
ULONG CQueryFrame::AddRef()
{
return InterlockedIncrement(&_cRef);
}
ULONG CQueryFrame::Release()
{
if (InterlockedDecrement(&_cRef))
return _cRef;
delete this;
return 0;
}
HRESULT CQueryFrame::QueryInterface(REFIID riid, void **ppv)
{
static const QITAB qit[] =
{
QITABENT(CQueryFrame, IQueryFrame), // IID_IQueryFrame
{0, 0 },
};
return QISearch(this, qit, riid, ppv);
}
/*-----------------------------------------------------------------------------
/ IQueryFrame
/----------------------------------------------------------------------------*/
STDMETHODIMP CQueryFrame::DoModal(HWND hwndParent)
{
HRESULT hres;
HWND hwndFrame = NULL;
HWND hwndFocus = NULL;
HWND hwndTopOwner = hwndParent;
MSG msg;
INITCOMMONCONTROLSEX iccex;
TraceEnter(TRACE_FRAME, "CQueryFrame::DoModal");
// initialize with the query handler we need
hres = CoCreateInstance(_pOpenQueryWnd->clsidHandler, NULL, CLSCTX_INPROC_SERVER, IID_IQueryHandler, (LPVOID*)&_pQueryHandler);
FailGracefully(hres, "Failed to get IQueryHandler for the given CLSID");
hres = _pQueryHandler->Initialize(this, _pOpenQueryWnd->dwFlags, _pOpenQueryWnd->pHandlerParameters);
FailGracefully(hres, "Failed to initialize the handler");
// mimic the behaviour of DialogBox by working out which control previously
// had focus, which window to disable and then running a message
// pump for our dialog. Having done this we can then restore the state
// back to something sensible.
_fExitModalLoop = FALSE; // can be changed from hear down
iccex.dwSize = SIZEOF(iccex);
iccex.dwICC = ICC_USEREX_CLASSES;
InitCommonControlsEx(&iccex);
if (_pOpenQueryWnd->dwFlags & OQWF_HIDESEARCHUI)
{
hwndFrame = CreateDialogParam(GLOBAL_HINSTANCE, MAKEINTRESOURCE(IDD_FILTER),
hwndParent,
QueryWnd_DlgProc, (LPARAM)this);
}
else
{
hwndFrame = CreateDialogParam(GLOBAL_HINSTANCE, MAKEINTRESOURCE(IDD_FIND),
hwndParent,
QueryWnd_DlgProc, (LPARAM)this);
}
if (!hwndFrame)
ExitGracefully(hres, E_FAIL, "Failed to create the dialog");
hwndFocus = GetFocus();
if (hwndTopOwner)
{
// walk up the window stack looking for the window to be disabled, this must
// be the top-most non-child window. If the resulting window is either
// the desktop or is already disabled then don't bother.
while (GetWindowLong(hwndTopOwner, GWL_STYLE) & WS_CHILD)
hwndTopOwner = GetParent(hwndTopOwner);
TraceAssert(hwndTopOwner);
if ((hwndTopOwner == GetDesktopWindow())
|| EnableWindow(hwndTopOwner, FALSE))
{
TraceMsg("Parent is disabled or the desktop window, therefore setting to NULL");
hwndTopOwner = NULL;
}
}
ShowWindow(hwndFrame, SW_SHOW); // show the query window
while (!_fExitModalLoop && GetMessage(&msg, NULL, 0, 0) > 0)
{
if (!QueryWnd_MessageProc(hwndFrame, &msg) && !IsDialogMessage(hwndFrame, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
// Now tidy up, make the parent the active window, enable the top most
// window if there is one and restore focus as required.
if (hwndTopOwner)
EnableWindow(hwndTopOwner, TRUE);
if (hwndParent && (GetActiveWindow() == hwndFrame))
{
TraceMsg("Passing activation to parent");
SetActiveWindow(hwndParent);
}
if (IsWindow(hwndFocus))
SetFocus(hwndFocus);
DestroyWindow(hwndFrame); // discard the current frame window
exit_gracefully:
DoRelease(_pQueryHandler);
TraceLeaveResult(_hResult);
}
/*---------------------------------------------------------------------------*/
STDMETHODIMP CQueryFrame::AddScope(THIS_ LPCQSCOPE pScope, INT i, BOOL fSelect)
{
HRESULT hres;
TraceEnter(TRACE_FRAME, "CQueryFrame::AddScope");
if (!pScope)
ExitGracefully(hres, E_INVALIDARG, "No scope to add to the list");
// Add the scope to the control and then ensure that we either have
// its index stored (for default selection) or we select the
// item.
if (!_hdsaScopes || !DSA_GetItemCount(_hdsaScopes))
{
TraceMsg("First scope being added, thefore selecting");
fSelect = TRUE;
}
hres = InsertScopeIntoList(pScope, i, _fScopesPopulated);
FailGracefully(hres, "Failed to add scope to control");
if (fSelect)
{
if (!_fScopesPopulated)
{
Trace(TEXT("Storing default scope index %d"), ShortFromResult(hres));
_iDefaultScope = ShortFromResult(hres);
}
else
{
Trace(TEXT("Selecting scope index %d"), ShortFromResult(hres));
ComboBox_SetCurSel(_hwndLookIn, ShortFromResult(hres));
}
}
// hres = S_OK;
exit_gracefully:
TraceLeaveResult(hres);
}
/*---------------------------------------------------------------------------*/
STDMETHODIMP CQueryFrame::GetWindow(THIS_ HWND* phWnd)
{
TraceEnter(TRACE_FRAME, "CQueryFrame::GetWindow");
TraceAssert(phWnd);
*phWnd = _hwnd;
TraceLeaveResult(S_OK);
}
/*---------------------------------------------------------------------------*/
// Add a menu group to the given menu bar, updating the width index accordingly
// so that other people can merge in accordingly
VOID _DoInsertMenu(HMENU hMenu, INT iIndexTo, HMENU hMenuToInsert, INT iIndexFrom)
{
TCHAR szBuffer[MAX_PATH];
HMENU hPopupMenu = NULL;
TraceEnter(TRACE_FRAME, "_DoInsertMenu");
hPopupMenu = CreatePopupMenu();
if (hPopupMenu)
{
Shell_MergeMenus(hPopupMenu, GetSubMenu(hMenuToInsert, iIndexFrom), 0x0, 0x0, 0x7fff, 0);
GetMenuString(hMenuToInsert, iIndexFrom, szBuffer, ARRAYSIZE(szBuffer), MF_BYPOSITION);
InsertMenu(hMenu, iIndexTo, MF_BYPOSITION|MF_POPUP, (UINT_PTR)hPopupMenu, szBuffer);
}
TraceLeave();
}
VOID _AddMenuGroup(HMENU hMenuShared, HMENU hMenuGroup, LONG iInsertAt, LPLONG pWidth)
{
HRESULT hres;
TCHAR szBuffer[MAX_PATH];
HMENU hMenu;
INT i;
TraceEnter(TRACE_FRAME, "_AddMenuGroup");
TraceAssert(hMenuShared);
TraceAssert(hMenuGroup);
TraceAssert(pWidth);
for (i = 0 ; i < GetMenuItemCount(hMenuGroup) ; i++)
{
_DoInsertMenu(hMenuShared, iInsertAt+i, hMenuGroup, i);
*pWidth += 1;
}
TraceLeave();
}
STDMETHODIMP CQueryFrame::InsertMenus(THIS_ HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidth)
{
HRESULT hres;
TraceEnter(TRACE_FRAME, "CQueryFrame::InsertMenus");
if (!hmenuShared || !lpMenuWidth)
ExitGracefully(hres, E_INVALIDARG, "Unable to insert menus");
// if we don't have the menu bar already loaded then lets load it,
// having done that we can then add our menu to the bar (we only
// provide entries for the file menu).
if (!_hmenuFile)
{
_hmenuFile = LoadMenu(GLOBAL_HINSTANCE, MAKEINTRESOURCE(IDR_FILEMENUGROUP));
if (!_hmenuFile)
ExitGracefully(hres, E_FAIL, "Failed to load base menu defn");
}
_AddMenuGroup(hmenuShared, _hmenuFile, 0, &lpMenuWidth->width[0]);
hres = S_OK; // success
exit_gracefully:
TraceLeaveResult(hres);
}
/*---------------------------------------------------------------------------*/
STDMETHODIMP CQueryFrame::RemoveMenus(THIS_ HMENU hmenuShared)
{
TraceEnter(TRACE_FRAME, "CQueryFrame::RemoveMenus");
// We don't need to implement this as we copy or menus into the
// menu that the handler supplies - fix DSQUERY if this ever
// changes.
TraceLeaveResult(S_OK);
}
/*---------------------------------------------------------------------------*/
STDMETHODIMP CQueryFrame::SetMenu(THIS_ HMENU hmenuShared, HOLEMENU holereservedMenu)
{
TraceEnter(TRACE_FRAME, "CQueryFrame::SetMenu");
if (!(_pOpenQueryWnd->dwFlags & OQWF_HIDEMENUS))
{
HMENU hmenuOld = ::GetMenu(_hwnd);
if (!hmenuShared)
hmenuShared = _hmenuFile;
::SetMenu(_hwnd, hmenuShared);
DoEnableControls(); // ensure the menu state is valid
::DrawMenuBar(_hwnd);
if (hmenuOld && (hmenuOld != _hmenuFile) && (hmenuOld != hmenuShared))
{
TraceMsg("Destroying old menu");
DestroyMenu(hmenuOld);
}
}
TraceLeaveResult(S_OK);
}
/*---------------------------------------------------------------------------*/
STDMETHODIMP CQueryFrame::SetStatusText(THIS_ LPCTSTR pszStatusText)
{
TraceEnter(TRACE_FRAME, "CQueryFrame::SetStatusText");
Trace(TEXT("Setting status text to: %s"), pszStatusText);
if (_hwndStatus)
SendMessage(_hwndStatus, SB_SETTEXT, 0, (LPARAM)pszStatusText);
TraceLeaveResult(S_OK);
}
/*---------------------------------------------------------------------------*/
STDMETHODIMP CQueryFrame::StartQuery(THIS_ BOOL fStarting)
{
TraceEnter(TRACE_FRAME, "CQueryFrame::StartQuery");
if (fStarting)
{
Animate_Play(_hwndFindAnimation, 0, -1, -1);
}
else
{
Animate_Stop(_hwndFindAnimation);
Animate_Seek(_hwndFindAnimation, 0); // go to start
}
if (_pQueryHandler)
_pQueryHandler->ActivateView(CQRVA_STARTQUERY, (WPARAM)fStarting, 0);
// now set the controls into a sensble state
_fQueryRunning = fStarting;
DoEnableControls();
TraceLeaveResult(S_OK);
}
/*---------------------------------------------------------------------------*/
STDMETHODIMP CQueryFrame::LoadQuery(THIS_ IPersistQuery* pPersistQuery)
{
HRESULT hres;
TCHAR szGUID[GUIDSTR_MAX+1];
LPQUERYFORM pQueryForm = NULL;
GUID guid;
TraceEnter(TRACE_FRAME, "CQueryFrame::LoadQuery");
_pQueryHandler->StopQuery(); // ensure that the handler stops its processing
// Attempt to read the handler GUID from the query stream, first try reading it as
// as string then parsing it into something that we can use, if that fails then
// try again, but this time read it as a structure.
//
// having aquired the GUID for the handler make sure that we have the correct handler
// selected.
if (FAILED(pPersistQuery->ReadString(c_szCommonQuery, c_szHandlerIs, szGUID, ARRAYSIZE(szGUID))) ||
!GetGUIDFromString(szGUID, &guid))
{
TraceMsg("Trying new style handler GUID as struct");
hres = pPersistQuery->ReadStruct(c_szCommonQuery, c_szHandlerIs, &guid, SIZEOF(guid));
FailGracefully(hres, "Failed to read handler GUID as struct");
}
if (guid != _pOpenQueryWnd->clsidHandler)
ExitGracefully(hres, E_FAIL, "Persisted handler GUID and specified handler GUID don't match");
hres = _pQueryHandler->LoadQuery(pPersistQuery);
FailGracefully(hres, "Handler failed to load its query data");
// Get the form ID, then look up the form to see if we have one that matches,
// if not then we cannot load any thing else. If we do haved that form then
// ensure that we clear it and then load away.
if (FAILED(pPersistQuery->ReadString(c_szCommonQuery, c_szFormIs, szGUID, ARRAYSIZE(szGUID))) ||
!GetGUIDFromString(szGUID, &guid))
{
TraceMsg("Trying new style form GUID as struct");
hres = pPersistQuery->ReadStruct(c_szCommonQuery, c_szFormIs, &guid, SIZEOF(guid));
FailGracefully(hres, "Failed to read handler GUID as struct");
}
hres = SelectForm(guid);
FailGracefully(hres, "Failed to select the query form");
if (hres == S_FALSE)
ExitGracefully(hres, E_FAIL, "Failed to select the query form to read the query info");
hres = CallFormPages(_pCurrentForm, CQPM_CLEARFORM, 0, 0);
FailGracefully(hres, "Failed to clear form before loading");
// Load the persisted query from the stream, coping correctly with the
// UNICODE / ANSI issue. We will be passed an IPersistQuery object which
// we must then thunk accordingly if we are UNICODE for the pages we
// are going to talk to.
hres = CallFormPages(_pCurrentForm, CQPM_PERSIST, TRUE, (LPARAM)pPersistQuery);
FailGracefully(hres, "Failed to load page data (UNICODE)");
hres = S_OK; // success
exit_gracefully:
if (SUCCEEDED(hres))
{
TraceMsg("Query loaded successfully, select form query");
SelectForm(guid);
}
TraceLeaveResult(hres);
}
/*---------------------------------------------------------------------------*/
STDMETHODIMP CQueryFrame::SaveQuery(THIS_ IPersistQuery* pPersistQuery)
{
HRESULT hres;
LPQUERYSCOPE pQueryScope;
TCHAR szBuffer[MAX_PATH];
TraceEnter(TRACE_FRAME, "CQueryFrame::SaveQuery");
if (!pPersistQuery)
ExitGracefully(hres, E_INVALIDARG, "No pPersistQuery object to write into");
pPersistQuery->Clear(); // flush the contents
hres = pPersistQuery->WriteStruct(c_szCommonQuery, c_szHandlerIs,
&_pOpenQueryWnd->clsidHandler,
SIZEOF(_pOpenQueryWnd->clsidHandler));
FailGracefully(hres, "Failed to write handler GUID");
hres = pPersistQuery->WriteStruct(c_szCommonQuery, c_szFormIs,
&_pCurrentForm->clsidForm,
SIZEOF(_pCurrentForm->clsidForm));
FailGracefully(hres, "Failed to write form GUID");
// Allow the handler to persist itself into the the stream, this includes
// giving it the current scope to store.
hres = GetSelectedScope(&pQueryScope);
FailGracefully(hres, "Failed to get the scope from the LookIn control");
hres = _pQueryHandler->SaveQuery(pPersistQuery, pQueryScope->pScope);
FailGracefully(hres, "Failed when calling handler to persist itself");
// Save the query into the stream, coping correctly with the
// UNICODE / ANSI issue. We will be passed an IPersistQuery object which
// we must then thunk accordingly if we are UNICODE for the pages we
// are going to talk to.
hres = CallFormPages(_pCurrentForm, CQPM_PERSIST, FALSE, (LPARAM)pPersistQuery);
FailGracefully(hres, "Failed to load page data (UNICODE)");
hres = S_OK;
exit_gracefully:
TraceLeaveResult(hres);
}
/*---------------------------------------------------------------------------*/
STDMETHODIMP CQueryFrame::CallForm(THIS_ LPCLSID pclsidForm, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
HRESULT hres;
LPQUERYFORM pQueryForm = _pCurrentForm;
TraceEnter(TRACE_FRAME, "CQueryFrame::CallForm");
if (pclsidForm)
{
pQueryForm = FindQueryForm(*pclsidForm);
TraceAssert(pQueryForm);
}
if (!pQueryForm)
ExitGracefully(hres, E_FAIL, "Failed to find query form for given CLSID");
hres = CallFormPages(pQueryForm, uMsg, wParam, lParam);
FailGracefully(hres, "Failed when calling CallFormPages");
// hres = S_OK;
exit_gracefully:
TraceLeaveResult(hres);
}
/*---------------------------------------------------------------------------*/
STDMETHODIMP CQueryFrame::GetScope(THIS_ LPCQSCOPE* ppScope)
{
HRESULT hres;
LPQUERYSCOPE pQueryScope;
TraceEnter(TRACE_FRAME, "CQueryFrame::GetScope");
if (!ppScope)
ExitGracefully(hres, E_INVALIDARG, "ppScope == NULL, thats bad");
hres = GetSelectedScope(&pQueryScope);
FailGracefully(hres, "Failed to get the current scope");
*ppScope = (LPCQSCOPE)CoTaskMemAlloc(pQueryScope->pScope->cbStruct);
TraceAssert(*ppScope);
if (!*ppScope)
ExitGracefully(hres, E_OUTOFMEMORY, "Failed to allocate the scope block");
memcpy(*ppScope, pQueryScope->pScope, pQueryScope->pScope->cbStruct);
hres = S_OK;
exit_gracefully:
TraceLeaveResult(hres);
}
/*---------------------------------------------------------------------------*/
STDMETHODIMP CQueryFrame::GetHandler(THIS_ REFIID riid, void **ppv)
{
HRESULT hres;
TraceEnter(TRACE_FRAME, "CQueryFrame::GetHandler");
if (!_pQueryHandler)
ExitGracefully(hres, E_UNEXPECTED, "_pQueryHandler is NULL");
hres = _pQueryHandler->QueryInterface(riid, ppv);
exit_gracefully:
TraceLeaveResult(hres);
}
/*-----------------------------------------------------------------------------
/ Dialog box handler functions (core guts)
/----------------------------------------------------------------------------*/
#define REAL_WINDOW(hwnd) \
(hwnd && \
IsWindowVisible(hwnd) && \
IsWindowEnabled(hwnd) && \
(GetWindowLong(hwnd, GWL_STYLE) & WS_TABSTOP))
HWND _NextTabStop(HWND hwndSearch, BOOL fShift)
{
HWND hwnd;
Trace(TEXT("hwndSearch %08x, fShift %d"), hwndSearch, fShift);
// do we have a window to search into?
while (hwndSearch)
{
// if we have a window then lets check to see if it has any children?
hwnd = GetWindow(hwndSearch, GW_CHILD);
Trace(TEXT("Child of %08x is %08x"), hwndSearch, hwnd);
if (hwnd)
{
// it has a child therefore lets to go its first/last
// and continue the search there for a window that
// matches the criteria we are looking for.
hwnd = GetWindow(hwnd, fShift ? GW_HWNDLAST:GW_HWNDFIRST);
if (!REAL_WINDOW(hwnd))
{
Trace(TEXT("Trying to recurse into %08x"), hwnd);
hwnd = _NextTabStop(hwnd, fShift);
}
Trace(TEXT("Tabstop child of %08x is %08x"), hwndSearch, hwnd);
}
// after all that is hwnd a valid window? if so then pass
// that back out to the caller.
if (REAL_WINDOW(hwnd))
{
Trace(TEXT("Child tab stop was %08x"), hwnd);
return hwnd;
}
// do we have a sibling? if so then lets return that otherwise
// lets just continue to search until we either run out of windows
// or hit something interesting
hwndSearch = GetWindow(hwndSearch, fShift ? GW_HWNDPREV:GW_HWNDNEXT);
if (REAL_WINDOW(hwndSearch))
{
Trace(TEXT("Next tab stop was %08x"), hwndSearch);
return hwndSearch;
}
}
return hwndSearch;
}
INT QueryWnd_MessageProc(HWND hwnd, LPMSG pMsg)
{
LRESULT lResult = 0;
CQueryFrame* pQueryFrame = NULL;
NMHDR nmhdr;
pQueryFrame = (CQueryFrame*)GetWindowLongPtr(hwnd, DWLP_USER);
if (!pQueryFrame)
return 0;
if ((pMsg->message == WM_KEYDOWN) && (pMsg->wParam == VK_TAB))
{
BOOL fCtrl = GetAsyncKeyState(VK_CONTROL) < 0;
BOOL fShift = GetAsyncKeyState(VK_SHIFT) < 0;
// ensure that the focus rectangles are shown
#if (_WIN32_WINNT >= 0x0500)
SendMessage(hwnd, WM_CHANGEUISTATE, MAKEWPARAM(UIS_CLEAR, UISF_HIDEFOCUS), 0);
#endif
if (fCtrl)
{
// if this is a key press within the parent then lets ensure that we
// allow the tab control to change the page correctly. otherwise lets
// just hack around the problem of the result view not handling tabs
// properly.
INT iCur = TabCtrl_GetCurSel(pQueryFrame->_hwndFrame);
INT nPages = TabCtrl_GetItemCount(pQueryFrame->_hwndFrame);
if (fShift)
iCur += (nPages-1);
else
iCur++;
pQueryFrame->SelectFormPage(pQueryFrame->_pCurrentForm, iCur % nPages);
return 1; // we processed it
}
else
{
// is the window that has the focus a child of the result view, if
// so then we must attempt to pass focus to its 1st child and hope
// that is can do the rest.
HWND hwndNext, hwnd = GetFocus();
Trace(TEXT("Current focus window %08x"), hwnd);
while (hwnd && GetWindowLong(hwnd, GWL_STYLE) & WS_CHILD)
{
hwndNext = _NextTabStop(hwnd, fShift);
Trace(TEXT("_NextTabStop yeilds %08x from %08x"), hwndNext, hwnd);
if (hwndNext)
{
Trace(TEXT("SetFocus on child %08x"), hwndNext);
SetFocus(hwndNext);
return 1;
}
while (TRUE)
{
// look up the parent list trying to find a window that we can
// tab back into. We must watch that when we walk out of the
// child list we loop correctly at the top of the list.
hwndNext = GetParent(hwnd);
Trace(TEXT("Parent hwnd %08x"), hwndNext);
if (GetWindowLong(hwndNext, GWL_STYLE) & WS_CHILD)
{
// the parent window is a child, therefore we can check
// to see if has any siblings.
Trace(TEXT("hwndNext is a child, therefore hwndNext of it is %08x"),
GetWindow(hwndNext, fShift ? GW_HWNDPREV:GW_HWNDNEXT));
if (GetWindow(hwndNext, fShift ? GW_HWNDPREV:GW_HWNDNEXT))
{
hwnd = GetWindow(hwndNext, fShift ? GW_HWNDPREV:GW_HWNDNEXT);
Trace(TEXT("Silbing window found %08x"), hwnd);
break;
}
else
{
TraceMsg("There was no sibling, therefore continuing parent loop");
hwnd = hwndNext;
}
}
else
{
// we have hit the parent window of it all (the overlapped one)
// therefore we must attempt to go to its first child. Walk forward
// in the stack looking for a window that matches the
// "REAL_WINDOW" conditions.
hwnd = GetWindow(hwnd, fShift ? GW_HWNDLAST:GW_HWNDFIRST);
Trace(TEXT("First child is %08x"), hwnd);
break; // continue the sibling search etc
}
}
if (REAL_WINDOW(hwnd))
{
SetFocus(hwnd);
return 1;
}
}
}
}
return 0;
}
//
// Main DLGPROC
//
INT_PTR CALLBACK QueryWnd_DlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
CQueryFrame* pQueryFrame;
if (uMsg == WM_INITDIALOG)
{
HRESULT hres;
pQueryFrame = (CQueryFrame*)lParam;
SetWindowLongPtr(hwnd, DWLP_USER, (LRESULT)pQueryFrame);
hres = pQueryFrame->OnInitDialog(hwnd);
Trace(TEXT("OnInitDialog returns %08x"), hres);
if (FAILED(hres))
{
TraceMsg("Failed to initialize the dialog, Destroying the window");
pQueryFrame->CloseQueryFrame(hres);
DestroyWindow(hwnd);
}
}
else
{
pQueryFrame = (CQueryFrame*)GetWindowLongPtr(hwnd, DWLP_USER);
if (!pQueryFrame)
goto exit_gracefully;
switch (uMsg)
{
case WM_ERASEBKGND:
{
HDC hdc = (HDC)wParam;
RECT rc;
// if we have a DC then lets fill it, and if we have a
// query form then lets paint the divider between the menu bar and
// this area.
if (hdc)
{
GetClientRect(hwnd, &rc);
FillRect(hdc, &rc, (HBRUSH)(COLOR_3DFACE+1));
if (!(pQueryFrame->_pOpenQueryWnd->dwFlags & OQWF_HIDEMENUS))
DrawEdge(hdc, &rc, EDGE_ETCHED, BF_TOP);
SetWindowLongPtr(hwnd, DWLP_MSGRESULT, 1L);
}
return 1;
}
case WM_NOTIFY:
return pQueryFrame->OnNotify((int)wParam, (LPNMHDR)lParam);
case WM_SIZE:
pQueryFrame->OnSize(LOWORD(lParam), HIWORD(lParam));
return(1);
case WM_GETMINMAXINFO:
pQueryFrame->OnGetMinMaxInfo((LPMINMAXINFO)lParam);
return(1);
case WM_COMMAND:
pQueryFrame->OnCommand(wParam, lParam);
return(1);
case WM_ACTIVATE:
pQueryFrame->_pQueryHandler->ActivateView(wParam ? CQRVA_ACTIVATE : CQRVA_DEACTIVATE, 0, 0);
return(1);
case WM_INITMENU:
pQueryFrame->OnInitMenu((HMENU)wParam);
return(1);
case WM_SETCURSOR:
{
// do we have any scopes? if not then let us display the wait
// cursor for the user. if we have a query running then lets
// display the app start cursor.
if (!pQueryFrame->_fAddScopesNYI &&
!ComboBox_GetCount(pQueryFrame->_hwndLookIn))
{
if (LOWORD(lParam) == HTCLIENT)
{
SetCursor(LoadCursor(NULL, MAKEINTRESOURCE(IDC_WAIT)));
SetWindowLongPtr(hwnd, DWLP_MSGRESULT, 1L);
return 1;
}
}
break;
}
case WM_INITMENUPOPUP:
{
// only send sub-menu activates if the menu bar is being tracked, this is
// handled within OnInitMenu, if we are not tracking the menu then we
// assume that the client has already primed the menu and that they are
// using some kind of popup menu.
if (pQueryFrame->_fTrackingMenuBar)
pQueryFrame->_pQueryHandler->ActivateView(CQRVA_INITMENUBARPOPUP, wParam, lParam);
return(1);
}
case WM_ENTERMENULOOP:
pQueryFrame->OnEnterMenuLoop(TRUE);
return(1);
case WM_EXITMENULOOP:
pQueryFrame->OnEnterMenuLoop(FALSE);
return(1);
case WM_MENUSELECT:
{
UINT uID = LOWORD(wParam);
UINT uFlags = HIWORD(wParam);
HMENU hMenu = (HMENU)lParam;
// the command opens a popup menu the the uID is actually
// the index into the menu, so lets ensure that we pick
// up the correct ID by calling GetMenuItemInfo, note that
// GetMenuItemID returns -1 in this case which is totally
// useless.
if (uFlags & MF_POPUP)
{
MENUITEMINFO mii;
ZeroMemory(&mii, SIZEOF(mii));
mii.cbSize = SIZEOF(mii);
mii.fMask = MIIM_ID;
if (GetMenuItemInfo(hMenu, uID, TRUE, &mii))
uID = mii.wID;
}
pQueryFrame->OnMenuSelect(hMenu, uID);
return(1);
}
case WM_SYSCOMMAND:
if (wParam == SC_CLOSE)
{
pQueryFrame->CloseQueryFrame(S_FALSE);
return(1);
}
break;
case WM_CONTEXTMENU:
{
// there are a couple of controls we don't care about for the
// frame, so lets ignore those when passing the CQRVA_CONTEXTMENU
// through to the handler.
POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
ScreenToClient((HWND)wParam, &pt);
switch (GetDlgCtrlID(ChildWindowFromPoint((HWND)wParam, pt)))
{
case IDC_FORMAREA:
case IDC_FINDANIMATION:
case IDC_STATUS:
return TRUE; // handled
default:
pQueryFrame->_pQueryHandler->ActivateView(CQRVA_CONTEXTMENU, wParam, lParam);
return TRUE;
}
return FALSE;
}
case WM_HELP:
{
LPHELPINFO phi = (LPHELPINFO)lParam;
// filter out those controls we are not interested in (they make no sense)
// to bother the user with
switch (GetDlgCtrlID((HWND)phi->hItemHandle))
{
case IDC_FORMAREA:
case IDC_FINDANIMATION:
case IDC_STATUS:
return TRUE;
default:
pQueryFrame->OnHelp(phi);
return TRUE;
}
return FALSE;
}
case CQFWM_ADDSCOPE:
{
LPCQSCOPE pScope = (LPCQSCOPE)wParam;
BOOL fSelect = LOWORD(lParam);
INT iIndex = HIWORD(lParam);
if (SUCCEEDED(pQueryFrame->AddScope(pScope, iIndex, fSelect)))
SetWindowLongPtr(hwnd, DWLP_MSGRESULT, 1L);
return 1;
}
case CQFWM_GETFRAME:
{
IQueryFrame** ppQueryFrame = (IQueryFrame**)lParam;
if (ppQueryFrame)
{
pQueryFrame->AddRef();
*ppQueryFrame = pQueryFrame;
SetWindowLongPtr(hwnd, DWLP_MSGRESULT, 1L);
}
return 1;
}
case CQFWM_ALLSCOPESADDED:
{
// there is an async scope collector, it has added all the scopes
// so we must now attempt to issue the query if the we are in the
// holding pattern waiting for the scopes to be collected.
pQueryFrame->_fScopesAddedAsync = FALSE; // all scopes have been added
if (pQueryFrame->_pOpenQueryWnd->dwFlags & OQWF_ISSUEONOPEN)
PostMessage(pQueryFrame->_hwnd, CQFWM_STARTQUERY, 0, 0);
return 1;
}
case CQFWM_STARTQUERY:
pQueryFrame->OnFindNow();
return 1;
case CQFWM_SETDEFAULTFOCUS:
{
HWND hwndNextTab = _NextTabStop(pQueryFrame->_pCurrentFormPage->hwndPage, FALSE);
SendMessage(pQueryFrame->_pCurrentFormPage->hwndPage, WM_NEXTDLGCTL, (WPARAM)hwndNextTab, 1);
break;
}
default:
break;
}
}
exit_gracefully:
return(0);
}
/*-----------------------------------------------------------------------------
/ CQueryFrame::CloseQueryFrame
/ ----------------------------
/ Close the query window passing back the data object if required, and ensuring
/ that our result code indicates what is going on.
/
/ In:
/ hResult = result code to pass to the caller
/
/ Out:
/ -
/----------------------------------------------------------------------------*/
VOID CQueryFrame::CloseQueryFrame(HRESULT hres)
{
TraceEnter(TRACE_FRAME, "CQueryFrame::CloseQueryFrame");
Trace(TEXT("hResult %08x"), hres);
// If we succeeded then attempt to collect the IDataObject and pass it
// back to the caller.
if (hres == S_OK)
{
if (_ppDataObject)
{
hres = _pQueryHandler->GetViewObject(CQRVS_SELECTION, IID_IDataObject, (LPVOID*)_ppDataObject);
FailGracefully(hres, "Failed when collecting the data object");
}
if ((_pOpenQueryWnd->dwFlags & OQWF_SAVEQUERYONOK) && _pOpenQueryWnd->pPersistQuery)
{
hres = SaveQuery(_pOpenQueryWnd->pPersistQuery);
FailGracefully(hres, "Failed when persisting query to IPersistQuery blob");
}
hres = S_OK; // success
}
exit_gracefully:
_hResult = hres;
_fExitModalLoop = TRUE; // bomb out of the modal loop
TraceLeave();
}
/*-----------------------------------------------------------------------------
/ CQueryFrame::FrameMessageBox
/ ----------------------------
/ Our message box for putting up prompts that relate to the current
/ query. We handle getting the view information and displaying
/ the prompt, returning the result from MessageBox.
/
/ In:
/ pPrompt = text displayed as a prompt
/ uType = message box type
/
/ Out:
/ INT
/----------------------------------------------------------------------------*/
INT CQueryFrame::FrameMessageBox(LPCTSTR pPrompt, UINT uType)
{
TCHAR szTitle[MAX_PATH];
CQVIEWINFO vi;
TraceEnter(TRACE_FRAME, "CQueryFrame::FrameMessageBox");
ZeroMemory(&vi, SIZEOF(vi));
//vi. dwFlags = 0; // display attributes
if (SUCCEEDED(_pQueryHandler->GetViewInfo(&vi)) && vi.hInstance && vi.idTitle)
LoadString(vi.hInstance, vi.idTitle, szTitle, ARRAYSIZE(szTitle));
else
GetWindowText(_hwnd, szTitle, ARRAYSIZE(szTitle));
TraceLeaveValue(MessageBox(_hwnd, pPrompt, szTitle, uType));
}
/*-----------------------------------------------------------------------------
/ CQueryFrame::OnInitDlg
/ ----------------------
/ Handle a WM_INITDAILOG message, this is sent as the first thing the
/ dialog receives, therefore we must handle our initialization that
/ was not handled in the constructor.
/
/ In:
/ hwnd = handle of dialog we are initializing
/
/ Out:
/ HRESULT
/----------------------------------------------------------------------------*/
HRESULT CQueryFrame::OnInitDialog(HWND hwnd)
{
HRESULT hres;
HICON hIcon = NULL;
TCHAR szGUID[GUIDSTR_MAX+1];
TCHAR szBuffer[MAX_PATH];
CQVIEWINFO vi;
INT dyControls = 0;
RECT rect, rect2;
SIZE size;
TraceEnter(TRACE_FRAMEDLG, "CQueryFrame::OnInitDialog");
// get the HKEY for the handler we are using
hres = GetKeyForCLSID(_pOpenQueryWnd->clsidHandler, NULL, &_hkHandler);
FailGracefully(hres, "Failed to open handlers HKEY");
// pick up the control handles and store them, saves picking them up later
_hwnd = hwnd;
_hwndFrame = GetDlgItem(hwnd, IDC_FORMAREA);
_hwndLookForLabel = GetDlgItem(hwnd, CQID_LOOKFORLABEL);
_hwndLookFor = GetDlgItem(hwnd, CQID_LOOKFOR);
_hwndLookInLabel = GetDlgItem(hwnd, CQID_LOOKINLABEL);
_hwndLookIn = GetDlgItem(hwnd, CQID_LOOKIN);
_hwndBrowse = GetDlgItem(hwnd, CQID_BROWSE);
_hwndFindNow = GetDlgItem(hwnd, CQID_FINDNOW);
_hwndStop = GetDlgItem(hwnd, CQID_STOP);
_hwndNewQuery = GetDlgItem(hwnd, CQID_CLEARALL);
_hwndFindAnimation = GetDlgItem(hwnd, IDC_FINDANIMATION);
_hwndOK = GetDlgItem(hwnd, IDOK);
_hwndCancel = GetDlgItem(hwnd, IDCANCEL);
// when enable is called this will be the first
_fFormFirstEnable = TRUE;
// call the IQueryHandler interface and get its display attributes,
// then reflect these into the dialog we are about to display to the
// outside world.
vi.dwFlags = 0;
vi.hInstance = NULL;
vi.idLargeIcon = 0;
vi.idSmallIcon = 0;
vi.idTitle = 0;
vi.idAnimation = 0;
hres = _pQueryHandler->GetViewInfo(&vi);
FailGracefully(hres, "Failed when getting the view info from the handler");
_dwHandlerViewFlags = vi.dwFlags;
if (vi.hInstance)
{
HICON hiTemp = NULL;
if (vi.idLargeIcon)
{
_hiconLarge = (HICON)LoadImage(vi.hInstance,
MAKEINTRESOURCE(vi.idLargeIcon),
IMAGE_ICON,
0, 0,
LR_DEFAULTCOLOR|LR_DEFAULTSIZE);
if (_hiconLarge)
SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM)_hiconLarge);
}
if (vi.idSmallIcon)
{
_hiconSmall = (HICON)LoadImage(vi.hInstance,
MAKEINTRESOURCE(vi.idLargeIcon),
IMAGE_ICON,
GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
LR_DEFAULTCOLOR);
if (_hiconSmall)
SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)_hiconSmall);
}
if (vi.idTitle)
{
LoadString(vi.hInstance, vi.idTitle, szBuffer, ARRAYSIZE(szBuffer));
SetWindowText(hwnd, szBuffer);
}
}
if (vi.hInstance && vi.idAnimation)
{
SetWindowLongPtr(_hwndFindAnimation, GWLP_HINSTANCE, (LRESULT)vi.hInstance);
Animate_Open(_hwndFindAnimation, MAKEINTRESOURCE(vi.idAnimation));
}
else
{
Animate_Open(_hwndFindAnimation, MAKEINTRESOURCE(IDR_FINDANIMATION));
}
// now adjust the positions and hide the controls we are not interested in
if (_pOpenQueryWnd->dwFlags & OQWF_REMOVEFORMS)
{
ShowWindow(_hwndLookForLabel, SW_HIDE);
ShowWindow(_hwndLookFor, SW_HIDE);
}
if (_pOpenQueryWnd->dwFlags & OQWF_REMOVESCOPES)
{
ShowWindow(_hwndLookInLabel, SW_HIDE);
ShowWindow(_hwndLookIn, SW_HIDE);
ShowWindow(_hwndBrowse, SW_HIDE);
}
// hiding both the scopes and the forms control causes us to
// move all the controls up by so many units.
if ((_pOpenQueryWnd->dwFlags & (OQWF_REMOVEFORMS|OQWF_REMOVESCOPES))
== (OQWF_REMOVEFORMS|OQWF_REMOVESCOPES))
{
GetRealWindowInfo(_hwndLookForLabel, &rect, NULL);
GetRealWindowInfo(_hwndFrame, &rect2, NULL);
dyControls += rect2.top - rect.top;
Trace(TEXT("Moving all controls up by %d units"), dyControls);
OffsetWindow(_hwndFrame, 0, -dyControls);
OffsetWindow(_hwndFindNow, 0, -dyControls);
OffsetWindow(_hwndStop, 0, -dyControls);
OffsetWindow(_hwndNewQuery, 0, -dyControls);
OffsetWindow(_hwndFindAnimation, 0, -dyControls);
OffsetWindow(_hwndOK, 0, -dyControls);
if (_hwndCancel)
OffsetWindow(_hwndCancel, 0, -dyControls);
}
// hiding OK/Cancel so lets adjust the size here to include the
// OK/Cancel buttons disappearing, note that we update dyControls
// to include this delta
if (!(_pOpenQueryWnd->dwFlags & OQWF_OKCANCEL))
{
ShowWindow(_hwndOK, SW_HIDE);
if (_hwndCancel)
ShowWindow(_hwndCancel, SW_HIDE);
// if this is the filter dialog then lets ensure that
// we trim the OK/Cancel buttons from the size by adjusting the
// dyControls further.
GetRealWindowInfo(_hwndOK, &rect, NULL);
GetRealWindowInfo(_hwndFrame, &rect2, NULL);
dyControls += rect.bottom - rect2.bottom;
}
// having performed that extra bit of initialization lets cache the
// positions of the various controls, to make sizing more fun...
GetClientRect(hwnd, &rect2);
rect2.bottom -= dyControls;
_dyResultsTop = rect2.bottom;
GetRealWindowInfo(hwnd, NULL, &size);
GetRealWindowInfo(_hwndFrame, &rect, &_szForm);
Trace(TEXT("dyControls %d"), dyControls);
size.cy -= dyControls;
_dxFormAreaLeft = rect.left;
_dxFormAreaRight = rect2.right - rect.right;
_szMinTrack.cx = size.cx - _szForm.cx;
_szMinTrack.cy = size.cy - _szForm.cy;
if (!(_pOpenQueryWnd->dwFlags & OQWF_HIDEMENUS))
{
TraceMsg("Adjusting _szMinTrack.cy to account for menu bar");
_szMinTrack.cy += GetSystemMetrics(SM_CYMENU);
}
GetRealWindowInfo(_hwndBrowse, &rect, NULL);
_dxButtonsLeft = rect2.right - rect.left;
GetRealWindowInfo(_hwndLookIn, &rect, NULL);
_dxGap = (rect2.right - rect.right) - _dxButtonsLeft;
GetRealWindowInfo(_hwndFindAnimation, &rect, NULL);
_dxAnimationLeft = rect2.right - rect.left;
GetRealWindowInfo(_hwndOK, &rect, NULL);
_dyOKTop = rect2.bottom - rect.top;
_dyGap = size.cy - rect.bottom;
// Now collect the forms and pages, then walk them building the size
// information that we need.
hres = GatherForms();
FailGracefully(hres, "Failed to init form list");
_szMinTrack.cx += _szForm.cx;
_szMinTrack.cy += _szForm.cy;
// Populate the scope control by querying the handler for them,
// if there are none then we display a suitable message box and
// let the user know that something went wrong.
hres = PopulateScopeControl();
FailGracefully(hres, "Failed to init scope list");
_fScopesPopulated = TRUE; // scope control now populated
// perform final fix up of the window, ensure that we size it so that
// the entire form and buttons are visible. Then set ourselves into the
// no query state and reset the animation.
SetWindowPos(hwnd,
NULL,
0, 0,
_szMinTrack.cx, _szMinTrack.cy,
SWP_NOMOVE|SWP_NOZORDER);
if (_pOpenQueryWnd->dwFlags & OQWF_HIDEMENUS)
::SetMenu(hwnd, NULL);
hres = PopulateFormControl(_pOpenQueryWnd->dwFlags & OQWF_SHOWOPTIONAL);
FailGracefully(hres, "Failed to populate form control");
// Now load the query which inturn selects the form that we should be using,
// if there is no query to load then either use the default form or
// the first in the list.
if ((_pOpenQueryWnd->dwFlags & OQWF_LOADQUERY) && _pOpenQueryWnd->pPersistQuery)
{
hres = LoadQuery(_pOpenQueryWnd->pPersistQuery);
FailGracefully(hres, "Failed when to load query from supplied IPersistQuery");
}
else
{
if (_pOpenQueryWnd->dwFlags & OQWF_DEFAULTFORM)
{
SelectForm(_pOpenQueryWnd->clsidDefaultForm);
if (!_pCurrentForm)
ExitGracefully(hres, E_FAIL, "Failed to select the query form");
}
else
{
INT iForm = (int)ComboBox_GetItemData(_hwndLookFor, 0);
LPQUERYFORM pQueryForm = (LPQUERYFORM)DSA_GetItemPtr(_hdsaForms, iForm);
TraceAssert(pQueryForm);
SelectForm(pQueryForm->clsidForm);
}
}
StartQuery(FALSE);
// issue on open, therefore lets get the query going, if there is async
// scope collection then the query will be issued by the bg thread.
if (_pOpenQueryWnd->dwFlags & OQWF_ISSUEONOPEN)
PostMessage(_hwnd, CQFWM_STARTQUERY, 0, 0);
SetForegroundWindow(hwnd);
hres = S_OK; // success
exit_gracefully:
TraceLeaveResult(hres);
}
/*-----------------------------------------------------------------------------
/ CQueryFrame::EnableControls
/ ---------------------------
/ Set the controls into their enabled/disabled state based on the
/ state of the dialog.
/
/ In:
/ -
/
/ Out:
/ HRESULT
/----------------------------------------------------------------------------*/
VOID CQueryFrame::DoEnableControls(VOID)
{
BOOL fScopes = (_fAddScopesNYI || ComboBox_GetCount(_hwndLookIn));
BOOL fEnable = fScopes;
UINT uEnable = fScopes ? MF_ENABLED:MF_GRAYED;
HMENU hMenu = GetMenu(_hwnd);
INT i;
TraceEnter(TRACE_FRAMEDLG, "CQueryFrame::DoEnableControls");
EnableWindow(_hwndFindNow, !_fQueryRunning && fEnable);
EnableWindow(_hwndStop, _fQueryRunning && fEnable);
EnableWindow(_hwndNewQuery, fEnable);
EnableWindow(_hwndLookFor, !_fQueryRunning && fEnable);
EnableWindow(_hwndLookIn, !_fQueryRunning && fEnable);
EnableWindow(_hwndBrowse, !_fQueryRunning && fEnable);
if (_pCurrentForm)
{
CallFormPages(_pCurrentForm, CQPM_ENABLE, (BOOL)(!_fQueryRunning && fEnable), 0);
if (_fFormFirstEnable)
{
PostMessage(_hwnd, CQFWM_SETDEFAULTFOCUS, 0, 0);
_fFormFirstEnable = FALSE;
}
}
if (_hwndOK)
EnableWindow(_hwndOK, !_fQueryRunning && fEnable);
if (_hwndCancel)
EnableWindow(_hwndCancel, !_fQueryRunning && fEnable);
for (i = 0 ; i < GetMenuItemCount(hMenu) ; i++)
EnableMenuItem(hMenu, i, MF_BYPOSITION|uEnable);
DrawMenuBar(_hwnd);
TraceLeave();
}
/*-----------------------------------------------------------------------------
/ CQueryFrame::OnNotify
/ ---------------------
/ Notify event received, decode it and handle accordingly
/
/ In:
/ idCtrl = ID of control issuing notify
/ pNotify -> LPNMHDR structure
/
/ Out:
/ LRESULT
/----------------------------------------------------------------------------*/
LRESULT CQueryFrame::OnNotify(INT idCtrl, LPNMHDR pNotify)
{
LRESULT lr = 0;
TraceEnter(TRACE_FRAMEDLG, "CQueryFrame::OnNotify");
// TCN_SELCHANGE used to indicate that the currently active
// tab has been changed
if (pNotify->code == TCN_SELCHANGE)
{
INT iPage = TabCtrl_GetCurSel(_hwndFrame);
TraceAssert(iPage >= 0);
if (iPage >= 0)
{
SelectFormPage(_pCurrentForm, iPage);
lr = 0;
}
}
TraceLeaveResult((HRESULT)lr);
}
/*-----------------------------------------------------------------------------
/ CQueryFrame::OnSize
/ -------------------
/ The window is being sized and we received a WM_SIZE, therefore move
/ the content of the window about.
/
/ In:
/ cx = new width
/ cy = new height
/
/ Out:
/ -
/----------------------------------------------------------------------------*/
VOID CQueryFrame::OnSize(INT cx, INT cy)
{
HDWP hdwp;
RECT rect, rect2;
SIZE sz, sz2;
INT x, cxForm, cyForm;
INT dyResultsTop = 0;
TraceEnter(TRACE_FRAMEDLG, "CQueryFrame::OnSize");
// do as much as we can within a DefWindowPos to aVOID too
// much flicker.
hdwp = BeginDeferWindowPos(16);
if (hdwp)
{
{
// adjust the look for controls, if there is no scope then
// stretch the look for control over the entire client area
// of the window.
if (!(_pOpenQueryWnd->dwFlags & OQWF_REMOVEFORMS))
{
if (_pOpenQueryWnd->dwFlags & OQWF_REMOVESCOPES)
{
GetRealWindowInfo(_hwndLookFor, &rect, &sz);
hdwp = DeferWindowPos(hdwp, _hwndLookFor, NULL,
0, 0,
(cx - _dxFormAreaRight) - rect.left, sz.cy,
SWP_NOZORDER|SWP_NOMOVE);
}
}
// adjust the "look in" controls, if there is a form control
// then stretch across the remaining space, otherwise move the
// label and stretch the scope over the remaining space.
if (!(_pOpenQueryWnd->dwFlags & OQWF_REMOVESCOPES))
{
INT xScopeRight;
GetRealWindowInfo(_hwndLookIn, &rect, &sz);
xScopeRight = cx - _dxFormAreaRight - _dxGap;
if (_pOpenQueryWnd->dwFlags & OQWF_HIDESEARCHUI)
{
//
// when hiding the search UI, then adjust the button position to account for the
// right edge of the dialog not having buttons.
//
xScopeRight -= (_dxButtonsLeft - _dxFormAreaRight) + _dxGap;
}
if (_pOpenQueryWnd->dwFlags & OQWF_REMOVEFORMS)
{
GetRealWindowInfo(_hwndLookInLabel, &rect2, &sz2);
hdwp = DeferWindowPos(hdwp, _hwndLookInLabel, NULL,
_dxFormAreaLeft, rect2.top,
0, 0,
SWP_NOSIZE|SWP_NOZORDER);
hdwp = DeferWindowPos(hdwp, _hwndLookIn, NULL,
_dxFormAreaLeft+sz2.cx, rect.top,
xScopeRight - (_dxFormAreaLeft + sz2.cx), sz.cy,
SWP_NOZORDER);
}
else
{
hdwp = DeferWindowPos(hdwp, _hwndLookIn, NULL,
0, 0,
xScopeRight - rect.left, sz.cy,
SWP_NOZORDER|SWP_NOMOVE);
}
// browse control is displayed always if we are showing the
// scopes.
GetRealWindowInfo(_hwndBrowse, &rect, NULL);
hdwp = DeferWindowPos(hdwp, _hwndBrowse, NULL,
xScopeRight+_dxGap, rect.top,
0, 0,
SWP_NOZORDER|SWP_NOSIZE);
}
// all the buttons have a fixed offset from the right edege
// of the dialog, so just handle that as we can.
if (!(_pOpenQueryWnd->dwFlags & OQWF_HIDESEARCHUI))
{
GetRealWindowInfo(_hwndFindNow, &rect, NULL);
hdwp = DeferWindowPos(hdwp, _hwndFindNow, NULL,
(cx - _dxButtonsLeft), rect.top,
0, 0,
SWP_NOZORDER|SWP_NOSIZE);
GetRealWindowInfo(_hwndStop, &rect, &sz);
hdwp = DeferWindowPos(hdwp, _hwndStop, NULL,
(cx - _dxButtonsLeft), rect.top,
0, 0,
SWP_NOZORDER|SWP_NOSIZE);
GetRealWindowInfo(_hwndNewQuery, &rect, NULL);
hdwp = DeferWindowPos(hdwp, _hwndNewQuery, NULL,
(cx - _dxButtonsLeft), rect.top,
0, 0,
SWP_NOZORDER|SWP_NOSIZE);
GetRealWindowInfo(_hwndFindAnimation, &rect2, &sz2);
hdwp = DeferWindowPos(hdwp, _hwndFindAnimation, NULL,
(cx - _dxAnimationLeft), rect2.top,
0, 0,
SWP_NOZORDER|SWP_NOSIZE);
}
// position the form "frame" control
GetRealWindowInfo(_hwndFrame, &rect, &sz);
cxForm = (cx - _dxFormAreaRight) - rect.left;
hdwp = DeferWindowPos(hdwp, _hwndFrame, NULL,
0, 0,
cxForm, _szForm.cy,
SWP_NOZORDER|SWP_NOMOVE);
dyResultsTop = _dyResultsTop;
// when we have a cancel button then ensure that it is to the right
// of the OK button.
if (_hwndCancel)
{
GetRealWindowInfo(_hwndCancel, &rect, &sz);
hdwp = DeferWindowPos(hdwp, _hwndCancel, NULL,
(cx - _dxButtonsLeft), dyResultsTop - _dyOKTop,
0, 0,
SWP_NOZORDER|SWP_NOSIZE);
GetRealWindowInfo(_hwndOK, &rect, &sz);
hdwp = DeferWindowPos(hdwp, _hwndOK, NULL,
(cx - _dxButtonsLeft - _dxGap - sz.cx), dyResultsTop - _dyOKTop,
0, 0,
SWP_NOZORDER|SWP_NOSIZE);
}
else
{
GetRealWindowInfo(_hwndOK, &rect, &sz);
hdwp = DeferWindowPos(hdwp, _hwndOK, NULL,
(cx - _dxButtonsLeft), dyResultsTop - _dyOKTop,
0, 0,
SWP_NOZORDER|SWP_NOSIZE);
}
}
// move the results and status bar as required
if (_hwndResults)
{
hdwp = DeferWindowPos(hdwp, _hwndStatus, NULL,
0, cy - _cyStatus,
cx, _cyStatus,
SWP_SHOWWINDOW|SWP_NOZORDER);
hdwp = DeferWindowPos(hdwp, _hwndResults, NULL,
0, dyResultsTop,
cx, max(0, cy - (dyResultsTop + _cyStatus)),
SWP_SHOWWINDOW|SWP_NOZORDER);
}
EndDeferWindowPos(hdwp);
// here is the strange bit, by this point we have moved & sized all the
// controls on the dialog except the current page, as this is a child window
// and not a control which in turn has controls doing this would break
// the DefWindowPos path, therefore having updated everybody, lets update
// the page.
if (_pCurrentFormPage && _pCurrentFormPage->hwndPage)
{
GetRealWindowInfo(_hwndFrame, &rect, NULL);
TabCtrl_AdjustRect(_hwndFrame, FALSE, &rect);
cxForm = rect.right - rect.left;
cyForm = rect.bottom - rect.top;
SetWindowPos(_pCurrentFormPage->hwndPage, NULL,
rect.left, rect.top, cxForm, cyForm,
SWP_NOZORDER);
}
}
TraceLeave();
}
/*-----------------------------------------------------------------------------
/ CQueryFrame::OnGetMinMaxInfo
/ ----------------------------
/ The window is being sized and we received a WM_SIZE, therefore move
/ the content of the window about.
/
/ In:
/ lpmmin -> MINMAXINFO structure
/
/ Out:
/ -
/----------------------------------------------------------------------------*/
VOID CQueryFrame::OnGetMinMaxInfo(LPMINMAXINFO lpmmi)
{
RECT rect = {0, 0, 0, 0};
TraceEnter(TRACE_FRAMEDLG, "CQueryFrame::OnGetMinMaxInfo");
#if 0
if (!_fHideSearchPane)
#endif
{
lpmmi->ptMinTrackSize.x = _szMinTrack.cx;
lpmmi->ptMinTrackSize.y = _szMinTrack.cy;
if (!_hwndResults)
{
lpmmi->ptMaxSize.y = lpmmi->ptMinTrackSize.y;
lpmmi->ptMaxTrackSize.y = lpmmi->ptMinTrackSize.y;
}
}
#if 0
else
{
AdjustWindowRect(&rect, GetWindowLong(_hwnd, GWL_STYLE), (NULL != GetMenu(_hwnd)));
lpmmi->ptMinTrackSize.y = rect.bottom - rect.top;
}
#endif
if (_hwndResults && _hwndStatus)
lpmmi->ptMinTrackSize.y += _cyStatus;
TraceLeave();
}
/*-----------------------------------------------------------------------------
/ CQueryFrame::OnCommand
/ ----------------------
/ We have recieved a WM_COMMAND so process it accordingly.
/
/ In:
/ wParam, lParam = parameters from the message
/
/ Out:
/ -
/----------------------------------------------------------------------------*/
VOID CQueryFrame::OnCommand(WPARAM wParam, LPARAM lParam)
{
HRESULT hres;
UINT uID = LOWORD(wParam);
UINT uNotify = HIWORD(wParam);
HWND hwndControl = (HWND)lParam;
INT i;
TraceEnter(TRACE_FRAMEDLG, "CQueryFrame::OnCommand");
Trace(TEXT("uID %08x, uNotify %d, hwndControl %08x"), uID, uNotify, hwndControl);
switch (uID)
{
case IDOK:
TraceMsg("IDOK received");
CloseQueryFrame(S_OK);
break;
case IDCANCEL:
TraceMsg("IDCANCEL received");
CloseQueryFrame(S_FALSE);
break;
case CQID_LOOKFOR:
{
if (uNotify == CBN_SELCHANGE)
{
INT iSel = ComboBox_GetCurSel(_hwndLookFor);
INT iForm = (int)ComboBox_GetItemData(_hwndLookFor, iSel);
LPQUERYFORM pQueryForm = (LPQUERYFORM)DSA_GetItemPtr(_hdsaForms, iForm);
TraceAssert(pQueryForm);
if (S_FALSE == SelectForm(pQueryForm->clsidForm))
{
TraceMsg("SelectForm return S_FALSE, so the user doesn't want the new form");
PostMessage(_hwndLookFor, CB_SETCURSEL, (WPARAM)_pCurrentForm->iForm, 0);
}
}
break;
}
case CQID_BROWSE:
OnBrowse();
break;
case CQID_FINDNOW:
OnFindNow();
break;
case CQID_STOP:
{
LONG style;
_pQueryHandler->StopQuery();
// For some reason, the standard method of getting the old
// def button used in SetDefButton() below isn't working,
// so we have to forcibly remove the BS_DEFPUSHBUTTON style
// from the CQID_STOP button.
style = GetWindowLong(_hwndStop, GWL_STYLE) & ~BS_DEFPUSHBUTTON;
SendMessage(_hwndStop,
BM_SETSTYLE,
MAKEWPARAM(style, 0),
MAKELPARAM(TRUE, 0));
SetDefButton(_hwnd, CQID_FINDNOW);
SetFocus(_hwndFindNow);
break;
}
case CQID_CLEARALL:
OnNewQuery(TRUE); // discard the current query
break;
case CQID_FILE_CLOSE:
TraceMsg("CQID_FILE_CLOSE received");
CloseQueryFrame(S_FALSE);
break;
default:
_pQueryHandler->InvokeCommand(_hwnd, uID);
break;
}
TraceLeave();
}
/*-----------------------------------------------------------------------------
/ CQueryFrame::OnInitMenu
/ -----------------------
/ Handle telling the handler that the menu is being initialised, however
/ this should only happen if the menu being activated is the
/ menu bar, otherwise we assume that the caller is tracking a popup
/ menu and has performed the required initalization.
/
/ In:
/ wParam, lParam = parameters from the WM_INITMENU
/
/ Out:
/ -
/----------------------------------------------------------------------------*/
VOID CQueryFrame::OnInitMenu(HMENU hMenu)
{
TraceEnter(TRACE_FRAMEDLG, "CQueryFrame::OnInitMenu");
_fTrackingMenuBar = (GetMenu(_hwnd) == hMenu);
if (_fTrackingMenuBar)
{
TraceMsg("Tracking the menu bar, sending activate");
_pQueryHandler->ActivateView(CQRVA_INITMENUBAR, (WPARAM)hMenu, 0L);
EnableMenuItem(hMenu, CQID_VIEW_SEARCHPANE,
MF_BYCOMMAND|(_hwndResults != NULL) ? MF_ENABLED:MF_GRAYED);
}
TraceLeave();
}
/*-----------------------------------------------------------------------------
/ CQueryFrame::OnEnterMenuLoop
/ ----------------------------
/ When the user displays a menu we must reflect this into the status bar
/ so that we can give the user help text relating to the commands they
/ select.
/
/ In:
/ fEntering = entering the menu loop, or leaving.
/
/ Out:
/ -
/----------------------------------------------------------------------------*/
VOID CQueryFrame::OnEnterMenuLoop(BOOL fEntering)
{
TraceEnter(TRACE_FRAMEDLG, "CQueryFrame::OnEnterMenuLoop");
if (_hwndStatus)
{
if (fEntering)
{
SendMessage(_hwndStatus, SB_SIMPLE, (WPARAM)TRUE, 0L);
SendMessage(_hwndStatus, SB_SETTEXT, (WPARAM)SBT_NOBORDERS|255, 0L);
}
else
{
SendMessage(_hwndStatus, SB_SIMPLE, (WPARAM)FALSE, 0L);
}
}
TraceLeave();
}
/*-----------------------------------------------------------------------------
/ CQueryFrame::OnMenuSelect
/ -------------------------
/ Get the status text for this menu item and display it to the user,
/ if this doesn't map to any particular command then NULL out
/ the string. At this point we also trap our commands.
/
/ In:
/ hMenu = menu the user is on
/ uID = command ID for that item
/
/ Out:
/ -
/----------------------------------------------------------------------------*/
VOID CQueryFrame::OnMenuSelect(HMENU hMenu, UINT uID)
{
TCHAR szBuffer[MAX_PATH] = { TEXT('\0') };
TraceEnter(TRACE_FRAMEDLG, "CQueryFrame::OnMenuSelect");
Trace(TEXT("hMenu %08x, uID %08x"), hMenu, uID);
if (_hwndStatus)
{
switch (uID)
{
case CQID_FILE_CLOSE:
case CQID_VIEW_SEARCHPANE:
LoadString(GLOBAL_HINSTANCE, uID, szBuffer, ARRAYSIZE(szBuffer));
break;
default:
_pQueryHandler->GetCommandString(uID, 0x0, szBuffer, ARRAYSIZE(szBuffer));
break;
}
Trace(TEXT("Setting status bar to: %s"), szBuffer);
SendMessage(_hwndStatus, SB_SETTEXT, (WPARAM)SBT_NOBORDERS|255, (LPARAM)szBuffer);
}
TraceLeave();
}
/*-----------------------------------------------------------------------------
/ CQueryFrame::OnFindNow
/ ----------------------
// Issue the query, resulting in a view window being created and then issuing
// the parameter block to the query client.
/
/ In:
/ Out:
/ HRESULT
/----------------------------------------------------------------------------*/
HRESULT CQueryFrame::OnFindNow(VOID)
{
HRESULT hres;
CQPARAMS qp = { 0 };
LPQUERYSCOPE pQueryScope = NULL;
TCHAR szBuffer[MAX_PATH];
BOOL fFixSize = TRUE;
RECT rc;
DECLAREWAITCURSOR;
BOOL fSetCursor = FALSE;
TraceEnter(TRACE_FRAMEDLG, "CQueryFrame::OnFindNow");
TraceAssert(_pCurrentForm != NULL);
if (_fQueryRunning)
ExitGracefully(hres, E_FAIL, "Quyery is already running");
SetWaitCursor();
fSetCursor = TRUE;
// If we have not created the viewer before now lets do so, also at the
// same time we attempt to fix the window size to ensure that enough
// of the view is visible.
if (!_hwndResults)
{
if (!_hwndStatus)
{
_hwndStatus = CreateStatusWindow(WS_CHILD, NULL, _hwnd, IDC_STATUS);
GetClientRect(_hwndStatus, &rc);
_cyStatus = rc.bottom - rc.top;
}
// Now construct the result viewer for us to use
hres = _pQueryHandler->CreateResultView(_hwnd, &_hwndResults);
FailGracefully(hres, "Failed when creating the view object");
GetWindowRect(_hwnd, &rc);
SetWindowPos(_hwnd, NULL,
0, 0,
rc.right - rc.left,
_szMinTrack.cy + VIEWER_DEFAULT_CY,
SWP_NOZORDER|SWP_NOMOVE);
}
// are we still collecting the scopes async? If so then lets wait until
// they have all arrived before we set the UI running.
if (_hdsaScopes && DSA_GetItemCount(_hdsaScopes))
{
// Collect the parameters ready for starting the query, if this fails then
// there is no point us continuing.
ZeroMemory(&qp, SIZEOF(qp));
qp.cbStruct = SIZEOF(qp);
//qp.dwFlags = 0x0;
qp.clsidForm = _pCurrentForm->clsidForm; // new NT5 beta 2
hres = GetSelectedScope(&pQueryScope);
FailGracefully(hres, "Failed to get the scope from the LookIn control");
if (pQueryScope)
{
Trace(TEXT("pQueryScope %08x"), pQueryScope);
qp.pQueryScope = pQueryScope->pScope;
}
hres = CallFormPages(_pCurrentForm, CQPM_GETPARAMETERS, 0, (LPARAM)&qp.pQueryParameters);
FailGracefully(hres, "Failed when collecting parameters from form");
if (!qp.pQueryParameters)
{
LoadString(GLOBAL_HINSTANCE, IDS_ERR_NOPARAMS, szBuffer, ARRAYSIZE(szBuffer));
FrameMessageBox(szBuffer, MB_ICONERROR|MB_OK);
ExitGracefully(hres, E_FAIL, "Failed to issue the query, no parameters");
}
// We either already had a view, or have just created one. Either way
// we must now prepare the query for sending.
Trace(TEXT("qp.cbStruct %08x"), qp.cbStruct);
Trace(TEXT("qp.dwFlags %08x"), qp.dwFlags);
Trace(TEXT("qp.pQueryScope %08x"), qp.pQueryScope);
Trace(TEXT("qp.pQueryParameters %08x"), qp.pQueryParameters);
TraceGUID("qp.clsidForm: ", qp.clsidForm);
hres = _pQueryHandler->IssueQuery(&qp);
FailGracefully(hres, "Failed in IssueQuery");
}
else
{
// set the status text to reflect that we are initializng, otherwise it is
// left empty and looks like we have crashed.
if (LoadString(GLOBAL_HINSTANCE, IDS_INITIALIZING, szBuffer, ARRAYSIZE(szBuffer)))
{
SetStatusText(szBuffer);
}
}
hres = S_OK; // success
exit_gracefully:
if (qp.pQueryParameters)
CoTaskMemFree(qp.pQueryParameters);
if (fSetCursor)
ResetWaitCursor();
TraceLeaveResult(hres);
}
/*-----------------------------------------------------------------------------
/ CQueryFrame::OnNewQuery
/ -----------------------
/ Discard the current query, prompting the user as requierd.
/
/ In:
/ fAlwaysPrompt = TRUE if we force prompting of the user
/
/ Out:
/ BOOL
/----------------------------------------------------------------------------*/
BOOL CQueryFrame::OnNewQuery(BOOL fAlwaysPrompt)
{
BOOL fQueryCleared = TRUE;
TCHAR szBuffer[MAX_PATH];
RECT rc;
TraceEnter(TRACE_FRAMEDLG, "CQueryFrame::OnNewQuery");
if (_hwndResults || fAlwaysPrompt)
{
LoadString(GLOBAL_HINSTANCE, IDS_CLEARCURRENT, szBuffer, ARRAYSIZE(szBuffer));
if (IDOK != FrameMessageBox(szBuffer, MB_ICONINFORMATION|MB_OKCANCEL))
ExitGracefully(fQueryCleared, FALSE, "Used cancled new query");
if (_pQueryHandler)
_pQueryHandler->StopQuery();
CallFormPages(_pCurrentForm, CQPM_CLEARFORM, 0, 0);
if (_hwndResults)
{
DestroyWindow(_hwndResults); // no result view now
_hwndResults = NULL;
DestroyWindow(_hwndStatus); // no status bar
_hwndStatus = NULL;
GetWindowRect(_hwnd, &rc); // shrink the window
SetWindowPos(_hwnd, NULL,
0, 0, rc.right - rc.left, _szMinTrack.cy,
SWP_NOZORDER|SWP_NOMOVE);
}
}
exit_gracefully:
TraceLeaveValue(fQueryCleared);
}
/*-----------------------------------------------------------------------------
/ CQueryFrame::OnBrowse
/ ---------------------
/ Browse for a new scope, adding it to the list if not already present,
/ or selecting the previous scope.
/
/ In:
/ Out:
/ HRESULT
/----------------------------------------------------------------------------*/
HRESULT CQueryFrame::OnBrowse(VOID)
{
HRESULT hres;
LPQUERYSCOPE pQueryScope = NULL;
LPCQSCOPE pScope = NULL;
TraceEnter(TRACE_FRAMEDLG, "CQueryFrame::OnBrowse");
// Call the handler and get a scope allocation back, then add it to the list
// of scopes to be displayed.
hres = GetSelectedScope(&pQueryScope);
FailGracefully(hres, "Failed to get the scope from the LookIn control");
Trace(TEXT("Calling BrowseForScope _hwnd %08x, pQueryScope %08x (%08x)"),
_hwnd, pQueryScope, pQueryScope->pScope);
hres = _pQueryHandler->BrowseForScope(_hwnd, pQueryScope ? pQueryScope->pScope:NULL, &pScope);
FailGracefully(hres, "Failed when calling BrowseForScope");
if ((hres != S_FALSE) && pScope)
{
hres = InsertScopeIntoList(pScope, DA_LAST, TRUE);
FailGracefully(hres, "Failed when adding the scope to the control");
ComboBox_SetCurSel(_hwndLookIn, ShortFromResult(hres));
}
hres = S_OK;
exit_gracefully:
if (pScope)
CoTaskMemFree(pScope);
TraceLeaveResult(hres);
}
/*-----------------------------------------------------------------------------
/ CQueryFrame::OnHelp
/ -------------------
/ Invoke the context sensitive help for the window, catch the
/ handler specific and page specific stuff and pass those help
/ requests down to the relevant objects.
/
/ In:
/ pHelpInfo -> help info structure
/
/ Out:
/ HRESULT
/----------------------------------------------------------------------------*/
HRESULT CQueryFrame::OnHelp(LPHELPINFO pHelpInfo)
{
HRESULT hres;
RECT rc;
HWND hwnd = (HWND)pHelpInfo->hItemHandle;
TraceEnter(TRACE_FRAME, "CQueryFrame::OnHelp");
// We are invoking help, theroefore we need ot check to see where element
// of the window we are being invoked for. If it is the
// result view then route the message to that, if its the form then
// likewise.
//
// If we don't hit any of the extension controls then lets pass the
// help onto WinHelp and get it to display the topics we have.
if (pHelpInfo->iContextType != HELPINFO_WINDOW)
ExitGracefully(hres, E_FAIL, "WM_HELP handler only copes with WINDOW objects");
if (_pCurrentFormPage->hwndPage && IsChild(_pCurrentFormPage->hwndPage, hwnd))
{
// it was on the query form page, therefore let it go there, that way
// they can provide topics specific to them
TraceMsg("Invoking help on the form pane");
hres = _CallPageProc(_pCurrentFormPage, CQPM_HELP, 0, (LPARAM)pHelpInfo);
FailGracefully(hres, "Failed when calling page proc to get help");
}
else
{
// pass the help information through to the handler as an activation,
// this should really just be a new method, but this works.
TraceMsg("Invoking help on the results pane");
TraceAssert(_pQueryHandler);
hres = _pQueryHandler->ActivateView(CQRVA_HELP, 0, (LPARAM)pHelpInfo);
FailGracefully(hres, "Handler WndProc returned FALSE");
}
hres = S_OK;
exit_gracefully:
TraceLeaveResult(hres);
}
/*-----------------------------------------------------------------------------
/ Scope helper functions
/----------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------
/ _CallScopeProc
/ --------------
/ Releae the given scope object, freeing the object that is referenced
/ and passing a CQSM_RELEASE message to it.
/
/ In:
/ pQueryScope -> scope object to be called
/ uMsg, pVoid -> parameters for the scope
/
/ Out:
/ HRESULT
/----------------------------------------------------------------------------*/
HRESULT _CallScopeProc(LPQUERYSCOPE pQueryScope, UINT uMsg, LPVOID pVoid)
{
HRESULT hres;
TraceEnter(TRACE_SCOPES, "_CallScopeProc");
Trace(TEXT("pQueryScope %08x, uMsg %d, pVoid %08x"), pQueryScope, uMsg, pVoid);
Trace(TEXT("(cbStruct %d, pScopeProc %08x, lParam %08x)"),
pQueryScope->pScope->cbStruct,
pQueryScope->pScope->pScopeProc,
pQueryScope->pScope->lParam);
if (!pQueryScope)
ExitGracefully(hres, S_OK, "pQueryScope == NULL");
hres = (pQueryScope->pScope->pScopeProc)(pQueryScope->pScope, uMsg, pVoid);
FailGracefully(hres, "Failed calling ScopeProc");
exit_gracefully:
TraceLeaveResult(hres);
}
/*-----------------------------------------------------------------------------
/ _FreeScope
/ ----------
/ Releae the given scope object, freeing the object that is referenced
/ and passing a CQSM_RELEASE message to it.
/
/ In:
/ pQueryScope -> scope object to be released
/
/ Out:
/ INT == 1 always
/----------------------------------------------------------------------------*/
INT _FreeScopeCB(LPVOID pItem, LPVOID pData)
{
return _FreeScope((LPQUERYSCOPE)pItem);
}
INT _FreeScope(LPQUERYSCOPE pQueryScope)
{
TraceEnter(TRACE_SCOPES, "_FreeScope");
Trace(TEXT("pQueryScope %08x, pQueryScope->pScope %08x"), pQueryScope, pQueryScope->pScope);
if (pQueryScope)
{
_CallScopeProc(pQueryScope, CQSM_RELEASE, NULL);
if (pQueryScope->pScope)
{
LocalFree((HLOCAL)pQueryScope->pScope);
pQueryScope->pScope = NULL;
}
}
TraceLeaveValue(TRUE);
}
/*-----------------------------------------------------------------------------
/ CQueryFrame::InsertScopeIntoList
/ --------------------------------
/ Adds the given scope to the scope picker.
/
/ In:
/ pQueryScope -> zcope object to be added to the view
/ i = index to insert the scope at
/ fAddToControl = add the scope the picker control
/ ppQueryScope -> recieves the new query scope object / = NULL
/
/ Out:
/ HRESULT
/----------------------------------------------------------------------------*/
HRESULT CQueryFrame::InsertScopeIntoList(LPCQSCOPE pScope, INT i, BOOL fAddToControl)
{
HRESULT hres;
QUERYSCOPE qs;
INT iScope;
TraceEnter(TRACE_SCOPES, "CQueryFrame::InsertScopeIntoList");
Trace(TEXT("pScope %08x, i %d, fAddToControl %d"), pScope, i, fAddToControl);
if (!pScope)
ExitGracefully(hres, E_INVALIDARG, "pScope == NULL, not allowed");
// if we don't have any scopes then allocate the DSA
if (!_hdsaScopes)
{
_hdsaScopes = DSA_Create(SIZEOF(QUERYSCOPE), 4);
TraceAssert(_hdsaScopes);
if (!_hdsaScopes)
ExitGracefully(hres, E_OUTOFMEMORY, "Failed to allocate the scope DPA");
}
// Walk the list of scopes checking to see if this one is already in
// there, if not then we can add it.
for (iScope = 0 ; iScope < DSA_GetItemCount(_hdsaScopes) ; iScope++)
{
LPQUERYSCOPE pQueryScope = (LPQUERYSCOPE)DSA_GetItemPtr(_hdsaScopes, iScope);
TraceAssert(pQueryScope);
if (S_OK == _CallScopeProc(pQueryScope, CQSM_SCOPEEQUAL, pScope))
{
hres = ResultFromShort(iScope);
goto exit_gracefully;
}
}
// Take a copy of the scope blob passed by the caller. We copy the entire
// structure who's size is defined by cbStruct into a LocalAlloc block,
// once we have this we can then build the QUERYSCOPE structure that references
// it.
Trace(TEXT("pScope->cbStruct == %d"), pScope->cbStruct);
qs.pScope = (LPCQSCOPE)LocalAlloc(LPTR, pScope->cbStruct);
if (!qs.pScope)
ExitGracefully(hres, E_OUTOFMEMORY, "Failed to allocate query scope");
Trace(TEXT("Copying structure qs.pScope %08x, pScope %08x"), qs.pScope, pScope);
CopyMemory(qs.pScope, pScope, pScope->cbStruct);
//qs.pScope = NULL;
qs.iImage = -1; // no image
// We have a QUERYSCOPE, so initialize it, if that works then append it to the
// DSA before either setting the return value or appending it to the control.
_CallScopeProc(&qs, CQSM_INITIALIZE, NULL);
iScope = DSA_InsertItem(_hdsaScopes, i, &qs);
Trace(TEXT("iScope = %d"), iScope);
if (iScope == -1)
{
_FreeScope(&qs);
ExitGracefully(hres, E_OUTOFMEMORY, "Failed to add scope to DSA");
}
if (fAddToControl)
{
LPQUERYSCOPE pQueryScope = (LPQUERYSCOPE)DSA_GetItemPtr(_hdsaScopes, iScope);
TraceAssert(pQueryScope);
Trace(TEXT("Calling AddScopeToControl with %08x (%d)"), pQueryScope, iScope);
hres = AddScopeToControl(pQueryScope, iScope);
}
else
{
hres = ResultFromShort(iScope);
}
exit_gracefully:
TraceLeaveResult(hres);
}
/*-----------------------------------------------------------------------------
/ CQueryFrame::AddScopeToControl
/ ------------------------------
/ Adds the given scope to the scope picker.
/
/ In:
/ pQueryScope -> zcope object to be added to the view
/ i = index into view where to insert the scope
/
/ Out:
/ HRESULT (== index of item added)
/----------------------------------------------------------------------------*/
HRESULT CQueryFrame::AddScopeToControl(LPQUERYSCOPE pQueryScope, INT i)
{
HRESULT hres;
CQSCOPEDISPLAYINFO cqsdi;
COMBOBOXEXITEM cbi;
TCHAR szBuffer[MAX_PATH];
TCHAR szIconLocation[MAX_PATH] = { 0 };
INT item;
TraceEnter(TRACE_SCOPES, "CQueryFrame::AddScopeToControl");
if (!pQueryScope)
ExitGracefully(hres, E_INVALIDARG, "No scope specified");
// Call the scope to get the display information about this
// scope before we attempt to add it.
cqsdi.cbStruct = SIZEOF(cqsdi);
cqsdi.dwFlags = 0;
cqsdi.pDisplayName = szBuffer;
cqsdi.cchDisplayName = ARRAYSIZE(szBuffer);
cqsdi.pIconLocation = szIconLocation;
cqsdi.cchIconLocation = ARRAYSIZE(szIconLocation);
cqsdi.iIconResID = 0;
cqsdi.iIndent = 0;
hres = _CallScopeProc(pQueryScope, CQSM_GETDISPLAYINFO, &cqsdi);
FailGracefully(hres, "Failed to get display info for the scope");
// Now add the item to the control, if they gave as an image then
// add that to the image list (and tweak the INSERTITEM structure
// accordingly).
cbi.mask = CBEIF_TEXT|CBEIF_INDENT;
cbi.iItem = i;
cbi.pszText = cqsdi.pDisplayName;
cbi.iIndent = cqsdi.iIndent;
Trace(TEXT("Indent is %d"), cqsdi.iIndent);
if (szIconLocation[0] && cqsdi.iIconResID)
{
INT iImage;
if (!_fScopeImageListSet)
{
HIMAGELIST himlSmall;
Shell_GetImageLists(NULL, &himlSmall);
SendMessage(_hwndLookIn, CBEM_SETIMAGELIST, 0, (LPARAM)himlSmall);
_fScopeImageListSet = TRUE;
}
cbi.mask |= CBEIF_IMAGE|CBEIF_SELECTEDIMAGE;
cbi.iImage = Shell_GetCachedImageIndex(szIconLocation, cqsdi.iIconResID, 0x0);;
cbi.iSelectedImage = cbi.iImage;
Trace(TEXT("Image index set to: %d"), cbi.iImage);
}
item = (INT)SendMessage(_hwndLookIn, CBEM_INSERTITEM, 0, (LPARAM)&cbi);
if (item == -1)
ExitGracefully(hres, E_FAIL, "Failed when inserting the scope to the list");
DoEnableControls(); // reflect button changes into UI
hres = ResultFromShort(item);
exit_gracefully:
TraceLeaveResult(hres);
}
/*-----------------------------------------------------------------------------
/ CQueryFrame::PopulateScopeControl
/ ---------------------------------
/ Collect the scopes that we want to display in the scope control and
/ then populate it. If the handler doesn't return any scopes then
/ we remove the control and assume that know what to do when they
/ don't receive a scope pointer.
/
/ In:
/ -
/
/ Out:
/ HRESULT
/----------------------------------------------------------------------------*/
HRESULT CQueryFrame::PopulateScopeControl(VOID)
{
HRESULT hres;
LPQUERYSCOPE pQueryScope;
INT i;
TraceEnter(TRACE_SCOPES, "CQueryFrame::PopulateScopeControl");
// Collect the scopes that we should be showing in the view, if we don't
// get any back then we disable the scope control, if we do get some then
// populate the scope control with them.
hres = _pQueryHandler->AddScopes();
_fAddScopesNYI = (hres == E_NOTIMPL);
if (hres != E_NOTIMPL)
FailGracefully(hres, "Failed when calling handler to add scopes");
if (_hdsaScopes)
{
// We have some scopes, so now we create the image list that we can use
// for icons with scopes. Then walk through the DPA getting the scope
// to give us some display information about itself that we can
// add to the combo box.
ComboBox_SetExtendedUI(_hwndLookIn, TRUE);
for (i = 0 ; i < DSA_GetItemCount(_hdsaScopes); i++)
{
pQueryScope = (LPQUERYSCOPE)DSA_GetItemPtr(_hdsaScopes, i);
TraceAssert(pQueryScope);
AddScopeToControl(pQueryScope, i);
}
}
else
{
// we don't have any scopes after calling AddScopes, this is either
// because the ::AddScopes method is not implemented, or the
// scopes are being added async. If IssueQuery returned a success
// we assume they are coming in async and flag as such in our
// state.
if (!_fAddScopesNYI)
{
TraceMsg("Handler adding scopes async, so marking so");
_fScopesAddedAsync = TRUE;
}
}
hres = S_OK; // success
exit_gracefully:
Trace(TEXT("Default scope is index %d"), _iDefaultScope);
ComboBox_SetCurSel(_hwndLookIn, _iDefaultScope);
TraceLeaveResult(hres);
}
/*-----------------------------------------------------------------------------
/ CQueryFrame::GetSelectedScope
/ -----------------------------
/ Get the selected from the the scope ComboBox, this is a reference into the
/ scope DSA.
/
/ In:
/ ppQueryScope = receives a pointer to the new scope
/
/ Out:
/ HRESULT
/----------------------------------------------------------------------------*/
HRESULT CQueryFrame::GetSelectedScope(LPQUERYSCOPE* ppQueryScope)
{
HRESULT hres;
COMBOBOXEXITEM cbi;
INT iScope;
TraceEnter(TRACE_SCOPES, "CQueryFrame::GetSelectedScope");
*ppQueryScope = NULL;
if (_hdsaScopes)
{
// Get the index for the current scope, if it doesn't give a real
// index to a item in our view then barf! Otherwise look up the
// associated scope.
iScope = ComboBox_GetCurSel(_hwndLookIn);
Trace(TEXT("iScope %d"), iScope);
if (iScope == -1)
ExitGracefully(hres, E_FAIL, "User entered scopes not supported yet");
*ppQueryScope = (LPQUERYSCOPE)DSA_GetItemPtr(_hdsaScopes, iScope);
TraceAssert(*ppQueryScope);
}
hres = *ppQueryScope ? S_OK : E_FAIL;
exit_gracefully:
Trace(TEXT("Returning LPQUERYSCOPE %08x"), *ppQueryScope);
TraceLeaveResult(hres);
}
/*-----------------------------------------------------------------------------
/ Form handling functions
/----------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------
/ _FreeQueryForm
/ ---------------
/ Destroy the QUERYFORM allocation being used to describe the form in
/ our DPA. We ensure that we issue a CQPM_RELEASE before doing anything
/
/ In:
/ pQueryForm -> query form to be destroyed
/
/ Out:
/ INT == 1 always
/----------------------------------------------------------------------------*/
INT _FreeQueryFormCB(LPVOID pItem, LPVOID pData)
{
return _FreeQueryForm((LPQUERYFORM)pItem);
}
INT _FreeQueryForm(LPQUERYFORM pQueryForm)
{
TraceEnter(TRACE_FORMS, "_FreeQueryForm");
if (pQueryForm)
{
if (pQueryForm->hdsaPages)
{
DSA_DestroyCallback(pQueryForm->hdsaPages, _FreeQueryFormPageCB, NULL);
pQueryForm->hdsaPages = NULL;
}
Str_SetPtr(&pQueryForm->pTitle, NULL);
if (pQueryForm->hIcon)
{
DestroyIcon(pQueryForm->hIcon);
}
}
TraceLeaveValue(TRUE);
}
/*-----------------------------------------------------------------------------
/ _FreeQueryFormPage
/ ------------------
/ Given a pointer to a query form page structure release the members that
// are of interest, including calling the PAGEPROC to releasee the underlying
/ object.
/
/ In:
/ pQueryFormPage -> page to be removed
/
/ Out:
/ INT == 1 always
/----------------------------------------------------------------------------*/
INT _FreeQueryFormPageCB(LPVOID pItem, LPVOID pData)
{
return _FreeQueryFormPage((LPQUERYFORMPAGE)pItem);
}
INT _FreeQueryFormPage(LPQUERYFORMPAGE pQueryFormPage)
{
TraceEnter(TRACE_FORMS, "_FreeQueryFormPage");
if (pQueryFormPage)
{
_CallPageProc(pQueryFormPage, CQPM_RELEASE, 0, 0); // NB: ignore return code
if (pQueryFormPage->hwndPage)
{
EnableThemeDialogTexture(pQueryFormPage->hwndPage, ETDT_DISABLE);
DestroyWindow(pQueryFormPage->hwndPage);
pQueryFormPage->hwndPage = NULL;
}
if (pQueryFormPage->pPage)
{
LocalFree(pQueryFormPage->pPage);
pQueryFormPage->pPage = NULL;
}
}
TraceLeaveValue(TRUE);
}
/*-----------------------------------------------------------------------------
/ _CallPageProc
/ -------------
/ Call the given page object thunking the arguments as required if the
/ page object is non-UNICODE (only if building UNICODE).
/
/ In:
/ pQueryFormPage -> page object to be called
/ uMsg, wParam, lParam = parameters for message
/
/ Out:
/ HRESULT
/----------------------------------------------------------------------------*/
HRESULT _CallPageProc(LPQUERYFORMPAGE pQueryFormPage, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
HRESULT hres;
TraceEnter(TRACE_FORMS, "_CallPageProc");
Trace(TEXT("pQueryFormPage %08x, pPage %08x, uMsg %d, wParam %08x, lParam %08x"),
pQueryFormPage, pQueryFormPage->pPage, uMsg, wParam, lParam);
if (!pQueryFormPage)
ExitGracefully(hres, S_OK, "pQueryFormPage == NULL");
hres = (pQueryFormPage->pPage->pPageProc)(pQueryFormPage->pPage, pQueryFormPage->hwndPage, uMsg, wParam, lParam);
FailGracefully(hres, "Failed calling PageProc");
// hres = S_OK;
exit_gracefully:
TraceLeaveResult(hres);
}
/*-----------------------------------------------------------------------------
/ Functions for adding query forms/pages
/----------------------------------------------------------------------------*/
// CB to add forms to the form DSA.
HRESULT _AddFormsProc(LPARAM lParam, LPCQFORM pForm)
{
HRESULT hres;
QUERYFORM qf = {0};
HDSA hdsaForms = (HDSA)lParam;
TraceEnter(TRACE_FORMS, "_AddFormsProc");
if (!pForm || !hdsaForms)
ExitGracefully(hres, E_INVALIDARG, "Failed to add page pForm == NULL");
// Allocate and thunk as required
qf.hdsaPages = NULL; // DSA of pages
qf.dwFlags = pForm->dwFlags; // flags
qf.clsidForm = pForm->clsid; // CLSID identifier for this form
qf.pTitle = NULL; // title used for drop down / title bar
qf.hIcon = pForm->hIcon; // hIcon passed by caller
qf.iImage = -1; // image list index of icon
qf.iForm = 0; // visible index of form in control
qf.iPage = 0; // currently selected page on form
if (!Str_SetPtr(&qf.pTitle, pForm->pszTitle))
ExitGracefully(hres, E_OUTOFMEMORY, "Failed to copy form title string");
// Allocate the DSA if one doesn't exist yet, then add in the form
// structure as required.
if (-1 == DSA_AppendItem(hdsaForms, &qf))
ExitGracefully(hres, E_FAIL, "Failed to add form to the form DSA");
hres = S_OK; // success
exit_gracefully:
if (FAILED(hres))
_FreeQueryForm(&qf);
TraceLeaveResult(hres);
}
// CB to add pages to the page DSA.
HRESULT _AddPagesProc(LPARAM lParam, REFCLSID clsidForm, LPCQPAGE pPage)
{
HRESULT hres;
QUERYFORMPAGE qfp = {0};
HDSA hdsaPages = (HDSA)lParam;
TraceEnter(TRACE_FORMS, "_AddPagesProc");
if (!pPage || !hdsaPages)
ExitGracefully(hres, E_INVALIDARG, "Failed to add page pPage == NULL");
// copy the pPage structure for us to pass to the PAGEPROC later, nb: we
// use the cbStruct field to indicate the size of blob we must copy.
Trace(TEXT("pPage->cbStruct == %d"), pPage->cbStruct);
qfp.pPage = (LPCQPAGE)LocalAlloc(LPTR, pPage->cbStruct);
if (!qfp.pPage)
ExitGracefully(hres, E_OUTOFMEMORY, "Failed to allocate copy of page structure");
Trace(TEXT("Copying structure qfp.pPage %08x, pPage %08x"), qfp.pPage, pPage);
CopyMemory(qfp.pPage, pPage, pPage->cbStruct); // copy the page structure
//qfp.pPage = NULL;
qfp.clsidForm = clsidForm;
qfp.pPageProc = pPage->pPageProc;
qfp.lParam = pPage->lParam;
qfp.hwndPage = NULL;
_CallPageProc(&qfp, CQPM_INITIALIZE, 0, 0);
if (-1 == DSA_AppendItem(hdsaPages, &qfp))
ExitGracefully(hres, E_FAIL, "Failed to add the form to the DSA");
hres = S_OK; // succcess
exit_gracefully:
if (FAILED(hres))
_FreeQueryFormPage(&qfp);
TraceLeaveResult(hres);
}
// Add forms/pages from a UNICODE IQueryForm iface
HRESULT CQueryFrame::AddFromIQueryForm(IQueryForm* pQueryForm, HKEY hKeyForm)
{
HRESULT hres;
TraceEnter(TRACE_FORMS, "CQueryFrame::AddFromIQueryForm");
if (!pQueryForm)
ExitGracefully(hres, E_FAIL, "pQueryForm == NULL, failing");
hres = pQueryForm->Initialize(hKeyForm);
FailGracefully(hres, "Failed in IQueryFormW::Initialize");
// Call the form object to add its form and then its pages
hres = pQueryForm->AddForms(_AddFormsProc, (LPARAM)_hdsaForms);
if (SUCCEEDED(hres) || (hres == E_NOTIMPL))
{
hres = pQueryForm->AddPages(_AddPagesProc, (LPARAM)_hdsaPages);
FailGracefully(hres, "Failed in IQueryForm::AddPages");
}
else
{
FailGracefully(hres, "Failed when calling IQueryForm::AddForms");
}
hres = S_OK; // success
exit_gracefully:
TraceLeaveResult(hres);
}
#ifdef UNICODE
#define ADD_FROM_IQUERYFORM AddFromIQueryFormW
#else
#define ADD_FROM_IQUERYFORM AddFromIQueryFormA
#endif
/*-----------------------------------------------------------------------------
/ CQueryFrame::GatherForms
/ ------------------------
/ Enumerate all the query forms for the given query handler and build
/ the DPA containing the list of them. Once we have done this we
/ can then populate the control at some more convientent moment.
/
/ When gathering we first hit the "handler", then the "Forms" sub-key
/ trying to load all the InProc servers that provide forms. We build
/ list of hidden, never shown etc.
/
/ In:
/ -
/ Out:
/ HRESULT
/----------------------------------------------------------------------------*/
HRESULT _AddPageToForm(LPQUERYFORM pQueryForm, LPQUERYFORMPAGE pQueryFormPage, BOOL fClone)
{
HRESULT hres;
QUERYFORMPAGE qfp;
LPCQPAGE pPage;
TraceEnter(TRACE_FORMS, "_AddPageToForm");
TraceAssert(pQueryForm);
TraceAssert(pQueryFormPage);
// ensure that we have a page DSA for this form object
if (!pQueryForm->hdsaPages)
{
TraceMsg("Creating a new page DSA for form");
pQueryForm->hdsaPages = DSA_Create(SIZEOF(QUERYFORMPAGE), 4);
if (!pQueryForm->hdsaPages)
ExitGracefully(hres, E_OUTOFMEMORY, "*** No page DSA on form object ***");
}
if (!fClone)
{
// Moving this page structure to the one associated with the query form,
// therefore just ensure that the form has a DSA for pages and just
// insert an item at the header (yes, we add the pages in reverse).
Trace(TEXT("Adding page %08x to form %s"), pQueryFormPage, pQueryForm->pTitle);
if (-1 == DSA_InsertItem(pQueryForm->hdsaPages, 0, pQueryFormPage))
ExitGracefully(hres, E_FAIL, "Failed to copy page to form page DSA");
}
else
{
LPCQPAGE pPage = pQueryFormPage->pPage;
// Copying the page structure (it must be global), therefore clone
// the QUERYFORMPAGE strucutre and the CQPAGE into a new allocation
// and insert that into the page DSA.
Trace(TEXT("Cloning page %08x to form %s"), pQueryFormPage, pQueryForm->pTitle);
CopyMemory(&qfp, pQueryFormPage, SIZEOF(QUERYFORMPAGE));
qfp.pPage = (LPCQPAGE)LocalAlloc(LPTR, pPage->cbStruct);
if (!qfp.pPage)
ExitGracefully(hres, E_OUTOFMEMORY, "Failed to allocate copy of page structure");
Trace(TEXT("Copying structure qfp.pPage %08x, pPage %08x"), qfp.pPage, pPage);
CopyMemory(qfp.pPage, pPage, pPage->cbStruct); // copy the page structure
_CallPageProc(&qfp, CQPM_INITIALIZE, 0, 0);
if (-1 == DSA_AppendItem(pQueryForm->hdsaPages, &qfp))
{
_FreeQueryFormPage(&qfp);
ExitGracefully(hres, E_FAIL, "Failed to copy page to form DSA");
}
}
hres = S_OK; // success
exit_gracefully:
TraceLeaveResult(hres);
}
HRESULT CQueryFrame::GatherForms(VOID)
{
HRESULT hres;
IQueryForm* pQueryForm = NULL;
HKEY hKeyForms = NULL;
TCHAR szBuffer[MAX_PATH];
INT i, iPage, iForm;
RECT rect;
TC_ITEM tci;
TraceEnter(TRACE_FORMS, "CQueryFrame::GatherForms");
// Construct DSA's so we can store the forms and pages as required.
_hdsaForms = DSA_Create(SIZEOF(QUERYFORM), 4);
_hdsaPages = DSA_Create(SIZEOF(QUERYFORMPAGE), 4);
if (!_hdsaForms || !_hdsaPages)
ExitGracefully(hres, E_OUTOFMEMORY, "Failed to create DSA's for storing pages/forms");
// First check the IQueryHandler to see if it supports IQueryForm, if it does
// then call it to add its objects. Note that we don't bother with ANSI/UNICODE
// at this point as the handler is assumed to be built the same the
// the query framework.
if (SUCCEEDED(_pQueryHandler->QueryInterface(IID_IQueryForm, (LPVOID*)&pQueryForm)))
{
hres = AddFromIQueryForm(pQueryForm, NULL);
FailGracefully(hres, "Failed when calling AddFromIQueryForm on handlers IQueryForm iface)");
}
// now attempt to build the list of forms and pages from the registered form
// extensions. These are declared under the handlers CLSID in the registry,
// under the sub-key "Forms".
if (ERROR_SUCCESS != RegOpenKeyEx(_hkHandler, c_szForms, NULL, KEY_READ, &hKeyForms))
{
TraceMsg("No 'Forms' sub-key found, therefore skipping");
}
else
{
// Enumerate all the keys in the "Forms" key, these are assumed to be a list of
// the form handlers.
for (i = 0 ; TRUE ; i++)
{
DWORD cchStruct = ARRAYSIZE(szBuffer);
if (ERROR_SUCCESS != RegEnumKeyEx(hKeyForms, i, szBuffer, &cchStruct, NULL, NULL, NULL, NULL))
{
TraceMsg("RegEnumKeyEx return's false, therefore stopping eunmeration");
break;
}
GetForms(hKeyForms, szBuffer);
}
}
// Now tally the form/page information together and remove duplicates and attach the pages
// to forms, take special note of the global pages. As all forms will now be in the
// DSA we can check for a zero count and we don't have to worry about the order
// in which the the forms and pages were added.
if (!DSA_GetItemCount(_hdsaForms) || !DSA_GetItemCount(_hdsaPages))
ExitGracefully(hres, E_FAIL, "Either the forms or pages DSA is empty");
for (iPage = DSA_GetItemCount(_hdsaPages) ; --iPage >= 0 ;)
{
LPQUERYFORMPAGE pQueryFormPage = (LPQUERYFORMPAGE)DSA_GetItemPtr(_hdsaPages, iPage);
TraceAssert(pQueryFormPage);
Trace(TEXT("iPage %d (of %d)"), iPage, DSA_GetItemCount(_hdsaPages));
if (!(pQueryFormPage->pPage->dwFlags & CQPF_ISGLOBAL))
{
LPQUERYFORM pQueryForm = FindQueryForm(pQueryFormPage->clsidForm);
TraceAssert(pQueryForm);
TraceGUID("Adding page to form:", pQueryFormPage->clsidForm);
if (pQueryForm)
{
hres = _AddPageToForm(pQueryForm, pQueryFormPage, FALSE);
FailGracefully(hres, "Failed when adding page to form");
if (!DSA_DeleteItem(_hdsaPages, iPage))
TraceMsg("**** Failed to remove page from global DSA ****");
}
}
}
for (iPage = DSA_GetItemCount(_hdsaPages) ; --iPage >= 0 ;)
{
LPQUERYFORMPAGE pQueryFormPage = (LPQUERYFORMPAGE)DSA_GetItemPtr(_hdsaPages, iPage);
TraceAssert(pQueryFormPage);
if ((pQueryFormPage->pPage->dwFlags & CQPF_ISGLOBAL))
{
Trace(TEXT("Adding global page to %d forms"), DSA_GetItemCount(_hdsaForms));
for (iForm = 0 ; iForm < DSA_GetItemCount(_hdsaForms); iForm++)
{
LPQUERYFORM pQueryForm = (LPQUERYFORM)DSA_GetItemPtr(_hdsaForms, iForm);
TraceAssert(pQueryForm);
if (!(pQueryForm->dwFlags & CQFF_NOGLOBALPAGES))
{
hres = _AddPageToForm(pQueryForm, pQueryFormPage, TRUE);
FailGracefully(hres, "Failed when adding global page to form");
}
}
_FreeQueryFormPage(pQueryFormPage);
if (!DSA_DeleteItem(_hdsaPages, iPage))
TraceMsg("**** Failed to remove page from global DSA ****");
}
}
// Walk the list of forms, rmeoving the ones which have no pages assocaited with
// them, we don't need these around confusing the world around us. Note that
// we walk backwards through the list removing.
//
// Also remove the optional forms we don't want to ehw orld to see
for (iForm = DSA_GetItemCount(_hdsaForms) ; --iForm >= 0 ;)
{
LPQUERYFORM pQueryForm = (LPQUERYFORM)DSA_GetItemPtr(_hdsaForms, iForm);
TraceAssert(pQueryForm);
Trace(TEXT("pQueryForm %08x (%s), pQueryForm->hdsaPages %08x (%d)"),
pQueryForm,
pQueryForm->pTitle,
pQueryForm->hdsaPages,
pQueryForm->hdsaPages ? DSA_GetItemCount(pQueryForm->hdsaPages):0);
if (!pQueryForm->hdsaPages
|| !DSA_GetItemCount(pQueryForm->hdsaPages)
|| ((pQueryForm->dwFlags & CQFF_ISOPTIONAL) && !(_pOpenQueryWnd->dwFlags & OQWF_SHOWOPTIONAL)))
{
TraceGUID("Removing form: ", pQueryForm->clsidForm);
_FreeQueryForm(pQueryForm);
DSA_DeleteItem(_hdsaForms, iForm);
}
}
if (!DSA_GetItemCount(_hdsaForms))
ExitGracefully(hres, E_FAIL, "!!!!! No forms registered after page/form fix ups !!!!!");
// The pages have been attached to the forms so we can now attempt to create the
// form/page objects.
_szForm.cx = 0;
_szForm.cy = 0;
tci.mask = TCIF_TEXT;
tci.pszText = TEXT("");
tci.cchTextMax = 0;
TabCtrl_InsertItem(_hwndFrame, 0, &tci); // tabctrl needs at least one item so we can compute sizes
for (iForm = 0 ; iForm < DSA_GetItemCount(_hdsaForms); iForm++)
{
LPQUERYFORM pQueryForm = (LPQUERYFORM)DSA_GetItemPtr(_hdsaForms, iForm);
TraceAssert(pQueryForm);
// Create each of the modeless page dialoges that we show to allow the user
// to edit the search criteria. We also grab the size and modify the
// form informaiton we have so that the default size of the dialog can be
// correctly computed.
for (iPage = 0 ; iPage < DSA_GetItemCount(pQueryForm->hdsaPages); iPage++)
{
LPQUERYFORMPAGE pQueryFormPage = (LPQUERYFORMPAGE)DSA_GetItemPtr(pQueryForm->hdsaPages, iPage);
TraceAssert(pQueryFormPage);
pQueryFormPage->hwndPage = CreateDialogParam(pQueryFormPage->pPage->hInstance,
MAKEINTRESOURCE(pQueryFormPage->pPage->idPageTemplate),
_hwnd,
pQueryFormPage->pPage->pDlgProc,
(LPARAM)pQueryFormPage->pPage);
if (!pQueryFormPage->hwndPage)
ExitGracefully(hres, E_FAIL, "Failed to create query form page");
EnableThemeDialogTexture(pQueryFormPage->hwndPage, ETDT_ENABLETAB);
GetRealWindowInfo(pQueryFormPage->hwndPage, &rect, NULL);
TabCtrl_AdjustRect(_hwndFrame, TRUE, &rect);
_szForm.cx = max(rect.right-rect.left, _szForm.cx);
_szForm.cy = max(rect.bottom-rect.top, _szForm.cy);
// flush the form parameters
_CallPageProc(pQueryFormPage, CQPM_CLEARFORM, 0, 0);
// Call the page with CQPM_SETDEFAULTPARAMETERS with the
// OPENQUERYWINDOW structure. wParam is TRUE/FALSE indiciating if
// the form is the default one, and therefore if the pFormParam is
// valid.
_CallPageProc(pQueryFormPage, CQPM_SETDEFAULTPARAMETERS,
(WPARAM)((_pOpenQueryWnd->dwFlags & OQWF_DEFAULTFORM) &&
IsEqualCLSID(_pOpenQueryWnd->clsidDefaultForm, pQueryFormPage->clsidForm)),
(LPARAM)_pOpenQueryWnd);
}
// If the form has an hIcon then lets ensure that we add that to the form image
// list, any failure here is non-fatal, in that we will just skip that forms
// icon in the list (rather than barfing)
if (pQueryForm->hIcon)
{
if (!_himlForms)
_himlForms = ImageList_Create(COMBOEX_IMAGE_CX, COMBOEX_IMAGE_CY, 0, 4, 1);
if (_himlForms)
{
pQueryForm->iImage = ImageList_AddIcon(_himlForms, pQueryForm->hIcon);
TraceAssert(pQueryForm->iImage >= 0);
}
DestroyIcon(pQueryForm->hIcon);
pQueryForm->hIcon = NULL;
}
}
hres = S_OK; // success
exit_gracefully:
DoRelease(pQueryForm);
if (hKeyForms)
RegCloseKey(hKeyForms);
TraceLeaveResult(hres);
}
/*-----------------------------------------------------------------------------
/ CQueryFrame::GetForms
/ ---------------------
/ Given a HKEY to the forms list and the value name for the form we want
/ to add, query for the form information add add the form objects
/ to the master list.
/
/ In:
/ hKeyForms = HKEY for the {CLSID provider}\Forms key
/ pName -> key value to query for
/
/ Out:
/ VOID
/----------------------------------------------------------------------------*/
HRESULT CQueryFrame::GetForms(HKEY hKeyForms, LPTSTR pName)
{
HRESULT hres;
HKEY hKeyForm = NULL;
TCHAR szQueryFormCLSID[GUIDSTR_MAX+1];
DWORD dwFlags;
DWORD dwSize;
IUnknown* pUnknown = NULL;
IQueryForm* pQueryForm = NULL;
CLSID clsidForm;
BOOL fIncludeForms = FALSE;
TraceEnter(TRACE_FORMS, "CQueryFrame::_GetForms");
Trace(TEXT("pName %s"), pName);
if (ERROR_SUCCESS != RegOpenKeyEx(hKeyForms, pName, NULL, KEY_READ, &hKeyForm))
ExitGracefully(hres, E_UNEXPECTED, "Failed to open the form key");
// Read the flags and try to determine if we should invoke this form object.
dwSize = SIZEOF(dwFlags);
if (ERROR_SUCCESS != RegQueryValueEx(hKeyForm, c_szFlags, NULL, NULL, (LPBYTE)&dwFlags, &dwSize))
{
TraceMsg("No flags, defaulting to something sensible");
dwFlags = QUERYFORM_CHANGESFORMLIST;
}
Trace(TEXT("Forms flag is %08x"), dwFlags);
// should be invoke this form object?
//
// - if dwFlags has QUERYFORM_CHANGESFORMSLIST, or
// - if dwFlags has QUERYFORM_CHANGESOPTFORMLIST and we are showing optional forms, or
// - neither set and the form object supports the requested form
if (!(dwFlags & QUERYFORM_CHANGESFORMLIST))
{
if ((dwFlags & QUERYFORM_CHANGESOPTFORMLIST) &&
(_pOpenQueryWnd->dwFlags & OQWF_SHOWOPTIONAL))
{
TraceMsg("Form is optional, are we are showing optional forms");
fIncludeForms = TRUE;
}
else
{
// OK, so it either didn't update the form list, or wasn't marked as optional,
// so lets check to see if it supports the form the user has requested, if not
// then don't bother loading this guy.
if (_pOpenQueryWnd->dwFlags & OQWF_DEFAULTFORM)
{
TCHAR szBuffer[GUIDSTR_MAX+32];
HKEY hkFormsSupported;
TraceMsg("Checking for supported form");
if (ERROR_SUCCESS == RegOpenKeyEx(hKeyForm, TEXT("Forms Supported"), NULL, KEY_READ, &hkFormsSupported))
{
TraceMsg("Form has a 'Supported Forms' sub-key");
GetStringFromGUID(_pOpenQueryWnd->clsidDefaultForm, szQueryFormCLSID, ARRAYSIZE(szQueryFormCLSID));
Trace(TEXT("Checking for: %s"), szQueryFormCLSID);
if (ERROR_SUCCESS == RegQueryValueEx(hkFormsSupported, szQueryFormCLSID, NULL, NULL, NULL, NULL))
{
TraceMsg("Query form is in supported list");
fIncludeForms = TRUE;
}
RegCloseKey(hkFormsSupported);
}
else
{
TraceMsg("No forms supported sub-key, so loading form object anyway");
fIncludeForms = TRUE;
}
}
}
}
else
{
TraceMsg("Form updates form list");
fIncludeForms = TRUE;
}
// if fIncludeForms is TRUE, then the checks above succeeded and we are including forms
// from this object (identified by pName), so we must now get the CLSID of the object
// we are invoking and use its IQueryForm interface to add the forms that we want.
if (fIncludeForms)
{
// get the form object CLSID, having parse it, then CoCreate it adding the forms.
dwSize = SIZEOF(szQueryFormCLSID);
if (ERROR_SUCCESS != RegQueryValueEx(hKeyForm, c_szCLSID, NULL, NULL, (LPBYTE)szQueryFormCLSID, &dwSize))
ExitGracefully(hres, E_UNEXPECTED, "Failed to read the CLSID of the form");
Trace(TEXT("szQueryFormCLSID: %s"), szQueryFormCLSID);
if (!GetGUIDFromString(szQueryFormCLSID, &clsidForm))
ExitGracefully(hres, E_UNEXPECTED, "Fialed to parse the string as a GUID");
// we now have the CLISD of the form object, so we must attempt to CoCreate it, we try for
// the current build type (eg UNICODE) and then fall back to ANSI if thats not supported,
// so we can support ANSI query form objects on a UNICODE platform.
hres = CoCreateInstance(clsidForm, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (void**)&pUnknown);
FailGracefully(hres, "Failed to CoCreate the form object");
if (SUCCEEDED(pUnknown->QueryInterface(IID_IQueryForm, (LPVOID*)&pQueryForm)))
{
hres = AddFromIQueryForm(pQueryForm, hKeyForm);
FailGracefully(hres, "Failed when adding forms from specified IQueryForm iface");
}
else
{
ExitGracefully(hres, E_UNEXPECTED, "Form object doesn't support IQueryForm(A/W)");
}
}
hres = S_OK;
exit_gracefully:
if (hKeyForm)
RegCloseKey(hKeyForm);
DoRelease(pUnknown);
DoRelease(pQueryForm);
TraceLeaveResult(hres);
}
/*-----------------------------------------------------------------------------
/ CQueryFrame::PopulateFormControl
/ ---------------------------------
/ Enumerate all the query forms for the given query handler and build
/ the DPA containing the list of them. Once we have done this we
/ can then populate the control at some more convientent moment.
/
/ When gathering we first hit the "handler", then the "Forms" sub-key
/ trying to load all the InProc servers that provide forms. We build
/ list of hidden, never shown etc.
/
/ In:
/ fIncludeHidden = list forms marked as hidden in control
/
/ Out:
/ VOID
/----------------------------------------------------------------------------*/
HRESULT CQueryFrame::PopulateFormControl(BOOL fIncludeHidden)
{
HRESULT hres;
COMBOBOXEXITEM cbi;
LPQUERYFORM pQueryForm;
INT i, iForm;
TraceEnter(TRACE_FORMS, "CQueryFrame::PopulateFormControl");
Trace(TEXT("fIncludeHidden: %d"), fIncludeHidden);
// list which forms within the control
if (!_hdsaForms)
ExitGracefully(hres, E_FAIL, "No forms to list");
ComboBox_ResetContent(_hwndLookFor); // remove all items from that control
for (i = 0, iForm = 0 ; iForm < DSA_GetItemCount(_hdsaForms); iForm++)
{
LPQUERYFORM pQueryForm = (LPQUERYFORM)DSA_GetItemPtr(_hdsaForms, iForm);
TraceAssert(pQueryForm);
// filter out those forms that are not of interest to this instance of the
// dialog.
if (((pQueryForm->dwFlags & CQFF_ISOPTIONAL) && !fIncludeHidden) ||
(pQueryForm->dwFlags & CQFF_ISNEVERLISTED))
{
Trace(TEXT("Hiding form: %s"), pQueryForm->pTitle);
continue;
}
// now add the form to the control, including the image if there is an image
// specified.
cbi.mask = CBEIF_TEXT|CBEIF_LPARAM;
cbi.iItem = i++;
cbi.pszText = pQueryForm->pTitle;
cbi.cchTextMax = lstrlen(pQueryForm->pTitle);
cbi.lParam = iForm;
if (pQueryForm->iImage >= 0)
{
Trace(TEXT("Form has an image %d"), pQueryForm->iImage);
cbi.mask |= CBEIF_IMAGE|CBEIF_SELECTEDIMAGE;
cbi.iImage = pQueryForm->iImage;
cbi.iSelectedImage = pQueryForm->iImage;
}
pQueryForm->iForm = (int)SendMessage(_hwndLookFor, CBEM_INSERTITEM, 0, (LPARAM)&cbi);
if (pQueryForm->iForm < 0)
{
Trace(TEXT("Form name: %s"), pQueryForm->pTitle);
ExitGracefully(hres, E_FAIL, "Failed to add the entry to the combo box");
}
}
hres = S_OK;
exit_gracefully:
TraceLeaveValue(hres);
}
/*-----------------------------------------------------------------------------
/ CQueryFrame::SelectForm
/ -----------------------
/ Changes the current form to the one specified as an into the DPA.
/
/ In:
/ iForm = form to be selected
/
/ Out:
/ -
/----------------------------------------------------------------------------*/
HRESULT CQueryFrame::SelectForm(REFCLSID clsidForm)
{
HRESULT hres;
LPQUERYFORM pQueryForm, pOldQueryForm;
LPQUERYFORMPAGE pQueryFormPage;
LPCQPAGE pPage;
INT nCmdShow = SW_SHOW;
TCHAR szBuffer[64], szTitle[MAX_PATH];;
TC_ITEM tci;
INT i;
TraceEnter(TRACE_FORMS, "CQueryFrame::SelectForm");
pQueryForm = FindQueryForm(clsidForm);
TraceAssert(pQueryForm);
if (!pQueryForm)
ExitGracefully(hres, S_FALSE, "Failed to find the requested form");
// Change the currently displayed form and change the displayed
// tabs to correctly indicate this
if ((pQueryForm != _pCurrentForm))
{
if (!OnNewQuery(FALSE)) // prompt the user
ExitGracefully(hres, S_FALSE, "Failed to select the new form");
TabCtrl_DeleteAllItems(_hwndFrame);
for (i = 0 ; i < DSA_GetItemCount(pQueryForm->hdsaPages) ; i++)
{
pQueryFormPage = (LPQUERYFORMPAGE)DSA_GetItemPtr(pQueryForm->hdsaPages, i);
pPage = pQueryFormPage->pPage;
tci.mask = TCIF_TEXT;
tci.pszText = pQueryForm->pTitle;
tci.cchTextMax = MAX_PATH;
if (pPage->idPageName &&
LoadString(pPage->hInstance, pPage->idPageName, szBuffer, ARRAYSIZE(szBuffer)))
{
Trace(TEXT("Loaded page title string %s"), szBuffer);
tci.pszText = szBuffer;
}
TabCtrl_InsertItem(_hwndFrame, i, &tci);
}
ComboBox_SetCurSel(_hwndLookFor, pQueryForm->iForm);
_pCurrentForm = pQueryForm;
SelectFormPage(pQueryForm, pQueryForm->iPage);
// Change the dialog title to reflect the new form
if (LoadString(GLOBAL_HINSTANCE, IDS_FRAMETITLE, szBuffer, ARRAYSIZE(szBuffer)))
{
wsprintf(szTitle, szBuffer, pQueryForm->pTitle);
SetWindowText(_hwnd, szTitle);
}
// Tell the handler that we have changed the form, they can then use this
// new form name to modify their UI.
_pQueryHandler->ActivateView(CQRVA_FORMCHANGED, (WPARAM)lstrlen(pQueryForm->pTitle), (LPARAM)pQueryForm->pTitle);
}
hres = S_OK;
exit_gracefully:
TraceLeaveResult(hres);
}
/*-----------------------------------------------------------------------------
/ CQueryFrame::SelectFormPage
/ ---------------------------
/ Change the currently active page of a query form to the one specified
/ by the index.
/
/ In:
/ pQueryForm = query form to be changed
/ iForm = form to be selected
/
/ Out:
/ -
/----------------------------------------------------------------------------*/
VOID CQueryFrame::SelectFormPage(LPQUERYFORM pQueryForm, INT iPage)
{
LPQUERYFORMPAGE pQueryFormPage;
RECT rect;
TraceEnter(TRACE_FORMS, "CQueryFrame::SelectFormPage");
pQueryFormPage = (LPQUERYFORMPAGE)DSA_GetItemPtr(pQueryForm->hdsaPages, iPage);
// Have we changed the query form page? If so then display the now dialog
// hiding the previous one. We call the TabCtrl to find out where we should
// be placing this new control.
if (pQueryFormPage != _pCurrentFormPage)
{
// Reflect the change into the tab control
TabCtrl_SetCurSel(_hwndFrame, iPage);
pQueryForm->iPage = iPage;
// Fix the size and visability of the new form
if (_pCurrentFormPage)
ShowWindow(_pCurrentFormPage->hwndPage, SW_HIDE);
GetRealWindowInfo(_hwndFrame, &rect, NULL);
TabCtrl_AdjustRect(_hwndFrame, FALSE, &rect);
SetWindowPos(pQueryFormPage->hwndPage,
HWND_TOP,
rect.left, rect.top,
rect.right - rect.left,
rect.bottom - rect.top,
SWP_SHOWWINDOW);
_pCurrentFormPage = pQueryFormPage;
}
TraceLeave();
}
/*-----------------------------------------------------------------------------
/ CQueryFrame::CallFormPages
/ --------------------------
/ Given a query form traverse the array of pages calling each of them
/ with the given message information. If any of the pages return
/ an error code (other than E_NOTIMPL) we bail.
/
/ In:
/ pQueryForm = query form to call
/ uMsg, wParam, lParam = parameters for the page
/
/ Out:
/ HRESULT
/----------------------------------------------------------------------------*/
HRESULT CQueryFrame::CallFormPages(LPQUERYFORM pQueryForm, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
HRESULT hres = S_OK;
INT iPage;
TraceEnter(TRACE_FORMS, "CQueryFrame::CallFormPages");
if (!pQueryForm || !pQueryForm->hdsaPages)
ExitGracefully(hres, E_FAIL, "No pQueryForm || pQueryForm->hdsaPages == NULL");
Trace(TEXT("pQueryForm %08x"), pQueryForm);
Trace(TEXT("uMsg %08x, wParam %08x, lParam %08x"), uMsg, wParam, lParam);
Trace(TEXT("%d pages to call"), DSA_GetItemCount(pQueryForm->hdsaPages));
// Call each page in turn if it matches the filter we have been given for calling
// down. If a page returns S_FALSE or a FAILURE then we exit the loop. If the
// failure however is E_NOTIMPL then we ignore.
for (iPage = 0 ; iPage < DSA_GetItemCount(pQueryForm->hdsaPages); iPage++)
{
LPQUERYFORMPAGE pQueryFormPage = (LPQUERYFORMPAGE)DSA_GetItemPtr(pQueryForm->hdsaPages, iPage);
TraceAssert(pQueryFormPage);
hres = _CallPageProc(pQueryFormPage, uMsg, wParam, lParam);
if (FAILED(hres) && (hres != E_NOTIMPL))
{
TraceMsg("PageProc returned a FAILURE");
break;
}
else if (hres == S_FALSE)
{
TraceMsg("PageProc returned S_FALSE, exiting loop");
break;
}
}
exit_gracefully:
TraceLeaveResult(hres);
}
/*-----------------------------------------------------------------------------
/ CQueryFrame::FindQueryForm
/ --------------------------
/ Given the CLSID for the form return a pointer to its LPQUERYFORM structure,
/ or NULL if not found.
/
/ In:
/ clsidForm = ID of the form
/
/ Out:
/ LPQUERYFORM
/----------------------------------------------------------------------------*/
LPQUERYFORM CQueryFrame::FindQueryForm(REFCLSID clsidForm)
{
LPQUERYFORM pQueryForm = NULL;
INT i;
TraceEnter(TRACE_FORMS, "CQueryFrame::FindQueryForm");
TraceGUID("Form ID", clsidForm);
for (i = 0 ; _hdsaForms && (i < DSA_GetItemCount(_hdsaForms)) ; i++)
{
pQueryForm = (LPQUERYFORM)DSA_GetItemPtr(_hdsaForms, i);
TraceAssert(pQueryForm);
if (IsEqualCLSID(clsidForm, pQueryForm->clsidForm))
{
Trace(TEXT("Form is index %d (%08x)"), i, pQueryForm);
break;
}
}
if (!_hdsaForms || (i >= DSA_GetItemCount(_hdsaForms)))
pQueryForm = NULL;
TraceLeaveValue(pQueryForm);
}