query.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 173k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. #include "pch.h"
  2. #include "stddef.h"
  3. #pragma hdrstop
  4. /*-----------------------------------------------------------------------------
  5. / Result view
  6. /----------------------------------------------------------------------------*/
  7. //
  8. // CDsQuery which implements IQueryHandler, IQueryForm etc
  9. //
  10. class CDsQuery; // forward reference
  11. typedef HRESULT (*LPCOLLECTPROC)(CDsQuery* pdq, LPARAM lParam, INT item, LPQUERYRESULT pResult);
  12. class CDsQuery : public IQueryHandler, IQueryForm, IObjectWithSite, IDsQueryHandler, CUnknown
  13. {
  14.     friend HRESULT _ScopeProc(LPCQSCOPE pScope, UINT uMsg, LPVOID pVoid);
  15.     friend HRESULT _AddScope(INT iIndent, LPWSTR pPath, LPWSTR pObjectClass, BOOL fSelect);
  16.     friend LRESULT CALLBACK _ResultViewWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  17.     friend int CALLBACK _BrowseForScopeCB(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData);
  18.     friend HRESULT _GetIDLCollectCB(CDsQuery* pdq, LPARAM lParam, INT item, LPQUERYRESULT pResult);
  19.     public:
  20.         CDsQuery();
  21.         ~CDsQuery();
  22.         // IUnknown
  23.         STDMETHOD(QueryInterface)(REFIID riid, void **ppvObject);                             
  24.         STDMETHOD_(ULONG, AddRef)();
  25.         STDMETHOD_(ULONG, Release)();
  26.         // IQueryForms
  27.         STDMETHOD(Initialize)(THIS_ HKEY hkForm);
  28.         STDMETHOD(AddForms)(THIS_ LPCQADDFORMSPROC pAddFormsProc, LPARAM lParam);
  29.         STDMETHOD(AddPages)(THIS_ LPCQADDPAGESPROC pAddPagesProc, LPARAM lParam);
  30.         // IQueryHandler        
  31.         STDMETHOD(Initialize)(THIS_ IQueryFrame* pQueryFrame, DWORD dwOQWFlags, LPVOID pParameters);
  32.         STDMETHOD(GetViewInfo)(THIS_ LPCQVIEWINFO pViewInfo);
  33.         STDMETHOD(AddScopes)(THIS);
  34.         STDMETHOD(BrowseForScope)(THIS_ HWND hwndParent, LPCQSCOPE pCurrentScope, LPCQSCOPE* ppScope);
  35.         STDMETHOD(CreateResultView)(THIS_ HWND hwndParent, HWND* phWndView);
  36.         STDMETHOD(ActivateView)(THIS_ UINT uState, WPARAM wParam, LPARAM lParam);
  37.         STDMETHOD(InvokeCommand)(THIS_ HWND hwndParent, UINT uID);
  38.         STDMETHOD(GetCommandString)(THIS_ UINT uID, DWORD dwFlags, LPTSTR pBuffer, INT cchBuffer);
  39.         STDMETHOD(IssueQuery)(THIS_ LPCQPARAMS pQueryParams);
  40.         STDMETHOD(StopQuery)(THIS);
  41.         STDMETHOD(GetViewObject)(THIS_ UINT uScope, REFIID riid, void **ppvOut);
  42.         STDMETHOD(LoadQuery)(THIS_ IPersistQuery* pPersistQuery);
  43.         STDMETHOD(SaveQuery)(THIS_ IPersistQuery* pPersistQuery, LPCQSCOPE pScope);
  44.         // IObjectWithSite
  45.         STDMETHODIMP SetSite(IUnknown* punk);
  46.         STDMETHODIMP GetSite(REFIID riid, void **ppv);
  47.         // IDsQueryHandler
  48.         STDMETHOD(UpdateView)(THIS_ DWORD dwType, LPDSOBJECTNAMES pdon);
  49.         
  50.     private:        
  51.         LRESULT OnSize(INT cx, INT cy);
  52.         LRESULT OnNotify(HWND hWnd, WPARAM wParam, LPARAM lParam);
  53.         HRESULT OnAddResults(DWORD dwQueryReference, HDPA hdpaResults);
  54.         LRESULT OnContextMenu(HWND hwndMenu, LPARAM lParam);    
  55.         HRESULT OnFileProperties(VOID);
  56. #if !DOWNLEVEL_SHELL
  57.         HRESULT OnFileCreateShortcut(VOID);
  58. #endif
  59.         HRESULT OnFileSaveQuery(VOID);
  60.         HRESULT OnEditSelectAll(VOID);
  61.         HRESULT OnEditInvertSelection(VOID);
  62.         HRESULT OnPickColumns(HWND hwndParent);
  63.         HRESULT _InitNewQuery(LPDSQUERYPARAMS pDsQueryParams, BOOL fRefreshColumnTable);
  64.         HRESULT _GetFilterValue(INT iColumn, HD_ITEM* pitem);
  65.         HRESULT _FilterView(BOOL fCheck);
  66.         HRESULT _PopulateView(INT iFirstItem, INT iLast);
  67.         VOID _FreeResults(VOID);
  68.         DWORD _SetViewMode(INT uID);
  69.         VOID _SortResults(INT iColumn);
  70.         VOID _SetFilter(BOOL fFilter);
  71.         VOID _ShowBanner(UINT flags, UINT idPrompt);
  72.         VOID _InitViewMenuItems(HMENU hMenu);
  73.         HRESULT _GetQueryFormKey(REFCLSID clsidForm, HKEY* phKey);
  74.         HRESULT _GetColumnTable(REFCLSID clsidForm, LPDSQUERYPARAMS pDsQueryParams, HDSA* pHDSA, BOOL fSetInView);
  75.         VOID _SaveColumnTable(VOID);
  76.         HRESULT _SaveColumnTable(REFCLSID clsidForm, HDSA hdsaColumns);
  77.         HRESULT _CollectViewSelection(BOOL fGetAll, INT* pCount, LPCOLLECTPROC pCollectProc, LPARAM lParam);
  78.         HRESULT _GetIDLsAndViewObject(BOOL fGetAll, REFIID riid, void **ppcm);
  79.         VOID _GetContextMenuVerbs(IContextMenu* pcm, HMENU hMenu, DWORD dwFlags);
  80.         HRESULT _CopyCredentials(LPWSTR *ppszUserName, LPWSTR *ppszPassword, LPWSTR *ppszServer);
  81.         HRESULT _GetDirectorySF(IShellFolder **ppsf);
  82.         HRESULT _ADsPathToIdList(LPITEMIDLIST* ppidl, LPWSTR pPath, LPWSTR pObjectClasse);
  83.         VOID _DeleteViewItems(LPDSOBJECTNAMES pdon);
  84.     private:
  85.         IQueryFrame*  _pqf;                    // our parent window
  86.         IUnknown*     _punkSite;               // site object
  87.         IContextMenu* _pcm;                    // Curerntly displayed context menu / == NULL if none
  88.         DWORD         _dwOQWFlags;             // flags passed to OpenQueryWindow
  89.         DWORD         _dwFlags;                // flags as part of the ds query parameters
  90.         LPWSTR        _pDefaultScope;          // default scope passed
  91.         LPWSTR        _pDefaultSaveLocation;   // directory to save queries into by default
  92.         LPTSTR        _pDefaultSaveName;       // default save name (from the query form)
  93.         LPWSTR        _pServer;                // server to target
  94.         LPWSTR        _pUserName;              // user name and password to authenticate with
  95.         LPWSTR        _pPassword;
  96.         BOOL          _fNoSelection:1;         // the IContextMenu was from no selection
  97.         BOOL          _fColumnsModified:1;     // settings of the view modified
  98.         BOOL          _fSortDescending:1;      // sort the results descending
  99.         BOOL          _fFilter:1;              // filter enabled
  100.         BOOL          _fFilterSupported:1;     // is the filter available, eg: comctl32 > 5.0
  101.         
  102.         INT           _idViewMode;             // default view mode
  103.         INT           _iSortColumn;            // sort column
  104.         HWND          _hwnd;                   // container window
  105.         HWND          _hwndView;               // listview window (child of parent)
  106.         HWND          _hwndBanner;             // banner window which is a child of the list view
  107.         DWORD         _dwQueryReference;       // reference value passed to query 
  108.         HANDLE        _hThread;                // worker thread handle
  109.         DWORD         _dwThreadId;             // thread ID for the Query processing thread
  110.         CLSID         _clsidForm;              // form being used for column table
  111.         HDSA          _hdsaColumns;            // column information (size, filters, etc)
  112.         HDPA          _hdpaResults;            // results for tr the query we have issued
  113.         LPTSTR        _pFilter;                // current filter
  114.         HMENU         _hFrameMenuBar;          // stored frame menu bar, stored from activate
  115.         HMENU         _hFileMenu;              // added to the frames view menu
  116.         HMENU         _hEditMenu;              // inserted into the menu bar
  117.         HMENU         _hViewMenu;              // inserted into the menu bar
  118.         HMENU         _hHelpMenu;              // inserted into the menu bar
  119. };
  120. //
  121. // Window classes we create to show the results
  122. //
  123. #define VIEW_CLASS                  TEXT("ActiveDsQueryView")
  124. LRESULT CALLBACK _ResultViewWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  125. #define BANNER_CLASS                TEXT("ActiveDsQueryBanner")
  126. LRESULT CALLBACK _BannerWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  127. // 
  128. // Registry values used for the settings
  129. // 
  130. #define VIEW_SETTINGS_VALUE         TEXT("ViewSettings")
  131. #define ADMIN_VIEW_SETTINGS_VALUE   TEXT("AdminViewSettings");
  132. //
  133. // When filtering we populate the view using PostMessage, doing so many items
  134. // at a time
  135. //
  136. #define FILTER_UPDATE_COUNT         128
  137. // 
  138. // All items within the list view contain the following LPARAM structure used
  139. // for storing the magic properties we are interested in. 
  140. //
  141. #define ENABLE_MENU_ITEM(hMenu, id, fEnabled) 
  142.                 EnableMenuItem(hMenu, id, (fEnabled) ? (MF_BYCOMMAND|MF_ENABLED):(MF_BYCOMMAND|MF_GRAYED))
  143. //
  144. // Persisted column data, this is stored in the registry under the CLSID for the
  145. // form we are interested in.
  146. //
  147. typedef struct
  148. {
  149.     DWORD cbSize;                   // offset to the next column / == 0 if none
  150.     DWORD dwFlags;                  // flags
  151.     DWORD offsetProperty;           // offset to property name (UNICODE)
  152.     DWORD offsetHeading;            // offset to column heading
  153.     INT cx;                         // pixel width of the column
  154.     INT fmt;                        // format of the column
  155. } SAVEDCOLUMN, * LPSAVEDCOLUMN;
  156. //
  157. // Table to map property types to useful information
  158. //
  159. struct
  160. {
  161.     LPCTSTR pMenuName;
  162.     INT idOperator;
  163.     INT hdft;
  164. }
  165. property_type_table[] =
  166. {
  167.     0, 0, 0,
  168.     MAKEINTRESOURCE(IDR_OP_STRING), FILTER_CONTAINS, HDFT_ISSTRING,
  169.     MAKEINTRESOURCE(IDR_OP_STRING), FILTER_CONTAINS, HDFT_ISSTRING,
  170.     MAKEINTRESOURCE(IDR_OP_NUMBER), FILTER_IS,       HDFT_ISNUMBER,
  171.     MAKEINTRESOURCE(IDR_OP_NUMBER), FILTER_IS,       HDFT_ISNUMBER,           // PROPERTY_ISBOOL
  172. };
  173. //
  174. // Help information for the frame and the control
  175. //
  176. static DWORD const aHelpIDs[] =
  177. {
  178.     CQID_LOOKFORLABEL, IDH_FIND,
  179.     CQID_LOOKFOR,      IDH_FIND, 
  180.     CQID_LOOKINLABEL,  IDH_IN, 
  181.     CQID_LOOKIN,       IDH_IN,
  182.     CQID_BROWSE,       IDH_BROWSE,
  183.     CQID_FINDNOW,      IDH_FIND_NOW,
  184.     CQID_STOP,         IDH_STOP,
  185.     CQID_CLEARALL,     IDH_CLEAR_ALL,
  186.     IDC_RESULTS,       IDH_RESULTS,
  187.     IDC_STATUS,        IDH_NO_HELP,
  188.     0, 0,    
  189. }; 
  190. //
  191. // Help information for the browse dialog that is shown for scopes
  192. //
  193. static DWORD const aBrowseHelpIDs[] =
  194. {
  195.     DSBID_BANNER, (DWORD)-1,
  196.     DSBID_CONTAINERLIST, IDH_BROWSE_CONTAINER,
  197.     0, 0,
  198. };
  199. //
  200. // path to DsFolder
  201. //
  202. #if DELEGATE
  203. WCHAR c_szDsMagicPath[] = L"::{208D2C60-3AEA-1069-A2D7-08002B30309D}";
  204. #else
  205. WCHAR c_szDsMagicPath[] = L"::{208D2C60-3AEA-1069-A2D7-08002B30309D}\EntireNetwork\::{fe1290f0-cfbd-11cf-a330-00aa00c16e65}";
  206. #endif
  207. /*-----------------------------------------------------------------------------
  208. / CDsQuery
  209. /----------------------------------------------------------------------------*/
  210. CDsQuery::CDsQuery() :
  211.     _fNoSelection(TRUE),
  212.     _iSortColumn(-1),      
  213.     _idViewMode(DSQH_VIEW_DETAILS)
  214. {
  215.     TraceEnter(TRACE_HANDLER, "CDsQuery::CDsQuery");
  216.     if ( CheckDsPolicy(NULL, c_szEnableFilter) )
  217.     {
  218.         TraceMsg("QuickFilter enabled in policy");
  219.         _fFilter = TRUE;
  220.     }
  221.     TraceLeave();       
  222. }
  223. CDsQuery::~CDsQuery()
  224. {
  225.     TraceEnter(TRACE_HANDLER, "CDsQuery::~CDsQuery");
  226.     // persist the column information if we need to
  227.     if ( _hdsaColumns )
  228.     {
  229.         if ( _fColumnsModified )
  230.         {
  231.             _SaveColumnTable(_clsidForm, _hdsaColumns);
  232.             _fColumnsModified = FALSE;
  233.         }
  234.         _SaveColumnTable();
  235.     }
  236.     // discard all the other random state we have
  237.     LocalFreeStringW(&_pDefaultScope);
  238.     LocalFreeStringW(&_pDefaultSaveLocation);
  239.     LocalFreeString(&_pDefaultSaveName);
  240.     LocalFreeStringW(&_pUserName);
  241.     LocalFreeStringW(&_pPassword);
  242.     LocalFreeStringW(&_pServer);
  243.     if ( IsWindow(_hwnd) )
  244.         DestroyWindow(_hwnd);
  245.     if ( IsMenu(_hFileMenu) )
  246.         DestroyMenu(_hFileMenu);
  247.     if ( IsMenu(_hEditMenu) )
  248.          DestroyMenu(_hEditMenu);
  249.     if ( IsMenu(_hViewMenu) )
  250.         DestroyMenu(_hViewMenu);
  251.     if ( IsMenu(_hHelpMenu) )
  252.         DestroyMenu(_hHelpMenu);
  253.     // tell the thread its time to die
  254.     if ( _hThread )
  255.     {
  256.         PostThreadMessage(_dwThreadId, RVTM_STOPQUERY, 0, 0);
  257.         PostThreadMessage(_dwThreadId, WM_QUIT, 0, 0);
  258.         CloseHandle(_hThread);
  259.     }
  260.     DoRelease(_pqf);
  261.     DoRelease(_punkSite);
  262.     DoRelease(_pcm);
  263.     TraceLeave();
  264. }
  265. // IUnknown bits
  266. #undef  CLASS_NAME
  267. #define CLASS_NAME CDsQuery
  268. #include "unknown.inc"
  269. STDMETHODIMP CDsQuery::QueryInterface(REFIID riid, void **ppvObject)
  270. {
  271.     INTERFACES iface[] =
  272.     {
  273.         &IID_IQueryForm, (IQueryForm*)this,
  274.         &IID_IQueryHandler, (IQueryHandler*)this,
  275.         &IID_IObjectWithSite, (IObjectWithSite*)this,
  276.         &IID_IDsQueryHandler, (IDsQueryHandler*)this,
  277.     };
  278.     return HandleQueryInterface(riid, ppvObject, iface, ARRAYSIZE(iface));
  279. }
  280. //
  281. // Handle creating an instance of CLSID_DsQuery
  282. //
  283. STDAPI CDsQuery_CreateInstance(IUnknown* punkOuter, IUnknown** ppunk, LPCOBJECTINFO poi)
  284. {
  285.     CDsQuery *pdq = new CDsQuery();
  286.     if ( !pdq )
  287.         return E_OUTOFMEMORY;
  288.     HRESULT hres = pdq->QueryInterface(IID_IUnknown, (void **)ppunk);
  289.     pdq->Release();
  290.     return hres;
  291. }
  292. /*-----------------------------------------------------------------------------
  293. / IQueryForm methods
  294. /----------------------------------------------------------------------------*/
  295. STDMETHODIMP CDsQuery::Initialize(THIS_ HKEY hkForm)
  296. {
  297.     TraceEnter(TRACE_FORMS, "CDsQuery::Initialize");
  298.     TraceLeaveResult(S_OK);
  299. }
  300. /*---------------------------------------------------------------------------*/
  301. struct
  302. {
  303.     CLSID const * clsidForm;
  304.     INT idsTitle;
  305.     DWORD dwFlags;
  306. }
  307. forms[] =
  308. {
  309.     &CLSID_DsFindPeople,           IDS_FINDUSER,          0,
  310.     &CLSID_DsFindComputer,         IDS_FINDCOMPUTER,      0,
  311.     &CLSID_DsFindPrinter,          IDS_FINDPRINTERS,      0,
  312.     &CLSID_DsFindVolume,           IDS_FINDSHAREDFOLDERS, 0,
  313.     &CLSID_DsFindContainer,        IDS_FINDOU,            0,
  314.     &CLSID_DsFindAdvanced,         IDS_CUSTOMSEARCH,      CQFF_NOGLOBALPAGES,
  315.     &CLSID_DsFindDomainController, IDS_FINDDOMCTL,        CQFF_ISNEVERLISTED|CQFF_NOGLOBALPAGES,
  316.     &CLSID_DsFindFrsMembers,       IDS_FINDFRSMEMBER,     CQFF_ISNEVERLISTED|CQFF_NOGLOBALPAGES,
  317. };
  318. STDMETHODIMP CDsQuery::AddForms(THIS_ LPCQADDFORMSPROC pAddFormsProc, LPARAM lParam)
  319. {
  320.     HRESULT hres;
  321.     TCHAR szBuffer[MAX_PATH];
  322.     INT i;
  323.     TraceEnter(TRACE_FORMS, "CDsQuery::AddForms");
  324.     if ( !pAddFormsProc )
  325.         ExitGracefully(hres, E_INVALIDARG, "No AddFormsProc");
  326.     for ( i = 0; i < ARRAYSIZE(forms); i++ ) 
  327.     {
  328.         CQFORM qf = { 0 };
  329.         qf.cbStruct = SIZEOF(qf);
  330.         qf.dwFlags = forms[i].dwFlags;
  331.         qf.clsid = *forms[i].clsidForm;
  332.         qf.pszTitle = szBuffer;
  333.         LoadString(GLOBAL_HINSTANCE, forms[i].idsTitle, szBuffer, ARRAYSIZE(szBuffer));
  334.         hres = (*pAddFormsProc)(lParam, &qf);
  335.         FailGracefully(hres, "Failed to add form (calling pAddFormsFunc)");        
  336.     }
  337.     hres = S_OK;                  // success
  338. exit_gracefully:
  339.     TraceLeaveResult(hres);
  340. }
  341. /*---------------------------------------------------------------------------*/
  342. struct
  343. {
  344.     CLSID const * clisdForm;
  345.     LPCQPAGEPROC pPageProc;
  346.     DLGPROC pDlgProc;
  347.     INT idPageTemplate;
  348.     INT idPageName;
  349.     DWORD dwFlags;
  350. pages[] =
  351. {   
  352.     //
  353.     // Page list for the default forms that we add
  354.     //
  355.     &CLSID_DsFindPeople,           PageProc_User,             DlgProc_User,             IDD_FINDUSER,        IDS_FINDUSER,          0, 
  356.     &CLSID_DsFindComputer,         PageProc_Computer,         DlgProc_Computer,         IDD_FINDCOMPUTER,    IDS_FINDCOMPUTER,      0,
  357.     &CLSID_DsFindPrinter,          PageProc_Printers,         DlgProc_Printers,         IDD_FINDPRINT1,      IDS_FINDPRINTERS,      0, 
  358.     &CLSID_DsFindPrinter,          PageProc_PrintersMore,     DlgProc_PrintersMore,     IDD_FINDPRINT2,      IDS_MORECHOICES,       0, 
  359.     &CLSID_DsFindVolume,           PageProc_Volume,           DlgProc_Volume,           IDD_FINDVOLUME,      IDS_FINDSHAREDFOLDERS, 0, 
  360.     &CLSID_DsFindContainer,        PageProc_Container,        DlgProc_Container,        IDD_FINDCONTAINER,   IDS_FINDOU,            0, 
  361.     &CLSID_DsFindAdvanced,         PageProc_PropertyWell,     DlgProc_PropertyWell,     IDD_PROPERTYWELL,    IDS_CUSTOMSEARCH,      0,
  362.     &CLSID_DsFindAdvanced,         PageProc_RawLDAP,          DlgProc_RawLDAP,          IDD_FINDUSINGLDAP,   IDS_ADVANCED,          0, 
  363.     &CLSID_DsFindDomainController, PageProc_DomainController, DlgProc_DomainController, IDD_FINDDOMCTL,      IDS_FINDDOMCTL,        0, 
  364.     &CLSID_DsFindFrsMembers,       PageProc_FrsMember,        DlgProc_FrsMember,        IDD_FINDFRSMEMBER,   IDS_FINDFRSMEMBER,     0, 
  365.     //
  366.     // Make the property well available on all pages (using the magic CQPF_ADDTOALLFORMS bit)
  367.     //
  368.     &CLSID_DsFindAdvanced,          PageProc_PropertyWell,    DlgProc_PropertyWell,     IDD_PROPERTYWELL,  IDS_ADVANCED,          CQPF_ISGLOBAL,
  369. };
  370. STDMETHODIMP CDsQuery::AddPages(THIS_ LPCQADDPAGESPROC pAddPagesProc, LPARAM lParam)
  371. {
  372.     HRESULT hres;
  373.     INT i;
  374.     TraceEnter(TRACE_FORMS, "CDsQuery::AddPages");
  375.     if ( !pAddPagesProc )
  376.         ExitGracefully(hres, E_INVALIDARG, "No AddPagesProc");
  377.     for ( i = 0 ; i < ARRAYSIZE(pages) ; i++ )
  378.     {
  379.         CQPAGE qp = { 0 };
  380.         qp.cbStruct = SIZEOF(qp);
  381.         qp.dwFlags = pages[i].dwFlags;
  382.         qp.pPageProc = pages[i].pPageProc;
  383.         qp.hInstance = GLOBAL_HINSTANCE;
  384.         qp.idPageName = pages[i].idPageName;
  385.         qp.idPageTemplate = pages[i].idPageTemplate;
  386.         qp.pDlgProc = pages[i].pDlgProc;        
  387.         hres = (*pAddPagesProc)(lParam, *pages[i].clisdForm, &qp);
  388.         FailGracefully(hres, "Failed to add page (calling pAddPagesFunc)");        
  389.     }
  390.     hres = S_OK;
  391. exit_gracefully:
  392.     TraceLeaveResult(S_OK);
  393. }
  394. /*-----------------------------------------------------------------------------
  395. / IQueryHandler methods
  396. /----------------------------------------------------------------------------*/
  397. STDMETHODIMP CDsQuery::Initialize(THIS_ IQueryFrame* pQueryFrame, DWORD dwOQWFlags, LPVOID pParameters)
  398. {
  399.     HRESULT hres;
  400.     LPDSQUERYINITPARAMS pDsQueryInitParams = (LPDSQUERYINITPARAMS)pParameters;
  401.     TCHAR szGUID[GUIDSTR_MAX];
  402.     TCHAR szBuffer[MAX_PATH];
  403.     HINSTANCE hInstanceComCtl32 = NULL;
  404.     USES_CONVERSION;
  405.   
  406.     TraceEnter(TRACE_HANDLER, "CDsQuery::Initialize");
  407.     // Keep the IQueryFrame interface, we need it for menu negotiation and other
  408.     // view -> frame interactions.
  409.     _pqf = pQueryFrame;
  410.     _pqf->AddRef();
  411.     _dwOQWFlags = dwOQWFlags;
  412.     // If we have a parameter block then lets take copies of the interesting
  413.     // fields from there.
  414.     if ( pDsQueryInitParams )
  415.     {
  416.         _dwFlags = pDsQueryInitParams->dwFlags;
  417.         // did the user specify a default scope?
  418.         if ( pDsQueryInitParams->pDefaultScope && pDsQueryInitParams->pDefaultScope[0] )
  419.         {
  420.             Trace(TEXT("Default scope:"), W2T(pDsQueryInitParams->pDefaultScope));
  421.             hres = LocalAllocStringW(&_pDefaultScope, pDsQueryInitParams->pDefaultScope);
  422.             FailGracefully(hres, "Failed to cope default scope");
  423.         }
  424.         // default save location?
  425.         if ( (_dwFlags & DSQPF_SAVELOCATION) && pDsQueryInitParams->pDefaultSaveLocation )
  426.         {
  427.             Trace(TEXT("Default save location:"), W2T(pDsQueryInitParams->pDefaultSaveLocation));
  428.             hres = LocalAllocStringW(&_pDefaultSaveLocation, pDsQueryInitParams->pDefaultSaveLocation);
  429.             FailGracefully(hres, "Failed to copy save location");
  430.         }
  431.         // do we have credential information?
  432.         if ( _dwFlags & DSQPF_HASCREDENTIALS )
  433.         {
  434.             TraceMsg("Copying credential/server information from init params");
  435.             if ( pDsQueryInitParams->pUserName )
  436.             {
  437.                 hres = LocalAllocStringW(&_pUserName, pDsQueryInitParams->pUserName);
  438.                 FailGracefully(hres, "Failed to copy user name");
  439.             }
  440.             if ( pDsQueryInitParams->pPassword )
  441.             {
  442.                 hres = LocalAllocStringW(&_pPassword, pDsQueryInitParams->pPassword);
  443.                 FailGracefully(hres, "Failed to copy password");
  444.             }
  445.             if ( pDsQueryInitParams->pServer )
  446.             {
  447.                 hres = LocalAllocStringW(&_pServer, pDsQueryInitParams->pServer);
  448.                 FailGracefully(hres, "Failed to copy server");
  449.             }
  450.             Trace(TEXT("_pUserName : %s"), _pUserName ? W2T(_pUserName):TEXT("<not specified>"));
  451.             Trace(TEXT("_pPassword : %s"), _pPassword ? W2T(_pPassword):TEXT("<not specified>"));
  452.             Trace(TEXT("_pServer : %s"), _pServer ? W2T(_pServer):TEXT("<not specified>"));
  453.         }
  454.     }
  455.     // Finally load the must structures that we are going to use, then modify them
  456.     // based on the flags that the caller gave us.
  457.     //
  458.     // NB: removes the last two items from the file menu assumed to be the
  459.     //     "save" and its seperator
  460.     _hFileMenu = LoadMenu(GLOBAL_HINSTANCE, MAKEINTRESOURCE(IDR_MENU_FILE));
  461.     _hEditMenu = LoadMenu(GLOBAL_HINSTANCE, MAKEINTRESOURCE(IDR_MENU_EDIT));
  462.     _hViewMenu = LoadMenu(GLOBAL_HINSTANCE, MAKEINTRESOURCE(IDR_MENU_VIEW));
  463.     _hHelpMenu = LoadMenu(GLOBAL_HINSTANCE, MAKEINTRESOURCE(IDR_MENU_HELP));
  464.     if ( !_hFileMenu || !_hEditMenu || !_hViewMenu || !_hHelpMenu )
  465.         ExitGracefully(hres, E_FAIL, "Failed to load resources for menus");
  466.     if ( _dwFlags & DSQPF_NOSAVE )
  467.     {
  468.         HMENU hFileMenu = GetSubMenu(_hFileMenu, 0);
  469.         INT i = GetMenuItemCount(hFileMenu);
  470.         DeleteMenu(hFileMenu, i-1, MF_BYPOSITION);
  471.         DeleteMenu(hFileMenu, i-2, MF_BYPOSITION);
  472.     }
  473.     // Init ComCtl32, including checking to see if we can use the filter control or not,
  474.     // the filter control was added to the WC_HEADER32 in IE5, so check the DLL version
  475.     // to see which we are using.
  476.     InitCommonControls();
  477.     hInstanceComCtl32 = GetModuleHandle(TEXT("comctl32"));
  478.     TraceAssert(hInstanceComCtl32);
  479.     if ( hInstanceComCtl32 )
  480.     {
  481.         DLLVERSIONINFO dllVersionInfo = { 0 };
  482.         DLLGETVERSIONPROC pfnDllGetVersion = (DLLGETVERSIONPROC)GetProcAddress(hInstanceComCtl32, "DllGetVersion");        
  483.         TraceAssert(pfnDllGetVersion);
  484.         dllVersionInfo.cbSize = SIZEOF(dllVersionInfo);
  485.         if ( pfnDllGetVersion && SUCCEEDED(pfnDllGetVersion(&dllVersionInfo)) )
  486.         {
  487.             Trace(TEXT("DllGetVersion succeeded on ComCtl32, dwMajorVersion %08x"), dllVersionInfo.dwMajorVersion);
  488.             _fFilterSupported = dllVersionInfo.dwMajorVersion >= 5;
  489.         }
  490.     }
  491.     
  492.     Trace(TEXT("_fFilterSupported is %d"), _fFilterSupported);
  493.     hres = S_OK;                  // success
  494. exit_gracefully:
  495.     TraceLeaveResult(hres);
  496. }
  497. /*---------------------------------------------------------------------------*/
  498. STDMETHODIMP CDsQuery::GetViewInfo(THIS_ LPCQVIEWINFO pViewInfo)
  499. {
  500.     HICON hIcon;
  501.     TraceEnter(TRACE_HANDLER, "CDsQuery::GetViewInfo");
  502.     pViewInfo->dwFlags      = 0;
  503.     pViewInfo->hInstance    = GLOBAL_HINSTANCE;
  504.     pViewInfo->idLargeIcon  = IDI_FIND;
  505.     pViewInfo->idSmallIcon  = IDI_FIND;
  506.     pViewInfo->idTitle      = IDS_WINDOWTITLE;
  507.     pViewInfo->idAnimation  = IDR_DSFINDANIMATION;
  508.     TraceLeaveResult(S_OK);
  509. }
  510. /*---------------------------------------------------------------------------*/
  511. STDMETHODIMP CDsQuery::AddScopes(THIS)
  512. {
  513.     HRESULT hres;
  514.     DWORD dwThreadId;
  515.     HANDLE hThread;
  516.     LPSCOPETHREADDATA pstd = NULL;
  517.     USES_CONVERSION;
  518.     TraceEnter(TRACE_HANDLER, "CDsQuery::AddScopes");
  519.     // Enumerate the rest of the scopes on a seperate thread to gather the
  520.     // scopes we are interested in.
  521.     pstd = (LPSCOPETHREADDATA)LocalAlloc(LPTR, SIZEOF(SCOPETHREADDATA));
  522.     TraceAssert(pstd);
  523.     if ( !pstd )
  524.         ExitGracefully(hres, E_OUTOFMEMORY, "Failed to allocate scope data structure");
  525.     _pqf->GetWindow(&pstd->hwndFrame);
  526.     // pstd->pDefaultScope = NULL;
  527.     // pstd->pServer = NULL;            // no credential stuff currently
  528.     // pstd->pUserName = NULL;
  529.     // pstd->pPassword = NULL;
  530.     if ( _pDefaultScope )
  531.     {
  532.         hres = LocalAllocStringW(&pstd->pDefaultScope, _pDefaultScope);
  533.         FailGracefully(hres, "Failed to copy the default scope");
  534.     }
  535.     hres = _CopyCredentials(&pstd->pUserName, &pstd->pPassword, &pstd->pServer);
  536.     FailGracefully(hres, "Failed to copy credentails");
  537.     InterlockedIncrement(&GLOBAL_REFCOUNT);
  538.     hThread = CreateThread(NULL, 0, AddScopesThread, pstd, 0, &dwThreadId);
  539.     TraceAssert(hThread);
  540.     if ( !hThread )
  541.     {
  542.         InterlockedDecrement(&GLOBAL_REFCOUNT);
  543.         ExitGracefully(hres, E_FAIL, "Failed to create background thread to enum scopes - BAD!");
  544.     }
  545.     CloseHandle(hThread);
  546.     hres = S_OK;
  547. exit_gracefully:
  548.     if ( FAILED(hres) && pstd )
  549.     {
  550.         LocalFreeStringW(&pstd->pDefaultScope);
  551.         LocalFree((HLOCAL)pstd);
  552.     }
  553.     TraceLeaveResult(hres);
  554. }
  555. /*---------------------------------------------------------------------------*/
  556. typedef struct
  557. {
  558.     IADsPathname *padp;
  559.     WCHAR szGcPath[MAX_PATH];
  560. } BROWSEFORSCOPE;
  561. int CALLBACK _BrowseForScopeCB(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
  562. {
  563.     HRESULT hres;
  564.     INT iResult = 0;
  565.     BROWSEFORSCOPE *pbfs = (BROWSEFORSCOPE*)lpData;
  566.     LPTSTR pDirectoryName = NULL;
  567.     USES_CONVERSION;
  568.     TraceEnter(TRACE_HANDLER, "_BrowseForScopeCB");
  569.     switch ( uMsg )
  570.     {
  571.         case DSBM_QUERYINSERT:
  572.         {
  573.             PDSBITEM pItem = (PDSBITEM)lParam;
  574.             TraceAssert(pItem);
  575.             // We are interested in modifying the root item of the tree, therefore
  576.             // lets check for that being inserted, if it is then we change the
  577.             // display name and the icon being shown.
  578.             if ( pItem->dwState & DSBS_ROOT )
  579.             {
  580.                 GetModuleFileName(GLOBAL_HINSTANCE, pItem->szIconLocation, ARRAYSIZE(pItem->szIconLocation));
  581.                 pItem->iIconResID = -IDI_GLOBALCATALOG;
  582.                 if ( SUCCEEDED(FormatDirectoryName(&pDirectoryName, GLOBAL_HINSTANCE, IDS_GLOBALCATALOG)) )
  583.                 {
  584.                     StrCpyN(pItem->szDisplayName, pDirectoryName, DSB_MAX_DISPLAYNAME_CHARS);
  585.                     LocalFreeString(&pDirectoryName);
  586.                 }
  587.                 pItem->dwMask |= DSBF_DISPLAYNAME|DSBF_ICONLOCATION;
  588.                 iResult = TRUE;
  589.             }
  590.             break;
  591.         }
  592.         case BFFM_SELCHANGED:
  593.         {
  594.             BOOL fEnableOK = TRUE;
  595.             LPWSTR pszPath = (LPWSTR)lParam;
  596.             LONG nElements = 0;
  597.             // The user changes the selection in the browse dialog, therefore
  598.             // lets see if we should be enabling the OK button.  If the user
  599.             // selects GC, but we don't have a GC then we disable it.
  600.             if ( SUCCEEDED(pbfs->padp->Set(pszPath, ADS_SETTYPE_FULL)) )
  601.             {
  602.                 pbfs->padp->GetNumElements(&nElements);
  603.                 Trace(TEXT("nElements on exit from GetNumElements %d"), nElements);
  604.             }
  605.             if ( !nElements && !pbfs->szGcPath[0] )
  606.             {
  607.                 TraceMsg("'entire directory' selected with NO GC!");
  608.                 fEnableOK = FALSE;
  609.             }
  610.             SendMessage(hwnd, BFFM_ENABLEOK, (WPARAM)fEnableOK, 0L);
  611.             break;
  612.         }
  613.         case DSBM_HELP:
  614.         {
  615.             WinHelp((HWND)((LPHELPINFO)lParam)->hItemHandle,
  616.                     DSQUERY_HELPFILE,
  617.                     HELP_WM_HELP,
  618.                     (DWORD_PTR)aBrowseHelpIDs);
  619.             break;
  620.         }
  621.         case DSBM_CONTEXTMENU:
  622.         {
  623.             WinHelp((HWND)lParam,
  624.                     DSQUERY_HELPFILE,
  625.                     HELP_CONTEXTMENU,
  626.                     (DWORD_PTR)aBrowseHelpIDs);
  627.             break;
  628.         }
  629.     }
  630.     TraceLeaveValue(iResult);
  631. }
  632. STDMETHODIMP CDsQuery::BrowseForScope(THIS_ HWND hwndParent,  LPCQSCOPE pCurrentScope, LPCQSCOPE* ppScope)
  633. {
  634.     HRESULT hres;
  635.     LPDSQUERYSCOPE pDsQueryScope = (LPDSQUERYSCOPE)pCurrentScope;
  636.     BROWSEFORSCOPE bfs = { 0 };
  637.     DSBROWSEINFO dsbi = { 0 };
  638.     INT iResult;
  639.     WCHAR szPath[2048];
  640.     WCHAR szRoot[MAX_PATH+10];      // LDAP://
  641.     WCHAR szObjectClass[64];
  642.     LONG nElements;
  643.     USES_CONVERSION;
  644.     
  645.     TraceEnter(TRACE_HANDLER, "CDsQuery::BrowseForScope");
  646.     Trace(TEXT("hwndParent %08x, pCurrentScope %08x, ppScope %08x"), hwndParent, pCurrentScope, ppScope);
  647.     *ppScope = NULL;                        // nothing yet!
  648.     if ( SUCCEEDED(GetGlobalCatalogPath(_pServer, bfs.szGcPath, ARRAYSIZE(bfs.szGcPath))) )
  649.         Trace(TEXT("GC path is: %s"), W2T(bfs.szGcPath));
  650.     hres = CoCreateInstance(CLSID_Pathname, NULL, CLSCTX_INPROC_SERVER, IID_IADsPathname, (void **)&bfs.padp);
  651.     FailGracefully(hres, "Failed to get the IADsPathname interface");
  652.     // Fill out the browse info structure to display the object picker, if we have
  653.     // enabled admin features then lets make all objects visible, otherwise
  654.     // just the standard features.
  655.     dsbi.cbStruct = SIZEOF(dsbi);
  656.     dsbi.hwndOwner = hwndParent;
  657.     dsbi.pszRoot = szRoot;
  658.     dsbi.pszPath = szPath;
  659.     dsbi.cchPath = ARRAYSIZE(szPath);
  660.     dsbi.dwFlags = (DSBI_RETURNOBJECTCLASS|DSBI_EXPANDONOPEN|DSBI_ENTIREDIRECTORY) & ~DSBI_NOROOT;
  661.     dsbi.pfnCallback = _BrowseForScopeCB;
  662.     dsbi.lParam = (LPARAM)&bfs;
  663.     dsbi.pszObjectClass = szObjectClass;
  664.     dsbi.cchObjectClass = ARRAYSIZE(szObjectClass);
  665.     if ( _dwFlags & DSQPF_SHOWHIDDENOBJECTS )
  666.         dsbi.dwFlags |= DSBI_INCLUDEHIDDEN;
  667.     FormatMsgResource((LPTSTR*)&dsbi.pszTitle, GLOBAL_HINSTANCE, IDS_BROWSEPROMPT);
  668.     StrCpyW(szRoot, c_szLDAP);
  669.     if ( _pServer )
  670.     {
  671.         if ( lstrlenW(_pServer) > MAX_PATH )
  672.             ExitGracefully(hres, E_INVALIDARG, "_pServer is too big");
  673.         StrCatW(szRoot, L"//");
  674.         StrCatW(szRoot, _pServer);
  675.     }
  676.     if ( pDsQueryScope )
  677.     {
  678.         StrCpyNW(szPath, OBJECT_NAME_FROM_SCOPE(pDsQueryScope), ARRAYSIZE(szPath));
  679.         Trace(TEXT("pDsQueryScope: %s"), W2T(szPath));
  680.     }
  681.     // copy the credential information if needed
  682.     if ( _dwFlags & DSQPF_HASCREDENTIALS )
  683.     {
  684.         TraceMsg("Setting credentails information");
  685.         dsbi.pUserName = _pUserName;
  686.         dsbi.pPassword = _pPassword;
  687.         dsbi.dwFlags |= DSBI_HASCREDENTIALS;
  688.     }
  689.     iResult = DsBrowseForContainer(&dsbi);
  690.     Trace(TEXT("DsBrowseForContainer returns %d"), iResult);
  691.     // iResult == IDOK if something was selected (szPath),
  692.     // if it is -VE if the call failed and we should error
  693.     if ( iResult == IDOK )
  694.     {
  695.         LPWSTR pszScope = szPath;
  696.         LPWSTR pszObjectClass = szObjectClass;
  697.         LONG nElements = 0;
  698.         Trace(TEXT("Path on exit from DsBrowseForContainer: %s"), W2T(szPath));
  699.         // does this look like the GC?  If so then default to it, as DsBrowseForContainer
  700.         // will return us iffy looking information
  701.         if ( SUCCEEDED(bfs.padp->Set(szPath, ADS_SETTYPE_FULL)) )
  702.         {
  703.             bfs.padp->GetNumElements(&nElements);
  704.             Trace(TEXT("nElements on exit from GetNumElements %d"), nElements);
  705.         }
  706.         if ( !nElements )
  707.         {
  708.             TraceMsg("nElements = 0, so defaulting to GC");
  709.             pszScope = bfs.szGcPath;
  710.             pszObjectClass = GC_OBJECTCLASS;
  711.         }
  712.         Trace(TEXT("Scope selected is: %s, Object class: %s"), W2T(pszScope), W2T(pszObjectClass));
  713.         hres = AllocScope(ppScope, 0, pszScope, pszObjectClass);
  714.         FailGracefully(hres, "Failed converting the DS path to a scope");
  715.     }
  716.     else if ( iResult == IDCANCEL )
  717.     {
  718.         hres = S_FALSE;               // nothing selected, returning S_FALSE;
  719.     }
  720.     else if ( iResult < 0 )
  721.     {
  722.         ExitGracefully(hres, E_FAIL, "DsBrowseForContainer failed");
  723.     }
  724. exit_gracefully:
  725.     LocalFreeString((LPTSTR*)&dsbi.pszTitle);
  726.     Trace(TEXT("*ppScope == %08x"), *ppScope);
  727.     DoRelease(bfs.padp);
  728.     TraceLeaveResult(hres);
  729. }
  730. /*---------------------------------------------------------------------------*/
  731. //
  732. // WndProc for the banner window
  733. //
  734. LRESULT CALLBACK _BannerWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  735. {
  736.     LRESULT lResult = 0;
  737.     switch ( uMsg )
  738.     {
  739.         case WM_SIZE:
  740.             InvalidateRect(hwnd, NULL, FALSE);
  741.             break;
  742.         case WM_ERASEBKGND:
  743.             break;
  744.         case WM_PAINT:
  745.         {
  746.             TCHAR szBuffer[MAX_PATH];
  747.             HFONT hFont, hOldFont;
  748.             SIZE szText;
  749.             RECT rcClient;
  750.             INT len;
  751.             PAINTSTRUCT paint;
  752.             COLORREF oldFgColor, oldBkColor;
  753.     
  754.             BeginPaint(hwnd, &paint);
  755.             hFont = (HFONT)SendMessage(GetParent(hwnd), WM_GETFONT, 0, 0L);
  756.             hOldFont = (HFONT)SelectObject(paint.hdc, hFont);
  757.             if ( hOldFont )
  758.             {
  759.                 oldFgColor = SetTextColor(paint.hdc, GetSysColor(COLOR_WINDOWTEXT));                    
  760.                 oldBkColor = SetBkColor(paint.hdc, ListView_GetBkColor(GetParent(hwnd)));
  761.                 len = GetWindowText(hwnd, szBuffer, ARRAYSIZE(szBuffer));
  762.                 GetTextExtentPoint32(paint.hdc, szBuffer, len, &szText);
  763.                 GetClientRect(GetParent(hwnd), &rcClient);
  764.                 
  765.                 ExtTextOut(paint.hdc, 
  766.                            (rcClient.right - szText.cx) / 2, 
  767.                            GetSystemMetrics(SM_CYBORDER)*4,
  768.                            ETO_CLIPPED|ETO_OPAQUE, &rcClient, 
  769.                            szBuffer, len,
  770.                            NULL);
  771.                 SetTextColor(paint.hdc, oldFgColor);
  772.                 SetBkColor(paint.hdc, oldBkColor);
  773.                 SelectObject(paint.hdc, hOldFont);
  774.             }
  775.             EndPaint(hwnd, &paint);
  776.             break;
  777.         }
  778.         case WM_SETTEXT:
  779.         {
  780.             InvalidateRect(hwnd, NULL, FALSE);
  781.             //break;                                // deliberate drop through..
  782.         }
  783.         default:
  784.             lResult = DefWindowProc(hwnd, uMsg, wParam, lParam);
  785.             break;
  786.     }
  787.     return lResult;
  788. }
  789. //
  790. // WndProc for the bg window (lives behind list view, used by rest of the world)
  791. //
  792. LRESULT CALLBACK _ResultViewWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  793. {
  794.     LRESULT lResult = 0;
  795.     CDsQuery* pDsQuery = NULL;
  796.     if ( uMsg == WM_CREATE )
  797.     {
  798.         pDsQuery = (CDsQuery*)((LPCREATESTRUCT)lParam)->lpCreateParams;
  799.         SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pDsQuery);
  800.     }
  801.     else
  802.     {
  803.         pDsQuery = (CDsQuery*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
  804.         switch ( uMsg )
  805.         {
  806.             case WM_SIZE:
  807.                 pDsQuery->OnSize(LOWORD(lParam), HIWORD(lParam));
  808.                 return(0);
  809.             case WM_DESTROY:
  810.                 pDsQuery->_hwndView = NULL;         // view is gone!
  811.                 break;
  812.             case WM_NOTIFY:
  813.                 return(pDsQuery->OnNotify(hwnd, wParam, lParam));
  814.             case WM_SETFOCUS:
  815.                 SetFocus(pDsQuery->_hwndView);
  816.                 break;
  817.             case WM_GETDLGCODE:
  818.                 return ((LRESULT)(DLGC_WANTARROWS | DLGC_WANTCHARS));
  819.             case WM_CONTEXTMENU:
  820.                 pDsQuery->OnContextMenu(NULL, lParam);
  821.                 return TRUE;
  822.         
  823.             case DSQVM_ADDRESULTS:
  824.                 return SUCCEEDED(pDsQuery->OnAddResults((DWORD)wParam, (HDPA)lParam));
  825.                                  
  826.             case DSQVM_FINISHED:
  827.                 if ( (DWORD)wParam == pDsQuery->_dwQueryReference )
  828.                 {
  829.                     // the references match so lets finish the query, and display 
  830.                     // the "too many results" prompt if the user did a really
  831.                     // big query and we chopped them off
  832.                     pDsQuery->StopQuery();
  833.                     if ( lParam )     // == 0 then we are OK!
  834.                     {
  835.                         HWND hwndFrame;
  836.                         pDsQuery->_pqf->GetWindow(&hwndFrame);
  837.                         FormatMsgBox(GetParent(hwndFrame),
  838.                                      GLOBAL_HINSTANCE, IDS_WINDOWTITLE, IDS_ERR_MAXRESULT, 
  839.                                      MB_OK|MB_ICONERROR);                        
  840.                     }
  841.                 }
  842.                 SetFocus(pDsQuery->_hwndView);
  843.                 return(1);
  844.         }
  845.     }
  846.     return DefWindowProc(hwnd, uMsg, wParam, lParam);
  847. }
  848. STDMETHODIMP CDsQuery::CreateResultView(THIS_ HWND hwndParent, HWND* phWndView)
  849. {
  850.     HRESULT hres;
  851.     WNDCLASS wc;
  852.     HWND hwndFilter, hwndFilterOld;
  853.     HIMAGELIST himlSmall, himlLarge;
  854.     DWORD dwLVStyle = LVS_AUTOARRANGE|LVS_SHAREIMAGELISTS|LVS_SHOWSELALWAYS|LVS_REPORT;
  855.     RECT rc;
  856.     TraceEnter(TRACE_HANDLER, "CDsQuery::CreateResultView");
  857.     if ( IsWindow(_hwnd) )
  858.         ExitGracefully(hres, E_FAIL, "Can only create one view at a time");
  859.     // Create our result viewer, this is the parent window to the ListView
  860.     // that we attach when we issue the query.
  861.     
  862.     ZeroMemory(&wc, SIZEOF(wc));
  863.     wc.lpfnWndProc = _ResultViewWndProc;
  864.     wc.hInstance =  GLOBAL_HINSTANCE;
  865.     wc.lpszClassName = VIEW_CLASS;
  866.     RegisterClass(&wc);
  867.     _hwnd = CreateWindow(VIEW_CLASS, 
  868.                           NULL,
  869.                           WS_TABSTOP|WS_CLIPCHILDREN|WS_CHILD|WS_VISIBLE,
  870.                           0, 0, 0, 0,
  871.                           hwndParent,
  872.                           NULL,
  873.                           GLOBAL_HINSTANCE,
  874.                           this);
  875.     if ( !_hwnd )
  876.         ExitGracefully(hres, E_FAIL, "Failed to create view parent window");
  877.     // Now register the window classes we are using.
  878.     ZeroMemory(&wc, SIZEOF(wc));
  879.     wc.lpfnWndProc = _BannerWndProc;
  880.     wc.hInstance =  GLOBAL_HINSTANCE;
  881.     wc.lpszClassName = BANNER_CLASS;
  882.     RegisterClass(&wc);
  883.     if ( _dwOQWFlags & OQWF_SINGLESELECT )
  884.         dwLVStyle |= LVS_SINGLESEL;
  885.     GetClientRect(_hwnd, &rc);
  886.     _hwndView = CreateWindowEx(WS_EX_CLIENTEDGE,
  887.                                 WC_LISTVIEW,
  888.                                 NULL,
  889.                                 WS_TABSTOP|WS_CLIPCHILDREN|WS_CHILD|WS_VISIBLE|dwLVStyle,
  890.                                 0, 0, 
  891.                                 rc.right, rc.bottom,
  892.                                 _hwnd,
  893.                                 (HMENU)IDC_RESULTS,
  894.                                 GLOBAL_HINSTANCE,
  895.                                 NULL);
  896.     if ( !_hwndView )
  897.         ExitGracefully(hres, E_FAIL, "Failed to create the view window");
  898.     ListView_SetExtendedListViewStyle(_hwndView, LVS_EX_FULLROWSELECT|LVS_EX_LABELTIP);
  899.     
  900.     Shell_GetImageLists(&himlLarge, &himlSmall);
  901.     ListView_SetImageList(_hwndView, himlLarge, LVSIL_NORMAL);
  902.     ListView_SetImageList(_hwndView, himlSmall, LVSIL_SMALL);
  903.     
  904.     // Create the banner window, this is a child of the ListView, it is used to display
  905.     // information about the query being issued
  906.     _hwndBanner = CreateWindow(BANNER_CLASS, NULL,
  907.                                 WS_CHILD,
  908.                                 0, 0, 0, 0,               // nb: size fixed later
  909.                                 _hwndView,
  910.                                 (HMENU)IDC_STATUS, 
  911.                                 GLOBAL_HINSTANCE, 
  912.                                 NULL);
  913.     if ( !_hwndBanner )
  914.         ExitGracefully(hres, E_FAIL, "Failed to create the static banner window");
  915.     _SetFilter(_fFilter);
  916.     _SetViewMode(_idViewMode);
  917.     _ShowBanner(SWP_SHOWWINDOW, IDS_INITALIZING);                
  918.     hres = S_OK;                      // success
  919. exit_gracefully:
  920.     
  921.     if ( SUCCEEDED(hres) )
  922.         *phWndView = _hwnd;
  923.     TraceLeaveResult(hres);
  924. }
  925. /*---------------------------------------------------------------------------*/
  926. #define MGW_EDIT 2
  927. STDMETHODIMP CDsQuery::ActivateView(THIS_ UINT uState, WPARAM wParam, LPARAM lParam)
  928. {
  929.     HRESULT hres;
  930.     HWND hwnd;
  931.     INT i;
  932.     
  933.     TraceEnter(TRACE_HANDLER, "CDsQuery::ActivateView");
  934.     switch ( uState )
  935.     {
  936.         case CQRVA_ACTIVATE:
  937.         {
  938.             HMENU hMenu;
  939.             OLEMENUGROUPWIDTHS omgw = { 0, 0, 0, 0, 0, 0 };
  940.             // Allow the cframe to merge its menus into our menu bar before we
  941.             // add ours to it.  
  942.             if ( !(hMenu = CreateMenu()) )
  943.                 ExitGracefully(hres, E_FAIL, "Failed to create a base menu bar to be used");
  944.             hres = _pqf->InsertMenus(hMenu, &omgw);
  945.             FailGracefully(hres, "Failed when calling CQueryFrame::InsertMenus");
  946.             Shell_MergeMenus(GetSubMenu(hMenu, 0), GetSubMenu(_hFileMenu, 0), 0x0, 0x0, 0x7fff, 0);
  947.             MergeMenu(hMenu, _hEditMenu, omgw.width[0]);
  948.             MergeMenu(hMenu, _hViewMenu, omgw.width[0]+1);
  949.             MergeMenu(hMenu, _hHelpMenu, omgw.width[0]+MGW_EDIT+omgw.width[2]+omgw.width[4]);
  950.             if ( _dwOQWFlags & OQWF_SINGLESELECT )
  951.             {
  952.                 ENABLE_MENU_ITEM(hMenu, DSQH_EDIT_SELECTALL, FALSE);
  953.                 ENABLE_MENU_ITEM(hMenu, DSQH_EDIT_INVERTSELECTION, FALSE);
  954.             }
  955.             hres = _pqf->SetMenu(hMenu, NULL);                           // set the frames menu bar
  956.             FailGracefully(hres, "Failed when calling CQueryFrame::SetMenu");
  957.             break;
  958.         }
  959.         case CQRVA_INITMENUBAR:
  960.         {
  961.             // we recieve a CQRVA_INITMENUBAR before the popup so that we can store the 
  962.             // menu bar information, and invalidate an interface pointers we maybe holding
  963.             // onto.
  964.             Trace(TEXT("Received an CQRVA_INITMENUBAR, hMenu %08x"), wParam);
  965.             _hFrameMenuBar = (HMENU)wParam;
  966.             DoRelease(_pcm);
  967.             break;
  968.         }
  969.         case CQRVA_INITMENUBARPOPUP:
  970.         {
  971.             HMENU hFileMenu;
  972.             BOOL fDeleteItems = FALSE;
  973.             TraceMsg("Received an CQRVA_INITMENUBARPOPUP");
  974.             hFileMenu = GetSubMenu(_hFrameMenuBar, 0);
  975.             // if we have a view then lets try and collect the selection from it,
  976.             // having done that we can merge the verbs for that selection into the
  977.             // views "File" menu.
  978.             if ( (hFileMenu == (HMENU)wParam) && !_pcm )
  979.             {
  980.                 _fNoSelection = TRUE;             // no selection currenlty
  981.                 if ( IsWindow(_hwndView) )
  982.                 {
  983.                     for ( i = GetMenuItemCount(hFileMenu) - 1; i >= 0 ; i-- )
  984.                     {
  985. #if !DOWNLEVEL_SHELL
  986.                         if ( !fDeleteItems && (GetMenuItemID(hFileMenu, i) == DSQH_FILE_CREATESHORTCUT) )
  987. #else
  988.                         if ( !fDeleteItems && (GetMenuItemID(hFileMenu, i) == DSQH_FILE_PROPERTIES) )
  989. #endif
  990.                         {
  991.                             Trace(TEXT("Setting fDeleteItems true on index %d"), i);
  992.                             fDeleteItems = TRUE;
  993.                         }
  994.                         else
  995.                         {
  996.                             if ( fDeleteItems )
  997.                                 DeleteMenu(hFileMenu, i, MF_BYPOSITION);
  998.                         }
  999.                     }
  1000.                     // Collect the selection, and using that construct an IContextMenu interface, if that works
  1001.                     // then we can merge in the verbs that relate to this object.
  1002.                     hres = _GetIDLsAndViewObject(FALSE, IID_IContextMenu, (void **)&_pcm);    
  1003.                     FailGracefully(hres, "Failed when calling _GetIDLsAndViewObject");
  1004.                     if ( ShortFromResult(hres) > 0 )
  1005.                     {
  1006.                         _GetContextMenuVerbs(_pcm, hFileMenu, CMF_VERBSONLY);
  1007.                         _fNoSelection = FALSE;
  1008.                     }
  1009.                 }
  1010.                 ENABLE_MENU_ITEM(hFileMenu, DSQH_FILE_CREATESHORTCUT, !_fNoSelection);
  1011.                 ENABLE_MENU_ITEM(hFileMenu, DSQH_FILE_PROPERTIES,     !_fNoSelection);
  1012.             }
  1013.             ENABLE_MENU_ITEM(_hFrameMenuBar, DSQH_VIEW_PICKCOLUMNS, _hdsaColumns);
  1014.             ENABLE_MENU_ITEM(_hFrameMenuBar, DSQH_VIEW_REFRESH, _dwThreadId);
  1015.             
  1016.             _InitViewMenuItems(_hFrameMenuBar);       
  1017.             break;
  1018.         }
  1019.         case CQRVA_FORMCHANGED:
  1020.         {
  1021.             // we receieve a form change, we store the form name as we will use it
  1022.             // as the default name for saved queries authored by the user.
  1023.             Trace(TEXT("Form '%s' selected"), (LPTSTR)lParam);
  1024.             LocalFreeString(&_pDefaultSaveName);
  1025.             hres = LocalAllocString(&_pDefaultSaveName, (LPCTSTR)lParam);
  1026.             FailGracefully(hres, "Failed to set the default save name");
  1027.             break;
  1028.         }
  1029.         case CQRVA_STARTQUERY:
  1030.         {
  1031.             Trace(TEXT("Query is: %s"), wParam ? TEXT("starting"):TEXT("stopping"));
  1032.             break;
  1033.         }
  1034.         case CQRVA_HELP:
  1035.         {
  1036.             LPHELPINFO pHelpInfo = (LPHELPINFO)lParam;
  1037.             TraceAssert(pHelpInfo)
  1038.             TraceMsg("Invoking help on the objects in the windows");                
  1039.             WinHelp((HWND)pHelpInfo->hItemHandle, DSQUERY_HELPFILE, HELP_WM_HELP, (DWORD_PTR)aHelpIDs);
  1040.             break;
  1041.         }
  1042.         case CQRVA_CONTEXTMENU:
  1043.         {
  1044.             HWND hwndForHelp = (HWND)wParam;
  1045.             Trace(TEXT("CQRVA_CONTEXTMENU recieved on the bg of the frame %d"), GetDlgCtrlID(hwndForHelp));
  1046.             WinHelp(hwndForHelp, DSQUERY_HELPFILE, HELP_CONTEXTMENU, (DWORD_PTR)aHelpIDs);
  1047.             break;
  1048.         }
  1049.     }
  1050.     
  1051.     hres = S_OK;
  1052. exit_gracefully:
  1053.     TraceLeaveResult(hres);
  1054. }
  1055. /*---------------------------------------------------------------------------*/
  1056. STDMETHODIMP CDsQuery::InvokeCommand(THIS_ HWND hwndParent, UINT uID)
  1057. {
  1058.     HRESULT hres;
  1059.     HWND hwndFrame;
  1060.     DECLAREWAITCURSOR;
  1061.     TraceEnter(TRACE_HANDLER, "CDsQuery::InvokeCommand");
  1062.     Trace(TEXT("hwndParent %08x, uID %d"), hwndParent, uID);
  1063.     SetWaitCursor();
  1064.     switch ( uID )
  1065.     {
  1066.         case DSQH_BG_SELECT:
  1067.             SendMessage(hwndParent, WM_COMMAND, IDOK, 0);
  1068.             break;
  1069.         case DSQH_FILE_PROPERTIES:
  1070.             hres = OnFileProperties();
  1071.             break;
  1072. #if !DOWNLEVEL_SHELL
  1073.         case DSQH_FILE_CREATESHORTCUT:
  1074.             hres = OnFileCreateShortcut();
  1075.             break;
  1076. #endif
  1077.         case DSQH_FILE_SAVEQUERY:
  1078.             hres = OnFileSaveQuery();
  1079.             break;
  1080.         case DSQH_EDIT_SELECTALL:
  1081.             hres = OnEditSelectAll();
  1082.             break;
  1083.         case DSQH_EDIT_INVERTSELECTION:
  1084.             hres = OnEditInvertSelection();
  1085.             break;
  1086.         case DSQH_VIEW_FILTER:
  1087.             _SetFilter(!_fFilter);
  1088.             break;
  1089.         case DSQH_VIEW_LARGEICONS:
  1090.         case DSQH_VIEW_SMALLICONS:
  1091.         case DSQH_VIEW_LIST:
  1092.         case DSQH_VIEW_DETAILS:
  1093.             _SetViewMode(uID);
  1094.             break;
  1095.         
  1096.         case DSQH_VIEW_REFRESH:
  1097.         {
  1098.             if ( IsWindow(_hwndView) && _dwThreadId )
  1099.             {
  1100.                 _InitNewQuery(NULL, FALSE);
  1101.                 PostThreadMessage(_dwThreadId, RVTM_REFRESH, _dwQueryReference, 0L);
  1102.             }
  1103.             break;
  1104.         }
  1105.         case DSQH_VIEW_PICKCOLUMNS:
  1106.         {
  1107.             TraceAssert(_hdsaColumns);
  1108.             OnPickColumns(hwndParent);
  1109.             break;
  1110.         }
  1111.         case DSQH_HELP_CONTENTS:
  1112.         {
  1113.             TraceMsg("Calling for to display help topics");
  1114.             _pqf->GetWindow(&hwndFrame);
  1115.             _pqf->CallForm(NULL, DSQPM_HELPTOPICS, 0, (LPARAM)hwndFrame);
  1116. break;
  1117.         }
  1118.         case DSQH_HELP_WHATISTHIS:
  1119.             _pqf->GetWindow(&hwndFrame);
  1120.             SendMessage(hwndFrame, WM_SYSCOMMAND, SC_CONTEXTHELP, MAKELPARAM(0,0)); 
  1121.             break;
  1122.             
  1123.         default:
  1124.         {
  1125.             // if it looks like a sort request then lets handle it, otherwise attempt
  1126.             // to send to the context menu handler we may have at htis poiunt.
  1127.             if ( (uID >= DSQH_VIEW_ARRANGEFIRST) && (uID < DSQH_VIEW_ARRANGELAST) )
  1128.             {
  1129.                 TraceAssert(_hdsaColumns);
  1130.                 if ( _hdsaColumns )
  1131.                 {
  1132.                     Trace(TEXT("Calling _SortResults for column %d"), uID - DSQH_VIEW_ARRANGEFIRST);
  1133.                     _SortResults(uID - DSQH_VIEW_ARRANGEFIRST);
  1134.                 }
  1135.             }
  1136.             else if ( _pcm )
  1137.             {       
  1138.                 CMINVOKECOMMANDINFO ici;
  1139.                 ici.cbSize = SIZEOF(ici);
  1140.                 ici.fMask = 0;
  1141.                 _pqf->GetWindow(&ici.hwnd);
  1142.                 ici.lpVerb = (LPCSTR)(uID - DSQH_FILE_CONTEXT_FIRST);
  1143.                 ici.lpParameters = NULL;
  1144.                 ici.lpDirectory = NULL;
  1145.                 ici.nShow = SW_NORMAL;
  1146.                 ici.dwHotKey = 0;
  1147.                 ici.hIcon = NULL;
  1148.                 hres = _pcm->InvokeCommand(&ici);
  1149.                 FailGracefully(hres, "Failed when calling IContextMenu::InvokeCommand");
  1150.                 DoRelease(_pcm);                  // no longer needed
  1151.             }
  1152.             break;
  1153.         }
  1154.     }
  1155. exit_gracefully:
  1156.     ResetWaitCursor();
  1157.     TraceLeaveResult(hres);
  1158. }
  1159. /*---------------------------------------------------------------------------*/
  1160. STDMETHODIMP CDsQuery::GetCommandString(THIS_ UINT uID, DWORD dwFlags, LPTSTR pBuffer, INT cchBuffer)
  1161. {
  1162.     HRESULT hres;
  1163.     TCHAR szBuffer[MAX_PATH];
  1164.     TraceEnter(TRACE_HANDLER, "CDsQuery::GetCommandString");
  1165.     Trace(TEXT("uID %08x, dwFlags %08x, pBuffer %08x, cchBuffer %d"), uID, dwFlags, pBuffer, cchBuffer);
  1166.     if ( (uID >= DSQH_FILE_CONTEXT_FIRST) && (uID < DSQH_FILE_CONTEXT_LAST) )
  1167.     {
  1168.         if ( _pcm )
  1169.         {
  1170.             TraceMsg("Trying the IContextMenu::GetCommandString");
  1171.             hres = _pcm->GetCommandString((uID - DSQH_FILE_CONTEXT_FIRST), GCS_HELPTEXT, NULL, (LPSTR)pBuffer, cchBuffer);
  1172. #if UNICODE
  1173.             // we build UNICODE, therefore if we failed then try and pick up the ANSI string from
  1174.             // the handler, if that works then we convert the multi-byte string to UNICODE 
  1175.             // and hand that back to the caller.
  1176.             if ( FAILED(hres) )
  1177.             {
  1178.                 CHAR szBuffer[MAX_PATH];
  1179.                 
  1180.                 hres = _pcm->GetCommandString((uID - DSQH_FILE_CONTEXT_FIRST), GCS_HELPTEXTA, NULL, szBuffer, ARRAYSIZE(szBuffer));
  1181.                 if ( SUCCEEDED(hres) )
  1182.                 {
  1183.                     TraceMsg("Handler provided an ANSI string");
  1184.                     MultiByteToWideChar(CP_ACP, 0, szBuffer, -1, pBuffer, cchBuffer);
  1185.                 }
  1186.             }
  1187. #endif
  1188.             FailGracefully(hres, "Failed when asking for help text from IContextMenu iface");
  1189.         }
  1190.     }
  1191.     else
  1192.     {
  1193.         if ( (uID >= DSQH_VIEW_ARRANGEFIRST) && (uID < DSQH_VIEW_ARRANGELAST) )
  1194.         {
  1195.             INT iColumn = uID-DSQH_VIEW_ARRANGEFIRST;
  1196.             TCHAR szFmt[MAX_PATH];
  1197.             Trace(TEXT("Get command text for column %d"), iColumn);
  1198.             if ( _hdsaColumns && (iColumn < DSA_GetItemCount(_hdsaColumns)) )
  1199.             {
  1200.                 LPCOLUMN pColumn = (LPCOLUMN)DSA_GetItemPtr(_hdsaColumns, iColumn);
  1201.                 TraceAssert(pColumn);
  1202.                 LoadString(GLOBAL_HINSTANCE, IDS_ARRANGEBY_HELP, szFmt, ARRAYSIZE(szFmt));
  1203.                 wsprintf(pBuffer, szFmt, pColumn->pHeading);
  1204.                 Trace(TEXT("Resulting string is: %s"), pBuffer);
  1205.             }
  1206.         }
  1207.         else
  1208.         {
  1209.             if ( !LoadString(GLOBAL_HINSTANCE, uID, pBuffer, cchBuffer) )
  1210.                 ExitGracefully(hres, E_FAIL, "Failed to load the command text for this verb");
  1211.         }
  1212.     }
  1213.     hres = S_OK;
  1214. exit_gracefully:
  1215.     TraceLeaveResult(hres);
  1216. }
  1217. /*---------------------------------------------------------------------------*/
  1218. STDMETHODIMP CDsQuery::IssueQuery(THIS_ LPCQPARAMS pQueryParams)
  1219. {
  1220.     HRESULT hres;
  1221.     LPTHREADINITDATA ptid = NULL;
  1222.     LPDSQUERYSCOPE pDsQueryScope = (LPDSQUERYSCOPE)pQueryParams->pQueryScope;
  1223.     LPDSQUERYPARAMS pDsQueryParams = (LPDSQUERYPARAMS)pQueryParams->pQueryParameters;
  1224.     LPTSTR pBuffer = NULL;
  1225.     MSG msg;
  1226.     TraceEnter(TRACE_HANDLER, "CDsQuery::IssueQuery");
  1227.     Trace(TEXT("pQueryParams %08x, pDsQueryScope %08x, pDsQueryParams %08x"), pQueryParams, pDsQueryScope, pDsQueryParams);    
  1228.     // Persist the existing column information if there was some, then 
  1229.     // get the new column table initialized and the columns added to the
  1230.     // view
  1231.     if ( _hdsaColumns )
  1232.     {
  1233.         if ( _fColumnsModified )
  1234.         {
  1235.             _SaveColumnTable(_clsidForm, _hdsaColumns);
  1236.             _fColumnsModified = FALSE;
  1237.         }
  1238.         _SaveColumnTable();       
  1239.     }
  1240.     // Initialize the view with items
  1241.     
  1242.     _clsidForm = pQueryParams->clsidForm;          // keep the form ID (for persistance)
  1243.     hres = _InitNewQuery(pDsQueryParams, TRUE);
  1244.     FailGracefully(hres, "Failed to initialize the new query");
  1245.     // Now build the thread information needed to get the thread
  1246.     // up and running.
  1247.     ptid = (LPTHREADINITDATA)LocalAlloc(LPTR, SIZEOF(THREADINITDATA));
  1248.     TraceAssert(ptid);
  1249.     if ( !ptid )
  1250.         ExitGracefully(hres, E_OUTOFMEMORY, "Failed to allocate THREADINITDATA");
  1251.     ptid->dwReference = _dwQueryReference;
  1252.     //ptid->hwndView = NULL;
  1253.     //ptid->pQuery = NULL;
  1254.     //ptid->pScope = NULL;
  1255.     //ptid->hdsaColumns = NULL;
  1256.     //ptid->fShowHidden = FALSE;
  1257.     //ptid->pServer = NULL;
  1258.     //ptid->pUserName = NULL;
  1259.     //ptid->pPassword = NULL;
  1260.     Trace(TEXT("_dwFlags %08x (& DSQPF_SHOWHIDDENOBJECTS)"), _dwFlags, _dwFlags & DSQPF_SHOWHIDDENOBJECTS);
  1261.     ptid->fShowHidden = (_dwFlags & DSQPF_SHOWHIDDENOBJECTS) ? 1:0;
  1262.     ptid->hwndView = _hwndView;
  1263.     hres = _GetColumnTable(_clsidForm, pDsQueryParams, &ptid->hdsaColumns, FALSE);
  1264.     FailGracefully(hres, "Failed to create column DSA");
  1265.     hres = LocalAllocStringW(&ptid->pQuery, (LPWSTR)ByteOffset(pDsQueryParams, pDsQueryParams->offsetQuery));
  1266.     FailGracefully(hres, "Failed to copy query filter string");
  1267.     hres = LocalAllocStringW(&ptid->pScope, OBJECT_NAME_FROM_SCOPE(pDsQueryScope));
  1268.     FailGracefully(hres, "Failed to copy scope to thread init data");
  1269.     hres = _CopyCredentials(&ptid->pUserName, &ptid->pPassword, &ptid->pServer);
  1270.     FailGracefully(hres, "Failed to copy credentails");
  1271.     // now create the thread that is going to perform the query, this includes
  1272.     // telling the previous one that it needs to close down
  1273.     if ( _hThread && _dwThreadId )
  1274.     {
  1275.         Trace(TEXT("Killing old query thread %08x, ID %d"), _hThread, _dwThreadId);
  1276.         PostThreadMessage(_dwThreadId, RVTM_STOPQUERY, 0, 0);
  1277.         PostThreadMessage(_dwThreadId, WM_QUIT, 0, 0);
  1278.         CloseHandle(_hThread);
  1279.         _hThread = NULL;
  1280.         _dwThreadId = 0;
  1281.     }
  1282.     InterlockedIncrement(&GLOBAL_REFCOUNT);
  1283.     _hThread = CreateThread(NULL, 0, QueryThread, ptid, 0, &_dwThreadId);
  1284.     TraceAssert(_hThread);
  1285.     if ( !_hThread )
  1286.     {
  1287.         InterlockedDecrement(&GLOBAL_REFCOUNT);
  1288.         ExitGracefully(hres, E_FAIL, "Failed to create background thread - BAD!");
  1289.     }
  1290.     hres = S_OK;                      // success
  1291. exit_gracefully:
  1292.     if ( SUCCEEDED(hres) && IsWindow(_hwndView) )
  1293.         SetFocus(_hwndView);
  1294.     if ( FAILED(hres) )
  1295.     {
  1296.         QueryThread_FreeThreadInitData(&ptid);
  1297.         _pqf->StartQuery(FALSE);
  1298.     }
  1299.     TraceLeaveResult(hres);
  1300. }
  1301. /*---------------------------------------------------------------------------*/
  1302. STDMETHODIMP CDsQuery::StopQuery(THIS)
  1303. {
  1304.     HRESULT hres;
  1305.     INT cResults = _hdpaResults ? DPA_GetPtrCount(_hdpaResults):0;
  1306.     LPTSTR pBuffer;
  1307.     TraceEnter(TRACE_HANDLER, "CDsQuery::StopQuery");
  1308.     if ( !IsWindow(_hwndView) )
  1309.         ExitGracefully(hres, E_FAIL, "View not initalized yet");
  1310.     // we are stopping the query, we are going to tidy up the UI now
  1311.     // and we just want the thread to closedown cleanly, therefore lets
  1312.     // do so, increasing our query reference
  1313.     _pqf->StartQuery(FALSE);
  1314.     _dwQueryReference++;
  1315.     _PopulateView(-1, -1);                // update status bar etc
  1316.     if ( _dwThreadId )
  1317.         PostThreadMessage(_dwThreadId, RVTM_STOPQUERY, 0, 0);
  1318.     hres = S_OK;              // success
  1319. exit_gracefully:
  1320.     TraceLeaveResult(hres);
  1321. }
  1322. /*---------------------------------------------------------------------------*/
  1323. HRESULT _SetDataObjectData(IDataObject* pDataObject, UINT cf, LPVOID pData, DWORD cbSize)
  1324. {
  1325.     HRESULT hres;
  1326.     FORMATETC fmte = {(CLIPFORMAT)cf, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  1327.     STGMEDIUM medium = { TYMED_NULL, NULL, NULL };
  1328.     LPVOID pAlloc;
  1329.     TraceEnter(TRACE_HANDLER, "_SetDataObjectData");
  1330.     hres = AllocStorageMedium(&fmte, &medium, cbSize, &pAlloc);
  1331.     FailGracefully(hres, "Failed to allocate STGMEDIUM for data");
  1332.     CopyMemory(pAlloc, pData, cbSize);
  1333.     hres = pDataObject->SetData(&fmte, &medium, TRUE);
  1334.     FailGracefully(hres, "Failed to pass the data to the IDataObject");
  1335.     hres = S_OK;
  1336. exit_gracefully:
  1337.     ReleaseStgMedium(&medium);
  1338.     TraceLeaveResult(hres);
  1339. }
  1340. STDMETHODIMP CDsQuery::GetViewObject(THIS_ UINT uScope, REFIID riid, void **ppvOut)
  1341. {
  1342.     HRESULT hres;
  1343.     IDataObject* pDataObject = NULL;
  1344.     LPDSQUERYPARAMS pDsQueryParams = NULL;
  1345.     LPDSQUERYSCOPE pDsQueryScope = NULL;
  1346.     UINT cfDsQueryParams = RegisterClipboardFormat(CFSTR_DSQUERYPARAMS);
  1347.     UINT cfDsQueryScope = RegisterClipboardFormat(CFSTR_DSQUERYSCOPE);
  1348.     BOOL fJustSelection = !(_dwFlags & DSQPF_RETURNALLRESULTS);
  1349.     TraceEnter(TRACE_HANDLER, "CDsQuery::GetViewObject");
  1350.     // We only support returning the selection as an IDataObject
  1351.     DECLAREWAITCURSOR;
  1352.     SetWaitCursor();
  1353.     if ( !ppvOut && ((uScope & CQRVS_MASK) != CQRVS_SELECTION) )
  1354.         ExitGracefully(hres, E_INVALIDARG, "Bad arguments to GetViewObject");
  1355.     if ( !IsEqualIID(riid, IID_IDataObject) )
  1356.         ExitGracefully(hres, E_NOINTERFACE, "Object IID supported");
  1357.     //
  1358.     // write the extra data we have into the IDataObject:
  1359.     //
  1360.     //  - query parameters (filter)
  1361.     //  - scope
  1362.     //  - attribute prefix information
  1363.     //
  1364.     hres = _GetIDLsAndViewObject(fJustSelection, IID_IDataObject, (void **)&pDataObject);
  1365.     FailGracefully(hres, "Failed to get the IDataObject from the namespace");
  1366.     if ( SUCCEEDED(_pqf->CallForm(NULL, CQPM_GETPARAMETERS, 0, (LPARAM)&pDsQueryParams)) )
  1367.     {
  1368.         if ( pDsQueryParams )
  1369.         {
  1370.             hres = _SetDataObjectData(pDataObject, cfDsQueryParams, pDsQueryParams, pDsQueryParams->cbStruct);
  1371.             FailGracefully(hres, "Failed set the DSQUERYPARAMS into the data object");
  1372.         }
  1373.     }
  1374.     if ( SUCCEEDED(_pqf->GetScope((LPCQSCOPE*)&pDsQueryScope)) )
  1375.     {
  1376.         if ( pDsQueryScope )
  1377.         {
  1378.             LPWSTR pScope = OBJECT_NAME_FROM_SCOPE(pDsQueryScope);
  1379.             TraceAssert(pScope);
  1380.             hres = _SetDataObjectData(pDataObject, cfDsQueryScope, pScope, StringByteSizeW(pScope));
  1381.             FailGracefully(hres, "Failed set the DSQUERYSCOPE into the data object");
  1382.         }
  1383.     }
  1384.     // success, so lets pass out the IDataObject.
  1385.     pDataObject->AddRef();
  1386.     *ppvOut = (LPVOID)pDataObject;
  1387.     hres = S_OK;
  1388. exit_gracefully:
  1389.     DoRelease(pDataObject);
  1390.     
  1391.     if ( pDsQueryParams )
  1392.         CoTaskMemFree(pDsQueryParams);
  1393.     if ( pDsQueryScope )
  1394.         CoTaskMemFree(pDsQueryScope);
  1395.     ResetWaitCursor();
  1396.     TraceLeaveResult(hres);
  1397. }   
  1398. /*---------------------------------------------------------------------------*/
  1399. STDMETHODIMP CDsQuery::LoadQuery(THIS_ IPersistQuery* pPersistQuery)
  1400. {
  1401.     HRESULT hres;
  1402.     WCHAR szBuffer[MAX_PATH];
  1403.     IADs *pDsObject = NULL;
  1404.     BSTR bstrObjectClass = NULL;
  1405.     INT iFilter;
  1406.     LPCQSCOPE pScope = NULL;
  1407.     INT cbScope;
  1408.     USES_CONVERSION;
  1409.     TraceEnter(TRACE_HANDLER, "CDsQuery::LoadQuery");
  1410.     
  1411.     if ( !pPersistQuery )
  1412.         ExitGracefully(hres, E_INVALIDARG, "No IPersistQuery object");
  1413.     if ( SUCCEEDED(pPersistQuery->ReadInt(c_szDsQuery, c_szScopeSize, &cbScope)) &&
  1414.          (cbScope < SIZEOF(szBuffer)) &&
  1415.          SUCCEEDED(pPersistQuery->ReadStruct(c_szDsQuery, c_szScope, szBuffer, cbScope)) )
  1416.     {
  1417.         Trace(TEXT("Selected scope from file is %s"), W2T(szBuffer));
  1418.         // get the object class from the file - this should be written to the file
  1419.         hres = ADsOpenObject(szBuffer, _pUserName, _pPassword, ADS_SECURE_AUTHENTICATION, IID_IADs, (void **)&pDsObject);
  1420.         FailGracefully(hres, "Failed to bind to the specified object");
  1421.         hres = pDsObject->get_Class(&bstrObjectClass);
  1422.         FailGracefully(hres, "Failed to get the object class");
  1423.         // allocate a new scope
  1424.         if ( SUCCEEDED(AllocScope(&pScope, 0, szBuffer, bstrObjectClass)) )
  1425.         {
  1426.             hres = _pqf->AddScope(pScope, 0x0, TRUE);
  1427.             FailGracefully(hres, "Failed to add scope to list");
  1428.         }
  1429.     }
  1430.     // Read the remainder of the view state
  1431.     if ( SUCCEEDED(pPersistQuery->ReadInt(c_szDsQuery, c_szViewMode, &_idViewMode)) )
  1432.     {
  1433.         Trace(TEXT("View mode is: %0x8"), _idViewMode);
  1434.         _SetViewMode(_idViewMode);
  1435.     }
  1436.     if ( SUCCEEDED(pPersistQuery->ReadInt(c_szDsQuery, c_szEnableFilter, &iFilter)) )
  1437.     {
  1438.         Trace(TEXT("Filter mode set to %d"), _fFilter);
  1439.         _SetFilter(iFilter);
  1440.     }
  1441.     hres = S_OK;
  1442. exit_gracefully:
  1443.     if ( pScope )
  1444.         CoTaskMemFree(pScope);
  1445.     DoRelease(pDsObject);
  1446.     SysFreeString(bstrObjectClass);
  1447.     TraceLeaveResult(hres);
  1448. }
  1449. /*---------------------------------------------------------------------------*/
  1450. STDMETHODIMP CDsQuery::SaveQuery(THIS_ IPersistQuery* pPersistQuery, LPCQSCOPE pScope)
  1451. {
  1452.     HRESULT hres;
  1453.     LPDSQUERYSCOPE pDsQueryScope = (LPDSQUERYSCOPE)pScope;
  1454.     LPWSTR pScopePath = OBJECT_NAME_FROM_SCOPE(pDsQueryScope);
  1455.     WCHAR szGcPath[MAX_PATH];
  1456.     
  1457.     TraceEnter(TRACE_HANDLER, "CDsQuery::SaveQuery");
  1458.     if ( !pPersistQuery || !pScope )
  1459.         ExitGracefully(hres, E_INVALIDARG, "No IPersistQuery/pScope object");
  1460.     if ( SUCCEEDED(GetGlobalCatalogPath(_pServer, szGcPath, ARRAYSIZE(szGcPath))) && StrCmpW(pScopePath, szGcPath) ) 
  1461.     {
  1462.         // if this is not the GC then persist
  1463.         TraceMsg("GC path differs from scope, so persisting");
  1464.         hres = pPersistQuery->WriteInt(c_szDsQuery, c_szScopeSize, StringByteSizeW(pScopePath));
  1465.         FailGracefully(hres, "Failed to write the scope size");
  1466.         hres = pPersistQuery->WriteStruct(c_szDsQuery, c_szScope, pScopePath, StringByteSizeW(pScopePath));
  1467.         FailGracefully(hres, "Failed to write scope");
  1468.     }
  1469.     hres = pPersistQuery->WriteInt(c_szDsQuery, c_szViewMode, _idViewMode);
  1470.     FailGracefully(hres, "Failed to write view mode");
  1471.     hres = pPersistQuery->WriteInt(c_szDsQuery, c_szEnableFilter, _fFilter);
  1472.     FailGracefully(hres, "Failed to write filter state");
  1473.     hres = S_OK;
  1474. exit_gracefully:
  1475.     TraceLeaveResult(hres);
  1476. }
  1477. /*----------------------------------------------------------------------------
  1478. / IObjectWithSite
  1479. /----------------------------------------------------------------------------*/
  1480. STDMETHODIMP CDsQuery::SetSite(IUnknown* punk)
  1481. {
  1482.     HRESULT hres = S_OK;
  1483.     TraceEnter(TRACE_HANDLER, "CDsQuery::SetSite");
  1484.     DoRelease(_punkSite);
  1485.     if ( punk )
  1486.     {
  1487.         TraceMsg("QIing for IUnknown from the site object");
  1488.         hres = punk->QueryInterface(IID_IUnknown, (void **)&_punkSite);
  1489.         FailGracefully(hres, "Failed to get IUnknown from the site object");
  1490.     }
  1491. exit_gracefully:
  1492.     TraceLeaveResult(hres);
  1493. }
  1494. /*---------------------------------------------------------------------------*/
  1495. STDMETHODIMP CDsQuery::GetSite(REFIID riid, void **ppv)
  1496. {
  1497.     HRESULT hres;
  1498.     
  1499.     TraceEnter(TRACE_HANDLER, "CDsQuery::GetSite");
  1500.     if ( !_punkSite )
  1501.         ExitGracefully(hres, E_NOINTERFACE, "No site to QI from");
  1502.     hres = _punkSite->QueryInterface(riid, ppv);
  1503.     FailGracefully(hres, "QI failed on the site unknown object");
  1504. exit_gracefully:
  1505.     TraceLeaveResult(hres);
  1506. }
  1507. /*----------------------------------------------------------------------------
  1508. / IDsQueryHandler
  1509. /----------------------------------------------------------------------------*/
  1510. VOID CDsQuery::_DeleteViewItems(LPDSOBJECTNAMES pdon)
  1511. {
  1512.     INT iResult;
  1513.     DWORD iItem;
  1514.     USES_CONVERSION;
  1515.     TraceEnter(TRACE_HANDLER, "CDsQuery::_DeleteObjectNames");
  1516.     if ( pdon->cItems )
  1517.     {
  1518.         // walk through all the items in the view deleting as required.
  1519.         for ( iItem = 0 ; iItem != pdon->cItems ; iItem++ )
  1520.         {
  1521.             // do we have an item to delete?
  1522.             if ( pdon->aObjects[iItem].offsetName )
  1523.             {
  1524.                 LPCWSTR pwszName = (LPCWSTR)ByteOffset(pdon, pdon->aObjects[iItem].offsetName);
  1525.                 Trace(TEXT("pwszName to delete: %s"), W2CT(pwszName));
  1526.                 // walk all the results in the view deleting them as we go.
  1527.                 for ( iResult = 0 ; iResult < DPA_GetPtrCount(_hdpaResults); iResult++ )
  1528.                 {
  1529.                     LPQUERYRESULT pResult = (LPQUERYRESULT)DPA_GetPtr(_hdpaResults, iResult);
  1530.                     TraceAssert(pResult);
  1531.                     // if we match the item we want to delete then remove it, if the view
  1532.                     // is not filtered then remove ite from the list, otherwise leave the 
  1533.                     // view update until we have finished deleting
  1534.                     if ( !StrCmpW(pwszName, pResult->pPath) )
  1535.                     {
  1536.                         Trace(TEXT("Item maps to result %d in the list"), iResult);
  1537.                         
  1538.                         FreeQueryResult(pResult, DSA_GetItemCount(_hdsaColumns));
  1539.                         DPA_DeletePtr(_hdpaResults, iResult); 
  1540.                         
  1541.                         if ( !_fFilter )
  1542.                         {
  1543.                             TraceMsg("Deleting the item from the view");
  1544.                             ListView_DeleteItem(_hwndView, iResult);
  1545.                         }
  1546.                     }
  1547.                 }
  1548.             }
  1549.         }
  1550.         // the view was filtered, so lets repopulate with the items
  1551.         if ( _fFilter )
  1552.         {
  1553.             TraceMsg("View is filter, therefore just forcing a refresh");
  1554.             _FilterView(FALSE);    
  1555.         }
  1556.     }        
  1557.     TraceLeave();
  1558. }
  1559. STDMETHODIMP CDsQuery::UpdateView(DWORD dwType, LPDSOBJECTNAMES pdon)
  1560. {
  1561.     HRESULT hres;
  1562.     TraceEnter(TRACE_HANDLER, "CDsQuery::UpdateView");
  1563.     switch ( dwType & DSQRVF_OPMASK )
  1564.     {
  1565.         case DSQRVF_ITEMSDELETED:
  1566.         {
  1567.             if ( !pdon )
  1568.                 ExitGracefully(hres, E_INVALIDARG, "Invlaidate pdon specified for refresh");
  1569.             _DeleteViewItems(pdon);
  1570.             break;
  1571.         }
  1572.         default:
  1573.             ExitGracefully(hres, E_INVALIDARG, "Invalidate refresh type speciifed");
  1574.     }
  1575.     hres = S_OK;
  1576. exit_gracefully:
  1577.     TraceLeaveResult(hres);
  1578. }
  1579. /*-----------------------------------------------------------------------------
  1580. / Message/Command Handlers
  1581. /----------------------------------------------------------------------------*/
  1582. /*-----------------------------------------------------------------------------
  1583. / CDsQuery::OnSize
  1584. / ----------------
  1585. /   Result viewer is being sized, so ensure that our children have their
  1586. /   sizes correctly addjusted.
  1587. /
  1588. / In:
  1589. /   cx, cy = new size of the parent window
  1590. /
  1591. / Out:
  1592. /   -
  1593. /----------------------------------------------------------------------------*/
  1594. LRESULT CDsQuery::OnSize(INT cx, INT cy)
  1595. {
  1596.     TraceEnter(TRACE_VIEW, "CDsQuery::OnSize");
  1597.     SetWindowPos(_hwndView, NULL, 0, 0, cx, cy, SWP_NOZORDER|SWP_NOMOVE);
  1598.     _ShowBanner(0, 0);
  1599.     TraceLeaveValue(0);
  1600. }
  1601. /*-----------------------------------------------------------------------------
  1602. / CDsQuery::OnNotify
  1603. / ------------------
  1604. /   Notify message being recieved by the view, so try and handle it as best
  1605. /   we can.
  1606. /
  1607. / In:
  1608. /   hWnd = window handle of the notify
  1609. /   wParam, lParam = parameters for the notify event
  1610. /
  1611. / Out:
  1612. /   LRESULT
  1613. /----------------------------------------------------------------------------*/
  1614. LRESULT CDsQuery::OnNotify(HWND hWnd, WPARAM wParam, LPARAM lParam)
  1615. {
  1616.     HRESULT hres;
  1617.     LRESULT lr = 0;
  1618.     DECLAREWAITCURSOR = GetCursor();
  1619.     USES_CONVERSION;
  1620.     TraceEnter(TRACE_VIEW, "CDsQuery::OnNotify");
  1621.     switch ( ((LPNMHDR)lParam)->code )
  1622.     {
  1623.         case HDN_FILTERCHANGE:
  1624.             _FilterView(TRUE);
  1625.             break;
  1626.         case HDN_FILTERBTNCLICK:
  1627.         {
  1628.             NMHDFILTERBTNCLICK* pNotify = (NMHDFILTERBTNCLICK*)lParam;
  1629.             HMENU hMenu;
  1630.             POINT pt;
  1631.             HD_ITEM hdi;
  1632.             UINT uID;
  1633.             
  1634.             if ( _hdsaColumns && (pNotify->iItem < DSA_GetItemCount(_hdsaColumns)) )
  1635.             {
  1636.                 LPCOLUMN pColumn = (LPCOLUMN)DSA_GetItemPtr(_hdsaColumns, pNotify->iItem);
  1637.                 TraceAssert(pColumn);                   
  1638.                 hMenu = LoadMenu(GLOBAL_HINSTANCE, property_type_table[pColumn->iPropertyType].pMenuName);
  1639.                 TraceAssert(hMenu);
  1640.                 if ( hMenu )
  1641.                 {
  1642.                     pt.x = pNotify->rc.right;
  1643.                     pt.y = pNotify->rc.bottom;
  1644.                     MapWindowPoints(pNotify->hdr.hwndFrom, NULL, &pt, 1);
  1645.                     CheckMenuRadioItem(GetSubMenu(hMenu, 0), 
  1646.                                        FILTER_FIRST, FILTER_LAST, pColumn->idOperator, 
  1647.                                        MF_BYCOMMAND);
  1648.                     uID = TrackPopupMenu(GetSubMenu(hMenu, 0),
  1649.                                          TPM_RIGHTALIGN|TPM_RETURNCMD,  
  1650.                                          pt.x, pt.y,
  1651.                                          0, pNotify->hdr.hwndFrom, NULL);                  
  1652.                     switch ( uID )
  1653.                     {
  1654.                         case DSQH_CLEARFILTER:
  1655.                             Header_ClearFilter(ListView_GetHeader(_hwndView), pNotify->iItem);
  1656.                             break;
  1657.                         case DSQH_CLEARALLFILTERS:
  1658.                             Header_ClearAllFilters(ListView_GetHeader(_hwndView));
  1659.                             break;
  1660.                         
  1661.                         default:
  1662.                         {
  1663.                             if ( uID && (uID != pColumn->idOperator) )
  1664.                             {
  1665.                                 // update the filter string based on the new operator
  1666.                                 pColumn->idOperator = uID;              
  1667.                                 _GetFilterValue(pNotify->iItem, NULL);
  1668.                                 lr = TRUE;
  1669.                             }
  1670.                             break;
  1671.                         }
  1672.                     }
  1673.                     DestroyMenu(hMenu);
  1674.                 }       
  1675.             }
  1676.             break;
  1677.         }
  1678.         case HDN_ITEMCHANGED:
  1679.         {
  1680.             HD_NOTIFY* pNotify = (HD_NOTIFY*)lParam;
  1681.             HD_ITEM* pitem = (HD_ITEM*)pNotify->pitem;
  1682.         
  1683.             if ( _hdsaColumns && (pNotify->iItem < DSA_GetItemCount(_hdsaColumns)) )
  1684.             {
  1685.                 LPCOLUMN pColumn = (LPCOLUMN)DSA_GetItemPtr(_hdsaColumns, pNotify->iItem);
  1686.                 TraceAssert(pColumn);
  1687.                 // store the new column width information in the column structure and
  1688.                 // mark the column table as dirty
  1689.                 if ( pitem->mask & HDI_WIDTH )
  1690.                 {
  1691.                    Trace(TEXT("Column %d, cx %d (marking state as dirty)"), pNotify->iItem, pitem->cxy);
  1692.                     pColumn->cx = pitem->cxy;
  1693.                     _fColumnsModified = TRUE;
  1694.                 }
  1695.             
  1696.                 if ( pitem->mask & HDI_FILTER )
  1697.                 {
  1698.                     Trace(TEXT("Filter for column %d has been changed"), pNotify->iItem);
  1699.                     _GetFilterValue(pNotify->iItem, pitem);
  1700.                 }
  1701.             }
  1702.             break;
  1703.         }
  1704.         case LVN_GETDISPINFO:
  1705.         {
  1706.             LV_DISPINFO* pNotify = (LV_DISPINFO*)lParam;
  1707.             TraceAssert(pNotify);
  1708.             if ( pNotify && (pNotify->item.mask & LVIF_TEXT) && pNotify->item.lParam )
  1709.             {
  1710.                 LPQUERYRESULT pResult = (LPQUERYRESULT)pNotify->item.lParam;
  1711.                 INT iColumn = pNotify->item.iSubItem;
  1712.                 pNotify->item.pszText[0] = TEXT('');          // nothing to display yet
  1713.                 switch ( pResult->aColumn[iColumn].iPropertyType )
  1714.                 {
  1715.                     case PROPERTY_ISUNDEFINED:
  1716.                         break;
  1717.                     case PROPERTY_ISUNKNOWN:
  1718.                     case PROPERTY_ISSTRING:
  1719.                     {
  1720.                         if ( pResult->aColumn[iColumn].pszText )
  1721.                             StrCpyN(pNotify->item.pszText, pResult->aColumn[iColumn].pszText, pNotify->item.cchTextMax);
  1722.                         break;
  1723.                     }
  1724.                         
  1725.                     case PROPERTY_ISNUMBER:
  1726.                     case PROPERTY_ISBOOL:
  1727.                         wsprintf(pNotify->item.pszText, TEXT("%d"), pResult->aColumn[iColumn].iValue);
  1728.                         break;
  1729.                 }
  1730.                 lr = TRUE;          // we formatted a value
  1731.             }
  1732.             break;
  1733.         }
  1734.         case LVN_ITEMACTIVATE:
  1735.         {
  1736.             LPNMHDR pNotify = (LPNMHDR)lParam;
  1737.             DWORD dwFlags = CMF_NORMAL;
  1738.             HWND hwndFrame;
  1739.             HMENU hMenu;
  1740.             UINT uID;
  1741.             // convert the current selection to IDLITs and an IContextMenu interface
  1742.             // that we can then get the default verb from.
  1743.             SetWaitCursor();
  1744.             DoRelease(_pcm);
  1745.             hres = _GetIDLsAndViewObject(FALSE, IID_IContextMenu, (void **)&_pcm);
  1746.             FailGracefully(hres, "Failed when calling _GetIDLsAndViewObject");
  1747.             _fNoSelection = !ShortFromResult(hres);
  1748.             if ( !_fNoSelection )
  1749.             {
  1750.                 // create a popup menu pickup the context menu for the current selection
  1751.                 // and then pass it down to the invoke command handler.
  1752.                 hMenu = CreatePopupMenu();
  1753.                 TraceAssert(hMenu);
  1754.                 if ( hMenu )
  1755.                 {
  1756.                     if ( GetKeyState(VK_SHIFT) < 0 )
  1757.                         dwFlags |= CMF_EXPLORE;          // SHIFT + dblclick does a Explore by default
  1758.                     _GetContextMenuVerbs(_pcm, hMenu, dwFlags);
  1759.                     uID = GetMenuDefaultItem(hMenu, MF_BYCOMMAND, 0);
  1760.                     Trace(TEXT("Default uID after double click %08x"), uID);
  1761.                     if ( uID != -1 )
  1762.                     {
  1763.                         _pqf->GetWindow(&hwndFrame);                
  1764.                         InvokeCommand(hwndFrame, uID);
  1765.                     }
  1766.                     DoRelease(_pcm);          // no longer needed
  1767.                     DestroyMenu(hMenu);
  1768.                 }
  1769.             }
  1770.             break;
  1771.         }
  1772.         case LVN_COLUMNCLICK:
  1773.         {
  1774.             NM_LISTVIEW* pNotify = (NM_LISTVIEW*)lParam;
  1775.             TraceAssert(pNotify);
  1776.             _SortResults(pNotify->iSubItem);
  1777.             break;
  1778.         }
  1779.         default:
  1780.             lr = DefWindowProc(hWnd, WM_NOTIFY, wParam, lParam);
  1781.             break;
  1782.     }
  1783. exit_gracefully:
  1784.     ResetWaitCursor();
  1785.     TraceLeaveValue(lr);
  1786. }
  1787. /*-----------------------------------------------------------------------------
  1788. / CDsQuery::OnAddResults
  1789. / ----------------------
  1790. /   The background thread has sent us some results, so lets add them to
  1791. /   the DPA of results, discarding the ones we don't add because we cannot
  1792. /   grow the DPA.
  1793. /
  1794. /   dwQueryReference conatins the reference ID for this query, only add
  1795. /   results where these match.
  1796. /
  1797. / In:
  1798. /   dwQueryReference = reference that this block is for
  1799. /   hdpaResults = DPA containing the results to add
  1800. /
  1801. / Out:
  1802. /   HRESULT
  1803. /----------------------------------------------------------------------------*/
  1804. HRESULT CDsQuery::OnAddResults(DWORD dwQueryReference, HDPA hdpaResults)
  1805. {
  1806.     HRESULT hres;
  1807.     INT i, iPopulateFrom;
  1808.     TraceEnter(TRACE_VIEW, "CDsQuery::OnAddResults");
  1809.     if ( (dwQueryReference != _dwQueryReference) || !hdpaResults )
  1810.         ExitGracefully(hres, E_FAIL, "Failed to add results, bad DPA/reference ID");
  1811.     // the caller gives us a DPA then we add them to our result DPA, we then
  1812.     // update the view populating from the first item we added.
  1813.     iPopulateFrom = DPA_GetPtrCount(_hdpaResults);
  1814.     for ( i = DPA_GetPtrCount(hdpaResults); --i >= 0 ;  )
  1815.     {
  1816.         LPQUERYRESULT pResult = (LPQUERYRESULT)DPA_GetPtr(hdpaResults, i);
  1817.         TraceAssert(pResult);
  1818.         // add the result to the main DPA, if that fails then ensure we nuke
  1819.         // this result blob!
  1820.     
  1821.         if ( -1 == DPA_AppendPtr(_hdpaResults, pResult) )
  1822.             FreeQueryResult(pResult, DSA_GetItemCount(_hdsaColumns));
  1823.         DPA_DeletePtr(hdpaResults, i);          // remove from result DPA
  1824.     }
  1825.     _PopulateView(iPopulateFrom, DPA_GetPtrCount(_hdpaResults));
  1826.     TraceAssert(DPA_GetPtrCount(hdpaResults) == 0);
  1827.     DPA_Destroy(hdpaResults);
  1828.     hres = S_OK;
  1829. exit_gracefully:
  1830.     TraceLeaveResult(hres);
  1831. }
  1832. /*-----------------------------------------------------------------------------
  1833. / CDsQuery::OnContextMenu
  1834. / -----------------------
  1835. /   The user has right clicked in the result view, therefore we must attempt
  1836. /   to display the context menu for those objects
  1837. /
  1838. / In:
  1839. /   hwndMenu = window that that the user menued over
  1840. /   pt = point to show the context menu
  1841. /
  1842. / Out:
  1843. /   -
  1844. /----------------------------------------------------------------------------*/
  1845. LRESULT CDsQuery::OnContextMenu(HWND hwndMenu, LPARAM lParam)
  1846. {
  1847.     HRESULT hres;
  1848.     HMENU hMenu = NULL;
  1849.     POINT pt = { 0, 0 };
  1850.     INT i;
  1851.     RECT rc;
  1852.     HWND hwndFrame;
  1853.     TraceEnter(TRACE_VIEW, "CDsQuery::OnContextMenu");
  1854.     // Collect the selection, obtaining a IContextMenu interface pointer, or a HR == S_FALSE
  1855.     // if there is no selection for us to be using.
  1856.     DoRelease(_pcm);
  1857.     hres = _GetIDLsAndViewObject(FALSE, IID_IContextMenu, (void **)&_pcm);
  1858.     FailGracefully(hres, "Failed when calling _GetIDLsAndViewObject");
  1859.     _fNoSelection = !ShortFromResult(hres);
  1860.     if ( !(hMenu = CreatePopupMenu()) )
  1861.         ExitGracefully(hres, E_FAIL, "Failed to create the popup menu");
  1862.     if ( !_fNoSelection )
  1863.     {
  1864.         // pick up the context menu that maps tot he current selection, including fixing
  1865.         // the "select" verb if we need one.
  1866.         _GetContextMenuVerbs(_pcm, hMenu, CMF_NORMAL);
  1867.     }
  1868.     else
  1869.     {
  1870.         // There is no selection so lets pick up the view bg menu, this contains
  1871.         // some useful helpers for modifying the view state.
  1872.         HMENU hBgMenu = LoadMenu(GLOBAL_HINSTANCE, MAKEINTRESOURCE(IDR_VIEWBACKGROUND));
  1873.         if ( !hBgMenu )
  1874.             ExitGracefully(hres, E_FAIL, "Failed to load pop-up menu for the background");
  1875.         Shell_MergeMenus(hMenu, GetSubMenu(hBgMenu, 0), 0, 0, CQID_MAXHANDLERMENUID, 0x0);
  1876.         DestroyMenu(hBgMenu);
  1877.         _InitViewMenuItems(hMenu);
  1878.     }
  1879.     // if lParam == -1 then we know that the user hit the "context menu" key
  1880.     // so lets set the co-ordinates of the item.
  1881.     if ( lParam == (DWORD)-1 )
  1882.     {
  1883.         i = ListView_GetNextItem(_hwndView, -1, LVNI_FOCUSED|LVNI_SELECTED);
  1884.         Trace(TEXT("Item with focus + selection: %d"), i);
  1885.         if ( i == -1 )
  1886.         {
  1887.             i = ListView_GetNextItem(_hwndView, -1, LVNI_SELECTED);
  1888.             Trace(TEXT("1st selected item: %D"), i);
  1889.         }            
  1890.         if ( i != -1 )
  1891.         {
  1892.             TraceMsg("We have an item, so getting bounds of the icon for position");
  1893.             ListView_GetItemRect(_hwndView, i, &rc, LVIR_ICON);
  1894.             pt.x = (rc.left+rc.right)/2;
  1895.             pt.y = (rc.top+rc.bottom)/2;
  1896.         }
  1897.         MapWindowPoints(_hwndView, HWND_DESKTOP, &pt, 1);      // they are in client co-ordinates
  1898.     }
  1899.     else
  1900.     {
  1901.         pt.x = GET_X_LPARAM(lParam);
  1902.         pt.y = GET_Y_LPARAM(lParam);
  1903.     }
  1904.     
  1905.     // we have the position so lets use it
  1906.     _pqf->GetWindow(&hwndFrame);
  1907.     TrackPopupMenu(hMenu, TPM_LEFTALIGN, pt.x, pt.y, 0, hwndFrame, NULL);
  1908. exit_gracefully:
  1909.     if ( hMenu )
  1910.         DestroyMenu(hMenu);
  1911.     TraceLeaveValue(0);
  1912. }
  1913. /*-----------------------------------------------------------------------------
  1914. / CDsQuery::OnFileProperties
  1915. / --------------------------
  1916. /   Show properties for the given selection.  To do this we CoCreate 
  1917. /   IDsFolderProperties on the IDsFolder implementation and that
  1918. /   we can invoke properties using.
  1919. /
  1920. / In:
  1921. / Out:
  1922. /   HRESULT
  1923. /----------------------------------------------------------------------------*/
  1924. HRESULT CDsQuery::OnFileProperties(VOID)
  1925. {
  1926.     HRESULT hres;
  1927.     IDataObject* pDataObject = NULL;
  1928.     IDsFolderProperties* pDsFolderProperties = NULL;
  1929.     TraceEnter(TRACE_VIEW, "CDsQuery::OnFileProperties");
  1930.     hres = GetViewObject(CQRVS_SELECTION, IID_IDataObject, (void **)&pDataObject);
  1931.     FailGracefully(hres, "Failed to get IDataObject for shortcut creation");
  1932.     hres = CoCreateInstance(CLSID_DsFolderProperties, NULL, CLSCTX_INPROC_SERVER, IID_IDsFolderProperties, (void **)&pDsFolderProperties);
  1933.     FailGracefully(hres, "Failed to get IDsFolderProperties for the desktop object");
  1934.     hres = pDsFolderProperties->ShowProperties(_hwnd, pDataObject);
  1935.     FailGracefully(hres, "Failed to invoke property UI for the given selection");
  1936.     // hres = S_OK;                  // success
  1937. exit_gracefully:
  1938.     
  1939.     DoRelease(pDataObject);
  1940.     DoRelease(pDsFolderProperties);
  1941.     TraceLeaveResult(hres);
  1942. }
  1943. /*-----------------------------------------------------------------------------
  1944. / CDsQuery::OnFileCreateShortcut
  1945. / ------------------------------
  1946. /   Get the selection as a IDataObject then call the shell for it to
  1947. /   create shortucts to the objects.  These shortcuts are placed onto
  1948. /   the desktop.
  1949. /
  1950. / In:
  1951. / Out:
  1952. /   HRESULT
  1953. /----------------------------------------------------------------------------*/
  1954. #if !DOWNLEVEL_SHELL
  1955. HRESULT CDsQuery::OnFileCreateShortcut(VOID)
  1956. {
  1957.     HRESULT hres;
  1958.     IDataObject* pDataObject = NULL;
  1959.     TraceEnter(TRACE_VIEW, "CDsQuery::OnFileCreateShortcut");
  1960.     hres = GetViewObject(CQRVS_SELECTION, IID_IDataObject, (void **)&pDataObject);
  1961.     FailGracefully(hres, "Failed to get IDataObject for shortcut creation");
  1962.     hres = SHCreateLinks(_hwnd, NULL, pDataObject, SHCL_USETEMPLATE | SHCL_USEDESKTOP | SHCL_CONFIRM, NULL);
  1963.     FailGracefully(hres, "Failed when calling SHCreateLinks");
  1964.     // hres = S_OK;                  // success
  1965. exit_gracefully:
  1966.     
  1967.     DoRelease(pDataObject);
  1968.     TraceLeaveResult(hres);
  1969. }
  1970. #endif
  1971. /*-----------------------------------------------------------------------------
  1972. / CDsQuery::OnFileSaveQuery
  1973. / -------------------------
  1974. /   Allow the user to choose a location to save the query (initial directory
  1975. /   is nethood).  Having done that we then start the save process by passing
  1976. /   the frame object a IQueryIO object that allows them to persist the
  1977. /   query into.
  1978. /
  1979. / In:
  1980. / Out:
  1981. /   HRESULT
  1982. /----------------------------------------------------------------------------*/
  1983. HRESULT CDsQuery::OnFileSaveQuery(VOID)
  1984. {
  1985.     HRESULT hres;
  1986.     OPENFILENAME ofn;
  1987.     TCHAR szFilename[MAX_PATH];
  1988.     TCHAR szDirectory[MAX_PATH];
  1989.     TCHAR szFilter[64];
  1990.     TCHAR szTitle[64];
  1991.     LPTSTR pFilter;
  1992.     CDsPersistQuery* pPersistQuery = NULL;
  1993.     USES_CONVERSION;
  1994.     TraceEnter(TRACE_VIEW, "CDsQuery::OnFileSaveQuery");
  1995.     // Load the default strings and fix up the filter string as it needs
  1996.     // NULL's seperating the various resource sections.
  1997.     LoadString(GLOBAL_HINSTANCE, IDS_SAVETITLE, szTitle, ARRAYSIZE(szTitle));
  1998.     StrCpy(szFilename, _pDefaultSaveName);
  1999.     LoadString(GLOBAL_HINSTANCE, IDS_SAVEFILTER, szFilter, ARRAYSIZE(szFilter));
  2000.     for ( pFilter = szFilter ; *pFilter ; pFilter++ )
  2001.     {
  2002.         if ( *pFilter == TEXT('n') )
  2003.             *pFilter = TEXT('');
  2004.     }
  2005.     // fix the open filename structure ready to do our save....
  2006.     ZeroMemory(&ofn, SIZEOF(ofn));
  2007.     ofn.lStructSize = SIZEOF(ofn);
  2008.     _pqf->GetWindow(&ofn.hwndOwner);
  2009.     ofn.hInstance = GLOBAL_HINSTANCE;
  2010.     ofn.lpstrFilter = szFilter;
  2011.     ofn.lpstrFile = szFilename;
  2012.     ofn.nMaxFile = ARRAYSIZE(szFilename);
  2013.     if ( _pDefaultSaveLocation )
  2014.     {
  2015.         Trace(TEXT("Saving into: %s"), W2T(_pDefaultSaveLocation));
  2016.         StrCpy(szDirectory, W2T(_pDefaultSaveLocation));
  2017.         ofn.lpstrInitialDir = szDirectory;
  2018.     }
  2019.     ofn.lpstrTitle = szTitle;
  2020.     ofn.Flags = OFN_EXPLORER|OFN_NOCHANGEDIR|OFN_OVERWRITEPROMPT|OFN_PATHMUSTEXIST|OFN_HIDEREADONLY;
  2021.     ofn.lpstrDefExt = TEXT("dsq");
  2022.     // If we get a save filename then lets ensure that we delete the previous
  2023.     // query saved there (if there is one) and then we can create an IPersistQuery
  2024.     // object that will save to that location.
  2025.     if ( GetSaveFileName(&ofn) )
  2026.     {
  2027.         Trace(TEXT("Saving query as: %s"), szFilename);
  2028.         if ( !DeleteFile(szFilename) && (GetLastError() != ERROR_FILE_NOT_FOUND) )
  2029.             ExitGracefully(hres, E_FAIL, "Failed to delete previous query");
  2030.         pPersistQuery = new CDsPersistQuery(szFilename);
  2031.         if ( !pPersistQuery )
  2032.             ExitGracefully(hres, E_OUTOFMEMORY, "Failed to allocate CDsPersistQuery");
  2033.         hres = _pqf->SaveQuery(pPersistQuery);
  2034.         FailGracefully(hres, "Failed when calling IQueryFrame::SaveSearch");
  2035.     }   
  2036.     hres = S_OK;
  2037. exit_gracefully:
  2038.     DoRelease(pPersistQuery);