home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / com / dcom / comperf / comperf.cpp next >
C/C++ Source or Header  |  1996-07-29  |  50KB  |  1,614 lines

  1. // ===========================================================================
  2. // File: C O M P E R F . C P P
  3. #define PURPOSE "This is the reference performance sample for COM/DCOM run on local\n\
  4. and remote machines. This program is both a client and a server.\n\
  5. It launches as a client by default, registering its executable as a\n\
  6. server with COM and creating other instances of itself on a remote and\n\
  7. local machine to be servers. A single command-line argument is allowed\n\
  8. for a remote server name. Performance numbers in calls/sec are output\n\
  9. in tabular form. Tests COM and IDispatch method calls with two security\n\
  10. levels: default/min and full. Use DCOMCNFG to set default security to \n\
  11. Authn Lvl to NONE for best comparison. Parameter sizes are varied to see\n\
  12. effect on security levels(~4/50/4k bytes). Uses psoleperf.dll MIDL generated\n\
  13. proxy/stub implementation. Put pscomperf.dll in same dir as this exe on\n\
  14. all machines. Run exe on each machine to automatically register class code\n\
  15. and proxy/stub dll. You can then run on either machine and pass a remote\n\
  16. machine name (DNS or IP address) as single cmd-line parameter.\n\n" 
  17.  
  18. // Instructions:
  19. // Install on one or more machines as described above. Run on command-line as "comperf".
  20. // A single command-line argument is allowed for a remote server name. E.g.
  21. // "comperf MyComputer" or "comperf 123.44.44.234" using IP address.
  22. // This sample may be compiled as UNICODE or ANSI
  23. // 
  24. // Copyright 1996 Microsoft Corporation.  All Rights Reserved.
  25. // ===========================================================================
  26.  
  27. // %%Includes: ---------------------------------------------------------------
  28. #define INC_OLE2
  29. #define STRICT
  30. #define LOOPS 2000  // default number of test function calls
  31. #include <windows.h>
  32. #include <initguid.h>
  33. #include <tchar.h>
  34. #include <stdio.h>
  35. #include "psperf.h" // MIDL generated header
  36.  
  37. // %%Constants: --------------------------------------------------------------
  38. #define cServerThreads  3 // number support threads each server will generate
  39. #define dispidICOMPerformance_Test1  11
  40. #define dispidICOMPerformance_Test23  12
  41. #define szTitleServer   TEXT("SERVER: COM Performance Sample")
  42. #define szTitleClient   TEXT("COM Performance Sample")
  43. const LARGE_INTEGER     bZero = {0,0};
  44.  
  45. // %%IDispatch support
  46. PARAMDATA paramdata[2] = {{L"i", VT_I4},{L"bstr", VT_BSTR}}; 
  47. METHODDATA methoddata[2] = {{L"Test1", ¶mdata[0], 11, 3, CC_CDECL, 1, DISPATCH_METHOD, VT_I4},
  48.             {L"Test23", ¶mdata[1], 12, 4, CC_CDECL, 1, DISPATCH_METHOD, VT_I4}};
  49. INTERFACEDATA interfacedata = { methoddata, 2 };
  50.  
  51. // %%Guids: ------------------------------------------------------------------
  52. // {DDC68870-E08E-11cf-A535-00AA00615B03}
  53. DEFINE_GUID(CLSID_CTestCOMPerformance,0xddc68870,0xe08e,0x11cf,0xa5,0x35,0x0,0xaa,0x0,0x61,0x5b,0x3);
  54.  
  55. // %%typedefs: --------------------------------------------------------------
  56. typedef HRESULT (WINAPI *LPFNREG)();
  57. typedef struct  perf 
  58. {
  59.     TCHAR   *szTest;
  60.     float    sec[3]; // time for all three methods in ICOMPerformance
  61. } PERF;
  62.  
  63. // %%Globals: ----------------------------------------------------------------
  64. BOOL        vfServer = FALSE;               // is this instance a server or client?
  65. BOOL        vfRemote = FALSE;               // is there a remote server?
  66. HANDLE      vrghThread[cServerThreads];     // worker thread handles
  67. DWORD       vrgtid[cServerThreads];         // worker thread id's
  68. HANDLE      vrghEvent[cServerThreads];      // creation event for each worker
  69. HANDLE          vhEventCliDone;
  70. HANDLE      vhEventServer;                  // creation-complete event for class-factory
  71. HANDLE          vhEventCliStart;
  72. HANDLE          hKillSvr;                       // shuts down the server  
  73. UINT        viNextThread;                   // next worker to create an object on
  74. UINT            g_cObjectCount = 0;
  75. LPSTREAM    vpstmMarshalling;               // scratch stream used for cross-apt marshalling
  76. HRESULT     vhrThreadStatus;                // signals status to class-factory
  77.  
  78. LPWSTR pszDesc1 = L"String is passed to Test methd of ICOMPerformance";
  79.  
  80. PERF    vrgperfloc[] = {
  81.     { TEXT("COM FreeToApt"), {-1.0f,-1.0f,-1.0f}},
  82.     { TEXT("IDisp FreeToApt"), {-1.0f,-1.0f,-1.0f}},
  83.     { TEXT("COM FreeTo Free"), {-1.0f,-1.0f,-1.0f}},
  84.     { TEXT("IDispFreeToFree"), {-1.0f,-1.0f,-1.0f}},
  85.     { TEXT("COM AptToApt"), {-1.0f,-1.0f,-1.0f}},
  86.     { TEXT("IDispAptToApt"), {-1.0f,-1.0f,-1.0f}},
  87.     { NULL, {-1.0f,-1.0f,-1.0f}} };
  88.  
  89. PERF    vrgperfrmt[] = {
  90.     { TEXT("COM FreeToApt"), {-1.0f,-1.0f,-1.0f}},
  91.     { TEXT("IDisp FreeToApt"), {-1.0f,-1.0f,-1.0f}},
  92.     { TEXT("COM FreeTo Free"), {-1.0f,-1.0f,-1.0f}},
  93.     { TEXT("IDispFreeToFree"), {-1.0f,-1.0f,-1.0f}},
  94.     { TEXT("COM AptToApt"), {-1.0f,-1.0f,-1.0f}},
  95.     { TEXT("IDispAptToApt"), {-1.0f,-1.0f,-1.0f}},
  96.     { NULL, {-1.0f,-1.0f,-1.0f}} };         
  97.  
  98. // %%Prototypes: -------------------------------------------------------------
  99. LRESULT     ServerThreadProc(LPARAM lParam);
  100. LRESULT     ClientThreadProc(LPARAM lParam);
  101. BOOL        FAutoRegister();
  102. void            Message(LPTSTR szPrefix, HRESULT hr);
  103. void            FPrintResults(void);
  104. BOOL        AptFreeCOMTest(int cLoops);
  105. BOOL            AptFreeAutoTest(int cLoops);
  106. BOOL            FreeFreeCOMTest(int cLoops);
  107. BOOL            FreeFreeAutoTest(int cLoops);
  108. BOOL            DoTests(void);
  109. void            Usage(void);
  110.  
  111. typedef IClientSecurity *LPCLIENTSECURITY;
  112. typedef ICOMPerformance *LPCOMPERFORMANCE;
  113. LPCOMPERFORMANCE pCOMApt, pCOMFree, pCOMAptRmt, pCOMFreeRmt; 
  114. LPDISPATCH pAutoApt, pAutoFree, pAutoAptRmt, pAutoFreeRmt; 
  115.  
  116. // %%Classes: ----------------------------------------------------------------
  117. // the class-factory object exists in the main application apartment/thread
  118. // and is used to create instances of the worker objects on worker threads.
  119. class CClassFactory : public IClassFactory
  120. {
  121. public:  
  122.     // IClassFactory
  123.     STDMETHODIMP            QueryInterface(REFIID iid, void **ppv);
  124.     STDMETHODIMP_(ULONG)    AddRef(void)  { return m_cRef++; }
  125.     STDMETHODIMP_(ULONG)    Release(void) { if (--m_cRef == 0){ delete this; return 0; } return m_cRef;}
  126.     STDMETHODIMP            CreateInstance(LPUNKNOWN punkOuter, REFIID iid, void **ppv);
  127.     STDMETHODIMP            LockServer(BOOL fLock);
  128.     
  129.     CClassFactory() { m_cRef = 1; }
  130. private:
  131.     ULONG   m_cRef;
  132. };
  133.  
  134. // this worker object is simple: it simply supports IUnknown. more interesting
  135. // interfaces can be readily added here and implemented for the worker.
  136. class CTestCOMPerformance : public ICOMPerformance , public IDispatch
  137. {
  138. public:
  139.     // IUnknown
  140.     STDMETHODIMP            QueryInterface(REFIID iid, void **ppv);
  141.     STDMETHODIMP_(ULONG)    AddRef(void)    { return m_cRef++; }
  142.     STDMETHODIMP_(ULONG)    Release(void);
  143.  
  144.     // ICOMPerformance
  145.     STDMETHODIMP                    Test1(int l);
  146.     STDMETHODIMP                        Test23(BSTR szDesc);
  147.     
  148.     // IDispatch
  149.     STDMETHODIMP  GetTypeInfoCount(unsigned int  *pcti);
  150.     STDMETHODIMP  GetTypeInfo(unsigned int iti, LCID lcid, LPTYPEINFO  *ppti);
  151.     STDMETHODIMP  GetIDsOfNames(REFIID riid, WCHAR  *  *rgszNames, unsigned int cNames, LCID lcid, DISPID  *pdispid);
  152.     STDMETHODIMP  Invoke(DISPID dispidMember, REFIID riid, LCID lcid, unsigned short wFlags,
  153.          DISPPARAMS  *pdispparams, VARIANT  *pvarResult, EXCEPINFO  *pexcepinfo, unsigned int  *puArgErr);
  154.  
  155.     CTestCOMPerformance() { m_cRef = 1;}
  156. private:
  157.     ULONG   m_cRef;
  158. };
  159.  
  160. class CTIMER 
  161. {
  162.   public:
  163.     inline CTIMER()              { memset(this, 0, sizeof(*this)); }
  164.     inline void Start()  { QueryPerformanceCounter(&m_sStart); }
  165.     inline void Stop()   { QueryPerformanceCounter(&m_sStop); }
  166.     inline float OutputTime()       { QueryPerformanceFrequency(&m_liFreq); 
  167.             return (float)(( m_sStop.LowPart - m_sStart.LowPart)/(float)m_liFreq.LowPart);}
  168.     // data members
  169.     LARGE_INTEGER   m_sStart, m_sStop, m_liFreq;
  170. };
  171.  
  172. // ---------------------------------------------------------------------------
  173. // %%Function: Message
  174. // 
  175. //  Formats and displays a message to the console.
  176. // ---------------------------------------------------------------------------
  177.  void
  178. Message(LPTSTR szPrefix, HRESULT hr)
  179. {
  180.     LPTSTR   szMessage;
  181.  
  182.     if (hr == S_OK)
  183.     {
  184.     _tprintf(szPrefix);
  185.     _tprintf(TEXT("\n"));
  186.     return;
  187.     }
  188.  
  189.     if (HRESULT_FACILITY(hr) == FACILITY_WINDOWS)
  190.     hr = HRESULT_CODE(hr);
  191.  
  192.     FormatMessage(
  193.     FORMAT_MESSAGE_ALLOCATE_BUFFER |
  194.     FORMAT_MESSAGE_FROM_SYSTEM,
  195.     NULL,
  196.     hr,
  197.     MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), //The user default language
  198.     (LPTSTR)&szMessage,
  199.     0,
  200.     NULL );
  201.  
  202.     _tprintf(TEXT("%s: %s(%lx)\n"), szPrefix, szMessage, hr);
  203.     LocalFree(szMessage);
  204. }  // Message
  205.  
  206. // ---------------------------------------------------------------------------
  207. // %%Function: main 
  208. // ---------------------------------------------------------------------------
  209.  int __cdecl
  210. main(int argc, CHAR **argv)
  211. {
  212.     HRESULT hr;
  213.     int     i;
  214.     DWORD   dwRegister = 0;
  215.     COSERVERINFO csi, *pcsi=NULL;
  216.     WCHAR wsz [MAX_PATH];
  217.     CClassFactory   *pcf = NULL;
  218.     LPCLASSFACTORY pcflocal = NULL;
  219.     LPCLASSFACTORY pcfrmt = NULL;
  220.     LPCLIENTSECURITY pclntsec = NULL; 
  221.     TCHAR    rgch[32];      
  222.     
  223.     DWORD AuthnSvc, AuthzSvc, AuthnLvl, ImpLvl, Capabilities;
  224.  
  225.     
  226.     if(!FAutoRegister())
  227.     {
  228.         exit(-1);
  229.     }
  230.     // parse command-line
  231.     if (argc > 1)
  232.     {
  233.     // either started as server or passing in server name
  234.     MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, argv[1], -1,
  235.         wsz, MAX_PATH);
  236.  
  237.         // register the CTestCOMPerformance class in the registry so
  238.         // that the client can create instances of the server
  239.         if((!lstrcmpW(L"-?", wsz)) || (!lstrcmpW(L"/?", wsz)))
  240.         {
  241.             Usage();
  242.             return 0;
  243.         }
  244.         if(!lstrcmpW(L"-Embedding", wsz))
  245.             vfServer = TRUE;
  246.         else
  247.         {
  248.             // allow a machine-name as the command-line argument
  249.             csi.dwReserved1 = 0;
  250.             csi.pAuthInfo = NULL;
  251.             csi.dwReserved2 = 0;
  252.             csi.pwszName = wsz;
  253.             pcsi = &csi;
  254.             vfRemote = TRUE;
  255.         }
  256.     }
  257.     if(vfServer)
  258.         Message(szTitleServer, S_OK);
  259.     else
  260.         Message(szTitleClient, S_OK);
  261.         
  262.     // initialize COM
  263.     hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
  264.     if (FAILED(hr))
  265.     {
  266.     Message(TEXT("CoInitializeEx"), hr);
  267.         exit(hr);
  268.     }
  269.  
  270.     // create an IStream to be used for marshalling interfaces
  271.     hr = CreateStreamOnHGlobal(NULL, TRUE, &vpstmMarshalling);
  272.     if (FAILED(hr))
  273.     {
  274.         Message(TEXT("CreateStreamOnHGlobal"), hr);
  275.     goto LCleanup;
  276.     }
  277.  
  278.     if (vfServer)
  279.     {
  280.     // create the threads and synchronization events
  281.     // which the server will need
  282.     for (i=0; i<cServerThreads; i++)
  283.     {
  284.         // create the thread suspended so its event can be
  285.         // created using its thread-id and it will be able to
  286.         // use it as soon as it runs
  287.         vrghThread[i] = CreateThread(NULL,
  288.         0,
  289.         (LPTHREAD_START_ROUTINE)&ServerThreadProc,
  290.         0,
  291.         CREATE_SUSPENDED,
  292.         &vrgtid[i]);
  293.         if (vrghThread[i] == NULL)
  294.         {
  295.         hr = GetLastError();
  296.         goto LCleanup;
  297.         }
  298.  
  299.         // this event signals to a worker thread to create a new CTestCOMPerformance
  300.         wsprintf(rgch, TEXT("Thread_%d"), vrgtid[i]);
  301.         vrghEvent[i] = CreateEvent(NULL, FALSE, FALSE, rgch);
  302.         if (vrghEvent[i] == NULL)
  303.         {
  304.         hr = GetLastError();
  305.         goto LCleanup;
  306.         }
  307.         // now that the event is available, let the thread run
  308.         ResumeThread(vrghThread[i]);
  309.         }
  310.         hKillSvr = CreateEvent(NULL, FALSE, FALSE, NULL);
  311.     if (hKillSvr == NULL)
  312.         {
  313.         hr = GetLastError();
  314.         goto LCleanup;
  315.      }
  316.  
  317.     // this signals the status of a worker threads creation after
  318.     // receiving its create signal via vrghEvent[i]
  319.     vhEventServer = CreateEvent(NULL, FALSE, FALSE, TEXT("Server"));
  320.     if (vhEventServer == NULL)
  321.     {
  322.         hr = GetLastError();
  323.         goto LCleanup;
  324.     }
  325.         pcf = new CClassFactory;
  326.         if(pcf == NULL)
  327.     {
  328.         hr = E_OUTOFMEMORY;
  329.         goto LCleanup;
  330.     }
  331.  
  332.     // register the class-factory with COM
  333.     hr = CoRegisterClassObject(CLSID_CTestCOMPerformance,
  334.         (IUnknown *)pcf,
  335.         CLSCTX_LOCAL_SERVER,
  336.         REGCLS_MULTIPLEUSE,
  337.         &dwRegister);
  338.     if (FAILED(hr))
  339.         {
  340.             Message(TEXT("CoRegisterClassObject"), hr);
  341.         goto LCleanup;
  342.         }
  343.         
  344.         Message(TEXT("Server waiting"), S_OK);
  345.         WaitForSingleObject(hKillSvr, INFINITE);
  346.         Sleep(7000); // allow time for last Release call processing
  347.          delete pcf;
  348.         pcf = NULL;
  349.     }
  350.  
  351.     else // client case 
  352.     {
  353.         pCOMApt = pCOMFree = pCOMAptRmt =pCOMFreeRmt = NULL; 
  354.         pAutoFree = pAutoFree = pAutoAptRmt = pAutoFreeRmt = NULL; 
  355.         
  356.         // get local class factory
  357.     hr = CoGetClassObject(CLSID_CTestCOMPerformance, CLSCTX_LOCAL_SERVER, NULL,
  358.             IID_IClassFactory, (void**)&pcflocal);
  359.         if(FAILED(hr))
  360.         {
  361.             Message(TEXT("CoGetClassObject:"), hr);
  362.             goto LCleanup;
  363.         }
  364.         // apt-model obj
  365.         hr = pcflocal->CreateInstance(NULL, IID_ICOMPerformance, (void**)&pCOMApt);
  366.     if (FAILED(hr))
  367.         {
  368.             Message(TEXT("Create Local Apt Instance:"), hr);
  369.             goto LCleanup;
  370.         }
  371.         hr = pCOMApt->QueryInterface(IID_IDispatch, (void**)&pAutoApt);
  372.         if (FAILED(hr))
  373.         {
  374.             Message(TEXT("QI for pAutoApt:"), hr);
  375.             goto LCleanup;
  376.         }
  377.         // get free-threaded obj
  378.         hr = pcflocal->CreateInstance(NULL, IID_ICOMPerformance, (void**)&pCOMFree);
  379.     if (FAILED(hr))
  380.         {
  381.             Message(TEXT("Create Local Free Instance"), hr);
  382.             goto LCleanup;
  383.         }               
  384.         hr = pCOMFree->QueryInterface(IID_IDispatch, (void**)&pAutoFree);
  385.         if (FAILED(hr))
  386.         {
  387.             Message(TEXT("QI for pAutoFree"), hr);
  388.             goto LCleanup;
  389.         }
  390.         hr = pcflocal->Release();
  391.         pcflocal = NULL;
  392.         if(vfRemote)
  393.         {
  394.             hr = CoGetClassObject(CLSID_CTestCOMPerformance, CLSCTX_REMOTE_SERVER, pcsi,
  395.                 IID_IClassFactory, (void**)&pcfrmt);
  396.             if(FAILED(hr))
  397.             {
  398.                 Message(TEXT("CoGetClassObject for remote CF"), hr);
  399.                 vfRemote = FALSE;
  400.                 goto LContinue;
  401.             }
  402.             // apt-model obj
  403.             hr = pcfrmt->CreateInstance(NULL, IID_ICOMPerformance, (void**)&pCOMAptRmt);
  404.             if (FAILED(hr))
  405.             {
  406.                 Message(TEXT("Create Remote Instance"), hr);
  407.                 goto LCleanup;
  408.             }
  409.             hr = pCOMAptRmt->QueryInterface(IID_IDispatch, (void**)&pAutoAptRmt);
  410.             if (FAILED(hr))
  411.             {
  412.                 Message(TEXT("QI for pAutoAptFreeRmt"), hr);
  413.                 goto LCleanup;
  414.             }
  415.             // get free-threaded obj
  416.             hr = pcfrmt->CreateInstance(NULL, IID_ICOMPerformance, (void**)&pCOMFreeRmt);
  417.             if (FAILED(hr))
  418.             {
  419.                 Message(TEXT("Create Remote Free Instance"), hr);
  420.                 goto LCleanup;
  421.             }
  422.             hr = pCOMFreeRmt->QueryInterface(IID_IDispatch, (void**)&pAutoFreeRmt);
  423.             if (FAILED(hr))
  424.             {
  425.                 Message(TEXT("QI for pAutoFreeFreeRmt"), hr);
  426.                 goto LCleanup;
  427.             }
  428.             hr = pcfrmt->Release();
  429.             pcfrmt = NULL;
  430.         }
  431. LContinue:
  432.         // create apartment thread for client
  433.         DWORD   dwClienttid;
  434.     // create the thread suspended so its event can be
  435.     // created using its thread-id and it will be able to
  436.     // use it as soon as it runs
  437.     HANDLE hClientThread = CreateThread(NULL,
  438.         0,
  439.         (LPTHREAD_START_ROUTINE)&ClientThreadProc,
  440.         0,
  441.         CREATE_SUSPENDED,
  442.         &dwClienttid);
  443.     if (hClientThread == NULL)
  444.     {
  445.         hr = GetLastError();
  446.             goto LCleanup;
  447.     }
  448.         wsprintf(rgch, TEXT("Thread_%d"), dwClienttid);
  449.     
  450.         vhEventCliStart = CreateEvent(NULL, FALSE, FALSE, rgch);
  451.     if (vhEventCliStart == NULL)
  452.     {
  453.         hr = GetLastError();
  454.         goto LCleanup;
  455.     }
  456.         vhEventCliDone = CreateEvent(NULL, FALSE, FALSE, NULL);
  457.     if (vhEventCliDone == NULL)
  458.     {
  459.         hr = GetLastError();
  460.         goto LCleanup;
  461.     }       
  462.         // Marshall local apt thread
  463.         hr = vpstmMarshalling->Seek(bZero, STREAM_SEEK_SET, NULL);
  464.     if (FAILED(hr))
  465.         throw hr;
  466.     hr = CoMarshalInterface(vpstmMarshalling,
  467.         IID_IUnknown,
  468.         (ICOMPerformance*)pCOMApt,
  469.         MSHCTX_INPROC,
  470.         NULL,
  471.         MSHLFLAGS_NORMAL);
  472.     if (FAILED(hr))
  473.         throw hr;
  474.         // now that the event is available, let the thread run
  475.     ResumeThread(hClientThread);
  476.         SetEvent(vhEventCliStart);
  477.         WaitForSingleObject(vhEventCliDone, INFINITE);
  478.         
  479.         if(vfRemote && NULL != pCOMAptRmt)
  480.         {
  481.             // Marshall local apt thread
  482.             hr = vpstmMarshalling->Seek(bZero, STREAM_SEEK_SET, NULL);
  483.             if (FAILED(hr))
  484.                 throw hr;
  485.             hr = CoMarshalInterface(vpstmMarshalling,
  486.                 IID_IUnknown,
  487.                 (ICOMPerformance*)pCOMAptRmt,
  488.                 MSHCTX_INPROC,
  489.                 NULL,
  490.                 MSHLFLAGS_NORMAL);
  491.             if (FAILED(hr))
  492.                 throw hr;
  493.             SetEvent(vhEventCliStart);
  494.             WaitForSingleObject(vhEventCliDone, INFINITE);
  495.         }
  496.         
  497.         // Test
  498.         _tprintf(TEXT("Output in Calls per sec\n"));
  499.         _tprintf(TEXT("DEF Sec:\t\tLOCAL\t\t\tREMOTE\n"));
  500.         // Do all tests
  501.         if(!DoTests())
  502.             goto LCleanup;
  503.         // Up security on proxies
  504.         // Get current security
  505.         hr = pCOMApt->QueryInterface(IID_IClientSecurity, (void**)&pclntsec);
  506.         hr = pclntsec->QueryBlanket(pCOMApt, &AuthnSvc, &AuthzSvc, NULL, &AuthnLvl, &ImpLvl, NULL,
  507.             &Capabilities);
  508.  
  509.         _tprintf(TEXT("Increasing local security from AuthnLvl:%d  ImpLvl:%d\n"), AuthnLvl, ImpLvl);
  510.  
  511.         hr = pclntsec->SetBlanket(pCOMApt, AuthnSvc, AuthzSvc, NULL, 6,
  512.                 4, NULL, Capabilities);
  513.         hr = pclntsec->QueryBlanket(pCOMApt, &AuthnSvc, &AuthzSvc, NULL, &AuthnLvl, &ImpLvl, NULL,
  514.             &Capabilities);
  515.  
  516.         _tprintf(TEXT("Local security is now AuthnLvl:%d  ImpLvl:%d\n"), AuthnLvl, ImpLvl);
  517.  
  518.         pclntsec->Release();
  519.         pclntsec = NULL;
  520.         hr = pCOMFree->QueryInterface(IID_IClientSecurity, (void**)&pclntsec);  
  521.         hr = pclntsec->SetBlanket(pCOMFree, AuthnSvc, AuthzSvc, NULL, 6,
  522.                 4, NULL, Capabilities);
  523.         pclntsec->Release();
  524.         pclntsec = NULL;
  525.         hr = pAutoApt->QueryInterface(IID_IClientSecurity, (void**)&pclntsec);  
  526.         hr = pclntsec->SetBlanket(pAutoApt, AuthnSvc, AuthzSvc, NULL, 6,
  527.                 4, NULL, Capabilities);
  528.         pclntsec->Release();
  529.         pclntsec = NULL;
  530.         hr = pAutoFree->QueryInterface(IID_IClientSecurity, (void**)&pclntsec); 
  531.         hr = pclntsec->SetBlanket(pAutoFree, AuthnSvc, AuthzSvc, NULL, 6,
  532.                 4, NULL, Capabilities);
  533.         pclntsec->Release();
  534.         pclntsec = NULL;
  535.         if(vfRemote)
  536.         {
  537.             hr = pCOMAptRmt->QueryInterface(IID_IClientSecurity, (void**)&pclntsec);        
  538.             hr = pclntsec->QueryBlanket(pCOMAptRmt, &AuthnSvc, &AuthzSvc, NULL, &AuthnLvl, &ImpLvl, NULL,
  539.             &Capabilities);
  540.  
  541.             _tprintf(TEXT("Increasing remote security from AuthnLvl:%d  ImpLvl:%d\n"), AuthnLvl, ImpLvl);
  542.  
  543.             hr = pclntsec->SetBlanket(pCOMAptRmt, AuthnSvc, AuthzSvc, NULL, 6,
  544.                 4, NULL, Capabilities);
  545.  
  546.             _tprintf(TEXT("Remote security is now AuthnLvl:%d  ImpLvl:%d\n"), AuthnLvl, ImpLvl);
  547.  
  548.             pclntsec->Release();
  549.             pclntsec = NULL;
  550.             hr = pCOMFreeRmt->QueryInterface(IID_IClientSecurity, (void**)&pclntsec);       
  551.             hr = pclntsec->SetBlanket(pCOMFreeRmt, AuthnSvc, AuthzSvc, NULL, 6,
  552.                 4, NULL, Capabilities);
  553.             pclntsec->Release();
  554.             pclntsec = NULL;
  555.             hr = pAutoAptRmt->QueryInterface(IID_IClientSecurity, (void**)&pclntsec);       
  556.             hr = pclntsec->SetBlanket(pAutoAptRmt, AuthnSvc, AuthzSvc, NULL, 6,
  557.                 4, NULL, Capabilities);
  558.             pclntsec->Release();
  559.             pclntsec = NULL;
  560.             hr = pAutoFreeRmt->QueryInterface(IID_IClientSecurity, (void**)&pclntsec);
  561.             hr = pclntsec->SetBlanket(pAutoFreeRmt, AuthnSvc, AuthzSvc, NULL, 6,
  562.                 4, NULL, Capabilities);
  563.             pclntsec->Release();
  564.             pclntsec = NULL;
  565.         }
  566.         // Do all tests with FULL sec
  567.         // Apt to Apt first
  568.         // Marshall local apt thread
  569.         hr = vpstmMarshalling->Seek(bZero, STREAM_SEEK_SET, NULL);
  570.     if (FAILED(hr))
  571.         throw hr;
  572.     hr = CoMarshalInterface(vpstmMarshalling,
  573.         IID_IUnknown,
  574.         (ICOMPerformance*)pCOMApt,
  575.         MSHCTX_INPROC,
  576.         NULL,
  577.         MSHLFLAGS_NORMAL);
  578.     if (FAILED(hr))
  579.         throw hr;
  580.         // now that the event is available, let the thread run
  581.     ResumeThread(hClientThread);
  582.         SetEvent(vhEventCliStart);
  583.         WaitForSingleObject(vhEventCliDone, INFINITE);
  584.         
  585.         if(vfRemote && NULL != pCOMAptRmt)
  586.         {
  587.             // Marshall local apt thread
  588.             hr = vpstmMarshalling->Seek(bZero, STREAM_SEEK_SET, NULL);
  589.             if (FAILED(hr))
  590.                 throw hr;
  591.             hr = CoMarshalInterface(vpstmMarshalling,
  592.                 IID_IUnknown,
  593.                 (ICOMPerformance*)pCOMAptRmt,
  594.                 MSHCTX_INPROC,
  595.                 NULL,
  596.                 MSHLFLAGS_NORMAL);
  597.             if (FAILED(hr))
  598.                 throw hr;
  599.             SetEvent(vhEventCliStart);
  600.             WaitForSingleObject(vhEventCliDone, INFINITE);
  601.         }
  602.         _tprintf(TEXT("Modified Sec:\t\tLOCAL\t\t\tREMOTE\n"));
  603.         DoTests();
  604.     }
  605. LCleanup:
  606.     if (vpstmMarshalling != NULL)
  607.             vpstmMarshalling->Release();
  608.     if (vfServer)
  609.     {
  610.         // we explicitly don't clean up threads and events
  611.         if (dwRegister != 0)
  612.             CoRevokeClassObject(dwRegister);
  613.         if(NULL != pcf)
  614.             delete pcf;
  615.     }
  616.     else // client
  617.     {
  618.         // client case: release objects
  619.         if(NULL != pcflocal)
  620.             hr = pcflocal->Release();
  621.         if(NULL != pcfrmt)
  622.             hr = pcfrmt->Release();
  623.         if(NULL != pCOMFree)
  624.             hr = pCOMFree->Release();
  625.         if(NULL != pAutoFree)
  626.             hr = pAutoFree->Release();
  627.         if(NULL != pCOMApt)
  628.             hr = pCOMApt->Release();
  629.         if(NULL != pAutoApt)
  630.             hr = pAutoApt->Release();
  631.         if(NULL != pCOMFreeRmt)
  632.             hr = pCOMFreeRmt->Release();
  633.         if(NULL != pAutoFreeRmt)
  634.             hr = pAutoFreeRmt->Release();
  635.         if(NULL != pCOMAptRmt)
  636.             hr = pCOMAptRmt->Release();
  637.         if(NULL != pAutoAptRmt)
  638.             hr = pAutoAptRmt->Release();
  639.     }
  640.     CoUninitialize();
  641.     return hr;
  642. }  // main
  643.  
  644. // ---------------------------------------------------------------------------
  645. // %%Function: FAutoRegister
  646. //  Registers the CTestCOMPerformance class in the registry.
  647. // ---------------------------------------------------------------------------
  648.  BOOL
  649. FAutoRegister()
  650. {
  651.     static TCHAR szClassDesc[] = TEXT("COM Performance Sample");
  652.     static TCHAR szCLSIDEntry[] = TEXT("CLSID\\{DDC68870-E08E-11cf-A535-00AA00615B03}");
  653.     TCHAR       szBuf[512];
  654.     TCHAR       szPath[512];
  655.     HKEY        hkeyT = NULL;
  656.  
  657.  
  658.     HRESULT hr;
  659.     LPFNREG lpfn = NULL;
  660.     HINSTANCE hLib = NULL;
  661.  
  662.     // register class code
  663.     if ((RegSetValue(HKEY_CLASSES_ROOT, szCLSIDEntry, REG_SZ, szClassDesc,
  664.         lstrlen(szClassDesc)) != ERROR_SUCCESS) ||
  665.     (RegCreateKey(HKEY_CLASSES_ROOT, szCLSIDEntry, &hkeyT)
  666.         != ERROR_SUCCESS) ||
  667.     !GetModuleFileName(NULL, szBuf, sizeof(szBuf)))
  668.     return FALSE;
  669.     lstrcpy(szPath, szBuf);
  670.     if (RegSetValue(hkeyT, TEXT("LocalServer32"), REG_SZ, szBuf, lstrlen(szBuf))
  671.         != ERROR_SUCCESS)
  672.     goto LErrExit;
  673.     RegCloseKey(hkeyT);
  674.     hkeyT = NULL;
  675.     // Register the ICOMPerformance MIDL-generated proxy-stub component
  676.     hLib = LoadLibrary(TEXT("psperf.dll"));
  677.     if (NULL == hLib)
  678.     {    
  679.         goto  LErrExit;
  680.     }
  681.     // Find entry point.
  682.     lpfn = (LPFNREG)GetProcAddress(hLib, TEXT("DllRegisterServer"));
  683.     if (lpfn == NULL)
  684.     {
  685.         //Message(_T("Couldn't find entry point in DLL"), S_OK); //unable to locate entry point
  686.         goto LErrExit;
  687.     }
  688.     hr = (*lpfn)();
  689.  
  690.     FreeLibrary(hLib);
  691.     if(SUCCEEDED(hr))
  692.         return TRUE;
  693. LErrExit:
  694.     if(NULL != hkeyT)
  695.         RegCloseKey(hkeyT);
  696.     return FALSE;
  697. }  // FAutoRegister
  698.  
  699. // ===========================================================================
  700. //                          C C L A S S F A C T O R Y
  701. // ===========================================================================
  702.  
  703. // ---------------------------------------------------------------------------
  704. // %%Function: CClassFactory::QueryInterface
  705. //  Returns a new reference of the specified iid-type to a CClassFactory.
  706. // ---------------------------------------------------------------------------
  707.  STDMETHODIMP
  708. CClassFactory::QueryInterface(REFIID iid, void **ppv)
  709. {
  710.     *ppv = NULL;
  711.  
  712.     if (iid == IID_IClassFactory || iid == IID_IUnknown)
  713.     {
  714.     *ppv = (IClassFactory *)this;
  715.     }
  716.     if (*ppv != NULL)
  717.     {
  718.     AddRef();
  719.     return S_OK;
  720.     }
  721.     return E_NOINTERFACE;
  722. }  // CClassFactory::QueryInterface
  723.  
  724. // ---------------------------------------------------------------------------
  725. // %%Function: CClassFactory::CreateInstance
  726. //  Creates a new instance of a CTestCOMPerformance on the next worker thread.
  727. // ---------------------------------------------------------------------------
  728.  STDMETHODIMP
  729. CClassFactory::CreateInstance(LPUNKNOWN punkOuter, REFIID iid, void **ppv)
  730. {
  731.     LPUNKNOWN   punk;
  732.     HRESULT     hr;
  733.  
  734.     *ppv = NULL;
  735.     if (punkOuter != NULL)
  736.     return CLASS_E_NOAGGREGATION;
  737.  
  738.     // trigger the worker thread that we want to create an object
  739.     SetEvent(vrghEvent[viNextThread]);
  740.  
  741.     // now wait for the object to signal its completion
  742.     WaitForSingleObject(vhEventServer, INFINITE);
  743.  
  744.     // once the worker thread signals completion, vhrThreadStatus
  745.     // lets us know if the creation process was successful, and if
  746.     // vpstmMarshalling creates a marshalled interface pointer
  747.     if (FAILED(vhrThreadStatus))
  748.     return vhrThreadStatus;
  749.  
  750.     // unmarshal an IUnknown from the scratch stream. if unmarshaling
  751.     // fails, it takes care of releasing the object inside the marshal-data
  752.     hr = vpstmMarshalling->Seek(bZero, STREAM_SEEK_SET, NULL);
  753.     if (FAILED(hr))
  754.     return hr;
  755.     hr = CoUnmarshalInterface(vpstmMarshalling, IID_IUnknown, (void **)&punk);
  756.     if (FAILED(hr))
  757.     return hr;
  758.  
  759.     // get a reference to the interface asked for
  760.     hr = punk->QueryInterface(iid, ppv);
  761.     punk->Release();
  762.     ++g_cObjectCount;
  763.     viNextThread++;
  764. //    viNextThread %= cServerThreads;
  765.  
  766.     return hr;
  767. }  // CClassFactory::CreateInstance
  768.  
  769.  STDMETHODIMP
  770. CClassFactory::LockServer(BOOL fLock)
  771. {
  772.     // there's no need to support this for this sample
  773.     return E_FAIL;
  774. }  // CClassFactory::LockServer
  775.  
  776.  
  777. // ===========================================================================
  778. //                               C O B J E C T
  779. // ===========================================================================
  780.  
  781. // ---------------------------------------------------------------------------
  782. // %%Function: ServerThreadProc
  783. //  The worker thread function. Handles messages for objects of its thread/apt
  784. // and creates new objects.
  785. // ---------------------------------------------------------------------------
  786.  LRESULT
  787. ServerThreadProc(LPARAM lParam)
  788. {
  789.     HRESULT hr;
  790.     MSG     msg;
  791.     int     iThread;
  792.  
  793.     // figure out which thread this is: it needs its synchronization event
  794.     for (iThread=0; iThread<cServerThreads; iThread++)
  795.     {
  796.     if (vrgtid[iThread] == GetCurrentThreadId())
  797.         break;
  798.     }
  799.     if (iThread==cServerThreads)
  800.     return E_UNEXPECTED;
  801.  
  802.     // initialize COM
  803.     if((0 == iThread) || (2 == iThread))
  804.     {
  805.         hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
  806.         Message(TEXT("Apartment Thread"), hr);
  807.     }
  808.     else
  809.     {
  810.         hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
  811.         Message(TEXT("Free-threaded Model"), hr);
  812.     }
  813.     if (FAILED(hr))
  814.     {
  815.     MessageBeep(0);
  816.     return hr;
  817.     }
  818.  
  819.     // apartment message/event loop
  820.     // here worker message loops last forever. in situations without a
  821.     // static number of worker threads, the loop could easily be terminated by
  822.     // WM_QUITs sent from the main thread which might manage the worker thread
  823.     // pool more carefully.
  824.     while (TRUE)
  825.     {
  826.     DWORD dwWaitResult;
  827.  
  828.     // wait for any message sent or posted to this queue
  829.     // or for one of the passed handles to become signaled
  830.     dwWaitResult = MsgWaitForMultipleObjects(1, &vrghEvent[iThread],
  831.         FALSE, INFINITE, QS_ALLINPUT);
  832.  
  833.     // result tells us the type of event we have:
  834.     // a message or a signaled handle
  835.  
  836.     // if there are one or more messages in the queue ...
  837.     if (dwWaitResult == (WAIT_OBJECT_0 + 1))
  838.         {
  839.         // dispatch all of the messages in this next loop
  840.         // (here is where we'd check for WM_QUITs to end this
  841.         // worker thread if we wanted to)
  842.         while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  843.         DispatchMessage(&msg);
  844.         }
  845.     else
  846.         {
  847.         // this thread was signaled to create a new object
  848.         try
  849.         {
  850.         LPUNKNOWN   punk;
  851.  
  852.         // create a new CTestCOMPerformance
  853.         punk = (ICOMPerformance *)new CTestCOMPerformance;
  854.         if (punk == NULL)
  855.             throw E_OUTOFMEMORY;
  856.  
  857.         hr = vpstmMarshalling->Seek(bZero, STREAM_SEEK_SET, NULL);
  858.         if (FAILED(hr))
  859.             throw hr;
  860.         hr = CoMarshalInterface(vpstmMarshalling,
  861.             IID_IUnknown,
  862.             punk,
  863.             MSHCTX_INPROC,
  864.             NULL,
  865.             MSHLFLAGS_NORMAL);
  866.         if (FAILED(hr))
  867.             throw hr;
  868.  
  869.         // punk is now referenced by its marshal-data in vpstmMarshalling.
  870.         // we release our local reference here so the unmarshaller will
  871.         // have the sole reference. a common mistake is to forget this
  872.         // release and end up with orphaned objects in the server.
  873.         punk->Release();
  874.         vhrThreadStatus = S_OK;
  875.         }
  876.         catch (HRESULT hr)
  877.         {
  878.         vhrThreadStatus = hr;
  879.         }
  880.         SetEvent(vhEventServer);
  881.         }
  882.  
  883.     }
  884.  
  885.     CoUninitialize();
  886.     return msg.wParam;
  887. }  // ServerThreadProc
  888.  
  889. // ---------------------------------------------------------------------------
  890. // %%Function: ServerThreadProc
  891. //  The worker thread function. Handles messages for objects of its thread/apt
  892. // and creates new objects.
  893. // ---------------------------------------------------------------------------
  894.  LRESULT
  895. ClientThreadProc(LPARAM lParam)
  896. {
  897.     HRESULT hr;
  898.     MSG     msg;
  899.     UINT cCount = 0;
  900.     hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
  901.     if (FAILED(hr))
  902.     {
  903.     return hr;
  904.     }
  905.     while (TRUE)
  906.     {
  907.     DWORD dwWaitResult;
  908.  
  909.     // wait for any message sent or posted to this queue
  910.     // or for one of the passed handles to become signaled
  911.     dwWaitResult = MsgWaitForMultipleObjectsEx(1, &vhEventCliStart,
  912.         INFINITE, QS_SENDMESSAGE, 0);
  913.         
  914.     // result tells us the type of event we have:
  915.     // a message or a signaled handle
  916.  
  917.     // if there are one or more messages in the queue ...
  918.     if (dwWaitResult == (WAIT_OBJECT_0 + 1))
  919.     {
  920.         // dispatch all of the messages in this next loop
  921.         // (here is where we'd check for WM_QUITs to end this
  922.         // worker thread if we wanted to)
  923.         while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  924.         DispatchMessage(&msg);
  925.     }
  926.     else
  927.     {
  928.         // this thread was signaled to test Apt to Apt
  929.         try
  930.         {
  931.             //Message(TEXT("Testing Apt to Apt"), hr);
  932.             LPUNKNOWN   punk;
  933.             LPDISPATCH   pdisp;
  934.             // unmarshal an IUnknown from the scratch stream. if unmarshaling
  935.             // fails, it takes care of releasing the object inside the marshal-data
  936.             hr = vpstmMarshalling->Seek(bZero, STREAM_SEEK_SET, NULL);
  937.             if (FAILED(hr))
  938.                 return hr;
  939.             hr = CoUnmarshalInterface(vpstmMarshalling, IID_IUnknown, (void **)&punk);
  940.             if (FAILED(hr))
  941.                 return hr;
  942.             ICOMPerformance *pcomperf = NULL;
  943.             // get a reference to ICOMPerformance and IDispatch interface
  944.             hr = punk->QueryInterface(IID_ICOMPerformance, (void**)&pcomperf);
  945.             hr = punk->QueryInterface(IID_IDispatch, (void**)&pdisp);
  946.             LONG    i, k;
  947.             CTIMER  tmElapsed;
  948.             BSTR bstr1, bstr2;
  949.             bstr1 = SysAllocString(pszDesc1);
  950.             bstr2 = SysAllocStringByteLen((const char *)pszDesc1, 4096);
  951.             // Test1
  952.             tmElapsed.Start();
  953.             for (i=0; i<LOOPS; i++)
  954.                 k = (LONG)pcomperf->Test1(i);
  955.             tmElapsed.Stop();
  956.             if(cCount && vfRemote)
  957.                 vrgperfrmt[4].sec[0] = tmElapsed.OutputTime();
  958.             else 
  959.                 vrgperfloc[4].sec[0] = tmElapsed.OutputTime();
  960.             // Test2
  961.             tmElapsed.Start();
  962.             for (i=0; i<LOOPS; i++)
  963.                 k = (LONG)pcomperf->Test23(bstr1);
  964.             tmElapsed.Stop();
  965.             if(cCount && vfRemote)
  966.                 vrgperfrmt[4].sec[1] = tmElapsed.OutputTime();
  967.             else
  968.                 vrgperfloc[4].sec[1] = tmElapsed.OutputTime();
  969.             // Test3
  970.             tmElapsed.Start();
  971.             for (i=0; i<LOOPS; i++)
  972.                 k = (LONG)pcomperf->Test23(bstr2);
  973.             tmElapsed.Stop();
  974.             if(cCount && vfRemote)
  975.                 vrgperfrmt[4].sec[2] = tmElapsed.OutputTime();
  976.             else
  977.                 vrgperfloc[4].sec[2] = tmElapsed.OutputTime();
  978.             // Now IDispatch
  979.             VARIANTARG  rgvt[1];
  980.             DISPPARAMS  dispparams = { rgvt, NULL, 1, 0 };
  981.             EXCEPINFO  excepinfo;
  982.             
  983.             VARIANT vtResult;
  984.             UINT    argerr;
  985.             // Test1
  986.             tmElapsed.Start();
  987.             V_VT(&vtResult) = VT_HRESULT;
  988.             for (i=0; i<LOOPS; i++)
  989.             {
  990.                 V_VT(&rgvt[0]) = VT_I4;
  991.                 V_I4(&rgvt[0]) = i;
  992.                 hr = pdisp->Invoke(dispidICOMPerformance_Test1, IID_NULL, 0, DISPATCH_METHOD, &dispparams,
  993.                     &vtResult, &excepinfo, &argerr);
  994.                 k = V_I4(&vtResult);
  995.             }
  996.             tmElapsed.Stop();
  997.             if(cCount && vfRemote)
  998.                 vrgperfrmt[5].sec[0] = tmElapsed.OutputTime();
  999.             else
  1000.                 vrgperfloc[5].sec[0] = tmElapsed.OutputTime();
  1001.             // Test2
  1002.             tmElapsed.Start();
  1003.             V_VT(&vtResult) = VT_HRESULT;
  1004.             for (i=0; i<LOOPS; i++)
  1005.             {
  1006.                 V_VT(&rgvt[0]) = VT_BSTR;
  1007.                 V_BSTR(&rgvt[0]) = bstr1;       
  1008.                 hr = pdisp->Invoke(dispidICOMPerformance_Test23, IID_NULL, 0, DISPATCH_METHOD, &dispparams,
  1009.                     &vtResult, &excepinfo, &argerr);
  1010.                 k = V_I4(&vtResult);
  1011.             }
  1012.             tmElapsed.Stop();
  1013.             if(cCount && vfRemote)
  1014.                 vrgperfrmt[5].sec[1] = tmElapsed.OutputTime();
  1015.             else
  1016.                 vrgperfloc[5].sec[1] = tmElapsed.OutputTime();
  1017.             // Test3
  1018.             tmElapsed.Start();
  1019.             V_VT(&vtResult) = VT_HRESULT;
  1020.             for (i=0; i<LOOPS; i++)
  1021.             {
  1022.                 V_VT(&rgvt[0]) = VT_BSTR;
  1023.                 V_BSTR(&rgvt[0]) = bstr2;
  1024.                 hr = pdisp->Invoke(dispidICOMPerformance_Test23, IID_NULL, 0, DISPATCH_METHOD, &dispparams,
  1025.                     &vtResult, &excepinfo, &argerr);
  1026.                 k = V_I4(&vtResult);
  1027.             }
  1028.             tmElapsed.Stop();
  1029.             if(cCount && vfRemote)
  1030.                 vrgperfrmt[5].sec[2] = tmElapsed.OutputTime();
  1031.             else
  1032.                 vrgperfloc[5].sec[2] = tmElapsed.OutputTime();
  1033.             SysFreeString(bstr1);
  1034.             SysFreeString(bstr2);
  1035.             hr = pcomperf->Release();
  1036.             hr = pdisp->Release();
  1037.             hr = punk->Release();
  1038.  
  1039.             vhrThreadStatus = S_OK;
  1040.         }
  1041.         catch (HRESULT hr)
  1042.         {
  1043.         vhrThreadStatus = hr;
  1044.             }
  1045.         SetEvent(vhEventCliDone);
  1046.             if(cCount)
  1047.                 --cCount;
  1048.             else
  1049.                 ++cCount;
  1050.     }
  1051.     }
  1052.     CoUninitialize();
  1053.     return msg.wParam;
  1054. }  // ClientThreadProc
  1055. // ---------------------------------------------------------------------------
  1056. // %%Function: CTestCOMPerformance::QueryInterface
  1057. //  Returns a new reference of the specified iid-type to a CTestCOMPerformance.
  1058. // ---------------------------------------------------------------------------
  1059.  STDMETHODIMP
  1060. CTestCOMPerformance::QueryInterface(REFIID iid, void **ppv)
  1061. {
  1062.     *ppv = NULL;
  1063.  
  1064.     if (iid == IID_IUnknown || iid == IID_ICOMPerformance)
  1065.     {
  1066.     *ppv = (ICOMPerformance *)this;
  1067.     }
  1068.     else if (iid == IID_IDispatch)
  1069.         *ppv = (IDispatch *)this;
  1070.     if (*ppv == NULL)
  1071.     {
  1072.         return E_NOINTERFACE;
  1073.     }
  1074.     AddRef();
  1075.     return S_OK;
  1076. }  // CTestCOMPerformance::QueryInterface
  1077.  
  1078. // ---------------------------------------------------------------------------
  1079. // %%Function: CTestCOMPerformance::Release
  1080. //  Handles releases of references to a CTestCOMPerformance. Purpose here is to have code
  1081. // which alters the global state which is displayed in the servers UI.
  1082. // ---------------------------------------------------------------------------
  1083.  STDMETHODIMP_(ULONG)
  1084. CTestCOMPerformance::Release(void)
  1085. {
  1086.     if (--m_cRef == 0)
  1087.     {
  1088.         --g_cObjectCount;
  1089.         delete this;
  1090.     Message(TEXT("Object Deleted"), S_OK);
  1091.         if(g_cObjectCount == 0) SetEvent(hKillSvr);
  1092.         return 0;
  1093.     }
  1094.     return m_cRef;
  1095. }  // CTestCOMPerformance::Release
  1096.  
  1097. // ---------------------------------------------------------------------------
  1098. // %%Function: CTestCOMPerformance::GetTypeInfoCount
  1099. // ---------------------------------------------------------------------------
  1100.  STDMETHODIMP
  1101. CTestCOMPerformance::GetTypeInfoCount(UINT  *pctInfo)
  1102. {
  1103.     *pctInfo = 1;
  1104.     return S_OK;
  1105. }  // CTestCOMPerformance::GetTypeInfoCount
  1106.  
  1107. // ---------------------------------------------------------------------------
  1108. // %%Function: CTestCOMPerformance::GetTypeInfo
  1109. // ---------------------------------------------------------------------------
  1110.  STDMETHODIMP
  1111. CTestCOMPerformance::GetTypeInfo(unsigned int itInfo, LCID lcid, LPTYPEINFO  *ppti)
  1112. {
  1113.     HRESULT hr;
  1114.  
  1115.     if (ppti == NULL)
  1116.         return E_POINTER;
  1117.     hr = CreateDispTypeInfo( &interfacedata, 0, ppti);
  1118.     return hr;
  1119. }  // CTestCOMPerformance::GetTypeInfo
  1120.  
  1121. // ---------------------------------------------------------------------------
  1122. // %%Function: CTestCOMPerformance::GetIDsOfNames
  1123. // ---------------------------------------------------------------------------
  1124.  STDMETHODIMP
  1125. CTestCOMPerformance::GetIDsOfNames(REFIID riid, WCHAR  *  *rgszNames, unsigned int cNames, LCID lcid, DISPID  *pdispid)
  1126. {
  1127.     return E_NOTIMPL;
  1128. }  // CTestCOMPerformance::GetIDsOfNames
  1129.  
  1130. // ---------------------------------------------------------------------------
  1131. // %%Function: CTestCOMPerformance::Invoke
  1132. // ---------------------------------------------------------------------------
  1133.  STDMETHODIMP
  1134. CTestCOMPerformance::Invoke(DISPID dispidMember, REFIID riid, LCID lcid, unsigned short wFlags, DISPPARAMS  *pdispparams, VARIANT  *pvarResult,
  1135.           EXCEPINFO  *pexcepinfo, unsigned int  *puArgErr)
  1136. {
  1137.     LPTYPEINFO pti = NULL;
  1138.     HRESULT hr = GetTypeInfo(0, lcid, &pti);
  1139.     if(FAILED(hr))
  1140.         return hr;
  1141.  
  1142.     hr =  pti->Invoke((ICOMPerformance*)this, dispidMember,
  1143.         wFlags, pdispparams, pvarResult,
  1144.         pexcepinfo, puArgErr);
  1145.     hr = pti->Release();
  1146.     return hr;
  1147. }  // CTestCOMPerformance::Invoke
  1148.  
  1149.  
  1150.  STDMETHODIMP                   
  1151. CTestCOMPerformance::Test1(int l)
  1152. {
  1153.      return S_OK;
  1154. }
  1155.  
  1156.  STDMETHODIMP                   
  1157. CTestCOMPerformance::Test23(BSTR bstr)
  1158. {
  1159.      return S_OK;
  1160. }
  1161.  
  1162. // Tests
  1163.  BOOL        
  1164. AptFreeCOMTest(int cLoops)
  1165. {
  1166.     LONG    i, k;
  1167.     CTIMER  tmElapsed;
  1168.     BSTR bstr1, bstr2;
  1169.     bstr1 = SysAllocString(pszDesc1);
  1170.     bstr2 = SysAllocStringByteLen((const char *)pszDesc1, 4096);
  1171.     // Local
  1172.     // Test1
  1173.     tmElapsed.Start();
  1174.     for (i=0; i<cLoops; i++)
  1175.         k = (LONG)pCOMApt->Test1(i);
  1176.     tmElapsed.Stop();
  1177.     vrgperfloc[0].sec[0] = tmElapsed.OutputTime();
  1178.     // Test2
  1179.     tmElapsed.Start();
  1180.     for (i=0; i<cLoops; i++)
  1181.         k = (LONG)pCOMApt->Test23(bstr1);
  1182.     tmElapsed.Stop();
  1183.     vrgperfloc[0].sec[1] = tmElapsed.OutputTime();
  1184.     // Test3
  1185.     tmElapsed.Start();
  1186.     for (i=0; i<cLoops; i++)
  1187.         k = (LONG)pCOMApt->Test23(bstr2);
  1188.     tmElapsed.Stop();
  1189.     vrgperfloc[0].sec[2] = tmElapsed.OutputTime();
  1190.     
  1191.     // Remote
  1192.     if(vfRemote)
  1193.     {
  1194.         tmElapsed.Start();
  1195.         for (i=0; i<cLoops; i++)
  1196.             k = (LONG)pCOMAptRmt->Test1(i);
  1197.         tmElapsed.Stop();
  1198.         vrgperfrmt[0].sec[0] = tmElapsed.OutputTime();
  1199.         // Test2
  1200.         tmElapsed.Start();
  1201.         for (i=0; i<cLoops; i++)
  1202.             k = (LONG)pCOMAptRmt->Test23(bstr1);
  1203.         tmElapsed.Stop();
  1204.         vrgperfrmt[0].sec[1] = tmElapsed.OutputTime();
  1205.         // Test3
  1206.         tmElapsed.Start();
  1207.         for (i=0; i<cLoops; i++)
  1208.             k = (LONG)pCOMAptRmt->Test23(bstr2);
  1209.         tmElapsed.Stop();
  1210.         vrgperfrmt[0].sec[2] = tmElapsed.OutputTime();
  1211.  
  1212.     }
  1213.     SysFreeString(bstr1);
  1214.     SysFreeString(bstr2);
  1215.     return TRUE;
  1216. }
  1217.  
  1218.  BOOL           
  1219. AptFreeAutoTest(int cLoops)
  1220. {
  1221.     HRESULT hr;
  1222.     static VARIANTARG  rgvt[1];
  1223.     static DISPPARAMS  dispparams = { rgvt, NULL, 1, 0 };
  1224.     static EXCEPINFO  excepinfo;
  1225.     VARIANT vtResult;
  1226.     UINT    argerr;
  1227.     LONG    i, k;
  1228.     CTIMER  tmElapsed;
  1229.     BSTR bstr1, bstr2;
  1230.     bstr1 = SysAllocString(pszDesc1);
  1231.     bstr2 = SysAllocStringByteLen((const char *)pszDesc1, 4096);
  1232.  
  1233.     // Test1
  1234.     tmElapsed.Start();
  1235.     V_VT(&vtResult) = VT_HRESULT;
  1236.     for (i=0; i<cLoops; i++)
  1237.     {
  1238.         V_VT(&rgvt[0]) = VT_I4;
  1239.         V_I4(&rgvt[0]) = i;
  1240.         hr = pAutoApt->Invoke(dispidICOMPerformance_Test1, IID_NULL, 0, DISPATCH_METHOD, &dispparams,
  1241.             &vtResult, &excepinfo, &argerr);
  1242.         k = V_I4(&vtResult);
  1243.     }
  1244.     tmElapsed.Stop();
  1245.     vrgperfloc[1].sec[0] = tmElapsed.OutputTime();
  1246.     // Test2
  1247.     tmElapsed.Start();
  1248.     V_VT(&vtResult) = VT_HRESULT;
  1249.     for (i=0; i<cLoops; i++)
  1250.     {
  1251.         V_VT(&rgvt[0]) = VT_BSTR;
  1252.         V_BSTR(&rgvt[0]) = bstr1;       
  1253.         hr = pAutoApt->Invoke(dispidICOMPerformance_Test23, IID_NULL, 0, DISPATCH_METHOD, &dispparams,
  1254.             &vtResult, &excepinfo, &argerr);
  1255.         k = V_I4(&vtResult);
  1256.     }
  1257.     tmElapsed.Stop();
  1258.     vrgperfloc[1].sec[1] = tmElapsed.OutputTime();
  1259.     // Test3
  1260.     tmElapsed.Start();
  1261.     V_VT(&vtResult) = VT_HRESULT;
  1262.     for (i=0; i<cLoops; i++)
  1263.     {
  1264.         V_VT(&rgvt[0]) = VT_BSTR;
  1265.         V_BSTR(&rgvt[0]) = bstr2;
  1266.         hr = pAutoApt->Invoke(dispidICOMPerformance_Test23, IID_NULL, 0, DISPATCH_METHOD, &dispparams,
  1267.             &vtResult, &excepinfo, &argerr);
  1268.         k = V_I4(&vtResult);
  1269.     }
  1270.     tmElapsed.Stop();
  1271.     vrgperfloc[1].sec[2] = tmElapsed.OutputTime();
  1272.     // Remote
  1273.     if(vfRemote)
  1274.     {
  1275.         // Test1
  1276.         tmElapsed.Start();
  1277.         V_VT(&vtResult) = VT_HRESULT;
  1278.         for (i=0; i<cLoops; i++)
  1279.         {
  1280.             V_VT(&rgvt[0]) = VT_I4;
  1281.             V_I4(&rgvt[0]) = i;
  1282.             hr = pAutoAptRmt->Invoke(dispidICOMPerformance_Test1, IID_NULL, 0, DISPATCH_METHOD, &dispparams,
  1283.                 &vtResult, &excepinfo, &argerr);
  1284.             k = V_I4(&vtResult);
  1285.         }
  1286.         tmElapsed.Stop();
  1287.         vrgperfrmt[1].sec[0] = tmElapsed.OutputTime();
  1288.         // Test2
  1289.         tmElapsed.Start();
  1290.         V_VT(&vtResult) = VT_HRESULT;
  1291.         for (i=0; i<cLoops; i++)
  1292.         {
  1293.             V_VT(&rgvt[0]) = VT_BSTR;
  1294.             V_BSTR(&rgvt[0]) = bstr1;       
  1295.             hr = pAutoAptRmt->Invoke(dispidICOMPerformance_Test23, IID_NULL, 0, DISPATCH_METHOD, &dispparams,
  1296.                 &vtResult, &excepinfo, &argerr);
  1297.             k = V_I4(&vtResult);
  1298.         }
  1299.         tmElapsed.Stop();
  1300.         vrgperfrmt[1].sec[1] = tmElapsed.OutputTime();
  1301.         // Test3
  1302.         tmElapsed.Start();
  1303.         V_VT(&vtResult) = VT_HRESULT;
  1304.         for (i=0; i<cLoops; i++)
  1305.         {
  1306.             V_VT(&rgvt[0]) = VT_BSTR;
  1307.             V_BSTR(&rgvt[0]) = bstr2;
  1308.             hr = pAutoAptRmt->Invoke(dispidICOMPerformance_Test23, IID_NULL, 0, DISPATCH_METHOD, &dispparams,
  1309.                 &vtResult, &excepinfo, &argerr);
  1310.             k = V_I4(&vtResult);
  1311.         }
  1312.         tmElapsed.Stop();
  1313.         vrgperfrmt[1].sec[2] = tmElapsed.OutputTime();
  1314.     }
  1315.  
  1316.     SysFreeString(bstr1);
  1317.     SysFreeString(bstr2);
  1318.     return TRUE;
  1319. }
  1320.  
  1321.  BOOL           
  1322. FreeFreeCOMTest(int cLoops)
  1323. {
  1324.     LONG    i, k;
  1325.     CTIMER  tmElapsed;
  1326.     BSTR bstr1, bstr2;
  1327.     bstr1 = SysAllocString(pszDesc1);
  1328.     bstr2 = SysAllocStringByteLen((const char *)pszDesc1, 4096);
  1329.  
  1330.     // Test1
  1331.     tmElapsed.Start();
  1332.     for (i=0; i<cLoops; i++)
  1333.         k = (LONG)pCOMFree->Test1(i);
  1334.     tmElapsed.Stop();
  1335.     vrgperfloc[2].sec[0] = tmElapsed.OutputTime();
  1336.     // Test2
  1337.     tmElapsed.Start();
  1338.     for (i=0; i<cLoops; i++)
  1339.         k = (LONG)pCOMFree->Test23(bstr1);
  1340.     tmElapsed.Stop();
  1341.     vrgperfloc[2].sec[1] = tmElapsed.OutputTime();
  1342.     // Test3
  1343.     tmElapsed.Start();
  1344.     for (i=0; i<cLoops; i++)
  1345.     {
  1346.         k = (LONG)pCOMFree->Test23(bstr2);
  1347.     }
  1348.     tmElapsed.Stop();
  1349.     vrgperfloc[2].sec[2] = tmElapsed.OutputTime();
  1350.     
  1351.     // Remote
  1352.     if(vfRemote)
  1353.     {
  1354.         // Test1
  1355.     tmElapsed.Start();
  1356.     for (i=0; i<cLoops; i++)
  1357.         k = (LONG)pCOMFreeRmt->Test1(i);
  1358.         tmElapsed.Stop();
  1359.         vrgperfrmt[2].sec[0] = tmElapsed.OutputTime();
  1360.         // Test2
  1361.         tmElapsed.Start();
  1362.         for (i=0; i<cLoops; i++)
  1363.             k = (LONG)pCOMFreeRmt->Test23(bstr1);
  1364.         tmElapsed.Stop();
  1365.         vrgperfrmt[2].sec[1] = tmElapsed.OutputTime();
  1366.         // Test3
  1367.         tmElapsed.Start();
  1368.         for (i=0; i<cLoops; i++)
  1369.         {
  1370.             k = (LONG)pCOMFreeRmt->Test23(bstr2);
  1371.         }
  1372.         tmElapsed.Stop();
  1373.         vrgperfrmt[2].sec[2] = tmElapsed.OutputTime();
  1374.     }
  1375.  
  1376.     SysFreeString(bstr1);
  1377.     SysFreeString(bstr2);
  1378.     return TRUE;
  1379. }
  1380.  
  1381.  BOOL           
  1382. FreeFreeAutoTest(int cLoops)
  1383. {
  1384.     HRESULT hr;
  1385.     static VARIANTARG  rgvt[1];
  1386.     static DISPPARAMS  dispparams = { rgvt, NULL, 1, 0 };
  1387.     static EXCEPINFO  excepinfo;
  1388.     VARIANT vtResult;
  1389.     UINT    argerr;
  1390.     LONG    i, k;
  1391.     CTIMER  tmElapsed;
  1392.     BSTR bstr1, bstr2;
  1393.     bstr1 = SysAllocString(pszDesc1);
  1394.     bstr2 = SysAllocStringByteLen((const char *)pszDesc1, 4096);
  1395.  
  1396.     // Local
  1397.     // Test1
  1398.     tmElapsed.Start();
  1399.     V_VT(&vtResult) = VT_HRESULT;
  1400.     for (i=0; i<cLoops; i++)
  1401.     {
  1402.         V_VT(&rgvt[0]) = VT_I4;
  1403.         V_I4(&rgvt[0]) = i;
  1404.         hr = pAutoFree->Invoke(dispidICOMPerformance_Test1, IID_NULL, 0, DISPATCH_METHOD, &dispparams,
  1405.             &vtResult, &excepinfo, &argerr);
  1406.         k = V_I4(&vtResult);
  1407.     }
  1408.     tmElapsed.Stop();
  1409.     vrgperfloc[3].sec[0] = tmElapsed.OutputTime();
  1410.     // Test2
  1411.     tmElapsed.Start();
  1412.     V_VT(&vtResult) = VT_HRESULT;
  1413.     for (i=0; i<cLoops; i++)
  1414.     {
  1415.         V_VT(&rgvt[0]) = VT_BSTR;
  1416.         V_BSTR(&rgvt[0]) = bstr1;       
  1417.         hr = pAutoFree->Invoke(dispidICOMPerformance_Test23, IID_NULL, 0, DISPATCH_METHOD, &dispparams,
  1418.             &vtResult, &excepinfo, &argerr);
  1419.         k = V_I4(&vtResult);
  1420.     }
  1421.     tmElapsed.Stop();
  1422.     vrgperfloc[3].sec[1] = tmElapsed.OutputTime();
  1423.     // Test3
  1424.     tmElapsed.Start();
  1425.     V_VT(&vtResult) = VT_HRESULT;
  1426.     for (i=0; i<cLoops; i++)
  1427.     {
  1428.         V_VT(&rgvt[0]) = VT_BSTR;
  1429.         V_BSTR(&rgvt[0]) = bstr2;
  1430.         hr = pAutoFree->Invoke(dispidICOMPerformance_Test23, IID_NULL, 0, DISPATCH_METHOD, &dispparams,
  1431.             &vtResult, &excepinfo, &argerr);
  1432.         k = V_I4(&vtResult);
  1433.     }
  1434.     tmElapsed.Stop();
  1435.     vrgperfloc[3].sec[2] = tmElapsed.OutputTime();
  1436.     
  1437.     // Remote
  1438.     if(vfRemote)
  1439.     {
  1440.         // Test1
  1441.         tmElapsed.Start();
  1442.         V_VT(&vtResult) = VT_HRESULT;
  1443.         for (i=0; i<cLoops; i++)
  1444.         {
  1445.             V_VT(&rgvt[0]) = VT_I4;
  1446.             V_I4(&rgvt[0]) = i;
  1447.             hr = pAutoFreeRmt->Invoke(dispidICOMPerformance_Test1, IID_NULL, 0, DISPATCH_METHOD, &dispparams,
  1448.                 &vtResult, &excepinfo, &argerr);
  1449.             k = V_I4(&vtResult);
  1450.         }
  1451.         tmElapsed.Stop();
  1452.         vrgperfrmt[3].sec[0] = tmElapsed.OutputTime();
  1453.         // Test2
  1454.         tmElapsed.Start();
  1455.         V_VT(&vtResult) = VT_HRESULT;
  1456.         for (i=0; i<cLoops; i++)
  1457.         {
  1458.             V_VT(&rgvt[0]) = VT_BSTR;
  1459.             V_BSTR(&rgvt[0]) = bstr1;       
  1460.             hr = pAutoFreeRmt->Invoke(dispidICOMPerformance_Test23, IID_NULL, 0, DISPATCH_METHOD, &dispparams,
  1461.                 &vtResult, &excepinfo, &argerr);
  1462.             k = V_I4(&vtResult);
  1463.         }
  1464.         tmElapsed.Stop();
  1465.         vrgperfrmt[3].sec[1] = tmElapsed.OutputTime();
  1466.         // Test3
  1467.         tmElapsed.Start();
  1468.         V_VT(&vtResult) = VT_HRESULT;
  1469.         for (i=0; i<cLoops; i++)
  1470.         {
  1471.             V_VT(&rgvt[0]) = VT_BSTR;
  1472.             V_BSTR(&rgvt[0]) = bstr2;
  1473.             hr = pAutoFreeRmt->Invoke(dispidICOMPerformance_Test23, IID_NULL, 0, DISPATCH_METHOD, &dispparams,
  1474.                 &vtResult, &excepinfo, &argerr);
  1475.             k = V_I4(&vtResult);
  1476.         }
  1477.         tmElapsed.Stop();
  1478.         vrgperfrmt[3].sec[2] = tmElapsed.OutputTime();
  1479.     }
  1480.     SysFreeString(bstr1);
  1481.     SysFreeString(bstr2);
  1482.     return TRUE;
  1483. }
  1484.  
  1485.  void
  1486. FPrintResults()
  1487. {
  1488.     _tprintf(TEXT("Data Size\t\t4\t50\t4k\t4\t50\t4k\n"));
  1489.     _tprintf(TEXT("%s\t\t"), vrgperfloc[0].szTest);
  1490.     _tprintf(TEXT("%4.2f\t"), LOOPS/vrgperfloc[0].sec[0]);
  1491.     _tprintf(TEXT("%4.2f\t"), LOOPS/vrgperfloc[0].sec[1]);
  1492.     _tprintf(TEXT("%4.2f\t"), LOOPS/vrgperfloc[0].sec[2]);
  1493.     if(vfRemote)       
  1494.     {
  1495.         _tprintf(TEXT("%4.2f\t"), LOOPS/vrgperfrmt[0].sec[0]);
  1496.         _tprintf(TEXT("%4.2f\t"), LOOPS/vrgperfrmt[0].sec[1]);
  1497.         _tprintf(TEXT("%4.2f\n"), LOOPS/vrgperfrmt[0].sec[2]);
  1498.     }
  1499.     else
  1500.     {
  1501.         _tprintf(TEXT("--\t"));
  1502.         _tprintf(TEXT("--\t"));
  1503.         _tprintf(TEXT("--\n"));
  1504.     }
  1505.     _tprintf(TEXT("%s\t\t"), vrgperfloc[1].szTest);
  1506.     _tprintf(TEXT("%4.2f\t"), LOOPS/vrgperfloc[1].sec[0]);
  1507.     _tprintf(TEXT("%4.2f\t"), LOOPS/vrgperfloc[1].sec[1]);
  1508.     _tprintf(TEXT("%4.2f\t"), LOOPS/vrgperfloc[1].sec[2]);
  1509.     if(vfRemote)   
  1510.     {
  1511.         _tprintf(TEXT("%4.2f\t"), LOOPS/vrgperfrmt[1].sec[0]);
  1512.         _tprintf(TEXT("%4.2f\t"), LOOPS/vrgperfrmt[1].sec[1]);
  1513.         _tprintf(TEXT("%4.2f\n"), LOOPS/vrgperfrmt[1].sec[2]);
  1514.     }
  1515.     else
  1516.     {
  1517.         _tprintf(TEXT("--\t"));
  1518.         _tprintf(TEXT("--\t"));
  1519.         _tprintf(TEXT("--\n"));
  1520.     }
  1521.     _tprintf(TEXT("%s\t\t"), vrgperfloc[2].szTest);
  1522.     _tprintf(TEXT("%4.2f\t"), LOOPS/vrgperfloc[2].sec[0]);
  1523.     _tprintf(TEXT("%4.2f\t"), LOOPS/vrgperfloc[2].sec[1]);
  1524.     _tprintf(TEXT("%4.2f\t"), LOOPS/vrgperfloc[2].sec[2]);
  1525.     if(vfRemote)    
  1526.     {
  1527.         _tprintf(TEXT("%4.2f\t"), LOOPS/vrgperfrmt[2].sec[0]);
  1528.         _tprintf(TEXT("%4.2f\t"), LOOPS/vrgperfrmt[2].sec[1]);
  1529.         _tprintf(TEXT("%4.2f\n"), LOOPS/vrgperfrmt[2].sec[2]);
  1530.     }
  1531.     else
  1532.     {
  1533.         _tprintf(TEXT("--\t"));
  1534.         _tprintf(TEXT("--\t"));
  1535.         _tprintf(TEXT("--\n"));
  1536.     }
  1537.     _tprintf(TEXT("%s\t\t"), vrgperfloc[3].szTest);
  1538.     _tprintf(TEXT("%4.2f\t"), LOOPS/vrgperfloc[3].sec[0]);
  1539.     _tprintf(TEXT("%4.2f\t"), LOOPS/vrgperfloc[3].sec[1]);
  1540.     _tprintf(TEXT("%4.2f\t"), LOOPS/vrgperfloc[3].sec[2]);
  1541.     if(vfRemote)    
  1542.     {
  1543.         _tprintf(TEXT("%4.2f\t"), LOOPS/vrgperfrmt[3].sec[0]);
  1544.         _tprintf(TEXT("%4.2f\t"), LOOPS/vrgperfrmt[3].sec[1]);
  1545.         _tprintf(TEXT("%4.2f\n"), LOOPS/vrgperfrmt[3].sec[2]);
  1546.     }
  1547.     else
  1548.     {
  1549.         _tprintf(TEXT("--\t"));
  1550.         _tprintf(TEXT("--\t"));
  1551.         _tprintf(TEXT("--\n"));
  1552.     }
  1553.     _tprintf(TEXT("%s\t\t"), vrgperfloc[4].szTest);
  1554.     _tprintf(TEXT("%4.2f\t"), LOOPS/vrgperfloc[4].sec[0]);
  1555.     _tprintf(TEXT("%4.2f\t"), LOOPS/vrgperfloc[4].sec[1]);
  1556.     _tprintf(TEXT("%4.2f\t"), LOOPS/vrgperfloc[4].sec[2]);
  1557.     if(vfRemote)    
  1558.     {
  1559.         _tprintf(TEXT("%4.2f\t"), LOOPS/vrgperfrmt[4].sec[0]);
  1560.         _tprintf(TEXT("%4.2f\t"), LOOPS/vrgperfrmt[4].sec[1]);
  1561.         _tprintf(TEXT("%4.2f\n"), LOOPS/vrgperfrmt[4].sec[2]);
  1562.     }
  1563.     else
  1564.     {
  1565.         _tprintf(TEXT("--\t"));
  1566.         _tprintf(TEXT("--\t"));
  1567.         _tprintf(TEXT("--\n"));
  1568.     }
  1569.     _tprintf(TEXT("%s\t\t"), vrgperfloc[5].szTest);
  1570.     _tprintf(TEXT("%4.2f\t"), LOOPS/vrgperfloc[5].sec[0]);
  1571.     _tprintf(TEXT("%4.2f\t"), LOOPS/vrgperfloc[5].sec[1]);
  1572.     _tprintf(TEXT("%4.2f\t"), LOOPS/vrgperfloc[5].sec[2]);
  1573.     if(vfRemote)    
  1574.     {
  1575.         _tprintf(TEXT("%4.2f\t"), LOOPS/vrgperfrmt[5].sec[0]);
  1576.         _tprintf(TEXT("%4.2f\t"), LOOPS/vrgperfrmt[5].sec[1]);
  1577.         _tprintf(TEXT("%4.2f\n"), LOOPS/vrgperfrmt[5].sec[2]);
  1578.     }
  1579.     else
  1580.     {
  1581.         _tprintf(TEXT("--\t"));
  1582.         _tprintf(TEXT("--\t"));
  1583.         _tprintf(TEXT("--\n"));
  1584.     }
  1585.  
  1586.   
  1587. }
  1588.  
  1589.  BOOL 
  1590. DoTests(void)
  1591. {
  1592.     if(!AptFreeCOMTest(LOOPS))
  1593.         return FALSE;
  1594.     if(!AptFreeAutoTest(LOOPS))
  1595.         return FALSE;
  1596.     if(!FreeFreeCOMTest(LOOPS))
  1597.         return FALSE;
  1598.     if(!FreeFreeAutoTest(LOOPS))
  1599.         return FALSE;
  1600.     FPrintResults();
  1601.     return TRUE;
  1602. } // DoTests
  1603.  
  1604. void Usage()
  1605. {
  1606.     _tprintf(TEXT("Usage: COMPERF [machine name | IP address | /? | -?]\n\n"));
  1607.     _tprintf(TEXT("/?\t\t\tDisplays this help screen.\n"));
  1608.     _tprintf(TEXT("machine name\t\tName of remote machine.\n"));
  1609.     _tprintf(TEXT("IP address\t\tIP address of remote machine.\n\n"));
  1610.     _tprintf("%s", PURPOSE);
  1611. }
  1612.  
  1613. // EOF =======================================================================
  1614.