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 / ekoala4 / ekoala4.cpp next >
C/C++ Source or Header  |  1995-05-03  |  9KB  |  433 lines

  1. /*
  2.  * EKOALA4.CPP
  3.  * Koala Object EXE Server with Custom Interface Chapter 6
  4.  *
  5.  * Example object with a custom interface 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 "ekoala4.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.         case WM_DESTROY:
  84.             PostQuitMessage(0);
  85.             break;
  86.  
  87.         default:
  88.             return (DefWindowProc(hWnd, iMsg, wParam, lParam));
  89.         }
  90.  
  91.     return 0L;
  92.     }
  93.  
  94.  
  95.  
  96.  
  97. /*
  98.  * ObjectDestroyed
  99.  *
  100.  * Purpose:
  101.  *  Function for the Koala object to call when it gets destroyed.
  102.  *  We destroy the main window if the proper conditions are met
  103.  *  for shutdown.
  104.  */
  105.  
  106. void ObjectDestroyed(void)
  107.     {
  108.     g_cObj--;
  109.  
  110.     //No more objects and no locks, shut the app down.
  111.     if (0L==g_cObj && 0L==g_cLock && IsWindow(g_hWnd))
  112.         PostMessage(g_hWnd, WM_CLOSE, 0, 0L);
  113.  
  114.     return;
  115.     }
  116.  
  117.  
  118.  
  119.  
  120. /*
  121.  * CApp::CApp
  122.  * CApp::~CApp
  123.  *
  124.  * Constructor Parameters:
  125.  *  hInst           HINSTANCE of the Application from WinMain
  126.  *  hInstPrev       HINSTANCE of a previous instance from WinMain
  127.  *  pszCmdLine      LPSTR of the command line.
  128.  *  nCmdShow        UINT specifying how to show the app window,
  129.  *                  from WinMain.
  130.  */
  131.  
  132. CApp::CApp(HINSTANCE hInst, HINSTANCE hInstPrev
  133.     , LPSTR pszCmdLine, UINT nCmdShow)
  134.     {
  135.     //Initialize WinMain parameter holders.
  136.     m_hInst     =hInst;
  137.     m_hInstPrev =hInstPrev;
  138.     m_pszCmdLine=pszCmdLine;
  139.     m_nCmdShow  =nCmdShow;
  140.  
  141.     m_hWnd=NULL;
  142.     m_dwRegCO=0;
  143.     m_pIClassFactory=NULL;
  144.     m_fInitialized=FALSE;
  145.     return;
  146.     }
  147.  
  148.  
  149. CApp::~CApp(void)
  150.     {
  151.     //Opposite of CoRegisterClassObject; class factory ref is now 1
  152.     if (0L!=m_dwRegCO)
  153.         CoRevokeClassObject(m_dwRegCO);
  154.  
  155.     //The last Release, which frees the class factory.
  156.     if (NULL!=m_pIClassFactory)
  157.         m_pIClassFactory->Release();
  158.  
  159.     if (m_fInitialized)
  160.         CoUninitialize();
  161.  
  162.     return;
  163.     }
  164.  
  165.  
  166.  
  167.  
  168. /*
  169.  * CApp::Init
  170.  *
  171.  * Purpose:
  172.  *  Initializes an CApp object by registering window classes,
  173.  *  creating the main window, and doing anything else prone to
  174.  *  failure.  If this function fails the caller should guarantee
  175.  *  that the destructor is called.
  176.  *
  177.  * Parameters:
  178.  *  None
  179.  *
  180.  * Return Value:
  181.  *  BOOL            TRUE if successful, FALSE otherwise.
  182.  */
  183.  
  184. BOOL CApp::Init(void)
  185.     {
  186.     WNDCLASS    wc;
  187.     HRESULT     hr;
  188.    #ifndef WIN32
  189.     DWORD       dwVer;
  190.    #endif
  191.  
  192.     //Fail if we're run outside of CoGetClassObject
  193.     if (lstrcmpiA(m_pszCmdLine, "-Embedding")
  194.         && lstrcmpiA(m_pszCmdLine, "/Embedding"))
  195.         return FALSE;
  196.  
  197.    #ifndef WIN32
  198.     dwVer=CoBuildVersion();
  199.  
  200.     if (rmm!=HIWORD(dwVer))
  201.         return FALSE;
  202.  
  203.     //No need to check minor versions.
  204.    #endif
  205.  
  206.     //Call CoInitialize so we can call other Co* functions
  207.     if (FAILED(CoInitialize(NULL)))
  208.         return FALSE;
  209.  
  210.     m_fInitialized=TRUE;
  211.  
  212.     if (!m_hInstPrev)
  213.         {
  214.         wc.style          = CS_HREDRAW | CS_VREDRAW;
  215.         wc.lpfnWndProc    = KoalaWndProc;
  216.         wc.cbClsExtra     = 0;
  217.         wc.cbWndExtra     = CBWNDEXTRA;
  218.         wc.hInstance      = m_hInst;
  219.         wc.hIcon          = NULL;
  220.         wc.hCursor        = NULL;
  221.         wc.hbrBackground  = (HBRUSH)(COLOR_WINDOW + 1);
  222.         wc.lpszMenuName   = NULL;
  223.         wc.lpszClassName  = TEXT("Koala");
  224.  
  225.         if (!RegisterClass(&wc))
  226.             return FALSE;
  227.         }
  228.  
  229.     m_hWnd=CreateWindow(TEXT("Koala"), TEXT("Koala")
  230.         , WS_OVERLAPPEDWINDOW, 35, 35, 350, 250
  231.         , NULL, NULL, m_hInst, this);
  232.  
  233.     if (NULL==m_hWnd)
  234.         return FALSE;
  235.  
  236.     g_hWnd=m_hWnd;
  237.  
  238.     /*
  239.      * Create our class factory and register it for this application
  240.      * using CoRegisterClassObject. We are able to service more than
  241.      * one object at a time so we use REGCLS_MULTIPLEUSE.
  242.      */
  243.     m_pIClassFactory=new CKoalaClassFactory();
  244.  
  245.     if (NULL==m_pIClassFactory)
  246.         return FALSE;
  247.  
  248.     //Since we hold on to this, we should AddRef it.
  249.     m_pIClassFactory->AddRef();
  250.  
  251.     hr=CoRegisterClassObject(CLSID_Koala, m_pIClassFactory
  252.         , CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &m_dwRegCO);
  253.  
  254.     if (FAILED(hr))
  255.         return FALSE;
  256.  
  257.     return TRUE;
  258.     }
  259.  
  260.  
  261.  
  262.  
  263.  
  264. /*
  265.  * CKoalaClassFactory::CKoalaClassFactory
  266.  * CKoalaClassFactory::~CKoalaClassFactory
  267.  *
  268.  * Constructor Parameters:
  269.  *  None
  270.  */
  271.  
  272. CKoalaClassFactory::CKoalaClassFactory(void)
  273.     {
  274.     m_cRef=0L;
  275.     return;
  276.     }
  277.  
  278. CKoalaClassFactory::~CKoalaClassFactory(void)
  279.     {
  280.     return;
  281.     }
  282.  
  283.  
  284.  
  285.  
  286. /*
  287.  * CKoalaClassFactory::QueryInterface
  288.  * CKoalaClassFactory::AddRef
  289.  * CKoalaClassFactory::Release
  290.  */
  291.  
  292. STDMETHODIMP CKoalaClassFactory::QueryInterface(REFIID riid
  293.     , PPVOID ppv)
  294.     {
  295.     *ppv=NULL;
  296.  
  297.     if (IID_IUnknown==riid || IID_IClassFactory==riid)
  298.         *ppv=this;
  299.  
  300.     if (NULL!=*ppv)
  301.         {
  302.         ((LPUNKNOWN)*ppv)->AddRef();
  303.         return NOERROR;
  304.         }
  305.  
  306.     return ResultFromScode(E_NOINTERFACE);
  307.     }
  308.  
  309.  
  310. STDMETHODIMP_(ULONG) CKoalaClassFactory::AddRef(void)
  311.     {
  312.     return ++m_cRef;
  313.     }
  314.  
  315.  
  316. STDMETHODIMP_(ULONG) CKoalaClassFactory::Release(void)
  317.     {
  318.     if (0L!=--m_cRef)
  319.         return m_cRef;
  320.  
  321.     delete this;
  322.     return 0;
  323.     }
  324.  
  325.  
  326.  
  327.  
  328.  
  329.  
  330. /*
  331.  * CKoalaClassFactory::CreateInstance
  332.  *
  333.  * Purpose:
  334.  *  Instantiates a Koala object returning an interface pointer.
  335.  *
  336.  * Parameters:
  337.  *  pUnkOuter       LPUNKNOWN to the controlling IUnknown if we are
  338.  *                  being used in an aggregation.
  339.  *  riid            REFIID identifying the interface the caller
  340.  *                  desires to have for the new object.
  341.  *  ppvObj          PPVOID in which to store the desired
  342.  *                  interface pointer for the new object.
  343.  *
  344.  * Return Value:
  345.  *  HRESULT         NOERROR if successful, otherwise E_NOINTERFACE
  346.  *                  if we cannot support the requested interface.
  347.  */
  348.  
  349. STDMETHODIMP CKoalaClassFactory::CreateInstance(LPUNKNOWN pUnkOuter
  350.     , REFIID riid, PPVOID ppvObj)
  351.     {
  352.     PCKoala             pObj;
  353.     HRESULT             hr;
  354.  
  355.     *ppvObj=NULL;
  356.     hr=ResultFromScode(E_OUTOFMEMORY);
  357.  
  358.     //Verify that a controlling unknown asks for IUnknown
  359.     if (NULL!=pUnkOuter && IID_IUnknown!=riid)
  360.         return ResultFromScode(CLASS_E_NOAGGREGATION);
  361.  
  362.     //Create the object telling us to notify us when it's gone.
  363.     pObj=new CKoala(pUnkOuter, ObjectDestroyed);
  364.  
  365.     if (NULL==pObj)
  366.         {
  367.         //This starts shutdown if there are no other objects.
  368.         g_cObj++;
  369.         ObjectDestroyed();
  370.         return hr;
  371.         }
  372.  
  373.     if (pObj->Init())
  374.         hr=pObj->QueryInterface(riid, ppvObj);
  375.  
  376.     g_cObj++;
  377.  
  378.     /*
  379.      * Kill the object if initial creation or Init failed. If
  380.      * the object failed, we handle the g_cObj increment above
  381.      * in ObjectDestroyed.
  382.      */
  383.     if (FAILED(hr))
  384.         {
  385.         delete pObj;
  386.         ObjectDestroyed();  //Handle shutdown cases.
  387.         }
  388.  
  389.     return hr;
  390.     }
  391.  
  392.  
  393.  
  394.  
  395.  
  396.  
  397. /*
  398.  * CKoalaClassFactory::LockServer
  399.  *
  400.  * Purpose:
  401.  *  Increments or decrements the lock count of the serving
  402.  *  IClassFactory object.  When the number of locks goes to
  403.  *  zero and the number of objects is zero, we shut down the
  404.  *  application.
  405.  *
  406.  * Parameters:
  407.  *  fLock           BOOL specifying whether to increment or
  408.  *                  decrement the lock count.
  409.  *
  410.  * Return Value:
  411.  *  HRESULT         NOERROR always.
  412.  */
  413.  
  414. STDMETHODIMP CKoalaClassFactory::LockServer(BOOL fLock)
  415.     {
  416.     if (fLock)
  417.         g_cLock++;
  418.     else
  419.         {
  420.         g_cLock--;
  421.  
  422.         /*
  423.          * Fake an object destruction:  this centralizes
  424.          * all the shutdown code in the ObjectDestroyed
  425.          * function, eliminating duplicate code here.
  426.          */
  427.         g_cObj++;
  428.         ObjectDestroyed();
  429.         }
  430.  
  431.     return NOERROR;
  432.     }
  433.