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.

2005 lines
62 KiB

  1. //+--------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1997
  5. //
  6. // File: pipes.cxx
  7. //
  8. // History:
  9. // RichN 10/30/97 Created.
  10. //
  11. //---------------------------------------------------------------------------
  12. #include <ole2int.h>
  13. #include "pipes.hxx"
  14. /////////////////////////////////////////////////////////////////////////////
  15. // Externals
  16. EXTERN_C HRESULT PrxDllGetClassObject(REFCLSID clsid, REFIID iid, void **ppv);
  17. //////////////////////////////////////////////////////////////////////////////
  18. // Constants
  19. const DWORD WAIT_INFINITE = DWORD(-1);
  20. const ULONG FRAGMENT_SIZE = 1300;
  21. typedef struct
  22. {
  23. const char *key;
  24. const char *value;
  25. } RegistryKeyValue;
  26. const RegistryKeyValue REG_CONST_KEY[] =
  27. {
  28. "CLSID\\{0000032E-0000-0000-C000-000000000046}", "PipePSFactory",
  29. "CLSID\\{0000032E-0000-0000-C000-000000000046}\\InprocServer32", "ole32.dll",
  30. "Interface\\{DB2F3ACA-2F86-11d1-8E04-00C04FB9989A}", "IPipeByte",
  31. "Interface\\{DB2F3ACA-2F86-11d1-8E04-00C04FB9989A}\\ProxyStubClsid32", "{0000032E-0000-0000-C000-000000000046}",
  32. "Interface\\{DB2F3ACC-2F86-11d1-8E04-00C04FB9989A}", "IPipeLong",
  33. "Interface\\{DB2F3ACC-2F86-11d1-8E04-00C04FB9989A}\\ProxyStubClsid32", "{0000032E-0000-0000-C000-000000000046}",
  34. "Interface\\{DB2F3ACE-2F86-11d1-8E04-00C04FB9989A}", "IPipeDouble",
  35. "Interface\\{DB2F3ACE-2F86-11d1-8E04-00C04FB9989A}\\ProxyStubClsid32", "{0000032E-0000-0000-C000-000000000046}",
  36. // Indicates end of list.
  37. "", ""
  38. };
  39. /////////////////////////////////////////////////////////////////////////////
  40. // Macros
  41. inline ULONG MIN( ULONG a, ULONG b )
  42. {
  43. return a < b ? a : b;
  44. }
  45. inline ULONG MAX( ULONG a, ULONG b )
  46. {
  47. return a < b ? b : a;
  48. }
  49. inline HRESULT MAKE_WIN32( HRESULT status )
  50. {
  51. return MAKE_SCODE( SEVERITY_ERROR, FACILITY_WIN32, status );
  52. }
  53. inline HRESULT FIX_WIN32( HRESULT result )
  54. {
  55. if ((ULONG) result > 0xfffffff7 || (ULONG) result < 0x2000)
  56. return MAKE_WIN32( result );
  57. else
  58. return result;
  59. }
  60. /////////////////////////////////////////////////////////////////////////////
  61. // Globals
  62. #define DISABLEASYNC 0
  63. /////////////////////////////////////////////////////////////////////////////
  64. // Prototypes
  65. //+**************************************************************************
  66. // FixUpPipeRegistry(void)
  67. //
  68. // Description: Modifies the registry to have the pipe interface point
  69. // to a different class ID for the PSFactory. Adds to the
  70. // registry the new ID for the PipePSFactory.
  71. //
  72. // History:
  73. // Date: Time: Developer: Action:
  74. // 12/3/97 10:14:48 AM RichN Created.
  75. //
  76. // Notes: We do not change the async interfaces. They should still
  77. // be handled by ole32 directly. Only modify the synchronous varity.
  78. //
  79. //-**************************************************************************
  80. HRESULT FixUpPipeRegistry(void)
  81. {
  82. HRESULT result = ERROR_SUCCESS;
  83. // Create the Pipe interfaces and add the clsid for the PipePSFactory.
  84. for (int i = 0; (REG_CONST_KEY[i].key[0] != '\0') && result == ERROR_SUCCESS; i++)
  85. {
  86. // Use Ascii so it works on Win95.
  87. result = RegSetValueA(
  88. HKEY_CLASSES_ROOT,
  89. REG_CONST_KEY[i].key,
  90. REG_SZ,
  91. REG_CONST_KEY[i].value,
  92. (DWORD) strlen(REG_CONST_KEY[i].value) );
  93. }
  94. if( result != ERROR_SUCCESS )
  95. return FIX_WIN32( result );
  96. return S_OK;
  97. }
  98. //+**************************************************************************
  99. // ProxyDllGetClassObject(REFCLSID clsid, REFIID iid, void **ppv)
  100. //
  101. // Description: Creates a proxy. Trys PrxDllGetClassObject first since that
  102. // is the most likely. If not, then sees if it is the pipe
  103. // proxy being created.
  104. //
  105. // History:
  106. // Date: Time: Developer: Action:
  107. // 10/30/97 11:43:55 AM RichN Created.
  108. //
  109. // Notes:
  110. //
  111. //-**************************************************************************
  112. EXTERN_C HRESULT ProxyDllGetClassObject(REFCLSID clsid, REFIID riid, void **ppv)
  113. {
  114. ComDebOut(( DEB_MARSHAL, "ProxyDllGetClassObject, clsid: %l, riid: %l \n",
  115. clsid, riid));
  116. HRESULT hr = PrxDllGetClassObject(clsid, riid, ppv);
  117. if( FAILED(hr) )
  118. {
  119. // Not a well known one, maybe it is the pipe factory.
  120. if( clsid == CLSID_PipePSFactory )
  121. {
  122. // Create the pipe proxy/stub class factory
  123. CPipePSFactory *pPipePSFactory = new CPipePSFactory();
  124. if( NULL != pPipePSFactory )
  125. {
  126. // Get the interface Requested.
  127. hr = pPipePSFactory->QueryInterface(riid, ppv);
  128. pPipePSFactory->Release();
  129. }
  130. else
  131. {
  132. *ppv = NULL;
  133. hr = E_OUTOFMEMORY;
  134. }
  135. }
  136. }
  137. return hr;
  138. }
  139. //+**************************************************************************
  140. // CPipePSFactory()
  141. //
  142. // Description: CTOR
  143. //
  144. // History:
  145. // Date: Time: Developer: Action:
  146. // 10/30/97 12:55:55 PM RichN Created.
  147. //
  148. // Notes:
  149. //
  150. //-**************************************************************************
  151. CPipePSFactory::CPipePSFactory() :
  152. m_cRef(1)
  153. {
  154. ComDebOut(( DEB_MARSHAL, "CPipePSFactory - ctor, this:%x \n", this));
  155. }
  156. //+**************************************************************************
  157. // CPipePSFactory()
  158. //
  159. // Description: DTOR
  160. //
  161. // History:
  162. // Date: Time: Developer: Action:
  163. // 10/30/97 12:56:19 PM RichN Created.
  164. //
  165. // Notes:
  166. //
  167. //-**************************************************************************
  168. CPipePSFactory::~CPipePSFactory()
  169. {
  170. ComDebOut(( DEB_MARSHAL, "CPipePSFactory - dtor, this:%x \n"));
  171. }
  172. //+**************************************************************************
  173. // QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
  174. //
  175. // Description: Standard QI
  176. //
  177. // History:
  178. // Date: Time: Developer: Action:
  179. // 10/30/97 11:10:58 AM RichN Created.
  180. //
  181. // Notes:
  182. //
  183. //-**************************************************************************
  184. STDMETHODIMP CPipePSFactory::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
  185. {
  186. ComDebOut(( DEB_MARSHAL, "CPipePSFactory::QueryInterface, this:%x, riid:%i \n",
  187. this, riid));
  188. if (IsEqualIID(riid, IID_IUnknown) ||
  189. IsEqualIID(riid, IID_IPSFactoryBuffer) )
  190. {
  191. *ppvObj = (IPSFactoryBuffer *) this;
  192. }
  193. else
  194. {
  195. *ppvObj = NULL;
  196. return E_NOINTERFACE;
  197. }
  198. ((IUnknown *)*ppvObj)->AddRef();
  199. return S_OK;
  200. }
  201. //+**************************************************************************
  202. // CPipePSFactory::AddRef()
  203. //
  204. // Description: Standard AddRef
  205. //
  206. // History:
  207. // Date: Time: Developer: Action:
  208. // 10/30/97 11:11:16 AM RichN Created.
  209. //
  210. // Notes:
  211. //
  212. //-**************************************************************************
  213. STDMETHODIMP_(ULONG) CPipePSFactory::AddRef()
  214. {
  215. ComDebOut(( DEB_MARSHAL, "CPipePSFactory::AddRef, this:%x, m_cRef:%d \n",
  216. this, m_cRef + 1));
  217. return InterlockedIncrement( &m_cRef );
  218. }
  219. //+**************************************************************************
  220. // CPipePSFactory::Release()
  221. //
  222. // Description: Standard Release
  223. //
  224. // History:
  225. // Date: Time: Developer: Action:
  226. // 10/30/97 11:11:31 AM RichN Created.
  227. //
  228. // Notes:
  229. //
  230. //-**************************************************************************
  231. STDMETHODIMP_(ULONG) CPipePSFactory::Release()
  232. {
  233. ComDebOut(( DEB_MARSHAL, "CPipePSFactory::Release, this:%x, m_cRef:%d \n",
  234. this, m_cRef - 1));
  235. ULONG lRef;
  236. if( (lRef = InterlockedDecrement( &m_cRef )) == 0)
  237. {
  238. delete this;
  239. return 0;
  240. }
  241. return lRef;
  242. }
  243. //+**************************************************************************
  244. // CreateProxy
  245. //
  246. // Description: Creates a pipe proxy.
  247. //
  248. // History:
  249. // Date: Time: Developer: Action:
  250. // 10/30/97 11:11:45 AM RichN Created.
  251. //
  252. // Notes: We will pass back to the call a ptr to our object and we will
  253. // hold a pointer to the real proxy. When the client calls us, we
  254. // can do whatever we want/need to do and then call the real proxy.
  255. //
  256. //-**************************************************************************
  257. STDMETHODIMP CPipePSFactory::CreateProxy( IUnknown *pUnkOuter,
  258. REFIID riid,
  259. IRpcProxyBuffer **ppProxy,
  260. void **ppv )
  261. {
  262. ComDebOut(( DEB_MARSHAL, "CreateProxy, pUnkOuter:%x riid:%I \n",
  263. pUnkOuter, riid));
  264. if( NULL == ppv || NULL == ppProxy )
  265. return E_INVALIDARG;
  266. *ppProxy = NULL;
  267. *ppv = NULL;
  268. IPSFactoryBuffer *pPSFactory;
  269. // Create the real PSFactory for the pipe interface.
  270. HRESULT hr = PrxDllGetClassObject( riid,
  271. IID_IPSFactoryBuffer,
  272. (void **) &pPSFactory);
  273. IUnknown *pNDRPipeProxy = NULL;
  274. IRpcProxyBuffer *pInternalProxyBuffer = NULL;
  275. if( SUCCEEDED(hr) )
  276. {
  277. // Create the real proxy.
  278. hr = pPSFactory->CreateProxy( pUnkOuter,
  279. riid,
  280. &pInternalProxyBuffer,
  281. (void **)&pNDRPipeProxy);
  282. pPSFactory->Release();
  283. }
  284. if( FAILED(hr) )
  285. return hr;
  286. if( IID_IPipeByte == riid )
  287. {
  288. *ppv = new CPipeProxy<BYTE,
  289. &IID_IPipeByte,
  290. &IID_AsyncIPipeByte,
  291. IPipeByte,
  292. AsyncIPipeByte>
  293. (pUnkOuter, pNDRPipeProxy);
  294. }
  295. else if( IID_IPipeLong == riid )
  296. {
  297. *ppv = new CPipeProxy<LONG,
  298. &IID_IPipeLong,
  299. &IID_AsyncIPipeLong,
  300. IPipeLong,
  301. AsyncIPipeLong>
  302. (pUnkOuter, pNDRPipeProxy);
  303. }
  304. else if( IID_IPipeDouble == riid )
  305. {
  306. *ppv = new CPipeProxy<DOUBLE,
  307. &IID_IPipeDouble,
  308. &IID_AsyncIPipeDouble,
  309. IPipeDouble,
  310. AsyncIPipeDouble>
  311. (pUnkOuter, pNDRPipeProxy);
  312. }
  313. else
  314. {
  315. hr = E_NOINTERFACE;
  316. }
  317. if( SUCCEEDED(hr) && NULL == *ppv)
  318. hr = E_OUTOFMEMORY;
  319. // Create the object that contains the IRpcProxyBuffer
  320. // and the pipe interface. Created with refcount of 1.
  321. if( SUCCEEDED(hr) )
  322. {
  323. CPipeProxyImp *pProxyImp = new CPipeProxyImp(pUnkOuter,
  324. pInternalProxyBuffer,
  325. pNDRPipeProxy,
  326. (IUnknown*) *ppv,
  327. riid);
  328. if( NULL == pProxyImp )
  329. {
  330. hr = E_OUTOFMEMORY;
  331. }
  332. else
  333. *ppProxy = (IRpcProxyBuffer *) pProxyImp;
  334. }
  335. // Clean up failure.
  336. if( FAILED(hr) )
  337. {
  338. if( NULL != *ppv )
  339. {
  340. delete *ppv;
  341. *ppv = NULL;
  342. }
  343. pNDRPipeProxy->Release();
  344. pInternalProxyBuffer->Release();
  345. }
  346. return hr;
  347. }
  348. //+**************************************************************************
  349. // CreateStub
  350. //
  351. // Description: Creates a pipe stub.
  352. //
  353. // History:
  354. // Date: Time: Developer: Action:
  355. // 10/30/97 11:12:46 AM RichN Created.
  356. //
  357. // Notes:
  358. //
  359. //-**************************************************************************
  360. STDMETHODIMP CPipePSFactory::CreateStub( REFIID riid,
  361. IUnknown *pUnkServer,
  362. IRpcStubBuffer **ppStub )
  363. {
  364. ComDebOut(( DEB_MARSHAL, "CreateStub, riid:%x pUnkServer:%x \n",
  365. riid, pUnkServer ));
  366. HRESULT hr = S_OK;
  367. IPSFactoryBuffer *pPSFactory;
  368. // Create the real PSFactory for the pipe interface.
  369. hr = PrxDllGetClassObject( riid,
  370. IID_IPSFactoryBuffer,
  371. (void **) &pPSFactory);
  372. // Call real factory to get stub.
  373. if( SUCCEEDED(hr) )
  374. {
  375. hr = pPSFactory->CreateStub(riid, pUnkServer, ppStub);
  376. pPSFactory->Release();
  377. }
  378. return hr;
  379. }
  380. //+**************************************************************************
  381. // CPipePoxyImp(IRpcProxyBuffer *pInternalPB, IUnknown *pPipe)
  382. //
  383. // Description: CTOR
  384. //
  385. // History:
  386. // Date: Time: Developer: Action:
  387. // 11/11/97 11:31:43 AM RichN Created.
  388. //
  389. // Notes:
  390. //
  391. //-**************************************************************************
  392. CPipeProxyImp::CPipeProxyImp(IUnknown *pUnkOuter,
  393. IRpcProxyBuffer *pInternalPB,
  394. IUnknown *pRealPipeProxy,
  395. IUnknown *pInternalPipeProxy,
  396. IID iid) :
  397. m_cRef (1),
  398. m_pInternalPipeProxy(pInternalPipeProxy),
  399. m_pInternalPB (pInternalPB),
  400. m_pRealPipeProxy (pRealPipeProxy),
  401. m_pUnkOuter (pUnkOuter),
  402. m_IidOfPipe (iid)
  403. {
  404. ComDebOut(( DEB_MARSHAL, "CPipeProxyImp ctor, this:%x \n"));
  405. Win4Assert(NULL != m_pInternalPB);
  406. Win4Assert(NULL != m_pRealPipeProxy);
  407. Win4Assert(NULL != m_pInternalPipeProxy);
  408. }
  409. //+**************************************************************************
  410. // CPipeProxyImp()
  411. //
  412. // Description: DTOR
  413. //
  414. // History:
  415. // Date: Time: Developer: Action:
  416. // 11/11/97 11:32:02 AM RichN Created.
  417. //
  418. // Notes:
  419. //
  420. //-**************************************************************************
  421. CPipeProxyImp::~CPipeProxyImp()
  422. {
  423. ComDebOut(( DEB_MARSHAL, "~CPipeProxyImp, this:%x \n", this));
  424. // AddRef the outer because we are aggregated.
  425. m_pUnkOuter->AddRef();
  426. // Delete the internal proxy.
  427. if( NULL != m_pInternalPipeProxy )
  428. {
  429. delete m_pInternalPipeProxy;
  430. m_pInternalPipeProxy = NULL;
  431. }
  432. // Release the real proxy.
  433. if( NULL != m_pRealPipeProxy )
  434. {
  435. m_pRealPipeProxy->Release();
  436. m_pRealPipeProxy = NULL;
  437. }
  438. // Release the pointer to the IRpcProxyBuffer
  439. if( NULL != m_pInternalPB )
  440. m_pInternalPB->Release();
  441. }
  442. //+**************************************************************************
  443. // QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
  444. //
  445. // Description: QI
  446. //
  447. // History:
  448. // Date: Time: Developer: Action:
  449. // 11/11/97 11:36:15 AM RichN Created.
  450. //
  451. // Notes:
  452. //
  453. //-**************************************************************************
  454. STDMETHODIMP CPipeProxyImp::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
  455. {
  456. ComDebOut(( DEB_MARSHAL, "QueryInterface, this:%x \n", this));
  457. HRESULT hr = S_OK;
  458. if( NULL == ppvObj )
  459. return E_INVALIDARG;
  460. if (IsEqualIID(riid, IID_IUnknown) ||
  461. IsEqualIID(riid, IID_IRpcProxyBuffer) )
  462. {
  463. *ppvObj = (IUnknown *) this;
  464. }
  465. else if( IsEqualIID(riid, m_IidOfPipe) )
  466. {
  467. *ppvObj = m_pInternalPipeProxy;
  468. }
  469. else
  470. {
  471. return m_pInternalPB->QueryInterface(riid, ppvObj);
  472. }
  473. ((IUnknown *)(*ppvObj))->AddRef();
  474. return hr;
  475. }
  476. //+**************************************************************************
  477. // CPipeProxyImp::AddRef()
  478. //
  479. // Description: AddRef
  480. //
  481. // History:
  482. // Date: Time: Developer: Action:
  483. // 11/11/97 11:36:34 AM RichN Created.
  484. //
  485. // Notes:
  486. //
  487. //-**************************************************************************
  488. STDMETHODIMP_(ULONG) CPipeProxyImp::AddRef()
  489. {
  490. return InterlockedIncrement( &m_cRef );
  491. }
  492. //+**************************************************************************
  493. // CPipeProxyImp::Release()
  494. //
  495. // Description:
  496. //
  497. // History:
  498. // Date: Time: Developer: Action:
  499. // 11/11/97 11:36:48 AM RichN Created.
  500. //
  501. // Notes:
  502. //
  503. //-**************************************************************************
  504. STDMETHODIMP_(ULONG) CPipeProxyImp::Release()
  505. {
  506. ULONG lRef;
  507. if( (lRef = InterlockedDecrement( &m_cRef )) == 0)
  508. {
  509. delete this;
  510. return 0;
  511. }
  512. return lRef;
  513. }
  514. //+**************************************************************************
  515. // Connect(IRpcChannelBuffer *pRpcChannelBuffer)
  516. //
  517. // Description: Simple pass through.
  518. //
  519. // History:
  520. // Date: Time: Developer: Action:
  521. // 11/11/97 11:36:59 AM RichN Created.
  522. //
  523. // Notes:
  524. //
  525. //-**************************************************************************
  526. STDMETHODIMP CPipeProxyImp::Connect(IRpcChannelBuffer *pRpcChannelBuffer)
  527. {
  528. return m_pInternalPB->Connect(pRpcChannelBuffer);
  529. }
  530. //+**************************************************************************
  531. // Disconnect( void )
  532. //
  533. // Description: Simple pass through.
  534. //
  535. // History:
  536. // Date: Time: Developer: Action:
  537. // 11/11/97 11:37:25 AM RichN Created.
  538. //
  539. // Notes:
  540. //
  541. //-**************************************************************************
  542. STDMETHODIMP_(void) CPipeProxyImp::Disconnect( void )
  543. {
  544. m_pInternalPB->Disconnect();
  545. }
  546. template<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
  547. //+**************************************************************************
  548. // CPipeProxy( void * pProxy ):
  549. //
  550. // Description:CTOR
  551. //
  552. // History:
  553. // Date: Time: Developer: Action:
  554. // 11/11/97 11:43:00 AM RichN Created.
  555. //
  556. // Notes:
  557. //
  558. //-**************************************************************************
  559. CPipeProxy<T, ID, AsyncID, I, AsyncI>
  560. ::CPipeProxy(IUnknown *pUnkOuter, void * pProxy ):
  561. m_cFreeSpace (0), m_cKeepBufferSize (0),
  562. m_cKeepDataSize (0), m_cLastRead (0),
  563. m_cPushBufferSize (0), m_cReadAhead (0),
  564. m_cRef (0), m_pAsyncPullPipe (NULL),
  565. m_pAsyncPushPipe (NULL), m_pFreeSpace (NULL),
  566. m_pISyncPull (NULL), m_pISyncPush (NULL),
  567. m_pKeepBuffer (NULL), m_pKeepData (NULL),
  568. m_pRealProxy ((I *)pProxy), m_pUnkOuter (pUnkOuter),
  569. m_pPushBuffer (NULL), m_PullState (PULLSTATE0_ENTRY),
  570. m_PushState (PUSHSTATE0_ENTRY)
  571. {
  572. ComDebOut(( DEB_MARSHAL, "CPipeProxy, pUnkOuter:%x pProxy:%x p \n",
  573. pUnkOuter, pProxy));
  574. Win4Assert(NULL != m_pUnkOuter);
  575. Win4Assert(NULL != m_pRealProxy);
  576. // Fill in the array of functions for the pull states.
  577. PullStateFunc[0] = NULL; // Should never execute in state zero.
  578. PullStateFunc[1] = NbNaRgtRA1; // No Buffer, No async outstanding, Request > Read ahead
  579. PullStateFunc[2] = NbaRltRA2; // No Buffer, async call outstanding, Request < Read Ahead
  580. PullStateFunc[3] = NbaRgtRA3; // No Buffer, async, Req >= Read ahead
  581. PullStateFunc[4] = baRltB4; // Buffer, async, Request < Buffer size
  582. PullStateFunc[5] = baRgtB5; // Buffer, async, Request >= Buffer size
  583. PullStateFunc[6] = PullDone6; // done.
  584. // Fill in the array of functions for the push states.
  585. PushStateFunc[0] = NULL; // Should never execute in state zero.
  586. PushStateFunc[1] = NbNf1; // No Buffer, No free buffer space
  587. PushStateFunc[2] = bfPgtF2; // Buffer, free space in buffer, push size >= free size
  588. PushStateFunc[3] = bfPltF3; // Buffer, free, push < free
  589. PushStateFunc[4] = bPSz4; // Buffer, push size zero
  590. PushStateFunc[5] = PushDone5; // Done
  591. #if DBG==1
  592. for(int i = 1; i < MAX_PULL_STATES; i++)
  593. Win4Assert(PullStateFunc[i] != NULL);
  594. for(i = 1; i < MAX_PUSH_STATES; i++)
  595. Win4Assert(PushStateFunc[i] != NULL);
  596. #endif
  597. return;
  598. }
  599. template<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
  600. //+**************************************************************************
  601. // CPipeProxy( void )
  602. //
  603. // Description: DTOR
  604. //
  605. // History:
  606. // Date: Time: Developer: Action:
  607. // 11/11/97 11:43:20 AM RichN Created.
  608. //
  609. // Notes: Addref the outer unknown and then release the pointer to the
  610. // real proxy.
  611. //
  612. //-**************************************************************************
  613. CPipeProxy<T, ID, AsyncID, I, AsyncI>
  614. ::~CPipeProxy( void )
  615. {
  616. Win4Assert(NULL != m_pUnkOuter);
  617. Win4Assert(NULL != m_pRealProxy);
  618. }
  619. //+**************************************************************************
  620. // QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
  621. //
  622. // Description: IUnknown implementation. All delegate to outer unknown.
  623. //
  624. // History:
  625. // Date: Time: Developer: Action:
  626. // 11/11/97 11:48:42 AM RichN Created.
  627. //
  628. // Notes:
  629. //
  630. //-**************************************************************************
  631. template<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
  632. STDMETHODIMP CPipeProxy<T, ID, AsyncID, I, AsyncI>
  633. ::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
  634. {
  635. return m_pUnkOuter->QueryInterface(riid, ppvObj);
  636. }
  637. template<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
  638. STDMETHODIMP_(ULONG) CPipeProxy<T, ID, AsyncID, I, AsyncI>
  639. ::AddRef()
  640. {
  641. m_cRef++;
  642. return m_pUnkOuter->AddRef();
  643. }
  644. template<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
  645. STDMETHODIMP_(ULONG) CPipeProxy<T, ID, AsyncID, I, AsyncI>
  646. ::Release()
  647. {
  648. m_cRef--;
  649. return m_pUnkOuter->Release();
  650. }
  651. template<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
  652. //+**************************************************************************
  653. // Pull( T *Buf, ULONG Request, ULONG *Received)
  654. //
  655. // Description: Pull the data from the server.
  656. //
  657. // History:
  658. // Date: Time: Developer: Action:
  659. // 11/11/97 11:49:18 AM RichN Created.
  660. //
  661. // Notes: We read data ahead by using async calls. The size of the
  662. // read ahead can be controled by the user by implementing
  663. // the IPipeHueristic and setting it on the interface.
  664. //
  665. //-**************************************************************************
  666. STDMETHODIMP CPipeProxy<T, ID, AsyncID, I, AsyncI>
  667. ::Pull( T *Buf, ULONG Request, ULONG *Received)
  668. {
  669. ComDebOut(( DEB_MARSHAL, "Pull, this:%x, Buf:%x, Request:%d, Received:%x \n",
  670. this, Buf, Request, Received));
  671. if( 0 == Request )
  672. return E_UNEXPECTED;
  673. HRESULT hr;
  674. // For debugging it is sometimes useful to disable
  675. // the async read ahead.
  676. #if DISABLEASYNC==1
  677. hr = m_pRealProxy->Pull(Buf, Request, Received);
  678. return hr;
  679. #endif
  680. *Received = 0;
  681. // Transition to the next state.
  682. hr = PullStateTransition( Request );
  683. // Should never see state 0.
  684. Win4Assert(0 != m_PullState);
  685. // Call the function for the new state.
  686. if( SUCCEEDED(hr) )
  687. {
  688. hr = (this->*(PullStateFunc[m_PullState]))( Buf, Request, Received );
  689. }
  690. return hr;
  691. }
  692. template<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
  693. //+**************************************************************************
  694. // Push( T *Buf, ULONG count)
  695. //
  696. // Description: Pushes data to the server.
  697. //
  698. // History:
  699. // Date: Time: Developer: Action:
  700. // 11/11/97 11:49:39 AM RichN Created.
  701. //
  702. // Notes:
  703. //
  704. //-**************************************************************************
  705. STDMETHODIMP CPipeProxy<T, ID, AsyncID, I, AsyncI>
  706. ::Push( T *Buf, ULONG Count)
  707. {
  708. ComDebOut(( DEB_MARSHAL, "Push, this:%x, Buf:%x, Count:%u \n",
  709. this, Buf, Count));
  710. HRESULT hr;
  711. // For debugging it is sometimes useful to disable
  712. // write behind.
  713. #if DISABLEASYNC==1
  714. hr = m_pRealProxy->Push(Buf, Count);
  715. return hr;
  716. #endif
  717. // Transition to the next state.
  718. hr = PushStateTransition( Count );
  719. // Should never see state 0.
  720. Win4Assert(0 != m_PushState);
  721. // Call the function for the new state.
  722. if( SUCCEEDED(hr) )
  723. {
  724. hr = (this->*(PushStateFunc[m_PushState]))( Buf, Count );
  725. }
  726. return hr;
  727. }
  728. template<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
  729. //+**************************************************************************
  730. // InitAsync(void)
  731. //
  732. // Description: Initializes, gets, the pointers to the async parts.
  733. //
  734. // History:
  735. // Date: Time: Developer: Action:
  736. // 12/8/97 4:45:22 PM RichN Created.
  737. //
  738. // Notes:
  739. //
  740. //-**************************************************************************
  741. HRESULT CPipeProxy<T, ID, AsyncID, I, AsyncI>
  742. ::InitAsync(IUnknown** ppCallObj,
  743. AsyncI** ppAsyncPipe,
  744. ISynchronize** ppISync)
  745. {
  746. ComDebOut(( DEB_MARSHAL, "InitAsync, this:%x \n", this));
  747. Win4Assert(NULL != m_pRealProxy);
  748. Win4Assert(NULL == (*ppAsyncPipe));
  749. Win4Assert(NULL == (*ppISync));
  750. HRESULT hr;
  751. ICallFactory *pCF = NULL;
  752. hr = m_pRealProxy->QueryInterface(IID_ICallFactory, (void **) &pCF);
  753. if( FAILED(hr) )
  754. return hr;
  755. hr = pCF->CreateCall(*AsyncID, NULL, IID_IUnknown, ppCallObj);
  756. pCF->Release();
  757. if( FAILED(hr) )
  758. return hr;
  759. hr = (*ppCallObj)->QueryInterface(*AsyncID, (void **) ppAsyncPipe);
  760. if( FAILED(hr) )
  761. goto ErrorCallObj;
  762. hr = (*ppCallObj)->QueryInterface(IID_ISynchronize, (void **) ppISync);
  763. if( FAILED(hr) )
  764. goto ErrorAsyncPipe;
  765. return S_OK;
  766. ErrorAsyncPipe:
  767. (*ppAsyncPipe)->Release();
  768. (*ppAsyncPipe) = NULL;
  769. ErrorCallObj:
  770. (*ppCallObj)->Release();
  771. (*ppCallObj) = NULL;
  772. return hr;
  773. }
  774. template<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
  775. //+**************************************************************************
  776. // CleanupProxy(IUnknown* pCallObj, IUnknown* pAsyncPipe, ISynchronize* pISync)
  777. //
  778. // Description: Cleans up all the async interfaces acquired.
  779. //
  780. // History:
  781. // Date: Time: Developer: Action:
  782. // 12/16/97 11:42:42 AM RichN Created.
  783. //
  784. // Notes:
  785. //
  786. //-**************************************************************************
  787. void CPipeProxy<T, ID, AsyncID, I, AsyncI>
  788. ::CleanupProxy(T ** ppBuffer,
  789. IUnknown** ppCallObj,
  790. AsyncI** ppAsyncPipe,
  791. ISynchronize** ppISync)
  792. {
  793. if( *ppBuffer )
  794. {
  795. delete (*ppBuffer);
  796. (*ppBuffer) = NULL;
  797. }
  798. if( NULL != (*ppISync) )
  799. {
  800. (*ppISync)->Release();
  801. *ppISync = NULL;
  802. }
  803. if( NULL != (*ppAsyncPipe) )
  804. {
  805. (*ppAsyncPipe)->Release();
  806. *ppAsyncPipe = NULL;
  807. }
  808. if( NULL != (*ppCallObj) )
  809. {
  810. (*ppCallObj)->Release();
  811. *ppCallObj = NULL;
  812. }
  813. }
  814. template<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
  815. //+**************************************************************************
  816. // CancelTheCall(DWORD delay)
  817. //
  818. // Description: Cancel the currently outstanding call.
  819. //
  820. // History:
  821. // Date: Time: Developer: Action:
  822. // 12/9/97 10:59:54 AM RichN Created.
  823. //
  824. // Notes:
  825. //
  826. //-**************************************************************************
  827. void CPipeProxy<T, ID, AsyncID, I, AsyncI>
  828. ::CancelTheCall(IUnknown *pCallObj, DWORD delay)
  829. {
  830. ComDebOut(( DEB_MARSHAL, "CancelTheCall, this:%x \n", this));
  831. ICancelMethodCalls *pICancel;
  832. HRESULT hr = pCallObj->QueryInterface(IID_ICancelMethodCalls,
  833. (void **) &pICancel);
  834. if( FAILED(hr) )
  835. return;
  836. pICancel->Cancel(delay);
  837. pICancel->Release();
  838. return;
  839. }
  840. template<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
  841. //+**************************************************************************
  842. // SetReadAhead(ULONG Request)
  843. //
  844. // Description: Determine the size of the read ahead.
  845. //
  846. // History:
  847. // Date: Time: Developer: Action:
  848. // 11/20/97 10:01:10 AM RichN Created.
  849. //
  850. // Notes:
  851. //
  852. //-**************************************************************************
  853. void CPipeProxy<T, ID, AsyncID, I, AsyncI>
  854. ::SetReadAhead(ULONG Request)
  855. {
  856. ComDebOut(( DEB_MARSHAL, "SetReadAhead, this:%x Request:%u \n", this, Request));
  857. Win4Assert(Request != 0);
  858. switch(m_PullState)
  859. {
  860. case PULLSTATE1_FIRST_CALL :
  861. // On the first call just set the read ahead to the request.
  862. // This assumes that the request will be constant and
  863. // we will be one call ahead all the time.
  864. m_cReadAhead = Request;
  865. break;
  866. case PULLSTATE2_NS_RQlsRA :
  867. // We haven't had a zero read or we wouldn't be here
  868. Win4Assert(m_cLastRead != 0);
  869. // Set the read ahead to the lesser of the request and the
  870. // amount last read. We are trying to match the read ahead with
  871. // the request by assuming a constant request, but the server
  872. // may only return a given amount regardless of what we
  873. // request.
  874. m_cReadAhead = MIN(Request, m_cLastRead);
  875. break;
  876. case PULLSTATE3_NS_RQgeRA :
  877. case PULLSTATE5_S_RQgeBS :
  878. // No zero read
  879. Win4Assert(m_cLastRead != 0);
  880. // The request is greater than what was asked for last time. So
  881. // we increase the read ahead to the max of the request or what
  882. // was actually read last time.
  883. m_cReadAhead = MAX(Request, m_cLastRead);
  884. break;
  885. default :
  886. // For all other states we should not be making read ahead calls.
  887. // Mostly because we read zero elements last time which indicates
  888. // the end of the data. The PULLSTATE4_S_RQlsBS doesn't do a read
  889. // ahead so we shouldn't be here while in that state.
  890. Win4Assert(FALSE && "Request read ahead in wrong state.");
  891. }
  892. Win4Assert( 0 != m_cReadAhead );
  893. }
  894. template<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
  895. //+**************************************************************************
  896. // CheckAndSetKeepBuffer()
  897. //
  898. // Description: Check to see if the Buffer is the correct size and if not
  899. // make it the correct size.
  900. //
  901. // History:
  902. // Date: Time: Developer: Action:
  903. // 11/19/97 3:27:25 PM RichN Created.
  904. //
  905. // Notes: The buffer will never get smaller.
  906. //
  907. //-**************************************************************************
  908. HRESULT CPipeProxy<T, ID, AsyncID, I, AsyncI>
  909. ::CheckAndSetKeepBuffer(void)
  910. {
  911. Win4Assert(0 != m_cReadAhead);
  912. // Create a keep buffer the size of the read ahead.
  913. // We assume here that the user will not change the
  914. // request size and that the amount of data on hand
  915. // will never be larger. When it is we will re-allocate.
  916. // The buffer will never get smaller. Something to look at.
  917. if( m_cKeepBufferSize >= m_cReadAhead )
  918. return S_OK;
  919. T *temp = new T[m_cReadAhead];
  920. if( NULL == temp )
  921. {
  922. delete[] m_pKeepBuffer;
  923. m_pKeepBuffer = NULL;
  924. return E_OUTOFMEMORY;
  925. }
  926. if( m_pKeepBuffer != NULL )
  927. {
  928. // Copy the data into the new buffer
  929. memcpy(temp, m_pKeepBuffer, m_cKeepDataSize * sizeof(T));
  930. // Delete the old buffer and reset the bookkeeping.
  931. delete[] m_pKeepBuffer;
  932. }
  933. m_pKeepBuffer = temp;
  934. m_cKeepBufferSize = m_cReadAhead;
  935. m_pKeepData = m_pKeepBuffer + m_cKeepDataSize;
  936. return S_OK;
  937. }
  938. template<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
  939. //+**************************************************************************
  940. // PullStateTransition(ULONG Request)
  941. //
  942. // Description: Transition from one state to the next. See pipes document
  943. // for a description of the state machine.
  944. //
  945. // History:
  946. // Date: Time: Developer: Action:
  947. // 11/11/97 4:20:19 PM RichN Created.
  948. //
  949. // Notes:
  950. //
  951. //-**************************************************************************
  952. HRESULT CPipeProxy<T, ID, AsyncID, I, AsyncI>
  953. ::PullStateTransition(ULONG Request)
  954. {
  955. ComDebOut(( DEB_MARSHAL, "PullStateTransition \n"));
  956. Win4Assert(Request > 0);
  957. switch( m_PullState )
  958. {
  959. case PULLSTATE0_ENTRY:
  960. // Transition to the first call state.
  961. m_PullState = PULLSTATE1_FIRST_CALL;
  962. break;
  963. case PULLSTATE1_FIRST_CALL:
  964. // If the last read was zero we are done. We have no stored
  965. // data so go to the state that handles request
  966. // that are either less than or greater than or
  967. // equal to the last read ahead. Realize the amount of
  968. // data returned from the last read ahead may
  969. // not equal the requeat and could be greater than or less than.
  970. if( 0 == m_cLastRead )
  971. m_PullState = PULLSTATE6_DONE;
  972. else
  973. m_PullState = (Request < m_cReadAhead) ?
  974. PULLSTATE2_NS_RQlsRA : PULLSTATE3_NS_RQgeRA;
  975. break;
  976. case PULLSTATE2_NS_RQlsRA:
  977. // In this state, either the last read is not zero or
  978. // the amount of data remaining is zero. Whatever state
  979. // we get to this one from does not go here on a last read
  980. // of zero nor if there is any data in the buffer (kept data).
  981. // Possible we where in this state and got a last
  982. // read of zero, in which case the amount of held data will
  983. // be = zero. We are in a state with no held data and got
  984. // a zero read of data, there can't be any kept data.
  985. Win4Assert(!( m_cLastRead == 0 && m_cKeepDataSize > 0));
  986. // If we had a zero read, we cleaned up in
  987. // this state and go to the state that just returns zero.
  988. if( 0 == m_cLastRead)
  989. {
  990. Win4Assert( 0 == m_cKeepDataSize );
  991. m_PullState = PULLSTATE6_DONE;
  992. }
  993. else
  994. {
  995. // If the kept data is zero, then we need to go to a state
  996. // that understands an empty buffer. Determine which one
  997. // by the request and the read ahead.
  998. // If there is kept data then go to a state that understands
  999. // a non empty buffer. This time the correct one depends on
  1000. // the amount of data in the buffer.
  1001. if( 0 == m_cKeepDataSize )
  1002. m_PullState = ( Request < m_cReadAhead ) ?
  1003. PULLSTATE2_NS_RQlsRA : PULLSTATE3_NS_RQgeRA;
  1004. else
  1005. m_PullState = ( Request < m_cKeepDataSize) ?
  1006. PULLSTATE4_S_RQlsBS : PULLSTATE5_S_RQgeBS;
  1007. }
  1008. break;
  1009. case PULLSTATE3_NS_RQgeRA:
  1010. // We can never leave this state with data in the buffer. The
  1011. // request is greater than the read ahead and the returned amount
  1012. // of data can never be greater than the requested data, but it
  1013. // could be less.
  1014. Win4Assert(m_cKeepDataSize == 0);
  1015. // If the last read was zero go to the done state.
  1016. // else go to the state that understands empty buffers depending
  1017. // on the request and the read ahead.
  1018. if( 0 == m_cLastRead )
  1019. m_PullState = PULLSTATE6_DONE;
  1020. else
  1021. m_PullState = ( Request < m_cReadAhead ) ?
  1022. PULLSTATE2_NS_RQlsRA : PULLSTATE3_NS_RQgeRA;
  1023. break;
  1024. case PULLSTATE4_S_RQlsBS:
  1025. // When this state was entered there was data in the buffer. The
  1026. // request was for less than the buffer size so when we returned
  1027. // there should have still been data in the buffer. No read is done.
  1028. Win4Assert(m_cKeepDataSize > 0);
  1029. Win4Assert(m_cLastRead > 0);
  1030. // Go to the state that handles data in the buffer
  1031. // depending on the request and the amount of data in the buffer.
  1032. m_PullState = ( Request < m_cKeepDataSize ) ?
  1033. PULLSTATE4_S_RQlsBS : PULLSTATE5_S_RQgeBS;
  1034. break;
  1035. case PULLSTATE5_S_RQgeBS:
  1036. // Because we can fulfill at aleast part of the request from
  1037. // the buffer, we don't wait on the async call to finish. If it
  1038. // did finish (wait 0 tells us that) then there is data in the
  1039. // buffer (assuming it returned data) otherwise it is empty.
  1040. // So when the call finished last time the buffer
  1041. // could be empty or not. If the read was zero the buffer is empty.
  1042. Win4Assert( (m_cLastRead == 0 && m_cKeepDataSize == 0) ||
  1043. m_cLastRead != 0 );
  1044. // If the buffer is empty then on a zero last read go to done.
  1045. // Otherwise go to a state that understands empty buffers depending
  1046. // on the request size and the read ahead.
  1047. if( 0 == m_cKeepDataSize )
  1048. if( 0 == m_cLastRead )
  1049. m_PullState = PULLSTATE6_DONE;
  1050. else
  1051. m_PullState = ( Request < m_cReadAhead ) ?
  1052. PULLSTATE2_NS_RQlsRA : PULLSTATE3_NS_RQgeRA;
  1053. else
  1054. // Otherwise go to one that understands having data in the
  1055. // buffer depending on the request and the amount of data in
  1056. // the buffer.
  1057. m_PullState = ( Request < m_cKeepDataSize ) ?
  1058. PULLSTATE4_S_RQlsBS : PULLSTATE5_S_RQgeBS;
  1059. break;
  1060. case PULLSTATE6_DONE:
  1061. // When in this state there better not be any data left and
  1062. // the last read must be zero.
  1063. Win4Assert(m_cKeepDataSize == 0);
  1064. Win4Assert(m_cLastRead == 0);
  1065. m_PullState = PULLSTATE1_FIRST_CALL;
  1066. break;
  1067. default:
  1068. return E_UNEXPECTED;
  1069. }
  1070. return S_OK;
  1071. }
  1072. template<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
  1073. //+**************************************************************************
  1074. // NbNaRgtRA1
  1075. //
  1076. // Description: Pull, No data in buffer, no async call outstanding and
  1077. // request is >= read ahead. State 1.
  1078. //
  1079. // History:
  1080. // Date: Time: Developer: Action:
  1081. // 11/19/97 2:30:11 PM RichN Created.
  1082. //
  1083. // Notes: Make a sync call to get some data and then make an async call to
  1084. // read ahead.
  1085. //
  1086. //-**************************************************************************
  1087. HRESULT CPipeProxy<T, ID, AsyncID, I, AsyncI>
  1088. ::NbNaRgtRA1(T *Buf,
  1089. ULONG Request,
  1090. ULONG *Received)
  1091. {
  1092. ComDebOut(( DEB_MARSHAL, "NbNaRgtRA1 Request:%d\n", Request));
  1093. Win4Assert(1 == m_PullState);
  1094. Win4Assert(NULL != Buf);
  1095. // State conditions
  1096. Win4Assert(0 == m_cLastRead );
  1097. Win4Assert(0 == m_cKeepDataSize);
  1098. HRESULT hr = S_OK;
  1099. // We are only in this state one time. There will always be
  1100. // an out standing async call, so we init async here.
  1101. hr = InitAsync(&m_pPullCallObj, &m_pAsyncPullPipe, &m_pISyncPull);
  1102. if( FAILED(hr) )
  1103. return hr;
  1104. // make a sync call to get started.
  1105. hr = m_pRealProxy->Pull(Buf, Request, Received);
  1106. m_cLastRead = *Received;
  1107. if( m_cLastRead > 0 && SUCCEEDED(hr))
  1108. {
  1109. SetReadAhead(Request);
  1110. // Make the async call.
  1111. hr = m_pAsyncPullPipe->Begin_Pull(m_cReadAhead);
  1112. }
  1113. else
  1114. {
  1115. CleanupProxy(&m_pKeepBuffer,
  1116. &m_pPullCallObj,
  1117. &m_pAsyncPullPipe,
  1118. &m_pISyncPull);
  1119. }
  1120. // Post condition
  1121. // Wouldn't expect the last read to be zero here, but no reason
  1122. // it couldn't be.
  1123. Win4Assert( 0 == m_cKeepDataSize );
  1124. return hr;
  1125. }
  1126. template<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
  1127. //+**************************************************************************
  1128. // NbaRltRA2 (T *Buf, ULONG Request, ULONG *Received)
  1129. //
  1130. // Description: Pull, No Buffer, read ahead call outstanding.
  1131. // State 2. We have to be prepared
  1132. // for the amount returned to be greater than, less than or equal
  1133. // to the amount requested. This works for both states 2 and 3.
  1134. //
  1135. // History:
  1136. // Date: Time: Developer: Action:
  1137. // 11/19/97 2:32:13 PM RichN Created.
  1138. //
  1139. // Notes: wait on the sync object,
  1140. // Finish the async call,
  1141. // Copy the data into the user Buffer
  1142. // make another async call
  1143. //
  1144. //-**************************************************************************
  1145. HRESULT CPipeProxy<T, ID, AsyncID, I, AsyncI>
  1146. ::NbaRltRA2 (T *Buf, ULONG Request, ULONG *Received)
  1147. {
  1148. ComDebOut(( DEB_MARSHAL, "NbaRltRA2 Request:%d\n", Request));
  1149. Win4Assert(2 == m_PullState);
  1150. Win4Assert(NULL != Buf);
  1151. // State conditions.
  1152. Win4Assert(0 == m_cKeepDataSize); // No data in keep Buffer.
  1153. Win4Assert(0 < m_cLastRead);
  1154. Win4Assert(Request < m_cReadAhead);
  1155. HRESULT hr = S_OK;
  1156. bool bDoCleanup = false;
  1157. // There might be a Bug here. Bug!
  1158. // We should just be able to call the finish method, but the
  1159. // bug requires us to wait first.
  1160. hr = m_pISyncPull->Wait(0, WAIT_INFINITE);
  1161. if( SUCCEEDED(hr) )
  1162. {
  1163. hr = CheckAndSetKeepBuffer();
  1164. if( SUCCEEDED(hr) )
  1165. {
  1166. // Get the data requested last time. Remember the amount returned
  1167. // could be less than we requested.
  1168. hr = m_pAsyncPullPipe->Finish_Pull(m_pKeepBuffer, &m_cLastRead);
  1169. // We can't return more than requested, the buffer may not be
  1170. // large enough.
  1171. *Received = MIN(Request, m_cLastRead);
  1172. if( SUCCEEDED(hr) && m_cLastRead > 0 )
  1173. {
  1174. // Copy the data to the users Buffer and updata bookkeeping.
  1175. memcpy(Buf, m_pKeepBuffer, (*Received) * sizeof(T));
  1176. m_pKeepData = m_pKeepBuffer + *Received;
  1177. m_cKeepDataSize = m_cLastRead - *Received;
  1178. SetReadAhead(Request);
  1179. // Make another read ahead
  1180. hr = m_pAsyncPullPipe->Begin_Pull(m_cReadAhead);
  1181. }
  1182. else
  1183. {
  1184. // If the call failed or we received no data, we
  1185. // need to clean up since we won't be called again.
  1186. bDoCleanup = true;
  1187. }
  1188. }
  1189. else
  1190. {
  1191. //Cancel the call here.
  1192. CancelTheCall(m_pPullCallObj, 0);
  1193. }
  1194. }
  1195. if( FAILED(hr) || bDoCleanup )
  1196. CleanupProxy(&m_pKeepBuffer,
  1197. &m_pPullCallObj,
  1198. &m_pAsyncPullPipe,
  1199. &m_pISyncPull);
  1200. // Post condition
  1201. Win4Assert(!(m_cLastRead == 0 && m_cKeepDataSize > 0));
  1202. return hr;
  1203. }
  1204. template<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
  1205. //+**************************************************************************
  1206. // NbaRgtRA3 (T *Buf, ULONG Request, ULONG *Received)
  1207. //
  1208. // Description: Pull, No Buffered data, async call outstanding and request
  1209. // is greater than read ahead.
  1210. //
  1211. // History:
  1212. // Date: Time: Developer: Action:
  1213. // 11/20/97 10:50:22 AM RichN Created.
  1214. //
  1215. // Notes: Difference between this and the previous state: we know
  1216. // we don't need a keep Buffer here.
  1217. // wait on the sync object,
  1218. // Finish the async call,
  1219. // Copy the data into the user Buffer
  1220. // make another async call
  1221. //
  1222. //-**************************************************************************
  1223. HRESULT CPipeProxy<T, ID, AsyncID, I, AsyncI>
  1224. ::NbaRgtRA3 (T *Buf, ULONG Request, ULONG *Received)
  1225. {
  1226. ComDebOut(( DEB_MARSHAL, "NbaRgtRA3, Request:%d \n", Request));
  1227. Win4Assert(3 == m_PullState);
  1228. Win4Assert(NULL != Buf);
  1229. // State conditions.
  1230. Win4Assert(0 == m_cKeepDataSize); // No data in keep Buffer.
  1231. Win4Assert(0 < m_cLastRead);
  1232. Win4Assert(Request >= m_cReadAhead);
  1233. bool bDoCleanup = false;
  1234. HRESULT hr = m_pISyncPull->Wait(0, WAIT_INFINITE);
  1235. if( SUCCEEDED(hr))
  1236. {
  1237. // Get the data requested last time.
  1238. hr = m_pAsyncPullPipe->Finish_Pull(Buf, &m_cLastRead);
  1239. *Received = m_cLastRead;
  1240. if( SUCCEEDED(hr) && m_cLastRead > 0 )
  1241. {
  1242. // Reset the amount of data remaining.
  1243. m_cKeepDataSize = 0;
  1244. m_pKeepData = NULL;
  1245. SetReadAhead(Request);
  1246. // Make another read ahead
  1247. hr = m_pAsyncPullPipe->Begin_Pull(m_cReadAhead);
  1248. }
  1249. else
  1250. {
  1251. // If the call failed or we received no data, we
  1252. // need to clean up since we won't be called again.
  1253. bDoCleanup = TRUE;
  1254. }
  1255. }
  1256. if( FAILED(hr) || bDoCleanup )
  1257. CleanupProxy(&m_pKeepBuffer,
  1258. &m_pPullCallObj,
  1259. &m_pAsyncPullPipe,
  1260. &m_pISyncPull);
  1261. // Post condition
  1262. Win4Assert( 0 < m_cReadAhead);
  1263. Win4Assert(0 == m_cKeepDataSize);
  1264. return hr;
  1265. }
  1266. template<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
  1267. //+**************************************************************************
  1268. // baRltB4 (T *Buf, ULONG Request, ULONG *Received)
  1269. //
  1270. // Description: Pull, Data in Buffer, async call outstanding and Request is
  1271. // less than the data in the keep Buffer.
  1272. //
  1273. // History:
  1274. // Date: Time: Developer: Action:
  1275. // 11/20/97 1:22:41 PM RichN Created.
  1276. //
  1277. // Notes: Copy data from the keep Buffer to the users Buffer.
  1278. // Update state variables.
  1279. //
  1280. //-**************************************************************************
  1281. HRESULT CPipeProxy<T, ID, AsyncID, I, AsyncI>
  1282. ::baRltB4 (T *Buf, ULONG Request, ULONG *Received)
  1283. {
  1284. ComDebOut(( DEB_MARSHAL, "baRltB4 \n"));
  1285. Win4Assert(NULL != Buf);
  1286. Win4Assert(4 == m_PullState);
  1287. // State conditions.
  1288. Win4Assert(0 < m_cKeepDataSize); // Data in keep Buffer.
  1289. Win4Assert(0 < m_cLastRead);
  1290. Win4Assert(Request < m_cKeepDataSize);
  1291. memcpy(Buf, m_pKeepData, Request * (sizeof(T)));
  1292. m_cKeepDataSize -= Request;
  1293. m_pKeepData += Request;
  1294. // Post condition
  1295. Win4Assert(m_cKeepDataSize > 0);
  1296. Win4Assert(m_cLastRead > 0);
  1297. // Post condition
  1298. Win4Assert(0 < m_cKeepDataSize); // Data in keep Buffer.
  1299. Win4Assert(0 < m_cLastRead);
  1300. return S_OK;
  1301. }
  1302. template<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
  1303. //+**************************************************************************
  1304. // baRgtB5 (T *Buf, ULONG Request, ULONG *Received)
  1305. //
  1306. // Description: Pull, Data in Buffer, async call outstanding and Request is
  1307. // greater than or equal the data in the keep Buffer.
  1308. //
  1309. // History:
  1310. // Date: Time: Developer: Action:
  1311. // 11/20/97 1:24:25 PM RichN Created.
  1312. //
  1313. // Notes: Copy the keep Buffer data to the users Buffer.
  1314. // Wait 0
  1315. // if the call has completed.
  1316. // Finish the async call (keep Buffer, RA)
  1317. // Copy data into users Buffer to fill request
  1318. // Update keep data size.
  1319. // if we didn't read zero
  1320. // set read ahead
  1321. // Begin async call(RA)
  1322. //
  1323. //-**************************************************************************
  1324. HRESULT CPipeProxy<T, ID, AsyncID, I, AsyncI>
  1325. ::baRgtB5 (T *Buf, ULONG Request, ULONG *Received)
  1326. {
  1327. ComDebOut(( DEB_MARSHAL, "baRgtB5 \n"));
  1328. Win4Assert(NULL != Buf);
  1329. Win4Assert(5 == m_PullState);
  1330. // State conditions.
  1331. Win4Assert(0 < m_cKeepDataSize); // Data in keep buffer.
  1332. Win4Assert(0 < m_cLastRead);
  1333. Win4Assert(Request >= m_cKeepDataSize);
  1334. HRESULT hr = S_OK;
  1335. // Give whatever data we already have.
  1336. T *tempBuf = Buf;
  1337. memcpy(tempBuf, m_pKeepData, m_cKeepDataSize * (sizeof(T)) );
  1338. // Remainder of the request.
  1339. ULONG Remainder = Request - m_cKeepDataSize;
  1340. tempBuf += m_cKeepDataSize;
  1341. m_cKeepDataSize = 0;
  1342. m_pKeepData = NULL;
  1343. hr = m_pISyncPull->Wait(0, 0);
  1344. // If the call is finished get the data and
  1345. // copy up to the total request or as much as
  1346. // we have into the buffer.
  1347. if( SUCCEEDED(hr) && RPC_S_CALLPENDING != hr)
  1348. {
  1349. hr = CheckAndSetKeepBuffer();
  1350. if( SUCCEEDED(hr) )
  1351. {
  1352. hr = m_pAsyncPullPipe->Finish_Pull(m_pKeepBuffer, &m_cLastRead);
  1353. if( SUCCEEDED(hr) )
  1354. {
  1355. // Copy the smaller of the remainder of the
  1356. // request or what was actually received.
  1357. ULONG CopySize = MIN(Remainder, m_cLastRead);
  1358. memcpy(tempBuf, m_pKeepBuffer, CopySize * sizeof(T));
  1359. m_cKeepDataSize = m_cLastRead - CopySize;
  1360. m_pKeepData = m_pKeepBuffer + CopySize;
  1361. if( m_cLastRead > 0 )
  1362. {
  1363. SetReadAhead(Request);
  1364. hr = m_pAsyncPullPipe->Begin_Pull(m_cReadAhead);
  1365. }
  1366. }
  1367. }
  1368. else
  1369. CancelTheCall(m_pPullCallObj, 0);
  1370. }
  1371. else
  1372. {
  1373. if( RPC_S_CALLPENDING == hr )
  1374. hr = S_OK;
  1375. else
  1376. CancelTheCall(m_pPullCallObj, 0);
  1377. }
  1378. *Received = (ULONG) (tempBuf - Buf);
  1379. if( FAILED(hr) )
  1380. CleanupProxy(&m_pKeepBuffer,
  1381. &m_pPullCallObj,
  1382. &m_pAsyncPullPipe,
  1383. &m_pISyncPull);
  1384. // Post condition
  1385. Win4Assert( (m_cLastRead == 0 && m_cKeepDataSize == 0) ||
  1386. m_cLastRead != 0 );
  1387. return hr;
  1388. }
  1389. template<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
  1390. //+**************************************************************************
  1391. // PullDone6 (T *Buf, ULONG Request, ULONG *Received)
  1392. //
  1393. // Description: Pull Done, no data in the Buffer and no outstanding calls.
  1394. //
  1395. // History:
  1396. // Date: Time: Developer: Action:
  1397. // 11/20/97 3:30:14 PM RichN Created.
  1398. //
  1399. // Notes:
  1400. //
  1401. //-**************************************************************************
  1402. HRESULT CPipeProxy<T, ID, AsyncID, I, AsyncI>
  1403. ::PullDone6 (T *Buf, ULONG Request, ULONG *Received)
  1404. {
  1405. ComDebOut(( DEB_MARSHAL, "PullDone6 \n"));
  1406. Win4Assert(6 == m_PullState);
  1407. CleanupProxy(&m_pKeepBuffer,
  1408. &m_pPullCallObj,
  1409. &m_pAsyncPullPipe,
  1410. &m_pISyncPull);
  1411. HRESULT hr = S_OK;
  1412. if (Request > 0)
  1413. {
  1414. m_PullState = PULLSTATE1_FIRST_CALL;
  1415. hr = (this->*(PullStateFunc[m_PullState]))( Buf, Request, Received );
  1416. }
  1417. else
  1418. {
  1419. *Received = 0;
  1420. // Post condition
  1421. Win4Assert( 0 == m_cKeepDataSize );
  1422. Win4Assert( 0 == m_cLastRead );
  1423. }
  1424. return hr;
  1425. }
  1426. template<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
  1427. //+**************************************************************************
  1428. // SetPushBuffer(ULONG PushSize)
  1429. //
  1430. // Description: Allocates a buffer for push, or reallocates if it
  1431. // needs to grow.
  1432. //
  1433. // History:
  1434. // Date: Time: Developer: Action:
  1435. // 11/21/97 10:10:50 AM RichN Created.
  1436. //
  1437. // Notes: The buffer will never get smaller. We might want
  1438. // to reduce it by some algorithm, but not this time.
  1439. //
  1440. //-**************************************************************************
  1441. HRESULT CPipeProxy<T, ID, AsyncID, I, AsyncI>
  1442. ::SetPushBuffer(ULONG PushSize)
  1443. {
  1444. ComDebOut(( DEB_MARSHAL, "SetPushBuffer, PushSize:%l \n"));
  1445. // If it is already big enough just return.
  1446. if( m_cPushBufferSize >= PushSize )
  1447. return S_OK;
  1448. ULONG NewSize = MAX(PushSize, (FRAGMENT_SIZE / sizeof(T)) + 1);
  1449. T *pTtemp = new T[NewSize];
  1450. if( NULL == pTtemp )
  1451. {
  1452. delete[] m_pPushBuffer;
  1453. m_pPushBuffer = NULL;
  1454. return E_OUTOFMEMORY;
  1455. }
  1456. ULONG BufferedDataSize = m_cPushBufferSize - m_cFreeSpace;
  1457. if( m_pPushBuffer != NULL )
  1458. {
  1459. // Copy data over and reset bookkeeping.
  1460. memcpy(pTtemp, m_pPushBuffer, BufferedDataSize * sizeof(T));
  1461. delete[] m_pPushBuffer;
  1462. }
  1463. m_pPushBuffer = pTtemp;
  1464. m_cPushBufferSize = NewSize;
  1465. m_pFreeSpace = m_pPushBuffer + BufferedDataSize;
  1466. m_cFreeSpace = m_cPushBufferSize - BufferedDataSize;
  1467. return S_OK;
  1468. }
  1469. template<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
  1470. //+**************************************************************************
  1471. // PushStateTransition(ULONG Request)
  1472. //
  1473. // Description: Implements the transition table for push. See the pipes
  1474. // document for a description of the state machine.
  1475. //
  1476. // History:
  1477. // Date: Time: Developer: Action:
  1478. // 11/13/97 4:36:43 PM RichN Created.
  1479. //
  1480. // 02/05/99 JohnStra Modified Push state machine to
  1481. // allow multiple Push operations
  1482. // on a pipe.
  1483. // Notes:
  1484. //
  1485. //-**************************************************************************
  1486. HRESULT CPipeProxy<T, ID, AsyncID, I, AsyncI>
  1487. ::PushStateTransition(ULONG PushSize)
  1488. {
  1489. ComDebOut(( DEB_MARSHAL, "PushStateTransition, PushSize:%l \n"));
  1490. switch( m_PushState )
  1491. {
  1492. case PUSHSTATE0_ENTRY:
  1493. // From the entry state we always go to the first call state.
  1494. m_PushState = PUSHSTATE1_FIRSTCALL;
  1495. break;
  1496. case PUSHSTATE1_FIRSTCALL:
  1497. case PUSHSTATE2_FS_PSgeFS:
  1498. case PUSHSTATE3_FS_PSltFS:
  1499. // If the push size is zero transition to state that
  1500. // does a zero send.
  1501. if( 0 == PushSize )
  1502. m_PushState = PUSHSTATE4_FS_PSZERO;
  1503. else
  1504. // Go to state that either puts the data in free space
  1505. // or one that handles a push greater than the free space.
  1506. m_PushState = (PushSize < m_cFreeSpace) ?
  1507. PUSHSTATE3_FS_PSltFS : PUSHSTATE2_FS_PSgeFS;
  1508. break;
  1509. case PUSHSTATE4_FS_PSZERO:
  1510. // If we are in the state that handles a zero push we may
  1511. // be called again with a positive buffer size to execute
  1512. // another push. If we are called with any other
  1513. // buffer size, go to the state that returns an error.
  1514. if( 0 < PushSize )
  1515. m_PushState = PUSHSTATE1_FIRSTCALL;
  1516. else
  1517. m_PushState = PUSHSTATE5_DONE_ERROR;
  1518. break;
  1519. case PUSHSTATE5_DONE_ERROR:
  1520. // Stay in state PUSHSTATE_DONE_ERROR.
  1521. break;
  1522. default:
  1523. return E_UNEXPECTED;
  1524. }
  1525. return S_OK;
  1526. }
  1527. template<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
  1528. //+**************************************************************************
  1529. // NbNf1(T *Buf, ULONG PushSize)
  1530. //
  1531. // Description: Push, No buffer, no free, state 1.
  1532. //
  1533. // History:
  1534. // Date: Time: Developer: Action:
  1535. // 11/21/97 9:42:57 AM RichN Created.
  1536. //
  1537. // Notes:
  1538. //
  1539. //-**************************************************************************
  1540. HRESULT CPipeProxy<T, ID, AsyncID, I, AsyncI>
  1541. ::NbNf1(T *Buf, ULONG PushSize)
  1542. {
  1543. ComDebOut(( DEB_MARSHAL, "NbNf1, PushSize:%l \n", PushSize));
  1544. Win4Assert(1 == m_PushState);
  1545. // This is the first call to push so PushSize shouldn't be zero.
  1546. if( PushSize == 0 || NULL == Buf)
  1547. return E_INVALIDARG;
  1548. HRESULT hr;
  1549. // We are only in this state one time so init the async stuff.
  1550. hr = InitAsync(&m_pPushCallObj, &m_pAsyncPushPipe, &m_pISyncPush);
  1551. if( FAILED(hr) )
  1552. return hr;
  1553. hr = m_pAsyncPushPipe->Begin_Push(Buf, PushSize);
  1554. if( FAILED(hr) )
  1555. CleanupProxy(&m_pPushBuffer,
  1556. &m_pPushCallObj,
  1557. &m_pAsyncPushPipe,
  1558. &m_pISyncPush);
  1559. return hr;
  1560. }
  1561. template<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
  1562. //+**************************************************************************
  1563. // bfPgtF2(T *Buf, ULONG PushSize)
  1564. //
  1565. // Description: Push, Have a buffer with free space and the push size
  1566. // is greater than or equal to the free space. State 2.
  1567. //
  1568. // History:
  1569. // Date: Time: Developer: Action:
  1570. // 11/21/97 10:52:41 AM RichN Created.
  1571. //
  1572. // Notes: This may grow the buffer, look at reducing it in the next method.
  1573. //
  1574. //-**************************************************************************
  1575. HRESULT CPipeProxy<T, ID, AsyncID, I, AsyncI>
  1576. ::bfPgtF2(T *Buf, ULONG PushSize)
  1577. {
  1578. ComDebOut(( DEB_MARSHAL, "bfPgtF2, PushSize:%l \n", PushSize));
  1579. Win4Assert(2 == m_PushState);
  1580. Win4Assert( PushSize >= m_cFreeSpace );
  1581. Win4Assert( PushSize > 0 );
  1582. Win4Assert( (LONG) m_cFreeSpace >= 0 );
  1583. if( PushSize == 0 || NULL == Buf)
  1584. return E_INVALIDARG;
  1585. // There might be a BUG here. BUG! Shouldn't have to wait.
  1586. HRESULT hr = m_pISyncPush->Wait(0, WAIT_INFINITE);
  1587. if( SUCCEEDED(hr) )
  1588. hr = m_pAsyncPushPipe->Finish_Push();
  1589. if( SUCCEEDED(hr) )
  1590. {
  1591. ULONG TotalData = PushSize + (m_cPushBufferSize - m_cFreeSpace);
  1592. hr = SetPushBuffer( TotalData );
  1593. if( SUCCEEDED(hr) )
  1594. {
  1595. // Append the data to the buffer.
  1596. memcpy(m_pFreeSpace, Buf, PushSize * sizeof(T));
  1597. hr = m_pAsyncPushPipe->Begin_Push(m_pPushBuffer, TotalData);
  1598. m_pFreeSpace = m_pPushBuffer;
  1599. m_cFreeSpace = m_cPushBufferSize;
  1600. }
  1601. }
  1602. if( FAILED(hr) )
  1603. CleanupProxy(&m_pPushBuffer,
  1604. &m_pPushCallObj,
  1605. &m_pAsyncPushPipe,
  1606. &m_pISyncPush);
  1607. return hr;
  1608. }
  1609. template<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
  1610. //+**************************************************************************
  1611. // bfPltF3(T *Buf, ULONG PushSize)
  1612. //
  1613. // Description: Push, Have buffer and pushed data is less than free space.
  1614. //
  1615. // History:
  1616. // Date: Time: Developer: Action:
  1617. // 11/21/97 11:03:19 AM RichN Created.
  1618. //
  1619. // Notes:
  1620. //
  1621. //-**************************************************************************
  1622. HRESULT CPipeProxy<T, ID, AsyncID, I, AsyncI>
  1623. ::bfPltF3(T *Buf, ULONG PushSize)
  1624. {
  1625. ComDebOut(( DEB_MARSHAL, "bfPltF3, PushSize:%l \n", PushSize));
  1626. Win4Assert(3 == m_PushState);
  1627. Win4Assert( m_cFreeSpace > PushSize );
  1628. Win4Assert( PushSize > 0 );
  1629. Win4Assert( m_cFreeSpace > 0 );
  1630. if( NULL == Buf)
  1631. return E_INVALIDARG;
  1632. // Copy the data into the buffer.
  1633. memcpy(m_pFreeSpace, Buf, PushSize * sizeof(T));
  1634. m_cFreeSpace -= PushSize;
  1635. m_pFreeSpace += PushSize;
  1636. return S_OK;
  1637. }
  1638. template<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
  1639. //+**************************************************************************
  1640. // bPSz4(T *Buf, ULONG PushSize)
  1641. //
  1642. // Description: Push, Have buffer and push size is zero.
  1643. //
  1644. // History:
  1645. // Date: Time: Developer: Action:
  1646. // 11/21/97 11:33:32 AM RichN Created.
  1647. //
  1648. // Notes:
  1649. //
  1650. //-**************************************************************************
  1651. HRESULT CPipeProxy<T, ID, AsyncID, I, AsyncI>
  1652. ::bPSz4(T *Buf, ULONG PushSize)
  1653. {
  1654. ComDebOut(( DEB_MARSHAL, "bPSz4, PushSize:$l \n", PushSize));
  1655. Win4Assert(4 == m_PushState);
  1656. Win4Assert( PushSize == 0 );
  1657. Win4Assert( (LONG) m_cFreeSpace >= 0 );
  1658. // There might be a BUG here. BUG! Shouldn't have to wait.
  1659. HRESULT hr = m_pISyncPush->Wait(0, WAIT_INFINITE);
  1660. if( SUCCEEDED(hr) )
  1661. hr = m_pAsyncPushPipe->Finish_Push();
  1662. if( SUCCEEDED(hr) )
  1663. {
  1664. if( (m_cPushBufferSize - m_cFreeSpace) > 0 )
  1665. {
  1666. // Data in buffer so send it.
  1667. hr = m_pAsyncPushPipe->Begin_Push(m_pPushBuffer,
  1668. m_cPushBufferSize - m_cFreeSpace);
  1669. if( FAILED(hr) )
  1670. goto asyncFailed;
  1671. hr = m_pISyncPush->Wait(0, WAIT_INFINITE);
  1672. if( FAILED(hr) )
  1673. goto asyncFailed;
  1674. hr = m_pAsyncPushPipe->Finish_Push();
  1675. }
  1676. if( SUCCEEDED(hr) )
  1677. {
  1678. // Push a zero size buffer to signal end of data.
  1679. hr = m_pAsyncPushPipe->Begin_Push(Buf, PushSize);
  1680. if( FAILED(hr) )
  1681. goto asyncFailed;
  1682. hr = m_pISyncPush->Wait(0, WAIT_INFINITE);
  1683. if( FAILED(hr) )
  1684. goto asyncFailed;
  1685. hr = m_pAsyncPushPipe->Finish_Push();
  1686. }
  1687. }
  1688. asyncFailed:
  1689. // Last call regardless of success or failure so clean async up.
  1690. CleanupProxy(&m_pPushBuffer,
  1691. &m_pPushCallObj,
  1692. &m_pAsyncPushPipe,
  1693. &m_pISyncPush);
  1694. return hr;
  1695. }
  1696. template<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
  1697. //+**************************************************************************
  1698. // PushDone5(T *Buf, ULONG PushSize)
  1699. //
  1700. // Description: Push Done, so this should never be called.
  1701. //
  1702. // History:
  1703. // Date: Time: Developer: Action:
  1704. // 11/21/97 11:42:08 AM RichN Created.
  1705. //
  1706. // Notes:
  1707. //
  1708. //-**************************************************************************
  1709. HRESULT CPipeProxy<T, ID, AsyncID, I, AsyncI>
  1710. ::PushDone5(T *Buf, ULONG PushSize)
  1711. {
  1712. ComDebOut(( DEB_MARSHAL, "PushDone5, PushSize:%u \n"));
  1713. Win4Assert(FALSE && "Push call after completion.");
  1714. Win4Assert(5 == m_PushState);
  1715. return E_UNEXPECTED;
  1716. }