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

Windows Kernel

Development Platform:

Visual C++

  1.                                           _dxFormAreaLeft+sz2.cx, rect.top, 
  2.                                           xScopeRight - (_dxFormAreaLeft + sz2.cx), sz.cy,
  3.                                           SWP_NOZORDER);
  4.                 }
  5.                 else
  6.                 {
  7.                     hdwp = DeferWindowPos(hdwp, _hwndLookIn, NULL,
  8.                                           0, 0, 
  9.                                           xScopeRight - rect.left, sz.cy,
  10.                                           SWP_NOZORDER|SWP_NOMOVE);
  11.                 }
  12.                 // browse control is displayed always if we are showing the 
  13.                 // scopes.
  14.                 GetRealWindowInfo(_hwndBrowse, &rect, NULL);
  15.                 hdwp = DeferWindowPos(hdwp, _hwndBrowse, NULL,
  16.                                       xScopeRight+_dxGap, rect.top,
  17.                                       0, 0,
  18.                                       SWP_NOZORDER|SWP_NOSIZE);
  19.             }
  20.                     
  21.             // all the buttons have a fixed offset from the right edege
  22.             // of the dialog, so just handle that as we can.
  23.             
  24.             if ( !(_pOpenQueryWnd->dwFlags & OQWF_HIDESEARCHUI) )
  25.             {
  26.                 GetRealWindowInfo(_hwndFindNow, &rect, NULL);
  27.                 hdwp = DeferWindowPos(hdwp, _hwndFindNow, NULL,
  28.                                      (cx - _dxButtonsLeft), rect.top, 
  29.                                      0, 0,
  30.                                      SWP_NOZORDER|SWP_NOSIZE);
  31.                 GetRealWindowInfo(_hwndStop, &rect, &sz);
  32.                 hdwp = DeferWindowPos(hdwp, _hwndStop, NULL,
  33.                                       (cx - _dxButtonsLeft), rect.top, 
  34.                                       0, 0,
  35.                                       SWP_NOZORDER|SWP_NOSIZE);
  36.                 GetRealWindowInfo(_hwndNewQuery, &rect, NULL);
  37.                 hdwp = DeferWindowPos(hdwp, _hwndNewQuery, NULL,
  38.                                       (cx - _dxButtonsLeft), rect.top, 
  39.                                       0, 0,
  40.                                       SWP_NOZORDER|SWP_NOSIZE);
  41.  
  42.                 GetRealWindowInfo(_hwndFindAnimation, &rect2, &sz2);
  43.                 hdwp = DeferWindowPos(hdwp, _hwndFindAnimation, NULL,
  44.                                      (cx - _dxAnimationLeft), rect2.top, 
  45.                                      0, 0,
  46.                                      SWP_NOZORDER|SWP_NOSIZE);
  47.             }
  48.             // position the form "frame" control
  49.         
  50.             GetRealWindowInfo(_hwndFrame, &rect, &sz);
  51.             cxForm = (cx - _dxFormAreaRight) - rect.left;
  52.             hdwp = DeferWindowPos(hdwp, _hwndFrame, NULL,
  53.                                   0, 0, 
  54.                                   cxForm, _szForm.cy,
  55.                                   SWP_NOZORDER|SWP_NOMOVE);
  56.             dyResultsTop = _dyResultsTop;
  57.             
  58.             // when we have a cancel button then ensure that it is to the right
  59.             // of the OK button.
  60.             if ( _hwndCancel )
  61.             {
  62.                 GetRealWindowInfo(_hwndCancel, &rect, &sz);
  63.                 hdwp = DeferWindowPos(hdwp, _hwndCancel, NULL,
  64.                                       (cx - _dxButtonsLeft), dyResultsTop - _dyOKTop,
  65.                                       0, 0,    
  66.                                       SWP_NOZORDER|SWP_NOSIZE);
  67.                 GetRealWindowInfo(_hwndOK, &rect, &sz);
  68.                 hdwp = DeferWindowPos(hdwp, _hwndOK, NULL,
  69.                                       (cx - _dxButtonsLeft - _dxGap - sz.cx), dyResultsTop - _dyOKTop,
  70.                                       0, 0,    
  71.                                       SWP_NOZORDER|SWP_NOSIZE);
  72.             }
  73.             else
  74.             {
  75.                 GetRealWindowInfo(_hwndOK, &rect, &sz);
  76.                 hdwp = DeferWindowPos(hdwp, _hwndOK, NULL,
  77.                                       (cx - _dxButtonsLeft), dyResultsTop - _dyOKTop,
  78.                                       0, 0,    
  79.                                       SWP_NOZORDER|SWP_NOSIZE);
  80.             }                                                                
  81.         }
  82.         // move the results and status bar as required
  83.         if ( _hwndResults )
  84.         {
  85.             hdwp = DeferWindowPos(hdwp, _hwndStatus, NULL,
  86.                                   0, cy - _cyStatus,
  87.                                   cx, _cyStatus,
  88.                                   SWP_SHOWWINDOW|SWP_NOZORDER);
  89.             hdwp = DeferWindowPos(hdwp, _hwndResults, NULL,
  90.                                   0, dyResultsTop, 
  91.                                   cx, max(0, cy - (dyResultsTop + _cyStatus)),
  92.                                   SWP_SHOWWINDOW|SWP_NOZORDER);
  93.         }
  94.         EndDeferWindowPos(hdwp);
  95.         // here is the strange bit, by this point we have moved & sized all the
  96.         // controls on the dialog except the current page, as this is a child window
  97.         // and not a control which in turn has controls doing this would break
  98.         // the DefWindowPos path, therefore having updated everybody, lets update
  99.         // the page.
  100. #if HIDE_SEARCH_PANE
  101.         if ( !_fHideSearchPane && _pCurrentFormPage && _pCurrentFormPage->hwndPage )
  102. #else
  103.         if ( _pCurrentFormPage && _pCurrentFormPage->hwndPage )
  104. #endif
  105.         {
  106.             GetRealWindowInfo(_hwndFrame, &rect, NULL);
  107.             TabCtrl_AdjustRect(_hwndFrame, FALSE, &rect);
  108.             cxForm = rect.right - rect.left;
  109.             cyForm = rect.bottom - rect.top;
  110.             SetWindowPos(_pCurrentFormPage->hwndPage, NULL,
  111.                          rect.left, rect.top, cxForm, cyForm,
  112.                          SWP_NOZORDER);
  113.         }
  114.     }
  115.     TraceLeave();
  116. }
  117. /*-----------------------------------------------------------------------------
  118. / CQueryFrame::OnGetMinMaxInfo
  119. / ----------------------------
  120. /   The window is being sized and we received a WM_SIZE, therefore move 
  121. /   the content of the window about.
  122. /
  123. / In:
  124. /   lpmmin -> MINMAXINFO structure
  125. /
  126. / Out:
  127. /   -
  128. /----------------------------------------------------------------------------*/
  129. VOID CQueryFrame::OnGetMinMaxInfo(LPMINMAXINFO lpmmi)
  130. {
  131.     RECT rect = {0, 0, 0, 0};
  132.     TraceEnter(TRACE_FRAMEDLG, "CQueryFrame::OnGetMinMaxInfo");
  133. #if 0
  134.     if ( !_fHideSearchPane )
  135. #endif
  136.     {
  137.         lpmmi->ptMinTrackSize.x = _szMinTrack.cx;
  138.         lpmmi->ptMinTrackSize.y = _szMinTrack.cy;
  139.         if ( !_hwndResults )
  140.         {
  141.             lpmmi->ptMaxSize.y = lpmmi->ptMinTrackSize.y;
  142.             lpmmi->ptMaxTrackSize.y = lpmmi->ptMinTrackSize.y;
  143.         }
  144.     }
  145. #if 0
  146.     else
  147.     {
  148.         AdjustWindowRect(&rect, GetWindowLong(_hwnd, GWL_STYLE), (NULL != GetMenu(_hwnd)));
  149.         lpmmi->ptMinTrackSize.y = rect.bottom - rect.top;
  150.     }
  151. #endif
  152.     if ( _hwndResults && _hwndStatus )
  153.         lpmmi->ptMinTrackSize.y += _cyStatus;
  154.     TraceLeave();
  155. }
  156. /*-----------------------------------------------------------------------------
  157. / CQueryFrame::OnCommand
  158. / ----------------------
  159. /   We have recieved a WM_COMMAND so process it accordingly.
  160. /
  161. / In:
  162. /   wParam, lParam = parameters from the message    
  163. /
  164. / Out:
  165. /   -
  166. /----------------------------------------------------------------------------*/
  167. VOID CQueryFrame::OnCommand(WPARAM wParam, LPARAM lParam)
  168. {
  169.     HRESULT hres;
  170.     UINT uID = LOWORD(wParam);
  171.     UINT uNotify = HIWORD(wParam); 
  172.     HWND hwndControl = (HWND)lParam;
  173.     INT i;
  174.     
  175.     TraceEnter(TRACE_FRAMEDLG, "CQueryFrame::OnCommand");
  176.     Trace(TEXT("uID %08x, uNotify %d, hwndControl %08x"), uID, uNotify, hwndControl);
  177.     switch ( uID )
  178.     {
  179.         case IDOK:
  180.             TraceMsg("IDOK received");
  181.             CloseQueryFrame(S_OK);
  182.             break;
  183.         case IDCANCEL:
  184.             TraceMsg("IDCANCEL received");
  185.             CloseQueryFrame(S_FALSE);
  186.             break;
  187.         case CQID_LOOKFOR:
  188.         {
  189.             if ( uNotify == CBN_SELCHANGE )
  190.             {
  191.                 INT iSel = ComboBox_GetCurSel(_hwndLookFor);
  192.                 INT iForm = (int)ComboBox_GetItemData(_hwndLookFor, iSel);
  193.                 LPQUERYFORM pQueryForm = (LPQUERYFORM)DSA_GetItemPtr(_hdsaForms, iForm);
  194.                 TraceAssert(pQueryForm);
  195.                 if ( S_FALSE == SelectForm(pQueryForm->clsidForm) )
  196.                 {
  197.                     TraceMsg("SelectForm return S_FALSE, so the user doesn't want the new form");
  198.                     PostMessage(_hwndLookFor, CB_SETCURSEL, (WPARAM)_pCurrentForm->iForm, 0);
  199.                 }
  200.                     
  201.             }
  202.             break;
  203.         }
  204.         case CQID_BROWSE:
  205.             OnBrowse();
  206.             break;
  207.         case CQID_FINDNOW:
  208.             OnFindNow();
  209.             break;
  210.         case CQID_STOP:
  211.         {
  212.             LONG style;
  213.             _pQueryHandler->StopQuery();
  214.             // For some reason, the standard method of getting the old
  215.             // def button used in SetDefButton() below isn't working,
  216.             // so we have to forcibly remove the BS_DEFPUSHBUTTON style
  217.             // from the CQID_STOP button.
  218.             style = GetWindowLong(_hwndStop, GWL_STYLE) & ~BS_DEFPUSHBUTTON;
  219.             SendMessage(_hwndStop, 
  220.                         BM_SETSTYLE, 
  221.                         MAKEWPARAM(style, 0), 
  222.                         MAKELPARAM(TRUE, 0));
  223.             SetDefButton(_hwnd, CQID_FINDNOW);
  224.             SetFocus(_hwndFindNow);
  225.             break;
  226.         }
  227.         case CQID_CLEARALL:
  228.             OnNewQuery(TRUE);                        // discard the current query
  229.             break;
  230. #if HIDE_SEARCH_PANE
  231.         case CQID_VIEW_SEARCHPANE:
  232.             HideSearchPane(!_fHideSearchPane);
  233.             break;
  234. #endif
  235.         case CQID_FILE_CLOSE:
  236.             TraceMsg("CQID_FILE_CLOSE received");
  237.             CloseQueryFrame(S_FALSE);
  238.             break;
  239.         default:
  240.             _pQueryHandler->InvokeCommand(_hwnd, uID);
  241.             break;
  242.     }
  243.     TraceLeave();
  244. }
  245. /*-----------------------------------------------------------------------------
  246. / CQueryFrame::OnInitMenu
  247. / -----------------------
  248. /   Handle telling the handler that the menu is being initialised, however
  249. /   this should only happen if the menu being activated is the
  250. /   menu bar, otherwise we assume that the caller is tracking a popup
  251. /   menu and has performed the required initalization.
  252. /
  253. / In:
  254. /   wParam, lParam = parameters from the WM_INITMENU
  255. /
  256. / Out:
  257. /   -
  258. /----------------------------------------------------------------------------*/
  259. VOID CQueryFrame::OnInitMenu(HMENU hMenu)
  260. {
  261.     TraceEnter(TRACE_FRAMEDLG, "CQueryFrame::OnInitMenu");
  262.     _fTrackingMenuBar = (GetMenu(_hwnd) == hMenu);
  263.     if ( _fTrackingMenuBar )
  264.     {
  265.         TraceMsg("Tracking the menu bar, sending activate");
  266.         _pQueryHandler->ActivateView(CQRVA_INITMENUBAR, (WPARAM)hMenu, 0L);
  267.         EnableMenuItem(hMenu, CQID_VIEW_SEARCHPANE, 
  268.                                 MF_BYCOMMAND|(_hwndResults != NULL) ? MF_ENABLED:MF_GRAYED);
  269. #if HIDE_SEARCH_PANE
  270.         CheckMenuItem(hMenu, CQID_VIEW_SEARCHPANE, 
  271.                                 MF_BYCOMMAND|(_fHideSearchPane) ? MF_UNCHECKED:MF_CHECKED);
  272. #endif
  273.     }
  274.         
  275.     TraceLeave();
  276. }
  277. /*-----------------------------------------------------------------------------
  278. / CQueryFrame::OnEnterMenuLoop
  279. / ----------------------------
  280. /   When the user displays a menu we must reflect this into the status bar
  281. /   so that we can give the user help text relating to the commands they 
  282. /   select.
  283. /
  284. / In:
  285. /   fEntering = entering the menu loop, or leaving.
  286. /
  287. / Out:
  288. /   -
  289. /----------------------------------------------------------------------------*/
  290. VOID CQueryFrame::OnEnterMenuLoop(BOOL fEntering)
  291. {
  292.     TraceEnter(TRACE_FRAMEDLG, "CQueryFrame::OnEnterMenuLoop");
  293.     if ( _hwndStatus )
  294.     {
  295.         if ( fEntering )
  296.         {
  297.             SendMessage(_hwndStatus, SB_SIMPLE, (WPARAM)TRUE, 0L);
  298.             SendMessage(_hwndStatus, SB_SETTEXT, (WPARAM)SBT_NOBORDERS|255, 0L);
  299.         }
  300.         else
  301.         {
  302.             SendMessage(_hwndStatus, SB_SIMPLE, (WPARAM)FALSE, 0L);
  303.         }
  304.     }
  305.     TraceLeave();
  306. }
  307. /*-----------------------------------------------------------------------------
  308. / CQueryFrame::OnMenuSelect
  309. / -------------------------
  310. /   Get the status text for this menu item and display it to the user,
  311. /   if this doesn't map to any particular command then NULL out
  312. /   the string.  At this point we also trap our commands.
  313. /
  314. / In:
  315. /   hMenu = menu the user is on
  316. /   uID = command ID for that item
  317. /
  318. / Out:
  319. /   -
  320. /----------------------------------------------------------------------------*/
  321. VOID CQueryFrame::OnMenuSelect(HMENU hMenu, UINT uID)
  322. {
  323.     TCHAR szBuffer[MAX_PATH] = { TEXT('') };
  324.     TraceEnter(TRACE_FRAMEDLG, "CQueryFrame::OnMenuSelect");
  325.     Trace(TEXT("hMenu %08x, uID %08x"), hMenu, uID);
  326.         
  327.     if ( _hwndStatus )
  328.     {
  329.         switch ( uID )
  330.         {
  331.             case CQID_FILE_CLOSE:
  332.             case CQID_VIEW_SEARCHPANE:
  333.                 LoadString(GLOBAL_HINSTANCE, uID, szBuffer, ARRAYSIZE(szBuffer));
  334.                 break;
  335.             default:
  336.                 _pQueryHandler->GetCommandString(uID, 0x0, szBuffer, ARRAYSIZE(szBuffer));
  337.                 break;
  338.         }
  339.         Trace(TEXT("Setting status bar to: %s"), szBuffer);
  340.         SendMessage(_hwndStatus, SB_SETTEXT, (WPARAM)SBT_NOBORDERS|255, (LPARAM)szBuffer);
  341.     }    
  342.     TraceLeave();
  343. }
  344. /*-----------------------------------------------------------------------------
  345. / CQueryFrame::OnFindNow
  346. / ----------------------
  347. //  Issue the query, resulting in a view window being created and then issuing
  348. //  the parameter block to the query client.
  349. /
  350. / In:
  351. / Out:
  352. /   HRESULT
  353. /----------------------------------------------------------------------------*/
  354. HRESULT CQueryFrame::OnFindNow(VOID)
  355. {
  356.     HRESULT hres;
  357.     CQPARAMS qp = { 0 };
  358.     LPQUERYSCOPE pQueryScope = NULL;
  359.     TCHAR szBuffer[MAX_PATH];
  360.     BOOL fFixSize = TRUE;
  361.     RECT rc;
  362.     DECLAREWAITCURSOR;
  363.     TraceEnter(TRACE_FRAMEDLG, "CQueryFrame::OnFindNow");
  364.     TraceAssert(_pCurrentForm != NULL);
  365.     if ( _fQueryRunning )
  366.         ExitGracefully(hres, E_FAIL, "Quyery is already running");
  367.     SetWaitCursor();
  368.     // If we have not created the viewer before now lets do so, also at the
  369.     // same time we attempt to fix the window size to ensure that enough
  370.     // of the view is visible.
  371.     if ( !_hwndResults )
  372.     {
  373.         if ( !_hwndStatus )
  374.         {
  375.             _hwndStatus = CreateStatusWindow(WS_CHILD, NULL, _hwnd, IDC_STATUS);
  376.             GetClientRect(_hwndStatus, &rc);
  377.             _cyStatus = rc.bottom - rc.top;
  378.         }
  379.         // Now construct the result viewer for us to use
  380.   
  381.         hres = _pQueryHandler->CreateResultView(_hwnd, &_hwndResults);
  382.         FailGracefully(hres, "Failed when creating the view object");
  383.     
  384.         GetWindowRect(_hwnd, &rc);
  385.         SetWindowPos(_hwnd, NULL,
  386.                      0, 0,
  387.                      rc.right - rc.left, 
  388.                      _szMinTrack.cy + VIEWER_DEFAULT_CY,
  389.                      SWP_NOZORDER|SWP_NOMOVE);        
  390.     }
  391.     // are we still collecting the scopes async?  If so then lets wait until
  392.     // they have all arrived before we set the UI running.
  393.     if ( _hdsaScopes && DSA_GetItemCount(_hdsaScopes) )
  394.     {         
  395.         // Collect the parameters ready for starting the query, if this fails then
  396.         // there is no point us continuing.
  397.         ZeroMemory(&qp, SIZEOF(qp));
  398.         qp.cbStruct = SIZEOF(qp);
  399.         //qp.dwFlags = 0x0;
  400.         qp.clsidForm = _pCurrentForm->clsidForm;           // new NT5 beta 2
  401.         hres = GetSelectedScope(&pQueryScope);
  402.         FailGracefully(hres, "Failed to get the scope from the LookIn control");
  403.         if ( pQueryScope )
  404.         {
  405.             Trace(TEXT("pQueryScope %08x"), pQueryScope);
  406.             qp.pQueryScope = pQueryScope->pScope;
  407.         }
  408.         hres = CallFormPages(_pCurrentForm, CALLFORMPAGES_ALL, CQPM_GETPARAMETERS, 0, (LPARAM)&qp.pQueryParameters);
  409.         FailGracefully(hres, "Failed when collecting parameters from form");
  410.         if ( !qp.pQueryParameters )
  411.         {
  412.             LoadString(GLOBAL_HINSTANCE, IDS_ERR_NOPARAMS, szBuffer, ARRAYSIZE(szBuffer));
  413.             FrameMessageBox(szBuffer, MB_ICONERROR|MB_OK);
  414.             ExitGracefully(hres, E_FAIL, "Failed to issue the query, no parameters");
  415.         }
  416.         // We either already had a view, or have just created one.  Either way
  417.         // we must now prepare the query for sending.
  418.         Trace(TEXT("qp.cbStruct %08x"), qp.cbStruct);
  419.         Trace(TEXT("qp.dwFlags %08x"), qp.dwFlags);
  420.         Trace(TEXT("qp.pQueryScope %08x"), qp.pQueryScope);
  421.         Trace(TEXT("qp.pQueryParameters %08x"), qp.pQueryParameters);
  422.         TraceGUID("qp.clsidForm: ", qp.clsidForm);
  423.         hres = _pQueryHandler->IssueQuery(&qp);
  424.         FailGracefully(hres, "Failed in IssueQuery");
  425.     }
  426.     else
  427.     {
  428.         // set the status text to reflect that we are initializng, otherwise it is
  429.         // left empty and looks like we have crashed.
  430.         if ( LoadString(GLOBAL_HINSTANCE, IDS_INITIALIZING, szBuffer, ARRAYSIZE(szBuffer)) )
  431.         {
  432.             SetStatusText(szBuffer);
  433.         }
  434.     }
  435.     hres = S_OK;               // success
  436. exit_gracefully:
  437. #if HIDE_SEARCH_PANE
  438.     if ( FAILED(hres) && !_hwndResults && _fHideSearchPane )
  439.     {
  440.         TraceMsg("Form area hidden, no results viewer created so now showing it");
  441.         HideSearchPane(FALSE);
  442.     }
  443. #endif
  444.     if ( qp.pQueryParameters )
  445.         CoTaskMemFree(qp.pQueryParameters);
  446.     ResetWaitCursor();
  447.     TraceLeaveResult(hres);
  448. }
  449. /*-----------------------------------------------------------------------------
  450. / CQueryFrame::OnNewQuery
  451. / -----------------------
  452. /   Discard the current query, prompting the user as requierd.
  453. /
  454. / In:
  455. /   fAlwaysPrompt = TRUE if we force prompting of the user
  456. /
  457. / Out:
  458. /   BOOL
  459. /----------------------------------------------------------------------------*/
  460. BOOL CQueryFrame::OnNewQuery(BOOL fAlwaysPrompt)
  461. {
  462.     BOOL fQueryCleared = TRUE;
  463.     TCHAR szBuffer[MAX_PATH];
  464.     RECT rc;
  465.     TraceEnter(TRACE_FRAMEDLG, "CQueryFrame::OnNewQuery");
  466.     if ( _hwndResults || fAlwaysPrompt )
  467.     {
  468.         LoadString(GLOBAL_HINSTANCE, IDS_CLEARCURRENT, szBuffer, ARRAYSIZE(szBuffer));
  469.         if ( IDOK != FrameMessageBox(szBuffer, MB_ICONINFORMATION|MB_OKCANCEL) )
  470.             ExitGracefully(fQueryCleared, FALSE, "Used cancled new query");
  471.         if ( _pQueryHandler )
  472.             _pQueryHandler->StopQuery();
  473.         CallFormPages(_pCurrentForm, CALLFORMPAGES_ALL, CQPM_CLEARFORM, 0, 0);
  474.         if ( _hwndResults )
  475.         {
  476.             DestroyWindow(_hwndResults);           // no result view now
  477.             _hwndResults = NULL;
  478.             DestroyWindow(_hwndStatus);            // no status bar
  479.             _hwndStatus = NULL;
  480.             GetWindowRect(_hwnd, &rc);             // shrink the window
  481.             SetWindowPos(_hwnd, NULL,
  482.                          0, 0, rc.right - rc.left, _szMinTrack.cy,         
  483.                          SWP_NOZORDER|SWP_NOMOVE);
  484.         }
  485.     }
  486. exit_gracefully:
  487.     TraceLeaveValue(fQueryCleared);
  488. }
  489. /*-----------------------------------------------------------------------------
  490. / CQueryFrame::OnBrowse
  491. / ---------------------
  492. /   Browse for a new scope, adding it to the list if not already present,
  493. /   or selecting the previous scope.
  494. /
  495. / In:
  496. / Out:
  497. /   HRESULT
  498. /----------------------------------------------------------------------------*/
  499. HRESULT CQueryFrame::OnBrowse(VOID)
  500. {
  501.     HRESULT hres;
  502.     LPQUERYSCOPE pQueryScope = NULL;
  503.     LPCQSCOPE pScope = NULL;
  504.     
  505.     TraceEnter(TRACE_FRAMEDLG, "CQueryFrame::OnBrowse");
  506.     // Call the handler and get a scope allocation back, then add it to the list
  507.     // of scopes to be displayed.
  508.     hres = GetSelectedScope(&pQueryScope);
  509.     FailGracefully(hres, "Failed to get the scope from the LookIn control");
  510.     Trace(TEXT("Calling BrowseForScope _hwnd %08x, pQueryScope %08x (%08x)"), 
  511.                                             _hwnd, pQueryScope, pQueryScope->pScope);
  512.     hres = _pQueryHandler->BrowseForScope(_hwnd, pQueryScope ? pQueryScope->pScope:NULL, &pScope);
  513.     FailGracefully(hres, "Failed when calling BrowseForScope");
  514.     if ( (hres != S_FALSE) && pScope )
  515.     {
  516.         hres = InsertScopeIntoList(pScope, DA_LAST, TRUE);
  517.         FailGracefully(hres, "Failed when adding the scope to the control");
  518.         ComboBox_SetCurSel(_hwndLookIn, ShortFromResult(hres));
  519.     }
  520.     hres = S_OK;
  521. exit_gracefully:
  522.     if ( pScope )
  523.         CoTaskMemFree(pScope);
  524.     TraceLeaveResult(hres);
  525. }
  526. /*-----------------------------------------------------------------------------
  527. / CQueryFrame::OnHelp
  528. / -------------------
  529. /   Invoke the context sensitive help for the window, catch the 
  530. /   handler specific and page specific stuff and pass those help
  531. /   requests down to the relevant objects.
  532. /
  533. / In:
  534. /   pHelpInfo -> help info structure
  535. /
  536. / Out:
  537. /   HRESULT
  538. /----------------------------------------------------------------------------*/
  539. HRESULT CQueryFrame::OnHelp(LPHELPINFO pHelpInfo)
  540. {
  541.     HRESULT hres;
  542.     RECT rc;
  543.     HWND hwnd = (HWND)pHelpInfo->hItemHandle;
  544.     TraceEnter(TRACE_FRAME, "CQueryFrame::OnHelp");
  545.     // We are invoking help, theroefore we need ot check to see where element
  546.     // of the window we are being invoked for.  If it is the 
  547.     // result view then route the message to that, if its the form then
  548.     // likewise.
  549.     //
  550.     // If we don't hit any of the extension controls then lets pass the
  551.     // help onto WinHelp and get it to display the topics we have.
  552.     if ( pHelpInfo->iContextType != HELPINFO_WINDOW )
  553.         ExitGracefully(hres, E_FAIL, "WM_HELP handler only copes with WINDOW objects");
  554.     if ( _pCurrentFormPage->hwndPage && IsChild(_pCurrentFormPage->hwndPage, hwnd) )
  555.     {
  556.         // it was on the query form page, therefore let it go there, that way
  557.         // they can provide topics specific to them
  558.         TraceMsg("Invoking help on the form pane");
  559.         hres = _CallPageProc(_pCurrentFormPage, CQPM_HELP, 0, (LPARAM)pHelpInfo);
  560.         FailGracefully(hres, "Failed when calling page proc to get help");
  561.     }
  562.     else
  563.     {
  564.         // pass the help information through to the handler as an activation,
  565.         // this should really just be a new method, but this works.
  566.         TraceMsg("Invoking help on the results pane");
  567.         TraceAssert(_pQueryHandler);
  568.         hres = _pQueryHandler->ActivateView(CQRVA_HELP, 0, (LPARAM)pHelpInfo);
  569.         FailGracefully(hres, "Handler WndProc returned FALSE");
  570.     }
  571.     hres = S_OK;
  572. exit_gracefully:
  573.     TraceLeaveResult(hres);
  574. }
  575. /*-----------------------------------------------------------------------------
  576. / Scope helper functions
  577. /----------------------------------------------------------------------------*/
  578. /*-----------------------------------------------------------------------------
  579. / _CallScopeProc
  580. / --------------
  581. /   Releae the given scope object, freeing the object that is referenced
  582. /   and passing a CQSM_RELEASE message to it.
  583. /
  584. / In:
  585. /   pQueryScope -> scope object to be called
  586. /   uMsg, pVoid -> parameters for the scope
  587. /
  588. / Out:
  589. /   HRESULT
  590. /----------------------------------------------------------------------------*/
  591. HRESULT _CallScopeProc(LPQUERYSCOPE pQueryScope, UINT uMsg, LPVOID pVoid)
  592. {
  593.     HRESULT hres;
  594.     TraceEnter(TRACE_SCOPES, "_CallScopeProc");
  595.     Trace(TEXT("pQueryScope %08x, uMsg %d, pVoid %08x"), pQueryScope, uMsg, pVoid);
  596.     
  597.     Trace(TEXT("(cbStruct %d, pScopeProc %08x, lParam %08x)"),
  598.                     pQueryScope->pScope->cbStruct,
  599.                     pQueryScope->pScope->pScopeProc,
  600.                     pQueryScope->pScope->lParam);
  601.     if ( !pQueryScope )
  602.         ExitGracefully(hres, S_OK, "pQueryScope == NULL");
  603.     hres = (pQueryScope->pScope->pScopeProc)(pQueryScope->pScope, uMsg, pVoid);
  604.     FailGracefully(hres, "Failed calling ScopeProc");
  605. exit_gracefully:
  606.     TraceLeaveResult(hres);
  607. }
  608. /*-----------------------------------------------------------------------------
  609. / _FreeScope
  610. / ----------
  611. /   Releae the given scope object, freeing the object that is referenced
  612. /   and passing a CQSM_RELEASE message to it.
  613. /
  614. / In:
  615. /   pQueryScope -> scope object to be released
  616. /
  617. / Out:
  618. /   INT == 1 always
  619. /----------------------------------------------------------------------------*/
  620. INT _FreeScopeCB(LPVOID pItem, LPVOID pData)
  621. {
  622.     return _FreeScope((LPQUERYSCOPE)pItem);
  623. }
  624. INT _FreeScope(LPQUERYSCOPE pQueryScope)
  625. {   
  626.     TraceEnter(TRACE_SCOPES, "_FreeScope");
  627.     Trace(TEXT("pQueryScope %08x, pQueryScope->pScope %08x"), pQueryScope, pQueryScope->pScope);
  628.  
  629.     if ( pQueryScope )
  630.     {
  631.         _CallScopeProc(pQueryScope, CQSM_RELEASE, NULL);
  632.         if ( pQueryScope->pScope )
  633.         {
  634.             LocalFree((HLOCAL)pQueryScope->pScope);
  635.             pQueryScope->pScope = NULL;
  636.         }
  637.     }
  638.     TraceLeaveValue(TRUE);
  639. }   
  640. /*-----------------------------------------------------------------------------
  641. / CQueryFrame::InsertScopeIntoList
  642. / --------------------------------
  643. /   Adds the given scope to the scope picker.
  644. /
  645. / In:
  646. /   pQueryScope -> zcope object to be added to the view
  647. /   i = index to insert the scope at
  648. /   fAddToControl = add the scope the picker control
  649. /   ppQueryScope -> recieves the new query scope object / = NULL
  650. /
  651. / Out:
  652. /   HRESULT
  653. /----------------------------------------------------------------------------*/
  654. HRESULT CQueryFrame::InsertScopeIntoList(LPCQSCOPE pScope, INT i, BOOL fAddToControl)
  655. {
  656.     HRESULT hres;
  657.     QUERYSCOPE qs;
  658.     INT iScope;
  659.     TraceEnter(TRACE_SCOPES, "CQueryFrame::InsertScopeIntoList");
  660.     Trace(TEXT("pScope %08x, i %d, fAddToControl %d"), pScope, i, fAddToControl);
  661.     
  662.     if ( !pScope )
  663.         ExitGracefully(hres, E_INVALIDARG, "pScope == NULL, not allowed");
  664.     // if we don't have any scopes then allocate the DSA
  665.     if ( !_hdsaScopes )
  666.     {
  667.         _hdsaScopes = DSA_Create(SIZEOF(QUERYSCOPE), 4);
  668.         TraceAssert(_hdsaScopes);
  669.         if ( !_hdsaScopes )
  670.             ExitGracefully(hres, E_OUTOFMEMORY, "Failed to allocate the scope DPA");
  671.     }
  672.     // Walk the list of scopes checking to see if this one is already in
  673.     // there, if not then we can add it.
  674.     for ( iScope = 0 ; iScope < DSA_GetItemCount(_hdsaScopes) ; iScope++ )
  675.     {
  676.         LPQUERYSCOPE pQueryScope = (LPQUERYSCOPE)DSA_GetItemPtr(_hdsaScopes, iScope);
  677.         TraceAssert(pQueryScope);
  678.         if ( S_OK == _CallScopeProc(pQueryScope, CQSM_SCOPEEQUAL, pScope) )
  679.         {
  680.             hres = ResultFromShort(iScope);
  681.             goto exit_gracefully;
  682.         }
  683.     }
  684.     // Take a copy of the scope blob passed by the caller.  We copy the entire
  685.     // structure who's size is defined by cbStruct into a LocalAlloc block,
  686.     // once we have this we can then build the QUERYSCOPE structure that references
  687.     // it.
  688.     Trace(TEXT("pScope->cbStruct == %d"), pScope->cbStruct);
  689.     qs.pScope = (LPCQSCOPE)LocalAlloc(LPTR, pScope->cbStruct);
  690.     
  691.     if ( !qs.pScope )
  692.         ExitGracefully(hres, E_OUTOFMEMORY, "Failed to allocate query scope");
  693.     Trace(TEXT("Copying structure qs.pScope %08x, pScope %08x"), qs.pScope, pScope);
  694.     CopyMemory(qs.pScope, pScope, pScope->cbStruct);
  695.     //qs.pScope = NULL;
  696.     qs.iImage = -1;         // no image
  697.     // We have a QUERYSCOPE, so initialize it, if that works then append it to the
  698.     // DSA before either setting the return value or appending it to the control.
  699.     _CallScopeProc(&qs, CQSM_INITIALIZE, NULL);
  700.     
  701.     iScope = DSA_InsertItem(_hdsaScopes, i, &qs);
  702.     Trace(TEXT("iScope = %d"), iScope);
  703.     if ( iScope == -1 )
  704.     {
  705.         _FreeScope(&qs);
  706.         ExitGracefully(hres, E_OUTOFMEMORY, "Failed to add scope to DSA");
  707.     }
  708.     if ( fAddToControl )
  709.     {
  710.         LPQUERYSCOPE pQueryScope = (LPQUERYSCOPE)DSA_GetItemPtr(_hdsaScopes, iScope);
  711.         TraceAssert(pQueryScope);
  712.         Trace(TEXT("Calling AddScopeToControl with %08x (%d)"), pQueryScope, iScope);
  713.         hres = AddScopeToControl(pQueryScope, iScope);
  714.     }
  715.     else
  716.     {
  717.         hres = ResultFromShort(iScope);
  718.     }
  719. exit_gracefully:
  720.     TraceLeaveResult(hres);
  721. }
  722. /*-----------------------------------------------------------------------------
  723. / CQueryFrame::AddScopeToControl
  724. / ------------------------------
  725. /   Adds the given scope to the scope picker.
  726. /
  727. / In:
  728. /   pQueryScope -> zcope object to be added to the view
  729. /   i = index into view where to insert the scope
  730. /
  731. / Out:
  732. /   HRESULT ( == index of item added )
  733. /----------------------------------------------------------------------------*/
  734. HRESULT CQueryFrame::AddScopeToControl(LPQUERYSCOPE pQueryScope, INT i)
  735. {
  736.     HRESULT hres;
  737.     CQSCOPEDISPLAYINFO cqsdi;
  738.     COMBOBOXEXITEM cbi;
  739.     TCHAR szBuffer[MAX_PATH];
  740.     TCHAR szIconLocation[MAX_PATH] = { 0 };
  741.     INT item;
  742.     TraceEnter(TRACE_SCOPES, "CQueryFrame::AddScopeToControl");
  743.     if ( !pQueryScope )
  744.         ExitGracefully(hres, E_INVALIDARG, "No scope specified");
  745.     // Call the scope to get the display information about this
  746.     // scope before we attempt to add it.
  747.     cqsdi.cbStruct = SIZEOF(cqsdi);
  748.     cqsdi.dwFlags = 0;
  749.     cqsdi.pDisplayName = szBuffer;
  750.     cqsdi.cchDisplayName = ARRAYSIZE(szBuffer);
  751.     cqsdi.pIconLocation = szIconLocation;
  752.     cqsdi.cchIconLocation = ARRAYSIZE(szIconLocation);
  753.     cqsdi.iIconResID = 0;
  754.     cqsdi.iIndent = 0;
  755.     
  756.     hres = _CallScopeProc(pQueryScope, CQSM_GETDISPLAYINFO, &cqsdi);
  757.     FailGracefully(hres, "Failed to get display info for the scope");               
  758.     // Now add the item to the control, if they gave as an image then
  759.     // add that to the image list (and tweak the INSERTITEM structure
  760.     // accordingly).
  761.     cbi.mask = CBEIF_TEXT|CBEIF_INDENT;
  762.     cbi.iItem = i;
  763.     cbi.pszText = cqsdi.pDisplayName;
  764.     cbi.iIndent = cqsdi.iIndent;
  765.     Trace(TEXT("Indent is %d"), cqsdi.iIndent);
  766.     if ( szIconLocation[0] && cqsdi.iIconResID )
  767.     {
  768.         INT iImage;
  769.         if ( !_fScopeImageListSet )
  770.         {
  771.             HIMAGELIST himlSmall;
  772.             Shell_GetImageLists(NULL, &himlSmall);
  773.             SendMessage(_hwndLookIn, CBEM_SETIMAGELIST, 0, (LPARAM)himlSmall);
  774.             _fScopeImageListSet = TRUE;
  775.         }
  776.         cbi.mask |= CBEIF_IMAGE|CBEIF_SELECTEDIMAGE;
  777.         cbi.iImage = Shell_GetCachedImageIndex(szIconLocation, cqsdi.iIconResID, 0x0);;
  778.         cbi.iSelectedImage = cbi.iImage;
  779.         Trace(TEXT("Image index set to: %d"), cbi.iImage);
  780.     }
  781.     item = (INT)SendMessage(_hwndLookIn, CBEM_INSERTITEM, 0, (LPARAM)&cbi);
  782.     if ( item == -1 )
  783.         ExitGracefully(hres, E_FAIL, "Failed when inserting the scope to the list");
  784.     DoEnableControls();                     // reflect button changes into UI
  785.     hres = ResultFromShort(item);
  786. exit_gracefully:
  787.     TraceLeaveResult(hres);
  788. }
  789. /*-----------------------------------------------------------------------------
  790. / CQueryFrame::PopulateScopeControl
  791. / ---------------------------------
  792. /   Collect the scopes that we want to display in the scope control and
  793. /   then populate it.  If the handler doesn't return any scopes then
  794. /   we remove the control and assume that know what to do when they
  795. /   don't receive a scope pointer.
  796. /
  797. / In:
  798. /   -
  799. /
  800. / Out:
  801. /   HRESULT
  802. /----------------------------------------------------------------------------*/
  803. HRESULT CQueryFrame::PopulateScopeControl(VOID)
  804. {
  805.     HRESULT hres;
  806.     LPQUERYSCOPE pQueryScope;
  807.     INT i;
  808.     
  809.     TraceEnter(TRACE_SCOPES, "CQueryFrame::PopulateScopeControl");
  810.     // Collect the scopes that we should be showing in the view, if we don't
  811.     // get any back then we disable the scope control, if we do get some then
  812.     // populate the scope control with them.
  813.     hres = _pQueryHandler->AddScopes();    
  814.     _fAddScopesNYI = (hres == E_NOTIMPL);
  815.     if ( hres != E_NOTIMPL )
  816.         FailGracefully(hres, "Failed when calling handler to add scopes");        
  817.     if ( _hdsaScopes )
  818.     {
  819.         // We have some scopes, so now we create the image list that we can use
  820.         // for icons with scopes.  Then walk through the DPA getting the scope
  821.         // to give us some display information about itself that we can
  822.         // add to the combo box.
  823.         ComboBox_SetExtendedUI(_hwndLookIn, TRUE);
  824.         for ( i = 0 ; i < DSA_GetItemCount(_hdsaScopes); i++ )
  825.         {
  826.             pQueryScope = (LPQUERYSCOPE)DSA_GetItemPtr(_hdsaScopes, i);
  827.             TraceAssert(pQueryScope);
  828.             AddScopeToControl(pQueryScope, i);
  829.         }
  830.     }
  831.     else
  832.     {
  833.         // we don't have any scopes after calling AddScopes, this is either 
  834.         // because the ::AddScopes method is not implemented, or the
  835.         // scopes are being added async.  If IssueQuery returned a success
  836.         // we assume they are coming in async and flag as such in our
  837.         // state.
  838.         if ( !_fAddScopesNYI )
  839.         {
  840.             TraceMsg("Handler adding scopes async, so marking so");
  841.             _fScopesAddedAsync = TRUE;
  842.         }
  843.     }
  844.     hres = S_OK;                                      // success
  845. exit_gracefully:
  846.     Trace(TEXT("Default scope is index %d"), _iDefaultScope);
  847.     ComboBox_SetCurSel(_hwndLookIn, _iDefaultScope);
  848.     TraceLeaveResult(hres);
  849. }
  850. /*-----------------------------------------------------------------------------
  851. / CQueryFrame::GetSelectedScope
  852. / -----------------------------
  853. /   Get the selected from the the scope ComboBox, this is a reference into the 
  854. /   scope DSA.
  855. /
  856. / In:
  857. /   ppQueryScope = receives a pointer to the new scope
  858. /
  859. / Out:
  860. /   HRESULT
  861. /----------------------------------------------------------------------------*/
  862. HRESULT CQueryFrame::GetSelectedScope(LPQUERYSCOPE* ppQueryScope)
  863. {
  864.     HRESULT hres;
  865.     COMBOBOXEXITEM cbi;
  866.     INT iScope;
  867.     TraceEnter(TRACE_SCOPES, "CQueryFrame::GetSelectedScope");
  868.     *ppQueryScope = NULL;
  869.     if ( _hdsaScopes )
  870.     {
  871.         // Get the index for the current scope, if it doesn't give a real
  872.         // index to a item in our view then barf!  Otherwise look up the
  873.         // associated scope.
  874.         iScope = ComboBox_GetCurSel(_hwndLookIn);
  875.         Trace(TEXT("iScope %d"), iScope);
  876.         if ( iScope == -1 )
  877.             ExitGracefully(hres, E_FAIL, "User entered scopes not supported yet");
  878.         *ppQueryScope = (LPQUERYSCOPE)DSA_GetItemPtr(_hdsaScopes, iScope);
  879.         TraceAssert(*ppQueryScope);
  880.     }
  881.     hres = S_OK;
  882. exit_gracefully:
  883.     Trace(TEXT("Returning LPQUERYSCOPE %08x"), *ppQueryScope); 
  884.     TraceLeaveResult(hres);
  885. }
  886. /*-----------------------------------------------------------------------------
  887. / Form handling functions
  888. /----------------------------------------------------------------------------*/
  889. /*-----------------------------------------------------------------------------
  890. / _FreeQueryForm
  891. / ---------------
  892. /   Destroy the QUERYFORM allocation being used to describe the form in
  893. /   our DPA.  We ensure that we issue a CQPM_RELEASE before doing anything
  894. /
  895. / In:
  896. /   pQueryForm -> query form to be destroyed
  897. /
  898. / Out:
  899. /   INT == 1 always
  900. /----------------------------------------------------------------------------*/
  901. INT _FreeQueryFormCB(LPVOID pItem, LPVOID pData)
  902. {
  903.     return _FreeQueryForm((LPQUERYFORM)pItem);
  904. }
  905. INT _FreeQueryForm(LPQUERYFORM pQueryForm)
  906. {
  907.     TraceEnter(TRACE_FORMS, "_FreeQueryForm");
  908.  
  909.     if ( pQueryForm )
  910.     {
  911.         if ( pQueryForm->hdsaPages )
  912.         {
  913.             DSA_DestroyCallback(pQueryForm->hdsaPages, _FreeQueryFormPageCB, NULL);
  914.             pQueryForm->hdsaPages = NULL;
  915.         }
  916.         Str_SetPtr(&pQueryForm->pTitle, NULL);
  917.         DestroyIcon(pQueryForm->hIcon);
  918.     }
  919.     TraceLeaveValue(TRUE);
  920. }   
  921. /*-----------------------------------------------------------------------------
  922. / _FreeQueryFormPage
  923. / ------------------
  924. /   Given a pointer to a query form page structure release the members that
  925. //  are of interest, including calling the PAGEPROC to releasee the underlying
  926. /   object.
  927. /
  928. / In:
  929. /   pQueryFormPage -> page to be removed
  930. /
  931. / Out:
  932. /   INT == 1 always
  933. /----------------------------------------------------------------------------*/
  934. INT _FreeQueryFormPageCB(LPVOID pItem, LPVOID pData)
  935. {
  936.     return _FreeQueryFormPage((LPQUERYFORMPAGE)pItem);
  937. }
  938. INT _FreeQueryFormPage(LPQUERYFORMPAGE pQueryFormPage)
  939. {   
  940.     TraceEnter(TRACE_FORMS, "_FreeQueryFormPage");
  941.     if ( pQueryFormPage )
  942.     {
  943.         _CallPageProc(pQueryFormPage, CQPM_RELEASE, 0, 0);          // NB: ignore return code
  944.         if ( pQueryFormPage->hwndPage )
  945.         {
  946.             DestroyWindow(pQueryFormPage->hwndPage);
  947.             pQueryFormPage->hwndPage = NULL;
  948.         }
  949.         if ( pQueryFormPage->pPage )
  950.         {
  951.             LocalFree(pQueryFormPage->pPage);
  952.             pQueryFormPage->pPage = NULL;
  953.         }
  954.     }        
  955.     TraceLeaveValue(TRUE);
  956. }   
  957. /*-----------------------------------------------------------------------------
  958. / _CallPageProc
  959. / -------------
  960. /   Call the given page object thunking the arguments as required if the
  961. /   page object is non-UNICODE (only if building UNICODE).
  962. /
  963. / In:
  964. /   pQueryFormPage -> page object to be called
  965. /   uMsg, wParam, lParam = parameters for message
  966. /
  967. / Out:
  968. /   HRESULT
  969. /----------------------------------------------------------------------------*/
  970. HRESULT _CallPageProc(LPQUERYFORMPAGE pQueryFormPage, UINT uMsg, WPARAM wParam, LPARAM lParam)
  971. {
  972.     HRESULT hres;
  973.     TraceEnter(TRACE_FORMS, "_CallPageProc");
  974.     Trace(TEXT("pQueryFormPage %08x, pPage %08x, uMsg %d, wParam %08x, lParam %08x"), 
  975.                         pQueryFormPage, pQueryFormPage->pPage, uMsg, wParam, lParam);
  976.     if ( !pQueryFormPage )
  977.         ExitGracefully(hres, S_OK, "pQueryFormPage == NULL");
  978.     
  979.     hres = (pQueryFormPage->pPage->pPageProc)(pQueryFormPage->pPage, pQueryFormPage->hwndPage, uMsg, wParam, lParam);
  980.     FailGracefully(hres, "Failed calling PageProc");
  981.     // hres = S_OK;
  982. exit_gracefully:
  983.     TraceLeaveResult(hres);
  984. }
  985. /*-----------------------------------------------------------------------------
  986. / ANSI functions for adding query forms/pages
  987. /----------------------------------------------------------------------------*/
  988. #ifdef UNICODE
  989. // ANSI CB to add forms to the form DSA.
  990. HRESULT _AddFormsProcA(LPARAM lParam, LPCQFORM_A pForm)
  991. {
  992.     HRESULT hres;
  993.     QUERYFORM qf;
  994.     HDSA hdsaForms = (HDSA)lParam;
  995.     USES_CONVERSION;
  996.     TraceEnter(TRACE_FORMS, "_AddFormsProcA");
  997.     if ( !pForm || !hdsaForms )
  998.         ExitGracefully(hres, E_INVALIDARG, "Failed to add page pForm == NULL");
  999.     // Allocate and thunk as required
  1000.     qf.hdsaPages = NULL;               // DSA of pages
  1001.     qf.dwFlags = pForm->dwFlags;       // flags
  1002.     qf.clsidForm = pForm->clsid;       // CLSID identifier for this form
  1003.     qf.pTitle = NULL;                  // title used for drop down / title bar
  1004.     qf.hIcon = pForm->hIcon;           // hIcon passed by caller
  1005.     qf.iImage = -1;                    // image list index of icon
  1006.     qf.iForm = 0;                      // visible index of form in control
  1007.     qf.iPage = 0;                      // currently selected page on form
  1008.     if ( !Str_SetPtr(&qf.pTitle, A2T(pForm->pszTitle)) )
  1009.         ExitGracefully(hres, E_OUTOFMEMORY, "Failed to copy form title string");
  1010.     // Allocate the DSA if one doesn't exist yet, then add in the form
  1011.     // structure as required.
  1012.     if ( -1 == DSA_AppendItem(hdsaForms, &qf) )
  1013.         ExitGracefully(hres, E_FAIL, "Failed to add form to the form DSA");
  1014.     hres = S_OK;                          // success
  1015.     
  1016. exit_gracefully:
  1017.     if ( FAILED(hres) )
  1018.         _FreeQueryForm(&qf);
  1019.     TraceLeaveResult(hres);
  1020. }
  1021. // ANSI CB to add pages to the page DSA.
  1022. HRESULT _AddPagesProcA(LPARAM lParam, REFCLSID clsidForm, LPCQPAGE_A pPage)
  1023. {
  1024.     HRESULT hres;
  1025.     QUERYFORMPAGE qfp;
  1026.     HDSA hdsaPages = (HDSA)lParam;
  1027.     TraceEnter(TRACE_FORMS, "_AddPagesProcA");
  1028.     if ( !pPage || !hdsaPages )
  1029.         ExitGracefully(hres, E_INVALIDARG, "Failed to add page pPage == NULL");
  1030.     // copy the pPage structure for us to pass to the PAGEPROC later, nb: we
  1031.     // use the cbStruct field to indicate the size of blob we must copy.
  1032.     Trace(TEXT("pPage->cbStruct == %d"), pPage->cbStruct);
  1033.     qfp.pPage = (LPCQPAGE)LocalAlloc(LPTR, pPage->cbStruct);
  1034.    
  1035.     if ( !qfp.pPage )
  1036.         ExitGracefully(hres, E_OUTOFMEMORY, "Failed to allocate copy of page structure");
  1037.     Trace(TEXT("Copying structure qfp.pPage %08x, pPage %08x"), qfp.pPage, pPage);
  1038.     CopyMemory(qfp.pPage, pPage, pPage->cbStruct);              // copy the page structure
  1039.     qfp.fPageIsANSI = TRUE;
  1040.     //qfp.pPage = NULL;
  1041.     qfp.clsidForm = clsidForm;
  1042.     qfp.pPageProcA = pPage->pPageProc;
  1043.     qfp.lParam = pPage->lParam;
  1044.     qfp.hwndPage = NULL;
  1045.     _CallPageProc(&qfp, CQPM_INITIALIZE, 0, 0);
  1046.         
  1047.     if ( -1 == DSA_AppendItem(hdsaPages, &qfp) )
  1048.         ExitGracefully(hres, E_FAIL, "Failed to add the form to the DSA");
  1049.     hres = S_OK;                      // succcess
  1050. exit_gracefully:
  1051.     if ( FAILED(hres) )
  1052.         _FreeQueryFormPage(&qfp);
  1053.     TraceLeaveResult(hres);
  1054. }
  1055. // Add forms/pages from a ANSI IQueryForm iface
  1056. HRESULT CQueryFrame::AddFromIQueryFormA(IQueryFormA* pQueryForm, HKEY hKeyForm)
  1057. {
  1058.     HRESULT hres;
  1059.     TraceEnter(TRACE_FORMS, "CQueryFrame::AddFromIQueryFormA");
  1060.     if ( !pQueryForm )
  1061.         ExitGracefully(hres, E_FAIL, "pQueryForm == NULL, failing");
  1062.     hres = pQueryForm->Initialize(hKeyForm);
  1063.     FailGracefully(hres, "Failed in IQueryFormA::Initialize");
  1064.     // Call the form object to add its form and then its pages
  1065.     hres = pQueryForm->AddForms(_AddFormsProcA, (LPARAM)_hdsaForms);
  1066.     
  1067.     if ( SUCCEEDED(hres) || (hres == E_NOTIMPL) )
  1068.     {
  1069.         hres = pQueryForm->AddPages(_AddPagesProcA, (LPARAM)_hdsaPages);
  1070.         FailGracefully(hres, "Failed in IQueryFormA::AddPages");
  1071.     }
  1072.     else    
  1073.     {
  1074.         FailGracefully(hres, "Failed when calling IQueryFormA::AddForms");
  1075.     }
  1076.     hres = S_OK;                      // success
  1077. exit_gracefully:
  1078.     TraceLeaveResult(hres);
  1079. }
  1080. #endif // #ifndef UNICODE
  1081. /*-----------------------------------------------------------------------------
  1082. / Functions for adding query forms/pages
  1083. /----------------------------------------------------------------------------*/
  1084. // CB to add forms to the form DSA.
  1085. HRESULT _AddFormsProc(LPARAM lParam, LPCQFORM pForm)
  1086. {
  1087.     HRESULT hres;
  1088.     QUERYFORM qf;
  1089.     HDSA hdsaForms = (HDSA)lParam;
  1090.     TraceEnter(TRACE_FORMS, "_AddFormsProc");
  1091.     if ( !pForm || !hdsaForms )
  1092.         ExitGracefully(hres, E_INVALIDARG, "Failed to add page pForm == NULL");
  1093.     // Allocate and thunk as required
  1094.     qf.hdsaPages = NULL;               // DSA of pages
  1095.     qf.dwFlags = pForm->dwFlags;       // flags
  1096.     qf.clsidForm = pForm->clsid;       // CLSID identifier for this form
  1097.     qf.pTitle = NULL;                  // title used for drop down / title bar
  1098.     qf.hIcon = pForm->hIcon;           // hIcon passed by caller
  1099.     qf.iImage = -1;                    // image list index of icon
  1100.     qf.iForm = 0;                      // visible index of form in control
  1101.     qf.iPage = 0;                      // currently selected page on form
  1102.     if ( !Str_SetPtr(&qf.pTitle, pForm->pszTitle) )
  1103.         ExitGracefully(hres, E_OUTOFMEMORY, "Failed to copy form title string");
  1104.     // Allocate the DSA if one doesn't exist yet, then add in the form
  1105.     // structure as required.
  1106.     if ( -1 == DSA_AppendItem(hdsaForms, &qf) )
  1107.         ExitGracefully(hres, E_FAIL, "Failed to add form to the form DSA");
  1108.     hres = S_OK;                          // success
  1109.     
  1110. exit_gracefully:
  1111.     if ( FAILED(hres) )
  1112.         _FreeQueryForm(&qf);
  1113.     TraceLeaveResult(hres);
  1114. }
  1115. // CB to add pages to the page DSA.
  1116. HRESULT _AddPagesProc(LPARAM lParam, REFCLSID clsidForm, LPCQPAGE pPage)
  1117. {
  1118.     HRESULT hres;
  1119.     QUERYFORMPAGE qfp;
  1120.     HDSA hdsaPages = (HDSA)lParam;
  1121.     TraceEnter(TRACE_FORMS, "_AddPagesProc");
  1122.     if ( !pPage || !hdsaPages )
  1123.         ExitGracefully(hres, E_INVALIDARG, "Failed to add page pPage == NULL");
  1124.     // copy the pPage structure for us to pass to the PAGEPROC later, nb: we
  1125.     // use the cbStruct field to indicate the size of blob we must copy.
  1126.     Trace(TEXT("pPage->cbStruct == %d"), pPage->cbStruct);
  1127.     qfp.pPage = (LPCQPAGE)LocalAlloc(LPTR, pPage->cbStruct);
  1128.    
  1129.     if ( !qfp.pPage )
  1130.         ExitGracefully(hres, E_OUTOFMEMORY, "Failed to allocate copy of page structure");
  1131.     Trace(TEXT("Copying structure qfp.pPage %08x, pPage %08x"), qfp.pPage, pPage);
  1132.     CopyMemory(qfp.pPage, pPage, pPage->cbStruct);              // copy the page structure
  1133. #ifdef UNICODE
  1134.     qfp.fPageIsANSI = FALSE;
  1135. #else
  1136.     qfp.fPageIsANSI = TRUE;
  1137. #endif
  1138.     //qfp.pPage = NULL;
  1139.     qfp.clsidForm = clsidForm;
  1140.     qfp.pPageProc = pPage->pPageProc;
  1141.     qfp.lParam = pPage->lParam;
  1142.     qfp.hwndPage = NULL;
  1143.     _CallPageProc(&qfp, CQPM_INITIALIZE, 0, 0);
  1144.         
  1145.     if ( -1 == DSA_AppendItem(hdsaPages, &qfp) )
  1146.         ExitGracefully(hres, E_FAIL, "Failed to add the form to the DSA");
  1147.     hres = S_OK;                      // succcess
  1148. exit_gracefully:
  1149.     if ( FAILED(hres) )
  1150.         _FreeQueryFormPage(&qfp);
  1151.     TraceLeaveResult(hres);
  1152. }
  1153. // Add forms/pages from a UNICODE IQueryForm iface
  1154. HRESULT CQueryFrame::AddFromIQueryForm(IQueryForm* pQueryForm, HKEY hKeyForm)
  1155. {
  1156.     HRESULT hres;
  1157.     TraceEnter(TRACE_FORMS, "CQueryFrame::AddFromIQueryForm");
  1158.     if ( !pQueryForm )
  1159.         ExitGracefully(hres, E_FAIL, "pQueryForm == NULL, failing");
  1160.     hres = pQueryForm->Initialize(hKeyForm);
  1161.     FailGracefully(hres, "Failed in IQueryFormW::Initialize");
  1162.     // Call the form object to add its form and then its pages
  1163.     hres = pQueryForm->AddForms(_AddFormsProc, (LPARAM)_hdsaForms);
  1164.     
  1165.     if ( SUCCEEDED(hres) || (hres == E_NOTIMPL) )
  1166.     {
  1167.         hres = pQueryForm->AddPages(_AddPagesProc, (LPARAM)_hdsaPages);
  1168.         FailGracefully(hres, "Failed in IQueryForm::AddPages");
  1169.     }
  1170.     else    
  1171.     {
  1172.         FailGracefully(hres, "Failed when calling IQueryForm::AddForms");
  1173.     }
  1174.     hres = S_OK;                      // success
  1175. exit_gracefully:
  1176.     TraceLeaveResult(hres);
  1177. }
  1178. #ifdef UNICODE
  1179. #define ADD_FROM_IQUERYFORM AddFromIQueryFormW
  1180. #else
  1181. #define ADD_FROM_IQUERYFORM AddFromIQueryFormA
  1182. #endif
  1183. /*-----------------------------------------------------------------------------
  1184. / CQueryFrame::GatherForms
  1185. / ------------------------
  1186. /   Enumerate all the query forms for the given query handler and build
  1187. /   the DPA containing the list of them.  Once we have done this we
  1188. /   can then populate the control at some more convientent moment.  
  1189. /
  1190. /   When gathering we first hit the "handler", then the "Forms" sub-key
  1191. /   trying to load all the InProc servers that provide forms.  We build
  1192. /   list of hidden, never shown etc.
  1193. /
  1194. / In:
  1195. /   -
  1196. / Out:
  1197. /   HRESULT
  1198. /----------------------------------------------------------------------------*/
  1199. HRESULT _AddPageToForm(LPQUERYFORM pQueryForm, LPQUERYFORMPAGE pQueryFormPage, BOOL fClone)
  1200. {
  1201.     HRESULT hres;
  1202.     QUERYFORMPAGE qfp;
  1203.     LPCQPAGE pPage;
  1204.     TraceEnter(TRACE_FORMS, "_AddPageToForm");
  1205.     TraceAssert(pQueryForm);
  1206.     TraceAssert(pQueryFormPage);
  1207.     // ensure that we have a page DSA for this form object
  1208.     if ( !pQueryForm->hdsaPages )
  1209.     {
  1210.         TraceMsg("Creating a new page DSA for form");
  1211.         pQueryForm->hdsaPages = DSA_Create(SIZEOF(QUERYFORMPAGE), 4);
  1212.         if ( !pQueryForm->hdsaPages )
  1213.             ExitGracefully(hres, E_OUTOFMEMORY, "*** No page DSA on form object ***");
  1214.     }
  1215.     if ( !fClone )
  1216.     {
  1217.         // Moving this page structure to the one associated with the query form,
  1218.         // therefore just ensure that the form has a DSA for pages and just 
  1219.         // insert an item at the header (yes, we add the pages in reverse).
  1220.         Trace(TEXT("Adding page %08x to form %s"), pQueryFormPage, pQueryForm->pTitle);
  1221.         if ( -1 == DSA_InsertItem(pQueryForm->hdsaPages, 0, pQueryFormPage) )
  1222.             ExitGracefully(hres, E_FAIL, "Failed to copy page to form page DSA");
  1223.     }
  1224.     else
  1225.     {
  1226.         LPCQPAGE pPage = pQueryFormPage->pPage;
  1227.         // Copying the page structure (it must be global), therefore clone
  1228.         // the QUERYFORMPAGE strucutre and the CQPAGE into a new allocation
  1229.         // and insert that into the page DSA.
  1230.         Trace(TEXT("Cloning page %08x to form %s"), pQueryFormPage, pQueryForm->pTitle);
  1231.         CopyMemory(&qfp, pQueryFormPage, SIZEOF(QUERYFORMPAGE));
  1232.         qfp.pPage = (LPCQPAGE)LocalAlloc(LPTR, pPage->cbStruct);
  1233.         if ( !qfp.pPage )
  1234.             ExitGracefully(hres, E_OUTOFMEMORY, "Failed to allocate copy of page structure");
  1235.         Trace(TEXT("Copying structure qfp.pPage %08x, pPage %08x"), qfp.pPage, pPage);
  1236.         CopyMemory(qfp.pPage, pPage, pPage->cbStruct);                                      // copy the page structure
  1237.         _CallPageProc(&qfp, CQPM_INITIALIZE, 0, 0);
  1238.         
  1239.         if ( -1 == DSA_AppendItem(pQueryForm->hdsaPages, &qfp) )
  1240.         {
  1241.             _FreeQueryFormPage(&qfp);
  1242.             ExitGracefully(hres, E_FAIL, "Failed to copy page to form DSA");
  1243.         }
  1244.     }
  1245.     hres = S_OK;                  // success
  1246. exit_gracefully:
  1247.     TraceLeaveResult(hres);
  1248. }
  1249. HRESULT CQueryFrame::GatherForms(VOID)
  1250. {
  1251.     HRESULT hres;
  1252.     IQueryForm* pQueryForm = NULL;
  1253.     HKEY hKeyForms = NULL;
  1254.     TCHAR szBuffer[MAX_PATH];
  1255.     INT i, iPage, iForm;
  1256.     RECT rect;
  1257.     DWORD cbStruct;
  1258.     TC_ITEM tci;
  1259.     TraceEnter(TRACE_FORMS, "CQueryFrame::GatherForms");
  1260.     // Construct DSA's so we can store the forms and pages as required.
  1261.     _hdsaForms = DSA_Create(SIZEOF(QUERYFORM), 4);
  1262.     _hdsaPages = DSA_Create(SIZEOF(QUERYFORMPAGE), 4);
  1263.     if ( !_hdsaForms || !_hdsaPages )
  1264.         ExitGracefully(hres, E_OUTOFMEMORY, "Failed to create DSA's for storing pages/forms");
  1265.     // First check the IQueryHandler to see if it supports IQueryForm, if it does
  1266.     // then call it to add its objects.  Note that we don't bother with ANSI/UNICODE
  1267.     // at this point as the handler is assumed to be built the same the 
  1268.     // the query framework. 
  1269.     if ( SUCCEEDED(_pQueryHandler->QueryInterface(IID_IQueryForm, (LPVOID*)&pQueryForm)) )
  1270.     {
  1271.         hres = AddFromIQueryForm(pQueryForm, NULL);
  1272.         FailGracefully(hres, "Failed when calling AddFromIQueryForm on handlers IQueryForm iface)");
  1273.     }
  1274.     // now attempt to build the list of forms and pages from the registered form
  1275.     // extensions.  These are declared under the handlers CLSID in the registry,
  1276.     // under the sub-key "Forms". 
  1277.     if ( ERROR_SUCCESS != RegOpenKeyEx(_hkHandler, c_szForms, NULL, KEY_READ, &hKeyForms) )
  1278.     {
  1279.         TraceMsg("No 'Forms' sub-key found, therefore skipping");
  1280.     }
  1281.     else
  1282.     {
  1283.         // Enumerate all the keys in the "Forms" key, these are assumed to be a list of
  1284.         // the form handlers.
  1285.         for ( i = 0 ; TRUE ; i++ )
  1286.         {
  1287.             cbStruct = SIZEOF(szBuffer);
  1288.             if ( ERROR_SUCCESS != RegEnumKeyEx(hKeyForms, i, szBuffer, &cbStruct, NULL, NULL, NULL, NULL) )
  1289.             {
  1290.                 TraceMsg("RegEnumKeyEx return's false, therefore stopping eunmeration");
  1291.                 break;
  1292.             }
  1293.             GetForms(hKeyForms, szBuffer);
  1294.         }
  1295.     }
  1296.     // Now tally the form/page information together and remove duplicates and attach the pages 
  1297.     // to forms, take special note of the global pages.   As all forms will now be in the
  1298.     // DSA we can check for a zero count and we don't have to worry about the order
  1299.     // in which the the forms and pages were added.
  1300.     if ( !DSA_GetItemCount(_hdsaForms) || !DSA_GetItemCount(_hdsaPages) )
  1301.         ExitGracefully(hres, E_FAIL, "Either the forms or pages DSA is empty");
  1302.         
  1303.     for ( iPage = DSA_GetItemCount(_hdsaPages) ; --iPage >= 0 ; )
  1304.     {
  1305.         LPQUERYFORMPAGE pQueryFormPage = (LPQUERYFORMPAGE)DSA_GetItemPtr(_hdsaPages, iPage);
  1306.         TraceAssert(pQueryFormPage);
  1307.         Trace(TEXT("iPage %d (of %d)"), iPage, DSA_GetItemCount(_hdsaPages));
  1308.         if ( !(pQueryFormPage->pPage->dwFlags & CQPF_ISGLOBAL) )
  1309.         {
  1310.             LPQUERYFORM pQueryForm = FindQueryForm(pQueryFormPage->clsidForm);
  1311.             TraceAssert(pQueryForm);
  1312.             TraceGUID("Adding page to form:", pQueryFormPage->clsidForm);
  1313.             if ( pQueryForm )
  1314.             {
  1315.                 hres = _AddPageToForm(pQueryForm, pQueryFormPage, FALSE);
  1316.                 FailGracefully(hres, "Failed when adding page to form");
  1317.                 if ( !DSA_DeleteItem(_hdsaPages, iPage) )
  1318.                     TraceMsg("**** Failed to remove page from global DSA ****");
  1319.             }
  1320.         }
  1321.     }
  1322.     for ( iPage = DSA_GetItemCount(_hdsaPages) ; --iPage >= 0 ; )
  1323.     {
  1324.         LPQUERYFORMPAGE pQueryFormPage = (LPQUERYFORMPAGE)DSA_GetItemPtr(_hdsaPages, iPage);
  1325.         TraceAssert(pQueryFormPage);
  1326.         if ( (pQueryFormPage->pPage->dwFlags & CQPF_ISGLOBAL) )
  1327.         {
  1328.             Trace(TEXT("Adding global page to %d forms"), DSA_GetItemCount(_hdsaForms));
  1329.             for ( iForm = 0 ; iForm < DSA_GetItemCount(_hdsaForms); iForm++ )
  1330.             {
  1331.                 LPQUERYFORM pQueryForm = (LPQUERYFORM)DSA_GetItemPtr(_hdsaForms, iForm);
  1332.                 TraceAssert(pQueryForm);
  1333.                 if ( !(pQueryForm->dwFlags & CQFF_NOGLOBALPAGES) )
  1334.                 {
  1335.                     hres = _AddPageToForm(pQueryForm, pQueryFormPage, TRUE);
  1336.                     FailGracefully(hres, "Failed when adding global page to form");
  1337.                 }
  1338.             }
  1339.             _FreeQueryFormPage(pQueryFormPage);
  1340.             
  1341.             if ( !DSA_DeleteItem(_hdsaPages, iPage) )
  1342.                 TraceMsg("**** Failed to remove page from global DSA ****");        
  1343.         }
  1344.     }
  1345.     // Walk the list of forms, rmeoving the ones which have no pages assocaited with
  1346.     // them, we don't need these around confusing the world around us.  Note that
  1347.     // we walk backwards through the list removing.
  1348.     //
  1349.     // Also remove the optional forms we don't want to ehw orld to see
  1350.     for ( iForm = DSA_GetItemCount(_hdsaForms) ; --iForm >= 0 ; )
  1351.     {
  1352.         LPQUERYFORM pQueryForm = (LPQUERYFORM)DSA_GetItemPtr(_hdsaForms, iForm);
  1353.         TraceAssert(pQueryForm);
  1354.         Trace(TEXT("pQueryForm %08x (%s), pQueryForm->hdsaPages %08x (%d)"), 
  1355.                         pQueryForm, 
  1356.                         pQueryForm->pTitle,
  1357.                         pQueryForm->hdsaPages, 
  1358.                         pQueryForm->hdsaPages ? DSA_GetItemCount(pQueryForm->hdsaPages):0);
  1359.         if ( !pQueryForm->hdsaPages 
  1360.                 || !DSA_GetItemCount(pQueryForm->hdsaPages )
  1361.                     || ((pQueryForm->dwFlags & CQFF_ISOPTIONAL) && !(_pOpenQueryWnd->dwFlags & OQWF_SHOWOPTIONAL))  )
  1362.         {
  1363.             TraceGUID("Removing form: ", pQueryForm->clsidForm);
  1364.             _FreeQueryForm(pQueryForm);
  1365.             DSA_DeleteItem(_hdsaForms, iForm);
  1366.         } 
  1367.     }
  1368.     if ( !DSA_GetItemCount(_hdsaForms ) )
  1369.         ExitGracefully(hres, E_FAIL, "!!!!! No forms registered after page/form fix ups !!!!!");
  1370.     // The pages have been attached to the forms so we can now attempt to create the
  1371.     // form/page objects.
  1372.     _szForm.cx = 0;
  1373.     _szForm.cy = 0;
  1374.     tci.mask = TCIF_TEXT;
  1375.     tci.pszText = TEXT("");
  1376.     tci.cchTextMax = 0;
  1377.     TabCtrl_InsertItem(_hwndFrame, 0, &tci);           // tabctrl needs at least one item so we can compute sizes
  1378.     for ( iForm = 0 ; iForm < DSA_GetItemCount(_hdsaForms); iForm++ )
  1379.     {
  1380.         LPQUERYFORM pQueryForm = (LPQUERYFORM)DSA_GetItemPtr(_hdsaForms, iForm);
  1381.         TraceAssert(pQueryForm);
  1382.         // Create each of the modeless page dialoges that we show to allow the user
  1383.         // to edit the search criteria.  We also grab the size and modify the 
  1384.         // form informaiton we have so that the default size of the dialog can be 
  1385.         // correctly computed.
  1386.         for ( iPage = 0 ; iPage < DSA_GetItemCount(pQueryForm->hdsaPages); iPage++ )
  1387.         {
  1388.             LPQUERYFORMPAGE pQueryFormPage = (LPQUERYFORMPAGE)DSA_GetItemPtr(pQueryForm->hdsaPages, iPage);
  1389.             TraceAssert(pQueryFormPage);
  1390. #ifdef UNICODE
  1391.             if ( pQueryFormPage->fPageIsANSI )
  1392.             {
  1393.                 pQueryFormPage->hwndPage = CreateDialogParamA(pQueryFormPage->pPageA->hInstance, 
  1394.                                                               MAKEINTRESOURCEA(pQueryFormPage->pPageA->idPageTemplate),
  1395.                                                               _hwnd, 
  1396.                                                               pQueryFormPage->pPageA->pDlgProc, 
  1397.                                                               (LPARAM)pQueryFormPage->pPage);
  1398.             }
  1399.             else
  1400. #endif
  1401.             {
  1402.                 pQueryFormPage->hwndPage = CreateDialogParam(pQueryFormPage->pPage->hInstance, 
  1403.                                                              MAKEINTRESOURCE(pQueryFormPage->pPage->idPageTemplate),
  1404.                                                              _hwnd, 
  1405.                                                              pQueryFormPage->pPage->pDlgProc, 
  1406.                                                              (LPARAM)pQueryFormPage->pPage);
  1407.             }
  1408.             if ( !pQueryFormPage->hwndPage )
  1409.                 ExitGracefully(hres, E_FAIL, "Failed to create query form page");
  1410.             GetRealWindowInfo(pQueryFormPage->hwndPage, &rect, NULL);
  1411.             TabCtrl_AdjustRect(_hwndFrame, TRUE, &rect);
  1412.             _szForm.cx = max(rect.right-rect.left, _szForm.cx);
  1413.             _szForm.cy = max(rect.bottom-rect.top, _szForm.cy);
  1414.             // flush the form parameters
  1415.             _CallPageProc(pQueryFormPage, CQPM_CLEARFORM, 0, 0);
  1416.             // Call the page with CQPM_SETDEFAULTPARAMETERS with the
  1417.             // OPENQUERYWINDOW structure.  wParam is TRUE/FALSE indiciating if
  1418.             // the form is the default one, and therefore if the pFormParam is 
  1419.             // valid.
  1420.             _CallPageProc(pQueryFormPage, CQPM_SETDEFAULTPARAMETERS, 
  1421.                           (WPARAM)((_pOpenQueryWnd->dwFlags & OQWF_DEFAULTFORM) &&
  1422.                                 IsEqualCLSID(_pOpenQueryWnd->clsidDefaultForm, pQueryFormPage->clsidForm)),
  1423.                           (LPARAM)_pOpenQueryWnd);
  1424.         }
  1425.         // If the form has an hIcon then lets ensure that we add that to the form image
  1426.         // list, any failure here is non-fatal, in that we will just skip that forms
  1427.         // icon in the list (rather than barfing)
  1428.         if ( pQueryForm->hIcon )
  1429.         {
  1430.             if ( !_himlForms )
  1431.                 _himlForms = ImageList_Create(COMBOEX_IMAGE_CX, COMBOEX_IMAGE_CY, 0, 4, 1);                
  1432.             
  1433.             if ( _himlForms )
  1434.             {
  1435.                 pQueryForm->iImage = ImageList_AddIcon(_himlForms, pQueryForm->hIcon);
  1436.                 TraceAssert(pQueryForm->iImage >= 0);
  1437.             }            
  1438.             DestroyIcon(pQueryForm->hIcon);
  1439.             pQueryForm->hIcon = NULL;
  1440.         }
  1441.     }
  1442.     hres = S_OK;                  // success
  1443. exit_gracefully:
  1444.     DoRelease(pQueryForm);
  1445.     if ( hKeyForms )
  1446.         RegCloseKey(hKeyForms);
  1447.     TraceLeaveResult(hres);
  1448. }
  1449. /*-----------------------------------------------------------------------------
  1450. / CQueryFrame::GetForms
  1451. / ---------------------
  1452. /   Given a HKEY to the forms list and the value name for the form we want
  1453. /   to add, query for the form information add add the form objects
  1454. /   to the master list.
  1455. /
  1456. / In:
  1457. /   hKeyForms = HKEY for the {CLSID provider}Forms key
  1458. /   pName -> key value to query for
  1459. /
  1460. / Out:
  1461. /   VOID
  1462. /----------------------------------------------------------------------------*/
  1463. HRESULT CQueryFrame::GetForms(HKEY hKeyForms, LPTSTR pName)
  1464. {
  1465.     HRESULT hres;
  1466.     HKEY hKeyForm = NULL;
  1467.     TCHAR szQueryFormCLSID[GUIDSTR_MAX+1];
  1468.     DWORD dwFlags;
  1469.     DWORD dwSize;
  1470.     IUnknown* pUnknown = NULL;
  1471.     IQueryForm* pQueryForm = NULL;
  1472. #ifdef UNICODE
  1473.     IQueryFormA* pQueryFormA = NULL;
  1474. #endif
  1475.     CLSID clsidForm;
  1476.     BOOL fIncludeForms = FALSE;
  1477.     TraceEnter(TRACE_FORMS, "CQueryFrame::_GetForms");
  1478.     Trace(TEXT("pName %s"), pName);
  1479.     if ( ERROR_SUCCESS != RegOpenKeyEx(hKeyForms, pName, NULL, KEY_READ, &hKeyForm) )
  1480.         ExitGracefully(hres, E_UNEXPECTED, "Failed to open the form key");
  1481.     // Read the flags and try to determine if we should invoke this form object.
  1482.     dwSize = SIZEOF(dwFlags);
  1483.     if ( ERROR_SUCCESS != RegQueryValueEx(hKeyForm, c_szFlags, NULL, NULL, (LPBYTE)&dwFlags, &dwSize) )
  1484.     {
  1485.         TraceMsg("No flags, defaulting to something sensible");
  1486.         dwFlags = QUERYFORM_CHANGESFORMLIST;
  1487.     }
  1488.     Trace(TEXT("Forms flag is %08x"), dwFlags);
  1489.     // should be invoke this form object?
  1490.     //
  1491.     //  - if dwFlags has QUERYFORM_CHANGESFORMSLIST, or
  1492.     //  - if dwFlags has QUERYFORM_CHANGESOPTFORMLIST and we are showing optional forms, or
  1493.     //  - neither set and the form object supports the requested form
  1494.     if ( !(dwFlags & QUERYFORM_CHANGESFORMLIST) ) 
  1495.     {
  1496.         if ( (dwFlags & QUERYFORM_CHANGESOPTFORMLIST) &&
  1497.                 (_pOpenQueryWnd->dwFlags & OQWF_SHOWOPTIONAL) )
  1498.         {
  1499.             TraceMsg("Form is optional, are we are showing optional forms");
  1500.             fIncludeForms = TRUE;
  1501.         }
  1502.         else
  1503.         {
  1504.             // OK, so it either didn't update the form list, or wasn't marked as optional,
  1505.             // so lets check to see if it supports the form the user has requested, if not
  1506.             // then don't bother loading this guy.
  1507.             if ( _pOpenQueryWnd->dwFlags & OQWF_DEFAULTFORM )
  1508.             {
  1509.                 TCHAR szBuffer[GUIDSTR_MAX+32];
  1510.                 HKEY hkFormsSupported;
  1511.                 TraceMsg("Checking for supported form");                
  1512.                 if ( ERROR_SUCCESS == RegOpenKeyEx(hKeyForm, TEXT("Forms Supported"), NULL, KEY_READ, &hkFormsSupported) ) 
  1513.                 {
  1514.                     TraceMsg("Form has a 'Supported Forms' sub-key");
  1515.                     GetStringFromGUID(_pOpenQueryWnd->clsidDefaultForm, szQueryFormCLSID, ARRAYSIZE(szQueryFormCLSID));
  1516.                     Trace(TEXT("Checking for: %s"), szQueryFormCLSID);
  1517.                     if ( ERROR_SUCCESS == RegQueryValueEx(hkFormsSupported, szQueryFormCLSID, NULL, NULL, NULL, NULL) )
  1518.                     {
  1519.                         TraceMsg("Query form is in supported list");
  1520.                         fIncludeForms = TRUE;
  1521.                     }
  1522.                     RegCloseKey(hkFormsSupported);
  1523.                 }
  1524.                 else
  1525.                 {
  1526.                     TraceMsg("No forms supported sub-key, so loading form object anyway");
  1527.                     fIncludeForms = TRUE;
  1528.                 }
  1529.             }                
  1530.         }
  1531.     }
  1532.     else
  1533.     {
  1534.         TraceMsg("Form updates form list");
  1535.         fIncludeForms = TRUE;
  1536.     }
  1537.     // if fIncludeForms is TRUE, then the checks above succeeded and we are including forms
  1538.     // from this object (identified by pName), so we must now get the CLSID of the object
  1539.     // we are invoking and use its IQueryForm interface to add the forms that we want.
  1540.     if ( fIncludeForms )
  1541.     {
  1542.         // get the form object CLSID, having parse it, then CoCreate it adding the forms.
  1543.         dwSize = SIZEOF(szQueryFormCLSID);
  1544.         if ( ERROR_SUCCESS != RegQueryValueEx(hKeyForm, c_szCLSID, NULL, NULL, (LPBYTE)szQueryFormCLSID, &dwSize) )
  1545.             ExitGracefully(hres, E_UNEXPECTED, "Failed to read the CLSID of the form");
  1546.         Trace(TEXT("szQueryFormCLSID: %s"), szQueryFormCLSID);
  1547.         if ( !GetGUIDFromString(szQueryFormCLSID, &clsidForm) )
  1548.             ExitGracefully(hres, E_UNEXPECTED, "Fialed to parse the string as a GUID");
  1549.         // we now have the CLISD of the form object, so we must attempt to CoCreate it, we try for
  1550.         // the current build type (eg UNICODE) and then fall back to ANSI if thats not supported,
  1551.         // so we can support ANSI query form objects on a UNICODE platform.
  1552.         hres = CoCreateInstance(clsidForm, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (void**)&pUnknown);
  1553.         FailGracefully(hres, "Failed to CoCreate the form object");
  1554.         if ( SUCCEEDED(pUnknown->QueryInterface(IID_IQueryForm, (LPVOID*)&pQueryForm)) )
  1555.         {
  1556.             hres = AddFromIQueryForm(pQueryForm, hKeyForm);
  1557.             FailGracefully(hres, "Failed when adding forms from specified IQueryForm iface");
  1558.         }
  1559. #ifdef UNICODE
  1560.         else if ( SUCCEEDED(pUnknown->QueryInterface(IID_IQueryFormA, (LPVOID*)&pQueryFormA)) )
  1561.         {
  1562.             hres = AddFromIQueryFormA(pQueryFormA, hKeyForms);
  1563.             FailGracefully(hres, "(ANSI) Failed when adding forms from specified IQueryForm iface");
  1564.         }
  1565. #endif    
  1566.         else
  1567.         {
  1568.             ExitGracefully(hres, E_UNEXPECTED, "Form object doesn't support IQueryForm(A/W)");
  1569.         }
  1570.     }
  1571.     hres = S_OK;
  1572. exit_gracefully:
  1573.     if ( hKeyForm )
  1574.         RegCloseKey(hKeyForm);
  1575.     DoRelease(pUnknown);
  1576.     DoRelease(pQueryForm);
  1577. #ifdef UNICODE
  1578.     DoRelease(pQueryFormA);
  1579. #endif
  1580.     TraceLeaveResult(hres);
  1581. }
  1582. /*-----------------------------------------------------------------------------
  1583. / CQueryFrame::PopulateFormControl
  1584. / ---------------------------------
  1585. /   Enumerate all the query forms for the given query handler and build
  1586. /   the DPA containing the list of them.  Once we have done this we
  1587. /   can then populate the control at some more convientent moment.  
  1588. /
  1589. /   When gathering we first hit the "handler", then the "Forms" sub-key
  1590. /   trying to load all the InProc servers that provide forms.  We build
  1591. /   list of hidden, never shown etc.
  1592. /
  1593. / In:
  1594. /   fIncludeHidden = list forms marked as hidden in control
  1595. /
  1596. / Out:
  1597. /   VOID
  1598. /----------------------------------------------------------------------------*/
  1599. HRESULT CQueryFrame::PopulateFormControl(BOOL fIncludeHidden)
  1600. {
  1601.     HRESULT hres;
  1602.     COMBOBOXEXITEM cbi;
  1603.     LPQUERYFORM pQueryForm;
  1604.     INT i, iForm;
  1605.     TraceEnter(TRACE_FORMS, "CQueryFrame::PopulateFormControl");
  1606.     Trace(TEXT("fIncludeHidden: %d"), fIncludeHidden);
  1607.     // list which forms within the control
  1608.     if ( !_hdsaForms )
  1609.         ExitGracefully(hres, E_FAIL, "No forms to list");
  1610.         
  1611.     ComboBox_ResetContent(_hwndLookFor);                           // remove all items from that control
  1612.     
  1613.     for ( i = 0, iForm = 0 ; iForm < DSA_GetItemCount(_hdsaForms); iForm++ )
  1614.     {
  1615.         LPQUERYFORM pQueryForm = (LPQUERYFORM)DSA_GetItemPtr(_hdsaForms, iForm);
  1616.         TraceAssert(pQueryForm);
  1617.         // filter out those forms that are not of interest to this instance of the
  1618.         // dialog.
  1619.         if ( ((pQueryForm->dwFlags & CQFF_ISOPTIONAL) && !fIncludeHidden) || 
  1620.               (pQueryForm->dwFlags & CQFF_ISNEVERLISTED) )
  1621.         {
  1622.             Trace(TEXT("Hiding form: %s"), pQueryForm->pTitle);
  1623.             continue;
  1624.         }
  1625.         // now add the form to the control, including the image if there is an image
  1626.         // specified.
  1627.         cbi.mask = CBEIF_TEXT|CBEIF_LPARAM;
  1628.         cbi.iItem = i++;
  1629.         cbi.pszText = pQueryForm->pTitle;
  1630.         cbi.cchTextMax = lstrlen(pQueryForm->pTitle);
  1631.         cbi.lParam = iForm;
  1632.         if ( pQueryForm->iImage >= 0 )
  1633.         {
  1634.             Trace(TEXT("Form has an image %d"), pQueryForm->iImage);
  1635.             cbi.mask |= CBEIF_IMAGE|CBEIF_SELECTEDIMAGE;
  1636.             cbi.iImage = pQueryForm->iImage;
  1637.             cbi.iSelectedImage = pQueryForm->iImage;
  1638.         }
  1639.         pQueryForm->iForm = (int)SendMessage(_hwndLookFor, CBEM_INSERTITEM, 0, (LPARAM)&cbi);
  1640.         if ( pQueryForm->iForm < 0 )
  1641.         {
  1642.             Trace(TEXT("Form name: %s"), pQueryForm->pTitle);
  1643.             ExitGracefully(hres, E_FAIL, "Failed to add the entry to the combo box");
  1644.         }
  1645.     }
  1646.     hres = S_OK;
  1647. exit_gracefully:
  1648.     TraceLeaveValue(hres);
  1649. }
  1650. /*-----------------------------------------------------------------------------
  1651. / CQueryFrame::SelectForm
  1652. / -----------------------
  1653. /   Changes the current form to the one specified as an into the DPA.
  1654. /
  1655. / In:
  1656. /   iForm = form to be selected
  1657. /
  1658. / Out:
  1659. /   -
  1660. /----------------------------------------------------------------------------*/
  1661. HRESULT CQueryFrame::SelectForm(REFCLSID clsidForm)
  1662. {
  1663.     HRESULT hres;
  1664.     LPQUERYFORM pQueryForm, pOldQueryForm;
  1665.     LPQUERYFORMPAGE pQueryFormPage;
  1666.     LPCQPAGE pPage;
  1667.     INT nCmdShow = SW_SHOW;
  1668.     TCHAR szBuffer[64], szTitle[MAX_PATH];;
  1669.     TC_ITEM tci;
  1670.     INT i;
  1671.     
  1672.     TraceEnter(TRACE_FORMS, "CQueryFrame::SelectForm");
  1673.     
  1674.     pQueryForm = FindQueryForm(clsidForm);
  1675.     TraceAssert(pQueryForm);
  1676.     if ( !pQueryForm )
  1677.         ExitGracefully(hres, S_FALSE, "Failed to find the requested form");
  1678.     // Change the currently displayed form and change the displayed
  1679.     // tabs to correctly indicate this
  1680.     if ( (pQueryForm != _pCurrentForm) )
  1681.     {            
  1682.         if ( !OnNewQuery(FALSE) )                               // prompt the user
  1683.             ExitGracefully(hres, S_FALSE, "Failed to select the new form");
  1684.         TabCtrl_DeleteAllItems(_hwndFrame);
  1685.         for ( i = 0 ; i < DSA_GetItemCount(pQueryForm->hdsaPages) ; i++ )
  1686.         {
  1687.             pQueryFormPage = (LPQUERYFORMPAGE)DSA_GetItemPtr(pQueryForm->hdsaPages, i);
  1688.             pPage = pQueryFormPage->pPage;
  1689.             tci.mask = TCIF_TEXT;
  1690.             tci.pszText = pQueryForm->pTitle;
  1691.             tci.cchTextMax = MAX_PATH;
  1692.             if ( pPage->idPageName && 
  1693.                     LoadString(pPage->hInstance, pPage->idPageName, szBuffer, ARRAYSIZE(szBuffer)) ) 
  1694.             {
  1695.                 Trace(TEXT("Loaded page title string %s"), szBuffer);
  1696.                 tci.pszText = szBuffer;
  1697.             }
  1698.             TabCtrl_InsertItem(_hwndFrame, i, &tci);
  1699.         }
  1700.         ComboBox_SetCurSel(_hwndLookFor, pQueryForm->iForm);
  1701.         _pCurrentForm = pQueryForm;
  1702.         SelectFormPage(pQueryForm, pQueryForm->iPage);
  1703.        
  1704.         // Change the dialog title to reflect the new form
  1705.         if ( LoadString(GLOBAL_HINSTANCE, IDS_FIND, szBuffer, ARRAYSIZE(szBuffer)) )
  1706.         {
  1707.             wsprintf(szTitle, szBuffer, pQueryForm->pTitle);
  1708. #if defined(DSUI_DEBUG) && !defined(UNICODE)
  1709.             StrCat(szTitle, TEXT(" (ANSI CMNQUERY)"));
  1710. #endif
  1711.             SetWindowText(_hwnd, szTitle);
  1712.         }
  1713.         // Tell the handler that we have changed the form, they can then use this
  1714.         // new form name to modify their UI.
  1715.         _pQueryHandler->ActivateView(CQRVA_FORMCHANGED, (WPARAM)lstrlen(pQueryForm->pTitle), (LPARAM)pQueryForm->pTitle);
  1716.     }
  1717.     hres = S_OK;
  1718. exit_gracefully:
  1719.     TraceLeaveResult(hres);
  1720. }
  1721. /*-----------------------------------------------------------------------------
  1722. / CQueryFrame::SelectFormPage
  1723. / ---------------------------
  1724. /   Change the currently active page of a query form to the one specified
  1725. /   by the index.
  1726. /
  1727. / In:
  1728. /   pQueryForm = query form to be changed
  1729. /   iForm = form to be selected
  1730. /
  1731. / Out:
  1732. /   -
  1733. /----------------------------------------------------------------------------*/
  1734. VOID CQueryFrame::SelectFormPage(LPQUERYFORM pQueryForm, INT iPage)
  1735. {
  1736.     LPQUERYFORMPAGE pQueryFormPage;
  1737.     RECT rect;
  1738.     TraceEnter(TRACE_FORMS, "CQueryFrame::SelectFormPage");
  1739.     pQueryFormPage = (LPQUERYFORMPAGE)DSA_GetItemPtr(pQueryForm->hdsaPages, iPage);
  1740.        
  1741.     // Have we changed the query form page?  If so then display the now dialog
  1742.     // hiding the previous one.  We call the TabCtrl to find out where we should
  1743.     // be placing this new control.
  1744.     if ( pQueryFormPage != _pCurrentFormPage )
  1745.     {
  1746.         // Reflect the change into the tab control
  1747.         TabCtrl_SetCurSel(_hwndFrame, iPage);
  1748.         pQueryForm->iPage = iPage;
  1749.         // Fix the size and visability of the new form
  1750.         
  1751.         if ( _pCurrentFormPage )
  1752.             ShowWindow(_pCurrentFormPage->hwndPage, SW_HIDE);
  1753.     
  1754.         GetRealWindowInfo(_hwndFrame, &rect, NULL);
  1755.         TabCtrl_AdjustRect(_hwndFrame, FALSE, &rect);
  1756.         SetWindowPos(pQueryFormPage->hwndPage, 
  1757.                      HWND_TOP,
  1758.                      rect.left, rect.top, 
  1759.                      rect.right - rect.left,
  1760.                      rect.bottom - rect.top,
  1761.                      SWP_SHOWWINDOW);
  1762.         _pCurrentFormPage = pQueryFormPage;    
  1763.     }
  1764.     TraceLeave();
  1765. }
  1766. /*-----------------------------------------------------------------------------
  1767. / CQueryFrame::CallFormPages
  1768. / --------------------------
  1769. /   Given a query form traverse the array of pages calling each of them
  1770. /   with the given message information.  If any of the pages return
  1771. /   an error code (other than E_NOTIMPL) we bail.
  1772. /
  1773. / In:
  1774. /   pQueryForm = query form to call
  1775. /   dwFlags = flags indicating which pages to call
  1776. /   uMsg, wParam, lParam = parameters for the page
  1777. /   
  1778. / Out:
  1779. /   HRESULT
  1780. /----------------------------------------------------------------------------*/
  1781. HRESULT CQueryFrame::CallFormPages(LPQUERYFORM pQueryForm, DWORD dwFlags, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1782. {
  1783.     HRESULT hres = S_OK;    
  1784.     INT iPage;
  1785.     TraceEnter(TRACE_FORMS, "CQueryFrame::CallFormPages");
  1786.     if ( !pQueryForm || !pQueryForm->hdsaPages )
  1787.         ExitGracefully(hres, E_FAIL, "No pQueryForm || pQueryForm->hdsaPages == NULL");
  1788.     Trace(TEXT("pQueryForm %08x, dwFlags %08x"), pQueryForm, dwFlags);
  1789.     Trace(TEXT("uMsg %08x, wParam %08x, lParam %08x"), uMsg, wParam, lParam);
  1790.     Trace(TEXT("%d pages to call"), DSA_GetItemCount(pQueryForm->hdsaPages));
  1791.     // Call each page in turn if it matches the filter we have been given for calling
  1792.     // down.  If a page returns S_FALSE or a FAILURE then we exit the loop.  If the
  1793.     // failure however is E_NOTIMPL then we ignore.
  1794.     for ( iPage = 0 ; iPage < DSA_GetItemCount(pQueryForm->hdsaPages); iPage++ )
  1795.     {
  1796.         LPQUERYFORMPAGE pQueryFormPage = (LPQUERYFORMPAGE)DSA_GetItemPtr(pQueryForm->hdsaPages, iPage);
  1797.         TraceAssert(pQueryFormPage);
  1798.         if ( (  (pQueryFormPage->fPageIsANSI) && (dwFlags & CALLFORMPAGES_ANSI)) ||
  1799.              ( !(pQueryFormPage->fPageIsANSI) && (dwFlags & CALLFORMPAGES_UNICODE)) )
  1800.         {
  1801.             hres = _CallPageProc(pQueryFormPage, uMsg, wParam, lParam);
  1802.             if ( FAILED(hres) && (hres != E_NOTIMPL) )
  1803.             {
  1804.                 TraceMsg("PageProc returned a FAILURE");
  1805.                 break;
  1806.             }
  1807.             else if ( hres == S_FALSE )
  1808.             {
  1809.                 TraceMsg("PageProc returned S_FALSE, exiting loop");
  1810.                 break;
  1811.             }
  1812.         }
  1813.     }
  1814. exit_gracefully:
  1815.     TraceLeaveResult(hres);
  1816. }
  1817. /*-----------------------------------------------------------------------------
  1818. / CQueryFrame::FindQueryForm
  1819. / --------------------------
  1820. /   Given the CLSID for the form return a pointer to its LPQUERYFORM structure,
  1821. /   or NULL if not found.
  1822. /
  1823. / In:
  1824. /   clsidForm = ID of the form
  1825. /   
  1826. / Out:
  1827. /   LPQUERYFORM
  1828. /----------------------------------------------------------------------------*/
  1829. LPQUERYFORM CQueryFrame::FindQueryForm(REFCLSID clsidForm)
  1830. {
  1831.     LPQUERYFORM pQueryForm = NULL;
  1832.     INT i;
  1833.     TraceEnter(TRACE_FORMS, "CQueryFrame::FindQueryForm");
  1834.     TraceGUID("Form ID", clsidForm);
  1835.     for ( i = 0 ; _hdsaForms && (i < DSA_GetItemCount(_hdsaForms)) ; i++ )
  1836.     {
  1837.         pQueryForm = (LPQUERYFORM)DSA_GetItemPtr(_hdsaForms, i);
  1838.         TraceAssert(pQueryForm);
  1839.         if ( IsEqualCLSID(clsidForm, pQueryForm->clsidForm) )
  1840.         {
  1841.             Trace(TEXT("Form is index %d (%08x)"), i, pQueryForm);
  1842.             break;
  1843.         }
  1844.     }
  1845.     if ( !_hdsaForms || (i >= DSA_GetItemCount(_hdsaForms)) )
  1846.         pQueryForm = NULL;
  1847.     TraceLeaveValue(pQueryForm);
  1848. }