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 / chap04 / connect / connect.cpp next >
C/C++ Source or Header  |  1996-05-20  |  11KB  |  476 lines

  1. /*
  2.  * CONNECT.CPP
  3.  * Demonstration of connectable objects and connection points,
  4.  * Chapter 4
  5.  *
  6.  * Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  7.  *
  8.  * Kraig Brockschmidt, Microsoft
  9.  * Internet  :  kraigb@microsoft.com
  10.  * Compuserve:  >INTERNET:kraigb@microsoft.com
  11.  */
  12.  
  13.  
  14. #define INITGUIDS
  15. #include "connect.h"
  16.  
  17.  
  18. /*
  19.  * WinMain
  20.  *
  21.  * Purpose:
  22.  *  Main entry point of application.
  23.  */
  24.  
  25. int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hInstPrev
  26.     , LPSTR pszCmdLine, int nCmdShow)
  27.     {
  28.     MSG     msg;
  29.     PAPP    pApp;
  30.  
  31.     pApp=new CApp(hInst, hInstPrev, nCmdShow);
  32.  
  33.     if (NULL==pApp)
  34.         return -1;
  35.  
  36.     if (pApp->Init())
  37.         {
  38.         while (GetMessage(&msg, NULL, 0,0 ))
  39.             {
  40.             TranslateMessage(&msg);
  41.             DispatchMessage(&msg);
  42.             }
  43.         }
  44.  
  45.     delete pApp;
  46.     return msg.wParam;
  47.     }
  48.  
  49.  
  50.  
  51.  
  52.  
  53.  
  54.  
  55. /*
  56.  * ConnectWndProc
  57.  *
  58.  * Purpose:
  59.  *  Standard window class procedure.
  60.  */
  61.  
  62. LRESULT APIENTRY ConnectWndProc(HWND hWnd, UINT iMsg, WPARAM wParam
  63.     , LPARAM lParam)
  64.     {
  65.     PAPP            pApp;
  66.     BOOL            fRes;
  67.     PCConnObject    pObj;
  68.  
  69.     COMMANDPARAMS(wID, wCode, hWndMsg);
  70.  
  71.     pApp=(PAPP)GetWindowLong(hWnd, CONNECTWL_STRUCTURE);
  72.  
  73.     switch (iMsg)
  74.         {
  75.         case WM_NCCREATE:
  76.             pApp=(PAPP)(((LPCREATESTRUCT)lParam)->lpCreateParams);
  77.             SetWindowLong(hWnd, CONNECTWL_STRUCTURE, (LONG)pApp);
  78.             return (DefWindowProc(hWnd, iMsg, wParam, lParam));
  79.  
  80.  
  81.         case WM_DESTROY:
  82.             PostQuitMessage(0);
  83.             break;
  84.  
  85.  
  86.         case WM_COMMAND:
  87.             switch (wID)
  88.                 {
  89.                 case IDM_OBJECTCREATE:
  90.                     if (NULL!=pApp->m_pObj)
  91.                         {
  92.                         //Make sure the sinks disconnect
  93.                         pApp->Disconnect(SINK1);
  94.                         pApp->Disconnect(SINK2);
  95.                         pApp->m_pObj->Release();
  96.                         }
  97.  
  98.                     fRes=FALSE;
  99.  
  100.                     /*
  101.                      * OLE clients never have direct access to
  102.                      * an object's C++ class like this, so the
  103.                      * sequence from here through the AddRef will
  104.                      * always be encapsulated within the object's
  105.                      * own creation functions.  This sample is a
  106.                      * little contrived.
  107.                      */
  108.                     pObj=new CConnObject();
  109.  
  110.                     if (NULL!=pObj)
  111.                         {
  112.                         fRes=pObj->Init();
  113.                         pObj->AddRef();
  114.                         }
  115.  
  116.                     pApp->m_pObj=pObj;
  117.                     pApp->Message(fRes ? TEXT("Object created")
  118.                         : TEXT("Object creation failed"));
  119.  
  120.                     break;
  121.  
  122.  
  123.                 case IDM_OBJECTRELEASE:
  124.                     if (NULL==pApp->m_pObj)
  125.                         {
  126.                         pApp->Message(TEXT("There is no object"));
  127.                         break;
  128.                         }
  129.  
  130.                     //Make sure the sinks disconnect
  131.                     pApp->Disconnect(SINK1);
  132.                     pApp->Disconnect(SINK2);
  133.  
  134.                     if (0==pApp->m_pObj->Release())
  135.                         {
  136.                         pApp->m_pObj=NULL;
  137.                         pApp->Message(TEXT("Object released"));
  138.                         }
  139.  
  140.                     break;
  141.  
  142.  
  143.                 case IDM_OBJECTSINK1CONNECT:
  144.                     pApp->Connect(SINK1);
  145.                     break;
  146.  
  147.                 case IDM_OBJECTSINK1DISCONNECT:
  148.                     pApp->Disconnect(SINK1);
  149.                     break;
  150.  
  151.                 case IDM_OBJECTSINK2CONNECT:
  152.                     pApp->Connect(SINK2);
  153.                     break;
  154.  
  155.                 case IDM_OBJECTSINK2DISCONNECT:
  156.                     pApp->Disconnect(SINK2);
  157.                     break;
  158.  
  159.                 case IDM_OBJECTEXIT:
  160.                     PostMessage(hWnd, WM_CLOSE, 0, 0L);
  161.                     break;
  162.  
  163.  
  164.                 case IDM_TRIGGERQUACK:
  165.                 case IDM_TRIGGERFLAP:
  166.                 case IDM_TRIGGERPADDLE:
  167.                     if (NULL==pApp->m_pObj)
  168.                         {
  169.                         pApp->Message(TEXT("There is no object"));
  170.                         break;
  171.                         }
  172.  
  173.                     //The math gets the right ID for the event
  174.                     if (!pApp->m_pObj->TriggerEvent
  175.                         (wID-IDM_TRIGGERQUACK+EVENT_QUACK))
  176.                         {
  177.                         pApp->Message
  178.                             (TEXT("There are no connected sinks"));
  179.                         }
  180.  
  181.                     break;
  182.  
  183.                 }
  184.             break;
  185.  
  186.         default:
  187.             return (DefWindowProc(hWnd, iMsg, wParam, lParam));
  188.         }
  189.  
  190.     return 0L;
  191.     }
  192.  
  193.  
  194.  
  195.  
  196. /*
  197.  * CApp::CApp
  198.  * CApp::~CApp
  199.  *
  200.  * Constructor Parameters:
  201.  *  hInst           HINSTANCE of the Application from WinMain
  202.  *  hInstPrev       HINSTANCE of a previous instance from WinMain
  203.  *  nCmdShow        UINT specifying how to show the app window,
  204.  *                  from WinMain.
  205.  */
  206.  
  207. CApp::CApp(HINSTANCE hInst, HINSTANCE hInstPrev
  208.     , UINT nCmdShow)
  209.     {
  210.     //Initialize WinMain parameter holders.
  211.     m_hInst     =hInst;
  212.     m_hInstPrev =hInstPrev;
  213.     m_nCmdShow  =nCmdShow;
  214.  
  215.     m_hWnd=NULL;
  216.     m_pObj=NULL;
  217.  
  218.     m_rgpSink[0]=NULL;
  219.     m_rgpSink[1]=NULL;
  220.  
  221.     return;
  222.     }
  223.  
  224.  
  225. CApp::~CApp(void)
  226.     {
  227.     //Release the object if we still have it.
  228.     ReleaseInterface(m_pObj);
  229.     Disconnect(SINK1);
  230.     Disconnect(SINK2);
  231.  
  232.     ReleaseInterface(m_rgpSink[SINK1]);
  233.     ReleaseInterface(m_rgpSink[SINK2]);
  234.     return;
  235.     }
  236.  
  237.  
  238.  
  239.  
  240. /*
  241.  * CApp::Connect
  242.  * CApp::Disconnect
  243.  *
  244.  * Purpose:
  245.  *  Connects or disconnects a sink object to or from the
  246.  *  connectable object we have.
  247.  *
  248.  * Parameters:
  249.  *  uID             UINT identifying which sink to use.
  250.  */
  251.  
  252. void CApp::Connect(UINT uID)
  253.     {
  254.     HRESULT             hr;
  255.     IConnectionPoint   *pCP;
  256.  
  257.     if (NULL==m_pObj)
  258.         {
  259.         Message(TEXT("There is no object"));
  260.         return;
  261.         }
  262.  
  263.     if (SINK2 < uID)
  264.         return;
  265.  
  266.     //Is this sink connected already?
  267.     if (0!=m_rgpSink[uID]->m_dwCookie)
  268.         {
  269.         Message(TEXT("This sink is already connected"));
  270.         return;
  271.         }
  272.  
  273.     pCP=GetConnectionPoint();
  274.  
  275.     if (NULL!=pCP)
  276.         {
  277.         hr=pCP->Advise(m_rgpSink[uID]
  278.             , &m_rgpSink[uID]->m_dwCookie);
  279.  
  280.         if (FAILED(hr))
  281.             Message(TEXT("Connection failed"));
  282.         else
  283.             Message(TEXT("Connection complete"));
  284.  
  285.         pCP->Release();
  286.         }
  287.     else
  288.         Message(TEXT("Failed to get IConnectionPoint"));
  289.  
  290.     return;
  291.     }
  292.  
  293.  
  294. void CApp::Disconnect(UINT uID)
  295.     {
  296.     HRESULT             hr;
  297.     IConnectionPoint   *pCP;
  298.  
  299.     if (NULL==m_pObj)
  300.         {
  301.         Message(TEXT("There is no object"));
  302.         return;
  303.         }
  304.  
  305.     //Is the sink connected at all?
  306.     if (0==m_rgpSink[uID]->m_dwCookie)
  307.         {
  308.         Message(TEXT("This sink is not connected"));
  309.         return;
  310.         }
  311.  
  312.     pCP=GetConnectionPoint();
  313.  
  314.     if (NULL!=pCP)
  315.         {
  316.         hr=pCP->Unadvise(m_rgpSink[uID]->m_dwCookie);
  317.  
  318.         if (FAILED(hr))
  319.             Message(TEXT("Disconnection failed"));
  320.         else
  321.             {
  322.             Message(TEXT("Disconnection complete"));
  323.             m_rgpSink[uID]->m_dwCookie=0;
  324.             }
  325.  
  326.         pCP->Release();
  327.         }
  328.     else
  329.         Message(TEXT("Failed to get IConnectionPoint"));
  330.  
  331.     return;
  332.     }
  333.  
  334.  
  335.  
  336.  
  337. /*
  338.  * CApp::GetConnectionPoint
  339.  *
  340.  * Purpose:
  341.  *  Asks the connectable object for an IConnectionPoint for
  342.  *  IDuckEvents.
  343.  *
  344.  * Parameters:
  345.  *  None
  346.  *
  347.  * Return Value:
  348.  *  IConnectionPoint * to the interface
  349.  */
  350.  
  351. IConnectionPoint * CApp::GetConnectionPoint(void)
  352.     {
  353.     HRESULT                     hr;
  354.     IConnectionPointContainer  *pCPCont;
  355.     IConnectionPoint           *pCP=NULL;
  356.  
  357.     hr=m_pObj->QueryInterface(IID_IConnectionPointContainer
  358.         , (PPVOID)&pCPCont);
  359.  
  360.     if (FAILED(hr))
  361.         return NULL;
  362.  
  363.     hr=pCPCont->FindConnectionPoint(IID_IDuckEvents, &pCP);
  364.     pCPCont->Release();
  365.  
  366.     //This check isn't necessary...just adds clarity
  367.     if (FAILED(hr))
  368.         return NULL;
  369.  
  370.     return pCP;
  371.     }
  372.  
  373.  
  374.  
  375.  
  376. /*
  377.  * CApp::Init
  378.  *
  379.  * Purpose:
  380.  *  Initializes an CApp object by registering window classes,
  381.  *  creating the main window, and doing anything else prone to
  382.  *  failure.  If this function fails the caller should guarantee
  383.  *  that the destructor is called.
  384.  *
  385.  * Parameters:
  386.  *  None
  387.  *
  388.  * Return Value:
  389.  *  BOOL            TRUE if successful, FALSE otherwise.
  390.  */
  391.  
  392. BOOL CApp::Init(void)
  393.     {
  394.     WNDCLASS    wc;
  395.  
  396.     //Create the two sink objects we might use
  397.     m_rgpSink[SINK1]=new CDuckEvents(this, SINK1);
  398.     m_rgpSink[SINK2]=new CDuckEvents(this, SINK2);
  399.  
  400.     if (NULL==m_rgpSink[SINK1] || NULL==m_rgpSink[SINK2])
  401.         return FALSE;
  402.  
  403.     //Lock the lifetimes of these two objects
  404.     m_rgpSink[SINK1]->AddRef();
  405.     m_rgpSink[SINK2]->AddRef();
  406.  
  407.     //Create windows and such
  408.     if (!m_hInstPrev)
  409.         {
  410.         wc.style          = CS_HREDRAW | CS_VREDRAW;
  411.         wc.lpfnWndProc    = ConnectWndProc;
  412.         wc.cbClsExtra     = 0;
  413.         wc.cbWndExtra     = CBWNDEXTRA;
  414.         wc.hInstance      = m_hInst;
  415.         wc.hIcon          = LoadIcon(m_hInst, TEXT("Icon"));
  416.         wc.hCursor        = LoadCursor(NULL, IDC_ARROW);
  417.         wc.hbrBackground  = (HBRUSH)(COLOR_WINDOW + 1);
  418.         wc.lpszMenuName   = MAKEINTRESOURCE(IDR_MENU);
  419.         wc.lpszClassName  = TEXT("CONNECT");
  420.  
  421.         if (!RegisterClass(&wc))
  422.             return FALSE;
  423.         }
  424.  
  425.     m_hWnd=CreateWindow(TEXT("CONNECT"), TEXT("Connectable Object Demo")
  426.         , WS_MINIMIZEBOX | WS_OVERLAPPEDWINDOW
  427.         ,35, 35, 350, 250, NULL, NULL, m_hInst, this);
  428.  
  429.     if (NULL==m_hWnd)
  430.         return FALSE;
  431.  
  432.     ShowWindow(m_hWnd, m_nCmdShow);
  433.     UpdateWindow(m_hWnd);
  434.  
  435.     return TRUE;
  436.     }
  437.  
  438.  
  439.  
  440.  
  441. /*
  442.  * CApp::Message
  443.  *
  444.  * Purpose:
  445.  *  Displays a message in the client area of the window.  This is
  446.  *  just to centralize the call to simpify other code.
  447.  *
  448.  * Parameters:
  449.  *  psz             LPTSTR to the string to display.
  450.  *
  451.  * Return Value:
  452.  *  None
  453.  */
  454.  
  455. void inline CApp::Message(LPTSTR psz)
  456.     {
  457.     HDC     hDC;
  458.     RECT    rc;
  459.  
  460.     hDC=GetDC(m_hWnd);
  461.     GetClientRect(m_hWnd, &rc);
  462.  
  463.     SetBkColor(hDC, GetSysColor(COLOR_WINDOW));
  464.     SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT));
  465.  
  466.     /*
  467.      * We'll just be sloppy and clear the whole window as
  468.      * well as write the string with one ExtTextOut call.
  469.      * No word wrapping here...
  470.      */
  471.  
  472.     ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &rc, psz, lstrlen(psz), NULL);
  473.     ReleaseDC(m_hWnd, hDC);
  474.     return;
  475.     }
  476.