home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 39 / IOPROG_39.ISO / SOFT / sdkjava40.exe / data1.cab / fg_Samples / Samples / COM / JCOMApartment / oleapt.Cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2000-05-04  |  23.3 KB  |  654 lines

  1. // ===========================================================================
  2. // File: O L E A P T . C P P
  3. // 
  4. //  Demonstrates OLE Apartment model threading. "Apartment" is essentially
  5. // just a way of describing a thread with a message queue that supports OLE/COM
  6. // objects. Objects within an apartment are reentrant in only the traditional
  7. // Windows sense, identically to single-threaded OLE. That is to say that
  8. // operations which yield to the message queue can cause further messages to
  9. // be sent to any objects within the apartment. Apartment model threading simply
  10. // allows there to be more than one "apartment" where previously there was
  11. // only one: the main application thread.
  12. // 
  13. //  This program is both a client and an server. It launches as a client
  14. // by default, registering its executable as a server and creating another
  15. // instance of itself to be the server.
  16. // 
  17. //  The client does nothing interesting and is always shown as a minimized
  18. // window. It simply creates an instance of its worker COM object in the
  19. // server. When it shuts down, it releases its reference to the object,
  20. // which is reflected in the server's UI.
  21. // 
  22. //  The server registers a class-factory on the main application thread and
  23. // also spawns several worker threads. When requests arrive from clients to
  24. // create instances of the class, the server class-factory picks a worker
  25. // thread for the object (simply allocating them round-robin to the workers)
  26. // and then goes through the process of having the object created within the
  27. // thread and properly marshalled from the worker thread back to the class-
  28. // factory where it can be returned to the caller. Note that this marshalling
  29. // to the main thread is fairly transient, it lasts for creation only:
  30. // subsequent calls from the client to the object go straight from the client's
  31. // process into the worker apartment.
  32. // 
  33. //  The only mechanisms used here above-and-beyond NT 3.5 are:
  34. //   * Ability to call CoInitialize() in multiple threads
  35. //   * The use of the new marshalling flag, MSHCTX_INPROC, to marshall
  36. //     pointers between threads
  37. //
  38. //  This sample may be compiled as UNICODE for the NT 3.51 beta, or as Ansi
  39. // (listed here) to run on both the NT 3.51 beta and the Windows 95 M8 Beta.
  40. // 
  41. // (C) Copyright 1995 - 1999 Microsoft Corporation.  All rights reserved.
  42. // ===========================================================================
  43.  
  44. // %%Includes: ---------------------------------------------------------------
  45. #define INC_OLE2
  46. #define STRICT
  47. #include <windows.h>
  48. #include <initguid.h>
  49. #include <stdio.h>
  50.  
  51. // %%Constants: --------------------------------------------------------------
  52. #define cServerThreads  5
  53. #define szWindowClass   TEXT("OLEAPT_CLASS")
  54. #define szTitleServer   TEXT("SERVER: OLE Apartment Sample")
  55. #define szTitleClient   TEXT("CLIENT: OLE Apartment Sample")
  56. #define szCloseQuery    TEXT("Client references still exist. Are you sure you want to close?")
  57. #define COINIT_APARTMENTTHREADED    2
  58. const LARGE_INTEGER     bZero = {0,0};
  59.  
  60. // %%Guids: ------------------------------------------------------------------
  61. DEFINE_GUID(CLSID_CObject, 0x5c06abc0, 0x2dcd, 0x11ce, 0x84, 0x17, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
  62. DEFINE_GUID(IID_IPing, 0xBA009420, 0x272A, 0x11D2, 0xB9, 0x06, 0x00, 0xC0, 0x4F, 0x8C, 0x94, 0x91);
  63. DEFINE_GUID(CLSID_SERVEDOBJECT,  0xDD898100, 0x314C, 0x11D2, 0xB9, 0x16, 0x00, 0xC0, 0x4F, 0x8C, 0x94, 0x91);
  64.  
  65. // %%Classes: ----------------------------------------------------------------
  66. // the class-factory object exists in the main application apartment/thread
  67. // and is used to create instances of the worker objects on worker threads.
  68. class CClassFactory : public IClassFactory
  69.     {
  70.   // IClassFactory
  71.     STDMETHODIMP            QueryInterface(REFIID iid, void **ppv);
  72.     STDMETHODIMP_(ULONG)    AddRef(void)    { return mcRef++; }
  73.     STDMETHODIMP_(ULONG)    Release(void)   { if (--mcRef == 0) { delete this; return 0; } return mcRef; }
  74.     STDMETHODIMP            CreateInstance(LPUNKNOWN punkOuter, REFIID iid, LPVOID FAR *ppv);
  75.     STDMETHODIMP            LockServer(BOOL fLock);
  76.  
  77.   // data members
  78.     ULONG   mcRef;
  79.  
  80.   // constructors/destructors
  81.   public:
  82.     CClassFactory() { mcRef = 1; }
  83.     };
  84.  
  85. // this worker object is simple: it simply supports IUnknown. more interesting
  86. // interfaces can be readily added here and implemented for the worker.
  87. class CObject : public IUnknown
  88.     {
  89.   // IUnknown
  90.     STDMETHODIMP            QueryInterface(REFIID iid, void **ppv);
  91.     STDMETHODIMP_(ULONG)    AddRef(void)    { return mcRef++; }
  92.     STDMETHODIMP_(ULONG)    Release(void);
  93.  
  94.   // data members
  95.     ULONG   mcRef;
  96.     IUnknown* punkInner;        //pointer to the inner Java COM object
  97.  
  98.   // constructors/destructors
  99.   public:
  100.     STDMETHODIMP_(HRESULT)  init();
  101.     CObject() 
  102.     { 
  103.         mcRef = 1; 
  104.  
  105.     }
  106.     };
  107.  
  108. // %%Globals: ----------------------------------------------------------------
  109. BOOL        vfServer;                       // is this instance a server or client?
  110. HANDLE      vrghThread[cServerThreads];     // worker thread handles
  111. DWORD       vrgtid[cServerThreads];         // worker thread id's
  112. HANDLE      vrghEvent[cServerThreads];      // creation event for each worker
  113. INT         vrgcObjects[cServerThreads];    // # of objects created on each thread
  114. HANDLE      vhEventServer;                  // creation-complete event for class-factory
  115. CClassFactory   vclassfactory;
  116. UINT        viNextThread;                   // next worker to create an object on
  117. LPUNKNOWN   vpunkService;                   // client's x-process reference to its
  118.                                             //  worker object in the server
  119. HWND        vhwndMain;
  120. LPSTREAM    vpstmMarshalling;               // scratch stream used for cross-apt marshalling
  121. HRESULT     vhrThreadStatus;                // signals status to class-factory
  122. // %%Prototypes: -------------------------------------------------------------
  123. LRESULT CALLBACK    MainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
  124. LRESULT             ServerThreadProc(LPARAM lParam);
  125. BOOL                FAutoRegister(HINSTANCE hinst);
  126.  
  127. // ---------------------------------------------------------------------------
  128. // %%Function: MainWndProc
  129. //  Window procedure for both client and server versions of the sample. Clients
  130. // display nothing, server displays statistics about
  131. // ---------------------------------------------------------------------------
  132.  LRESULT CALLBACK
  133. MainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  134. {
  135.     LRESULT lresult = TRUE;
  136.  
  137.     switch (message)
  138.         {
  139.         case WM_QUERYOPEN:
  140.             // clients must stay minimized
  141.             return vfServer;
  142.  
  143.         case WM_PAINT:
  144.             {
  145.             HDC hdc;
  146.             PAINTSTRUCT ps;
  147.             int i;
  148.  
  149.             if ((hdc = BeginPaint(hwnd, &ps)) != NULL)
  150.                 {
  151.                 if (vfServer)
  152.                     {
  153.                     for (i=0; i<cServerThreads; i++)
  154.                         {
  155.                         TCHAR    rgch[200];
  156.  
  157.                         wsprintf(rgch, TEXT("Thread #%d: %d objects"), i, vrgcObjects[i]);
  158.                         TextOut(hdc, 20, 10+(i*25), rgch, lstrlen(rgch));
  159.                         }
  160.                     }
  161.                 }
  162.             EndPaint(hwnd, &ps);
  163.             }
  164.             break;
  165.  
  166.  
  167.         case WM_DESTROY:
  168.             PostQuitMessage(0);
  169.             break;
  170.  
  171.         case WM_CLOSE:
  172.             // check for clients and prompt in the UI.
  173.             if (vfServer)
  174.                 {
  175.                 for (int i=0; i<cServerThreads; i++)
  176.                     {
  177.                     if (vrgcObjects[i] > 0)
  178.                         {
  179.                         if (MessageBox(hwnd, szCloseQuery,
  180.                                 szTitleServer, MB_YESNO) == IDNO)
  181.                             return FALSE;
  182.                         else
  183.                             break;
  184.                         }
  185.                     }
  186.                 }
  187.  
  188.         default:
  189.             return DefWindowProc(hwnd, message, wParam, lParam);
  190.         }
  191.  
  192.     return lresult;
  193. }  // MainWndProc
  194.  
  195. // ---------------------------------------------------------------------------
  196. // %%Function: WinMain
  197. //  Initialization, main message-pump for clients and servers.
  198. // ---------------------------------------------------------------------------
  199.  int PASCAL
  200. WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR szCmdLine, int nCmdShow)
  201. {
  202.     WNDCLASS wndclass;
  203.     HRESULT hr;
  204.     int     i;
  205.     DWORD   dwRegister = 0;
  206.     MSG     msg;
  207.  
  208.     // parse the command-line
  209.  
  210.     if (szCmdLine)
  211.     {
  212.         LPSTR   sz = strtok(szCmdLine, " \t");
  213.  
  214.         vfServer = (sz && !strcmpi(sz, "-Embedding"));
  215.     }    
  216.     // initialize COM
  217.     hr = CoInitialize(NULL);
  218.     if (FAILED(hr))
  219.         {
  220.         MessageBeep(0);
  221.         return hr;
  222.         }
  223.  
  224.     // register the CObject class in the registry so
  225.     // that the client can create instances of the server
  226.     if (!FAutoRegister(hinst))
  227.         {
  228.         hr = GetLastError();
  229.         goto LCleanup;
  230.         }
  231.  
  232.     if (vfServer)
  233.         {
  234.         // create the threads and synchronization events
  235.         // which the server will need
  236.         for (i=0; i<cServerThreads; i++)
  237.             {
  238.             TCHAR    rgch[32];
  239.  
  240.             // create the thread suspended so its event can be
  241.             // created using its thread-id and it will be able to
  242.             // use it as soon as it runs
  243.             vrghThread[i] = CreateThread(NULL,
  244.                 0,
  245.                 (LPTHREAD_START_ROUTINE)&ServerThreadProc,
  246.                 0,
  247.                 CREATE_SUSPENDED,
  248.                 &vrgtid[i]);
  249.             if (vrghThread[i] == NULL)
  250.                 {
  251.                 hr = GetLastError();
  252.                 goto LCleanup;
  253.                 }
  254.  
  255.             // a thread can use its thread-id to OpenEvent this existing
  256.             // event at any time. it can also look for its thread-id in
  257.             // vrgtid[] to determine its index for use with vrghEvent.
  258.             // this event signals to a worker thread to create a new CObject
  259.             wsprintf(rgch, TEXT("Thread_%d"), vrgtid[i]);
  260.             vrghEvent[i] = CreateEvent(NULL, FALSE, FALSE, rgch);
  261.             if (vrghEvent[i] == NULL)
  262.                 {
  263.                 hr = GetLastError();
  264.                 goto LCleanup;
  265.                 }
  266.  
  267.             // now that the event is available, let the thread run
  268.             ResumeThread(vrghThread[i]);
  269.             }
  270.  
  271.         // this signals the status of a worker threads creation after
  272.         // receiving its create signal via vrghEvent[i]
  273.         vhEventServer = CreateEvent(NULL, FALSE, FALSE, TEXT("Server"));
  274.         if (vhEventServer == NULL)
  275.             {
  276.             hr = GetLastError();
  277.             goto LCleanup;
  278.             }
  279.  
  280.         // register the class-factory with COM
  281.         hr = CoRegisterClassObject(CLSID_CObject,
  282.             (IUnknown *)&vclassfactory,
  283.             CLSCTX_LOCAL_SERVER,
  284.             REGCLS_MULTIPLEUSE,
  285.             &dwRegister);
  286.         if (FAILED(hr))
  287.             goto LCleanup;
  288.  
  289.         // create an IStream to be used for marshalling new objects between
  290.         // the worker and the CClassFactory
  291.         hr = CreateStreamOnHGlobal(NULL, TRUE, &vpstmMarshalling);
  292.         if (FAILED(hr))
  293.             goto LCleanup;
  294.         }
  295.     else
  296.         {
  297.         // this is the client case: create an instance of the service object
  298.         // in the server
  299.         hr = CoCreateInstance(CLSID_CObject,
  300.             NULL,
  301.             CLSCTX_LOCAL_SERVER,
  302.             IID_IUnknown,
  303.             (void**)&vpunkService);
  304.         if (FAILED(hr))
  305.             goto LCleanup;
  306.         }
  307.  
  308.     // create the client and server UI
  309.     memset(&wndclass, 0, sizeof(wndclass));
  310.     wndclass.lpszClassName = szWindowClass;
  311.     wndclass.style = CS_HREDRAW | CS_VREDRAW;
  312.     wndclass.lpfnWndProc = MainWndProc;
  313.     wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  314.     wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
  315.     wndclass.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);
  316.     wndclass.hInstance = hinst;
  317.  
  318.     if (!RegisterClass(&wndclass) ||
  319.         (vhwndMain = CreateWindow(szWindowClass,
  320.             vfServer ? szTitleServer : szTitleClient,
  321.             WS_OVERLAPPEDWINDOW,
  322.             CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
  323.             HWND_DESKTOP, NULL, hinst, NULL)) == NULL)
  324.         {
  325.         hr = GetLastError();
  326.         goto LCleanup;
  327.         }
  328.  
  329.     // display clients as minimized, server as a normal window
  330.     ShowWindow(vhwndMain, vfServer ? nCmdShow : SW_SHOWMINNOACTIVE);
  331.  
  332.     while (GetMessage(&msg, NULL, 0, 0))
  333.         {
  334.         TranslateMessage(&msg);
  335.         DispatchMessage(&msg);
  336.         }
  337.     hr = msg.wParam;
  338.  
  339. LCleanup:
  340.     if (hr != S_OK)
  341.         MessageBeep(0);
  342.     if (vfServer)
  343.         {
  344.         // we explicitly don't clean up threads and events
  345.         if (dwRegister != 0)
  346.             CoRevokeClassObject(dwRegister);
  347.         if (vpstmMarshalling != NULL)
  348.             vpstmMarshalling->Release();
  349.         }
  350.     else
  351.         {
  352.         // this is the client case: make sure to release the service
  353.         if (vpunkService != NULL)
  354.             vpunkService->Release();
  355.         }
  356.  
  357.     CoUninitialize();
  358.     return hr;
  359. }  // WinMain
  360.  
  361. // ---------------------------------------------------------------------------
  362. // %%Function: FAutoRegister
  363. //  Registers the CObject class in the registry.
  364. // ---------------------------------------------------------------------------
  365.  BOOL
  366. FAutoRegister(HINSTANCE hinst)
  367. {
  368.     static TCHAR szClassDesc[] = TEXT("Ole Apartments Sample");
  369.     static TCHAR szCLSIDEntry[] = TEXT("CLSID\\{5c06abc0-2dcd-11ce-8417-00aa00389b71}");
  370.     TCHAR       szBuf[512];
  371.     TCHAR       szPath[512];
  372.     HKEY        hkeyT = NULL;
  373.  
  374.     // install the OLEPerf OLE1/OLE2 compatibility sections
  375.     if ((RegSetValue(HKEY_CLASSES_ROOT, szCLSIDEntry, REG_SZ, szClassDesc,
  376.             lstrlen(szClassDesc)) != ERROR_SUCCESS) ||
  377.         (RegCreateKey(HKEY_CLASSES_ROOT, szCLSIDEntry, &hkeyT)
  378.             != ERROR_SUCCESS) ||
  379.         !GetModuleFileName(hinst, szBuf, sizeof(szBuf)))
  380.         return FALSE;
  381.     lstrcpy(szPath, szBuf);
  382.     if (RegSetValue(hkeyT, TEXT("LocalServer32"), REG_SZ, szBuf, lstrlen(szBuf))
  383.             != ERROR_SUCCESS)
  384.         goto LErrExit;
  385.     RegCloseKey(hkeyT);
  386.     return TRUE;
  387. LErrExit:
  388.     RegCloseKey(hkeyT);
  389.     return FALSE;
  390. }  // FAutoRegister
  391.  
  392. // ===========================================================================
  393. //                          C C L A S S F A C T O R Y
  394. // ===========================================================================
  395.  
  396. // ---------------------------------------------------------------------------
  397. // %%Function: CClassFactory::QueryInterface
  398. //  Returns a new reference of the specified iid-type to a CClassFactory.
  399. // ---------------------------------------------------------------------------
  400.  STDMETHODIMP
  401. CClassFactory::QueryInterface(REFIID iid, void **ppv)
  402. {
  403.     *ppv = NULL;
  404.  
  405.     if (iid == IID_IClassFactory || iid == IID_IUnknown)
  406.         {
  407.         *ppv = (IClassFactory *)this;
  408.         }
  409.     if (*ppv != NULL)
  410.         {
  411.         AddRef();
  412.         return S_OK;
  413.         }
  414.     return E_NOINTERFACE;
  415. }  // CClassFactory::QueryInterface
  416.  
  417. // ---------------------------------------------------------------------------
  418. // %%Function: CClassFactory::CreateInstance
  419. //  Creates a new instance of a CObject on the next worker thread.
  420. // ---------------------------------------------------------------------------
  421.  STDMETHODIMP
  422. CClassFactory::CreateInstance(LPUNKNOWN punkOuter, REFIID iid, void **ppv)
  423. {
  424.     LPUNKNOWN   punk;
  425.     HRESULT     hr;
  426.  
  427.     *ppv = NULL;
  428.     if (punkOuter != NULL)
  429.         return CLASS_E_NOAGGREGATION;
  430.  
  431.     // trigger the worker thread that we want to create an object
  432.     SetEvent(vrghEvent[viNextThread]);
  433.  
  434.     // now wait for the object to signal its completion
  435.     WaitForSingleObject(vhEventServer, INFINITE);
  436.  
  437.     // once the worker thread signals completion, vhrThreadStatus
  438.     // lets us know if the creation process was successful, and if
  439.     // vpstmMarshalling creates a marshalled interface pointer
  440.     if (FAILED(vhrThreadStatus))
  441.         return vhrThreadStatus;
  442.  
  443.     // unmarshal an IUnknown from the scratch stream. if unmarshaling
  444.     // fails, it takes care of releasing the object inside the marshal-data
  445.     hr = vpstmMarshalling->Seek(bZero, STREAM_SEEK_SET, NULL);
  446.     if (FAILED(hr))
  447.         return hr;
  448.     hr = CoUnmarshalInterface(vpstmMarshalling, IID_IUnknown, (void **)&punk);
  449.     if (FAILED(hr))
  450.         return hr;
  451.  
  452.     // get a reference to the interface asked for
  453.     hr = punk->QueryInterface(iid, ppv);
  454.     punk->Release();
  455.  
  456.     viNextThread++;
  457.     viNextThread %= cServerThreads;
  458.  
  459.     return hr;
  460. }  // CClassFactory::CreateInstance
  461.  
  462.  STDMETHODIMP
  463. CClassFactory::LockServer(BOOL fLock)
  464. {
  465.     // there's no need to support this for this sample
  466.     return E_FAIL;
  467. }  // CClassFactory::LockServer
  468.  
  469.  
  470. // ===========================================================================
  471. //                               C O B J E C T
  472. // ===========================================================================
  473.  
  474. // ---------------------------------------------------------------------------
  475. // %%Function: ServerThreadProc
  476. //  The worker thread function. Handles messages for objects of its thread/apt
  477. // and creates new objects.
  478. // ---------------------------------------------------------------------------
  479.  LRESULT
  480. ServerThreadProc(LPARAM lParam)
  481. {
  482.     HRESULT hr;
  483.     MSG     msg;
  484.     int     iThread;
  485.  
  486.     // figure out which thread this is: it needs its synchronization event
  487.     for (iThread=0; iThread<cServerThreads; iThread++)
  488.         {
  489.         if (vrgtid[iThread] == GetCurrentThreadId())
  490.             break;
  491.         }
  492.     if (iThread==cServerThreads)
  493.         return E_UNEXPECTED;
  494.  
  495.     // initialize COM
  496.     hr = CoInitialize(NULL);
  497.     if (FAILED(hr))
  498.         {
  499.         MessageBeep(0);
  500.         return hr;
  501.         }
  502.  
  503.     // apartment message/event loop
  504.     // (see SDK documentation for MsgWaitForMultipleObjects)
  505.     // here worker message loops last forever. in situations without a
  506.     // static number of worker threads, the loop could easily be terminated by
  507.     // WM_QUITs sent from the main thread which might manage the worker thread
  508.     // pool more carefully.
  509.     while (TRUE)
  510.         {
  511.         DWORD dwWaitResult;
  512.  
  513.         // wait for any message sent or posted to this queue
  514.         // or for one of the passed handles to become signaled
  515.         dwWaitResult = MsgWaitForMultipleObjects(1, &vrghEvent[iThread],
  516.             FALSE, INFINITE, QS_ALLINPUT);
  517.  
  518.         // result tells us the type of event we have:
  519.         // a message or a signaled handle
  520.  
  521.         // if there are one or more messages in the queue ...
  522.         if (dwWaitResult == (WAIT_OBJECT_0 + 1))
  523.             {
  524.             // dispatch all of the messages in this next loop
  525.             // (here is where we'd check for WM_QUITs to end this
  526.             // worker thread if we wanted to)
  527.             while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  528.                 DispatchMessage(&msg);
  529.             }
  530.         else
  531.             {
  532.             // this thread was signaled to create a new object
  533.             try
  534.                 {
  535.                 LPUNKNOWN   punk;
  536.  
  537.                 // create a new CObject
  538.                 
  539.             CObject* pCobj = new CObject;
  540.             hr = pCobj->init();
  541.             if (FAILED(hr))
  542.             {
  543.                 throw hr;
  544.             }
  545.                 punk = (IUnknown*)pCobj;            
  546.                 
  547.                 if (punk == NULL)
  548.                     throw E_OUTOFMEMORY;
  549.  
  550.                 hr = vpstmMarshalling->Seek(bZero, STREAM_SEEK_SET, NULL);
  551.                 if (FAILED(hr))
  552.                     throw hr;
  553.                 hr = CoMarshalInterface(vpstmMarshalling,
  554.                     IID_IUnknown,
  555.                     punk,
  556.                     MSHCTX_INPROC,
  557.                     NULL,
  558.                     MSHLFLAGS_NORMAL);
  559.                 if (FAILED(hr))
  560.                     throw hr;
  561.  
  562.                 // punk is now referenced by its marshal-data in vpstmMarshalling.
  563.                 // we release our local reference here so the unmarshaller will
  564.                 // have the sole reference. a common mistake is to forget this
  565.                 // release and end up with orphaned objects in the server.
  566.                 punk->Release();
  567.  
  568.                 // modify the global state -- the # of objects/thread -- which is
  569.                 // displayed in the server UI
  570.                 vrgcObjects[iThread]++;
  571.                 InvalidateRect(vhwndMain, NULL, TRUE);
  572.  
  573.                 vhrThreadStatus = S_OK;
  574.                 }
  575.             catch (HRESULT hr)
  576.                 {
  577.                 vhrThreadStatus = hr;
  578.                 }
  579.             SetEvent(vhEventServer);
  580.             }
  581.  
  582.         }
  583.  
  584.     CoUninitialize();
  585.     return msg.wParam;
  586. }  // ServerThreadProc
  587.  
  588. // ---------------------------------------------------------------------------
  589. // %%Function: CObject::QueryInterface
  590. //  Returns a new reference of the specified iid-type to a CObject.
  591. // ---------------------------------------------------------------------------
  592.  STDMETHODIMP
  593. CObject::QueryInterface(REFIID iid, void **ppv)
  594. {
  595.     HRESULT hr=S_OK;
  596.     *ppv = NULL;
  597.  
  598.     if (iid == IID_IUnknown)
  599.         {
  600.         *ppv = (IUnknown *)this;
  601.     AddRef();
  602.     return S_OK;
  603.         }
  604.     else
  605.     {
  606.         return punkInner->QueryInterface(iid,ppv);
  607.     }
  608. }  // CObject::QueryInterface
  609. //----------------------------------------------------------------------------
  610. // %%Function: CObject::init
  611. //    Creates the inner Java COM object that will be aggregated with ourself.
  612. //----------------------------------------------------------------------------
  613.  STDMETHODIMP_(HRESULT)
  614. CObject::init()
  615. {
  616.         // Creates an instance of the inner Java COM object that is aggregated.
  617.  
  618.         return CoCreateInstance(CLSID_SERVEDOBJECT,
  619.                                         this,
  620.                                         CLSCTX_INPROC_SERVER,
  621.                                         IID_IUnknown,
  622.                                         (void**)&punkInner);
  623. } //CObject:init
  624. // ---------------------------------------------------------------------------
  625. // %%Function: CObject::Release
  626. //  Handles releases of references to a CObject. Purpose here is to have code
  627. // which alters the global state which is displayed in the servers UI.
  628. // ---------------------------------------------------------------------------
  629.  STDMETHODIMP_(ULONG)
  630. CObject::Release(void)
  631. {
  632.     if (--mcRef == 0)
  633.         {
  634.         // change the global server state -- the # of objects/thread --
  635.         // reflected in the server UI
  636.         for (int i=0; i<cServerThreads; i++)
  637.             {
  638.             if (vrgtid[i] == GetCurrentThreadId())
  639.                 {
  640.                 vrgcObjects[i]--;
  641.                 InvalidateRect(vhwndMain, NULL, TRUE);
  642.                 break;
  643.                 }
  644.             }
  645.     punkInner->Release();
  646.     punkInner = NULL;
  647.         delete this;
  648.         return 0;
  649.         }
  650.     return mcRef;
  651. }  // CObject::Release
  652.  
  653. // EOF =======================================================================
  654.