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.

764 lines
18 KiB

  1. //+-------------------------------------------------------------
  2. //
  3. // File: perfcli.cxx
  4. //
  5. // Contents: First attempt at getting perfcliing to work
  6. //
  7. // This is the client side
  8. //
  9. //
  10. //---------------------------------------------------------------
  11. #include <windows.h>
  12. #include <stdio.h>
  13. #include <sys/types.h>
  14. #include <sys/stat.h>
  15. #include <errno.h>
  16. #include <io.h>
  17. #include <ole2.h>
  18. #include <com.hxx>
  19. #include "app.hxx"
  20. #include <memalloc.h>
  21. #include <objerror.h>
  22. #pragma hdrstop
  23. //+--------------------------------------------------------------
  24. /* Definitions. */
  25. #define MAX_CALLS 1000
  26. #define MAX_THREADS 10
  27. typedef enum what_next_en
  28. {
  29. wait_wn,
  30. interrupt_wn,
  31. quit_wn
  32. } what_next_en;
  33. //+--------------------------------------------------------------
  34. /* Prototypes. */
  35. void interrupt ( void );
  36. void check_for_request ( void );
  37. BOOL server_loop ( void );
  38. DWORD _stdcall ThreadHelper ( void * );
  39. void wait_for_message ( void );
  40. void wake_up_and_smell_the_roses( void );
  41. //+--------------------------------------------------------------
  42. /* Globals. */
  43. DWORD thread_mode = COINIT_MULTITHREADED;
  44. HANDLE Done;
  45. BOOL server;
  46. BOOL Multicall_Test;
  47. BOOL InterruptTestResults;
  48. BOOL InterruptTestDone;
  49. DWORD MainThread;
  50. DWORD NestedCallCount = 0;
  51. what_next_en WhatNext;
  52. ITest *global_test = NULL;
  53. BOOL global_interrupt_test;
  54. /***************************************************************************/
  55. STDMETHODIMP_(ULONG) CTest::AddRef( THIS )
  56. {
  57. InterlockedIncrement( (long *) &ref_count );
  58. return ref_count;
  59. }
  60. /***************************************************************************/
  61. CTest::CTest()
  62. {
  63. ref_count = 1;
  64. custom = NULL;
  65. }
  66. /***************************************************************************/
  67. CTest::~CTest()
  68. {
  69. if (custom != NULL)
  70. {
  71. custom->Release();
  72. custom = NULL;
  73. }
  74. }
  75. /***************************************************************************/
  76. STDMETHODIMP CTest::sick( ULONG val )
  77. {
  78. TRY
  79. {
  80. THROW( CException(val) );
  81. }
  82. CATCH( CException, exp )
  83. {
  84. }
  85. END_CATCH;
  86. return S_OK;
  87. }
  88. /***************************************************************************/
  89. STDMETHODIMP CTest::die_cpp( ULONG val )
  90. {
  91. THROW( CException(val) );
  92. return S_OK;
  93. }
  94. /***************************************************************************/
  95. STDMETHODIMP CTest::die_nt( ULONG val )
  96. {
  97. RaiseException( val, 0, 0, NULL );
  98. return S_OK;
  99. }
  100. /***************************************************************************/
  101. STDMETHODIMP_(DWORD) CTest::die( ITest *callback, ULONG catch_depth,
  102. ULONG throw_depth, ULONG throw_val )
  103. {
  104. if (catch_depth == 0)
  105. {
  106. TRY
  107. {
  108. return callback->die( this, catch_depth - 1, throw_depth - 1, throw_val );
  109. }
  110. CATCH( CException, exp )
  111. {
  112. #if DBG==1
  113. if (DebugCoGetRpcFault() != throw_val)
  114. {
  115. printf( "Propogated server fault was returned as 0x%x not 0x%x\n",
  116. DebugCoGetRpcFault(), throw_val );
  117. // return FALSE;
  118. }
  119. #endif
  120. return TRUE;
  121. }
  122. END_CATCH
  123. }
  124. else if (throw_depth == 0)
  125. {
  126. THROW( CException(throw_val) );
  127. }
  128. else
  129. return callback->die( this, catch_depth - 1, throw_depth - 1, throw_val );
  130. return FALSE;
  131. }
  132. /***************************************************************************/
  133. STDMETHODIMP CTest::interrupt( ITest *param, BOOL go )
  134. {
  135. global_interrupt_test = go;
  136. if (go)
  137. {
  138. global_test = param;
  139. global_test->AddRef();
  140. WhatNext = interrupt_wn;
  141. wake_up_and_smell_the_roses();
  142. }
  143. else
  144. WhatNext = wait_wn;
  145. return S_OK;
  146. }
  147. /***************************************************************************/
  148. STDMETHODIMP_(BOOL) CTest::hello()
  149. {
  150. if (GetCurrentThreadId() == MainThread)
  151. printf( "Hello on the main thread.\n" );
  152. else
  153. printf( "Hello on thread %d.\n", GetCurrentThreadId );
  154. return !InterruptTestDone;
  155. }
  156. /***************************************************************************/
  157. STDMETHODIMP CTest::recurse( ITest *callback, ULONG depth )
  158. {
  159. if (depth == 0)
  160. return S_OK;
  161. else
  162. return callback->recurse( this, depth-1 );
  163. }
  164. /***************************************************************************/
  165. STDMETHODIMP CTest::recurse_interrupt( ITest *callback, ULONG depth )
  166. {
  167. MSG msg;
  168. if (PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ))
  169. {
  170. TranslateMessage (&msg);
  171. DispatchMessage (&msg);
  172. }
  173. if (depth == 0)
  174. return S_OK;
  175. else
  176. return callback->recurse( this, depth-1 );
  177. }
  178. /***************************************************************************/
  179. STDMETHODIMP CTest::sleep( ULONG time )
  180. {
  181. // For single threaded mode, verify that this is the only call on the
  182. // main thread.
  183. NestedCallCount += 1;
  184. printf( "Sleeping on thread %d for the %d time concurrently.\n",
  185. GetCurrentThreadId(), NestedCallCount );
  186. if (thread_mode == COINIT_SINGLETHREADED)
  187. {
  188. if (GetCurrentThreadId() != MainThread)
  189. {
  190. printf( "Sleep called on the wrong thread in single threaded mode.\n" );
  191. NestedCallCount -= 1;
  192. return FALSE;
  193. }
  194. else if (NestedCallCount != 1)
  195. {
  196. printf( "Sleep nested call count is %d instead of not 1 in single threaded mode.\n",
  197. NestedCallCount );
  198. NestedCallCount -= 1;
  199. return FALSE;
  200. }
  201. }
  202. // For multithreaded mode, verify that this is not the main thread.
  203. else if (GetCurrentThreadId() == MainThread)
  204. {
  205. printf( "Sleep called on the main thread in multi threaded mode.\n" );
  206. NestedCallCount -= 1;
  207. return FALSE;
  208. }
  209. Sleep( time );
  210. NestedCallCount -= 1;
  211. return S_OK;
  212. }
  213. /***************************************************************************/
  214. STDMETHODIMP_(DWORD) CTest::DoTest( ITest *test, ITest *another )
  215. {
  216. HRESULT result;
  217. int i;
  218. BOOL success;
  219. HANDLE helper[MAX_THREADS];
  220. DWORD thread_id;
  221. DWORD status;
  222. // Let the server throw and exception and catch it before returning.
  223. result = test->sick( 95 );
  224. if (result != S_OK)
  225. {
  226. printf( "Internal server fault was not dealt with correctly.\n" );
  227. return FALSE;
  228. }
  229. // Let the server throw a C++ exception here.
  230. result = test->die_cpp( 0xdeaff00d );
  231. if (result != RPC_E_FAULT)
  232. {
  233. printf( "C++ server fault was not dealt with correctly.\n" );
  234. return FALSE;
  235. }
  236. #if DBG==1
  237. if (DebugCoGetRpcFault() != 0xdeaff00d)
  238. {
  239. printf( "C++ server fault was returned as 0x%x not 0x%x\n",
  240. DebugCoGetRpcFault(), 0xdeaff00d );
  241. // return FALSE;
  242. }
  243. #endif
  244. // Let the server throw a NT exception here.
  245. result = test->die_nt( 0xaaaabdbd );
  246. if (result != RPC_E_FAULT)
  247. {
  248. printf( "NT server fault was not dealt with correctly.\n" );
  249. return FALSE;
  250. }
  251. #if DBG==1
  252. if (DebugCoGetRpcFault() != 0xaaaabdbd)
  253. {
  254. printf( "C++ server fault was returned as 0x%x not 0x%x\n",
  255. DebugCoGetRpcFault(), 0xaaaabdbd );
  256. return FALSE;
  257. }
  258. #endif
  259. // Test a recursive call.
  260. result = test->recurse( this, 10 );
  261. if (result != S_OK)
  262. {
  263. printf( "Recursive call failed: 0x%x\n", result );
  264. return FALSE;
  265. }
  266. // Test throwing and immediately catching an exception.
  267. //success = test->die( this, 2, 3, 0x12345678 );
  268. //if (!success)
  269. //{
  270. // printf( "Could not catch server exception.\n" );
  271. // return FALSE;
  272. //}
  273. // Test throwing, propogating, and then catching an exception.
  274. // success = test->die( this, 1, 3, 0x87654321 );
  275. //if (!success)
  276. //{
  277. // printf( "Could not catch propogated server exception.\n" );
  278. // return FALSE;
  279. //}
  280. // Test multiple threads.
  281. Multicall_Test = TRUE;
  282. for (i = 0; i < MAX_THREADS; i++)
  283. {
  284. helper[i] = CreateThread( NULL, 0, ThreadHelper, test, 0, &thread_id );
  285. if (helper == NULL)
  286. {
  287. printf( "Could not create helper thread number %d.\n", i );
  288. return FALSE;
  289. }
  290. }
  291. result = test->sleep(4000);
  292. if (result != S_OK)
  293. {
  294. printf( "Multiple call failed on main thread: 0x%x\n", result );
  295. return FALSE;
  296. }
  297. status = WaitForMultipleObjects( MAX_THREADS, helper, TRUE, INFINITE );
  298. if (status == WAIT_FAILED)
  299. {
  300. printf( "Could not wait for helper threads to die: 0x%x\n", status );
  301. return FALSE;
  302. }
  303. if (!Multicall_Test)
  304. {
  305. printf( "Multiple call failed on helper thread.\n" );
  306. return FALSE;
  307. }
  308. // See if methods can correctly call GetMessage.
  309. another->interrupt( test, TRUE );
  310. result = test->recurse_interrupt( this, 10 );
  311. if (result != S_OK)
  312. {
  313. printf( "Recursive call with interrupts failed: 0x%x\n", result );
  314. return FALSE;
  315. }
  316. another->interrupt( test, FALSE );
  317. // Finally, its all over.
  318. return TRUE;
  319. }
  320. /***************************************************************************/
  321. STDMETHODIMP CTest::QueryInterface( THIS_ REFIID riid, LPVOID FAR* ppvObj)
  322. {
  323. if (IsEqualIID(riid, IID_IUnknown) ||
  324. IsEqualIID(riid, IID_ITest))
  325. {
  326. *ppvObj = (IUnknown *) this;
  327. AddRef();
  328. return S_OK;
  329. }
  330. else if (IsEqualIID( riid, IID_IMarshal))
  331. {
  332. if (custom == NULL)
  333. {
  334. custom = new CCMarshal;
  335. if (custom == NULL)
  336. return E_FAIL;
  337. }
  338. *ppvObj = (IMarshal *) custom;
  339. custom->AddRef();
  340. return S_OK;
  341. }
  342. else
  343. {
  344. *ppvObj = NULL;
  345. return E_NOINTERFACE;
  346. }
  347. }
  348. /***************************************************************************/
  349. STDMETHODIMP_(ULONG) CTest::Release( THIS )
  350. {
  351. if (InterlockedDecrement( (long*) &ref_count ) == 0)
  352. {
  353. WhatNext = quit_wn;
  354. wake_up_and_smell_the_roses();
  355. delete this;
  356. return 0;
  357. }
  358. else
  359. return ref_count;
  360. }
  361. /***************************************************************************/
  362. STDMETHODIMP_(ULONG) CTestCF::AddRef( THIS )
  363. {
  364. InterlockedIncrement( (long *) &ref_count );
  365. return ref_count;
  366. }
  367. /***************************************************************************/
  368. CTestCF::CTestCF()
  369. {
  370. ref_count = 1;
  371. }
  372. /***************************************************************************/
  373. CTestCF::~CTestCF()
  374. {
  375. }
  376. /***************************************************************************/
  377. STDMETHODIMP CTestCF::CreateInstance(
  378. IUnknown FAR* pUnkOuter,
  379. REFIID iidInterface,
  380. void FAR* FAR* ppv)
  381. {
  382. *ppv = NULL;
  383. if (pUnkOuter != NULL)
  384. {
  385. return E_FAIL;
  386. }
  387. if (!IsEqualIID( iidInterface, IID_ITest ))
  388. return E_NOINTERFACE;
  389. CTest *Test = new FAR CTest();
  390. if (Test == NULL)
  391. {
  392. return E_OUTOFMEMORY;
  393. }
  394. *ppv = Test;
  395. return S_OK;
  396. }
  397. /***************************************************************************/
  398. STDMETHODIMP CTestCF::LockServer(BOOL fLock)
  399. {
  400. return E_FAIL;
  401. }
  402. /***************************************************************************/
  403. STDMETHODIMP CTestCF::QueryInterface( THIS_ REFIID riid, LPVOID FAR* ppvObj)
  404. {
  405. if (IsEqualIID(riid, IID_IUnknown) ||
  406. IsEqualIID(riid, IID_IClassFactory))
  407. {
  408. *ppvObj = (IUnknown *) this;
  409. AddRef();
  410. return S_OK;
  411. }
  412. *ppvObj = NULL;
  413. return E_NOINTERFACE;
  414. }
  415. /***************************************************************************/
  416. STDMETHODIMP_(ULONG) CTestCF::Release( THIS )
  417. {
  418. if (InterlockedDecrement( (long*) &ref_count ) == 0)
  419. {
  420. delete this;
  421. return 0;
  422. }
  423. else
  424. return ref_count;
  425. }
  426. /***************************************************************************/
  427. void interrupt()
  428. {
  429. while (global_interrupt_test)
  430. {
  431. global_test->hello();
  432. check_for_request();
  433. }
  434. global_test->Release();
  435. }
  436. //+--------------------------------------------------------------
  437. // Function: Main
  438. //
  439. // Synopsis: Executes the BasicBnd test
  440. //
  441. // Effects: None
  442. //
  443. //
  444. // Returns: Exits with exit code 0 if success, 1 otherwise
  445. //
  446. // History: 05-Mar-92 Sarahj Created
  447. //
  448. //---------------------------------------------------------------
  449. int _cdecl main(int argc, char *argv[])
  450. {
  451. HRESULT result;
  452. DWORD wrong;
  453. BOOL success = TRUE;
  454. ITest *another = NULL;
  455. ITest *test = NULL;
  456. CTest *tester = new CTest;
  457. // Initialize Globals.
  458. MainThread = GetCurrentThreadId();
  459. // Create an event for termination notification.
  460. Done = CreateEvent( NULL, FALSE, FALSE, NULL );
  461. if (Done == NULL)
  462. {
  463. printf( "Could not create event.\n" );
  464. success = FALSE;
  465. goto exit_main;
  466. }
  467. int len;
  468. TCHAR buffer[80];
  469. // Look up the thread mode from the win.ini file.
  470. len = GetProfileString( L"My Section", L"ThreadMode", L"MultiThreaded", buffer,
  471. sizeof(buffer) );
  472. if (lstrcmp(buffer, L"SingleThreaded") == 0)
  473. {
  474. thread_mode = COINIT_SINGLETHREADED;
  475. wrong = COINIT_MULTITHREADED;
  476. printf( "Testing channel in single threaded mode.\n" );
  477. }
  478. else if (lstrcmp(buffer, L"MultiThreaded") == 0)
  479. {
  480. thread_mode = COINIT_MULTITHREADED;
  481. wrong = COINIT_SINGLETHREADED;
  482. printf( "Testing channel in multithreaded mode.\n" );
  483. }
  484. // Initialize OLE.
  485. result = OleInitializeEx(NULL, thread_mode);
  486. if (!SUCCEEDED(result))
  487. {
  488. success = FALSE;
  489. printf( "OleInitializeEx failed: %x\n", result );
  490. goto exit_main;
  491. }
  492. result = CoInitializeEx(NULL, thread_mode);
  493. if (!SUCCEEDED(result))
  494. {
  495. success = FALSE;
  496. printf( "Recalling CoInitializeEx failed: %x\n", result );
  497. goto exit_main;
  498. }
  499. result = CoInitializeEx(NULL, wrong);
  500. if (result == S_OK)
  501. {
  502. success = FALSE;
  503. printf( "Recalling CoInitializeEx with wrong thread mode succeeded: %x\n", result );
  504. goto exit_main;
  505. }
  506. CoUninitialize();
  507. CoUninitialize();
  508. // If this is a server app, register and wait for a quit message.
  509. if (argv[1] == NULL)
  510. server = FALSE;
  511. else
  512. server = strcmp( argv[1], "-Embedding" ) == 0;
  513. if (server)
  514. {
  515. success = server_loop( );
  516. }
  517. // Initialize and run the tests.
  518. else
  519. {
  520. // Get a test object.
  521. result = CoCreateInstance( CLSID_ITest, NULL, CLSCTX_LOCAL_SERVER,
  522. IID_ITest, (void **) &test );
  523. if (!SUCCEEDED(result))
  524. {
  525. printf( "Could not create instance of test server: %x\n", result );
  526. success = FALSE;
  527. goto exit_main;
  528. }
  529. // Get another test object.
  530. result = CoCreateInstance( CLSID_ITest, NULL, CLSCTX_LOCAL_SERVER,
  531. IID_ITest, (void **) &another );
  532. if (!SUCCEEDED(result))
  533. {
  534. printf( "Could not create another instance of test server: %x\n", result );
  535. success = FALSE;
  536. goto exit_main;
  537. }
  538. success = tester->DoTest( test, another );
  539. }
  540. exit_main:
  541. // Release the external test objects used.
  542. if (test != NULL)
  543. test->Release();
  544. if (another != NULL)
  545. another->Release();
  546. // Release the internal test object.
  547. tester->Release();
  548. //wait_for_message();
  549. OleUninitialize();
  550. if (!server)
  551. if (success)
  552. printf("\nChannel Unit Test: PASSED\n");
  553. else
  554. printf("\nChannel Unit Test: FAILED\n");
  555. return !success;
  556. }
  557. //+--------------------------------------------------------------
  558. void check_for_request()
  559. {
  560. MSG msg;
  561. if (thread_mode == COINIT_SINGLETHREADED)
  562. {
  563. if (PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ))
  564. {
  565. TranslateMessage (&msg);
  566. DispatchMessage (&msg);
  567. }
  568. }
  569. }
  570. //+--------------------------------------------------------------
  571. BOOL server_loop( )
  572. {
  573. HRESULT result;
  574. DWORD dwRegistration;
  575. // Create our class factory
  576. WhatNext = wait_wn;
  577. CTestCF *test_cf = new CTestCF();
  578. // Register our class with OLE
  579. result = CoRegisterClassObject(CLSID_ITest, test_cf, CLSCTX_LOCAL_SERVER,
  580. REGCLS_SINGLEUSE, &dwRegistration);
  581. if (!SUCCEEDED(result))
  582. {
  583. printf( "CoRegisterClassObject failed: %x\n", result );
  584. return FALSE;
  585. }
  586. // CoRegister bumps reference count so we don't have to!
  587. test_cf->Release();
  588. // Do whatever we have to do till it is time to pay our taxes and die.
  589. while (WhatNext != quit_wn)
  590. switch (WhatNext)
  591. {
  592. // Wait till a quit arrives.
  593. case wait_wn:
  594. wait_for_message();
  595. break;
  596. case interrupt_wn:
  597. interrupt();
  598. break;
  599. }
  600. // Deregister out class - should release object as well
  601. result = CoRevokeClassObject(dwRegistration);
  602. if (!SUCCEEDED(result))
  603. {
  604. printf( "CoRevokeClassObject failed: %x\n", result );
  605. return FALSE;
  606. }
  607. return TRUE;
  608. }
  609. /***************************************************************************/
  610. DWORD _stdcall ThreadHelper( void *param )
  611. {
  612. ITest *test = (ITest *) param;
  613. HRESULT result;
  614. // Call the server.
  615. result = test->sleep( 2000 );
  616. // Check the result for single threaded mode.
  617. if (thread_mode == COINIT_SINGLETHREADED)
  618. {
  619. if (SUCCEEDED(result))
  620. {
  621. Multicall_Test = FALSE;
  622. printf( "Call succeeded on wrong thread in single threaded mode: 0x%x.\n",
  623. result );
  624. }
  625. #if DBG==1
  626. else if (DebugCoGetRpcFault() != RPC_E_ATTEMPTED_MULTITHREAD)
  627. {
  628. printf( "Multithread failure code was 0x%x not 0x%x\n",
  629. DebugCoGetRpcFault(), RPC_E_ATTEMPTED_MULTITHREAD );
  630. Multicall_Test = FALSE;
  631. }
  632. #endif
  633. }
  634. // Check the result for multithreaded mode.
  635. else if (result != S_OK)
  636. {
  637. printf( "Could not make multiple calls in multithreaded mode: 0x%x\n",
  638. result );
  639. Multicall_Test = FALSE;
  640. }
  641. #define DO_DA 42
  642. return DO_DA;
  643. }
  644. /***************************************************************************/
  645. void wait_for_message()
  646. {
  647. MSG msg;
  648. DWORD status;
  649. if (thread_mode == COINIT_MULTITHREADED)
  650. {
  651. status = WaitForSingleObject( Done, INFINITE );
  652. if (status != WAIT_OBJECT_0 )
  653. {
  654. printf( "Could not wait for event.\n" );
  655. }
  656. }
  657. else
  658. {
  659. while (GetMessage( &msg, NULL, 0, 0 ) && msg.message != WM_USER)
  660. {
  661. TranslateMessage (&msg);
  662. DispatchMessage (&msg);
  663. }
  664. }
  665. }
  666. /***************************************************************************/
  667. void wake_up_and_smell_the_roses()
  668. {
  669. if (thread_mode == COINIT_MULTITHREADED)
  670. SetEvent( Done );
  671. else
  672. PostThreadMessage(MainThread, WM_USER, 0, 0);
  673. }