Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5366 lines
175 KiB

  1. #include "pch.h"
  2. #include "stddef.h"
  3. #include <atlbase.h>
  4. #pragma hdrstop
  5. // class that implements the query UI
  6. class CDsQuery : public IQueryHandler, IQueryForm, IObjectWithSite, IDsQueryHandler, IShellFolder
  7. {
  8. public:
  9. CDsQuery();
  10. ~CDsQuery();
  11. // IUnknown
  12. STDMETHOD(QueryInterface)(REFIID riid, void **ppvObject);
  13. STDMETHOD_(ULONG, AddRef)();
  14. STDMETHOD_(ULONG, Release)();
  15. // IQueryForms
  16. STDMETHOD(Initialize)(HKEY hkForm);
  17. STDMETHOD(AddForms)(LPCQADDFORMSPROC pAddFormsProc, LPARAM lParam);
  18. STDMETHOD(AddPages)(LPCQADDPAGESPROC pAddPagesProc, LPARAM lParam);
  19. // IQueryHandler
  20. STDMETHOD(Initialize)(IQueryFrame* pQueryFrame, DWORD dwOQWFlags, LPVOID pParameters);
  21. STDMETHOD(GetViewInfo)(LPCQVIEWINFO pViewInfo);
  22. STDMETHOD(AddScopes)();
  23. STDMETHOD(BrowseForScope)(HWND hwndParent, LPCQSCOPE pCurrentScope, LPCQSCOPE* ppScope);
  24. STDMETHOD(CreateResultView)(HWND hwndParent, HWND* phWndView);
  25. STDMETHOD(ActivateView)(UINT uState, WPARAM wParam, LPARAM lParam);
  26. STDMETHOD(InvokeCommand)(HWND hwndParent, UINT uID);
  27. STDMETHOD(GetCommandString)(UINT uID, DWORD dwFlags, LPTSTR pBuffer, INT cchBuffer);
  28. STDMETHOD(IssueQuery)(LPCQPARAMS pQueryParams);
  29. STDMETHOD(StopQuery)();
  30. STDMETHOD(GetViewObject)(UINT uScope, REFIID riid, void **ppvOut);
  31. STDMETHOD(LoadQuery)(IPersistQuery* pPersistQuery);
  32. STDMETHOD(SaveQuery)(IPersistQuery* pPersistQuery, LPCQSCOPE pScope);
  33. // IObjectWithSite
  34. STDMETHODIMP SetSite(IUnknown* punk);
  35. STDMETHODIMP GetSite(REFIID riid, void **ppv);
  36. // IDsQueryHandler
  37. STDMETHOD(UpdateView)(DWORD dwType, LPDSOBJECTNAMES pdon);
  38. // IShellFolder
  39. STDMETHOD(ParseDisplayName)(HWND hwnd, LPBC pbc, LPOLESTR pszName, ULONG * pchEaten, LPITEMIDLIST * ppidl, ULONG *pdwAttributes)
  40. { return E_NOTIMPL; }
  41. STDMETHOD(EnumObjects)(HWND hwndOwner, DWORD grfFlags, LPENUMIDLIST * ppEnumIDList)
  42. { return E_NOTIMPL; }
  43. STDMETHOD(BindToObject)(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, void **ppv)
  44. { return E_NOTIMPL; }
  45. STDMETHOD(BindToStorage)(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, void **ppv)
  46. { return E_NOTIMPL; }
  47. STDMETHOD(CompareIDs)(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  48. { return E_NOTIMPL; }
  49. STDMETHOD(CreateViewObject)(HWND hwndOwner, REFIID riid, void **ppv)
  50. { return E_NOTIMPL; }
  51. STDMETHOD(GetAttributesOf)(UINT cidl, LPCITEMIDLIST * apidl, ULONG * rgfInOut)
  52. { *rgfInOut &= SFGAO_HASPROPSHEET; return S_OK; }
  53. STDMETHOD(GetUIObjectOf)(HWND hwndOwner, UINT cidl, LPCITEMIDLIST * apidl, REFIID riid, UINT * prgfInOut, void **ppv)
  54. { return GetViewObject(0x0, riid, ppv); }
  55. STDMETHOD(GetDisplayNameOf)(LPCITEMIDLIST pidl, DWORD uFlags, LPSTRRET pName)
  56. { return E_NOTIMPL; }
  57. STDMETHOD(SetNameOf)(HWND hwndOwner, LPCITEMIDLIST pidl, LPCOLESTR pszName, DWORD uFlags, LPITEMIDLIST* ppidlOut)
  58. { return E_NOTIMPL; }
  59. private:
  60. LRESULT OnSize(INT cx, INT cy);
  61. LRESULT OnNotify(HWND hWnd, WPARAM wParam, LPARAM lParam);
  62. HRESULT OnAddResults(DWORD dwQueryReference, HDPA hdpaResults);
  63. LRESULT OnContextMenu(HWND hwndMenu, LPARAM lParam);
  64. HRESULT OnFileProperties(VOID);
  65. HRESULT OnFileSaveQuery(VOID);
  66. HRESULT OnEditSelectAll(VOID);
  67. HRESULT OnEditInvertSelection(VOID);
  68. HRESULT OnPickColumns(HWND hwndParent);
  69. static int s_BrowseForScopeCB(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData);
  70. static LRESULT s_ResultViewWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  71. static LRESULT s_BannerWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  72. HRESULT _SetDataObjectData(IDataObject* pDataObject, UINT cf, LPVOID pData, DWORD cbSize);
  73. HRESULT _SetDispSpecOptions(IDataObject *pdo);
  74. HRESULT _InitNewQuery(LPDSQUERYPARAMS pDsQueryParams, BOOL fRefreshColumnTable);
  75. HRESULT _GetFilterValue(INT iColumn, HD_ITEM* pitem);
  76. HRESULT _FilterView(BOOL fCheck);
  77. HRESULT _PopulateView(INT iFirstItem, INT iLast);
  78. VOID _FreeResults(VOID);
  79. DWORD _SetViewMode(INT uID);
  80. VOID _SortResults(INT iColumn);
  81. VOID _SetFilter(BOOL fFilter);
  82. VOID _ShowBanner(UINT flags, UINT idPrompt);
  83. VOID _InitViewMenuItems(HMENU hMenu);
  84. HRESULT _GetQueryFormKey(REFCLSID clsidForm, HKEY* phKey);
  85. HRESULT _GetColumnTable(REFCLSID clsidForm, LPDSQUERYPARAMS pDsQueryParams, HDSA* pHDSA, BOOL fSetInView);
  86. VOID _SaveColumnTable(VOID);
  87. HRESULT _SaveColumnTable(REFCLSID clsidForm, HDSA hdsaColumns);
  88. HRESULT _AddResultToDataObject(HDSA hdsa, INT i);
  89. HRESULT _GetDataObjectFromSelection(BOOL fGetAll, IDataObject **pdo);
  90. HRESULT _GetContextMenu();
  91. VOID _GetContextMenuVerbs(HMENU hMenu, DWORD dwFlags);
  92. HRESULT _CopyCredentials(LPWSTR *ppszUserName, LPWSTR *ppszPassword, LPWSTR *ppszServer);
  93. VOID _DeleteViewItems(LPDSOBJECTNAMES pdon);
  94. private:
  95. LONG _cRef; // lifetime
  96. IQueryFrame* _pqf; // our parent window
  97. IUnknown* _punkSite; // site object
  98. IContextMenu* _pcm; // Curerntly displayed context menu / == NULL if none
  99. DWORD _dwOQWFlags; // flags passed to OpenQueryWindow
  100. DWORD _dwFlags; // flags as part of the ds query parameters
  101. LPWSTR _pDefaultScope; // default scope passed
  102. LPWSTR _pDefaultSaveLocation; // directory to save queries into by default
  103. LPTSTR _pDefaultSaveName; // default save name (from the query form)
  104. LPWSTR _pServer; // server to target
  105. LPWSTR _pUserName; // user name and password to authenticate with
  106. LPWSTR _pPassword;
  107. BOOL _fNoSelection:1; // the IContextMenu was from no selection
  108. BOOL _fColumnsModified:1; // settings of the view modified
  109. BOOL _fSortDescending:1; // sort the results descending
  110. BOOL _fFilter:1; // filter enabled
  111. BOOL _fFilterSupported:1; // is the filter available, eg: comctl32 > 5.0
  112. INT _idViewMode; // default view mode
  113. INT _iSortColumn; // sort column
  114. HWND _hwnd; // container window
  115. HWND _hwndView; // listview window (child of parent)
  116. HWND _hwndBanner; // banner window which is a child of the list view
  117. DWORD _dwQueryReference; // reference value passed to query
  118. HANDLE _hThread; // worker thread handle
  119. DWORD _dwThreadId; // thread ID for the Query processing thread
  120. CLSID _clsidForm; // form being used for column table
  121. HDSA _hdsaColumns; // column information (size, filters, etc)
  122. HDPA _hdpaResults; // results for tr the query we have issued
  123. LPTSTR _pFilter; // current filter
  124. HMENU _hFrameMenuBar; // stored frame menu bar, stored from activate
  125. HMENU _hFileMenu; // added to the frames view menu
  126. HMENU _hEditMenu; // inserted into the menu bar
  127. HMENU _hViewMenu; // inserted into the menu bar
  128. HMENU _hHelpMenu; // inserted into the menu bar
  129. };
  130. //
  131. // Window classes we create to show the results
  132. //
  133. #define VIEW_CLASS TEXT("ActiveDsQueryView")
  134. #define BANNER_CLASS TEXT("ActiveDsQueryBanner")
  135. //
  136. // Registry values used for the settings
  137. //
  138. #define VIEW_SETTINGS_VALUE TEXT("ViewSettings")
  139. #define ADMIN_VIEW_SETTINGS_VALUE TEXT("AdminViewSettings");
  140. //
  141. // When filtering we populate the view using PostMessage, doing so many items
  142. // at a time
  143. //
  144. #define FILTER_UPDATE_COUNT 128
  145. //
  146. // All items within the list view contain the following LPARAM structure used
  147. // for storing the magic properties we are interested in.
  148. //
  149. #define ENABLE_MENU_ITEM(hMenu, id, fEnabled) \
  150. EnableMenuItem(hMenu, id, (fEnabled) ? (MF_BYCOMMAND|MF_ENABLED):(MF_BYCOMMAND|MF_GRAYED))
  151. //
  152. // Persisted column data, this is stored in the registry under the CLSID for the
  153. // form we are interested in.
  154. //
  155. typedef struct
  156. {
  157. DWORD cbSize; // offset to the next column / == 0 if none
  158. DWORD dwFlags; // flags
  159. DWORD offsetProperty; // offset to property name (UNICODE)
  160. DWORD offsetHeading; // offset to column heading
  161. INT cx; // pixel width of the column
  162. INT fmt; // format of the column
  163. } SAVEDCOLUMN, * LPSAVEDCOLUMN;
  164. //
  165. // Table to map property types to useful information
  166. //
  167. struct
  168. {
  169. LPCTSTR pMenuName;
  170. INT idOperator;
  171. INT hdft;
  172. }
  173. // NTRAID#NTBUG9-618605-2002/09/17-lucios
  174. // Added the entry for PROPERTY_ISDNSTRING
  175. property_type_table[] =
  176. {
  177. 0, 0, 0,
  178. MAKEINTRESOURCE(IDR_OP_STRING), FILTER_CONTAINS, HDFT_ISSTRING,
  179. MAKEINTRESOURCE(IDR_OP_STRING), FILTER_CONTAINS, HDFT_ISSTRING,
  180. MAKEINTRESOURCE(IDR_OP_NUMBER), FILTER_IS, HDFT_ISNUMBER,
  181. MAKEINTRESOURCE(IDR_OP_NUMBER), FILTER_IS, HDFT_ISNUMBER, // PROPERTY_ISBOOL
  182. MAKEINTRESOURCE(IDR_OP_STRING), FILTER_CONTAINS, HDFT_ISSTRING, // PROPERTY_ISDNSTRING
  183. };
  184. //
  185. // Help information for the frame and the control
  186. //
  187. static DWORD const aHelpIDs[] =
  188. {
  189. CQID_LOOKFORLABEL, IDH_FIND,
  190. CQID_LOOKFOR, IDH_FIND,
  191. CQID_LOOKINLABEL, IDH_IN,
  192. CQID_LOOKIN, IDH_IN,
  193. CQID_BROWSE, IDH_BROWSE,
  194. CQID_FINDNOW, IDH_FIND_NOW,
  195. CQID_STOP, IDH_STOP,
  196. CQID_CLEARALL, IDH_CLEAR_ALL,
  197. IDC_RESULTS, IDH_RESULTS,
  198. IDC_STATUS, IDH_NO_HELP,
  199. 0, 0,
  200. };
  201. static DWORD const aBrowseHelpIDs[] =
  202. {
  203. DSBID_BANNER, (DWORD)-1,
  204. DSBID_CONTAINERLIST, IDH_BROWSE_CONTAINER,
  205. 0, 0,
  206. };
  207. // Query object
  208. CDsQuery::CDsQuery() :
  209. _cRef(1), _fNoSelection(TRUE), _iSortColumn(-1), _idViewMode(DSQH_VIEW_DETAILS)
  210. {
  211. if (CheckDsPolicy(NULL, c_szEnableFilter))
  212. {
  213. TraceMsg("QuickFilter enabled in policy");
  214. _fFilter = TRUE;
  215. }
  216. DllAddRef();
  217. }
  218. CDsQuery::~CDsQuery()
  219. {
  220. // persist the column information if we need to
  221. if (_hdsaColumns)
  222. {
  223. if (_fColumnsModified)
  224. {
  225. _SaveColumnTable(_clsidForm, _hdsaColumns);
  226. _fColumnsModified = FALSE;
  227. }
  228. _SaveColumnTable();
  229. }
  230. // discard all the other random state we have
  231. LocalFreeStringW(&_pDefaultScope);
  232. LocalFreeStringW(&_pDefaultSaveLocation);
  233. LocalFreeString(&_pDefaultSaveName);
  234. SecureLocalFreeStringW(&_pUserName);
  235. SecureLocalFreeStringW(&_pPassword);
  236. SecureLocalFreeStringW(&_pServer);
  237. if (IsWindow(_hwnd))
  238. DestroyWindow(_hwnd);
  239. if (IsMenu(_hFileMenu))
  240. DestroyMenu(_hFileMenu);
  241. if (IsMenu(_hEditMenu))
  242. DestroyMenu(_hEditMenu);
  243. if (IsMenu(_hViewMenu))
  244. DestroyMenu(_hViewMenu);
  245. if (IsMenu(_hHelpMenu))
  246. DestroyMenu(_hHelpMenu);
  247. // tell the thread its time to die
  248. if (_hThread)
  249. {
  250. PostThreadMessage(_dwThreadId, RVTM_STOPQUERY, 0, 0);
  251. PostThreadMessage(_dwThreadId, WM_QUIT, 0, 0);
  252. CloseHandle(_hThread);
  253. }
  254. DoRelease(_pqf);
  255. DoRelease(_punkSite);
  256. DoRelease(_pcm);
  257. DllRelease();
  258. }
  259. // IUnknown bits
  260. ULONG CDsQuery::AddRef()
  261. {
  262. return InterlockedIncrement(&_cRef);
  263. }
  264. ULONG CDsQuery::Release()
  265. {
  266. TraceAssert( 0 != _cRef );
  267. ULONG cRef = InterlockedDecrement(&_cRef);
  268. if ( 0 == cRef )
  269. {
  270. delete this;
  271. }
  272. return cRef;
  273. }
  274. HRESULT CDsQuery::QueryInterface(REFIID riid, void **ppv)
  275. {
  276. static const QITAB qit[] =
  277. {
  278. QITABENT(CDsQuery, IQueryForm), // IID_IQueryForm
  279. QITABENT(CDsQuery, IQueryHandler), // IID_IQueryHandler
  280. QITABENT(CDsQuery, IObjectWithSite), // IID_IObjectWIthSite
  281. QITABENT(CDsQuery, IDsQueryHandler), // IID_IDsQueryHandler
  282. QITABENT(CDsQuery, IShellFolder), // IID_IShellFolder
  283. {0, 0 },
  284. };
  285. return QISearch(this, qit, riid, ppv);
  286. }
  287. //
  288. // Handle creating an instance of CLSID_DsQuery
  289. //
  290. STDAPI CDsQuery_CreateInstance(IUnknown* punkOuter, IUnknown** ppunk, LPCOBJECTINFO poi)
  291. {
  292. CDsQuery *pdq = new CDsQuery();
  293. if (!pdq)
  294. return E_OUTOFMEMORY;
  295. HRESULT hr = pdq->QueryInterface(IID_IUnknown, (void **)ppunk);
  296. pdq->Release();
  297. return hr;
  298. }
  299. /// IQueryForm
  300. STDMETHODIMP CDsQuery::Initialize(HKEY hkForm)
  301. {
  302. return S_OK;
  303. }
  304. // query forms exposed from this object
  305. struct
  306. {
  307. CLSID const * clsidForm;
  308. INT idsTitle;
  309. DWORD dwFlags;
  310. }
  311. forms[] =
  312. {
  313. &CLSID_DsFindPeople, IDS_FINDUSER, 0,
  314. &CLSID_DsFindComputer, IDS_FINDCOMPUTER, 0,
  315. &CLSID_DsFindPrinter, IDS_FINDPRINTERS, 0,
  316. &CLSID_DsFindVolume, IDS_FINDSHAREDFOLDERS, 0,
  317. &CLSID_DsFindContainer, IDS_FINDOU, 0,
  318. &CLSID_DsFindAdvanced, IDS_CUSTOMSEARCH, CQFF_NOGLOBALPAGES,
  319. &CLSID_DsFindDomainController, IDS_FINDDOMCTL, CQFF_ISNEVERLISTED|CQFF_NOGLOBALPAGES,
  320. &CLSID_DsFindFrsMembers, IDS_FINDFRSMEMBER, CQFF_ISNEVERLISTED|CQFF_NOGLOBALPAGES,
  321. };
  322. STDMETHODIMP CDsQuery::AddForms(LPCQADDFORMSPROC pAddFormsProc, LPARAM lParam)
  323. {
  324. HRESULT hr;
  325. TCHAR szBuffer[MAX_PATH];
  326. INT i;
  327. TraceEnter(TRACE_FORMS, "CDsQuery::AddForms");
  328. if (!pAddFormsProc)
  329. ExitGracefully(hr, E_INVALIDARG, "No AddFormsProc");
  330. for (i = 0; i < ARRAYSIZE(forms); i++)
  331. {
  332. CQFORM qf = { 0 };
  333. qf.cbStruct = SIZEOF(qf);
  334. qf.dwFlags = forms[i].dwFlags;
  335. qf.clsid = *forms[i].clsidForm;
  336. qf.pszTitle = szBuffer;
  337. LoadString(GLOBAL_HINSTANCE, forms[i].idsTitle, szBuffer, ARRAYSIZE(szBuffer));
  338. hr = (*pAddFormsProc)(lParam, &qf);
  339. FailGracefully(hr, "Failed to add form (calling pAddFormsFunc)");
  340. }
  341. hr = S_OK; // success
  342. exit_gracefully:
  343. TraceLeaveResult(hr);
  344. }
  345. // page information for this object
  346. struct
  347. {
  348. CLSID const * clisdForm;
  349. LPCQPAGEPROC pPageProc;
  350. DLGPROC pDlgProc;
  351. INT idPageTemplate;
  352. INT idPageName;
  353. DWORD dwFlags;
  354. }
  355. pages[] =
  356. {
  357. //
  358. // Page list for the default forms that we add
  359. //
  360. &CLSID_DsFindPeople, PageProc_User, DlgProc_User, IDD_FINDUSER, IDS_FINDUSER, 0,
  361. &CLSID_DsFindComputer, PageProc_Computer, DlgProc_Computer, IDD_FINDCOMPUTER, IDS_FINDCOMPUTER, 0,
  362. &CLSID_DsFindPrinter, PageProc_Printers, DlgProc_Printers, IDD_FINDPRINT1, IDS_FINDPRINTERS, 0,
  363. &CLSID_DsFindPrinter, PageProc_PrintersMore, DlgProc_PrintersMore, IDD_FINDPRINT2, IDS_MORECHOICES, 0,
  364. &CLSID_DsFindVolume, PageProc_Volume, DlgProc_Volume, IDD_FINDVOLUME, IDS_FINDSHAREDFOLDERS, 0,
  365. &CLSID_DsFindContainer, PageProc_Container, DlgProc_Container, IDD_FINDCONTAINER, IDS_FINDOU, 0,
  366. &CLSID_DsFindAdvanced, PageProc_PropertyWell, DlgProc_PropertyWell, IDD_PROPERTYWELL, IDS_CUSTOMSEARCH, 0,
  367. &CLSID_DsFindAdvanced, PageProc_RawLDAP, DlgProc_RawLDAP, IDD_FINDUSINGLDAP, IDS_ADVANCED, 0,
  368. &CLSID_DsFindDomainController, PageProc_DomainController, DlgProc_DomainController, IDD_FINDDOMCTL, IDS_FINDDOMCTL, 0,
  369. &CLSID_DsFindFrsMembers, PageProc_FrsMember, DlgProc_FrsMember, IDD_FINDFRSMEMBER, IDS_FINDFRSMEMBER, 0,
  370. //
  371. // Make the property well available on all pages (using the magic CQPF_ADDTOALLFORMS bit)
  372. //
  373. &CLSID_DsFindAdvanced, PageProc_PropertyWell, DlgProc_PropertyWell, IDD_PROPERTYWELL, IDS_ADVANCED, CQPF_ISGLOBAL,
  374. };
  375. STDMETHODIMP CDsQuery::AddPages(LPCQADDPAGESPROC pAddPagesProc, LPARAM lParam)
  376. {
  377. HRESULT hr;
  378. INT i;
  379. TraceEnter(TRACE_FORMS, "CDsQuery::AddPages");
  380. if (!pAddPagesProc)
  381. ExitGracefully(hr, E_INVALIDARG, "No AddPagesProc");
  382. for (i = 0 ; i < ARRAYSIZE(pages) ; i++)
  383. {
  384. CQPAGE qp = { 0 };
  385. qp.cbStruct = SIZEOF(qp);
  386. qp.dwFlags = pages[i].dwFlags;
  387. qp.pPageProc = pages[i].pPageProc;
  388. qp.hInstance = GLOBAL_HINSTANCE;
  389. qp.idPageName = pages[i].idPageName;
  390. qp.idPageTemplate = pages[i].idPageTemplate;
  391. qp.pDlgProc = pages[i].pDlgProc;
  392. hr = (*pAddPagesProc)(lParam, *pages[i].clisdForm, &qp);
  393. FailGracefully(hr, "Failed to add page (calling pAddPagesFunc)");
  394. }
  395. hr = S_OK;
  396. exit_gracefully:
  397. TraceLeaveResult(S_OK);
  398. }
  399. // IQueryHandler
  400. STDMETHODIMP CDsQuery::Initialize(IQueryFrame* pQueryFrame, DWORD dwOQWFlags, LPVOID pParameters)
  401. {
  402. HRESULT hr;
  403. LPDSQUERYINITPARAMS pDsQueryInitParams = (LPDSQUERYINITPARAMS)pParameters;
  404. TCHAR szGUID[GUIDSTR_MAX];
  405. TCHAR szBuffer[MAX_PATH];
  406. HINSTANCE hInstanceComCtl32 = NULL;
  407. TraceEnter(TRACE_HANDLER, "CDsQuery::Initialize");
  408. // Keep the IQueryFrame interface, we need it for menu negotiation and other
  409. // view -> frame interactions.
  410. _pqf = pQueryFrame;
  411. _pqf->AddRef();
  412. _dwOQWFlags = dwOQWFlags;
  413. // If we have a parameter block then lets take copies of the interesting
  414. // fields from there.
  415. if (pDsQueryInitParams)
  416. {
  417. _dwFlags = pDsQueryInitParams->dwFlags;
  418. // did the user specify a default scope?
  419. if (pDsQueryInitParams->pDefaultScope && pDsQueryInitParams->pDefaultScope[0])
  420. {
  421. Trace(TEXT("Default scope:"), pDsQueryInitParams->pDefaultScope);
  422. hr = LocalAllocStringW(&_pDefaultScope, pDsQueryInitParams->pDefaultScope);
  423. FailGracefully(hr, "Failed to cope default scope");
  424. }
  425. // default save location?
  426. if ((_dwFlags & DSQPF_SAVELOCATION) && pDsQueryInitParams->pDefaultSaveLocation)
  427. {
  428. Trace(TEXT("Default save location:"), pDsQueryInitParams->pDefaultSaveLocation);
  429. hr = LocalAllocStringW(&_pDefaultSaveLocation, pDsQueryInitParams->pDefaultSaveLocation);
  430. FailGracefully(hr, "Failed to copy save location");
  431. }
  432. // do we have credential information?
  433. if (_dwFlags & DSQPF_HASCREDENTIALS)
  434. {
  435. TraceMsg("Copying credential/server information from init params");
  436. if (pDsQueryInitParams->pUserName)
  437. {
  438. hr = LocalAllocStringW(&_pUserName, pDsQueryInitParams->pUserName);
  439. FailGracefully(hr, "Failed to copy user name");
  440. }
  441. if (pDsQueryInitParams->pPassword)
  442. {
  443. hr = LocalAllocStringW(&_pPassword, pDsQueryInitParams->pPassword);
  444. FailGracefully(hr, "Failed to copy password");
  445. }
  446. if (pDsQueryInitParams->pServer)
  447. {
  448. hr = LocalAllocStringW(&_pServer, pDsQueryInitParams->pServer);
  449. FailGracefully(hr, "Failed to copy server");
  450. }
  451. Trace(TEXT("_pUserName : %s"), _pUserName ? _pUserName:TEXT("<not specified>"));
  452. Trace(TEXT("_pPassword : %s"), _pPassword ? _pPassword:TEXT("<not specified>"));
  453. Trace(TEXT("_pServer : %s"), _pServer ? _pServer:TEXT("<not specified>"));
  454. }
  455. }
  456. // Finally load the must structures that we are going to use, then modify them
  457. // based on the flags that the caller gave us.
  458. //
  459. // NB: removes the last two items from the file menu assumed to be the
  460. // "save" and its seperator
  461. _hFileMenu = LoadMenu(GLOBAL_HINSTANCE, MAKEINTRESOURCE(IDR_MENU_FILE));
  462. _hEditMenu = LoadMenu(GLOBAL_HINSTANCE, MAKEINTRESOURCE(IDR_MENU_EDIT));
  463. _hViewMenu = LoadMenu(GLOBAL_HINSTANCE, MAKEINTRESOURCE(IDR_MENU_VIEW));
  464. _hHelpMenu = LoadMenu(GLOBAL_HINSTANCE, MAKEINTRESOURCE(IDR_MENU_HELP));
  465. if (!_hFileMenu || !_hEditMenu || !_hViewMenu || !_hHelpMenu)
  466. ExitGracefully(hr, E_FAIL, "Failed to load resources for menus");
  467. if (_dwFlags & DSQPF_NOSAVE)
  468. {
  469. HMENU hFileMenu = GetSubMenu(_hFileMenu, 0);
  470. INT i = GetMenuItemCount(hFileMenu);
  471. DeleteMenu(hFileMenu, i-1, MF_BYPOSITION);
  472. DeleteMenu(hFileMenu, i-2, MF_BYPOSITION);
  473. }
  474. // Init ComCtl32, including checking to see if we can use the filter control or not,
  475. // the filter control was added to the WC_HEADER32 in IE5, so check the DLL version
  476. // to see which we are using.
  477. InitCommonControls();
  478. hInstanceComCtl32 = GetModuleHandle(TEXT("comctl32"));
  479. TraceAssert(hInstanceComCtl32);
  480. if (hInstanceComCtl32)
  481. {
  482. DLLVERSIONINFO dllVersionInfo = { 0 };
  483. DLLGETVERSIONPROC pfnDllGetVersion = (DLLGETVERSIONPROC)GetProcAddress(hInstanceComCtl32, "DllGetVersion");
  484. TraceAssert(pfnDllGetVersion);
  485. dllVersionInfo.cbSize = SIZEOF(dllVersionInfo);
  486. if (pfnDllGetVersion && SUCCEEDED(pfnDllGetVersion(&dllVersionInfo)))
  487. {
  488. Trace(TEXT("DllGetVersion succeeded on ComCtl32, dwMajorVersion %08x"), dllVersionInfo.dwMajorVersion);
  489. _fFilterSupported = dllVersionInfo.dwMajorVersion >= 5;
  490. }
  491. }
  492. Trace(TEXT("_fFilterSupported is %d"), _fFilterSupported);
  493. hr = S_OK; // success
  494. exit_gracefully:
  495. TraceLeaveResult(hr);
  496. }
  497. /*---------------------------------------------------------------------------*/
  498. STDMETHODIMP CDsQuery::GetViewInfo(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_FINDDS;
  505. pViewInfo->idSmallIcon = IDI_FINDDS;
  506. pViewInfo->idTitle = IDS_WINDOWTITLE;
  507. pViewInfo->idAnimation = IDR_DSFINDANIMATION;
  508. TraceLeaveResult(S_OK);
  509. }
  510. /*---------------------------------------------------------------------------*/
  511. STDMETHODIMP CDsQuery::AddScopes()
  512. {
  513. HRESULT hr;
  514. DWORD dwThreadId;
  515. HANDLE hThread;
  516. LPSCOPETHREADDATA pstd = NULL;
  517. TraceEnter(TRACE_HANDLER, "CDsQuery::AddScopes");
  518. // Enumerate the rest of the scopes on a seperate thread to gather the
  519. // scopes we are interested in.
  520. pstd = (LPSCOPETHREADDATA)LocalAlloc(LPTR, SIZEOF(SCOPETHREADDATA));
  521. TraceAssert(pstd);
  522. if (!pstd)
  523. ExitGracefully(hr, E_OUTOFMEMORY, "Failed to allocate scope data structure");
  524. _pqf->GetWindow(&pstd->hwndFrame);
  525. // pstd->pDefaultScope = NULL;
  526. // pstd->pServer = NULL; // no credential stuff currently
  527. // pstd->pUserName = NULL;
  528. // pstd->pPassword = NULL;
  529. if (_pDefaultScope)
  530. {
  531. hr = LocalAllocStringW(&pstd->pDefaultScope, _pDefaultScope);
  532. FailGracefully(hr, "Failed to copy the default scope");
  533. }
  534. hr = _CopyCredentials(&pstd->pUserName, &pstd->pPassword, &pstd->pServer);
  535. FailGracefully(hr, "Failed to copy credentails");
  536. DllAddRef();
  537. hThread = CreateThread(NULL, 0, AddScopesThread, pstd, 0, &dwThreadId);
  538. TraceAssert(hThread);
  539. if (!hThread)
  540. {
  541. DllRelease();
  542. ExitGracefully(hr, E_FAIL, "Failed to create background thread to enum scopes - BAD!");
  543. }
  544. CloseHandle(hThread);
  545. hr = S_OK;
  546. exit_gracefully:
  547. if (FAILED(hr) && pstd)
  548. {
  549. LocalFreeStringW(&pstd->pDefaultScope);
  550. LocalFree((HLOCAL)pstd);
  551. }
  552. TraceLeaveResult(hr);
  553. }
  554. /*---------------------------------------------------------------------------*/
  555. typedef struct
  556. {
  557. IADsPathname *padp;
  558. WCHAR szGcPath[MAX_PATH];
  559. } BROWSEFORSCOPE;
  560. int CALLBACK CDsQuery::s_BrowseForScopeCB(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
  561. {
  562. HRESULT hr;
  563. INT iResult = 0;
  564. BROWSEFORSCOPE *pbfs = (BROWSEFORSCOPE*)lpData;
  565. LPTSTR pDirectoryName = NULL;
  566. TraceEnter(TRACE_HANDLER, "CDsQuery::s_BrowseForScopeCB");
  567. switch (uMsg)
  568. {
  569. case DSBM_QUERYINSERT:
  570. {
  571. PDSBITEM pItem = (PDSBITEM)lParam;
  572. TraceAssert(pItem);
  573. // We are interested in modifying the root item of the tree, therefore
  574. // lets check for that being inserted, if it is then we change the
  575. // display name and the icon being shown.
  576. if (pItem->dwState & DSBS_ROOT)
  577. {
  578. GetModuleFileName(GLOBAL_HINSTANCE, pItem->szIconLocation, ARRAYSIZE(pItem->szIconLocation));
  579. pItem->iIconResID = -IDI_GLOBALCATALOG;
  580. if (SUCCEEDED(FormatDirectoryName(&pDirectoryName, GLOBAL_HINSTANCE, IDS_GLOBALCATALOG)))
  581. {
  582. StrCpyN(pItem->szDisplayName, pDirectoryName, ARRAYSIZE(pItem->szDisplayName));
  583. LocalFreeString(&pDirectoryName);
  584. }
  585. pItem->dwMask |= DSBF_DISPLAYNAME|DSBF_ICONLOCATION;
  586. iResult = TRUE;
  587. }
  588. break;
  589. }
  590. case BFFM_SELCHANGED:
  591. {
  592. BOOL fEnableOK = TRUE;
  593. LPWSTR pszPath = (LPWSTR)lParam;
  594. LONG nElements = 0;
  595. // The user changes the selection in the browse dialog, therefore
  596. // lets see if we should be enabling the OK button. If the user
  597. // selects GC, but we don't have a GC then we disable it.
  598. if (SUCCEEDED(pbfs->padp->Set(CComBSTR(pszPath), ADS_SETTYPE_FULL)))
  599. {
  600. pbfs->padp->GetNumElements(&nElements);
  601. Trace(TEXT("nElements on exit from GetNumElements %d"), nElements);
  602. }
  603. if (!nElements && !pbfs->szGcPath[0])
  604. {
  605. TraceMsg("'entire directory' selected with NO GC!");
  606. fEnableOK = FALSE;
  607. }
  608. SendMessage(hwnd, BFFM_ENABLEOK, (WPARAM)fEnableOK, 0L);
  609. break;
  610. }
  611. case DSBM_HELP:
  612. {
  613. WinHelp((HWND)((LPHELPINFO)lParam)->hItemHandle,
  614. DSQUERY_HELPFILE,
  615. HELP_WM_HELP,
  616. (DWORD_PTR)aBrowseHelpIDs);
  617. break;
  618. }
  619. case DSBM_CONTEXTMENU:
  620. {
  621. WinHelp((HWND)lParam,
  622. DSQUERY_HELPFILE,
  623. HELP_CONTEXTMENU,
  624. (DWORD_PTR)aBrowseHelpIDs);
  625. break;
  626. }
  627. }
  628. TraceLeaveValue(iResult);
  629. }
  630. STDMETHODIMP CDsQuery::BrowseForScope(HWND hwndParent, LPCQSCOPE pCurrentScope, LPCQSCOPE* ppScope)
  631. {
  632. HRESULT hr;
  633. LPDSQUERYSCOPE pDsQueryScope = (LPDSQUERYSCOPE)pCurrentScope;
  634. BROWSEFORSCOPE bfs = { 0 };
  635. DSBROWSEINFO dsbi = { 0 };
  636. INT iResult;
  637. WCHAR szPath[2048];
  638. WCHAR szRoot[MAX_PATH+10]; // LDAP://
  639. WCHAR szObjectClass[64];
  640. TraceEnter(TRACE_HANDLER, "CDsQuery::BrowseForScope");
  641. Trace(TEXT("hwndParent %08x, pCurrentScope %08x, ppScope %08x"), hwndParent, pCurrentScope, ppScope);
  642. *ppScope = NULL; // nothing yet!
  643. if (SUCCEEDED(GetGlobalCatalogPath(_pServer, bfs.szGcPath, ARRAYSIZE(bfs.szGcPath))))
  644. Trace(TEXT("GC path is: %s"), bfs.szGcPath);
  645. hr = CoCreateInstance(CLSID_Pathname, NULL, CLSCTX_INPROC_SERVER, IID_IADsPathname, (void **)&bfs.padp);
  646. FailGracefully(hr, "Failed to get the IADsPathname interface");
  647. // Fill out the browse info structure to display the object picker, if we have
  648. // enabled admin features then lets make all objects visible, otherwise
  649. // just the standard features.
  650. dsbi.cbStruct = SIZEOF(dsbi);
  651. dsbi.hwndOwner = hwndParent;
  652. dsbi.pszRoot = szRoot;
  653. dsbi.pszPath = szPath;
  654. dsbi.cchPath = ARRAYSIZE(szPath);
  655. dsbi.dwFlags = (DSBI_RETURNOBJECTCLASS|DSBI_EXPANDONOPEN|DSBI_ENTIREDIRECTORY) & ~DSBI_NOROOT;
  656. dsbi.pfnCallback = s_BrowseForScopeCB;
  657. dsbi.lParam = (LPARAM)&bfs;
  658. dsbi.pszObjectClass = szObjectClass;
  659. dsbi.cchObjectClass = ARRAYSIZE(szObjectClass);
  660. if (_dwFlags & DSQPF_SHOWHIDDENOBJECTS)
  661. dsbi.dwFlags |= DSBI_INCLUDEHIDDEN;
  662. FormatMsgResource((LPTSTR*)&dsbi.pszTitle, GLOBAL_HINSTANCE, IDS_BROWSEPROMPT);
  663. // NTRAID#NTBUG9-554905-2002/02/20-lucios. Pending fix.
  664. StrCpyW(szRoot, c_szLDAP);
  665. if (_pServer)
  666. {
  667. if (lstrlenW(_pServer) > MAX_PATH)
  668. ExitGracefully(hr, E_INVALIDARG, "_pServer is too big");
  669. // NTRAID#NTBUG9-554905-2002/02/20-lucios. Pending fix.
  670. StrCatW(szRoot, L"//");
  671. StrCatW(szRoot, _pServer);
  672. }
  673. if (pDsQueryScope)
  674. {
  675. //REVIEWED-2002-02-25-lucios.
  676. StrCpyNW(szPath, OBJECT_NAME_FROM_SCOPE(pDsQueryScope), ARRAYSIZE(szPath));
  677. Trace(TEXT("pDsQueryScope: %s"), szPath);
  678. }
  679. // copy the credential information if needed
  680. if (_dwFlags & DSQPF_HASCREDENTIALS)
  681. {
  682. TraceMsg("Setting credentails information");
  683. dsbi.pUserName = _pUserName;
  684. dsbi.pPassword = _pPassword;
  685. dsbi.dwFlags |= DSBI_HASCREDENTIALS;
  686. }
  687. iResult = DsBrowseForContainer(&dsbi);
  688. Trace(TEXT("DsBrowseForContainer returns %d"), iResult);
  689. // iResult == IDOK if something was selected (szPath),
  690. // if it is -VE if the call failed and we should error
  691. if (iResult == IDOK)
  692. {
  693. LPWSTR pszScope = szPath;
  694. LPWSTR pszObjectClass = szObjectClass;
  695. LONG nElements = 0;
  696. Trace(TEXT("Path on exit from DsBrowseForContainer: %s"), szPath);
  697. // does this look like the GC? If so then default to it, as DsBrowseForContainer
  698. // will return us iffy looking information
  699. if (SUCCEEDED(bfs.padp->Set(CComBSTR(szPath), ADS_SETTYPE_FULL)))
  700. {
  701. bfs.padp->GetNumElements(&nElements);
  702. Trace(TEXT("nElements on exit from GetNumElements %d"), nElements);
  703. }
  704. if (!nElements)
  705. {
  706. TraceMsg("nElements = 0, so defaulting to GC");
  707. pszScope = bfs.szGcPath;
  708. pszObjectClass = GC_OBJECTCLASS;
  709. }
  710. Trace(TEXT("Scope selected is: %s, Object class: %s"), pszScope, pszObjectClass);
  711. hr = AllocScope(ppScope, 0, pszScope, pszObjectClass);
  712. FailGracefully(hr, "Failed converting the DS path to a scope");
  713. }
  714. else if (iResult == IDCANCEL)
  715. {
  716. hr = S_FALSE; // nothing selected, returning S_FALSE;
  717. }
  718. else if (iResult < 0)
  719. {
  720. ExitGracefully(hr, E_FAIL, "DsBrowseForContainer failed");
  721. }
  722. exit_gracefully:
  723. LocalFreeString((LPTSTR*)&dsbi.pszTitle);
  724. Trace(TEXT("*ppScope == %08x"), *ppScope);
  725. DoRelease(bfs.padp);
  726. TraceLeaveResult(hr);
  727. }
  728. /*---------------------------------------------------------------------------*/
  729. //
  730. // WndProc for the banner window
  731. //
  732. LRESULT CALLBACK CDsQuery::s_BannerWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  733. {
  734. LRESULT lResult = 0;
  735. switch (uMsg)
  736. {
  737. case WM_SIZE:
  738. InvalidateRect(hwnd, NULL, FALSE);
  739. break;
  740. case WM_ERASEBKGND:
  741. break;
  742. case WM_PAINT:
  743. {
  744. TCHAR szBuffer[MAX_PATH];
  745. HFONT hFont, hOldFont;
  746. SIZE szText;
  747. RECT rcClient;
  748. INT len;
  749. PAINTSTRUCT paint;
  750. COLORREF oldFgColor, oldBkColor;
  751. BeginPaint(hwnd, &paint);
  752. hFont = (HFONT)SendMessage(GetParent(hwnd), WM_GETFONT, 0, 0L);
  753. hOldFont = (HFONT)SelectObject(paint.hdc, hFont);
  754. if (hOldFont)
  755. {
  756. oldFgColor = SetTextColor(paint.hdc, GetSysColor(COLOR_WINDOWTEXT));
  757. oldBkColor = SetBkColor(paint.hdc, ListView_GetBkColor(GetParent(hwnd)));
  758. len = GetWindowText(hwnd, szBuffer, ARRAYSIZE(szBuffer));
  759. GetTextExtentPoint32(paint.hdc, szBuffer, len, &szText);
  760. GetClientRect(GetParent(hwnd), &rcClient);
  761. ExtTextOut(paint.hdc,
  762. (rcClient.right - szText.cx) / 2,
  763. GetSystemMetrics(SM_CYBORDER)*4,
  764. ETO_CLIPPED|ETO_OPAQUE, &rcClient,
  765. szBuffer, len,
  766. NULL);
  767. SetTextColor(paint.hdc, oldFgColor);
  768. SetBkColor(paint.hdc, oldBkColor);
  769. SelectObject(paint.hdc, hOldFont);
  770. }
  771. EndPaint(hwnd, &paint);
  772. break;
  773. }
  774. case WM_SETTEXT:
  775. {
  776. InvalidateRect(hwnd, NULL, FALSE);
  777. //break; // deliberate drop through..
  778. }
  779. default:
  780. lResult = DefWindowProc(hwnd, uMsg, wParam, lParam);
  781. break;
  782. }
  783. return lResult;
  784. }
  785. //
  786. // WndProc for the bg window (lives behind list view, used by rest of the world)
  787. //
  788. LRESULT CALLBACK CDsQuery::s_ResultViewWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  789. {
  790. LRESULT lResult = 0;
  791. CDsQuery* pDsQuery = NULL;
  792. if (uMsg == WM_CREATE)
  793. {
  794. pDsQuery = (CDsQuery*)((LPCREATESTRUCT)lParam)->lpCreateParams;
  795. SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pDsQuery);
  796. }
  797. else
  798. {
  799. pDsQuery = (CDsQuery*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
  800. switch (uMsg)
  801. {
  802. case WM_SIZE:
  803. pDsQuery->OnSize(LOWORD(lParam), HIWORD(lParam));
  804. return(0);
  805. case WM_DESTROY:
  806. pDsQuery->_hwndView = NULL; // view is gone!
  807. break;
  808. case WM_NOTIFY:
  809. return(pDsQuery->OnNotify(hwnd, wParam, lParam));
  810. case WM_SETFOCUS:
  811. SetFocus(pDsQuery->_hwndView);
  812. break;
  813. case WM_GETDLGCODE:
  814. return ((LRESULT)(DLGC_WANTARROWS | DLGC_WANTCHARS));
  815. case WM_CONTEXTMENU:
  816. pDsQuery->OnContextMenu(NULL, lParam);
  817. return TRUE;
  818. case DSQVM_ADDRESULTS:
  819. return SUCCEEDED(pDsQuery->OnAddResults((DWORD)wParam, (HDPA)lParam));
  820. case DSQVM_FINISHED:
  821. if ((DWORD)wParam == pDsQuery->_dwQueryReference)
  822. {
  823. // the references match so lets finish the query, and display
  824. // the "too many results" prompt if the user did a really
  825. // big query and we chopped them off
  826. pDsQuery->StopQuery();
  827. if (lParam) // == 0 then we are OK!
  828. {
  829. HWND hwndFrame;
  830. pDsQuery->_pqf->GetWindow(&hwndFrame);
  831. FormatMsgBox(GetParent(hwndFrame),
  832. GLOBAL_HINSTANCE, IDS_WINDOWTITLE, IDS_ERR_MAXRESULT,
  833. MB_OK|MB_ICONERROR);
  834. }
  835. }
  836. SetFocus(pDsQuery->_hwndView);
  837. return(1);
  838. }
  839. }
  840. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  841. }
  842. STDMETHODIMP CDsQuery::CreateResultView(HWND hwndParent, HWND* phWndView)
  843. {
  844. HRESULT hr;
  845. WNDCLASS wc;
  846. HWND hwndFilter, hwndFilterOld;
  847. HIMAGELIST himlSmall, himlLarge;
  848. DWORD dwLVStyle = LVS_AUTOARRANGE|LVS_SHAREIMAGELISTS|LVS_SHOWSELALWAYS|LVS_REPORT;
  849. RECT rc;
  850. TraceEnter(TRACE_HANDLER, "CDsQuery::CreateResultView");
  851. if (IsWindow(_hwnd))
  852. ExitGracefully(hr, E_FAIL, "Can only create one view at a time");
  853. // Create our result viewer, this is the parent window to the ListView
  854. // that we attach when we issue the query.
  855. ZeroMemory(&wc, SIZEOF(wc));
  856. wc.lpfnWndProc = s_ResultViewWndProc;
  857. wc.hInstance = GLOBAL_HINSTANCE;
  858. wc.lpszClassName = VIEW_CLASS;
  859. RegisterClass(&wc);
  860. _hwnd = CreateWindow(VIEW_CLASS,
  861. NULL,
  862. WS_TABSTOP|WS_CLIPCHILDREN|WS_CHILD|WS_VISIBLE,
  863. 0, 0, 0, 0,
  864. hwndParent,
  865. NULL,
  866. GLOBAL_HINSTANCE,
  867. this);
  868. if (!_hwnd)
  869. ExitGracefully(hr, E_FAIL, "Failed to create view parent window");
  870. // Now register the window classes we are using.
  871. ZeroMemory(&wc, SIZEOF(wc));
  872. wc.lpfnWndProc = s_BannerWndProc;
  873. wc.hInstance = GLOBAL_HINSTANCE;
  874. wc.lpszClassName = BANNER_CLASS;
  875. RegisterClass(&wc);
  876. if (_dwOQWFlags & OQWF_SINGLESELECT)
  877. dwLVStyle |= LVS_SINGLESEL;
  878. GetClientRect(_hwnd, &rc);
  879. _hwndView = CreateWindowEx(WS_EX_CLIENTEDGE,
  880. WC_LISTVIEW,
  881. NULL,
  882. WS_TABSTOP|WS_CLIPCHILDREN|WS_CHILD|WS_VISIBLE|dwLVStyle,
  883. 0, 0,
  884. rc.right, rc.bottom,
  885. _hwnd,
  886. (HMENU)IDC_RESULTS,
  887. GLOBAL_HINSTANCE,
  888. NULL);
  889. if (!_hwndView)
  890. ExitGracefully(hr, E_FAIL, "Failed to create the view window");
  891. ListView_SetExtendedListViewStyle(_hwndView, LVS_EX_FULLROWSELECT|LVS_EX_LABELTIP);
  892. Shell_GetImageLists(&himlLarge, &himlSmall);
  893. ListView_SetImageList(_hwndView, himlLarge, LVSIL_NORMAL);
  894. ListView_SetImageList(_hwndView, himlSmall, LVSIL_SMALL);
  895. // Create the banner window, this is a child of the ListView, it is used to display
  896. // information about the query being issued
  897. _hwndBanner = CreateWindow(BANNER_CLASS, NULL,
  898. WS_CHILD,
  899. 0, 0, 0, 0, // nb: size fixed later
  900. _hwndView,
  901. (HMENU)IDC_STATUS,
  902. GLOBAL_HINSTANCE,
  903. NULL);
  904. if (!_hwndBanner)
  905. ExitGracefully(hr, E_FAIL, "Failed to create the static banner window");
  906. _SetFilter(_fFilter);
  907. _SetViewMode(_idViewMode);
  908. _ShowBanner(SWP_SHOWWINDOW, IDS_INITALIZING);
  909. hr = S_OK; // success
  910. exit_gracefully:
  911. if (SUCCEEDED(hr))
  912. *phWndView = _hwnd;
  913. TraceLeaveResult(hr);
  914. }
  915. /*---------------------------------------------------------------------------*/
  916. #define MGW_EDIT 2
  917. STDMETHODIMP CDsQuery::ActivateView(UINT uState, WPARAM wParam, LPARAM lParam)
  918. {
  919. HRESULT hr;
  920. HWND hwnd;
  921. INT i;
  922. TraceEnter(TRACE_HANDLER, "CDsQuery::ActivateView");
  923. switch (uState)
  924. {
  925. case CQRVA_ACTIVATE:
  926. {
  927. HMENU hMenu;
  928. OLEMENUGROUPWIDTHS omgw = { 0, 0, 0, 0, 0, 0 };
  929. // Allow the cframe to merge its menus into our menu bar before we
  930. // add ours to it.
  931. if (!(hMenu = CreateMenu()))
  932. ExitGracefully(hr, E_FAIL, "Failed to create a base menu bar to be used");
  933. hr = _pqf->InsertMenus(hMenu, &omgw);
  934. FailGracefully(hr, "Failed when calling CQueryFrame::InsertMenus");
  935. Shell_MergeMenus(GetSubMenu(hMenu, 0), GetSubMenu(_hFileMenu, 0), 0x0, 0x0, 0x7fff, 0);
  936. MergeMenu(hMenu, _hEditMenu, omgw.width[0]);
  937. MergeMenu(hMenu, _hViewMenu, omgw.width[0]+1);
  938. MergeMenu(hMenu, _hHelpMenu, omgw.width[0]+MGW_EDIT+omgw.width[2]+omgw.width[4]);
  939. if (_dwOQWFlags & OQWF_SINGLESELECT)
  940. {
  941. ENABLE_MENU_ITEM(hMenu, DSQH_EDIT_SELECTALL, FALSE);
  942. ENABLE_MENU_ITEM(hMenu, DSQH_EDIT_INVERTSELECTION, FALSE);
  943. }
  944. hr = _pqf->SetMenu(hMenu, NULL); // set the frames menu bar
  945. FailGracefully(hr, "Failed when calling CQueryFrame::SetMenu");
  946. break;
  947. }
  948. case CQRVA_INITMENUBAR:
  949. {
  950. // we recieve a CQRVA_INITMENUBAR before the popup so that we can store the
  951. // menu bar information, and invalidate an interface pointers we maybe holding
  952. // onto.
  953. Trace(TEXT("Received an CQRVA_INITMENUBAR, hMenu %08x"), wParam);
  954. _hFrameMenuBar = (HMENU)wParam;
  955. DoRelease(_pcm);
  956. break;
  957. }
  958. case CQRVA_INITMENUBARPOPUP:
  959. {
  960. HMENU hFileMenu;
  961. BOOL fDeleteItems = FALSE;
  962. TraceMsg("Received an CQRVA_INITMENUBARPOPUP");
  963. hFileMenu = GetSubMenu(_hFrameMenuBar, 0);
  964. // if we have a view then lets try and collect the selection from it,
  965. // having done that we can merge the verbs for that selection into the
  966. // views "File" menu.
  967. if ((hFileMenu == (HMENU)wParam) && !_pcm)
  968. {
  969. _fNoSelection = TRUE; // no selection currenlty
  970. if (IsWindow(_hwndView))
  971. {
  972. for (i = GetMenuItemCount(hFileMenu) - 1; i >= 0 ; i--)
  973. {
  974. if (!fDeleteItems && (GetMenuItemID(hFileMenu, i) == DSQH_FILE_PROPERTIES))
  975. {
  976. Trace(TEXT("Setting fDeleteItems true on index %d"), i);
  977. fDeleteItems = TRUE;
  978. }
  979. else
  980. {
  981. if (fDeleteItems)
  982. DeleteMenu(hFileMenu, i, MF_BYPOSITION);
  983. }
  984. }
  985. // Collect the selection, and using that construct an IContextMenu interface, if that works
  986. // then we can merge in the verbs that relate to this object.
  987. hr = _GetContextMenu();
  988. FailGracefully(hr, "Failed when calling _GetAndViewObject");
  989. if (ListView_GetSelectedCount(_hwndView) > 0)
  990. {
  991. _GetContextMenuVerbs(hFileMenu, CMF_VERBSONLY);
  992. _fNoSelection = FALSE;
  993. }
  994. }
  995. }
  996. // 211991 11/6/00 JonN and DavidDv
  997. // choose columns is disabled if there are no columns to show/the user has marked for disabled
  998. ENABLE_MENU_ITEM(_hFrameMenuBar, DSQH_VIEW_PICKCOLUMNS,
  999. IsWindow(_hwndView) && _hdsaColumns && (!(_dwFlags & DSQPF_NOCHOOSECOLUMNS)));
  1000. ENABLE_MENU_ITEM(_hFrameMenuBar, DSQH_VIEW_REFRESH, IsWindow(_hwndView) && _dwThreadId);
  1001. _InitViewMenuItems(_hFrameMenuBar);
  1002. break;
  1003. }
  1004. case CQRVA_FORMCHANGED:
  1005. {
  1006. // we receieve a form change, we store the form name as we will use it
  1007. // as the default name for saved queries authored by the user.
  1008. Trace(TEXT("Form '%s' selected"), (LPTSTR)lParam);
  1009. LocalFreeString(&_pDefaultSaveName);
  1010. hr = LocalAllocString(&_pDefaultSaveName, (LPCTSTR)lParam);
  1011. FailGracefully(hr, "Failed to set the default save name");
  1012. break;
  1013. }
  1014. case CQRVA_STARTQUERY:
  1015. {
  1016. Trace(TEXT("Query is: %s"), wParam ? TEXT("starting"):TEXT("stopping"));
  1017. break;
  1018. }
  1019. case CQRVA_HELP:
  1020. {
  1021. LPHELPINFO pHelpInfo = (LPHELPINFO)lParam;
  1022. TraceAssert(pHelpInfo)
  1023. TraceMsg("Invoking help on the objects in the windows");
  1024. WinHelp((HWND)pHelpInfo->hItemHandle, DSQUERY_HELPFILE, HELP_WM_HELP, (DWORD_PTR)aHelpIDs);
  1025. break;
  1026. }
  1027. case CQRVA_CONTEXTMENU:
  1028. {
  1029. HWND hwndForHelp = (HWND)wParam;
  1030. Trace(TEXT("CQRVA_CONTEXTMENU recieved on the bg of the frame %d"), GetDlgCtrlID(hwndForHelp));
  1031. WinHelp(hwndForHelp, DSQUERY_HELPFILE, HELP_CONTEXTMENU, (DWORD_PTR)aHelpIDs);
  1032. break;
  1033. }
  1034. }
  1035. hr = S_OK;
  1036. exit_gracefully:
  1037. TraceLeaveResult(hr);
  1038. }
  1039. /*---------------------------------------------------------------------------*/
  1040. STDMETHODIMP CDsQuery::InvokeCommand(HWND hwndParent, UINT uID)
  1041. {
  1042. HRESULT hr = S_OK;
  1043. HWND hwndFrame;
  1044. DECLAREWAITCURSOR;
  1045. TraceEnter(TRACE_HANDLER, "CDsQuery::InvokeCommand");
  1046. Trace(TEXT("hwndParent %08x, uID %d"), hwndParent, uID);
  1047. SetWaitCursor();
  1048. switch (uID)
  1049. {
  1050. case DSQH_BG_SELECT:
  1051. SendMessage(hwndParent, WM_COMMAND, IDOK, 0);
  1052. break;
  1053. case DSQH_FILE_PROPERTIES:
  1054. hr = OnFileProperties();
  1055. break;
  1056. case DSQH_FILE_SAVEQUERY:
  1057. hr = OnFileSaveQuery();
  1058. break;
  1059. case DSQH_EDIT_SELECTALL:
  1060. hr = OnEditSelectAll();
  1061. break;
  1062. case DSQH_EDIT_INVERTSELECTION:
  1063. hr = OnEditInvertSelection();
  1064. break;
  1065. case DSQH_VIEW_FILTER:
  1066. _SetFilter(!_fFilter);
  1067. break;
  1068. case DSQH_VIEW_LARGEICONS:
  1069. case DSQH_VIEW_SMALLICONS:
  1070. case DSQH_VIEW_LIST:
  1071. case DSQH_VIEW_DETAILS:
  1072. _SetViewMode(uID);
  1073. break;
  1074. case DSQH_VIEW_REFRESH:
  1075. {
  1076. if (IsWindow(_hwndView) && _dwThreadId)
  1077. {
  1078. _InitNewQuery(NULL, FALSE);
  1079. PostThreadMessage(_dwThreadId, RVTM_REFRESH, _dwQueryReference, 0L);
  1080. }
  1081. break;
  1082. }
  1083. case DSQH_VIEW_PICKCOLUMNS:
  1084. {
  1085. TraceAssert(_hdsaColumns);
  1086. OnPickColumns(hwndParent);
  1087. break;
  1088. }
  1089. case DSQH_HELP_CONTENTS:
  1090. {
  1091. TraceMsg("Calling for to display help topics");
  1092. _pqf->GetWindow(&hwndFrame);
  1093. _pqf->CallForm(NULL, DSQPM_HELPTOPICS, 0, (LPARAM)hwndFrame);
  1094. break;
  1095. }
  1096. case DSQH_HELP_WHATISTHIS:
  1097. _pqf->GetWindow(&hwndFrame);
  1098. SendMessage(hwndFrame, WM_SYSCOMMAND, SC_CONTEXTHELP, MAKELPARAM(0,0));
  1099. break;
  1100. default:
  1101. {
  1102. // if it looks like a sort request then lets handle it, otherwise attempt
  1103. // to send to the context menu handler we may have at htis poiunt.
  1104. if ((uID >= DSQH_VIEW_ARRANGEFIRST) && (uID < DSQH_VIEW_ARRANGELAST))
  1105. {
  1106. TraceAssert(_hdsaColumns);
  1107. if (_hdsaColumns)
  1108. {
  1109. Trace(TEXT("Calling _SortResults for column %d"), uID - DSQH_VIEW_ARRANGEFIRST);
  1110. _SortResults(uID - DSQH_VIEW_ARRANGEFIRST);
  1111. }
  1112. }
  1113. else if (_pcm)
  1114. {
  1115. CMINVOKECOMMANDINFO ici;
  1116. ici.cbSize = SIZEOF(ici);
  1117. ici.fMask = 0;
  1118. _pqf->GetWindow(&ici.hwnd);
  1119. ici.lpVerb = (LPCSTR)IntToPtr(uID - DSQH_FILE_CONTEXT_FIRST);
  1120. ici.lpParameters = NULL;
  1121. ici.lpDirectory = NULL;
  1122. ici.nShow = SW_NORMAL;
  1123. ici.dwHotKey = 0;
  1124. ici.hIcon = NULL;
  1125. hr = _pcm->InvokeCommand(&ici);
  1126. FailGracefully(hr, "Failed when calling IContextMenu::InvokeCommand");
  1127. DoRelease(_pcm); // no longer needed
  1128. }
  1129. break;
  1130. }
  1131. }
  1132. exit_gracefully:
  1133. ResetWaitCursor();
  1134. TraceLeaveResult(hr);
  1135. }
  1136. /*---------------------------------------------------------------------------*/
  1137. STDMETHODIMP CDsQuery::GetCommandString(UINT uID, DWORD dwFlags, LPTSTR pBuffer, INT cchBuffer)
  1138. {
  1139. HRESULT hr;
  1140. TCHAR szBuffer[MAX_PATH];
  1141. TraceEnter(TRACE_HANDLER, "CDsQuery::GetCommandString");
  1142. Trace(TEXT("uID %08x, dwFlags %08x, pBuffer %08x, cchBuffer %d"), uID, dwFlags, pBuffer, cchBuffer);
  1143. if ((uID >= DSQH_FILE_CONTEXT_FIRST) && (uID < DSQH_FILE_CONTEXT_LAST))
  1144. {
  1145. if (_pcm)
  1146. {
  1147. TraceMsg("Trying the IContextMenu::GetCommandString");
  1148. hr = _pcm->GetCommandString((uID - DSQH_FILE_CONTEXT_FIRST), GCS_HELPTEXT, NULL, (LPSTR)pBuffer, cchBuffer);
  1149. FailGracefully(hr, "Failed when asking for help text from IContextMenu iface");
  1150. }
  1151. }
  1152. else
  1153. {
  1154. if ((uID >= DSQH_VIEW_ARRANGEFIRST) && (uID < DSQH_VIEW_ARRANGELAST))
  1155. {
  1156. INT iColumn = uID-DSQH_VIEW_ARRANGEFIRST;
  1157. TCHAR szFmt[MAX_PATH];
  1158. Trace(TEXT("Get command text for column %d"), iColumn);
  1159. if (_hdsaColumns && (iColumn < DSA_GetItemCount(_hdsaColumns)))
  1160. {
  1161. LPCOLUMN pColumn = (LPCOLUMN)DSA_GetItemPtr(_hdsaColumns, iColumn);
  1162. TraceAssert(pColumn);
  1163. LoadString(GLOBAL_HINSTANCE, IDS_ARRANGEBY_HELP, szFmt, ARRAYSIZE(szFmt));
  1164. // NTRAID#NTBUG9-554458-2002/02/20-lucios. Pending fix.
  1165. wsprintf(pBuffer, szFmt, pColumn->pHeading);
  1166. Trace(TEXT("Resulting string is: %s"), pBuffer);
  1167. }
  1168. }
  1169. else
  1170. {
  1171. if (!LoadString(GLOBAL_HINSTANCE, uID, pBuffer, cchBuffer))
  1172. ExitGracefully(hr, E_FAIL, "Failed to load the command text for this verb");
  1173. }
  1174. }
  1175. hr = S_OK;
  1176. exit_gracefully:
  1177. TraceLeaveResult(hr);
  1178. }
  1179. /*---------------------------------------------------------------------------*/
  1180. STDMETHODIMP CDsQuery::IssueQuery(LPCQPARAMS pQueryParams)
  1181. {
  1182. HRESULT hr;
  1183. LPTHREADINITDATA ptid = NULL;
  1184. LPDSQUERYSCOPE pDsQueryScope = (LPDSQUERYSCOPE)pQueryParams->pQueryScope;
  1185. LPDSQUERYPARAMS pDsQueryParams = (LPDSQUERYPARAMS)pQueryParams->pQueryParameters;
  1186. LPTSTR pBuffer = NULL;
  1187. MSG msg;
  1188. TraceEnter(TRACE_HANDLER, "CDsQuery::IssueQuery");
  1189. Trace(TEXT("pQueryParams %08x, pDsQueryScope %08x, pDsQueryParams %08x"), pQueryParams, pDsQueryScope, pDsQueryParams);
  1190. // Persist the existing column information if there was some, then
  1191. // get the new column table initialized and the columns added to the
  1192. // view
  1193. if (_hdsaColumns)
  1194. {
  1195. if (_fColumnsModified)
  1196. {
  1197. _SaveColumnTable(_clsidForm, _hdsaColumns);
  1198. _fColumnsModified = FALSE;
  1199. }
  1200. _SaveColumnTable();
  1201. }
  1202. // Initialize the view with items
  1203. _clsidForm = pQueryParams->clsidForm; // keep the form ID (for persistance)
  1204. hr = _InitNewQuery(pDsQueryParams, TRUE);
  1205. FailGracefully(hr, "Failed to initialize the new query");
  1206. // Now build the thread information needed to get the thread
  1207. // up and running.
  1208. ptid = (LPTHREADINITDATA)LocalAlloc(LPTR, SIZEOF(THREADINITDATA));
  1209. TraceAssert(ptid);
  1210. if (!ptid)
  1211. ExitGracefully(hr, E_OUTOFMEMORY, "Failed to allocate THREADINITDATA");
  1212. ptid->dwReference = _dwQueryReference;
  1213. //ptid->hwndView = NULL;
  1214. //ptid->pQuery = NULL;
  1215. //ptid->pScope = NULL;
  1216. //ptid->hdsaColumns = NULL;
  1217. //ptid->fShowHidden = FALSE;
  1218. //ptid->pServer = NULL;
  1219. //ptid->pUserName = NULL;
  1220. //ptid->pPassword = NULL;
  1221. Trace(TEXT("_dwFlags %08x (& DSQPF_SHOWHIDDENOBJECTS)"), _dwFlags, _dwFlags & DSQPF_SHOWHIDDENOBJECTS);
  1222. ptid->fShowHidden = (_dwFlags & DSQPF_SHOWHIDDENOBJECTS) ? 1:0;
  1223. ptid->hwndView = _hwndView;
  1224. hr = _GetColumnTable(_clsidForm, pDsQueryParams, &ptid->hdsaColumns, FALSE);
  1225. FailGracefully(hr, "Failed to create column DSA");
  1226. hr = LocalAllocStringW(&ptid->pQuery, (LPWSTR)ByteOffset(pDsQueryParams, pDsQueryParams->offsetQuery));
  1227. FailGracefully(hr, "Failed to copy query filter string");
  1228. hr = LocalAllocStringW(&ptid->pScope, OBJECT_NAME_FROM_SCOPE(pDsQueryScope));
  1229. FailGracefully(hr, "Failed to copy scope to thread init data");
  1230. hr = _CopyCredentials(&ptid->pUserName, &ptid->pPassword, &ptid->pServer);
  1231. FailGracefully(hr, "Failed to copy credentails");
  1232. // now create the thread that is going to perform the query, this includes
  1233. // telling the previous one that it needs to close down
  1234. if (_hThread && _dwThreadId)
  1235. {
  1236. Trace(TEXT("Killing old query thread %08x, ID %d"), _hThread, _dwThreadId);
  1237. PostThreadMessage(_dwThreadId, RVTM_STOPQUERY, 0, 0);
  1238. PostThreadMessage(_dwThreadId, WM_QUIT, 0, 0);
  1239. CloseHandle(_hThread);
  1240. _hThread = NULL;
  1241. _dwThreadId = 0;
  1242. }
  1243. DllAddRef();
  1244. _hThread = CreateThread(NULL, 0, QueryThread, ptid, 0, &_dwThreadId);
  1245. TraceAssert(_hThread);
  1246. if (!_hThread)
  1247. {
  1248. DllRelease();
  1249. ExitGracefully(hr, E_FAIL, "Failed to create background thread - BAD!");
  1250. }
  1251. hr = S_OK; // success
  1252. exit_gracefully:
  1253. if (SUCCEEDED(hr) && IsWindow(_hwndView))
  1254. SetFocus(_hwndView);
  1255. if (FAILED(hr))
  1256. {
  1257. QueryThread_FreeThreadInitData(&ptid);
  1258. _pqf->StartQuery(FALSE);
  1259. }
  1260. TraceLeaveResult(hr);
  1261. }
  1262. /*---------------------------------------------------------------------------*/
  1263. STDMETHODIMP CDsQuery::StopQuery()
  1264. {
  1265. HRESULT hr;
  1266. INT cResults = _hdpaResults ? DPA_GetPtrCount(_hdpaResults):0;
  1267. LPTSTR pBuffer;
  1268. TraceEnter(TRACE_HANDLER, "CDsQuery::StopQuery");
  1269. if (!IsWindow(_hwndView))
  1270. ExitGracefully(hr, E_FAIL, "View not initalized yet");
  1271. // we are stopping the query, we are going to tidy up the UI now
  1272. // and we just want the thread to closedown cleanly, therefore lets
  1273. // do so, increasing our query reference
  1274. _pqf->StartQuery(FALSE);
  1275. _dwQueryReference++;
  1276. _PopulateView(-1, -1); // update status bar etc
  1277. if (_dwThreadId)
  1278. PostThreadMessage(_dwThreadId, RVTM_STOPQUERY, 0, 0);
  1279. hr = S_OK; // success
  1280. exit_gracefully:
  1281. TraceLeaveResult(hr);
  1282. }
  1283. /*---------------------------------------------------------------------------*/
  1284. HRESULT CDsQuery::_SetDataObjectData(IDataObject* pDataObject, UINT cf, LPVOID pData, DWORD cbSize)
  1285. {
  1286. FORMATETC fmte = {(CLIPFORMAT)cf, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  1287. STGMEDIUM medium = { TYMED_NULL, NULL, NULL };
  1288. LPVOID pAlloc;
  1289. HRESULT hr = AllocStorageMedium(&fmte, &medium, cbSize, &pAlloc);
  1290. if (SUCCEEDED(hr))
  1291. {
  1292. CopyMemory(pAlloc, pData, cbSize);
  1293. hr = pDataObject->SetData(&fmte, &medium, TRUE);
  1294. ReleaseStgMedium(&medium); // were done, so release the storage medium
  1295. }
  1296. return hr;
  1297. }
  1298. HRESULT CDsQuery::_SetDispSpecOptions(IDataObject *pdo)
  1299. {
  1300. CLIPFORMAT cfDsDispSpecOptions = (CLIPFORMAT)RegisterClipboardFormat(CFSTR_DSDISPLAYSPECOPTIONS);
  1301. FORMATETC fmte = {cfDsDispSpecOptions, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  1302. STGMEDIUM medium = { TYMED_NULL, NULL, NULL };
  1303. DSDISPLAYSPECOPTIONS *pddso;
  1304. LPWSTR pAttribPrefix = DS_PROP_SHELL_PREFIX;
  1305. // are we in admin mode? if so then lets fix the property prefix for reading things
  1306. // from the display specifiers
  1307. if (_dwFlags & DSQPF_ENABLEADMINFEATURES)
  1308. pAttribPrefix = DS_PROP_ADMIN_PREFIX;
  1309. // include all the string data into the allocation size (these are stored after the
  1310. // structure)
  1311. DWORD cbStruct = SIZEOF(DSDISPLAYSPECOPTIONS);
  1312. cbStruct += StringByteSizeW(pAttribPrefix);
  1313. cbStruct += StringByteSizeW(_pUserName);
  1314. cbStruct += StringByteSizeW(_pPassword);
  1315. cbStruct += StringByteSizeW(_pServer);
  1316. // allocate and fill...
  1317. HRESULT hr = AllocStorageMedium(&fmte, &medium, cbStruct, (void **)&pddso);
  1318. if (SUCCEEDED(hr))
  1319. {
  1320. DWORD offsetStrings = SIZEOF(DSDISPLAYSPECOPTIONS);
  1321. pddso->dwSize = SIZEOF(DSDISPLAYSPECOPTIONS);
  1322. pddso->dwFlags = DSDSOF_HASUSERANDSERVERINFO|DSDSOF_DSAVAILABLE;
  1323. //pddso->offsetAttribPrefix = 0x0;
  1324. //pddso->offsetUserName = 0x0;
  1325. //pddso->offsetPassword = 0x0;
  1326. //pddso->offsetServer = 0x0;
  1327. //pddso->offsetServerConfigPath = 0x0;
  1328. pddso->offsetAttribPrefix = offsetStrings;
  1329. StringByteCopyW(pddso, offsetStrings, pAttribPrefix);
  1330. offsetStrings += StringByteSizeW(pAttribPrefix);
  1331. if (_pUserName)
  1332. {
  1333. pddso->offsetUserName = offsetStrings;
  1334. StringByteCopyW(pddso, offsetStrings, _pUserName);
  1335. offsetStrings += StringByteSizeW(_pUserName);
  1336. }
  1337. if (_pPassword)
  1338. {
  1339. pddso->offsetPassword = offsetStrings;
  1340. StringByteCopyW(pddso, offsetStrings, _pPassword);
  1341. offsetStrings += StringByteSizeW(_pPassword);
  1342. }
  1343. if (_pServer)
  1344. {
  1345. pddso->offsetServer = offsetStrings;
  1346. StringByteCopyW(pddso, offsetStrings, _pServer);
  1347. offsetStrings += StringByteSizeW(_pServer);
  1348. }
  1349. // lets set into the IDataObject
  1350. hr = pdo->SetData(&fmte, &medium, TRUE);
  1351. ReleaseStgMedium(&medium);
  1352. }
  1353. return hr;
  1354. }
  1355. STDMETHODIMP CDsQuery::GetViewObject(UINT uScope, REFIID riid, void **ppvOut)
  1356. {
  1357. HRESULT hr;
  1358. IDataObject* pDataObject = NULL;
  1359. LPDSQUERYPARAMS pDsQueryParams = NULL;
  1360. LPDSQUERYSCOPE pDsQueryScope = NULL;
  1361. UINT cfDsQueryParams = RegisterClipboardFormat(CFSTR_DSQUERYPARAMS);
  1362. UINT cfDsQueryScope = RegisterClipboardFormat(CFSTR_DSQUERYSCOPE);
  1363. BOOL fJustSelection = !(_dwFlags & DSQPF_RETURNALLRESULTS);
  1364. TraceEnter(TRACE_HANDLER, "CDsQuery::GetViewObject");
  1365. // We only support returning the selection as an IDataObject
  1366. DECLAREWAITCURSOR;
  1367. SetWaitCursor();
  1368. if (!ppvOut && ((uScope & CQRVS_MASK) != CQRVS_SELECTION))
  1369. ExitGracefully(hr, E_INVALIDARG, "Bad arguments to GetViewObject");
  1370. if (!IsEqualIID(riid, IID_IDataObject))
  1371. ExitGracefully(hr, E_NOINTERFACE, "Object IID supported");
  1372. //
  1373. // write the extra data we have into the IDataObject:
  1374. //
  1375. // - query parameters (filter)
  1376. // - scope
  1377. // - attribute prefix information
  1378. //
  1379. hr = _GetDataObjectFromSelection(fJustSelection, &pDataObject);
  1380. FailGracefully(hr, "Failed to get the IDataObject from the namespace");
  1381. if (SUCCEEDED(_pqf->CallForm(NULL, CQPM_GETPARAMETERS, 0, (LPARAM)&pDsQueryParams)))
  1382. {
  1383. if (pDsQueryParams)
  1384. {
  1385. hr = _SetDataObjectData(pDataObject, cfDsQueryParams, pDsQueryParams, pDsQueryParams->cbStruct);
  1386. FailGracefully(hr, "Failed set the DSQUERYPARAMS into the data object");
  1387. }
  1388. }
  1389. if (SUCCEEDED(_pqf->GetScope((LPCQSCOPE*)&pDsQueryScope)))
  1390. {
  1391. if (pDsQueryScope)
  1392. {
  1393. LPWSTR pScope = OBJECT_NAME_FROM_SCOPE(pDsQueryScope);
  1394. TraceAssert(pScope);
  1395. hr = _SetDataObjectData(pDataObject, cfDsQueryScope, pScope, StringByteSizeW(pScope));
  1396. FailGracefully(hr, "Failed set the DSQUERYSCOPE into the data object");
  1397. }
  1398. }
  1399. // success, so lets pass out the IDataObject.
  1400. pDataObject->AddRef();
  1401. *ppvOut = (LPVOID)pDataObject;
  1402. hr = S_OK;
  1403. exit_gracefully:
  1404. DoRelease(pDataObject);
  1405. if (pDsQueryParams)
  1406. CoTaskMemFree(pDsQueryParams);
  1407. if (pDsQueryScope)
  1408. CoTaskMemFree(pDsQueryScope);
  1409. ResetWaitCursor();
  1410. TraceLeaveResult(hr);
  1411. }
  1412. /*---------------------------------------------------------------------------*/
  1413. STDMETHODIMP CDsQuery::LoadQuery(IPersistQuery* pPersistQuery)
  1414. {
  1415. HRESULT hr;
  1416. WCHAR szBuffer[MAX_PATH];
  1417. IADs *pDsObject = NULL;
  1418. BSTR bstrObjectClass = NULL;
  1419. INT iFilter;
  1420. LPCQSCOPE pScope = NULL;
  1421. INT cbScope;
  1422. TraceEnter(TRACE_HANDLER, "CDsQuery::LoadQuery");
  1423. if (!pPersistQuery)
  1424. ExitGracefully(hr, E_INVALIDARG, "No IPersistQuery object");
  1425. if (SUCCEEDED(pPersistQuery->ReadInt(c_szDsQuery, c_szScopeSize, &cbScope)) &&
  1426. (cbScope < SIZEOF(szBuffer)) &&
  1427. SUCCEEDED(pPersistQuery->ReadStruct(c_szDsQuery, c_szScope, szBuffer, cbScope)))
  1428. {
  1429. Trace(TEXT("Selected scope from file is %s"), szBuffer);
  1430. // get the object class from the file - this should be written to the file
  1431. hr = AdminToolsOpenObject(szBuffer, _pUserName, _pPassword, ADS_SECURE_AUTHENTICATION, IID_IADs, (void **)&pDsObject);
  1432. FailGracefully(hr, "Failed to bind to the specified object");
  1433. hr = pDsObject->get_Class(&bstrObjectClass);
  1434. FailGracefully(hr, "Failed to get the object class");
  1435. // allocate a new scope
  1436. if (SUCCEEDED(AllocScope(&pScope, 0, szBuffer, bstrObjectClass)))
  1437. {
  1438. hr = _pqf->AddScope(pScope, 0x0, TRUE);
  1439. FailGracefully(hr, "Failed to add scope to list");
  1440. }
  1441. }
  1442. // Read the remainder of the view state
  1443. if (SUCCEEDED(pPersistQuery->ReadInt(c_szDsQuery, c_szViewMode, &_idViewMode)))
  1444. {
  1445. Trace(TEXT("View mode is: %0x8"), _idViewMode);
  1446. _SetViewMode(_idViewMode);
  1447. }
  1448. if (SUCCEEDED(pPersistQuery->ReadInt(c_szDsQuery, c_szEnableFilter, &iFilter)))
  1449. {
  1450. Trace(TEXT("Filter mode set to %d"), _fFilter);
  1451. _SetFilter(iFilter);
  1452. }
  1453. hr = S_OK;
  1454. exit_gracefully:
  1455. if (pScope)
  1456. CoTaskMemFree(pScope);
  1457. DoRelease(pDsObject);
  1458. SysFreeString(bstrObjectClass);
  1459. TraceLeaveResult(hr);
  1460. }
  1461. /*---------------------------------------------------------------------------*/
  1462. STDMETHODIMP CDsQuery::SaveQuery(IPersistQuery* pPersistQuery, LPCQSCOPE pScope)
  1463. {
  1464. HRESULT hr;
  1465. LPDSQUERYSCOPE pDsQueryScope = (LPDSQUERYSCOPE)pScope;
  1466. LPWSTR pScopePath = OBJECT_NAME_FROM_SCOPE(pDsQueryScope);
  1467. WCHAR szGcPath[MAX_PATH];
  1468. TraceEnter(TRACE_HANDLER, "CDsQuery::SaveQuery");
  1469. if (!pPersistQuery || !pScope)
  1470. ExitGracefully(hr, E_INVALIDARG, "No IPersistQuery/pScope object");
  1471. if (SUCCEEDED(GetGlobalCatalogPath(_pServer, szGcPath, ARRAYSIZE(szGcPath))) && StrCmpW(pScopePath, szGcPath))
  1472. {
  1473. // if this is not the GC then persist
  1474. TraceMsg("GC path differs from scope, so persisting");
  1475. hr = pPersistQuery->WriteInt(c_szDsQuery, c_szScopeSize, StringByteSizeW(pScopePath));
  1476. FailGracefully(hr, "Failed to write the scope size");
  1477. hr = pPersistQuery->WriteStruct(c_szDsQuery, c_szScope, pScopePath, StringByteSizeW(pScopePath));
  1478. FailGracefully(hr, "Failed to write scope");
  1479. }
  1480. hr = pPersistQuery->WriteInt(c_szDsQuery, c_szViewMode, _idViewMode);
  1481. FailGracefully(hr, "Failed to write view mode");
  1482. hr = pPersistQuery->WriteInt(c_szDsQuery, c_szEnableFilter, _fFilter);
  1483. FailGracefully(hr, "Failed to write filter state");
  1484. hr = S_OK;
  1485. exit_gracefully:
  1486. TraceLeaveResult(hr);
  1487. }
  1488. /*----------------------------------------------------------------------------
  1489. / IObjectWithSite
  1490. /----------------------------------------------------------------------------*/
  1491. STDMETHODIMP CDsQuery::SetSite(IUnknown* punk)
  1492. {
  1493. HRESULT hr = S_OK;
  1494. TraceEnter(TRACE_HANDLER, "CDsQuery::SetSite");
  1495. DoRelease(_punkSite);
  1496. if (punk)
  1497. {
  1498. TraceMsg("QIing for IUnknown from the site object");
  1499. hr = punk->QueryInterface(IID_IUnknown, (void **)&_punkSite);
  1500. FailGracefully(hr, "Failed to get IUnknown from the site object");
  1501. }
  1502. exit_gracefully:
  1503. TraceLeaveResult(hr);
  1504. }
  1505. STDMETHODIMP CDsQuery::GetSite(REFIID riid, void **ppv)
  1506. {
  1507. HRESULT hr;
  1508. TraceEnter(TRACE_HANDLER, "CDsQuery::GetSite");
  1509. if (!_punkSite)
  1510. ExitGracefully(hr, E_NOINTERFACE, "No site to QI from");
  1511. hr = _punkSite->QueryInterface(riid, ppv);
  1512. FailGracefully(hr, "QI failed on the site unknown object");
  1513. exit_gracefully:
  1514. TraceLeaveResult(hr);
  1515. }
  1516. /*----------------------------------------------------------------------------
  1517. / IDsQueryHandler
  1518. /----------------------------------------------------------------------------*/
  1519. VOID CDsQuery::_DeleteViewItems(LPDSOBJECTNAMES pdon)
  1520. {
  1521. INT iResult;
  1522. DWORD iItem;
  1523. TraceEnter(TRACE_HANDLER, "CDsQuery::_DeleteObjectNames");
  1524. if (pdon->cItems)
  1525. {
  1526. // walk through all the items in the view deleting as required.
  1527. for (iItem = 0 ; iItem != pdon->cItems ; iItem++)
  1528. {
  1529. // do we have an item to delete?
  1530. if (pdon->aObjects[iItem].offsetName)
  1531. {
  1532. LPCWSTR pwszName = (LPCWSTR)ByteOffset(pdon, pdon->aObjects[iItem].offsetName);
  1533. Trace(TEXT("pwszName to delete: %s"), pwszName);
  1534. // walk all the results in the view deleting them as we go.
  1535. for (iResult = 0 ; iResult < DPA_GetPtrCount(_hdpaResults); iResult++)
  1536. {
  1537. LPQUERYRESULT pResult = (LPQUERYRESULT)DPA_GetPtr(_hdpaResults, iResult);
  1538. TraceAssert(pResult);
  1539. // if we match the item we want to delete then remove it, if the view
  1540. // is not filtered then remove ite from the list, otherwise leave the
  1541. // view update until we have finished deleting
  1542. if (!StrCmpW(pwszName, pResult->pPath))
  1543. {
  1544. Trace(TEXT("Item maps to result %d in the list"), iResult);
  1545. FreeQueryResult(pResult, DSA_GetItemCount(_hdsaColumns));
  1546. DPA_DeletePtr(_hdpaResults, iResult);
  1547. if (!_fFilter)
  1548. {
  1549. TraceMsg("Deleting the item from the view");
  1550. ListView_DeleteItem(_hwndView, iResult);
  1551. }
  1552. }
  1553. }
  1554. }
  1555. }
  1556. // the view was filtered, so lets repopulate with the items
  1557. if (_fFilter)
  1558. {
  1559. TraceMsg("View is filter, therefore just forcing a refresh");
  1560. _FilterView(FALSE);
  1561. }
  1562. }
  1563. TraceLeave();
  1564. }
  1565. STDMETHODIMP CDsQuery::UpdateView(DWORD dwType, LPDSOBJECTNAMES pdon)
  1566. {
  1567. HRESULT hr;
  1568. TraceEnter(TRACE_HANDLER, "CDsQuery::UpdateView");
  1569. switch (dwType & DSQRVF_OPMASK)
  1570. {
  1571. case DSQRVF_ITEMSDELETED:
  1572. {
  1573. if (!pdon)
  1574. ExitGracefully(hr, E_INVALIDARG, "Invlaidate pdon specified for refresh");
  1575. _DeleteViewItems(pdon);
  1576. break;
  1577. }
  1578. default:
  1579. ExitGracefully(hr, E_INVALIDARG, "Invalidate refresh type speciifed");
  1580. }
  1581. hr = S_OK;
  1582. exit_gracefully:
  1583. TraceLeaveResult(hr);
  1584. }
  1585. /*-----------------------------------------------------------------------------
  1586. / Message/Command Handlers
  1587. /----------------------------------------------------------------------------*/
  1588. /*-----------------------------------------------------------------------------
  1589. / CDsQuery::OnSize
  1590. / ----------------
  1591. / Result viewer is being sized, so ensure that our children have their
  1592. / sizes correctly addjusted.
  1593. /
  1594. / In:
  1595. / cx, cy = new size of the parent window
  1596. /
  1597. / Out:
  1598. / -
  1599. /----------------------------------------------------------------------------*/
  1600. LRESULT CDsQuery::OnSize(INT cx, INT cy)
  1601. {
  1602. TraceEnter(TRACE_VIEW, "CDsQuery::OnSize");
  1603. SetWindowPos(_hwndView, NULL, 0, 0, cx, cy, SWP_NOZORDER|SWP_NOMOVE);
  1604. _ShowBanner(0, 0);
  1605. TraceLeaveValue(0);
  1606. }
  1607. /*-----------------------------------------------------------------------------
  1608. / CDsQuery::OnNotify
  1609. / ------------------
  1610. / Notify message being recieved by the view, so try and handle it as best
  1611. / we can.
  1612. /
  1613. / In:
  1614. / hWnd = window handle of the notify
  1615. / wParam, lParam = parameters for the notify event
  1616. /
  1617. / Out:
  1618. / LRESULT
  1619. /----------------------------------------------------------------------------*/
  1620. LRESULT CDsQuery::OnNotify(HWND hWnd, WPARAM wParam, LPARAM lParam)
  1621. {
  1622. HRESULT hr;
  1623. LRESULT lr = 0;
  1624. DECLAREWAITCURSOR = GetCursor();
  1625. TraceEnter(TRACE_VIEW, "CDsQuery::OnNotify");
  1626. switch (((LPNMHDR)lParam)->code)
  1627. {
  1628. case HDN_FILTERCHANGE:
  1629. _FilterView(TRUE);
  1630. break;
  1631. case HDN_FILTERBTNCLICK:
  1632. {
  1633. NMHDFILTERBTNCLICK* pNotify = (NMHDFILTERBTNCLICK*)lParam;
  1634. HMENU hMenu;
  1635. POINT pt;
  1636. HD_ITEM hdi;
  1637. UINT uID;
  1638. if (_hdsaColumns && (pNotify->iItem < DSA_GetItemCount(_hdsaColumns)))
  1639. {
  1640. LPCOLUMN pColumn = (LPCOLUMN)DSA_GetItemPtr(_hdsaColumns, pNotify->iItem);
  1641. if (pColumn)
  1642. {
  1643. hMenu = LoadMenu(GLOBAL_HINSTANCE, property_type_table[pColumn->iPropertyType].pMenuName);
  1644. TraceAssert(hMenu);
  1645. if (hMenu)
  1646. {
  1647. pt.x = pNotify->rc.right;
  1648. pt.y = pNotify->rc.bottom;
  1649. MapWindowPoints(pNotify->hdr.hwndFrom, NULL, &pt, 1);
  1650. CheckMenuRadioItem(GetSubMenu(hMenu, 0),
  1651. FILTER_FIRST, FILTER_LAST, pColumn->idOperator,
  1652. MF_BYCOMMAND);
  1653. uID = TrackPopupMenu(GetSubMenu(hMenu, 0),
  1654. TPM_RIGHTALIGN|TPM_RETURNCMD,
  1655. pt.x, pt.y,
  1656. 0, pNotify->hdr.hwndFrom, NULL);
  1657. switch (uID)
  1658. {
  1659. case DSQH_CLEARFILTER:
  1660. Header_ClearFilter(ListView_GetHeader(_hwndView), pNotify->iItem);
  1661. break;
  1662. case DSQH_CLEARALLFILTERS:
  1663. Header_ClearAllFilters(ListView_GetHeader(_hwndView));
  1664. break;
  1665. default:
  1666. {
  1667. if (uID && (uID != pColumn->idOperator))
  1668. {
  1669. // update the filter string based on the new operator
  1670. pColumn->idOperator = uID;
  1671. _GetFilterValue(pNotify->iItem, NULL);
  1672. lr = TRUE;
  1673. }
  1674. break;
  1675. }
  1676. }
  1677. DestroyMenu(hMenu);
  1678. }
  1679. }
  1680. }
  1681. break;
  1682. }
  1683. case HDN_ITEMCHANGED:
  1684. {
  1685. HD_NOTIFY* pNotify = (HD_NOTIFY*)lParam;
  1686. HD_ITEM* pitem = (HD_ITEM*)pNotify->pitem;
  1687. if (_hdsaColumns && (pNotify->iItem < DSA_GetItemCount(_hdsaColumns)))
  1688. {
  1689. LPCOLUMN pColumn = (LPCOLUMN)DSA_GetItemPtr(_hdsaColumns, pNotify->iItem);
  1690. TraceAssert(pColumn);
  1691. // store the new column width information in the column structure and
  1692. // mark the column table as dirty
  1693. if (pitem->mask & HDI_WIDTH)
  1694. {
  1695. Trace(TEXT("Column %d, cx %d (marking state as dirty)"), pNotify->iItem, pitem->cxy);
  1696. pColumn->cx = pitem->cxy;
  1697. _fColumnsModified = TRUE;
  1698. }
  1699. if (pitem->mask & HDI_FILTER)
  1700. {
  1701. Trace(TEXT("Filter for column %d has been changed"), pNotify->iItem);
  1702. _GetFilterValue(pNotify->iItem, pitem);
  1703. }
  1704. }
  1705. break;
  1706. }
  1707. case LVN_GETDISPINFO:
  1708. {
  1709. LV_DISPINFO* pNotify = (LV_DISPINFO*)lParam;
  1710. TraceAssert(pNotify);
  1711. if (pNotify && (pNotify->item.mask & LVIF_TEXT) && pNotify->item.lParam)
  1712. {
  1713. LPQUERYRESULT pResult = (LPQUERYRESULT)pNotify->item.lParam;
  1714. INT iColumn = pNotify->item.iSubItem;
  1715. pNotify->item.pszText[0] = TEXT('\0'); // nothing to display yet
  1716. switch (pResult->aColumn[iColumn].iPropertyType)
  1717. {
  1718. case PROPERTY_ISUNDEFINED:
  1719. break;
  1720. case PROPERTY_ISUNKNOWN:
  1721. case PROPERTY_ISSTRING:
  1722. case PROPERTY_ISDNSTRING:
  1723. {
  1724. if (pResult->aColumn[iColumn].pszText)
  1725. StrCpyN(pNotify->item.pszText, pResult->aColumn[iColumn].pszText, pNotify->item.cchTextMax);
  1726. break;
  1727. }
  1728. case PROPERTY_ISNUMBER:
  1729. case PROPERTY_ISBOOL:
  1730. // NTRAID#NTBUG9-554458-2002/02/20-lucios. Pending fix.
  1731. wsprintf(pNotify->item.pszText, TEXT("%d"), pResult->aColumn[iColumn].iValue);
  1732. break;
  1733. }
  1734. lr = TRUE; // we formatted a value
  1735. }
  1736. break;
  1737. }
  1738. case LVN_ITEMACTIVATE:
  1739. {
  1740. LPNMHDR pNotify = (LPNMHDR)lParam;
  1741. DWORD dwFlags = CMF_NORMAL;
  1742. HWND hwndFrame;
  1743. HMENU hMenu;
  1744. UINT uID;
  1745. // convert the current selection to IDLITs and an IContextMenu interface
  1746. // that we can then get the default verb from.
  1747. SetWaitCursor();
  1748. hr = _GetContextMenu();
  1749. FailGracefully(hr, "Failed when calling _GetContextMenu");
  1750. _fNoSelection = !ListView_GetSelectedCount(_hwndView);
  1751. if (!_fNoSelection)
  1752. {
  1753. // create a popup menu pickup the context menu for the current selection
  1754. // and then pass it down to the invoke command handler.
  1755. hMenu = CreatePopupMenu();
  1756. TraceAssert(hMenu);
  1757. if (hMenu)
  1758. {
  1759. if (GetKeyState(VK_SHIFT) < 0)
  1760. dwFlags |= CMF_EXPLORE; // SHIFT + dblclick does a Explore by default
  1761. _GetContextMenuVerbs(hMenu, dwFlags);
  1762. uID = GetMenuDefaultItem(hMenu, MF_BYCOMMAND, 0);
  1763. Trace(TEXT("Default uID after double click %08x"), uID);
  1764. if (uID != -1)
  1765. {
  1766. _pqf->GetWindow(&hwndFrame);
  1767. InvokeCommand(hwndFrame, uID);
  1768. }
  1769. DoRelease(_pcm); // no longer needed
  1770. DestroyMenu(hMenu);
  1771. }
  1772. }
  1773. break;
  1774. }
  1775. case LVN_COLUMNCLICK:
  1776. {
  1777. NM_LISTVIEW* pNotify = (NM_LISTVIEW*)lParam;
  1778. TraceAssert(pNotify);
  1779. _SortResults(pNotify->iSubItem);
  1780. break;
  1781. }
  1782. default:
  1783. lr = DefWindowProc(hWnd, WM_NOTIFY, wParam, lParam);
  1784. break;
  1785. }
  1786. exit_gracefully:
  1787. ResetWaitCursor();
  1788. TraceLeaveValue(lr);
  1789. }
  1790. /*-----------------------------------------------------------------------------
  1791. / CDsQuery::OnAddResults
  1792. / ----------------------
  1793. / The background thread has sent us some results, so lets add them to
  1794. / the DPA of results, discarding the ones we don't add because we cannot
  1795. / grow the DPA.
  1796. /
  1797. / dwQueryReference conatins the reference ID for this query, only add
  1798. / results where these match.
  1799. /
  1800. / In:
  1801. / dwQueryReference = reference that this block is for
  1802. / hdpaResults = DPA containing the results to add
  1803. /
  1804. / Out:
  1805. / HRESULT
  1806. /----------------------------------------------------------------------------*/
  1807. HRESULT CDsQuery::OnAddResults(DWORD dwQueryReference, HDPA hdpaResults)
  1808. {
  1809. HRESULT hr;
  1810. INT i, iPopulateFrom;
  1811. TraceEnter(TRACE_VIEW, "CDsQuery::OnAddResults");
  1812. if ((dwQueryReference != _dwQueryReference) || !hdpaResults)
  1813. ExitGracefully(hr, E_FAIL, "Failed to add results, bad DPA/reference ID");
  1814. // the caller gives us a DPA then we add them to our result DPA, we then
  1815. // update the view populating from the first item we added.
  1816. iPopulateFrom = DPA_GetPtrCount(_hdpaResults);
  1817. for (i = DPA_GetPtrCount(hdpaResults); --i >= 0 ; )
  1818. {
  1819. LPQUERYRESULT pResult = (LPQUERYRESULT)DPA_GetPtr(hdpaResults, i);
  1820. TraceAssert(pResult);
  1821. // add the result to the main DPA, if that fails then ensure we nuke
  1822. // this result blob!
  1823. if (-1 == DPA_AppendPtr(_hdpaResults, pResult))
  1824. FreeQueryResult(pResult, DSA_GetItemCount(_hdsaColumns));
  1825. DPA_DeletePtr(hdpaResults, i); // remove from result DPA
  1826. }
  1827. _PopulateView(iPopulateFrom, DPA_GetPtrCount(_hdpaResults));
  1828. TraceAssert(DPA_GetPtrCount(hdpaResults) == 0);
  1829. DPA_Destroy(hdpaResults);
  1830. hr = S_OK;
  1831. exit_gracefully:
  1832. TraceLeaveResult(hr);
  1833. }
  1834. /*-----------------------------------------------------------------------------
  1835. / CDsQuery::OnContextMenu
  1836. / -----------------------
  1837. / The user has right clicked in the result view, therefore we must attempt
  1838. / to display the context menu for those objects
  1839. /
  1840. / In:
  1841. / hwndMenu = window that that the user menued over
  1842. / pt = point to show the context menu
  1843. /
  1844. / Out:
  1845. / -
  1846. /----------------------------------------------------------------------------*/
  1847. LRESULT CDsQuery::OnContextMenu(HWND hwndMenu, LPARAM lParam)
  1848. {
  1849. HRESULT hr;
  1850. HMENU hMenu = NULL;
  1851. POINT pt = { 0, 0 };
  1852. INT i;
  1853. RECT rc;
  1854. HWND hwndFrame;
  1855. TraceEnter(TRACE_VIEW, "CDsQuery::OnContextMenu");
  1856. // Collect the selection, obtaining a IContextMenu interface pointer, or a HR == S_FALSE
  1857. // if there is no selection for us to be using.
  1858. hr = _GetContextMenu();
  1859. FailGracefully(hr, "Failed when calling _GetContextMenu()");
  1860. _fNoSelection = !ListView_GetSelectedCount(_hwndView);
  1861. if (!(hMenu = CreatePopupMenu()))
  1862. ExitGracefully(hr, E_FAIL, "Failed to create the popup menu");
  1863. if (!_fNoSelection)
  1864. {
  1865. // pick up the context menu that maps to the current selection, including fixing
  1866. // the "select" verb if we need one.
  1867. _GetContextMenuVerbs(hMenu, CMF_NORMAL);
  1868. }
  1869. else
  1870. {
  1871. // There is no selection so lets pick up the view bg menu, this contains
  1872. // some useful helpers for modifying the view state.
  1873. HMENU hBgMenu = LoadMenu(GLOBAL_HINSTANCE, MAKEINTRESOURCE(IDR_VIEWBACKGROUND));
  1874. if (!hBgMenu)
  1875. ExitGracefully(hr, E_FAIL, "Failed to load pop-up menu for the background");
  1876. Shell_MergeMenus(hMenu, GetSubMenu(hBgMenu, 0), 0, 0, CQID_MAXHANDLERMENUID, 0x0);
  1877. DestroyMenu(hBgMenu);
  1878. _InitViewMenuItems(hMenu);
  1879. }
  1880. // if lParam == -1 then we know that the user hit the "context menu" key
  1881. // so lets set the co-ordinates of the item.
  1882. if (lParam == (DWORD)-1)
  1883. {
  1884. i = ListView_GetNextItem(_hwndView, -1, LVNI_FOCUSED|LVNI_SELECTED);
  1885. Trace(TEXT("Item with focus + selection: %d"), i);
  1886. if (i == -1)
  1887. {
  1888. i = ListView_GetNextItem(_hwndView, -1, LVNI_SELECTED);
  1889. Trace(TEXT("1st selected item: %D"), i);
  1890. }
  1891. if (i != -1)
  1892. {
  1893. TraceMsg("We have an item, so getting bounds of the icon for position");
  1894. ListView_GetItemRect(_hwndView, i, &rc, LVIR_ICON);
  1895. pt.x = (rc.left+rc.right)/2;
  1896. pt.y = (rc.top+rc.bottom)/2;
  1897. }
  1898. MapWindowPoints(_hwndView, HWND_DESKTOP, &pt, 1); // they are in client co-ordinates
  1899. }
  1900. else
  1901. {
  1902. pt.x = GET_X_LPARAM(lParam);
  1903. pt.y = GET_Y_LPARAM(lParam);
  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 hr;
  1927. IDataObject* pDataObject = NULL;
  1928. IDsFolderProperties* pDsFolderProperties = NULL;
  1929. TraceEnter(TRACE_VIEW, "CDsQuery::OnFileProperties");
  1930. hr = GetViewObject(CQRVS_SELECTION, IID_IDataObject, (void **)&pDataObject);
  1931. FailGracefully(hr, "Failed to get IDataObject for shortcut creation");
  1932. hr = CoCreateInstance(CLSID_DsFolderProperties, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IDsFolderProperties, &pDsFolderProperties));
  1933. FailGracefully(hr, "Failed to get IDsFolderProperties for the desktop object");
  1934. hr = pDsFolderProperties->ShowProperties(_hwnd, pDataObject);
  1935. FailGracefully(hr, "Failed to invoke property UI for the given selection");
  1936. // hr = S_OK; // success
  1937. exit_gracefully:
  1938. DoRelease(pDataObject);
  1939. DoRelease(pDsFolderProperties);
  1940. TraceLeaveResult(hr);
  1941. }
  1942. /*-----------------------------------------------------------------------------
  1943. / CDsQuery::OnFileSaveQuery
  1944. / -------------------------
  1945. / Allow the user to choose a location to save the query (initial directory
  1946. / is nethood). Having done that we then start the save process by passing
  1947. / the frame object a IQueryIO object that allows them to persist the
  1948. / query into.
  1949. /
  1950. / In:
  1951. / Out:
  1952. / HRESULT
  1953. /----------------------------------------------------------------------------*/
  1954. HRESULT CDsQuery::OnFileSaveQuery(VOID)
  1955. {
  1956. HRESULT hr;
  1957. OPENFILENAME ofn;
  1958. TCHAR szFilename[MAX_PATH];
  1959. TCHAR szDirectory[MAX_PATH];
  1960. TCHAR szFilter[64];
  1961. TCHAR szTitle[64];
  1962. LPTSTR pFilter;
  1963. IPersistQuery *ppq = NULL;
  1964. TraceEnter(TRACE_VIEW, "CDsQuery::OnFileSaveQuery");
  1965. // Load the default strings and fix up the filter string as it needs
  1966. // NULL's seperating the various resource sections.
  1967. LoadString(GLOBAL_HINSTANCE, IDS_SAVETITLE, szTitle, ARRAYSIZE(szTitle));
  1968. // NTRAID#NTBUG9-554905-2002/02/20-lucios. Pending fix.
  1969. StrCpy(szFilename, _pDefaultSaveName);
  1970. LoadString(GLOBAL_HINSTANCE, IDS_SAVEFILTER, szFilter, ARRAYSIZE(szFilter));
  1971. for (pFilter = szFilter ; *pFilter ; pFilter++)
  1972. {
  1973. if (*pFilter == TEXT('\n'))
  1974. *pFilter = TEXT('\0');
  1975. }
  1976. // fix the open filename structure ready to do our save....
  1977. ZeroMemory(&ofn, SIZEOF(ofn));
  1978. ofn.lStructSize = SIZEOF(ofn);
  1979. _pqf->GetWindow(&ofn.hwndOwner);
  1980. ofn.hInstance = GLOBAL_HINSTANCE;
  1981. ofn.lpstrFilter = szFilter;
  1982. ofn.lpstrFile = szFilename;
  1983. ofn.nMaxFile = ARRAYSIZE(szFilename);
  1984. if (_pDefaultSaveLocation)
  1985. {
  1986. Trace(TEXT("Saving into: %s"), _pDefaultSaveLocation);
  1987. // NTRAID#NTBUG9-554905-2002/02/20-lucios. Pending fix.
  1988. StrCpy(szDirectory, _pDefaultSaveLocation);
  1989. ofn.lpstrInitialDir = szDirectory;
  1990. }
  1991. ofn.lpstrTitle = szTitle;
  1992. ofn.Flags = OFN_EXPLORER|OFN_NOCHANGEDIR|OFN_OVERWRITEPROMPT|OFN_PATHMUSTEXIST|OFN_HIDEREADONLY;
  1993. ofn.lpstrDefExt = TEXT("dsq");
  1994. // If we get a save filename then lets ensure that we delete the previous
  1995. // query saved there (if there is one) and then we can create an IPersistQuery
  1996. // object that will save to that location.
  1997. if (GetSaveFileName(&ofn))
  1998. {
  1999. Trace(TEXT("Saving query as: %s"), szFilename);
  2000. if (!DeleteFile(szFilename) && (GetLastError() != ERROR_FILE_NOT_FOUND))
  2001. ExitGracefully(hr, E_FAIL, "Failed to delete previous query");
  2002. hr = CPersistQuery_CreateInstance(szFilename, &ppq);
  2003. FailGracefully(hr, "Failed to create the peristance object");
  2004. hr = _pqf->SaveQuery(ppq);
  2005. FailGracefully(hr, "Failed when calling IQueryFrame::SaveSearch");
  2006. }
  2007. hr = S_OK;
  2008. exit_gracefully:
  2009. DoRelease(ppq);
  2010. TraceLeaveResult(hr);
  2011. }
  2012. /*-----------------------------------------------------------------------------
  2013. / CDsQuery::OnEditSelectAll
  2014. / -------------------------
  2015. / Walk all the items in the view setting their selected state.
  2016. /
  2017. / In:
  2018. / Out:
  2019. / HRESULT
  2020. /----------------------------------------------------------------------------*/
  2021. HRESULT CDsQuery::OnEditSelectAll(VOID)
  2022. {
  2023. TraceEnter(TRACE_VIEW, "CDsQuery::OnEditSelectAll");
  2024. for (INT i = ListView_GetItemCount(_hwndView) ; --i >= 0 ;)
  2025. {
  2026. ListView_SetItemState(_hwndView, i, LVIS_SELECTED, LVIS_SELECTED);
  2027. }
  2028. TraceLeaveResult(S_OK);
  2029. }
  2030. /*-----------------------------------------------------------------------------
  2031. / CDsQuery::OnEditInvertSelection
  2032. / -------------------------------
  2033. / Walk all the items in the view and invert their selected state.
  2034. /
  2035. / In:
  2036. / Out:
  2037. / HRESULT
  2038. /----------------------------------------------------------------------------*/
  2039. HRESULT CDsQuery::OnEditInvertSelection(VOID)
  2040. {
  2041. TraceEnter(TRACE_VIEW, "CDsQuery::OnEditInvertSelection");
  2042. for (INT i = ListView_GetItemCount(_hwndView) ; --i >= 0 ;)
  2043. {
  2044. DWORD dwState = ListView_GetItemState(_hwndView, i, LVIS_SELECTED);
  2045. ListView_SetItemState(_hwndView, i, dwState ^ LVIS_SELECTED, LVIS_SELECTED);
  2046. }
  2047. TraceLeaveResult(S_OK);
  2048. }
  2049. /*-----------------------------------------------------------------------------
  2050. / CDsQuery::_InitNewQuery
  2051. / ----------------------
  2052. / Initialize the view ready for a new query, including setting the frame
  2053. / into a query running state.
  2054. /
  2055. / In:
  2056. / pDsQueryParams = DSQUERYPARAMs structure used to issue the query.
  2057. / fRefreshColumnTable = re-read the column table from the params/registry etc
  2058. /
  2059. / Out:
  2060. / HRESULT
  2061. /----------------------------------------------------------------------------*/
  2062. HRESULT CDsQuery::_InitNewQuery(LPDSQUERYPARAMS pDsQueryParams, BOOL fRefreshColumnTable)
  2063. {
  2064. HRESULT hr;
  2065. LPTSTR pBuffer;
  2066. TraceEnter(TRACE_VIEW, "CDsQuery::_InitNewQuery");
  2067. hr = _pqf->StartQuery(TRUE);
  2068. TraceAssert(SUCCEEDED(hr));
  2069. // Claim the cached DS object for this window
  2070. // if refreshing the column table then _GetColumnTable handles this all for us,
  2071. // otherwise lets just nuke the result set ourselves.
  2072. if (fRefreshColumnTable)
  2073. {
  2074. _SaveColumnTable();
  2075. hr = _GetColumnTable(_clsidForm, pDsQueryParams, &_hdsaColumns, TRUE);
  2076. FailGracefully(hr, "Failed to create column DSA");
  2077. }
  2078. else
  2079. {
  2080. _FreeResults();
  2081. }
  2082. // initialize the view to start the query running, display the prompt banner and
  2083. // initialize the result DPA.
  2084. _ShowBanner(SWP_SHOWWINDOW, IDS_SEARCHING); // we are now searching
  2085. if (SUCCEEDED(FormatMsgResource(&pBuffer, GLOBAL_HINSTANCE, IDS_SEARCHING)))
  2086. {
  2087. _pqf->SetStatusText(pBuffer);
  2088. LocalFreeString(&pBuffer);
  2089. }
  2090. TraceAssert(_hdpaResults==NULL); // should never catch
  2091. _hdpaResults = DPA_Create(16);
  2092. TraceAssert(_hdpaResults);
  2093. if (!_hdpaResults)
  2094. ExitGracefully(hr, E_OUTOFMEMORY, "Failed to allocate result DPA");
  2095. _dwQueryReference++;
  2096. exit_gracefully:
  2097. TraceLeaveResult(hr);
  2098. }
  2099. /*-----------------------------------------------------------------------------
  2100. / CDsQuery::_GetFilterValue
  2101. / ------------------------
  2102. / Given a column index collect the filter value from it, note that
  2103. / when doing this
  2104. /
  2105. / In:
  2106. / i = column to retrieve
  2107. / pitem -> HD_ITEM structure for the current filter / == NULL then read from header
  2108. /
  2109. / Out:
  2110. / HRESULT
  2111. /----------------------------------------------------------------------------*/
  2112. HRESULT CDsQuery::_GetFilterValue(INT i, HD_ITEM* pitem)
  2113. {
  2114. HRESULT hr;
  2115. HD_ITEM hdi;
  2116. HD_TEXTFILTER textFilter;
  2117. TCHAR szBuffer[MAX_PATH];
  2118. INT iValue;
  2119. UINT cchFilter = 0;
  2120. LPCOLUMN pColumn = (LPCOLUMN)DSA_GetItemPtr(_hdsaColumns, i);
  2121. if (!pColumn)
  2122. ExitGracefully(hr, E_FAIL, "Failed to get the column");
  2123. TraceEnter(TRACE_VIEW, "CDsQuery::_GetFilterValue");
  2124. // if pitem == NULL then lets pick up the filter value from the
  2125. // header control, using the stored property type (the filter one
  2126. // has already been nuked) to defined which filter we want.
  2127. if (!pitem)
  2128. {
  2129. hdi.mask = HDI_FILTER;
  2130. switch (pColumn->iPropertyType)
  2131. {
  2132. case PROPERTY_ISUNKNOWN:
  2133. case PROPERTY_ISSTRING:
  2134. case PROPERTY_ISDNSTRING:
  2135. {
  2136. hdi.type = HDFT_ISSTRING;
  2137. hdi.pvFilter = &textFilter;
  2138. textFilter.pszText = szBuffer;
  2139. textFilter.cchTextMax = ARRAYSIZE(szBuffer);
  2140. break;
  2141. }
  2142. case PROPERTY_ISNUMBER:
  2143. case PROPERTY_ISBOOL:
  2144. {
  2145. hdi.type = HDFT_ISNUMBER;
  2146. hdi.pvFilter = &iValue;
  2147. break;
  2148. }
  2149. }
  2150. if (!Header_GetItem(ListView_GetHeader(_hwndView), i, &hdi))
  2151. ExitGracefully(hr, E_FAIL, "Failed to get the filter string");
  2152. pitem = &hdi;
  2153. }
  2154. // discard the previous filter value and lets read from the
  2155. // structure the information we need to cache our filter information
  2156. FreeColumnValue(&pColumn->filter);
  2157. if (!(pitem->type & HDFT_HASNOVALUE) && pitem->pvFilter)
  2158. {
  2159. switch (pitem->type & HDFT_ISMASK)
  2160. {
  2161. case HDFT_ISSTRING:
  2162. {
  2163. LPHD_TEXTFILTER ptextFilter = (LPHD_TEXTFILTER)pitem->pvFilter;
  2164. TraceAssert(ptextFilter);
  2165. pColumn->filter.iPropertyType = PROPERTY_ISSTRING;
  2166. // text filters are stored in their wildcarded state, therefore
  2167. // filtering doesn't require converting from the text form
  2168. // to something more elobrate each pass through. the down
  2169. // side is when the operator changes we must rebuild the
  2170. // filter string for that column (small price)
  2171. GetPatternString(NULL, &cchFilter, pColumn->idOperator, ptextFilter->pszText);
  2172. TraceAssert(cchFilter != 0);
  2173. if (cchFilter)
  2174. {
  2175. hr = LocalAllocStringLen(&pColumn->filter.pszText, cchFilter);
  2176. FailGracefully(hr, "Failed to allocate buffer to read string into");
  2177. GetPatternString(pColumn->filter.pszText, &cchFilter, pColumn->idOperator, ptextFilter->pszText);
  2178. Trace(TEXT("Filter (with pattern info): %s"), pColumn->filter.pszText);
  2179. LCMapString(0x0, LCMAP_UPPERCASE, pColumn->filter.pszText, -1, pColumn->filter.pszText, cchFilter+1);
  2180. Trace(TEXT("After converting to uppercase (LCMapString): %s"), pColumn->filter.pszText);
  2181. }
  2182. break;
  2183. }
  2184. case HDFT_ISNUMBER:
  2185. {
  2186. INT* piFilter = (INT*)pitem->pvFilter;
  2187. TraceAssert(piFilter);
  2188. pColumn->filter.iPropertyType = PROPERTY_ISNUMBER;
  2189. pColumn->filter.iValue = *piFilter;
  2190. Trace(TEXT("Filter: %d"), pColumn->filter.iValue);
  2191. break;
  2192. }
  2193. }
  2194. }
  2195. hr = S_OK;
  2196. exit_gracefully:
  2197. TraceLeaveResult(hr);
  2198. }
  2199. /*-----------------------------------------------------------------------------
  2200. / CDsQuery::_FilterView
  2201. / --------------------
  2202. / Filter the result set populating the view again with the changes
  2203. /
  2204. / In:
  2205. / fCheck
  2206. /
  2207. / Out:
  2208. / HRESULT
  2209. /----------------------------------------------------------------------------*/
  2210. UINT _GetFilter(HDSA hdsaColumns, LPTSTR pBuffer, UINT* pcchBuffer)
  2211. {
  2212. INT i;
  2213. TCHAR szBuffer[MAX_PATH];
  2214. TraceEnter(TRACE_VIEW, "_GetFilter");
  2215. TraceAssert(hdsaColumns && pcchBuffer);
  2216. *pcchBuffer = 0;
  2217. // form the string containin [operatorID]value pairs for each of the
  2218. // filter columns that is defined.
  2219. for (i = 0 ; i < DSA_GetItemCount(hdsaColumns); i++)
  2220. {
  2221. LPCOLUMN pColumn = (LPCOLUMN)DSA_GetItemPtr(hdsaColumns, i);
  2222. TraceAssert(pColumn);
  2223. if (pColumn->filter.iPropertyType != PROPERTY_ISUNDEFINED)
  2224. {
  2225. // NTRAID#NTBUG9-554458-2002/02/20-lucios. Pending fix.
  2226. wsprintf(szBuffer, TEXT("[%d]"), pColumn->idOperator);
  2227. PutStringElement(pBuffer, pcchBuffer, szBuffer);
  2228. switch (pColumn->filter.iPropertyType)
  2229. {
  2230. case PROPERTY_ISUNDEFINED:
  2231. break;
  2232. case PROPERTY_ISUNKNOWN:
  2233. case PROPERTY_ISSTRING:
  2234. case PROPERTY_ISDNSTRING:
  2235. PutStringElement(pBuffer, pcchBuffer, pColumn->filter.pszText);
  2236. break;
  2237. case PROPERTY_ISNUMBER:
  2238. case PROPERTY_ISBOOL:
  2239. // NTRAID#NTBUG9-554458-2002/02/20-lucios. Pending fix.
  2240. wsprintf(szBuffer, TEXT("%d"), pColumn->filter.iValue);
  2241. PutStringElement(pBuffer, pcchBuffer, szBuffer);
  2242. break;
  2243. }
  2244. }
  2245. }
  2246. Trace(TEXT("pBuffer contains: %s (%d)"), pBuffer ? pBuffer:TEXT("<NULL>"), *pcchBuffer);
  2247. TraceLeaveValue(*pcchBuffer);
  2248. }
  2249. HRESULT CDsQuery::_FilterView(BOOL fCheck)
  2250. {
  2251. HRESULT hr = S_OK;
  2252. LPTSTR pFilter = NULL;
  2253. UINT cchFilter;
  2254. BOOL fSetCursor = FALSE;
  2255. TraceEnter(TRACE_VIEW, "CDsQuery::_FilterView");
  2256. if (!_hdpaResults)
  2257. ExitGracefully(hr, S_OK, "FitlerView bailing, no results");
  2258. DECLAREWAITCURSOR;
  2259. SetWaitCursor(); // this could take some time
  2260. fSetCursor = TRUE;
  2261. // get the current filter string, this consists of the filter
  2262. // information from all the columns
  2263. if (_GetFilter(_hdsaColumns, NULL, &cchFilter))
  2264. {
  2265. hr = LocalAllocStringLen(&pFilter, cchFilter);
  2266. FailGracefully(hr, "Failed to allocate filter string");
  2267. _GetFilter(_hdsaColumns, pFilter, &cchFilter);
  2268. }
  2269. // if the filters don't match then re-populate the view,
  2270. // as the criteria for the results has changed
  2271. if (!fCheck ||
  2272. (!pFilter || !_pFilter) ||
  2273. (pFilter && _pFilter && StrCmpI(pFilter, _pFilter)))
  2274. {
  2275. LPTSTR pBuffer;
  2276. TraceMsg("Filtering the view, filters differ");
  2277. ListView_DeleteAllItems(_hwndView);
  2278. _ShowBanner(SWP_SHOWWINDOW, IDS_FILTERING);
  2279. if (SUCCEEDED(FormatMsgResource(&pBuffer, GLOBAL_HINSTANCE, IDS_FILTERING)))
  2280. {
  2281. _pqf->SetStatusText(pBuffer);
  2282. LocalFreeString(&pBuffer);
  2283. }
  2284. _PopulateView(0, DPA_GetPtrCount(_hdpaResults));
  2285. }
  2286. // ensure we hang onto the new filter, discarding the previous one
  2287. LocalFreeString(&_pFilter);
  2288. _pFilter = pFilter;
  2289. exit_gracefully:
  2290. if (fSetCursor)
  2291. ResetWaitCursor();
  2292. TraceLeaveResult(hr);
  2293. }
  2294. /*-----------------------------------------------------------------------------
  2295. / CDsQuery::_PopulateView
  2296. / ----------------------
  2297. / Add items from the result DPA to the view filtering as required. The
  2298. / caller gives us the start index (0 if all) and we walk the results
  2299. / adding them to the view.
  2300. /
  2301. / In:
  2302. / iItem = first item to add / == 0 first / == -1 then add none, just update status
  2303. / iLast = last item to be updated
  2304. /
  2305. / Out:
  2306. / HRESULT
  2307. /----------------------------------------------------------------------------*/
  2308. HRESULT CDsQuery::_PopulateView(INT iItem, INT iLast)
  2309. {
  2310. HRESULT hr;
  2311. BOOL fBannerShown = IsWindowVisible(_hwndBanner);
  2312. LPTSTR pBuffer = NULL;
  2313. LV_ITEM lvi;
  2314. INT iColumn, i;
  2315. INT iVisible = 0;
  2316. INT iHidden = 0;
  2317. BOOL fIncludeItem;
  2318. MSG msg;
  2319. TraceEnter(TRACE_VIEW, "CDsQuery::_PopulateView");
  2320. Trace(TEXT("Range %d to %d"), iItem, iLast);
  2321. if (iItem > -1)
  2322. {
  2323. Trace(TEXT("Adding items %d to %d"), iItem, DPA_GetPtrCount(_hdpaResults));
  2324. lvi.mask = LVIF_TEXT|LVIF_PARAM|LVIF_IMAGE;
  2325. lvi.iItem = 0x7fffffff;
  2326. lvi.iSubItem = 0;
  2327. lvi.pszText = LPSTR_TEXTCALLBACK;
  2328. // Walk the results in the range we need to add and add them to the view
  2329. // applying the filter to remove items we are not interested in.
  2330. for (i = 0; iItem < iLast ; i++, iItem++)
  2331. {
  2332. LPQUERYRESULT pResult = (LPQUERYRESULT)DPA_GetPtr(_hdpaResults, iItem);
  2333. if (!pResult)
  2334. continue;
  2335. fIncludeItem = TRUE; // new items always get included
  2336. // if the filter is visilbe then lets walk it removing items from the list
  2337. // of results. fIncludeItem starts as TRUE and after the filter
  2338. // loop should become either TRUE/FALSE. All columns are ANDed together
  2339. // therefore the logic is quite simple.
  2340. if (_fFilter)
  2341. {
  2342. for (iColumn = 0 ; fIncludeItem && (iColumn < DSA_GetItemCount(_hdsaColumns)); iColumn++)
  2343. {
  2344. LPCOLUMN pColumn = (LPCOLUMN)DSA_GetItemPtr(_hdsaColumns, iColumn);
  2345. TraceAssert(pColumn);
  2346. // if the column has a filter defined (!PROPERTY_ISUNDEFINED) then
  2347. // check that the properties match, if they don't then skip the
  2348. // itmer otherwise lets try applying the filter based on
  2349. // the type.
  2350. if (pColumn->filter.iPropertyType == PROPERTY_ISUNDEFINED)
  2351. continue;
  2352. if (pResult->aColumn[iColumn].iPropertyType == PROPERTY_ISUNDEFINED)
  2353. {
  2354. // column is undefined therefore lets ignore it, it won't
  2355. // match the criteria
  2356. fIncludeItem = FALSE;
  2357. }
  2358. else
  2359. {
  2360. switch (pColumn->filter.iPropertyType)
  2361. {
  2362. case PROPERTY_ISUNDEFINED:
  2363. break;
  2364. case PROPERTY_ISUNKNOWN:
  2365. case PROPERTY_ISSTRING:
  2366. case PROPERTY_ISDNSTRING:
  2367. {
  2368. TCHAR szBuffer[MAX_PATH];
  2369. LPTSTR pszBuffer = NULL;
  2370. LPTSTR pszValue = pResult->aColumn[iColumn].pszText;
  2371. INT cchValue = lstrlen(pszValue);
  2372. LPTSTR pszValueUC = szBuffer;
  2373. // the filter value is stored in uppercase, so to ensure we are case insensitive
  2374. // we must convert the string to uppercase. We have a buffer we will use,
  2375. // however, if the value is too large we will allocate a buffer we can use.
  2376. if (cchValue > ARRAYSIZE(szBuffer))
  2377. {
  2378. TraceMsg("Value too big for our static buffer, so allocating");
  2379. if (FAILED(LocalAllocStringLen(&pszBuffer, cchValue)))
  2380. {
  2381. TraceMsg("Failed to allocate a buffer for the string, so ignoring it!");
  2382. fIncludeItem = FALSE;
  2383. break;
  2384. }
  2385. pszValueUC = pszBuffer; // fix the pointer to the new string
  2386. }
  2387. LCMapString(0x0, LCMAP_UPPERCASE, pszValue, -1, pszValueUC, cchValue+1);
  2388. Trace(TEXT("After converting to uppercase (LCMapString): %s"), pszValueUC);
  2389. // string properties need to be compared using the match filter
  2390. // function, this code is given the filter and the result
  2391. // and we must compare, in return we get TRUE/FALSE, therefore
  2392. // catch the NOT cases specificly.
  2393. switch (pColumn->idOperator)
  2394. {
  2395. case FILTER_CONTAINS:
  2396. case FILTER_STARTSWITH:
  2397. case FILTER_ENDSWITH:
  2398. case FILTER_IS:
  2399. fIncludeItem = MatchPattern(pszValueUC, pColumn->filter.pszText);
  2400. break;
  2401. case FILTER_NOTCONTAINS:
  2402. case FILTER_ISNOT:
  2403. fIncludeItem = !MatchPattern(pszValueUC, pColumn->filter.pszText);
  2404. break;
  2405. }
  2406. LocalFreeString(&pszBuffer); // ensure we don't leak, in thise case it would be costly!
  2407. break;
  2408. }
  2409. case PROPERTY_ISBOOL:
  2410. case PROPERTY_ISNUMBER:
  2411. {
  2412. // numeric properties are handled only as ints, therefore
  2413. // lets compare the numeric value we have
  2414. switch (pColumn->idOperator)
  2415. {
  2416. case FILTER_IS:
  2417. fIncludeItem = (pColumn->filter.iValue == pResult->aColumn[iColumn].iValue);
  2418. break;
  2419. case FILTER_ISNOT:
  2420. fIncludeItem = (pColumn->filter.iValue != pResult->aColumn[iColumn].iValue);
  2421. break;
  2422. case FILTER_GREATEREQUAL:
  2423. fIncludeItem = (pColumn->filter.iValue <= pResult->aColumn[iColumn].iValue);
  2424. break;
  2425. case FILTER_LESSEQUAL:
  2426. fIncludeItem = (pColumn->filter.iValue >= pResult->aColumn[iColumn].iValue);
  2427. break;
  2428. }
  2429. break;
  2430. }
  2431. }
  2432. }
  2433. }
  2434. }
  2435. Trace(TEXT("fInclude item is %d"), fIncludeItem);
  2436. if (fIncludeItem)
  2437. {
  2438. // we are going to add the item to the view, so lets hide the banner
  2439. // if it is shown, then add a list view item. The list view
  2440. // item has text-callback and the lParam -> pResult structure
  2441. // we are using.
  2442. //
  2443. // also, if the view hasn't had the image list set then lets
  2444. // take care of that now
  2445. if (fBannerShown)
  2446. {
  2447. TraceMsg("Adding an item and banner visible, therefore hiding");
  2448. _ShowBanner(SWP_HIDEWINDOW, 0); // hide the banner
  2449. fBannerShown = FALSE;
  2450. }
  2451. lvi.lParam = (LPARAM)pResult;
  2452. lvi.iImage = pResult->iImage;
  2453. ListView_InsertItem(_hwndView, &lvi);
  2454. if (i % FILTER_UPDATE_COUNT)
  2455. UpdateWindow(_hwndView);
  2456. }
  2457. }
  2458. }
  2459. // lets update the status bar to reflect the world around us
  2460. TraceAssert(_hdpaResults);
  2461. if (_hdpaResults)
  2462. {
  2463. iVisible = ListView_GetItemCount(_hwndView);
  2464. iHidden = DPA_GetPtrCount(_hdpaResults)-iVisible;
  2465. }
  2466. if (iVisible <= 0)
  2467. {
  2468. _ShowBanner(SWP_SHOWWINDOW, IDS_NOTHINGFOUND);
  2469. }
  2470. else
  2471. {
  2472. // ensure that at least one item in the view has focus
  2473. if (-1 == ListView_GetNextItem(_hwndView, -1, LVNI_FOCUSED))
  2474. ListView_SetItemState(_hwndView, 0, LVIS_FOCUSED, LVIS_FOCUSED);
  2475. }
  2476. if (SUCCEEDED(FormatMsgResource(&pBuffer,
  2477. GLOBAL_HINSTANCE, iHidden ? IDS_FOUNDITEMSHIDDEN:IDS_FOUNDITEMS,
  2478. iVisible, iHidden)))
  2479. {
  2480. Trace(TEXT("Setting status text to: %s"), pBuffer);
  2481. _pqf->SetStatusText(pBuffer);
  2482. LocalFreeString(&pBuffer);
  2483. }
  2484. _iSortColumn = -1; // sort is no longer valid!
  2485. TraceLeaveResult(S_OK);
  2486. }
  2487. /*-----------------------------------------------------------------------------
  2488. / CDsQuery::_FreeResults
  2489. / ---------------------
  2490. / Do the tidy up to release the results from the view. This includes
  2491. / destroying the DPA and removing the items from the list view.
  2492. /
  2493. / In:
  2494. / Out:
  2495. / -
  2496. /----------------------------------------------------------------------------*/
  2497. VOID CDsQuery::_FreeResults(VOID)
  2498. {
  2499. TraceEnter(TRACE_VIEW, "CDsQuery::_FreeResults");
  2500. if (IsWindow(_hwndView))
  2501. ListView_DeleteAllItems(_hwndView);
  2502. if (_hdpaResults)
  2503. {
  2504. DPA_DestroyCallback(_hdpaResults, FreeQueryResultCB, IntToPtr(DSA_GetItemCount(_hdsaColumns)));
  2505. _hdpaResults = NULL;
  2506. }
  2507. LocalFreeString(&_pFilter);
  2508. TraceLeave();
  2509. }
  2510. /*-----------------------------------------------------------------------------
  2511. / CDsQuery::_SetViewMode
  2512. / ---------------------
  2513. / Convert the command ID of the view mode into a LVS_ style bit that can
  2514. / then we applied to the view.
  2515. /
  2516. / In:
  2517. / uID = view mode to be selected
  2518. /
  2519. / Out:
  2520. / DWORD = LVS_ style for this view mode
  2521. /----------------------------------------------------------------------------*/
  2522. DWORD CDsQuery::_SetViewMode(INT uID)
  2523. {
  2524. const DWORD dwIdToStyle[] = { LVS_ICON, LVS_SMALLICON, LVS_LIST, LVS_REPORT };
  2525. DWORD dwResult = 0;
  2526. DWORD dwStyle;
  2527. TraceEnter(TRACE_HANDLER|TRACE_VIEW, "CDsQuery::_SetViewMode");
  2528. Trace(TEXT("Setting view mode to %08x"), uID);
  2529. _idViewMode = uID;
  2530. uID -= DSQH_VIEW_LARGEICONS;
  2531. if (uID < ARRAYSIZE(dwIdToStyle))
  2532. {
  2533. dwResult = dwIdToStyle[uID];
  2534. if (IsWindow(_hwndView))
  2535. {
  2536. dwStyle = GetWindowLong(_hwndView, GWL_STYLE);
  2537. if ((dwStyle & LVS_TYPEMASK) != dwResult)
  2538. {
  2539. TraceMsg("Changing view style to reflect new mode");
  2540. SetWindowLong(_hwndView, GWL_STYLE, (dwStyle & ~LVS_TYPEMASK)|dwResult);
  2541. }
  2542. }
  2543. }
  2544. _ShowBanner(0, 0);
  2545. TraceLeaveValue(dwResult);
  2546. }
  2547. /*-----------------------------------------------------------------------------
  2548. / CDsQuery::_SetFilter
  2549. / -------------------
  2550. / Sets the visible state of the filter, refreshing the view as required.
  2551. /
  2552. / NB: To ensure that the ListView correctly refrehes its contents we first
  2553. / remove the header from the view, then toggle the filter state
  2554. / and re-enable the banner.
  2555. / In:
  2556. / fFilter = flag indicating the filter state
  2557. /
  2558. / Out:
  2559. / VOID
  2560. /----------------------------------------------------------------------------*/
  2561. VOID CDsQuery::_SetFilter(BOOL fFilter)
  2562. {
  2563. TraceEnter(TRACE_HANDLER|TRACE_VIEW, "CDsQuery::_SetFilter");
  2564. _fFilter = fFilter; // store the new filter value
  2565. if (IsWindow(_hwndView))
  2566. {
  2567. HWND hwndHeader = ListView_GetHeader(_hwndView);
  2568. DWORD dwStyle = GetWindowLong(hwndHeader, GWL_STYLE) & ~(HDS_FILTERBAR|WS_TABSTOP);
  2569. SetWindowLong(_hwndView, GWL_STYLE, GetWindowLong(_hwndView, GWL_STYLE) | LVS_NOCOLUMNHEADER);
  2570. if (_fFilter)
  2571. dwStyle |= HDS_FILTERBAR|WS_TABSTOP;
  2572. SetWindowLong(hwndHeader, GWL_STYLE, dwStyle);
  2573. SetWindowLong(_hwndView, GWL_STYLE, GetWindowLong(_hwndView, GWL_STYLE) & ~LVS_NOCOLUMNHEADER);
  2574. _ShowBanner(0, 0);
  2575. if (_hdpaResults)
  2576. {
  2577. if ((_fFilter && _pFilter) ||
  2578. (!_fFilter && (DPA_GetPtrCount(_hdpaResults) != ListView_GetItemCount(_hwndView))))
  2579. {
  2580. _FilterView(FALSE);
  2581. }
  2582. }
  2583. }
  2584. TraceLeave();
  2585. }
  2586. /*-----------------------------------------------------------------------------
  2587. / CDsQuery::_SortResults
  2588. / ---------------------
  2589. / Sort the view given a column, handles either being clicked or
  2590. / invoked on from an API.
  2591. /
  2592. / In:
  2593. / iColumn = column to sort on
  2594. /
  2595. / Out:
  2596. / -
  2597. /----------------------------------------------------------------------------*/
  2598. INT _ResultSortCB(LPARAM lParam1, LPARAM lParam2, LPARAM lParam)
  2599. {
  2600. LPQUERYRESULT pResult1, pResult2;
  2601. INT iColumn = LOWORD(lParam);
  2602. // if lParam != 0 then we are reverse sorting, therefore swap
  2603. // over the object pointers
  2604. if (!HIWORD(lParam))
  2605. {
  2606. pResult1 = (LPQUERYRESULT)lParam1;
  2607. pResult2 = (LPQUERYRESULT)lParam2;
  2608. }
  2609. else
  2610. {
  2611. pResult2 = (LPQUERYRESULT)lParam1;
  2612. pResult1 = (LPQUERYRESULT)lParam2;
  2613. }
  2614. if (pResult1 && pResult2)
  2615. {
  2616. LPCOLUMNVALUE pColumn1 = (LPCOLUMNVALUE)&pResult1->aColumn[iColumn];
  2617. LPCOLUMNVALUE pColumn2 = (LPCOLUMNVALUE)&pResult2->aColumn[iColumn];
  2618. BOOL fHasColumn1 = pColumn1->iPropertyType != PROPERTY_ISUNDEFINED;
  2619. BOOL fHasColumn2 = pColumn2->iPropertyType != PROPERTY_ISUNDEFINED;
  2620. // check that both properties are defined, if they are not then return the
  2621. // comparison based on that field. then we check that the properties
  2622. // are the same type, if that matches then lets compare based on the
  2623. // type.
  2624. if (!fHasColumn1 || !fHasColumn2)
  2625. {
  2626. return fHasColumn1 ? -1:+1;
  2627. }
  2628. else
  2629. {
  2630. TraceAssert(pColumn1->iPropertyType == pColumn2->iPropertyType);
  2631. switch (pColumn1->iPropertyType)
  2632. {
  2633. case PROPERTY_ISUNDEFINED:
  2634. break;
  2635. case PROPERTY_ISUNKNOWN:
  2636. case PROPERTY_ISSTRING:
  2637. case PROPERTY_ISDNSTRING:
  2638. return StrCmpI(pColumn1->pszText, pColumn2->pszText);
  2639. case PROPERTY_ISBOOL:
  2640. case PROPERTY_ISNUMBER:
  2641. return pColumn1->iValue - pColumn2->iValue;
  2642. }
  2643. }
  2644. }
  2645. return 0;
  2646. }
  2647. VOID CDsQuery::_SortResults(INT iColumn)
  2648. {
  2649. DECLAREWAITCURSOR;
  2650. TraceEnter(TRACE_VIEW, "CDsQuery::_SortResults");
  2651. Trace(TEXT("iColumn %d"), iColumn);
  2652. if ((iColumn >= 0) && (iColumn < DSA_GetItemCount(_hdsaColumns)))
  2653. {
  2654. // if we have already hit the column then lets invert the sort order,
  2655. // there is no indicator to worry about so this should just work out
  2656. // fine. if we haven't used this column before then default oto
  2657. // ascending, then do the sort!
  2658. //
  2659. // ensure that the focused item is visible when the sort has completed
  2660. if (_iSortColumn == iColumn)
  2661. _fSortDescending = !_fSortDescending;
  2662. else
  2663. _fSortDescending = FALSE;
  2664. _iSortColumn = iColumn;
  2665. Trace(TEXT("Sorting on column %d, %s"),
  2666. _iSortColumn, _fSortDescending ? TEXT("(descending)"):TEXT("(ascending)"));
  2667. SetWaitCursor();
  2668. ListView_SortItems(_hwndView, _ResultSortCB, MAKELPARAM(_iSortColumn, _fSortDescending));
  2669. ResetWaitCursor();
  2670. }
  2671. TraceLeave();
  2672. }
  2673. /*-----------------------------------------------------------------------------
  2674. / CDsQuery::_ShowBanner
  2675. / --------------------
  2676. / Show the views banner, including sizing it to obscure only the top section
  2677. / of the window.
  2678. /
  2679. / In:
  2680. / uFlags = flags to combine when calling SetWindowPos
  2681. / idPrompt = resource ID of prompt text ot be displayed
  2682. /
  2683. / Out:
  2684. / -
  2685. /----------------------------------------------------------------------------*/
  2686. VOID CDsQuery::_ShowBanner(UINT uFlags, UINT idPrompt)
  2687. {
  2688. HRESULT hr;
  2689. WINDOWPOS wpos;
  2690. RECT rcClient;
  2691. HD_LAYOUT hdl;
  2692. TCHAR szBuffer[MAX_PATH];
  2693. TraceEnter(TRACE_VIEW, "CDsQuery::_ShowBanner");
  2694. // if we have a resource id then lets load the string and
  2695. // set the window text to have it
  2696. if (idPrompt)
  2697. {
  2698. LoadString(GLOBAL_HINSTANCE, idPrompt, szBuffer, ARRAYSIZE(szBuffer));
  2699. SetWindowText(_hwndBanner, szBuffer);
  2700. }
  2701. // now position the window back to real location, this we need to
  2702. // talk to the listview/header control to work out exactly where it
  2703. // should be living
  2704. GetClientRect(_hwndView, &rcClient);
  2705. if ((GetWindowLong(_hwndView, GWL_STYLE) & LVS_TYPEMASK) == LVS_REPORT)
  2706. {
  2707. TraceMsg("Calling header for layout information");
  2708. wpos.hwnd = ListView_GetHeader(_hwndView);
  2709. wpos.hwndInsertAfter = NULL;
  2710. wpos.x = 0;
  2711. wpos.y = 0;
  2712. wpos.cx = rcClient.right;
  2713. wpos.cy = rcClient.bottom;
  2714. wpos.flags = SWP_NOZORDER;
  2715. hdl.prc = &rcClient;
  2716. hdl.pwpos = &wpos;
  2717. if (!Header_Layout(wpos.hwnd, &hdl))
  2718. ExitGracefully(hr, E_FAIL, "Failed to get the layout information (HDM_LAYOUT)");
  2719. }
  2720. SetWindowPos(_hwndBanner,
  2721. HWND_TOP,
  2722. rcClient.left, rcClient.top,
  2723. rcClient.right - rcClient.left, 100,
  2724. uFlags);
  2725. exit_gracefully:
  2726. TraceLeave();
  2727. }
  2728. /*-----------------------------------------------------------------------------
  2729. / CDsQuery::_InitViewMenuItems
  2730. / ---------------------------
  2731. / Setup the view menu based on the given view mode and the filter state, enabled
  2732. / disable the items as required.
  2733. /
  2734. / In:
  2735. / hMenu = menu to set the menu items on
  2736. /
  2737. / Out:
  2738. / -
  2739. /----------------------------------------------------------------------------*/
  2740. VOID CDsQuery::_InitViewMenuItems(HMENU hMenu)
  2741. {
  2742. MENUITEMINFO mii;
  2743. HMENU hArrangeMenu;
  2744. BOOL fHaveView = IsWindow(_hwndView);
  2745. INT i;
  2746. TraceEnter(TRACE_HANDLER|TRACE_VIEW, "CDsQuery::_InitViewMenuItems");
  2747. CheckMenuItem(hMenu, DSQH_VIEW_FILTER, MF_BYCOMMAND| (_fFilter ? MF_CHECKED:0));
  2748. ENABLE_MENU_ITEM(hMenu, DSQH_VIEW_FILTER, fHaveView && _fFilterSupported && (_idViewMode == DSQH_VIEW_DETAILS));
  2749. CheckMenuRadioItem(hMenu, DSQH_VIEW_LARGEICONS, DSQH_VIEW_DETAILS, _idViewMode, MF_BYCOMMAND);
  2750. // construct the arrange menu, add it to the view menu that we have been given.
  2751. hArrangeMenu = CreatePopupMenu();
  2752. TraceAssert(hArrangeMenu);
  2753. if (_hdsaColumns && DSA_GetItemCount(_hdsaColumns))
  2754. {
  2755. TCHAR szFmt[32];
  2756. TCHAR szBuffer[MAX_PATH];
  2757. hArrangeMenu = CreatePopupMenu();
  2758. TraceAssert(hArrangeMenu);
  2759. LoadString(GLOBAL_HINSTANCE, IDS_ARRANGEBY, szFmt, ARRAYSIZE(szFmt));
  2760. if (hArrangeMenu)
  2761. {
  2762. for (i = 0 ; i < DSA_GetItemCount(_hdsaColumns); i++)
  2763. {
  2764. LPCOLUMN pColumn = (LPCOLUMN)DSA_GetItemPtr(_hdsaColumns, i);
  2765. TraceAssert(pColumn);
  2766. // NTRAID#NTBUG9-554458-2002/02/20-lucios. Pending fix.
  2767. wsprintf(szBuffer, szFmt, pColumn->pHeading);
  2768. InsertMenu(hArrangeMenu, i, MF_STRING|MF_BYPOSITION, DSQH_VIEW_ARRANGEFIRST+i, szBuffer);
  2769. }
  2770. }
  2771. }
  2772. // now place the arrange menu into the view and ungrey as required.
  2773. ZeroMemory(&mii, SIZEOF(mii));
  2774. mii.cbSize = SIZEOF(mii);
  2775. mii.fMask = MIIM_SUBMENU|MIIM_ID;
  2776. mii.hSubMenu = hArrangeMenu;
  2777. mii.wID = DSQH_VIEW_ARRANGEICONS;
  2778. if (SetMenuItemInfo(hMenu, DSQH_VIEW_ARRANGEICONS, FALSE, &mii))
  2779. {
  2780. ENABLE_MENU_ITEM(hMenu, DSQH_VIEW_ARRANGEICONS, fHaveView && GetMenuItemCount(hArrangeMenu));
  2781. hArrangeMenu = NULL;
  2782. }
  2783. if (hArrangeMenu)
  2784. DestroyMenu(hArrangeMenu);
  2785. TraceLeave();
  2786. }
  2787. /*-----------------------------------------------------------------------------
  2788. / CDsQuery::_GetQueryFormKey
  2789. / --------------------------
  2790. / Given the CLSID for the query form we are interested in, get the
  2791. / forms key for it, note that these settings are stored per-user.
  2792. /
  2793. / In:
  2794. / clsidForm = CLSID of form to pick up
  2795. / phKey -> recevies the HKEY of the form we are intersted in.
  2796. /
  2797. / Out:
  2798. / HRESULT
  2799. /----------------------------------------------------------------------------*/
  2800. HRESULT CDsQuery::_GetQueryFormKey(REFCLSID clsidForm, HKEY* phKey)
  2801. {
  2802. HRESULT hr;
  2803. TCHAR szGUID[GUIDSTR_MAX];
  2804. TCHAR szBuffer[MAX_PATH];
  2805. TraceEnter(TRACE_VIEW, "CDsQuery::_GetQueryFormKey");
  2806. GetStringFromGUID(clsidForm, szGUID, ARRAYSIZE(szGUID));
  2807. // NTRAID#NTBUG9-554458-2002/02/20-lucios. Pending fix.
  2808. wsprintf(szBuffer, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Directory UI\\QueryForms\\%s"), szGUID);
  2809. Trace(TEXT("Settings key is: %s"), szBuffer);
  2810. if (ERROR_SUCCESS != RegCreateKey(HKEY_CURRENT_USER, szBuffer, phKey))
  2811. ExitGracefully(hr, E_FAIL, "Failed to open settings key");
  2812. hr = S_OK;
  2813. exit_gracefully:
  2814. TraceLeaveResult(hr);
  2815. }
  2816. /*-----------------------------------------------------------------------------
  2817. / CDsQuery::_GetColumnTable
  2818. / ------------------------
  2819. / Build the column table for the view we are about to display. The column
  2820. / table is constructed from either the query parameters or the persisted
  2821. / column settings stored in the registry.
  2822. /
  2823. / In:
  2824. / clsidForm = clisd of the form to be used
  2825. / pDsQueryParams -> query parameter structure to be used
  2826. / pHDSA -> DSA to recieve the column table (sorted by visible order)
  2827. / fSetInView = Set the columns into the view
  2828. /
  2829. / Out:
  2830. / HRESULT
  2831. /----------------------------------------------------------------------------*/
  2832. HRESULT CDsQuery::_GetColumnTable(REFCLSID clsidForm, LPDSQUERYPARAMS pDsQueryParams, HDSA* pHDSA, BOOL fSetInView)
  2833. {
  2834. HRESULT hr;
  2835. HKEY hKey = NULL;
  2836. BOOL fDefaultSettings = TRUE;
  2837. LPSAVEDCOLUMN aSavedColumn = NULL;
  2838. LPTSTR pSettingsValue = VIEW_SETTINGS_VALUE;
  2839. BOOL fHaveSizeInfo = FALSE;
  2840. LPWSTR pPropertyG;
  2841. DWORD dwType, cbSize;
  2842. LV_COLUMN lvc;
  2843. SIZE sz;
  2844. INT i, iNewColumn;
  2845. HD_ITEM hdi;
  2846. IDsDisplaySpecifier *pdds = NULL;
  2847. TraceEnter(TRACE_VIEW, "CDsQuery::_GetColumnTable");
  2848. TraceGUID("clsidForm ", clsidForm);
  2849. Trace(TEXT("pDsQueryParams %08x, pHDSA %08x"), pDsQueryParams, pHDSA);
  2850. DECLAREWAITCURSOR;
  2851. SetWaitCursor();
  2852. if (!pHDSA)
  2853. ExitGracefully(hr, E_INVALIDARG, "Bad pDsQueryParams / pHDSA");
  2854. // construct the column DSA then attempt to look up the view settings stored in
  2855. // the registry for the current form.
  2856. *pHDSA = DSA_Create(SIZEOF(COLUMN), 16);
  2857. TraceAssert(*pHDSA);
  2858. if (!*pHDSA)
  2859. ExitGracefully(hr, E_OUTOFMEMORY, "Failed to construct the column DSA");
  2860. // If invoked for admin UI then we look at the admin view settings, this way
  2861. // the admin can have one set of columns, and the user can have another.
  2862. if (_dwFlags & DSQPF_ENABLEADMINFEATURES)
  2863. pSettingsValue = ADMIN_VIEW_SETTINGS_VALUE;
  2864. Trace(TEXT("View settings value: %s"), pSettingsValue);
  2865. if (SUCCEEDED(_GetQueryFormKey(clsidForm, &hKey)))
  2866. {
  2867. // we have the handle to the forms sub-key table, now lets check and
  2868. // see what size the view settings stream is.
  2869. if ((ERROR_SUCCESS == RegQueryValueEx(hKey, pSettingsValue, NULL, &dwType, NULL, &cbSize)) &&
  2870. (dwType == REG_BINARY) &&
  2871. (cbSize > SIZEOF(SAVEDCOLUMN)))
  2872. {
  2873. Trace(TEXT("Reading view settings from registry (size %d)"), cbSize);
  2874. aSavedColumn = (LPSAVEDCOLUMN)LocalAlloc(LPTR, cbSize);
  2875. TraceAssert(aSavedColumn);
  2876. if (aSavedColumn &&
  2877. (ERROR_SUCCESS == RegQueryValueEx(hKey, pSettingsValue, NULL, NULL, (LPBYTE)aSavedColumn, &cbSize)))
  2878. {
  2879. // compute the size of the table from the values that we have
  2880. // read from the registry and now lets allocate a table for it
  2881. for (i = 0; aSavedColumn[i].cbSize; i++)
  2882. {
  2883. COLUMN column = { 0 };
  2884. LPCWSTR pPropertyL = (LPCWSTR)ByteOffset(aSavedColumn, aSavedColumn[i].offsetProperty);
  2885. LPCTSTR pHeading = (LPCTSTR)ByteOffset(aSavedColumn, aSavedColumn[i].offsetHeading);
  2886. hr = LocalAllocStringW(&column.pProperty, pPropertyL);
  2887. FailGracefully(hr, "Failed to allocate property name");
  2888. hr = LocalAllocString(&column.pHeading, pHeading);
  2889. FailGracefully(hr, "Failed to allocate column heading");
  2890. //column.fHasColumnProvider = FALSE;
  2891. column.cx = aSavedColumn[i].cx;
  2892. column.fmt = aSavedColumn[i].fmt;
  2893. column.iPropertyType = PROPERTY_ISUNKNOWN;
  2894. //column.idOperator = 0;
  2895. //column.clsidColumnHandler = { 0 };
  2896. //column.pColumnHandler = NULL;
  2897. ZeroMemory(&column.filter, SIZEOF(column.filter));
  2898. column.filter.iPropertyType = PROPERTY_ISUNDEFINED;
  2899. Trace(TEXT("pProperty: '%s', pHeading: '%s', cx %d, fmt %08x"),
  2900. column.pProperty, column.pHeading, column.cx, column.fmt);
  2901. if (-1 == DSA_AppendItem(*pHDSA, &column))
  2902. ExitGracefully(hr, E_OUTOFMEMORY, "Failed to add column to the DSA");
  2903. }
  2904. fDefaultSettings = FALSE; // success we have a table
  2905. }
  2906. }
  2907. }
  2908. if (fDefaultSettings)
  2909. {
  2910. // unable to read the settings from the registy, therefore defaulting to
  2911. // those defined in the query parameters block.
  2912. if (!pDsQueryParams)
  2913. ExitGracefully(hr, E_INVALIDARG, "No DSQUERYPARAMs to default using");
  2914. for (i = 0 ; i < pDsQueryParams->iColumns; i++)
  2915. {
  2916. COLUMN column = { 0 };
  2917. switch (pDsQueryParams->aColumns[i].offsetProperty)
  2918. {
  2919. case DSCOLUMNPROP_ADSPATH:
  2920. pPropertyG = c_szADsPathCH;
  2921. break;
  2922. case DSCOLUMNPROP_OBJECTCLASS:
  2923. pPropertyG = c_szObjectClassCH;
  2924. break;
  2925. default:
  2926. pPropertyG = (LPWSTR)ByteOffset(pDsQueryParams, pDsQueryParams->aColumns[i].offsetProperty);
  2927. break;
  2928. }
  2929. hr = LocalAllocStringW(&column.pProperty, pPropertyG);
  2930. FailGracefully(hr, "Failed to allocate property name");
  2931. hr = FormatMsgResource(&column.pHeading, pDsQueryParams->hInstance, pDsQueryParams->aColumns[i].idsName);
  2932. FailGracefully(hr, "Failed to allocate column heading");
  2933. //column.fHasColumnProvider = FALSE;
  2934. column.cx = pDsQueryParams->aColumns[i].cx;
  2935. column.fmt = pDsQueryParams->aColumns[i].fmt;
  2936. column.iPropertyType = PROPERTY_ISUNKNOWN;
  2937. //column.idOperator = 0;
  2938. //column.clsidColumnHandler = { 0 };
  2939. //column.pColumnHandler = NULL;
  2940. ZeroMemory(&column.filter, SIZEOF(column.filter));
  2941. column.filter.iPropertyType = PROPERTY_ISUNDEFINED;
  2942. // Now fix the width of the column we are about to specify, this
  2943. // value has the following meaning:
  2944. //
  2945. // == 0 => use default width
  2946. // > 0 => user 'n' magic characters
  2947. // < 0 => pixel width
  2948. // FEATURE: -ve should be % of the view
  2949. if (column.cx < 0)
  2950. {
  2951. TraceMsg("Column width specified in pixels");
  2952. column.cx = -column.cx;
  2953. }
  2954. else
  2955. {
  2956. // Default the size if it is == 0, then having done this
  2957. // lets grab the font we want to use before moving on
  2958. // to create a DC and measure the character we need.
  2959. if (!column.cx)
  2960. column.cx = DEFAULT_WIDTH;
  2961. sz.cx = 10; // random default value.
  2962. if (!fHaveSizeInfo)
  2963. {
  2964. HDC hDC;
  2965. LOGFONT lf;
  2966. HFONT hFont, hOldFont;
  2967. SystemParametersInfo(SPI_GETICONTITLELOGFONT, SIZEOF(lf), &lf, FALSE);
  2968. hFont = CreateFontIndirect(&lf); // icon title font
  2969. if (hFont)
  2970. {
  2971. hDC = CreateCompatibleDC(NULL); // screen compatible DC
  2972. if (hDC)
  2973. {
  2974. hOldFont = (HFONT)SelectObject(hDC, hFont);
  2975. GetTextExtentPoint(hDC, TEXT("0"), 1, &sz);
  2976. SelectObject(hDC, hOldFont);
  2977. DeleteDC(hDC);
  2978. }
  2979. DeleteFont(hFont);
  2980. }
  2981. fHaveSizeInfo = TRUE;
  2982. }
  2983. column.cx = column.cx*sz.cx; // n chars width
  2984. }
  2985. Trace(TEXT("pProperty: '%s', pHeading: '%s', cx %d, fmt %08x"),
  2986. column.pProperty, column.pHeading, column.cx, column.fmt);
  2987. if (-1 == DSA_AppendItem(*pHDSA, &column))
  2988. ExitGracefully(hr, E_OUTOFMEMORY, "Failed to add column to the DSA");
  2989. }
  2990. }
  2991. // Scan the column list getting both the property name and the CLSID for the
  2992. // column handler (if there is one).
  2993. hr = CoCreateInstance(CLSID_DsDisplaySpecifier, NULL, CLSCTX_INPROC_SERVER, IID_IDsDisplaySpecifier, (void **)&pdds);
  2994. FailGracefully(hr, "Failed to get the IDsDisplaySpecifier interface");
  2995. if ( _dwFlags & DSQPF_HASCREDENTIALS)
  2996. {
  2997. hr = pdds->SetServer(_pServer, _pUserName, _pPassword, DSSSF_DSAVAILABLE);
  2998. FailGracefully(hr, "Failed to server information");
  2999. }
  3000. for (i = 0 ; i < DSA_GetItemCount(*pHDSA) ; i++)
  3001. {
  3002. LPCOLUMN pColumn = (LPCOLUMN)DSA_GetItemPtr(*pHDSA, i);
  3003. TraceAssert(pColumn);
  3004. Trace(TEXT("Property for column %d, %s"), i, pColumn->pProperty);
  3005. // lets get the property type, column handler and the default operator for it.
  3006. hr = GetColumnHandlerFromProperty(pColumn, NULL);
  3007. FailGracefully(hr, "Failed to get the column handler from property string");
  3008. if (pColumn->fHasColumnHandler)
  3009. {
  3010. TraceMsg("Has a column handler, therefore property is now a string");
  3011. pColumn->iPropertyType = PROPERTY_ISSTRING;
  3012. }
  3013. else
  3014. {
  3015. pColumn->iPropertyType = PropertyIsFromAttribute(pColumn->pProperty, pdds);
  3016. }
  3017. pColumn->idOperator = property_type_table[pColumn->iPropertyType].idOperator;
  3018. }
  3019. // Set the columns up in the view (remove all items first) to allow us
  3020. // to add/remove columns as required.
  3021. if (fSetInView)
  3022. {
  3023. for (i = Header_GetItemCount(ListView_GetHeader(_hwndView)); --i >= 0 ;)
  3024. ListView_DeleteColumn(_hwndView, i);
  3025. // add the columns to the view, then having done that set
  3026. // the type of the filter to reflect the property being
  3027. // shown.
  3028. for (i = 0 ; i < DSA_GetItemCount(_hdsaColumns); i++)
  3029. {
  3030. LPCOLUMN pColumn = (LPCOLUMN)DSA_GetItemPtr(_hdsaColumns, i);
  3031. TraceAssert(pColumn);
  3032. lvc.mask = LVCF_TEXT|LVCF_WIDTH|LVCF_FMT;
  3033. lvc.fmt = pColumn->fmt;
  3034. lvc.cx = pColumn->cx;
  3035. lvc.pszText = pColumn->pHeading;
  3036. iNewColumn = ListView_InsertColumn(_hwndView, i, &lvc);
  3037. TraceAssert(iNewColumn != -1);
  3038. if (iNewColumn != i)
  3039. ExitGracefully(hr, E_FAIL, "Failed to add the column to the view");
  3040. hdi.mask = HDI_FILTER;
  3041. hdi.type = property_type_table[pColumn->iPropertyType].hdft|HDFT_HASNOVALUE;
  3042. hdi.pvFilter = NULL;
  3043. Trace(TEXT("iPropertyType %d, hdi.type %08x"), pColumn->iPropertyType, hdi.type);
  3044. if (!Header_SetItem(ListView_GetHeader(_hwndView), iNewColumn, &hdi))
  3045. ExitGracefully(hr, E_FAIL, "Failed to set the filter type into the view");
  3046. }
  3047. }
  3048. hr = S_OK; // success
  3049. exit_gracefully:
  3050. if (hKey)
  3051. RegCloseKey(hKey);
  3052. if (aSavedColumn)
  3053. LocalFree((HLOCAL)aSavedColumn);
  3054. DoRelease(pdds);
  3055. ResetWaitCursor();
  3056. TraceLeaveResult(hr);
  3057. }
  3058. /*-----------------------------------------------------------------------------
  3059. / CDsQuery::_SaveColumnTable
  3060. / -------------------------
  3061. / Free the column table stored in a DSA. This code released all the
  3062. / allocated memory stored with the table.
  3063. /
  3064. / In:
  3065. / Out:
  3066. / -
  3067. /----------------------------------------------------------------------------*/
  3068. VOID CDsQuery::_SaveColumnTable(VOID)
  3069. {
  3070. TraceEnter(TRACE_VIEW, "CDsQuery::_SaveColumnTable");
  3071. _FreeResults();
  3072. if (_hdsaColumns)
  3073. {
  3074. DSA_DestroyCallback(_hdsaColumns, FreeColumnCB, NULL);
  3075. _hdsaColumns = NULL;
  3076. }
  3077. _iSortColumn = -1;
  3078. _fSortDescending = FALSE;
  3079. TraceLeave();
  3080. }
  3081. /*-----------------------------------------------------------------------------
  3082. / CDsQuery::_SaveColumnTable
  3083. / -------------------------
  3084. / Save the current column table from the DPA into the registry so
  3085. / we can restore it the next time the user uses this query form.
  3086. /
  3087. / In:
  3088. / clsidForm = form ID to store it under
  3089. / hdsaColumns -> DSA to destory
  3090. /
  3091. / Out:
  3092. / HRESULT
  3093. /----------------------------------------------------------------------------*/
  3094. HRESULT CDsQuery::_SaveColumnTable(REFCLSID clsidForm, HDSA hdsaColumns)
  3095. {
  3096. HRESULT hr;
  3097. LPWSTR pProperty;
  3098. LPSAVEDCOLUMN aSavedColumn = NULL;
  3099. DWORD cbData, offset;
  3100. HKEY hKey = NULL;
  3101. LPTSTR pSettingsValue = VIEW_SETTINGS_VALUE;
  3102. INT i;
  3103. TraceEnter(TRACE_VIEW, "CDsQuery::_SaveColumnTable");
  3104. TraceGUID("clsidForm ", clsidForm);
  3105. if (!hdsaColumns)
  3106. ExitGracefully(hr, E_FAIL, "No column data to save");
  3107. // first compute the size of the blob we are going to store into
  3108. // the registry, whilst doing this compute the offset to
  3109. // the start of the string data.
  3110. offset = SIZEOF(SAVEDCOLUMN);
  3111. cbData = SIZEOF(SAVEDCOLUMN);
  3112. for (i = 0 ; i < DSA_GetItemCount(hdsaColumns); i++)
  3113. {
  3114. LPCOLUMN pColumn = (LPCOLUMN)DSA_GetItemPtr(hdsaColumns, i);
  3115. TraceAssert(pColumn);
  3116. offset += SIZEOF(SAVEDCOLUMN);
  3117. cbData += SIZEOF(SAVEDCOLUMN);
  3118. cbData += StringByteSizeW(pColumn->pProperty);
  3119. // this is a potential problem, must be kept in sync with GetPropertyFromColumn
  3120. if (pColumn->fHasColumnHandler)
  3121. cbData += SIZEOF(WCHAR)*(GUIDSTR_MAX + 1); // nb+1 for seperator (,} + string is UNICODE
  3122. cbData += StringByteSize(pColumn->pHeading);
  3123. }
  3124. Trace(TEXT("offset %d, cbData %d"), offset, cbData);
  3125. // Allocate the structure and lets place all the data into it,
  3126. // again running over the data blocks, append the string data
  3127. // to the end of the blob in a single go.
  3128. aSavedColumn = (LPSAVEDCOLUMN)LocalAlloc(LPTR, cbData);
  3129. TraceAssert(aSavedColumn);
  3130. if (!aSavedColumn)
  3131. ExitGracefully(hr, E_OUTOFMEMORY, "Failed to allocate settings data");
  3132. Trace(TEXT("Building data blob at %08x"), aSavedColumn);
  3133. for (i = 0 ; i < DSA_GetItemCount(hdsaColumns); i++)
  3134. {
  3135. LPCOLUMN pColumn = (LPCOLUMN)DSA_GetItemPtr(hdsaColumns, i);
  3136. TraceAssert(pColumn);
  3137. hr = GetPropertyFromColumn(&pProperty, pColumn);
  3138. FailGracefully(hr, "Failed to allocate property from column");
  3139. aSavedColumn[i].cbSize = SIZEOF(SAVEDCOLUMN);
  3140. aSavedColumn[i].dwFlags = 0;
  3141. aSavedColumn[i].offsetProperty = offset;
  3142. aSavedColumn[i].offsetHeading = offset + StringByteSizeW(pProperty);
  3143. aSavedColumn[i].cx = pColumn->cx;
  3144. aSavedColumn[i].fmt = pColumn->fmt;
  3145. StringByteCopyW(aSavedColumn, aSavedColumn[i].offsetProperty, pProperty);
  3146. offset += StringByteSizeW(pProperty);
  3147. StringByteCopy(aSavedColumn, aSavedColumn[i].offsetHeading, pColumn->pHeading);
  3148. offset += StringByteSize(pColumn->pHeading);
  3149. LocalFreeStringW(&pProperty);
  3150. }
  3151. aSavedColumn[i].cbSize = 0; // terminate the list of columns with a NULL
  3152. Trace(TEXT("offset %d, cbData %d"), offset, cbData);
  3153. TraceAssert(offset == cbData);
  3154. // now put the data into the registry filed under the key for the query for that
  3155. // it maps to.
  3156. hr = _GetQueryFormKey(clsidForm, &hKey);
  3157. FailGracefully(hr, "Failed to get settings sub-key");
  3158. // If invoked for admin UI then we look at the admin view settings, this way
  3159. // the admin can have one set of columns, and the user can have another.
  3160. if (_dwFlags & DSQPF_ENABLEADMINFEATURES)
  3161. pSettingsValue = ADMIN_VIEW_SETTINGS_VALUE;
  3162. Trace(TEXT("View settings value: %s"), pSettingsValue);
  3163. if (ERROR_SUCCESS != RegSetValueEx(hKey, pSettingsValue, 0, REG_BINARY, (LPBYTE)aSavedColumn, cbData))
  3164. ExitGracefully(hr, E_FAIL, "Failed to write setting into the view");
  3165. hr = S_OK;
  3166. exit_gracefully:
  3167. if (aSavedColumn)
  3168. LocalFree((HLOCAL)aSavedColumn);
  3169. if (hKey)
  3170. RegCloseKey(hKey);
  3171. TraceLeaveResult(hr);
  3172. }
  3173. // retrieve the context menu object
  3174. HRESULT _FolderCFMCallback(LPSHELLFOLDER psf, HWND hwndView, LPDATAOBJECT pDataObject, UINT uMsg, WPARAM wParam, LPARAM lParam)
  3175. {
  3176. Trace(TEXT("uMsg %d, wParam %08x, lParam %08x"), uMsg, wParam, lParam);
  3177. switch (uMsg)
  3178. {
  3179. case DFM_MERGECONTEXTMENU:
  3180. return S_OK;
  3181. case DFM_INVOKECOMMAND:
  3182. switch (wParam)
  3183. {
  3184. case (WPARAM)DFM_CMD_PROPERTIES:
  3185. TraceMsg("ShowProperties");
  3186. return ShowObjectProperties(hwndView, pDataObject);
  3187. default:
  3188. return S_FALSE;
  3189. }
  3190. break;
  3191. case DFM_GETDEFSTATICID:
  3192. *((WPARAM*)lParam) = (WPARAM)DFM_CMD_PROPERTIES;
  3193. return NOERROR;
  3194. }
  3195. return E_NOTIMPL;
  3196. }
  3197. HRESULT CDsQuery::_GetContextMenu()
  3198. {
  3199. ITEMIDLIST idl = {0};
  3200. LPITEMIDLIST *aidl = NULL;
  3201. HKEY aKeys[UIKEY_MAX] = { 0 };
  3202. int cItems = ListView_GetSelectedCount(_hwndView);
  3203. if (cItems != 0)
  3204. {
  3205. // try to get the selected item (there is one, so first we try the focused, then the selected)
  3206. int i = ListView_GetNextItem(_hwndView, -1, LVNI_FOCUSED|LVNI_SELECTED);
  3207. if (i == -1)
  3208. i = ListView_GetNextItem(_hwndView, -1, LVNI_SELECTED);
  3209. // given the item lets get the result object so that we can create the menu based on
  3210. // the right class information
  3211. LV_ITEM lvi = { 0 };
  3212. lvi.mask = LVIF_PARAM;
  3213. lvi.iItem = i;
  3214. if (ListView_GetItem(_hwndView, &lvi))
  3215. {
  3216. LPQUERYRESULT pResult = (LPQUERYRESULT)lvi.lParam;
  3217. GetKeysForClass(pResult->pObjectClass, pResult->fIsContainer, ARRAYSIZE(aKeys), aKeys);
  3218. }
  3219. aidl = (LPITEMIDLIST*)LocalAlloc(LPTR, sizeof(LPITEMIDLIST)*cItems);
  3220. }
  3221. // given that we probably have the keys we are interested in,
  3222. // lets now create the context menu.
  3223. DoRelease(_pcm); // release the previous context menu
  3224. HRESULT hr = E_OUTOFMEMORY;
  3225. if (!cItems|| (cItems && aidl))
  3226. {
  3227. // fake up the array of IDLISTs so that they can be cloned correctly from
  3228. // the view.
  3229. for (int i= 0 ; i < cItems ; i++)
  3230. aidl[i] = &idl;
  3231. hr = CDefFolderMenu_Create2(&idl, _hwnd,
  3232. cItems, (LPCITEMIDLIST*)aidl,
  3233. this,
  3234. _FolderCFMCallback,
  3235. ARRAYSIZE(aKeys), aKeys,
  3236. &_pcm);
  3237. }
  3238. if (aidl)
  3239. LocalFree(aidl);
  3240. if (FAILED(hr))
  3241. TidyKeys(ARRAYSIZE(aKeys), aKeys);
  3242. return hr;
  3243. }
  3244. /*-----------------------------------------------------------------------------
  3245. / CDsQuery::_GetContextMenuVerbs
  3246. / -----------------------------
  3247. / Do the query context menu handling the case where we have been invoked
  3248. / modally.
  3249. /
  3250. / In:
  3251. / hMenu = menu handle to merge into
  3252. / dwFlags = flags for QueryContextMenu
  3253. /
  3254. / Out:
  3255. / VOID
  3256. /----------------------------------------------------------------------------*/
  3257. VOID CDsQuery::_GetContextMenuVerbs(HMENU hMenu, DWORD dwFlags)
  3258. {
  3259. TCHAR szBuffer[MAX_PATH];
  3260. TraceEnter(TRACE_VIEW, "CDsQuery::_GetContextMenuVerbs");
  3261. _pcm->QueryContextMenu(hMenu, 0, DSQH_FILE_CONTEXT_FIRST, DSQH_FILE_CONTEXT_LAST, dwFlags);
  3262. Trace(TEXT("Menu item count after QueryContextMenu %d (%08x)"), GetMenuItemCount(hMenu), hMenu);
  3263. if ((_dwOQWFlags & OQWF_OKCANCEL) && LoadString(GLOBAL_HINSTANCE, IDS_SELECT, szBuffer, ARRAYSIZE(szBuffer)))
  3264. {
  3265. InsertMenu(hMenu, 0, MF_BYPOSITION|MF_STRING, DSQH_BG_SELECT, szBuffer);
  3266. InsertMenu(hMenu, 1, MF_BYPOSITION|MF_SEPARATOR, 0, NULL);
  3267. SetMenuDefaultItem(hMenu, DSQH_BG_SELECT, FALSE);
  3268. }
  3269. // NTRAID#NTBUG9-598730-2002/05/23-artm
  3270. // Disable property pages when multiple items are selected.
  3271. BOOL enableProperties = ListView_GetSelectedCount(_hwndView) == 1;
  3272. ENABLE_MENU_ITEM(hMenu, DSQH_FILE_PROPERTIES, enableProperties);
  3273. ENABLE_MENU_ITEM(hMenu, DSQH_FILE_CONTEXT_FIRST + SHARED_FILE_PROPERTIES, enableProperties);
  3274. TraceLeave();
  3275. }
  3276. // get the items in the view into a IDataObject, the caller can request either the
  3277. // selection or all the items
  3278. HRESULT CDsQuery::_AddResultToDataObject(HDSA hdsa, INT i)
  3279. {
  3280. LV_ITEM lvi = { 0 };
  3281. lvi.mask = LVIF_PARAM;
  3282. lvi.iItem = i;
  3283. HRESULT hr = E_FAIL;
  3284. if (ListView_GetItem(_hwndView, &lvi))
  3285. {
  3286. QUERYRESULT *pResult = (QUERYRESULT*)lvi.lParam;
  3287. DATAOBJECTITEM doi = {0};
  3288. // copy the strings for the item into the structure
  3289. hr = LocalAllocStringW(&doi.pszPath, pResult->pPath);
  3290. if (SUCCEEDED(hr) && pResult->pObjectClass)
  3291. hr = LocalAllocStringW(&doi.pszObjectClass, pResult->pObjectClass);
  3292. // copy the rest of the state
  3293. doi.fIsContainer = pResult->fIsContainer;
  3294. // append to the DSA.
  3295. if (SUCCEEDED(hr))
  3296. {
  3297. if (-1 == DSA_AppendItem(hdsa, &doi))
  3298. {
  3299. LocalFreeStringW(&doi.pszPath);
  3300. LocalFreeStringW(&doi.pszObjectClass);
  3301. hr = E_OUTOFMEMORY;
  3302. }
  3303. else
  3304. {
  3305. hr = S_OK;
  3306. }
  3307. }
  3308. }
  3309. return hr;
  3310. }
  3311. HRESULT CDsQuery::_GetDataObjectFromSelection(BOOL fGetAll, IDataObject **ppdo)
  3312. {
  3313. HRESULT hr = S_OK;
  3314. HDSA hdsa = DSA_Create(SIZEOF(DATAOBJECTITEM), 16);
  3315. if (hdsa)
  3316. {
  3317. // focused item always come first (primary selection rulz).
  3318. int iFocused = ListView_GetNextItem(_hwndView, -1, LVNI_ALL|LVNI_SELECTED|LVNI_FOCUSED);
  3319. if (iFocused > -1)
  3320. {
  3321. hr = _AddResultToDataObject(hdsa, iFocused);
  3322. }
  3323. // now walk all the items in the view collecting the selection and adding
  3324. // those items to the DPA - we must skip the item which is focused as we
  3325. // have already added it.
  3326. if (SUCCEEDED(hr))
  3327. {
  3328. int i = -1;
  3329. do
  3330. {
  3331. i = ListView_GetNextItem(_hwndView, i, LVNI_ALL|LVNI_SELECTED);
  3332. if ((i >= 0) && (i != iFocused))
  3333. {
  3334. hr = _AddResultToDataObject(hdsa, i);
  3335. }
  3336. }
  3337. while (SUCCEEDED(hr) && (i != -1));
  3338. }
  3339. // given the DPA lets build an IDataObject using it.
  3340. hr = CDataObject_CreateInstance(hdsa,
  3341. (_dwFlags & DSQPF_ENABLEADVANCEDFEATURES),
  3342. IID_IDataObject, (void**)ppdo);
  3343. if (SUCCEEDED(hr))
  3344. hr = _SetDispSpecOptions(*ppdo);
  3345. }
  3346. else
  3347. {
  3348. hr = E_OUTOFMEMORY;
  3349. }
  3350. if (FAILED(hr) && hdsa)
  3351. FreeDataObjectDSA(hdsa); // data object failed to construct, lets kill the DSA
  3352. return hr;
  3353. }
  3354. /*-----------------------------------------------------------------------------
  3355. / CDsQuery::_CopyCredentials
  3356. / --------------------------
  3357. / Copy the user name, password and server as required.
  3358. /
  3359. / In:
  3360. / ppszUserName, psszPassword & ppszServer => destinations
  3361. /
  3362. / Out:
  3363. / HRESULT
  3364. /----------------------------------------------------------------------------*/
  3365. HRESULT CDsQuery::_CopyCredentials(LPWSTR *ppszUserName, LPWSTR *ppszPassword, LPWSTR *ppszServer)
  3366. {
  3367. HRESULT hr;
  3368. TraceEnter(TRACE_VIEW, "CDsQuery::_CopyCredentials");
  3369. hr = LocalAllocStringW(ppszUserName, _pUserName);
  3370. FailGracefully(hr, "Failed to copy the user name");
  3371. hr = LocalAllocStringW(ppszPassword, _pPassword);
  3372. FailGracefully(hr, "Failed to copy the password");
  3373. hr = LocalAllocStringW(ppszServer, _pServer);
  3374. FailGracefully(hr, "Failed to copy the server name");
  3375. exit_gracefully:
  3376. TraceLeaveResult(hr);
  3377. }
  3378. /*-----------------------------------------------------------------------------
  3379. / CDsQuery::OnPickColumns
  3380. /----------------------------------------------------------------------------*/
  3381. typedef struct
  3382. {
  3383. LPWSTR pProperty;
  3384. LPTSTR pHeading;
  3385. BOOL fIsColumn; // item is column and added to column list box on init
  3386. INT cx; // pixel width of column
  3387. INT fmt; // formatting information of column
  3388. } PICKERITEM, * LPPICKERITEM;
  3389. typedef struct
  3390. {
  3391. HDPA hdpaItems; // all the items in the view
  3392. HDSA hdsaColumns; // column table generated by this dialog
  3393. HWND hwndProperties; // hwnd's for the columns/property tables
  3394. HWND hwndColumns;
  3395. } PICKERSTATE, * LPPICKERSTATE;
  3396. VOID _PickerMoveColumn(HWND hwndDest, HWND hwndSrc, BOOL fInsert);
  3397. HRESULT _Picker_GetColumnTable(HWND hwndColumns, HDSA* pHDSA);
  3398. INT_PTR _PickerDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  3399. INT _PickerItemFreeCB(LPVOID pData, LPVOID lParam);
  3400. INT _PickerItemCmpCB(LPVOID p1, LPVOID p2, LPARAM lParam);
  3401. //
  3402. // Help ID mappings
  3403. //
  3404. static DWORD const aPickColumnsHelpIDs[] =
  3405. {
  3406. IDC_LBPROPERTIES, IDH_COLUMNS_AVAILABLE,
  3407. IDC_LBCOLUMNS, IDH_COLUMNS_SHOWN,
  3408. IDC_ADD, IDH_ADD_COLUMNS,
  3409. IDC_REMOVE, IDH_REMOVE_COLUMNS,
  3410. 0, 0
  3411. };
  3412. /*-----------------------------------------------------------------------------
  3413. / _PickerMoveColumn
  3414. / -----------------
  3415. / Move the selected item in one list box to another, we assume that the
  3416. / item data points to a PICKERITEM structure, we transfer the selection
  3417. / and
  3418. /
  3419. / In:
  3420. / hwndSrc, hwndState = windows to move selection within
  3421. / fInsert = insert at selection point in destionation, or add the string (sorted)
  3422. /
  3423. / Out:
  3424. / VOID
  3425. /----------------------------------------------------------------------------*/
  3426. VOID _PickerMoveColumn(HWND hwndDest, HWND hwndSrc, BOOL fInsert)
  3427. {
  3428. INT iSelection, i;
  3429. TraceEnter(TRACE_FIELDCHOOSER, "_PickerMoveColumn");
  3430. iSelection = ListBox_GetCurSel(hwndSrc);
  3431. TraceAssert(iSelection >= 0);
  3432. if (iSelection >= 0)
  3433. {
  3434. LPPICKERITEM pItem = (LPPICKERITEM)ListBox_GetItemData(hwndSrc, iSelection);
  3435. TraceAssert(pItem);
  3436. TraceAssert(pItem->pHeading);
  3437. // Add the new item to the view (if this it the properties)
  3438. // then this will result in the list being sorted and select
  3439. // it to allow the user to remove/add another
  3440. if (fInsert)
  3441. {
  3442. Trace(TEXT("Inserting the item at index %d"), ListBox_GetCurSel(hwndDest)+1);
  3443. i = ListBox_InsertString(hwndDest, ListBox_GetCurSel(hwndDest)+1, pItem->pHeading);
  3444. }
  3445. else
  3446. {
  3447. TraceMsg("Adding string to listbox");
  3448. i = ListBox_AddString(hwndDest, pItem->pHeading);
  3449. }
  3450. TraceAssert(i != -1);
  3451. ListBox_SetItemData(hwndDest, i, (LPARAM)pItem);
  3452. ListBox_SetCurSel(hwndDest, i);
  3453. // remove the item from the source, ensuring that the
  3454. // selection stays visually at the same place (nb
  3455. // cope with removing the last item).
  3456. ListBox_DeleteString(hwndSrc, iSelection);
  3457. if (iSelection >= ListBox_GetCount(hwndSrc))
  3458. iSelection = ListBox_GetCount(hwndSrc)-1;
  3459. if (iSelection >= 0)
  3460. ListBox_SetCurSel(hwndSrc, iSelection);
  3461. }
  3462. TraceLeave();
  3463. }
  3464. /*-----------------------------------------------------------------------------
  3465. / _Picker_GetColumnTable
  3466. / ---------------------
  3467. / The user has hit OK, therefore we must build a new column table, this
  3468. / code walks the items in the columns ListBox and generates the
  3469. / column DSA that we should be using.
  3470. /
  3471. / In:
  3472. / hwndColumns -> ListBox containing the columns
  3473. / pHDSA -> DSA to receive the columnt able
  3474. /
  3475. / Out:
  3476. / HRESULT
  3477. /----------------------------------------------------------------------------*/
  3478. HRESULT _Picker_GetColumnTable(HWND hwndColumns, HDSA* pHDSA)
  3479. {
  3480. HRESULT hr;
  3481. HDSA hdsaColumns = NULL;
  3482. INT i;
  3483. INT cxColumn = 0;
  3484. TraceEnter(TRACE_FIELDCHOOSER, "_Picker_GetColumnTable");
  3485. // Construct a DSA to store the column table in
  3486. hdsaColumns = DSA_Create(SIZEOF(COLUMN), 4);
  3487. TraceAssert(hdsaColumns);
  3488. if (!hdsaColumns)
  3489. ExitGracefully(hr, E_OUTOFMEMORY, "Failed to create the column DSA");
  3490. // For each entry in the ListBox add an item to the DSA that contains
  3491. // the relevant column information
  3492. for (i = 0 ; i < ListBox_GetCount(hwndColumns) ; i++)
  3493. {
  3494. COLUMN column = { 0 };
  3495. LPPICKERITEM pItem = (LPPICKERITEM)ListBox_GetItemData(hwndColumns, i);
  3496. TraceAssert(pItem);
  3497. // column.fHasColumnHandler = FALSE;
  3498. column.pProperty = NULL;
  3499. column.pHeading = NULL;
  3500. //column.cx = 0;
  3501. //column.fmt = 0;
  3502. column.iPropertyType = PROPERTY_ISUNKNOWN;
  3503. column.idOperator = 0;
  3504. // column.clsidColumnHandler = { 0 };
  3505. // column.pColumnHandler = NULL;
  3506. // fIsColumn indicates that the entry was originally a column therefore
  3507. // has extra state information, ensure that we copy this over, otherwise
  3508. // just pick sensible defaults. Having done that we can allocate the
  3509. // strings, add the item and continue...
  3510. if (pItem->fIsColumn)
  3511. {
  3512. column.cx = pItem->cx;
  3513. column.fmt = pItem->fmt;
  3514. }
  3515. else
  3516. {
  3517. // Have we cached the column width yet? If not then lets do
  3518. // so and apply it to all the columns which are using the
  3519. // default width (as they have not yet been sized)
  3520. if (!cxColumn)
  3521. {
  3522. HDC hDC;
  3523. LOGFONT lf;
  3524. HFONT hFont, hOldFont;
  3525. SIZE sz;
  3526. sz.cx = 10; // random default value.
  3527. SystemParametersInfo(SPI_GETICONTITLELOGFONT, SIZEOF(lf), &lf, FALSE);
  3528. hFont = CreateFontIndirect(&lf); // icon title font
  3529. if (hFont)
  3530. {
  3531. hDC = CreateCompatibleDC(NULL); // screen compatible DC
  3532. if (hDC)
  3533. {
  3534. hOldFont = (HFONT)SelectObject(hDC, hFont);
  3535. GetTextExtentPoint(hDC, TEXT("0"), 1, &sz);
  3536. SelectObject(hDC, hOldFont);
  3537. DeleteDC(hDC);
  3538. }
  3539. DeleteObject(hFont);
  3540. }
  3541. cxColumn = DEFAULT_WIDTH * sz.cx;
  3542. }
  3543. column.cx = cxColumn;
  3544. column.fmt = 0;
  3545. }
  3546. if (FAILED(GetColumnHandlerFromProperty(&column, pItem->pProperty)) ||
  3547. FAILED(LocalAllocString(&column.pHeading, pItem->pHeading)) ||
  3548. (-1 == DSA_AppendItem(hdsaColumns, &column)))
  3549. {
  3550. LocalFreeStringW(&column.pProperty);
  3551. LocalFreeString(&column.pHeading);
  3552. ExitGracefully(hr, E_OUTOFMEMORY, "Failed to construct the column entry");
  3553. }
  3554. }
  3555. Trace(TEXT("New column table contains %d items"), DSA_GetItemCount(hdsaColumns));
  3556. hr = S_OK;
  3557. exit_gracefully:
  3558. if (FAILED(hr) && hdsaColumns)
  3559. {
  3560. DSA_DestroyCallback(hdsaColumns, FreeColumnCB, NULL);
  3561. hdsaColumns = NULL;
  3562. }
  3563. *pHDSA = hdsaColumns;
  3564. TraceLeaveResult(hr);
  3565. }
  3566. /*-----------------------------------------------------------------------------
  3567. / _PickerDlgProc
  3568. / --------------
  3569. / Dialog proc for handling the dialog messages (there is a suprise)
  3570. /
  3571. / In:
  3572. / hwnd, uMsg, wParam, lParam = message information
  3573. / DWL_USER => LPPICKERSTATE structure
  3574. /
  3575. / Out:
  3576. / INT_PTR
  3577. /----------------------------------------------------------------------------*/
  3578. #define SET_BTN_STYLE(hwnd, idc, style) \
  3579. SendDlgItemMessage(hwnd, idc, BM_SETSTYLE, MAKEWPARAM(style, 0), MAKELPARAM(TRUE, 0));
  3580. INT_PTR _PickerDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  3581. {
  3582. INT_PTR fResult = FALSE;
  3583. LPPICKERSTATE pState = NULL;
  3584. BOOL fUpdateButtonState = TRUE;
  3585. PICKERITEM item;
  3586. INT i, j;
  3587. if (uMsg == WM_INITDIALOG)
  3588. {
  3589. pState = (LPPICKERSTATE)lParam;
  3590. TraceAssert(pState);
  3591. SetWindowLongPtr(hwnd, DWLP_USER, lParam);
  3592. pState->hwndProperties = GetDlgItem(hwnd, IDC_LBPROPERTIES);
  3593. pState->hwndColumns = GetDlgItem(hwnd, IDC_LBCOLUMNS);
  3594. // pState->hdsaColumns contains the currently visible column table, this is
  3595. // the table being used by the current view, therefore we must not modify
  3596. // it, just treat it as read only. Add the columns to the ListBox
  3597. // marking the visible items in the properties DPA, then add those
  3598. // items not already shown to the properties list box.
  3599. for (i = 0 ; i < DSA_GetItemCount(pState->hdsaColumns) ; i++)
  3600. {
  3601. LPCOLUMN pColumn = (LPCOLUMN)DSA_GetItemPtr(pState->hdsaColumns, i);
  3602. TraceAssert(pColumn);
  3603. if (SUCCEEDED(GetPropertyFromColumn(&item.pProperty, pColumn)))
  3604. {
  3605. j = DPA_Search(pState->hdpaItems, &item, 0, _PickerItemCmpCB, NULL, DPAS_SORTED);
  3606. Trace(TEXT("Searching for %s yielded %d"), item.pProperty, j);
  3607. if (j >= 0)
  3608. {
  3609. LPPICKERITEM pItem = (LPPICKERITEM)DPA_GetPtr(pState->hdpaItems, j);
  3610. TraceAssert(pItem);
  3611. ListBox_SetItemData(pState->hwndColumns,
  3612. ListBox_AddString(pState->hwndColumns, pItem->pHeading),
  3613. (LPARAM)pItem);
  3614. }
  3615. LocalFreeStringW(&item.pProperty);
  3616. }
  3617. }
  3618. for (i = 0 ; i < DPA_GetPtrCount(pState->hdpaItems) ; i++)
  3619. {
  3620. LPPICKERITEM pItem = (LPPICKERITEM)DPA_GetPtr(pState->hdpaItems, i);
  3621. TraceAssert(pItem && pItem->pHeading);
  3622. if (!pItem->fIsColumn)
  3623. {
  3624. ListBox_SetItemData(pState->hwndProperties,
  3625. ListBox_AddString(pState->hwndProperties, pItem->pHeading),
  3626. (LPARAM)pItem);
  3627. }
  3628. }
  3629. // Ensure we default select the top items of each list
  3630. ListBox_SetCurSel(pState->hwndProperties, 0);
  3631. ListBox_SetCurSel(pState->hwndColumns, 0);
  3632. }
  3633. else
  3634. {
  3635. pState = (LPPICKERSTATE)GetWindowLongPtr(hwnd, DWLP_USER);
  3636. TraceAssert(pState);
  3637. switch (uMsg)
  3638. {
  3639. case WM_HELP:
  3640. {
  3641. LPHELPINFO pHelpInfo = (LPHELPINFO)lParam;
  3642. WinHelp((HWND)pHelpInfo->hItemHandle,
  3643. DSQUERY_HELPFILE,
  3644. HELP_WM_HELP,
  3645. (DWORD_PTR)aPickColumnsHelpIDs);
  3646. break;
  3647. }
  3648. case WM_CONTEXTMENU:
  3649. WinHelp((HWND)wParam, DSQUERY_HELPFILE, HELP_CONTEXTMENU, (DWORD_PTR)aPickColumnsHelpIDs);
  3650. fResult = TRUE;
  3651. break;
  3652. case WM_COMMAND:
  3653. {
  3654. switch (LOWORD(wParam))
  3655. {
  3656. case IDOK:
  3657. {
  3658. _Picker_GetColumnTable(pState->hwndColumns, &pState->hdsaColumns);
  3659. EndDialog(hwnd, IDOK);
  3660. break;
  3661. }
  3662. case IDCANCEL:
  3663. EndDialog(hwnd, IDCANCEL);
  3664. break;
  3665. case IDC_ADD:
  3666. _PickerMoveColumn(pState->hwndColumns, pState->hwndProperties, TRUE);
  3667. break;
  3668. case IDC_REMOVE:
  3669. _PickerMoveColumn(pState->hwndProperties, pState->hwndColumns, FALSE);
  3670. break;
  3671. case IDC_LBPROPERTIES:
  3672. {
  3673. if (ListBox_GetCount(pState->hwndProperties) > 0)
  3674. {
  3675. if (HIWORD(wParam) == LBN_DBLCLK)
  3676. _PickerMoveColumn(pState->hwndColumns, pState->hwndProperties, TRUE);
  3677. }
  3678. break;
  3679. }
  3680. case IDC_LBCOLUMNS:
  3681. {
  3682. if (ListBox_GetCount(pState->hwndColumns) > 1)
  3683. {
  3684. if (HIWORD(wParam) == LBN_DBLCLK)
  3685. _PickerMoveColumn(pState->hwndProperties, pState->hwndColumns, FALSE);
  3686. }
  3687. break;
  3688. }
  3689. default:
  3690. fUpdateButtonState = FALSE;
  3691. break;
  3692. }
  3693. break;
  3694. }
  3695. default:
  3696. fUpdateButtonState = FALSE;
  3697. break;
  3698. }
  3699. }
  3700. // if the selections state change, or something which would cause
  3701. // us to refresh the add/remove buttons state then lets do it.
  3702. // each button is enabled only if there is a selection and the
  3703. // number of items is > the min value.
  3704. if (pState && fUpdateButtonState)
  3705. {
  3706. BOOL fEnableAdd = FALSE;
  3707. BOOL fEnableRemove = FALSE;
  3708. DWORD dwButtonStyle;
  3709. if ((ListBox_GetCount(pState->hwndProperties) > 0))
  3710. {
  3711. fEnableAdd = TRUE;
  3712. }
  3713. if ((ListBox_GetCount(pState->hwndColumns) > 1))
  3714. {
  3715. fEnableRemove = TRUE;
  3716. }
  3717. // Make sure the DefButton is an enabled button
  3718. // FEATURE: Need to add an SHSetDefID() export to shlwapi
  3719. // which is simply a SetDefID that "does the right thing"
  3720. // wrt disabled buttons.
  3721. if ((!fEnableRemove) && (!fEnableAdd))
  3722. {
  3723. SET_BTN_STYLE(hwnd, IDC_ADD, BS_PUSHBUTTON);
  3724. SET_BTN_STYLE(hwnd, IDC_REMOVE, BS_PUSHBUTTON);
  3725. SendMessage(hwnd, DM_SETDEFID, IDOK, 0);
  3726. SET_BTN_STYLE(hwnd, IDOK, BS_DEFPUSHBUTTON);
  3727. SendMessage(hwnd,WM_NEXTDLGCTL,(WPARAM)GetDlgItem(hwnd, IDOK),TRUE);
  3728. SetFocus(GetDlgItem(hwnd, IDOK));
  3729. }
  3730. else if (!fEnableAdd)
  3731. {
  3732. dwButtonStyle = (DWORD)GetWindowLong(GetDlgItem(hwnd, IDC_ADD), GWL_STYLE);
  3733. if (dwButtonStyle & BS_DEFPUSHBUTTON)
  3734. {
  3735. SET_BTN_STYLE(hwnd, IDC_ADD, BS_PUSHBUTTON);
  3736. SendMessage(hwnd, DM_SETDEFID, IDC_REMOVE, 0);
  3737. SET_BTN_STYLE(hwnd, IDC_REMOVE, BS_DEFPUSHBUTTON);
  3738. SendMessage(hwnd,WM_NEXTDLGCTL,(WPARAM)GetDlgItem(hwnd, IDC_REMOVE),TRUE);
  3739. SetFocus(GetDlgItem(hwnd, IDC_REMOVE));
  3740. }
  3741. }
  3742. else if (!fEnableRemove)
  3743. {
  3744. dwButtonStyle = (DWORD) GetWindowLong(GetDlgItem(hwnd, IDC_REMOVE), GWL_STYLE);
  3745. if (dwButtonStyle & BS_DEFPUSHBUTTON)
  3746. {
  3747. SET_BTN_STYLE(hwnd, IDC_REMOVE, BS_PUSHBUTTON);
  3748. SendMessage(hwnd, DM_SETDEFID, IDC_ADD, 0);
  3749. SET_BTN_STYLE(hwnd, IDC_ADD, BS_DEFPUSHBUTTON);
  3750. SendMessage(hwnd,WM_NEXTDLGCTL,(WPARAM)GetDlgItem(hwnd, IDC_ADD),TRUE);
  3751. SetFocus(GetDlgItem(hwnd, IDC_ADD));
  3752. }
  3753. }
  3754. Button_Enable(GetDlgItem(hwnd, IDC_ADD), fEnableAdd);
  3755. Button_Enable(GetDlgItem(hwnd, IDC_REMOVE), fEnableRemove);
  3756. }
  3757. return fResult;
  3758. }
  3759. /*-----------------------------------------------------------------------------
  3760. / CDsQuery::OnPickColumns
  3761. / -----------------------
  3762. / Handle picking the columns that should be displayed in the result view,
  3763. / if the user selects new columns and hits OK then we refresh the
  3764. / view and the internal table of visible columns.
  3765. /
  3766. / In:
  3767. / hwndParent = parent for the dialog
  3768. /
  3769. / Out:
  3770. / HRESULT
  3771. /----------------------------------------------------------------------------*/
  3772. INT _PickerItemFreeCB(LPVOID pData, LPVOID lParam)
  3773. {
  3774. LPPICKERITEM pItem = (LPPICKERITEM)pData;
  3775. LocalFreeStringW(&pItem->pProperty);
  3776. LocalFreeString(&pItem->pHeading);
  3777. LocalFree(pItem);
  3778. return 1;
  3779. }
  3780. INT _PickerItemCmpCB(LPVOID p1, LPVOID p2, LPARAM lParam)
  3781. {
  3782. LPPICKERITEM pEntry1 = (LPPICKERITEM)p1;
  3783. LPPICKERITEM pEntry2 = (LPPICKERITEM)p2;
  3784. INT nResult = -1;
  3785. if (pEntry1 && pEntry2)
  3786. nResult = StrCmpW(pEntry1->pProperty, pEntry2->pProperty);
  3787. return nResult;
  3788. }
  3789. typedef struct
  3790. {
  3791. PICKERSTATE *pps;
  3792. HDPA hdpaProperties; // attributes to be appeneded.
  3793. } PICKERENUMATTRIB;
  3794. HRESULT CALLBACK _PickerEnumAttribCB(LPARAM lParam, LPCWSTR pAttributeName, LPCWSTR pDisplayName, DWORD dwFlags)
  3795. {
  3796. HRESULT hr;
  3797. PICKERENUMATTRIB *ppea = (PICKERENUMATTRIB*)lParam;
  3798. PICKERITEM item;
  3799. INT j;
  3800. TraceEnter(TRACE_FIELDCHOOSER, "_PickerEnumAttribCB");
  3801. // fix casting
  3802. item.pProperty = (LPWSTR)pAttributeName;
  3803. j = DPA_Search(ppea->pps->hdpaItems, &item, 0, _PickerItemCmpCB, NULL, DPAS_SORTED);
  3804. if (j == -1)
  3805. {
  3806. Trace(TEXT("Property not already in list: %s"), pAttributeName);
  3807. hr = StringDPA_AppendStringW(ppea->hdpaProperties, pAttributeName, NULL);
  3808. FailGracefully(hr, "Failed to add unique property to DPA");
  3809. }
  3810. hr = S_OK;
  3811. exit_gracefully:
  3812. TraceLeaveResult(hr);
  3813. }
  3814. HRESULT CDsQuery::OnPickColumns(HWND hwndParent)
  3815. {
  3816. HRESULT hr;
  3817. HDPA hdpaProperties = NULL;
  3818. PICKERSTATE state;
  3819. PICKERENUMATTRIB pea = { 0 };
  3820. INT i, j, iProperty, iColumn;
  3821. LPDSQUERYCLASSLIST pDsQueryClassList = NULL;
  3822. IDsDisplaySpecifier* pdds = NULL;
  3823. TraceEnter(TRACE_FIELDCHOOSER, "CDsQuery::OnPickColumns");
  3824. Trace(TEXT("Column count %d"), DSA_GetItemCount(_hdsaColumns));
  3825. state.hdpaItems = NULL;
  3826. state.hdsaColumns = _hdsaColumns;
  3827. state.hwndProperties = NULL;
  3828. state.hwndColumns = NULL;
  3829. // Build a list of unique properties sorted and remove the ones
  3830. // which match the currently displayed property set.
  3831. state.hdpaItems = DPA_Create(16);
  3832. TraceAssert(state.hdpaItems);
  3833. if (!state.hdpaItems)
  3834. ExitGracefully(hr, E_OUTOFMEMORY, "Failed to create property DPA");
  3835. //
  3836. // attempt to get the IDsDisplaySpecifier object
  3837. //
  3838. hr = CoCreateInstance(CLSID_DsDisplaySpecifier, NULL, CLSCTX_INPROC_SERVER, IID_IDsDisplaySpecifier, (void **)&pdds);
  3839. FailGracefully(hr, "Failed to get the IDsDisplaySpecifier interface");
  3840. hr = pdds->SetServer(_pServer, _pUserName, _pPassword, DSSSF_DSAVAILABLE);
  3841. FailGracefully(hr, "Failed to server information");
  3842. // add the columns properties to the the list, marking them as active columns
  3843. // storing their size and other information.
  3844. for (i = 0 ; i < DPA_GetPtrCount(_hdsaColumns); i++)
  3845. {
  3846. LPCOLUMN pColumn = (LPCOLUMN)DSA_GetItemPtr(_hdsaColumns, i);
  3847. TraceAssert(pColumn);
  3848. LPPICKERITEM pItem = (LPPICKERITEM)LocalAlloc(LPTR, SIZEOF(PICKERITEM));
  3849. TraceAssert(pItem);
  3850. if (pItem)
  3851. {
  3852. pItem->pProperty = NULL;
  3853. pItem->pHeading = NULL;
  3854. pItem->fIsColumn = TRUE;
  3855. pItem->cx = pColumn->cx;
  3856. pItem->fmt = pColumn->fmt;
  3857. hr = GetPropertyFromColumn(&pItem->pProperty, pColumn);
  3858. TraceAssert(SUCCEEDED(hr));
  3859. if (SUCCEEDED(hr))
  3860. {
  3861. hr = LocalAllocString(&pItem->pHeading, pColumn->pHeading);
  3862. TraceAssert(SUCCEEDED(hr));
  3863. }
  3864. Trace(TEXT("Adding column %d, with property %s"), i, pItem->pProperty);
  3865. if (FAILED(hr) || (-1 == DPA_AppendPtr(state.hdpaItems, pItem)))
  3866. {
  3867. TraceMsg("Failed to add property to the DPA");
  3868. hr = E_FAIL;
  3869. }
  3870. if (FAILED(hr))
  3871. _PickerItemFreeCB(pItem, NULL);
  3872. }
  3873. }
  3874. DPA_Sort(state.hdpaItems, _PickerItemCmpCB, NULL); // sort the DPA now we have all the elements
  3875. // for all the classes we have loop through and build the unique
  3876. // list, sorted as we go.
  3877. hr = _pqf->CallForm(&_clsidForm, DSQPM_GETCLASSLIST, 0, (LPARAM)&pDsQueryClassList);
  3878. FailGracefully(hr, "Failed to get the class list");
  3879. if (!pDsQueryClassList)
  3880. ExitGracefully(hr, E_FAIL, "Failed to get the class list");
  3881. Trace(TEXT("Classes returned from DSQPM_GETCLASSLIST %d"), pDsQueryClassList->cClasses);
  3882. for (i = 0 ; i < pDsQueryClassList->cClasses ; i++)
  3883. {
  3884. LPWSTR pObjectClass = (LPWSTR)ByteOffset(pDsQueryClassList, pDsQueryClassList->offsetClass[i]);
  3885. TraceAssert(pObjectClass);
  3886. Trace(TEXT("Adding class '%s' to the property DPA"), pObjectClass);
  3887. // allocate a DPA to be filed with items
  3888. StringDPA_Destroy(&pea.hdpaProperties);
  3889. pea.pps = &state;
  3890. pea.hdpaProperties = DPA_Create(16);
  3891. if (!pea.hdpaProperties)
  3892. ExitGracefully(hr, E_OUTOFMEMORY, "Failed to allocate string DPA");
  3893. if (SUCCEEDED(EnumClassAttributes(pdds, pObjectClass, _PickerEnumAttribCB, (LPARAM)&pea)))
  3894. {
  3895. Trace(TEXT("Unique property list has %d entries"), DPA_GetPtrCount(pea.hdpaProperties));
  3896. // Having constructed the unique list of properties for this class lets now
  3897. // add them to the item data list and allocate real structures for them.
  3898. for (iProperty = 0 ; iProperty < DPA_GetPtrCount(pea.hdpaProperties); iProperty++)
  3899. {
  3900. LPWSTR pProperty = StringDPA_GetStringW(pea.hdpaProperties, iProperty);
  3901. TraceAssert(pProperty != NULL);
  3902. LPPICKERITEM pItem = (LPPICKERITEM)LocalAlloc(LPTR, SIZEOF(PICKERITEM));
  3903. TraceAssert(pItem);
  3904. if (pItem)
  3905. {
  3906. WCHAR szBuffer[MAX_PATH];
  3907. GetFriendlyAttributeName(pdds, pObjectClass, pProperty, szBuffer, ARRAYSIZE(szBuffer));
  3908. pItem->pProperty = NULL;
  3909. pItem->pHeading = NULL;
  3910. pItem->fIsColumn = FALSE;
  3911. pItem->cx = 0;
  3912. pItem->fmt = 0;
  3913. hr = LocalAllocStringW(&pItem->pProperty, pProperty);
  3914. TraceAssert(SUCCEEDED(hr));
  3915. if (SUCCEEDED(hr))
  3916. {
  3917. hr = LocalAllocStringW(&pItem->pHeading, szBuffer);
  3918. TraceAssert(SUCCEEDED(hr));
  3919. }
  3920. if (FAILED(hr) || (-1 == DPA_AppendPtr(state.hdpaItems, pItem)))
  3921. {
  3922. TraceMsg("Failed to add property to the DPA");
  3923. hr = E_FAIL;
  3924. }
  3925. if (FAILED(hr))
  3926. _PickerItemFreeCB(pItem, NULL);
  3927. }
  3928. DPA_Sort(state.hdpaItems, _PickerItemCmpCB, NULL); // sort the DPA now we have all the elements
  3929. }
  3930. }
  3931. }
  3932. Trace(TEXT("Property table is %d items in size"), DPA_GetPtrCount(state.hdpaItems));
  3933. // If the user selects OK then the DlgProc will have generated a new column
  3934. // table stored in the PICKERSTATE structure, we should persist this, then
  3935. // load it ready to refresh the result viewer.
  3936. i = (int)DialogBoxParam(GLOBAL_HINSTANCE, MAKEINTRESOURCE(IDD_PICKCOLUMNS),
  3937. hwndParent,
  3938. _PickerDlgProc, (LPARAM)&state);
  3939. if (i == IDOK)
  3940. {
  3941. hr = _SaveColumnTable(_clsidForm, state.hdsaColumns);
  3942. FailGracefully(hr, "Failed to write column table");
  3943. hr = _InitNewQuery(NULL, TRUE); // initialize the view
  3944. FailGracefully(hr, "Failed when starting new query");
  3945. TraceAssert(_dwThreadId);
  3946. PostThreadMessage(_dwThreadId, RVTM_SETCOLUMNTABLE, _dwQueryReference, (LPARAM)state.hdsaColumns);
  3947. _fColumnsModified = FALSE;
  3948. }
  3949. hr = S_OK;
  3950. exit_gracefully:
  3951. StringDPA_Destroy(&pea.hdpaProperties);
  3952. if (state.hdpaItems)
  3953. DPA_DestroyCallback(state.hdpaItems, _PickerItemFreeCB, NULL);
  3954. if (pDsQueryClassList)
  3955. CoTaskMemFree(pDsQueryClassList);
  3956. DoRelease(pdds);
  3957. TraceLeaveValue(hr);
  3958. }
  3959. // persistance object
  3960. class CDsPersistQuery : public IPersistQuery
  3961. {
  3962. private:
  3963. LONG _cRef;
  3964. TCHAR m_szFilename[MAX_PATH];
  3965. public:
  3966. CDsPersistQuery(LPCTSTR pFilename);;
  3967. ~CDsPersistQuery();
  3968. // IUnknown
  3969. STDMETHOD(QueryInterface)(REFIID riid, LPVOID* ppvObject);
  3970. STDMETHOD_(ULONG, AddRef)();
  3971. STDMETHOD_(ULONG, Release)();
  3972. // IPersist
  3973. STDMETHOD(GetClassID)(CLSID* pClassID)
  3974. { return E_NOTIMPL; }
  3975. // IPersistQuery
  3976. STDMETHOD(WriteString)(LPCTSTR pSection, LPCTSTR pValueName, LPCTSTR pValue);
  3977. STDMETHOD(ReadString)(LPCTSTR pSection, LPCTSTR pValueName, LPTSTR pBuffer, INT cchBuffer);
  3978. STDMETHOD(WriteInt)(LPCTSTR pSection, LPCTSTR pValueName, INT value);
  3979. STDMETHOD(ReadInt)(LPCTSTR pSection, LPCTSTR pValueName, LPINT pValue);
  3980. STDMETHOD(WriteStruct)(LPCTSTR pSection, LPCTSTR pValueName, LPVOID pStruct, DWORD cbStruct);
  3981. STDMETHOD(ReadStruct)(LPCTSTR pSection, LPCTSTR pValueName, LPVOID pStruct, DWORD cbStruct);
  3982. STDMETHOD(Clear)()
  3983. { return S_OK; }
  3984. };
  3985. #define STRING_SIZE TEXT("%sLength")
  3986. #define STRING_VALUE TEXT("%sValue")
  3987. CDsPersistQuery::CDsPersistQuery(LPCTSTR pFilename) :
  3988. _cRef(1)
  3989. {
  3990. // NTRAID#NTBUG9-554905-2002/02/20-lucios. Pending fix.
  3991. StrCpy(m_szFilename, pFilename); // copy the filename
  3992. DllAddRef();
  3993. }
  3994. CDsPersistQuery::~CDsPersistQuery()
  3995. {
  3996. DllRelease();
  3997. }
  3998. // IUnknown
  3999. ULONG CDsPersistQuery::AddRef()
  4000. {
  4001. return InterlockedIncrement(&_cRef);
  4002. }
  4003. ULONG CDsPersistQuery::Release()
  4004. {
  4005. TraceAssert( 0 != _cRef );
  4006. ULONG cRef = InterlockedDecrement(&_cRef);
  4007. if ( 0 == cRef )
  4008. {
  4009. delete this;
  4010. }
  4011. return cRef;
  4012. }
  4013. HRESULT CDsPersistQuery::QueryInterface(REFIID riid, void **ppv)
  4014. {
  4015. static const QITAB qit[] =
  4016. {
  4017. QITABENTMULTI(CDsPersistQuery, IPersist, IPersistQuery), // IID_IPersist
  4018. QITABENT(CDsPersistQuery, IPersistQuery), // IID_IPersistQuery
  4019. {0, 0 },
  4020. };
  4021. return QISearch(this, qit, riid, ppv);
  4022. }
  4023. STDAPI CPersistQuery_CreateInstance(LPTSTR pszPath, IPersistQuery **pppq)
  4024. {
  4025. CDsPersistQuery *ppq = new CDsPersistQuery(pszPath);
  4026. if (!ppq)
  4027. return E_OUTOFMEMORY;
  4028. HRESULT hr = ppq->QueryInterface(IID_IPersistQuery, (void **)pppq);
  4029. ppq->Release();
  4030. return hr;
  4031. }
  4032. // IPersistQuery
  4033. STDMETHODIMP CDsPersistQuery::WriteString(LPCTSTR pSection, LPCTSTR pKey, LPCTSTR pValue)
  4034. {
  4035. HRESULT hr = S_OK;
  4036. TCHAR szBuffer[MAX_PATH];
  4037. if (!pSection || !pKey || !pValue)
  4038. return E_INVALIDARG;
  4039. // Write the string into the stream as a UNICODE string. If we are built for UNICODE
  4040. // then we can simply WriteProfileStruct, otherwise we must attempt to convert it
  4041. // from a multi-byte string.
  4042. // Write the string size
  4043. // NTRAID#NTBUG9-554458-2002/02/20-lucios. Pending fix.
  4044. wsprintf(szBuffer, STRING_SIZE, pKey);
  4045. INT cchValue = 1+lstrlen(pValue);
  4046. if (!WritePrivateProfileStruct(pSection, szBuffer, &cchValue, SIZEOF(cchValue), m_szFilename))
  4047. ExitGracefully(hr, E_FAIL, "Failed to write string size to stream");
  4048. // NTRAID#NTBUG9-554458-2002/02/20-lucios. Pending fix.
  4049. wsprintf(szBuffer, STRING_VALUE, pKey);
  4050. if (!WritePrivateProfileStruct(pSection, szBuffer, (LPVOID)pValue, SIZEOF(WCHAR)*cchValue, m_szFilename))
  4051. ExitGracefully(hr, E_FAIL, "Failed to write string to stream");
  4052. hr = S_OK;
  4053. exit_gracefully:
  4054. TraceLeaveResult(hr);
  4055. }
  4056. STDMETHODIMP CDsPersistQuery::ReadString(LPCTSTR pSection, LPCTSTR pKey, LPTSTR pBuffer, INT cchBuffer)
  4057. {
  4058. HRESULT hr;
  4059. TCHAR szBuffer[MAX_PATH];
  4060. INT cchValue;
  4061. TraceEnter(TRACE_IO, "CDsPersistQuery::ReadString");
  4062. if (!pSection || !pKey || !pBuffer)
  4063. ExitGracefully(hr, E_INVALIDARG, "Nothing to read (or into)");
  4064. pBuffer[0] = TEXT('\0'); // terminate the buffer
  4065. Trace(TEXT("pSection: %s, pKey: %s"), pSection, pKey);
  4066. // Read the length of the string, checking to see if its fits in the the buffer
  4067. // we have, if it does then read and convert as requried.
  4068. // NTRAID#NTBUG9-554458-2002/02/20-lucios. Pending fix.
  4069. wsprintf(szBuffer, STRING_SIZE, pKey); // <key name>Length
  4070. Trace(TEXT("Opening key: %s"), szBuffer);
  4071. if (!GetPrivateProfileStruct(pSection, szBuffer, &cchValue, SIZEOF(cchValue), m_szFilename))
  4072. ExitGracefully(hr, E_FAIL, "Failed to read string size");
  4073. Trace(TEXT("cchValue %d"), cchValue);
  4074. if (cchValue > cchBuffer)
  4075. ExitGracefully(hr, E_FAIL, "Buffer too small for string in stream");
  4076. if (cchValue > 0)
  4077. {
  4078. // NTRAID#NTBUG9-554458-2002/02/20-lucios. Pending fix.
  4079. wsprintf(szBuffer, STRING_VALUE, pKey);
  4080. if (!GetPrivateProfileStruct(pSection, szBuffer, pBuffer, SIZEOF(WCHAR)*cchValue, m_szFilename))
  4081. ExitGracefully(hr, E_FAIL, "Failed to read string data");
  4082. }
  4083. Trace(TEXT("Value is: %s"), pBuffer);
  4084. hr = S_OK;
  4085. exit_gracefully:
  4086. TraceLeaveResult(hr);
  4087. }
  4088. STDMETHODIMP CDsPersistQuery::WriteInt(LPCTSTR pSection, LPCTSTR pKey, INT value)
  4089. {
  4090. HRESULT hr;
  4091. TraceEnter(TRACE_IO, "CDsPersistQuery::WriteInt");
  4092. if (!pSection || !pKey)
  4093. ExitGracefully(hr, E_INVALIDARG, "Nothing to write");
  4094. Trace(TEXT("pSection: %s, pKey: %s, value: %d"), pSection, pKey, value);
  4095. if (!WritePrivateProfileStruct(pSection, pKey, &value, SIZEOF(value), m_szFilename))
  4096. ExitGracefully(hr, E_FAIL, "Failed to write value");
  4097. hr = S_OK;
  4098. exit_gracefully:
  4099. TraceLeaveResult(hr);
  4100. }
  4101. STDMETHODIMP CDsPersistQuery::ReadInt(LPCTSTR pSection, LPCTSTR pKey, LPINT pValue)
  4102. {
  4103. HRESULT hr;
  4104. TraceEnter(TRACE_IO, "CDsPersistQuery::ReadInt");
  4105. if (!pSection || !pKey || !pValue)
  4106. ExitGracefully(hr, E_INVALIDARG, "Nothing to read");
  4107. Trace(TEXT("pSection: %s, pKey: %s, pValue: %08x"), pSection, pKey, pValue);
  4108. if (!GetPrivateProfileStruct(pSection, pKey, pValue, SIZEOF(*pValue), m_szFilename))
  4109. ExitGracefully(hr, E_FAIL, "Failed to read value");
  4110. hr = S_OK;
  4111. exit_gracefully:
  4112. TraceLeaveResult(hr);
  4113. }
  4114. STDMETHODIMP CDsPersistQuery::WriteStruct(LPCTSTR pSection, LPCTSTR pKey, LPVOID pStruct, DWORD cbStruct)
  4115. {
  4116. HRESULT hr;
  4117. TraceEnter(TRACE_IO, "CDsPersistQuery::WriteStruct");
  4118. if (!pSection || !pKey || !pStruct)
  4119. ExitGracefully(hr, E_INVALIDARG, "Nothing to write");
  4120. Trace(TEXT("pSection: %s, pKey: %s, pStruct: %08x, cbStruct: %d"), pSection, pKey, pStruct, cbStruct);
  4121. if (!WritePrivateProfileStruct(pSection, pKey, pStruct, cbStruct, m_szFilename))
  4122. ExitGracefully(hr, E_FAIL, "Failed to write struct");
  4123. hr = S_OK;
  4124. exit_gracefully:
  4125. TraceLeaveResult(hr);
  4126. }
  4127. STDMETHODIMP CDsPersistQuery::ReadStruct(LPCTSTR pSection, LPCTSTR pKey, LPVOID pStruct, DWORD cbStruct)
  4128. {
  4129. HRESULT hr;
  4130. TraceEnter(TRACE_IO, "CDsPersistQuery::ReadStruct");
  4131. if (!pSection || !pKey || !pStruct)
  4132. ExitGracefully(hr, E_INVALIDARG, "Nothing to read");
  4133. Trace(TEXT("pSection: %s, pKey: %s, pStruct: %08x, cbStruct: %d"), pSection, pKey, pStruct, cbStruct);
  4134. if (!GetPrivateProfileStruct(pSection, pKey, pStruct, cbStruct, m_szFilename))
  4135. ExitGracefully(hr, E_FAIL, "Failed to read struct");
  4136. hr = S_OK;
  4137. exit_gracefully:
  4138. TraceLeaveResult(hr);
  4139. }