home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / com / inole2 / chap06 / ekoala3 / ekoala3.cpp next >
Encoding:
C/C++ Source or Header  |  1995-05-03  |  15.7 KB  |  692 lines

  1. /*
  2.  * EKOALA3.CPP
  3.  * Koala Object EXE Server Chapter 6
  4.  *
  5.  * Example object implemented in an EXE.
  6.  *
  7.  * Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  8.  *
  9.  * Kraig Brockschmidt, Microsoft
  10.  * Internet  :  kraigb@microsoft.com
  11.  * Compuserve:  >INTERNET:kraigb@microsoft.com
  12.  */
  13.  
  14.  
  15. #define INITGUIDS
  16. #include "ekoala3.h"
  17.  
  18.  
  19. //Count number of objects and number of locks.
  20. ULONG       g_cObj=0;
  21. ULONG       g_cLock=0;
  22.  
  23. //Make window handle global so other code can cause a shutdown
  24. HWND        g_hWnd=NULL;
  25.  
  26.  
  27. /*
  28.  * WinMain
  29.  *
  30.  * Purpose:
  31.  *  Main entry point of application.
  32.  */
  33.  
  34. int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hInstPrev
  35.     , LPSTR pszCmdLine, int nCmdShow)
  36.     {
  37.     MSG         msg;
  38.     PAPP        pApp;
  39.  
  40.     SETMESSAGEQUEUE;
  41.  
  42.     pApp=new CApp(hInst, hInstPrev, pszCmdLine, nCmdShow);
  43.  
  44.     if (NULL==pApp)
  45.         return -1;
  46.  
  47.     if (pApp->Init())
  48.         {
  49.         while (GetMessage(&msg, NULL, 0,0 ))
  50.             {
  51.             TranslateMessage(&msg);
  52.             DispatchMessage(&msg);
  53.             }
  54.         }
  55.  
  56.     delete pApp;
  57.     return msg.wParam;
  58.     }
  59.  
  60.  
  61.  
  62. /*
  63.  * KoalaWndProc
  64.  *
  65.  * Purpose:
  66.  *  Standard window class procedure.
  67.  */
  68.  
  69. LRESULT APIENTRY KoalaWndProc(HWND hWnd, UINT iMsg
  70.     , WPARAM wParam, LPARAM lParam)
  71.     {
  72.     PAPP        pApp;
  73.  
  74.     pApp=(PAPP)GetWindowLong(hWnd, KOALAWL_STRUCTURE);
  75.  
  76.     switch (iMsg)
  77.         {
  78.         case WM_NCCREATE:
  79.             pApp=(PAPP)(((LPCREATESTRUCT)lParam)->lpCreateParams);
  80.             SetWindowLong(hWnd, KOALAWL_STRUCTURE, (LONG)pApp);
  81.             return (DefWindowProc(hWnd, iMsg, wParam, lParam));
  82.  
  83.         //CHAPTER6MOD
  84.         case WM_COMMAND:
  85.             switch (LOWORD(wParam))
  86.                 {
  87.                 case IDM_CALLBLOCK:
  88.                     pApp->m_fBlock=!pApp->m_fBlock;
  89.                     CheckMenuItem(GetMenu(hWnd), IDM_CALLBLOCK
  90.                         , pApp->m_fBlock ? MF_CHECKED : MF_UNCHECKED);
  91.                     break;
  92.  
  93.                 case IDM_CALLDELAY:
  94.                     pApp->m_fDelay=!pApp->m_fDelay;
  95.                     CheckMenuItem(GetMenu(hWnd), IDM_CALLDELAY
  96.                         , pApp->m_fDelay ? MF_CHECKED : MF_UNCHECKED);
  97.                     break;
  98.                 }
  99.             break;
  100.  
  101.  
  102.         case WM_CLOSE:
  103.             //Don't close with object's active
  104.             if (0==g_cObj && 0==g_cLock)
  105.                 return (DefWindowProc(hWnd, iMsg, wParam, lParam));
  106.  
  107.             break;
  108.         //End CHAPTER6MOD
  109.  
  110.         case WM_DESTROY:
  111.             PostQuitMessage(0);
  112.             break;
  113.  
  114.         default:
  115.             return (DefWindowProc(hWnd, iMsg, wParam, lParam));
  116.         }
  117.  
  118.     return 0L;
  119.     }
  120.  
  121.  
  122.  
  123.  
  124. /*
  125.  * ObjectDestroyed
  126.  *
  127.  * Purpose:
  128.  *  Function for the Koala object to call when it gets destroyed.
  129.  *  We destroy the main window if the proper conditions are met
  130.  *  for shutdown.
  131.  */
  132.  
  133. void ObjectDestroyed(void)
  134.     {
  135.     g_cObj--;
  136.  
  137.     //No more objects and no locks, shut the app down.
  138.     if (0L==g_cObj && 0L==g_cLock && IsWindow(g_hWnd))
  139.         PostMessage(g_hWnd, WM_CLOSE, 0, 0L);
  140.  
  141.     return;
  142.     }
  143.  
  144.  
  145.  
  146.  
  147. /*
  148.  * CApp::CApp
  149.  * CApp::~CApp
  150.  *
  151.  * Constructor Parameters:
  152.  *  hInst           HINSTANCE of the Application from WinMain
  153.  *  hInstPrev       HINSTANCE of a previous instance from WinMain
  154.  *  pszCmdLine      LPSTR of the command line.
  155.  *  nCmdShow        UINT specifying how to show the app window,
  156.  *                  from WinMain.
  157.  */
  158.  
  159. CApp::CApp(HINSTANCE hInst, HINSTANCE hInstPrev
  160.     , LPSTR pszCmdLine, UINT nCmdShow)
  161.     {
  162.     //Initialize WinMain parameter holders.
  163.     m_hInst     =hInst;
  164.     m_hInstPrev =hInstPrev;
  165.     m_pszCmdLine=pszCmdLine;
  166.     m_nCmdShow  =nCmdShow;
  167.  
  168.     m_hWnd=NULL;
  169.     m_dwRegCO=0;
  170.     m_pIClassFactory=NULL;
  171.     m_fInitialized=FALSE;
  172.  
  173.     //CHAPTER6MOD
  174.     m_pMsgFilter=NULL;
  175.     m_fBlock=FALSE;
  176.     m_fDelay=FALSE;
  177.     //End CHAPTER6MOD
  178.     return;
  179.     }
  180.  
  181.  
  182. CApp::~CApp(void)
  183.     {
  184.     //CHAPTER6MOD
  185.     if (NULL!=m_pMsgFilter)
  186.         {
  187.         CoRegisterMessageFilter(NULL, NULL);
  188.         ReleaseInterface(m_pMsgFilter);
  189.         }
  190.     //End CHAPTER6MOD
  191.  
  192.     //Opposite of CoRegisterClassObject; class factory ref is now 1
  193.     if (0L!=m_dwRegCO)
  194.         CoRevokeClassObject(m_dwRegCO);
  195.  
  196.     //The last Release, which frees the class factory.
  197.     if (NULL!=m_pIClassFactory)
  198.         m_pIClassFactory->Release();
  199.  
  200.     if (m_fInitialized)
  201.         CoUninitialize();
  202.  
  203.     return;
  204.     }
  205.  
  206.  
  207.  
  208.  
  209. /*
  210.  * CApp::Init
  211.  *
  212.  * Purpose:
  213.  *  Initializes an CApp object by registering window classes,
  214.  *  creating the main window, and doing anything else prone to
  215.  *  failure.  If this function fails the caller should guarantee
  216.  *  that the destructor is called.
  217.  *
  218.  * Parameters:
  219.  *  None
  220.  *
  221.  * Return Value:
  222.  *  BOOL            TRUE if successful, FALSE otherwise.
  223.  */
  224.  
  225. BOOL CApp::Init(void)
  226.     {
  227.     WNDCLASS    wc;
  228.     HRESULT     hr;
  229.    #ifndef WIN32
  230.     DWORD       dwVer;
  231.    #endif
  232.  
  233.     //Fail if we're run outside of CoGetClassObject
  234.     if (lstrcmpiA(m_pszCmdLine, "-Embedding")
  235.         && lstrcmpiA(m_pszCmdLine, "/Embedding"))
  236.         return FALSE;
  237.  
  238.    #ifndef WIN32
  239.     dwVer=CoBuildVersion();
  240.  
  241.     if (rmm!=HIWORD(dwVer))
  242.         return FALSE;
  243.  
  244.     //No need to check minor versions.
  245.    #endif
  246.  
  247.     //Call CoInitialize so we can call other Co* functions
  248.     if (FAILED(CoInitialize(NULL)))
  249.         return FALSE;
  250.  
  251.     m_fInitialized=TRUE;
  252.  
  253.     if (!m_hInstPrev)
  254.         {
  255.         wc.style          = CS_HREDRAW | CS_VREDRAW;
  256.         wc.lpfnWndProc    = KoalaWndProc;
  257.         wc.cbClsExtra     = 0;
  258.         wc.cbWndExtra     = CBWNDEXTRA;
  259.         wc.hInstance      = m_hInst;
  260.         wc.hIcon          = NULL;
  261.         wc.hCursor        = NULL;
  262.         wc.hbrBackground  = (HBRUSH)(COLOR_WINDOW + 1);
  263.         //CHAPTER6MOD
  264.         wc.lpszMenuName   = MAKEINTRESOURCE(IDR_MENU);
  265.         //End CHAPTER6MOD
  266.         wc.lpszClassName  = TEXT("Koala");
  267.  
  268.         if (!RegisterClass(&wc))
  269.             return FALSE;
  270.         }
  271.  
  272.     //CHAPTER6MOD
  273.     m_hWnd=CreateWindow(TEXT("Koala"), TEXT("Koala Object")
  274.         , WS_OVERLAPPEDWINDOW, 400, 35, 350, 250
  275.         , NULL, NULL, m_hInst, this);
  276.  
  277.     if (NULL==m_hWnd)
  278.         return FALSE;
  279.  
  280.     ShowWindow(m_hWnd, SW_SHOW);
  281.     UpdateWindow(m_hWnd);
  282.     //End CHAPTER6MOD
  283.  
  284.     g_hWnd=m_hWnd;
  285.  
  286.     /*
  287.      * Create our class factory and register it for this application
  288.      * using CoRegisterClassObject. We are able to service more than
  289.      * one object at a time so we use REGCLS_MULTIPLEUSE.
  290.      */
  291.     m_pIClassFactory=new CKoalaClassFactory();
  292.  
  293.     if (NULL==m_pIClassFactory)
  294.         return FALSE;
  295.  
  296.     //Since we hold on to this, we should AddRef it.
  297.     m_pIClassFactory->AddRef();
  298.  
  299.     hr=CoRegisterClassObject(CLSID_Koala, m_pIClassFactory
  300.         , CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &m_dwRegCO);
  301.  
  302.     if (FAILED(hr))
  303.         return FALSE;
  304.  
  305.     //CHAPTER6MOD
  306.     /*
  307.      * Call CoLockObjectExternal to lock and unlock to show
  308.      * its strong lock effect through IExternalConnection.
  309.      */
  310.     CoLockObjectExternal(m_pIClassFactory, TRUE,  FALSE);
  311.     CoLockObjectExternal(m_pIClassFactory, FALSE, FALSE);
  312.  
  313.     //Create and register the message filter
  314.     m_pMsgFilter=new CMessageFilter(this);
  315.  
  316.     if (NULL!=m_pMsgFilter)
  317.         {
  318.         m_pMsgFilter->AddRef();
  319.  
  320.         if (FAILED(CoRegisterMessageFilter(m_pMsgFilter, NULL)))
  321.             ReleaseInterface(m_pMsgFilter);
  322.         }
  323.     //End CHAPTER6MOD
  324.  
  325.     return TRUE;
  326.     }
  327.  
  328.  
  329.  
  330.  
  331.  
  332.  
  333. /*
  334.  * CKoalaClassFactory::CKoalaClassFactory
  335.  * CKoalaClassFactory::~CKoalaClassFactory
  336.  *
  337.  * Constructor Parameters:
  338.  *  None
  339.  */
  340.  
  341. CKoalaClassFactory::CKoalaClassFactory(void)
  342.     {
  343.     m_cRef=0L;
  344.     //CHAPTER6MOD
  345.     m_pImpIExtConn=new CImpIExternalConnection(this, this);
  346.     //End CHAPTER6MOD
  347.     return;
  348.     }
  349.  
  350. CKoalaClassFactory::~CKoalaClassFactory(void)
  351.     {
  352.     //CHAPTER6MOD
  353.     DeleteInterfaceImp(m_pImpIExtConn);
  354.     //End CHAPTER6MOD
  355.     return;
  356.     }
  357.  
  358.  
  359.  
  360.  
  361. /*
  362.  * CKoalaClassFactory::QueryInterface
  363.  * CKoalaClassFactory::AddRef
  364.  * CKoalaClassFactory::Release
  365.  */
  366.  
  367. STDMETHODIMP CKoalaClassFactory::QueryInterface(REFIID riid
  368.     , PPVOID ppv)
  369.     {
  370.     *ppv=NULL;
  371.  
  372.     if (IID_IUnknown==riid || IID_IClassFactory==riid)
  373.         *ppv=this;
  374.  
  375.     //CHAPTER6MOD
  376.     if (IID_IExternalConnection==riid && NULL!=m_pImpIExtConn)
  377.         *ppv=m_pImpIExtConn;
  378.     //End CHAPTER6MOD
  379.  
  380.     if (NULL!=*ppv)
  381.         {
  382.         ((LPUNKNOWN)*ppv)->AddRef();
  383.         return NOERROR;
  384.         }
  385.  
  386.     return ResultFromScode(E_NOINTERFACE);
  387.     }
  388.  
  389.  
  390. STDMETHODIMP_(ULONG) CKoalaClassFactory::AddRef(void)
  391.     {
  392.     return ++m_cRef;
  393.     }
  394.  
  395.  
  396. STDMETHODIMP_(ULONG) CKoalaClassFactory::Release(void)
  397.     {
  398.     if (0L!=--m_cRef)
  399.         return m_cRef;
  400.  
  401.     delete this;
  402.     return 0;
  403.     }
  404.  
  405.  
  406.  
  407.  
  408.  
  409.  
  410. /*
  411.  * CKoalaClassFactory::CreateInstance
  412.  *
  413.  * Purpose:
  414.  *  Instantiates a Koala object returning an interface pointer.
  415.  *
  416.  * Parameters:
  417.  *  pUnkOuter       LPUNKNOWN to the controlling IUnknown if we are
  418.  *                  being used in an aggregation.
  419.  *  riid            REFIID identifying the interface the caller
  420.  *                  desires to have for the new object.
  421.  *  ppvObj          PPVOID in which to store the desired
  422.  *                  interface pointer for the new object.
  423.  *
  424.  * Return Value:
  425.  *  HRESULT         NOERROR if successful, otherwise E_NOINTERFACE
  426.  *                  if we cannot support the requested interface.
  427.  */
  428.  
  429. STDMETHODIMP CKoalaClassFactory::CreateInstance(LPUNKNOWN pUnkOuter
  430.     , REFIID riid, PPVOID ppvObj)
  431.     {
  432.     PCKoala             pObj;
  433.     HRESULT             hr;
  434.  
  435.     *ppvObj=NULL;
  436.     hr=ResultFromScode(E_OUTOFMEMORY);
  437.  
  438.     //Verify that a controlling unknown asks for IUnknown
  439.     if (NULL!=pUnkOuter && IID_IUnknown!=riid)
  440.         return ResultFromScode(CLASS_E_NOAGGREGATION);
  441.  
  442.     //Create the object telling us to notify us when it's gone.
  443.     pObj=new CKoala(pUnkOuter, ObjectDestroyed);
  444.  
  445.     if (NULL==pObj)
  446.         {
  447.         //This starts shutdown if there are no other objects.
  448.         g_cObj++;
  449.         ObjectDestroyed();
  450.         return hr;
  451.         }
  452.  
  453.     if (pObj->Init())
  454.         hr=pObj->QueryInterface(riid, ppvObj);
  455.  
  456.     g_cObj++;
  457.  
  458.     /*
  459.      * Kill the object if initial creation or Init failed. If
  460.      * the object failed, we handle the g_cObj increment above
  461.      * in ObjectDestroyed.
  462.      */
  463.     if (FAILED(hr))
  464.         {
  465.         delete pObj;
  466.         ObjectDestroyed();  //Handle shutdown cases.
  467.         }
  468.  
  469.     return hr;
  470.     }
  471.  
  472.  
  473.  
  474.  
  475.  
  476.  
  477. /*
  478.  * CKoalaClassFactory::LockServer
  479.  *
  480.  * Purpose:
  481.  *  Increments or decrements the lock count of the serving
  482.  *  IClassFactory object.  When the number of locks goes to
  483.  *  zero and the number of objects is zero, we shut down the
  484.  *  application.
  485.  *
  486.  * Parameters:
  487.  *  fLock           BOOL specifying whether to increment or
  488.  *                  decrement the lock count.
  489.  *
  490.  * Return Value:
  491.  *  HRESULT         NOERROR always.
  492.  */
  493.  
  494. STDMETHODIMP CKoalaClassFactory::LockServer(BOOL fLock)
  495.     {
  496.     if (fLock)
  497.         g_cLock++;
  498.     else
  499.         {
  500.         g_cLock--;
  501.  
  502.         /*
  503.          * Fake an object destruction:  this centralizes
  504.          * all the shutdown code in the ObjectDestroyed
  505.          * function, eliminating duplicate code here.
  506.          */
  507.         g_cObj++;
  508.         ObjectDestroyed();
  509.         }
  510.  
  511.     return NOERROR;
  512.     }
  513.  
  514.  
  515.  
  516.  
  517. //CHAPTER6MOD
  518. //Class factory implementation of IExternalConnection
  519.  
  520. /*
  521.  * CImpIExternalConnection::CImpIExternalConnection
  522.  * CImpIExternalConnection::~CImpIExternalConnection
  523.  *
  524.  * Parameters (Constructor):
  525.  *  pObj            PCKoalaClassFactory of the object we're in.
  526.  *  pUnkOuter       LPUNKNOWN to which we delegate.
  527.  */
  528.  
  529. CImpIExternalConnection::CImpIExternalConnection
  530.     (PCKoalaClassFactory pObj, LPUNKNOWN pUnkOuter)
  531.     {
  532.     m_cRef=0;
  533.     m_pObj=pObj;
  534.     m_pUnkOuter=pUnkOuter;
  535.  
  536.     m_cStrong=0;
  537.     m_cWeak=0;
  538.     return;
  539.     }
  540.  
  541. CImpIExternalConnection::~CImpIExternalConnection(void)
  542.     {
  543.     return;
  544.     }
  545.  
  546.  
  547.  
  548. /*
  549.  * CImpIExternalConnection::QueryInterface
  550.  * CImpIExternalConnection::AddRef
  551.  * CImpIExternalConnection::Release
  552.  *
  553.  * Purpose:
  554.  *  Delegating IUnknown members for CImpIExternalConnection.
  555.  */
  556.  
  557. STDMETHODIMP CImpIExternalConnection::QueryInterface(REFIID riid
  558.     , LPVOID *ppv)
  559.     {
  560.     return m_pUnkOuter->QueryInterface(riid, ppv);
  561.     }
  562.  
  563. STDMETHODIMP_(ULONG) CImpIExternalConnection::AddRef(void)
  564.     {
  565.     ++m_cRef;
  566.     return m_pUnkOuter->AddRef();
  567.     }
  568.  
  569. STDMETHODIMP_(ULONG) CImpIExternalConnection::Release(void)
  570.     {
  571.     --m_cRef;
  572.     return m_pUnkOuter->Release();
  573.     }
  574.  
  575.  
  576.  
  577.  
  578.  
  579. /*
  580.  * CImpIExternalConnection::AddConnection
  581.  *
  582.  * Purpose:
  583.  *  Informs the object that a strong connection has been made to it.
  584.  *
  585.  * Parameters:
  586.  *  dwConn          DWORD identifying the type of connection, taken
  587.  *                  from the EXTCONN enumeration.
  588.  *  dwReserved      DWORD reserved.  This is used inside OLE and
  589.  *                  should not be validated.
  590.  *
  591.  * Return Value:
  592.  *  DWORD           The number of connection counts on the
  593.  *                  object, used for debugging purposes only.
  594.  */
  595.  
  596. STDMETHODIMP_(DWORD) CImpIExternalConnection::AddConnection
  597.     (DWORD dwConn, DWORD dwReserved)
  598.     {
  599.     DWORD       dwRet;
  600.     TCHAR       szTemp[80];
  601.  
  602.     if (EXTCONN_STRONG & dwConn)
  603.         {
  604.         dwRet=++m_cStrong;
  605.         wsprintf(szTemp
  606.             , TEXT("AddConnection cStrong=%lu"), m_cStrong);
  607.         }
  608.  
  609.    #ifdef WIN32
  610.     if (EXTCONN_WEAK & dwConn)
  611.         {
  612.         dwRet=++m_cWeak;
  613.         wsprintf(szTemp
  614.             , TEXT("ReleaseConnection cWeak=%lu"), m_cWeak);
  615.         }
  616.    #endif
  617.  
  618.    #ifndef WIN32
  619.     ODS(szTemp);
  620.    #else
  621.     MessageBox(NULL, szTemp
  622.         , TEXT("EKoala3: CKoalaClassFactory::IExternalConnection")
  623.         , MB_OK);
  624.    #endif
  625.  
  626.     return dwRet;
  627.     }
  628.  
  629.  
  630.  
  631. /*
  632.  * CImpIExternalConnection::ReleaseConnection
  633.  *
  634.  * Purpose:
  635.  *  Informs an object that a connection has been taken away from
  636.  *  it in which case the object may need to shut down.
  637.  *
  638.  * Parameters:
  639.  *  dwConn              DWORD identifying the type of connection,
  640.  *                      taken from the EXTCONN enumeration.
  641.  *  dwReserved          DWORD reserved.  This is used inside OLE and
  642.  *                      should not be validated.
  643.  *  dwRerved            DWORD reserved
  644.  *  fLastReleaseCloses  BOOL indicating if the last call to this
  645.  *                      function should close the object.
  646.  *
  647.  * Return Value:
  648.  *  DWORD           The number of remaining connection counts on
  649.  *                  the object, used for debugging purposes only.
  650.  */
  651.  
  652. STDMETHODIMP_(DWORD) CImpIExternalConnection::ReleaseConnection
  653.     (DWORD dwConn, DWORD dwReserved, BOOL fLastReleaseCloses)
  654.     {
  655.     DWORD       dwRet;
  656.     TCHAR       szTemp[80];
  657.  
  658.     if (EXTCONN_STRONG & dwConn)
  659.         {
  660.         /*
  661.          * Note:  We don't need to close ourselves when the last
  662.          * strong lock is removed; we're just implementing this
  663.          * interface for demonstration.
  664.          */
  665.  
  666.         dwRet=--m_cStrong;
  667.         wsprintf(szTemp
  668.             , TEXT("ReleaseConnection cStrong=%lu"), m_cStrong);
  669.         }
  670.  
  671.    #ifdef WIN32
  672.     if (EXTCONN_WEAK & dwConn)
  673.         {
  674.         dwRet=--m_cWeak;
  675.         wsprintf(szTemp
  676.             , TEXT("ReleaseConnection cWeak=%lu"), m_cWeak);
  677.         }
  678.    #endif
  679.  
  680.    #ifndef WIN32
  681.     ODS(szTemp);
  682.    #else
  683.     MessageBox(NULL, szTemp
  684.         , TEXT("EKoala3: CKoalaClassFactory::IExternalConnection")
  685.         , MB_OK);
  686.    #endif
  687.  
  688.     return dwRet;
  689.     }
  690.  
  691. //End CHAPTER6MOD
  692.