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 / chap05 / ekoala2 / ekoala2.cpp next >
C/C++ Source or Header  |  1995-05-03  |  14KB  |  601 lines

  1. /*
  2.  * EKOALA2.CPP
  3.  * Koala Object EXE Self-Registering Server Chapter 5
  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 "ekoala2.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.     /*
  193.      * Check if we're being run for self-registration.  If so,
  194.      * do the job, then quit by returning FALSE from here.
  195.      */
  196.     if (0==lstrcmpiA(m_pszCmdLine, "-RegServer")
  197.         || 0==lstrcmpiA(m_pszCmdLine, "/RegServer"))
  198.         {
  199.         RegisterServer();
  200.         return FALSE;
  201.         }
  202.  
  203.     if (0==lstrcmpiA(m_pszCmdLine, "-UnregServer")
  204.         || 0==lstrcmpiA(m_pszCmdLine, "/UnregServer"))
  205.         {
  206.         UnregisterServer();
  207.         return FALSE;
  208.         }
  209.  
  210.     //Fail if we're run outside of CoGetClassObject
  211.     if (lstrcmpiA(m_pszCmdLine, "-Embedding")
  212.         && lstrcmpiA(m_pszCmdLine, "/Embedding"))
  213.         return FALSE;
  214.  
  215.    #ifndef WIN32
  216.     dwVer=CoBuildVersion();
  217.  
  218.     if (rmm!=HIWORD(dwVer))
  219.         return FALSE;
  220.  
  221.     //No need to check minor versions.
  222.    #endif
  223.  
  224.     //Call CoInitialize so we can call other Co* functions
  225.     if (FAILED(CoInitialize(NULL)))
  226.         return FALSE;
  227.  
  228.     m_fInitialized=TRUE;
  229.  
  230.     if (!m_hInstPrev)
  231.         {
  232.         wc.style          = CS_HREDRAW | CS_VREDRAW;
  233.         wc.lpfnWndProc    = KoalaWndProc;
  234.         wc.cbClsExtra     = 0;
  235.         wc.cbWndExtra     = CBWNDEXTRA;
  236.         wc.hInstance      = m_hInst;
  237.         wc.hIcon          = NULL;
  238.         wc.hCursor        = NULL;
  239.         wc.hbrBackground  = (HBRUSH)(COLOR_WINDOW + 1);
  240.         wc.lpszMenuName   = NULL;
  241.         wc.lpszClassName  = TEXT("Koala");
  242.  
  243.         if (!RegisterClass(&wc))
  244.             return FALSE;
  245.         }
  246.  
  247.     m_hWnd=CreateWindow(TEXT("Koala"), TEXT("Koala")
  248.         , WS_OVERLAPPEDWINDOW, 35, 35, 350, 250
  249.         , NULL, NULL, m_hInst, this);
  250.  
  251.     if (NULL==m_hWnd)
  252.         return FALSE;
  253.  
  254.     g_hWnd=m_hWnd;
  255.  
  256.     /*
  257.      * Create our class factory and register it for this application
  258.      * using CoRegisterClassObject. We are able to service more than
  259.      * one object at a time so we use REGCLS_MULTIPLEUSE.
  260.      */
  261.     m_pIClassFactory=new CKoalaClassFactory();
  262.  
  263.     if (NULL==m_pIClassFactory)
  264.         return FALSE;
  265.  
  266.     //Since we hold on to this, we should AddRef it.
  267.     m_pIClassFactory->AddRef();
  268.  
  269.     hr=CoRegisterClassObject(CLSID_Koala, m_pIClassFactory
  270.         , CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &m_dwRegCO);
  271.  
  272.     if (FAILED(hr))
  273.         return FALSE;
  274.  
  275.     return TRUE;
  276.     }
  277.  
  278.  
  279.  
  280.  
  281.  
  282. /*
  283.  * CApp::RegisterServer
  284.  *
  285.  * Purpose:
  286.  *  Creates registry enties for this server.
  287.  */
  288.  
  289. void CApp::RegisterServer(void)
  290.     {
  291.     TCHAR       szID[128];
  292.     TCHAR       szCLSID[128];
  293.     TCHAR       szModule[512];
  294.  
  295.     //Create some bas key strings.
  296.     StringFromGUID2(CLSID_Koala, szID, 128);
  297.     lstrcpy(szCLSID, TEXT("CLSID\\"));
  298.     lstrcat(szCLSID, szID);
  299.  
  300.     //Create ProgID keys
  301.     SetKeyAndValue(TEXT("Koala1.0"), NULL
  302.         , TEXT("Koala Object Chapter 5"));
  303.     SetKeyAndValue(TEXT("Koala1.0"), TEXT("CLSID"), szID);
  304.  
  305.     //Create VersionIndependentProgID keys
  306.     SetKeyAndValue(TEXT("Koala"), NULL
  307.         , TEXT("Koala Object Chapter 5"));
  308.     SetKeyAndValue(TEXT("Koala"), TEXT("CurVer")
  309.         , TEXT("Koala1.0"));
  310.     SetKeyAndValue(TEXT("Koala"), TEXT("CLSID"), szID);
  311.  
  312.     //Create entries under CLSID
  313.     SetKeyAndValue(szCLSID, NULL, TEXT("Koala Object Chapter 5"));
  314.     SetKeyAndValue(szCLSID, TEXT("ProgID"), TEXT("Koala1.0"));
  315.     SetKeyAndValue(szCLSID, TEXT("VersionIndependentProgID")
  316.         , TEXT("Koala"));
  317.     SetKeyAndValue(szCLSID, TEXT("NotInsertable"), NULL);
  318.  
  319.     GetModuleFileName(m_hInst, szModule
  320.         , sizeof(szModule)/sizeof(TCHAR));
  321.  
  322.    #ifdef WIN32
  323.     SetKeyAndValue(szCLSID, TEXT("LocalServer32"), szModule);
  324.    #else
  325.     SetKeyAndValue(szCLSID, TEXT("LocalServer"), szModule);
  326.    #endif
  327.  
  328.     return;
  329.     }
  330.  
  331.  
  332.  
  333. /*
  334.  * CApp::RegisterServer
  335.  *
  336.  * Purpose:
  337.  *  Removes registry entries for this server
  338.  */
  339.  
  340.  
  341. void CApp::UnregisterServer(void)
  342.     {
  343.     TCHAR       szID[128];
  344.     TCHAR       szCLSID[128];
  345.     TCHAR       szTemp[256];
  346.  
  347.     //Create some base key strings.
  348.     StringFromGUID2(CLSID_Koala, szID, 128);
  349.     lstrcpy(szCLSID, TEXT("CLSID\\"));
  350.     lstrcat(szCLSID, szID);
  351.  
  352.     RegDeleteKey(HKEY_CLASSES_ROOT, TEXT("Koala\\CurVer"));
  353.     RegDeleteKey(HKEY_CLASSES_ROOT, TEXT("Koala\\CLSID"));
  354.     RegDeleteKey(HKEY_CLASSES_ROOT, TEXT("Koala"));
  355.  
  356.     RegDeleteKey(HKEY_CLASSES_ROOT, TEXT("Koala1.0\\CLSID"));
  357.     RegDeleteKey(HKEY_CLASSES_ROOT, TEXT("Koala1.0"));
  358.  
  359.     wsprintf(szTemp, TEXT("%s\\%s"), szCLSID, TEXT("ProgID"));
  360.     RegDeleteKey(HKEY_CLASSES_ROOT, szTemp);
  361.  
  362.     wsprintf(szTemp, TEXT("%s\\%s"), szCLSID, TEXT("VersionIndependentProgID"));
  363.     RegDeleteKey(HKEY_CLASSES_ROOT, szTemp);
  364.  
  365.     wsprintf(szTemp, TEXT("%s\\%s"), szCLSID, TEXT("NotInsertable"));
  366.     RegDeleteKey(HKEY_CLASSES_ROOT, szTemp);
  367.  
  368.    #ifdef WIN32
  369.     wsprintf(szTemp, TEXT("%s\\%s"), szCLSID, TEXT("LocalServer32"));
  370.    #else
  371.     wsprintf(szTemp, "%s\\%s", szCLSID, "LocalServer");
  372.    #endif
  373.     RegDeleteKey(HKEY_CLASSES_ROOT, szTemp);
  374.  
  375.     RegDeleteKey(HKEY_CLASSES_ROOT, szCLSID);
  376.     return;
  377.     }
  378.  
  379.  
  380.  
  381. /*
  382.  * CApp::SetKeyAndValue
  383.  *
  384.  * Purpose:
  385.  *  Private helper function for RegisterServer that creates
  386.  *  a key, sets a value, and closes that key.
  387.  *
  388.  * Parameters:
  389.  *  pszKey          LPTSTR to the ame of the key
  390.  *  pszSubkey       LPTSTR ro the name of a subkey
  391.  *  pszValue        LPTSTR to the value to store
  392.  *
  393.  * Return Value:
  394.  *  BOOL            TRUE if successful, FALSE otherwise.
  395.  */
  396.  
  397. BOOL CApp::SetKeyAndValue(LPTSTR pszKey, LPTSTR pszSubkey
  398.     , LPTSTR pszValue)
  399.     {
  400.     HKEY        hKey;
  401.     TCHAR       szKey[256];
  402.  
  403.     lstrcpy(szKey, pszKey);
  404.  
  405.     if (NULL!=pszSubkey)
  406.         {
  407.         lstrcat(szKey, TEXT("\\"));
  408.         lstrcat(szKey, pszSubkey);
  409.         }
  410.  
  411.     if (ERROR_SUCCESS!=RegCreateKeyEx(HKEY_CLASSES_ROOT
  412.         , szKey, 0, NULL, REG_OPTION_NON_VOLATILE
  413.         , KEY_ALL_ACCESS, NULL, &hKey, NULL))
  414.         return FALSE;
  415.  
  416.     if (NULL!=pszValue)
  417.         {
  418.         RegSetValueEx(hKey, NULL, 0, REG_SZ, (BYTE *)pszValue
  419.             , (lstrlen(pszValue)+1)*sizeof(TCHAR));
  420.         }
  421.  
  422.     RegCloseKey(hKey);
  423.     return TRUE;
  424.     }
  425.  
  426.  
  427.  
  428.  
  429.  
  430.  
  431.  
  432. /*
  433.  * CKoalaClassFactory::CKoalaClassFactory
  434.  * CKoalaClassFactory::~CKoalaClassFactory
  435.  *
  436.  * Constructor Parameters:
  437.  *  None
  438.  */
  439.  
  440. CKoalaClassFactory::CKoalaClassFactory(void)
  441.     {
  442.     m_cRef=0L;
  443.     return;
  444.     }
  445.  
  446. CKoalaClassFactory::~CKoalaClassFactory(void)
  447.     {
  448.     return;
  449.     }
  450.  
  451.  
  452.  
  453.  
  454. /*
  455.  * CKoalaClassFactory::QueryInterface
  456.  * CKoalaClassFactory::AddRef
  457.  * CKoalaClassFactory::Release
  458.  */
  459.  
  460. STDMETHODIMP CKoalaClassFactory::QueryInterface(REFIID riid
  461.     , PPVOID ppv)
  462.     {
  463.     *ppv=NULL;
  464.  
  465.     if (IID_IUnknown==riid || IID_IClassFactory==riid)
  466.         *ppv=this;
  467.  
  468.     if (NULL!=*ppv)
  469.         {
  470.         ((LPUNKNOWN)*ppv)->AddRef();
  471.         return NOERROR;
  472.         }
  473.  
  474.     return ResultFromScode(E_NOINTERFACE);
  475.     }
  476.  
  477.  
  478. STDMETHODIMP_(ULONG) CKoalaClassFactory::AddRef(void)
  479.     {
  480.     return ++m_cRef;
  481.     }
  482.  
  483.  
  484. STDMETHODIMP_(ULONG) CKoalaClassFactory::Release(void)
  485.     {
  486.     if (0L!=--m_cRef)
  487.         return m_cRef;
  488.  
  489.     delete this;
  490.     return 0;
  491.     }
  492.  
  493.  
  494.  
  495.  
  496.  
  497.  
  498. /*
  499.  * CKoalaClassFactory::CreateInstance
  500.  *
  501.  * Purpose:
  502.  *  Instantiates a Koala object returning an interface pointer.
  503.  *
  504.  * Parameters:
  505.  *  pUnkOuter       LPUNKNOWN to the controlling IUnknown if we are
  506.  *                  being used in an aggregation.
  507.  *  riid            REFIID identifying the interface the caller
  508.  *                  desires to have for the new object.
  509.  *  ppvObj          PPVOID in which to store the desired
  510.  *                  interface pointer for the new object.
  511.  *
  512.  * Return Value:
  513.  *  HRESULT         NOERROR if successful, otherwise E_NOINTERFACE
  514.  *                  if we cannot support the requested interface.
  515.  */
  516.  
  517. STDMETHODIMP CKoalaClassFactory::CreateInstance(LPUNKNOWN pUnkOuter
  518.     , REFIID riid, PPVOID ppvObj)
  519.     {
  520.     PCKoala             pObj;
  521.     HRESULT             hr;
  522.  
  523.     *ppvObj=NULL;
  524.     hr=ResultFromScode(E_OUTOFMEMORY);
  525.  
  526.     //Verify that a controlling unknown asks for IUnknown
  527.     if (NULL!=pUnkOuter && IID_IUnknown!=riid)
  528.         return ResultFromScode(CLASS_E_NOAGGREGATION);
  529.  
  530.     //Create the object telling us to notify us when it's gone.
  531.     pObj=new CKoala(pUnkOuter, ObjectDestroyed);
  532.  
  533.     if (NULL==pObj)
  534.         {
  535.         //This starts shutdown if there are no other objects.
  536.         g_cObj++;
  537.         ObjectDestroyed();
  538.         return hr;
  539.         }
  540.  
  541.     if (pObj->Init())
  542.         hr=pObj->QueryInterface(riid, ppvObj);
  543.  
  544.     g_cObj++;
  545.  
  546.     /*
  547.      * Kill the object if initial creation or Init failed. If
  548.      * the object failed, we handle the g_cObj increment above
  549.      * in ObjectDestroyed.
  550.      */
  551.     if (FAILED(hr))
  552.         {
  553.         delete pObj;
  554.         ObjectDestroyed();  //Handle shutdown cases.
  555.         }
  556.  
  557.     return hr;
  558.     }
  559.  
  560.  
  561.  
  562.  
  563.  
  564.  
  565. /*
  566.  * CKoalaClassFactory::LockServer
  567.  *
  568.  * Purpose:
  569.  *  Increments or decrements the lock count of the serving
  570.  *  IClassFactory object.  When the number of locks goes to
  571.  *  zero and the number of objects is zero, we shut down the
  572.  *  application.
  573.  *
  574.  * Parameters:
  575.  *  fLock           BOOL specifying whether to increment or
  576.  *                  decrement the lock count.
  577.  *
  578.  * Return Value:
  579.  *  HRESULT         NOERROR always.
  580.  */
  581.  
  582. STDMETHODIMP CKoalaClassFactory::LockServer(BOOL fLock)
  583.     {
  584.     if (fLock)
  585.         g_cLock++;
  586.     else
  587.         {
  588.         g_cLock--;
  589.  
  590.         /*
  591.          * Fake an object destruction:  this centralizes
  592.          * all the shutdown code in the ObjectDestroyed
  593.          * function, eliminating duplicate code here.
  594.          */
  595.         g_cObj++;
  596.         ObjectDestroyed();
  597.         }
  598.  
  599.     return NOERROR;
  600.     }
  601.