Source code of Windows XP (NT5)
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.

1226 lines
38 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996 - 1998
  5. //
  6. // File: crequest.cxx
  7. //
  8. // Contents: Client side of catalog/query requests
  9. //
  10. // Classes: CPipeClient
  11. // CRequestClient
  12. //
  13. // History: 16-Sep-96 dlee Created.
  14. //
  15. //--------------------------------------------------------------------------
  16. #include <pch.cxx>
  17. #pragma hdrstop
  18. #include <query.hxx>
  19. #include <cidbprop.hxx>
  20. #include <sizeser.hxx>
  21. #include <memser.hxx>
  22. DECLARE_INFOLEVEL(prx);
  23. //+-------------------------------------------------------------------------
  24. //
  25. // Member: CPipeClient::CPipeClient, protected
  26. //
  27. // Synopsis: Simple constructor
  28. //
  29. // History: 16-Sep-96 dlee Created.
  30. //
  31. //--------------------------------------------------------------------------
  32. CPipeClient::CPipeClient() : _hPipe( INVALID_HANDLE_VALUE )
  33. {
  34. } //CPipeClient
  35. //+-------------------------------------------------------------------------
  36. //
  37. // Member: CPipeClient::Init, protected
  38. //
  39. // Synopsis: Second phase constructor for a client pipe. The pipe is
  40. // opened or an exception is thrown. This method may take
  41. // awhile to complete depending on the availability of a pipe
  42. // instance on the server and on the timeout for the pipe as
  43. // set on the server.
  44. //
  45. // Arguments: [pwcMachine] - Name of the server or "." for local machine
  46. // [pwcPipe] - Name of the pipe
  47. //
  48. // History: 16-Sep-96 dlee Created.
  49. //
  50. //--------------------------------------------------------------------------
  51. void CPipeClient::Init(
  52. WCHAR const * pwcMachine,
  53. WCHAR const * pwcPipe )
  54. {
  55. #if CI_PIPE_TESTING
  56. _pTraceBefore = 0;
  57. _pTraceAfter = 0;
  58. _hTraceDll = LoadLibraryEx( L"cipipetrace.dll", 0,
  59. LOAD_WITH_ALTERED_SEARCH_PATH );
  60. if ( 0 != _hTraceDll )
  61. {
  62. _pTraceBefore = (PipeTraceBeforeCall)
  63. GetProcAddress( _hTraceDll, "Before" );
  64. _pTraceAfter = (PipeTraceAfterCall)
  65. GetProcAddress( _hTraceDll, "After" );
  66. }
  67. #endif // CI_PIPE_TESTING
  68. RtlZeroMemory( &_overlapped, sizeof _overlapped );
  69. RtlZeroMemory( &_overlappedWrite, sizeof _overlappedWrite );
  70. _fServerIsRemote = ( L'.' != pwcMachine[0] );
  71. WCHAR awcName[ MAX_PATH ];
  72. unsigned cwc = wcslen( pwcMachine );
  73. cwc += wcslen( pwcPipe );
  74. cwc += 20;
  75. if ( cwc >= ( sizeof awcName / sizeof WCHAR ) )
  76. THROW( CException( E_INVALIDARG ) );
  77. wcscpy( awcName, L"\\\\" );
  78. wcscat( awcName, pwcMachine );
  79. wcscat( awcName, L"\\pipe\\" );
  80. wcscat( awcName, pwcPipe );
  81. #if CIDBG == 1
  82. WCHAR awcThisUser[ UNLEN ];
  83. DWORD cbThisUser = sizeof awcThisUser / sizeof WCHAR;
  84. GetUserName( awcThisUser, &cbThisUser );
  85. prxDebugOut(( DEB_ITRACE,
  86. "connecting tid %d to pipe '%ws' as user '%ws'\n",
  87. GetCurrentThreadId(),
  88. awcName,
  89. awcThisUser ));
  90. #endif // CIDBG == 1
  91. do
  92. {
  93. // Timeout based on what the server specified if a pipe exists
  94. // but no instances are available. Throw if no pipe exists.
  95. if ( ! WaitNamedPipe( awcName, NMPWAIT_USE_DEFAULT_WAIT ) )
  96. QUIETTHROW( CException() );
  97. // At least one instance was available. This CreateFile will fail
  98. // if some other app grabbed the instance before we could. If so,
  99. // wait and try again.
  100. _hPipe = CreateFile( awcName,
  101. GENERIC_READ | GENERIC_WRITE,
  102. FILE_SHARE_READ | FILE_SHARE_WRITE,
  103. 0, // security
  104. OPEN_EXISTING,
  105. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
  106. 0 ); // template
  107. if ( INVALID_HANDLE_VALUE != _hPipe )
  108. {
  109. // Local client pipes are always created in byte mode, not
  110. // message mode, so set the mode to message.
  111. DWORD dwMode = PIPE_READMODE_MESSAGE | PIPE_WAIT;
  112. if ( ! SetNamedPipeHandleState( _hPipe, &dwMode, 0, 0 ) )
  113. {
  114. HRESULT hr = HRESULT_FROM_WIN32( GetLastError() );
  115. CloseHandle( _hPipe );
  116. _hPipe = INVALID_HANDLE_VALUE;
  117. THROW( CException( hr ) );
  118. }
  119. break;
  120. }
  121. else if ( ERROR_PIPE_BUSY != GetLastError() )
  122. {
  123. THROW( CException() );
  124. }
  125. } while ( TRUE );
  126. prxDebugOut(( DEB_ITRACE, "created pipe 0x%x\n", _hPipe ));
  127. } //Init
  128. //+-------------------------------------------------------------------------
  129. //
  130. // Member: CPipeClient::Close, protected
  131. //
  132. // Synopsis: Closes the pipe if it is open
  133. //
  134. // History: 16-Sep-96 dlee Created.
  135. //
  136. //--------------------------------------------------------------------------
  137. void CPipeClient::Close()
  138. {
  139. if ( INVALID_HANDLE_VALUE != _hPipe )
  140. {
  141. prxDebugOut(( DEB_ITRACE, "closing pipe: 0x%x\n", _hPipe ));
  142. BOOL fCloseOk = CloseHandle( _hPipe );
  143. Win4Assert( fCloseOk );
  144. _hPipe = INVALID_HANDLE_VALUE;
  145. }
  146. #if CI_PIPE_TESTING
  147. if ( 0 != _hTraceDll )
  148. {
  149. FreeLibrary( _hTraceDll );
  150. _hTraceDll = 0;
  151. }
  152. #endif // CI_PIPE_TESTING
  153. } //Close
  154. //+-------------------------------------------------------------------------
  155. //
  156. // Function: HandleClientWriteError
  157. //
  158. // Synopsis: Handles error case on pipe write commands
  159. //
  160. // Arguments: [hPipe] -- Pipe on which the operation failed
  161. //
  162. // Notes: When it looks like the connection has gone stale, throw
  163. // STATUS_CONNECTION_DISCONNECTED, so the caller knows to
  164. // open a new pipe to the server.
  165. //
  166. // History: 16-May-99 dlee Created.
  167. //
  168. //--------------------------------------------------------------------------
  169. void HandleClientWriteError( HANDLE hPipe )
  170. {
  171. //
  172. // This error state will happen for stale cached ICommands.
  173. // Alternatively, the handle will be set to INVALID_HANDLE_VALUE by
  174. // TerminateRudelyNoThrow(), and the pipe will no longer
  175. // be connected if cisvc went down.
  176. // Throw a well-known status so we can try to connect again.
  177. //
  178. DWORD dwError = GetLastError();
  179. if ( INVALID_HANDLE_VALUE == hPipe ||
  180. ERROR_PIPE_NOT_CONNECTED == dwError ||
  181. ERROR_BAD_PIPE == dwError ||
  182. ERROR_BAD_NET_RESP == dwError ) // rdr gives this sometimes
  183. THROW( CException( STATUS_CONNECTION_DISCONNECTED ) );
  184. THROW( CException() );
  185. } //HandleClientWriteError
  186. //+-------------------------------------------------------------------------
  187. //
  188. // Member: CPipeClient::TransactSync, protected
  189. //
  190. // Synopsis: Does a synchronous write/read transaction on the pipe.
  191. //
  192. // Arguments: [pvWrite] - Buffer to be written
  193. // [cbToWrite] - # of bytes to write
  194. // [pvRead] - Buffer for read result
  195. // [cbReadRequest] - Size of pvRead
  196. // [cbRead] - Returns # of bytes read
  197. //
  198. // History: 16-Sep-96 dlee Created.
  199. //
  200. //--------------------------------------------------------------------------
  201. void CPipeClient::TransactSync(
  202. void * pvWrite,
  203. DWORD cbToWrite,
  204. void * pvRead,
  205. DWORD cbReadRequest,
  206. DWORD & cbRead )
  207. {
  208. prxDebugOut(( DEB_ITRACE, "xact tid %d on pipe 0x%x\n",
  209. GetCurrentThreadId(),
  210. _hPipe ));
  211. //
  212. // Win32 named pipe operations require buffers < 64k. If you specify
  213. // a larger buffer it succeeds without a failure code, but the server
  214. // never sees the request. So do an explicit check here to validate
  215. // the buffer size.
  216. //
  217. if ( cbToWrite > 0xffff )
  218. THROW( CException( E_INVALIDARG ) );
  219. _overlapped.hEvent = _event.GetHandle();
  220. #if CI_PIPE_TESTING
  221. void * pvWriteOrg = pvWrite;
  222. DWORD cbToWriteOrg = cbToWrite;
  223. if ( 0 != _pTraceBefore )
  224. (*_pTraceBefore)( _hPipe,
  225. cbToWriteOrg,
  226. pvWriteOrg,
  227. cbToWrite,
  228. pvWrite );
  229. #endif // CI_PIPE_TESTING
  230. if ( ! TransactNamedPipe( _hPipe,
  231. pvWrite,
  232. cbToWrite,
  233. pvRead,
  234. cbReadRequest,
  235. &cbRead,
  236. &_overlapped ) )
  237. {
  238. if ( ERROR_IO_PENDING == GetLastError() )
  239. {
  240. if ( !GetOverlappedResult( _hPipe,
  241. &_overlapped,
  242. &cbRead,
  243. TRUE ) )
  244. HandleClientWriteError( _hPipe );
  245. }
  246. else
  247. HandleClientWriteError( _hPipe );
  248. }
  249. #if CI_PIPE_TESTING
  250. if ( 0 != _pTraceAfter )
  251. (*_pTraceAfter)( _hPipe,
  252. cbToWriteOrg,
  253. pvWriteOrg,
  254. cbToWrite,
  255. pvWrite,
  256. cbRead,
  257. pvRead );
  258. #endif // CI_PIPE_TESTING
  259. } //TransactSync
  260. //+-------------------------------------------------------------------------
  261. //
  262. // Member: CPipeClient::WriteSync, protected
  263. //
  264. // Synopsis: Does a synchronous write to the pipe.
  265. //
  266. // Arguments: [pvWrite] - Buffer to be written
  267. // [cbToWrite] - # of bytes to write
  268. //
  269. // Notes: When it looks like the connection has gone stale, throw
  270. // STATUS_CONNECTION_DISCONNECTED, so the caller knows to
  271. // open a new pipe to the server,.
  272. //
  273. // History: 16-Sep-96 dlee Created.
  274. //
  275. //--------------------------------------------------------------------------
  276. void CPipeClient::WriteSync(
  277. void * pvWrite,
  278. DWORD cbToWrite )
  279. {
  280. prxDebugOut(( DEB_ITRACE, "writesync tid %d on pipe 0x%x\n",
  281. GetCurrentThreadId(),
  282. _hPipe ));
  283. //
  284. // Win32 named pipe operations require buffers < 64k. If you specify
  285. // a larger buffer it succeeds without a failure code, but the server
  286. // never sees the request. So do an explicit check here to validate
  287. // the buffer size.
  288. //
  289. if ( cbToWrite > 0xffff )
  290. THROW( CException( E_INVALIDARG ) );
  291. _overlappedWrite.hEvent = _eventWrite.GetHandle();
  292. DWORD cbWritten;
  293. if ( ! WriteFile( _hPipe,
  294. pvWrite,
  295. cbToWrite,
  296. &cbWritten,
  297. &_overlappedWrite ) )
  298. {
  299. if ( ERROR_IO_PENDING == GetLastError() )
  300. {
  301. if ( !GetOverlappedResult( _hPipe,
  302. &_overlappedWrite,
  303. &cbWritten,
  304. TRUE ) )
  305. HandleClientWriteError( _hPipe );
  306. }
  307. else
  308. HandleClientWriteError( _hPipe );
  309. }
  310. } //WriteSync
  311. //+-------------------------------------------------------------------------
  312. //
  313. // Member: CPipeClient::ReadSync, protected
  314. //
  315. // Synopsis: Does a synchronous from the pipe.
  316. //
  317. // Arguments: [pvRead] - Buffer for read result
  318. // [cbReadRequest] - Size of pvRead
  319. // [cbRead] - Returns # of bytes read
  320. //
  321. // History: 16-Sep-96 dlee Created.
  322. //
  323. //--------------------------------------------------------------------------
  324. void CPipeClient::ReadSync(
  325. void * pvRead,
  326. DWORD cbToRead,
  327. DWORD & cbRead )
  328. {
  329. prxDebugOut(( DEB_ITRACE, "readsync 1 tid %d on pipe 0x%x\n",
  330. GetCurrentThreadId(),
  331. _hPipe ));
  332. _overlapped.hEvent = _event.GetHandle();
  333. if ( ! ReadFile( _hPipe,
  334. pvRead,
  335. cbToRead,
  336. &cbRead,
  337. &_overlapped ) )
  338. {
  339. if ( ERROR_IO_PENDING == GetLastError() )
  340. {
  341. if ( !GetOverlappedResult( _hPipe,
  342. &_overlapped,
  343. &cbRead,
  344. TRUE ) )
  345. {
  346. // If this assert hits, you probably added large notify msg
  347. Win4Assert( ERROR_MORE_DATA != GetLastError() );
  348. THROW( CException() );
  349. }
  350. }
  351. else
  352. THROW( CException() );
  353. }
  354. } //ReadSync
  355. //+-------------------------------------------------------------------------
  356. //
  357. // Member: CPipeClient::ReadSync, protected
  358. //
  359. // Synopsis: Does a synchronous read from the pipe, aborting the read
  360. // if hEvent is signalled before the read is started or
  361. // completed.
  362. //
  363. // Arguments: [pvRead] - Buffer for read result
  364. // [cbReadRequest] - Size of pvRead
  365. // [cbRead] - Returns # of bytes read
  366. // [hEvent] - When signalled, the read is aborted
  367. //
  368. // Returns: TRUE if hEvent has been triggered
  369. //
  370. // History: 16-Sep-96 dlee Created.
  371. //
  372. //--------------------------------------------------------------------------
  373. BOOL CPipeClient::ReadSync(
  374. void * pvRead,
  375. DWORD cbToRead,
  376. DWORD & cbRead,
  377. HANDLE hEvent )
  378. {
  379. cbRead = 0;
  380. // Since the read below can complete without going pending,
  381. // check the terminate event here first.
  382. if ( 0 == WaitForSingleObject( hEvent, 0 ) )
  383. return TRUE;
  384. prxDebugOut(( DEB_ITRACE, "readsync 2 tid %d on pipe 0x%x\n",
  385. GetCurrentThreadId(),
  386. _hPipe ));
  387. _overlapped.hEvent = _event.GetHandle();
  388. if ( ! ReadFile( _hPipe,
  389. pvRead,
  390. cbToRead,
  391. &cbRead,
  392. &_overlapped ) )
  393. {
  394. if ( ERROR_IO_PENDING == GetLastError() )
  395. {
  396. HANDLE ah[2];
  397. ah[0] = _event.GetHandle();
  398. ah[1] = hEvent;
  399. DWORD dw = WaitForMultipleObjects( 2, ah, FALSE, INFINITE );
  400. Win4Assert( 0 == dw || 1 == dw );
  401. if ( 0 == dw )
  402. {
  403. if ( !GetOverlappedResult( _hPipe,
  404. &_overlapped,
  405. &cbRead,
  406. FALSE ) )
  407. THROW( CException() );
  408. }
  409. else if ( 1 == dw )
  410. {
  411. prxDebugOut(( DEB_ITRACE,
  412. "notify thread told to die, cancel i/o\n" ));
  413. // Cancel the io so that it won't complete on buffers that
  414. // have been freed. No check can be made of the return code
  415. // since the pipe may have been closed by now on the server.
  416. BOOL fOK = CancelIo( _hPipe );
  417. prxDebugOut(( DEB_ITRACE, "CancelIo: %d\n", fOK ));
  418. if ( !fOK ) {
  419. prxDebugOut(( DEB_ITRACE, "CancelIo error: %d\n",
  420. GetLastError() ));
  421. }
  422. if ( !GetOverlappedResult( _hPipe,
  423. &_overlapped,
  424. &cbRead,
  425. TRUE ) )
  426. {
  427. cbRead = 0;
  428. DWORD dw = GetLastError();
  429. prxDebugOut(( DEB_ITRACE,
  430. "i/o cancelled, result: %d\n", dw ));
  431. // benign assert if hit; I'm is just curious.
  432. Win4Assert( ERROR_OPERATION_ABORTED == dw ||
  433. ERROR_NO_DATA == dw );
  434. }
  435. return TRUE;
  436. }
  437. else THROW( CException() );
  438. }
  439. else THROW( CException() );
  440. }
  441. return FALSE;
  442. } //ReadSync
  443. //+-------------------------------------------------------------------------
  444. //
  445. // Function: TranslateNewPropsToOldProps
  446. //
  447. // Synopsis: Translates v 6+ client properties into version 5 props
  448. //
  449. // Arguments: [oldProps] - destination of translated values
  450. // [newProps] - source of translated values
  451. //
  452. // History: 31-May-97 dlee Created.
  453. //
  454. //--------------------------------------------------------------------------
  455. void TranslateNewPropsToOldProps(
  456. CDbProperties & oldProps,
  457. CDbProperties & newProps )
  458. {
  459. const GUID guidFsClientPropset = DBPROPSET_FSCIFRMWRK_EXT;
  460. const GUID guidQueryCorePropset = DBPROPSET_CIFRMWRKCORE_EXT;
  461. // pluck out the catalog and scope information from the new set
  462. BSTR bstrMachine = 0;
  463. BSTR bstrCatalog = 0;
  464. CDynArrayInPlace<LONG> aDepths(2);
  465. CDynArrayInPlace<BSTR> aScopes(2);
  466. LONG lQueryType = 0;
  467. for ( ULONG i = 0; i < newProps.Count(); i++ )
  468. {
  469. CDbPropSet & propSet = newProps.GetPropSet( i );
  470. DBPROPSET *pSet = propSet.CastToStruct();
  471. if ( guidQueryCorePropset == pSet->guidPropertySet )
  472. {
  473. ULONG cProp = pSet->cProperties;
  474. DBPROP * pProp = pSet->rgProperties;
  475. for ( ULONG p = 0; p < pSet->cProperties; p++, pProp++ )
  476. {
  477. VARIANT &v = pProp->vValue;
  478. switch ( pProp->dwPropertyID )
  479. {
  480. case DBPROP_MACHINE :
  481. {
  482. if ( VT_BSTR == v.vt )
  483. bstrMachine = v.bstrVal;
  484. else if ( ( VT_ARRAY | VT_BSTR ) == v.vt )
  485. {
  486. ULONG cElem = v.parray->rgsabound[0].cElements;
  487. WCHAR **ppMachines = (WCHAR **) v.parray->pvData;
  488. if ( 0 != cElem )
  489. {
  490. // if not 1, it's a bug in higher level code
  491. Win4Assert( 1 == cElem );
  492. bstrMachine = ppMachines[0];
  493. }
  494. }
  495. break;
  496. }
  497. }
  498. }
  499. }
  500. else if ( guidFsClientPropset == pSet->guidPropertySet )
  501. {
  502. ULONG cProp = pSet->cProperties;
  503. DBPROP * pProp = pSet->rgProperties;
  504. for ( ULONG p = 0; p < pSet->cProperties; p++, pProp++ )
  505. {
  506. VARIANT &v = pProp->vValue;
  507. prxDebugOut(( DEB_ITRACE, "converting from vt: 0x%x\n", v.vt ));
  508. switch ( pProp->dwPropertyID )
  509. {
  510. case DBPROP_CI_INCLUDE_SCOPES :
  511. {
  512. // can be either a BSTR or a safearray of BSTRs
  513. if ( VT_BSTR == v.vt )
  514. {
  515. aScopes[0] = v.bstrVal;
  516. }
  517. else if ( ( VT_ARRAY | VT_BSTR ) == v.vt )
  518. {
  519. ULONG cElem = v.parray->rgsabound[0].cElements;
  520. WCHAR **ppScopes = (WCHAR **) v.parray->pvData;
  521. for ( ULONG e = 0; e < cElem; e++ )
  522. aScopes[ e ] = ppScopes[ e ];
  523. }
  524. break;
  525. }
  526. case DBPROP_CI_DEPTHS :
  527. {
  528. // can be either an I4 or an array of I4s
  529. if ( VT_I4 == v.vt )
  530. {
  531. aDepths[0] = v.lVal;
  532. }
  533. else if ( ( VT_ARRAY | VT_I4 ) == v.vt )
  534. {
  535. ULONG cElem = v.parray->rgsabound[0].cElements;
  536. ULONG *pElem = (ULONG *) v.parray->pvData;
  537. for ( ULONG e = 0; e < cElem; e++ )
  538. aDepths[ e ] = pElem[ e ];
  539. }
  540. break;
  541. }
  542. case DBPROP_CI_CATALOG_NAME :
  543. {
  544. if ( VT_BSTR == v.vt )
  545. bstrCatalog = v.bstrVal;
  546. else if ( ( VT_ARRAY | VT_BSTR ) == v.vt )
  547. {
  548. ULONG cElem = v.parray->rgsabound[0].cElements;
  549. WCHAR **ppNames = (WCHAR **) v.parray->pvData;
  550. if ( 0 != cElem )
  551. {
  552. // if not 1, it's a bug in higher level code
  553. Win4Assert( 1 == cElem );
  554. bstrCatalog = ppNames[0];
  555. }
  556. }
  557. break;
  558. }
  559. case DBPROP_CI_QUERY_TYPE :
  560. {
  561. Win4Assert( VT_I4 == v.vt );
  562. lQueryType = v.lVal;
  563. break;
  564. }
  565. }
  566. }
  567. }
  568. }
  569. if ( 0 == bstrCatalog ||
  570. 0 == bstrMachine )
  571. THROW( CException( STATUS_INVALID_PARAMETER ) );
  572. prxDebugOut(( DEB_ITRACE,
  573. "Converting new props to old props, catalog '%ws'\n",
  574. bstrCatalog ));
  575. prxDebugOut(( DEB_ITRACE,
  576. "type %d, %d scopes, %d depths\n",
  577. lQueryType,
  578. aScopes.Count(),
  579. aDepths.Count() ));
  580. // create an old set of properties based on the info
  581. DBPROPSET aNewSet[2];
  582. DBPROP aFSProps[4];
  583. RtlZeroMemory( aFSProps, sizeof aFSProps );
  584. ULONG cNewSet = 2;
  585. aNewSet[0].cProperties = 2;
  586. aNewSet[0].guidPropertySet = guidFsClientPropset;
  587. aNewSet[0].rgProperties = aFSProps;
  588. aFSProps[0].dwPropertyID = DBPROP_CI_CATALOG_NAME;
  589. aFSProps[0].vValue.vt = VT_LPWSTR;
  590. aFSProps[0].vValue.bstrVal = bstrCatalog;
  591. aFSProps[0].colid.eKind = DBKIND_GUID_PROPID;
  592. aFSProps[1].dwPropertyID = DBPROP_CI_QUERY_TYPE;
  593. aFSProps[1].vValue.vt = VT_I4;
  594. aFSProps[1].vValue.lVal = lQueryType;
  595. aFSProps[1].colid.eKind = DBKIND_GUID_PROPID;
  596. if ( 0 != aDepths.Count() )
  597. {
  598. aFSProps[cNewSet].dwPropertyID = DBPROP_CI_DEPTHS;
  599. aFSProps[cNewSet].colid.eKind = DBKIND_GUID_PROPID;
  600. PROPVARIANT &vDepths = (PROPVARIANT &) aFSProps[cNewSet].vValue;
  601. cNewSet++;
  602. vDepths.vt = VT_VECTOR | VT_I4;
  603. vDepths.cal.cElems = aDepths.Count();
  604. vDepths.cal.pElems = (LONG *) aDepths.GetPointer();
  605. }
  606. if ( 0 != aScopes.Count() )
  607. {
  608. aFSProps[cNewSet].dwPropertyID = DBPROP_CI_INCLUDE_SCOPES;
  609. aFSProps[cNewSet].colid.eKind = DBKIND_GUID_PROPID;
  610. PROPVARIANT &vScopes = (PROPVARIANT &) aFSProps[cNewSet].vValue;
  611. cNewSet++;
  612. vScopes.vt = VT_VECTOR | VT_LPWSTR;
  613. vScopes.calpwstr.cElems = aScopes.Count();
  614. vScopes.calpwstr.pElems = (WCHAR **) aScopes.GetPointer();
  615. }
  616. aNewSet[0].cProperties = cNewSet;
  617. DBPROP aQueryProps[1];
  618. RtlZeroMemory( aQueryProps, sizeof aQueryProps );
  619. aNewSet[1].cProperties = 1;
  620. aNewSet[1].guidPropertySet = guidQueryCorePropset;
  621. aNewSet[1].rgProperties = aQueryProps;
  622. aQueryProps[0].dwPropertyID = DBPROP_MACHINE;
  623. aQueryProps[0].vValue.vt = VT_BSTR;
  624. aQueryProps[0].vValue.bstrVal = bstrMachine;
  625. aQueryProps[0].colid.eKind = DBKIND_GUID_PROPID;
  626. SCODE sc = oldProps.SetProperties( 2, aNewSet );
  627. if ( FAILED( sc ) )
  628. THROW( CException( sc ) );
  629. } //TranslateNewPropsToOldProps
  630. //+-------------------------------------------------------------------------
  631. //
  632. // Member: CRequestClient::CRequestClient, public
  633. //
  634. // Synopsis: Constructor for a client request
  635. //
  636. // Arguments: [pwcMachine] - Machine name of server
  637. // [pDbProperties] - Client version 6 set of properties
  638. //
  639. // History: 16-Sep-96 dlee Created.
  640. //
  641. //--------------------------------------------------------------------------
  642. CRequestClient::CRequestClient(
  643. WCHAR const * pwcMachine,
  644. IDBProperties * pDbProperties ) :
  645. _fNotifyOn( FALSE ),
  646. _fNotifyEverOn( FALSE ),
  647. _fReadPending( FALSE ),
  648. _pvDataTemp( 0 ),
  649. _cbDataTemp( 0 )
  650. {
  651. WCHAR const * pwcMach = pwcMachine;
  652. WCHAR const * pwcPipe = CI_PIPE_NAME;
  653. WCHAR awcMachine[ MAX_PATH + 1 ];
  654. WCHAR const * pwcColon = wcschr( pwcMachine, L':' );
  655. if ( 0 != pwcColon )
  656. {
  657. unsigned cwc = (unsigned) ( pwcColon - pwcMachine );
  658. if ( cwc >= MAX_PATH )
  659. THROW( CException( E_INVALIDARG ) );
  660. RtlCopyMemory( awcMachine, pwcMachine, sizeof( WCHAR ) * cwc );
  661. awcMachine[ cwc ] = 0;
  662. pwcMach = awcMachine;
  663. pwcPipe = pwcColon + 1;
  664. }
  665. Init( pwcMach, pwcPipe );
  666. // Send the pmConnect message to the server. For logging and
  667. // debugging, send the machine and username with the message.
  668. WCHAR awcThisMachine[ MAX_COMPUTERNAME_LENGTH + 1 ];
  669. DWORD cwcThisMachine = sizeof awcThisMachine / sizeof WCHAR;
  670. if ( !GetComputerName( awcThisMachine, &cwcThisMachine ) )
  671. THROW( CException() );
  672. WCHAR awcThisUser[ UNLEN + 1 ];
  673. DWORD cwcThisUser = sizeof awcThisUser / sizeof WCHAR;
  674. if ( !GetUserName( awcThisUser, &cwcThisUser ) )
  675. THROW( CException() );
  676. Win4Assert( 0 != pDbProperties );
  677. //
  678. // We know that the IDbProperties is implemented by CDbProperties.
  679. //
  680. CDbProperties & dbp2 = *((CDbProperties *) pDbProperties);
  681. // Make and marshall v5 properties
  682. XInterface<CDbProperties> xdbp( new CDbProperties() );
  683. if ( xdbp.IsNull() )
  684. THROW( CException( E_OUTOFMEMORY ) );
  685. TranslateNewPropsToOldProps( xdbp.GetReference(), dbp2 );
  686. CSizeSerStream ssSize;
  687. xdbp->Marshall( ssSize );
  688. ULONG cbProps = ssSize.Size();
  689. //
  690. // Compute the size of the dbproperties to be sent.
  691. // The DBPROPSET_ROWSET properties aren't used on the server side in
  692. // this form -- it's a waste to marshall/unmarshall 0x27 properties
  693. // for no good reason. The rowset props we care about are sent in
  694. // a compressed form when a query is issued.
  695. //
  696. CSizeSerStream ssSize2;
  697. GUID guidRowsetProp = DBPROPSET_ROWSET;
  698. dbp2.Marshall( ssSize2, 1, &guidRowsetProp );
  699. ULONG cbProps2 = ssSize2.Size();
  700. prxDebugOut(( DEB_ITRACE, "cb old props %d, cb new props: %d\n",
  701. cbProps, cbProps2 ));
  702. DWORD cbRequest = CPMConnectIn::SizeOf( awcThisMachine,
  703. awcThisUser,
  704. cbProps,
  705. cbProps2 );
  706. XArray<BYTE> xRequest( cbRequest );
  707. CPMConnectIn *pRequest = new( xRequest.Get() )
  708. CPMConnectIn( awcThisMachine,
  709. awcThisUser,
  710. IsServerRemote(),
  711. cbProps,
  712. cbProps2 );
  713. //
  714. // Serialize the DbProperties.
  715. //
  716. BYTE * pb = pRequest->GetBlobStartAddr();
  717. CMemSerStream ss( pb, cbProps );
  718. xdbp->Marshall( ss );
  719. BYTE * pb2 = pRequest->GetBlob2StartAddr();
  720. CMemSerStream ss2( pb2, cbProps2 );
  721. dbp2.Marshall( ss2, 1, &guidRowsetProp );
  722. pRequest->SetCheckSum( cbRequest );
  723. CPMConnectOut reply;
  724. DWORD cbReply;
  725. DataWriteRead( pRequest,
  726. cbRequest,
  727. &reply,
  728. sizeof reply,
  729. cbReply );
  730. Win4Assert( sizeof reply == cbReply );
  731. _ServerVersion = reply.ServerVersion();
  732. } //CRequestClient
  733. //+-------------------------------------------------------------------------
  734. //
  735. // Member: CRequestClient::Disconnect, public
  736. //
  737. // Synopsis: Sends a disconnect message to the server, which will then
  738. // do a Win32 disconnect from the pipe. After this call, the
  739. // pipe handle can only be closed.
  740. //
  741. // History: 16-Sep-96 dlee Created.
  742. //
  743. //--------------------------------------------------------------------------
  744. void CRequestClient::Disconnect()
  745. {
  746. CProxyMessage request( pmDisconnect );
  747. DataWrite( &request, sizeof request );
  748. } //Disconnect
  749. //+-------------------------------------------------------------------------
  750. //
  751. // Member: CRequestClient::EnableNotify, public
  752. //
  753. // Synopsis: Tells the class that the notify thread will be doing reads
  754. // for data threads.
  755. //
  756. // History: 16-Sep-96 dlee Created.
  757. //
  758. //--------------------------------------------------------------------------
  759. void CRequestClient::EnableNotify()
  760. {
  761. CLock lock( _mutex );
  762. prxDebugOut(( DEB_ITRACE, "enable notify\n" ));
  763. Win4Assert( !_fNotifyOn );
  764. _fNotifyOn = TRUE;
  765. _fNotifyEverOn = TRUE;
  766. prxDebugOut(( DEB_ITRACE, "enabled notify\n" ));
  767. } //EnableNotify
  768. //+-------------------------------------------------------------------------
  769. //
  770. // Member: CRequestClient::DisableNotify, public
  771. //
  772. // Synopsis: Tells the class that the notify thread is busy so
  773. // data threads should wait for themselves.
  774. //
  775. // History: 16-Sep-96 dlee Created.
  776. //
  777. //--------------------------------------------------------------------------
  778. void CRequestClient::DisableNotify()
  779. {
  780. CReleasableLock lock( _mutex );
  781. prxDebugOut(( DEB_ITRACE, "disable notify\n" ));
  782. Win4Assert( _fNotifyOn );
  783. // If a read is pending for the notify thread to complete,
  784. // wake the data thread up so it can wait for itself.
  785. _fNotifyOn = FALSE;
  786. if ( _fReadPending )
  787. {
  788. _pvDataTemp = 0;
  789. _eventData.Set();
  790. lock.Release();
  791. _eventDataDone.Wait();
  792. }
  793. prxDebugOut(( DEB_ITRACE, "disabled notify\n" ));
  794. } //DisableNotify
  795. //+-------------------------------------------------------------------------
  796. //
  797. // Member: CRequestClient::DataWrite, public
  798. //
  799. // Synopsis: Writes data to the pipe
  800. //
  801. // Arguments: [pvWrite] - pointer to the buffer to be written
  802. // [cbWrite] - # of bytes to write
  803. //
  804. // History: 16-Sep-96 dlee Created.
  805. //
  806. //--------------------------------------------------------------------------
  807. void CRequestClient::DataWrite(
  808. void * pvWrite,
  809. DWORD cbWrite )
  810. {
  811. CLock lockData( _mutexData );
  812. CLock lock( _mutex );
  813. WriteSync( pvWrite, cbWrite );
  814. } //DataWrite
  815. //+-------------------------------------------------------------------------
  816. //
  817. // Member: CRequestClient::DataWriteRead, public
  818. //
  819. // Synopsis: Does a data (non-notification) write/read transaction with
  820. // the server.
  821. //
  822. // Arguments: [pvWrite] - Buffer to be written
  823. // [cbToWrite] - # of bytes to write
  824. // [pvRead] - Buffer for read result
  825. // [cbReadRequest] - Size of pvRead
  826. // [cbRead] - Returns # of bytes read
  827. //
  828. // History: 16-Sep-96 dlee Created.
  829. //
  830. //--------------------------------------------------------------------------
  831. void CRequestClient::DataWriteRead(
  832. void * pvWrite,
  833. DWORD cbWrite,
  834. void * pvRead,
  835. DWORD cbToRead,
  836. DWORD & cbRead )
  837. {
  838. int ExpectedMsg = ((CProxyMessage *)pvWrite)->GetMessage();
  839. prxDebugOut(( DEB_ITRACE, "DataWriteRead msg %d, cb %d\n",
  840. ExpectedMsg, cbWrite ));
  841. CLock lockData( _mutexData );
  842. CReleasableLock lock( _mutex );
  843. if ( _fNotifyOn )
  844. {
  845. WriteSync( pvWrite, cbWrite );
  846. _fReadPending = TRUE;
  847. lock.Release();
  848. _eventData.Wait();
  849. _fReadPending = FALSE;
  850. prxDebugOut(( DEB_ITRACE,
  851. "dwr eventdata triggered, _pvDataTemp: 0x%lx\n",
  852. _pvDataTemp ));
  853. // set this event when we fall out of scope
  854. CEventSetter setter( _eventDataDone );
  855. if ( 0 == _pvDataTemp )
  856. {
  857. // we can wait ourselves
  858. lock.Request();
  859. ReadSync( pvRead, cbToRead, cbRead );
  860. prxDebugOut(( DEB_ITRACE, "dwr done, this, cb: %d\n", cbRead ));
  861. }
  862. else
  863. {
  864. // notify thread completed the read for us
  865. Win4Assert( _cbDataTemp <= cbToRead );
  866. RtlCopyMemory( pvRead, _pvDataTemp, _cbDataTemp );
  867. cbRead = _cbDataTemp;
  868. prxDebugOut(( DEB_ITRACE, "dwr done, other, cb: %d\n", cbRead ));
  869. }
  870. }
  871. else
  872. {
  873. if ( _fNotifyEverOn )
  874. {
  875. // Spurious notify messages prohibit use of TransactSync. Use
  876. // an individual Write, then Read until the appropriate msg is
  877. // found, throwing away unwanted notification messages.
  878. WriteSync( pvWrite, cbWrite );
  879. do
  880. {
  881. // Some notification messages are larger than what we might
  882. // be reading here, so we may need to use a temporary buffer.
  883. void * pvReadBuffer = pvRead;
  884. DWORD cbReadBuffer = cbToRead;
  885. // CPMRatioFinishedOut is the largest notification msg.
  886. // Change this code if you add a larger notification message.
  887. Win4Assert( sizeof CPMRatioFinishedOut >=
  888. sizeof CPMSendNotifyOut );
  889. CPMRatioFinishedOut pmTmp;
  890. if ( cbToRead < sizeof pmTmp )
  891. {
  892. pvReadBuffer = &pmTmp;
  893. cbReadBuffer = sizeof pmTmp;
  894. }
  895. ReadSync( pvReadBuffer, cbReadBuffer, cbRead );
  896. int msg = ((CProxyMessage *) pvReadBuffer)->GetMessage();
  897. prxDebugOut(( DEB_ITRACE, "dwr done, msg %d cb: %d\n",
  898. msg, cbRead ));
  899. if ( ExpectedMsg == msg )
  900. {
  901. // Copy from the temporary buffer if it was used.
  902. if ( pvReadBuffer != pvRead )
  903. {
  904. // Normal case and error case...
  905. Win4Assert( cbToRead <= cbRead ||
  906. sizeof CProxyMessage == cbRead );
  907. RtlCopyMemory( pvRead, pvReadBuffer, cbRead );
  908. }
  909. break;
  910. }
  911. prxDebugOut(( DEB_WARN,
  912. "dwr tossing spurious notify msg %d cb: %d\n",
  913. msg, cbRead ));
  914. } while ( TRUE );
  915. }
  916. else
  917. {
  918. TransactSync( pvWrite, cbWrite, pvRead, cbToRead, cbRead );
  919. }
  920. }
  921. CProxyMessage &reply = * (CProxyMessage *) pvRead;
  922. // If the message returned a failure code, throw it.
  923. if ( ! SUCCEEDED( reply.GetStatus() ) )
  924. QUIETTHROW( CException( reply.GetStatus() ) );
  925. } //DataWriteRead
  926. //+-------------------------------------------------------------------------
  927. //
  928. // Member: CRequestClient::NotifyWriteRead, public
  929. //
  930. // Synopsis: Does a notification (non-data) write/read transaction with
  931. // the server. If the read is a message destined for another'
  932. // thread, notify the thread that data is available and wait
  933. // for another message.
  934. //
  935. // Arguments: [hStopNotify] - if signalled, read is cancelled
  936. // [pvWrite] - Buffer to be written
  937. // [cbWrite] - # of bytes to write
  938. // [pvRead] - Buffer for read result
  939. // [cbBuffer] - Size of pvRead
  940. // [cbRead] - Returns # of bytes read
  941. //
  942. // Returns: TRUE if hStopNotify was signalled, FALSE otherwise
  943. //
  944. // Notes: This function knows about pmGetNotify and pmSendNotify
  945. //
  946. // History: 16-Sep-96 dlee Created.
  947. //
  948. //--------------------------------------------------------------------------
  949. BOOL CRequestClient::NotifyWriteRead(
  950. HANDLE hStopNotify,
  951. void * pvWrite,
  952. DWORD cbWrite,
  953. void * pvRead,
  954. DWORD cbBuffer,
  955. DWORD & cbRead )
  956. {
  957. // First check if we are shutting down the query
  958. if ( 0 == WaitForSingleObject( hStopNotify, 0 ) )
  959. return TRUE;
  960. // ensure notifications are disabled by the time we exit scope
  961. Win4Assert( !_fNotifyOn );
  962. CEnableNotify enable( *this );
  963. Win4Assert( _fNotifyOn );
  964. // If a pmGetNotify is sent and the reply is pmGetNotify, it means that
  965. // notifications aren't available yet and a pmSendNotify will come later.
  966. // If a pmSendNotify is replied, notifications were available.
  967. int ExpectedMsg = ((CProxyMessage *)pvWrite)->GetMessage();
  968. if ( pmGetNotify == ExpectedMsg )
  969. ExpectedMsg = pmSendNotify;
  970. {
  971. CLock lock( _mutex );
  972. WriteSync( pvWrite, cbWrite );
  973. }
  974. do
  975. {
  976. BYTE abBuf[ cbMaxProxyBuffer ];
  977. cbRead = 0;
  978. BOOL fStopNotify = ReadSync( abBuf,
  979. sizeof abBuf,
  980. cbRead,
  981. hStopNotify );
  982. // If we got any data, process the data even if "stop notify" is
  983. // true, since we don't want to leave the data thread stranded.
  984. if ( 0 != cbRead )
  985. {
  986. CProxyMessage &msg = * (CProxyMessage *) abBuf;
  987. prxDebugOut(( DEB_ITRACE,
  988. "NotifyWriteRead complete cb %d, msg %d\n",
  989. cbRead,
  990. msg.GetMessage() ));
  991. // If the pmGetNotify came back, loop around and wait for
  992. // a real notification or a message intended for a data thread.
  993. if ( pmGetNotify == msg.GetMessage() )
  994. {
  995. if ( ! SUCCEEDED( msg.GetStatus() ) )
  996. THROW( CException( msg.GetStatus() ) );
  997. }
  998. else
  999. {
  1000. // If this is a notification, return so the client can be
  1001. // advised, then this function will be re-entered.
  1002. if ( msg.GetMessage() == ExpectedMsg )
  1003. {
  1004. CProxyMessage &reply = * (CProxyMessage *) pvRead;
  1005. if ( ! SUCCEEDED( msg.GetStatus() ) )
  1006. THROW( CException( msg.GetStatus() ) );
  1007. Win4Assert( cbRead <= cbBuffer );
  1008. RtlCopyMemory( pvRead, abBuf, cbRead );
  1009. return fStopNotify;
  1010. }
  1011. // Tell the thread waiting for data that it's available.
  1012. // That thread can throw if the status is failure.
  1013. _pvDataTemp = abBuf;
  1014. _cbDataTemp = cbRead;
  1015. _eventData.Set();
  1016. _eventDataDone.Wait();
  1017. }
  1018. }
  1019. if ( fStopNotify )
  1020. return TRUE;
  1021. } while ( TRUE );
  1022. return FALSE;
  1023. } //NotifyWriteRead