KOALA.CPP
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:10k
源码类别:

Windows编程

开发平台:

Visual C++

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