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.

641 lines
17 KiB

  1. //
  2. // Copyright 1997 - Microsoft
  3. //
  4. //
  5. // SERVERQY.CPP - The RIS server query form
  6. //
  7. #include "pch.h"
  8. #include "serverqy.h"
  9. #include "mangdlg.h"
  10. DEFINE_MODULE("IMADMUI")
  11. DEFINE_THISCLASS("CRISrvQueryForm")
  12. #define THISCLASS CRISrvQueryForm
  13. #define LPTHISCLASS LPCRISrvQueryForm
  14. #define FILTER_QUERY_SERVER L"(&(objectClass=computer)(netbootSCPBL=*)(CN=%s))"
  15. #define StringByteCopy(pDest, iOffset, sz) \
  16. { memcpy(&(((LPBYTE)pDest)[iOffset]), sz, StringByteSize(sz)); }
  17. #define StringByteSize(sz) \
  18. ((wcslen(sz)+1)*sizeof(WCHAR))
  19. DWORD aSrvQueryHelpMap[] = {
  20. IDC_E_SERVER, HIDC_E_SERVER,
  21. NULL, NULL
  22. };
  23. //
  24. // CRISrvQueryForm_CreateInstance( )
  25. //
  26. LPVOID
  27. CRISrvQueryForm_CreateInstance( void )
  28. {
  29. TraceFunc( "CRISrvQueryForm_CreateInstance()\n" );
  30. LPTHISCLASS lpcc = new THISCLASS( );
  31. if ( !lpcc ) {
  32. RETURN(lpcc);
  33. }
  34. HRESULT hr = THR( lpcc->Init( ) );
  35. if ( FAILED(hr) )
  36. {
  37. delete lpcc;
  38. RETURN(NULL);
  39. }
  40. RETURN(lpcc);
  41. }
  42. //
  43. // Constructor
  44. //
  45. THISCLASS::THISCLASS( )
  46. {
  47. TraceClsFunc( "CRISrvQueryForm( )\n" );
  48. InterlockIncrement( g_cObjects );
  49. TraceFuncExit();
  50. }
  51. //
  52. // Init( )
  53. //
  54. HRESULT
  55. THISCLASS::Init( )
  56. {
  57. TraceClsFunc( "Init( )\n" );
  58. HRESULT hr;
  59. // IUnknown stuff
  60. BEGIN_QITABLE_IMP( CRISrvQueryForm, IQueryForm );
  61. QITABLE_IMP( IQueryForm );
  62. END_QITABLE_IMP( CRISrvQueryForm );
  63. Assert( _cRef == 0);
  64. AddRef( );
  65. hr = CheckClipboardFormats( );
  66. HRETURN(hr);
  67. }
  68. //
  69. // Destructor
  70. //
  71. THISCLASS::~THISCLASS( )
  72. {
  73. TraceClsFunc( "~CRISrvQueryForm( )\n" );
  74. InterlockDecrement( g_cObjects );
  75. TraceFuncExit();
  76. }
  77. // ************************************************************************
  78. //
  79. // IUnknown
  80. //
  81. // ************************************************************************
  82. //
  83. // QueryInterface()
  84. //
  85. STDMETHODIMP
  86. THISCLASS::QueryInterface(
  87. REFIID riid,
  88. LPVOID *ppv )
  89. {
  90. TraceClsFunc( "" );
  91. HRESULT hr = ::QueryInterface( this, _QITable, riid, ppv );
  92. QIRETURN( hr, riid );
  93. }
  94. //
  95. // AddRef()
  96. //
  97. STDMETHODIMP_(ULONG)
  98. THISCLASS::AddRef( void )
  99. {
  100. TraceClsFunc( "[IUnknown] AddRef( )\n" );
  101. InterlockIncrement( _cRef );
  102. RETURN(_cRef);
  103. }
  104. //
  105. // Release()
  106. //
  107. STDMETHODIMP_(ULONG)
  108. THISCLASS::Release( void )
  109. {
  110. TraceClsFunc( "[IUnknown] Release( )\n" );
  111. InterlockDecrement( _cRef );
  112. if ( _cRef )
  113. RETURN(_cRef);
  114. TraceDo( delete this );
  115. RETURN(0);
  116. }
  117. // ************************************************************************
  118. //
  119. // IQueryForm
  120. //
  121. // ************************************************************************
  122. //
  123. // Initialize( )
  124. //
  125. STDMETHODIMP
  126. THISCLASS::Initialize(
  127. HKEY hkForm)
  128. {
  129. TraceClsFunc( "[IQueryForm] Initialize( )\n" );
  130. HRETURN(S_OK);
  131. }
  132. //
  133. // SetObject( )
  134. //
  135. STDMETHODIMP
  136. THISCLASS::AddForms(
  137. LPCQADDFORMSPROC pAddFormsProc,
  138. LPARAM lParam )
  139. {
  140. TraceClsFunc( "[IQueryForm] AddForms(" );
  141. TraceMsg( TF_FUNC, " pAddFormsProc = 0x%p, lParam = 0x%p )\n", pAddFormsProc, lParam );
  142. if ( !pAddFormsProc )
  143. HRETURN(E_INVALIDARG);
  144. HRESULT hr = S_OK;
  145. CQFORM cqf;
  146. WCHAR szTitle[ 255 ];
  147. DWORD dw;
  148. if (!LoadString( g_hInstance, IDS_REMOTE_INSTALL_SERVERS, szTitle, ARRAYSIZE(szTitle))) {
  149. HRETURN(HRESULT_FROM_WIN32(GetLastError()));
  150. }
  151. ZeroMemory( &cqf, sizeof(cqf) );
  152. cqf.cbStruct = sizeof(cqf);
  153. cqf.dwFlags = CQFF_ISOPTIONAL;
  154. cqf.clsid = CLSID_RISrvQueryForm;
  155. cqf.pszTitle = szTitle;
  156. hr = THR( pAddFormsProc(lParam, &cqf) );
  157. HRETURN(hr);
  158. }
  159. //
  160. // AddPages( )
  161. //
  162. STDMETHODIMP
  163. THISCLASS::AddPages(
  164. LPCQADDPAGESPROC pAddPagesProc,
  165. LPARAM lParam)
  166. {
  167. TraceClsFunc( "[IQueryForm] AddPages(" );
  168. TraceMsg( TF_FUNC, " pAddPagesProc = 0x%p, lParam = 0x%p )\n", pAddPagesProc, lParam );
  169. if ( !pAddPagesProc )
  170. HRETURN(E_INVALIDARG);
  171. HRESULT hr = S_OK;
  172. CQPAGE cqp;
  173. cqp.cbStruct = sizeof(cqp);
  174. cqp.dwFlags = 0x0;
  175. cqp.pPageProc = (LPCQPAGEPROC) PropSheetPageProc;
  176. cqp.hInstance = g_hInstance;
  177. cqp.idPageName = IDS_REMOTE_INSTALL_SERVERS;
  178. cqp.idPageTemplate = IDD_SERVER_QUERY_FORM;
  179. cqp.pDlgProc = PropSheetDlgProc;
  180. cqp.lParam = (LPARAM)this;
  181. hr = THR( pAddPagesProc(lParam, CLSID_RISrvQueryForm, &cqp) );
  182. HRETURN(hr);
  183. }
  184. // ************************************************************************
  185. //
  186. // Property Sheet Functions
  187. //
  188. // ************************************************************************
  189. //
  190. // PropSheetDlgProc()
  191. //
  192. INT_PTR CALLBACK
  193. THISCLASS::PropSheetDlgProc(
  194. HWND hDlg,
  195. UINT uMsg,
  196. WPARAM wParam,
  197. LPARAM lParam )
  198. {
  199. //TraceMsg( L"PropSheetDlgProc(" );
  200. //TraceMsg( TF_FUNC, L" hDlg = 0x%p, uMsg = 0x%p, wParam = 0x%p, lParam = 0x%p )\n",
  201. // hDlg, uMsg, wParam, lParam );
  202. LPTHISCLASS pcc = (LPTHISCLASS) GetWindowLongPtr( hDlg, GWLP_USERDATA );
  203. if ( uMsg == WM_INITDIALOG )
  204. {
  205. TraceMsg( TF_WM, L"WM_INITDIALOG\n");
  206. CQPAGE * pcqp = (CQPAGE *) lParam;
  207. SetWindowLongPtr( hDlg, GWLP_USERDATA, pcqp->lParam );
  208. pcc = (LPTHISCLASS) pcqp->lParam;
  209. pcc->_InitDialog( hDlg, lParam );
  210. }
  211. if (pcc)
  212. {
  213. Assert( hDlg == pcc->_hDlg );
  214. switch ( uMsg )
  215. {
  216. case WM_HELP:// F1
  217. {
  218. LPHELPINFO phelp = (LPHELPINFO) lParam;
  219. WinHelp( (HWND) phelp->hItemHandle, g_cszHelpFile, HELP_WM_HELP, (DWORD_PTR) &aSrvQueryHelpMap );
  220. }
  221. break;
  222. case WM_CONTEXTMENU: // right mouse click
  223. WinHelp((HWND) wParam, g_cszHelpFile, HELP_CONTEXTMENU, (DWORD_PTR) &aSrvQueryHelpMap );
  224. break;
  225. }
  226. }
  227. return FALSE;
  228. }
  229. //
  230. // PropSheetPageProc()
  231. //
  232. HRESULT CALLBACK
  233. THISCLASS::PropSheetPageProc(
  234. LPCQPAGE pQueryPage,
  235. HWND hwnd,
  236. UINT uMsg,
  237. WPARAM wParam,
  238. LPARAM lParam)
  239. {
  240. TraceClsFunc( "PropSheetPageProc( " );
  241. TraceMsg( TF_FUNC, L"pQueryPage = 0x%p, hwnd = 0x%p, uMsg = 0x%p, wParam= 0x%p, lParam = 0x%p )\n",
  242. pQueryPage, hwnd, uMsg, wParam, lParam );
  243. HRESULT hr = E_NOTIMPL;
  244. Assert( pQueryPage );
  245. LPTHISCLASS pQueryForm = (LPTHISCLASS )pQueryPage->lParam;
  246. Assert( pQueryForm );
  247. switch ( uMsg )
  248. {
  249. // Initialize so AddRef the object we are associated with so that
  250. // we don't get unloaded.
  251. case CQPM_INITIALIZE:
  252. TraceMsg( TF_WM, "CQPM_INITIALIZE\n" );
  253. pQueryForm->AddRef();
  254. hr = S_OK;
  255. break;
  256. // Release, therefore Release the object we are associated with to
  257. // ensure correct destruction etc.
  258. case CQPM_RELEASE:
  259. TraceMsg( TF_WM, "CQPM_RELEASE\n" );
  260. SetWindowLongPtr( pQueryForm->_hDlg, GWLP_USERDATA, NULL );
  261. pQueryForm->Release();
  262. hr = S_OK;
  263. break;
  264. // Enable so fix the state of our two controls within the window.
  265. case CQPM_ENABLE:
  266. TraceMsg( TF_WM, "CQPM_ENABLE\n" );
  267. EnableWindow( GetDlgItem( hwnd, IDC_E_SERVER ), (BOOL)wParam );
  268. hr = S_OK;
  269. break;
  270. // Fill out the parameter structure to return to the caller, this is
  271. // handler specific. In our case we constructure a query of the CN
  272. // and objectClass properties, and we show a columns displaying both
  273. // of these. For further information about the DSQUERYPARAMs structure
  274. // see dsquery.h
  275. case CQPM_GETPARAMETERS:
  276. TraceMsg( TF_WM, "CQPM_GETPARAMETERS\n" );
  277. hr = pQueryForm->_GetQueryParams( hwnd, (LPDSQUERYPARAMS*)lParam );
  278. break;
  279. // Clear form, therefore set the window text for these two controls
  280. // to zero.
  281. case CQPM_CLEARFORM:
  282. TraceMsg( TF_WM, "CQPM_CLEARFORM\n" );
  283. SetDlgItemText( hwnd, IDC_E_SERVER, L"" );
  284. hr = S_OK;
  285. break;
  286. case CQPM_SETDEFAULTPARAMETERS:
  287. TraceMsg( TF_WM, "CQPM_SETDEFAULTPARAMETERS: wParam = %s lParam = 0x%p\n", BOOLTOSTRING(wParam), lParam );
  288. SetDlgItemText( hwnd, IDC_E_SERVER, L"*" );
  289. hr = S_OK;
  290. break;
  291. default:
  292. TraceMsg( TF_WM, "CQPM_message 0x%08x *** NOT IMPL ***\n", uMsg );
  293. hr = E_NOTIMPL;
  294. break;
  295. }
  296. RETURN(hr);
  297. }
  298. //
  299. // _OnPSPCB_Create( )
  300. //
  301. HRESULT
  302. THISCLASS::_OnPSPCB_Create( )
  303. {
  304. TraceClsFunc( "_OnPSPCB_Create( )\n" );
  305. HRETURN(S_OK);
  306. }
  307. //
  308. // _InitDialog( )
  309. //
  310. HRESULT
  311. THISCLASS::_InitDialog(
  312. HWND hDlg,
  313. LPARAM lParam )
  314. {
  315. TraceClsFunc( "_InitDialog( )\n" );
  316. _hDlg = hDlg;
  317. Edit_LimitText( GetDlgItem( _hDlg, IDC_E_SERVER), DNS_MAX_NAME_LENGTH );
  318. HRETURN(S_OK);
  319. }
  320. struct
  321. {
  322. INT fmt;
  323. INT cx;
  324. INT uID;
  325. PCWSTR pDisplayProperty;
  326. }
  327. srvcolumns[] =
  328. {
  329. 0, 20, IDS_NAME, L"cn",
  330. };
  331. //
  332. // _GetQueryParams( )
  333. //
  334. HRESULT
  335. THISCLASS::_GetQueryParams(
  336. HWND hWnd,
  337. LPDSQUERYPARAMS* ppdsqp )
  338. {
  339. TraceClsFunc( "_GetQueryParams( )\n" );
  340. if ( !ppdsqp )
  341. HRETURN(E_POINTER);
  342. HRESULT hr = S_OK;
  343. INT i;
  344. WCHAR szServer[DNS_MAX_NAME_BUFFER_LENGTH];
  345. WCHAR szFilter[ARRAYSIZE(FILTER_QUERY_SERVER)+ARRAYSIZE(szServer)];
  346. ULONG offset;
  347. BOOL CallerSpecifiedQuery;
  348. BOOL CallerQueryStartsWithAmpersand = FALSE;
  349. ULONG cbStruct = 0;
  350. LPDSQUERYPARAMS pDsQueryParams = NULL;
  351. #if 0
  352. if ( *ppdsqp )
  353. {
  354. // This page doesn't support appending its query data to an
  355. // existing DSQUERYPARAMS strucuture, only creating a new block,
  356. // therefore bail if we see the pointer is not NULL.
  357. hr = THR(E_INVALIDARG);
  358. goto Error;
  359. }
  360. #endif
  361. if (!GetDlgItemText( hWnd, IDC_E_SERVER, szServer, ARRAYSIZE(szServer))) {
  362. wcscpy( szServer, L"*");
  363. }
  364. if (_snwprintf(
  365. szFilter,
  366. ARRAYSIZE(szFilter),
  367. FILTER_QUERY_SERVER,
  368. szServer) < 0) {
  369. hr = THR(E_INVALIDARG);
  370. goto Error;
  371. }
  372. szFilter[ARRAYSIZE(szFilter) -1] = L'\0';
  373. DebugMsg( "RI Filter: %s\n", szFilter );
  374. // compute the size of the new query block
  375. // Did they hand in a query that we need to modify?
  376. if ( !*ppdsqp )
  377. {
  378. CallerSpecifiedQuery = FALSE;
  379. //bugbug arraysize(srvcolumns)-1) == 0?
  380. offset = cbStruct = sizeof(DSQUERYPARAMS) + ((ARRAYSIZE(srvcolumns)-1)*sizeof(DSCOLUMN));
  381. cbStruct += StringByteSize(szFilter);
  382. for ( i = 0; i < ARRAYSIZE(srvcolumns); i++ )
  383. {
  384. cbStruct += StringByteSize(srvcolumns[i].pDisplayProperty);
  385. }
  386. }
  387. else
  388. {
  389. CallerSpecifiedQuery = TRUE;
  390. LPWSTR pszQuery = (LPWSTR) ((LPBYTE)(*ppdsqp) + (*ppdsqp)->offsetQuery);
  391. offset = (*ppdsqp)->cbStruct;
  392. //
  393. // save off the size that we're gonna need.
  394. // note that when we concatenate the current query with our query,
  395. // we need to make sure the query starts with "(&". If it doesn't
  396. // already, then we make this the case -- the buffer szFilter contains
  397. // these bytes, which ensures that cbStruct is large enough. If the current
  398. // query contains these strings, then the allocated buffer is a little
  399. // bigger than it needs to be.
  400. cbStruct = (*ppdsqp)->cbStruct + StringByteSize( pszQuery ) + StringByteSize( szFilter );
  401. //
  402. // do some extra query validation.
  403. // does the query start with "(&"?
  404. //
  405. if (pszQuery[0] == L'(' && pszQuery[1] == L'&' ) {
  406. CallerQueryStartsWithAmpersand = TRUE;
  407. //
  408. // we're assuming below that if the specified query
  409. // doesn't start with "(&", that it will end with ")".
  410. // If that's not the case then bail out.
  411. //
  412. Assert( pszQuery[ wcslen( pszQuery ) - 1 ] == L')' );
  413. if (pszQuery[ wcslen( pszQuery ) - 1 ] != L')' ) {
  414. hr = E_INVALIDARG;
  415. goto Error;
  416. }
  417. } else {
  418. //
  419. // conversely, if the query doesn't start with '(&', then
  420. // we assume that the query doesn't end with ')', and if it
  421. // does, we bail
  422. //
  423. CallerQueryStartsWithAmpersand = FALSE;
  424. Assert( pszQuery[ wcslen( pszQuery ) - 1 ] != L')' );
  425. if (pszQuery[ wcslen( pszQuery ) - 1 ] == L')' ) {
  426. hr = E_INVALIDARG;
  427. goto Error;
  428. }
  429. }
  430. }
  431. // Allocate it and populate it with the data, the header is fixed
  432. // but the strings are referenced by offset.
  433. pDsQueryParams = (LPDSQUERYPARAMS)CoTaskMemAlloc(cbStruct);
  434. if ( !pDsQueryParams )
  435. {
  436. hr = E_OUTOFMEMORY;
  437. goto Error;
  438. }
  439. // Did they hand in a query that we need to modify?
  440. if ( !CallerSpecifiedQuery)
  441. { // no... create our own query
  442. pDsQueryParams->cbStruct = cbStruct;
  443. pDsQueryParams->dwFlags = 0;
  444. pDsQueryParams->hInstance = g_hInstance;
  445. pDsQueryParams->offsetQuery = offset;
  446. pDsQueryParams->iColumns = ARRAYSIZE(srvcolumns);
  447. // Copy the filter string and bump the offset
  448. StringByteCopy(pDsQueryParams, offset, szFilter);
  449. offset += StringByteSize(szFilter);
  450. // Fill in the array of columns to dispaly, the cx is a percentage of the
  451. // current view, the propertie names to display are UNICODE strings and
  452. // are referenced by offset, therefore we bump the offset as we copy
  453. // each one.
  454. for ( i = 0 ; i < ARRAYSIZE(srvcolumns); i++ )
  455. {
  456. pDsQueryParams->aColumns[i].fmt = srvcolumns[i].fmt;
  457. pDsQueryParams->aColumns[i].cx = srvcolumns[i].cx;
  458. pDsQueryParams->aColumns[i].idsName = srvcolumns[i].uID;
  459. pDsQueryParams->aColumns[i].offsetProperty = offset;
  460. StringByteCopy(pDsQueryParams, offset, srvcolumns[i].pDisplayProperty);
  461. offset += StringByteSize(srvcolumns[i].pDisplayProperty);
  462. }
  463. }
  464. else
  465. { // yes, caller specified a query... add our parameters to the query
  466. LPWSTR pszQuery;
  467. LPWSTR pszNewQuery;
  468. INT n;
  469. // duplicate the existing query
  470. Assert( offset == (*ppdsqp)->cbStruct );
  471. CopyMemory( pDsQueryParams, *ppdsqp, offset );
  472. pDsQueryParams->cbStruct = cbStruct;
  473. // new query location
  474. pDsQueryParams->offsetQuery = offset;
  475. pszQuery = (LPWSTR) ((LPBYTE)(*ppdsqp) + (*ppdsqp)->offsetQuery);
  476. pszNewQuery = (LPWSTR) ((LPBYTE)pDsQueryParams + offset);
  477. Assert( pszQuery );
  478. // append to their query
  479. if ( CallerQueryStartsWithAmpersand ) {
  480. //
  481. // remove ")" from current query so that we can
  482. // add in our additional filter. We've got the trailing ")" in our
  483. // filter.
  484. // Also note that we can't really fail at this point, and we're
  485. // about to free the caller's memory so it's ok for us to overwrite their
  486. // query text.
  487. //
  488. Assert( pszQuery[ wcslen( pszQuery ) - 1 ] == L')' );
  489. pszQuery[ wcslen( pszQuery ) - 1 ] = L'\0'; // remove ")"
  490. // start with their query
  491. wcscpy(pszNewQuery, pszQuery);
  492. //
  493. // put it back to be a good citizen ")"
  494. //
  495. pszQuery[ wcslen( pszQuery )] = L')';
  496. //
  497. // now tack on our query, skipping the "(&" part
  498. //
  499. wcscat(pszNewQuery,&szFilter[2]);
  500. } else {
  501. Assert( pszQuery[ wcslen( pszQuery ) - 1 ] != L')' );
  502. wcscpy( pszNewQuery, L"(&" ); // add "(&" to begining of query
  503. wcscat( pszNewQuery, pszQuery ); // add their query
  504. wcscat( pszNewQuery, &szFilter[2] ); // add our query starting after the "(&"
  505. }
  506. offset += StringByteSize( pszNewQuery ); // compute new offset
  507. DebugMsg( "New Query String: %s\n", pszNewQuery );
  508. // Cleanup
  509. CoTaskMemFree( *ppdsqp );
  510. }
  511. // Success
  512. *ppdsqp = pDsQueryParams;
  513. Assert( hr == S_OK );
  514. Cleanup:
  515. HRETURN(hr);
  516. Error:
  517. if ( pDsQueryParams )
  518. CoTaskMemFree( pDsQueryParams );
  519. // If we aren't modifying the query and there wasn't
  520. // a query handed into us, indicate failure instead.
  521. if ( hr == S_FALSE && !*ppdsqp )
  522. {
  523. Assert(FALSE); // how did we get here?
  524. hr = E_FAIL;
  525. }
  526. goto Cleanup;
  527. }