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 / ekoala5 / koala.cpp < prev    next >
C/C++ Source or Header  |  1996-05-23  |  10KB  |  429 lines

  1. /*
  2.  * KOALA.CPP
  3.  * Koala Object with Custom Marshaling, Chapter 6
  4.  *
  5.  * Implementation of the CKoala object with a custom interface
  6.  * to demonstrate local/remote transparency.
  7.  *
  8.  * Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  9.  *
  10.  * Kraig Brockschmidt, Microsoft
  11.  * Internet  :  kraigb@microsoft.com
  12.  * Compuserve:  >INTERNET:kraigb@microsoft.com
  13.  */
  14.  
  15.  
  16. #include "koala.h"
  17.  
  18.  
  19. /*
  20.  * ObjectWndProc
  21.  *
  22.  * Purpose:
  23.  *  Standard window class procedure for each object.
  24.  */
  25.  
  26. LRESULT APIENTRY ObjectWndProc(HWND hWnd, UINT iMsg
  27.     , WPARAM wParam, LPARAM lParam)
  28.     {
  29.     PCKoala     pKoala;
  30.  
  31.     pKoala=(PCKoala)GetWindowLong(hWnd, OBJECTWL_STRUCTURE);
  32.  
  33.     switch (iMsg)
  34.         {
  35.         case WM_NCCREATE:
  36.             pKoala=(PCKoala)(((LPCREATESTRUCT)lParam)->lpCreateParams);
  37.             SetWindowLong(hWnd, OBJECTWL_STRUCTURE, (LONG)pKoala);
  38.             return (DefWindowProc(hWnd, iMsg, wParam, lParam));
  39.  
  40.         case WM_COMMAND:
  41.             //Dispatch the call to the right object
  42.             return pKoala->HandleCall(LOWORD(wParam), lParam);
  43.  
  44.         default:
  45.             return (DefWindowProc(hWnd, iMsg, wParam, lParam));
  46.         }
  47.  
  48.     return 0L;
  49.     }
  50.  
  51.  
  52.  
  53.  
  54.  
  55. /*
  56.  * CKoala::CKoala
  57.  * CKoala::~CKoala
  58.  *
  59.  * Parameters (Constructor):
  60.  *  pfnDestroy      PFNDESTROYED to call when an object
  61.  *                  is destroyed.
  62.  */
  63.  
  64. CKoala::CKoala(PFNDESTROYED pfnDestroy)
  65.     {
  66.     m_cRef=0;
  67.     m_pfnDestroy=pfnDestroy;
  68.  
  69.     m_fJustAte=FALSE;
  70.     m_cSleepAfterEat=0;
  71.     return;
  72.     }
  73.  
  74.  
  75. CKoala::~CKoala(void)
  76.     {
  77.     if (NULL!=m_hWnd)
  78.         DestroyWindow(m_hWnd);
  79.  
  80.     return;
  81.     }
  82.  
  83.  
  84.  
  85. /*
  86.  * CKoala::Init
  87.  *
  88.  * Purpose:
  89.  *  Performs any intiailization of a CKoala that's prone to failure
  90.  *  that we also use internally before exposing the object outside.
  91.  *
  92.  * Parameters:
  93.  *  hInst           HINSTANCE of the application.
  94.  *  hWndParent      HWND in which to create our window
  95.  *
  96.  * Return Value:
  97.  *  BOOL            TRUE if the function is successful,
  98.  *                  FALSE otherwise.
  99.  */
  100.  
  101. BOOL CKoala::Init(HINSTANCE hInst, HWND hWndParent)
  102.     {
  103.     //Create our window that receives marshaling calls
  104.     m_hWnd=CreateWindow(TEXT("KoalaObject"), TEXT("KoalaObject")
  105.         , WS_CHILD, 35, 35, 35, 25, hWndParent, NULL
  106.         , hInst, this);
  107.  
  108.     if (NULL==m_hWnd)
  109.         return FALSE;
  110.  
  111.     return TRUE;
  112.     }
  113.  
  114.  
  115.  
  116.  
  117.  
  118. /*
  119.  * CKoala::HandleCall
  120.  *
  121.  * Purpose:
  122.  *  Handles messages sent via custom marshaling from the client
  123.  *  side proxy.
  124.  *
  125.  * Parameters:
  126.  *  iMsg            UINT identifying the call made.
  127.  *  lParam          LPARAM with extra information.
  128.  *
  129.  * Return Value:
  130.  *  DWORD           Value to return to the proxy which it uses
  131.  *                  in whatever way it must to return a value to
  132.  *                  the client.
  133.  */
  134.  
  135. DWORD CKoala::HandleCall(UINT iMsg, LPARAM lParam)
  136.     {
  137.     DWORD       dw;
  138.     short       iRet=0;
  139.  
  140.     /*
  141.      * You'll notice that all the important server-side
  142.      * implementation of the object exists here instead of
  143.      * separate interface implementations.  Everything
  144.      * else is contained in the client-side proxy, who knows
  145.      * when there's no point at all in calling a function
  146.      * on the server side (such as with some of the IKoala
  147.      * functions that don't do anything.
  148.      */
  149.  
  150.     switch (iMsg)
  151.         {
  152.         case MSG_RELEASE:          //Last IUnknown::Release
  153.             /*
  154.              * There is only one reference count from
  155.              * IClassFactory::CreateInstance, which the proxy
  156.              * will own.  The proxy sends this message when
  157.              * it detects the last Release from the client.
  158.              * Otherwise it doesn't forward AddRef/Release calls.
  159.              */
  160.             Release();
  161.             break;
  162.  
  163.         case MSG_EAT:
  164.             m_fJustAte=TRUE;
  165.             break;
  166.  
  167.         case MSG_SLEEP:            //IAnimal::Sleep
  168.             //Client's in-parameter in LOWORD(lParam)
  169.             iRet=LOWORD(lParam)+m_cSleepAfterEat;
  170.             m_fJustAte=FALSE;     //Probably want to eat again
  171.             break;
  172.  
  173.         case MSG_PROCREATE:        //IAnimal::Procreate
  174.             dw=GetTickCount()/100;
  175.  
  176.             iRet=((dw/10)*10==dw) ? 1 : 0;
  177.             break;
  178.  
  179.         case MSG_SLEEPAFTEREATING: //IKoala::SleepAfterEating
  180.             m_cSleepAfterEat=LOWORD(lParam);
  181.             break;
  182.  
  183.         default:
  184.             break;
  185.         }
  186.  
  187.     return iRet;
  188.     }
  189.  
  190.  
  191.  
  192.  
  193.  
  194. /*
  195.  * CKoala::QueryInterface
  196.  * CKoala::AddRef
  197.  * CKoala::Release
  198.  *
  199.  * Purpose:
  200.  *  IUnknown members for CKoala object.
  201.  */
  202.  
  203. STDMETHODIMP CKoala::QueryInterface(REFIID riid, PPVOID ppv)
  204.     {
  205.     *ppv=NULL;
  206.  
  207.     if (IID_IUnknown==riid || IID_IMarshal==riid
  208.         || IID_IAnimal==riid || IID_IKoala==riid)
  209.         *ppv=this;
  210.  
  211.     if (NULL!=*ppv)
  212.         {
  213.         ((LPUNKNOWN)*ppv)->AddRef();
  214.         return NOERROR;
  215.         }
  216.  
  217.     return ResultFromScode(E_NOINTERFACE);
  218.     }
  219.  
  220.  
  221. STDMETHODIMP_(ULONG) CKoala::AddRef(void)
  222.     {
  223.     return ++m_cRef;
  224.     }
  225.  
  226.  
  227. STDMETHODIMP_(ULONG) CKoala::Release(void)
  228.     {
  229.     if (0L!=--m_cRef)
  230.         return m_cRef;
  231.  
  232.     if (NULL!=m_pfnDestroy)
  233.         (*m_pfnDestroy)();
  234.  
  235.     delete this;
  236.     return 0;
  237.     }
  238.  
  239.  
  240.  
  241.  
  242.  
  243. /*
  244.  * CKoala::GetUnmarshalClass
  245.  *
  246.  * Purpose:
  247.  *  Determines the class of object to be used to create an
  248.  *  uninitalized proxy in the unmarshaling process.
  249.  *
  250.  * Parameters:
  251.  *  riid            REFIID of the interface to be marshaled.
  252.  *  pv              LPVOID to the interface to be marshaled.
  253.  *  dwCtx           DWORD specifying the relation of the processes
  254.  *                  between which the marshaling is occuring, from the
  255.  *                  MSHCTX enumeration.
  256.  *  pvCtx           LPVOID Reserved for future MSHCTX values.
  257.  *  dwFlags         DWORD specifying why marshaling is taking place.
  258.  *  pClsID          LPCLSID in which to store the proxy CLSID.
  259.  */
  260.  
  261. STDMETHODIMP CKoala::GetUnmarshalClass(REFIID riid
  262.     , LPVOID pv, DWORD dwCtx, LPVOID pvCtx, DWORD dwFlags
  263.     , LPCLSID pClsID)
  264.     {
  265.    #ifdef WIN32
  266.     /*
  267.      * If the context is on a different machine we cannot use
  268.      * our custom marshaling based on SendMessage.
  269.      */
  270.     if (dwCtx & MSHCTX_DIFFERENTMACHINE)
  271.         return ResultFromScode(E_FAIL);
  272.    #endif
  273.  
  274.     //Same proxy for all interfaces.
  275.     *pClsID=CLSID_KoalaProxy;
  276.     return NOERROR;
  277.     }
  278.  
  279.  
  280.  
  281.  
  282. /*
  283.  * CKoala::GetMarshalSizeMax
  284.  *
  285.  * Purpose:
  286.  *  Returns the upper memory bound needed to write data into a stream
  287.  *  for IMarshal::MarshalInterface.
  288.  *
  289.  * Parameters:
  290.  *  riid            REFIID of the interface to be marshaled.
  291.  *  pv              LPVOID of the interface to be marshaled.
  292.  *  dwDestCtx       DWORD with the destination context from MSHCTX.
  293.  *  pvDestCtx       LPVOID reserved for future MSHCTX flags.
  294.  *  dwFlags         DWORD specifying why marshaling is taking place.
  295.  *  pdwSize         LPDWORD in which the size is returned.
  296.  */
  297.  
  298. STDMETHODIMP CKoala::GetMarshalSizeMax(REFIID riid, LPVOID pv
  299.     , DWORD dwDestCtx, LPVOID pvDestCtx, DWORD dwFlags
  300.     , LPDWORD pdwSize)
  301.     {
  302.    #ifdef WIN32
  303.     if (dwDestCtx & MSHCTX_DIFFERENTMACHINE)
  304.         return ResultFromScode(E_FAIL);
  305.    #endif
  306.  
  307.     *pdwSize=sizeof(KOALAMARSHAL);
  308.     return NOERROR;
  309.     }
  310.  
  311.  
  312.  
  313.  
  314.  
  315. /*
  316.  * CKoala::MarshalInterface
  317.  *
  318.  * Purpose:
  319.  *  Stores a marshaling packet in a stream for use by a client-side
  320.  *  proxy.
  321.  *
  322.  * Parameters:
  323.  *  pStm            LPSTREAM into which to marshal the interface.
  324.  *  riid            REFIID of the interface to be marshaled.
  325.  *  pv              LPVOID of the interface to be marshaled.
  326.  *  dwDestCtx       DWORD with the destination context from MSHCTX.
  327.  *  pvDestCtx       LPVOID reserved for future MSHCTX flags.
  328.  *  dwFlags         DWORD specifying why marshaling is taking place.
  329.  */
  330.  
  331. STDMETHODIMP CKoala::MarshalInterface(LPSTREAM pstm
  332.     , REFIID riid, LPVOID pv, DWORD dwDestCtx, LPVOID pvDestCtx
  333.     , DWORD dwFlags)
  334.     {
  335.     KOALAMARSHAL        km;
  336.  
  337.    #ifdef WIN32
  338.     if (dwDestCtx & MSHCTX_DIFFERENTMACHINE)
  339.         return ResultFromScode(E_FAIL);
  340.    #endif
  341.  
  342.     //Proxy only needs to know where to send messages
  343.     km.hWnd=m_hWnd;
  344.  
  345.     //This is for the client who will call Release when needed
  346.     AddRef();
  347.  
  348.     //Write the marshaling packet to the stream
  349.     return pstm->Write((void *)&km, sizeof(KOALAMARSHAL), NULL);
  350.     }
  351.  
  352.  
  353.  
  354.  
  355.  
  356. /*
  357.  * CKoala::UnmarshalInterface
  358.  *
  359.  * Purpose:
  360.  *  Initializes a newly created proxy the marshaling packet in
  361.  *  the stream created in the server-side implementation of
  362.  *  MarshalInterface.  This is the primary member of this interface
  363.  *  used on the client side proxy.
  364.  *
  365.  * Parameters:
  366.  *  pStm            LPSTREAM to the stream containing marshal
  367.  *                  data.
  368.  *  riid            REFIID of the interface to be marshaled.
  369.  *  pv              LPVOID of the interface to be marshaled.
  370.  */
  371.  
  372. STDMETHODIMP CKoala::UnmarshalInterface(LPSTREAM pstm
  373.     , REFIID riid, LPVOID *pv)
  374.     {
  375.     //No need to implement on server side
  376.     return ResultFromScode(E_NOTIMPL);
  377.     }
  378.  
  379.  
  380.  
  381.  
  382.  
  383.  
  384. /*
  385.  * CKoala::ReleaseMarshalData
  386.  *
  387.  * Purpose:
  388.  *  Destroy a marshaled data packet, client-side only.
  389.  *
  390.  * Parameters:
  391.  *  pStm            LPSTREAM containing the data to release.
  392.  */
  393.  
  394. STDMETHODIMP CKoala::ReleaseMarshalData(LPSTREAM pstm)
  395.     {
  396.     //Client-side function
  397.     return ResultFromScode(E_NOTIMPL);
  398.     }
  399.  
  400.  
  401.  
  402.  
  403.  
  404.  
  405. /*
  406.  * CKoala::Disconnect
  407.  *
  408.  * Purpose:
  409.  *  Instructs an object with custom marshaling that it's being
  410.  *  disconnected.
  411.  *
  412.  * Parameters:
  413.  *  dwReserved      DWORD reserved.
  414.  */
  415.  
  416. STDMETHODIMP CKoala::DisconnectObject(DWORD dwReserved)
  417.     {
  418.     /*
  419.      * This is generated from within CoDisconnectObject, which
  420.      * our server doesn't call itself.  This would give the object
  421.      * a chance to close its connection and cleanup before going
  422.      * away since the proxy will no longer be calling it.
  423.      * This should also be used to block any additional calls
  424.      * made after this point.
  425.      */
  426.  
  427.     return NOERROR;
  428.     }
  429.