home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 39 / IOPROG_39.ISO / SOFT / sdkjava40.exe / data1.cab / fg_Samples / Samples / Native / BrowserAppletControl / AppletHoster.cpp next >
Encoding:
C/C++ Source or Header  |  2000-05-04  |  34.6 KB  |  1,199 lines

  1. /*++
  2.  
  3. (C) Copyright 1995 - 1999 Microsoft Corporation.  All rights reserved.
  4.  
  5. Module Name:
  6.  
  7.     AppletHoster.cpp
  8.  
  9. Abstract:
  10.  
  11.     Demonstrates the use of the ActiveX Browser Applet Control.  This is the
  12.     same control used by Microsoft Internet Explorer to handle the <applet>
  13.     tag.  This control was added in the SDK 2.0 / Internet Explorer 4.0
  14.     Microsoft virtual machine.
  15.  
  16. --*/
  17.  
  18. #include <windows.h>
  19. #include <olectl.h>
  20. #ifndef __IPropertyBag2_INTERFACE_DEFINED__
  21. //  propbag2.h is automatically included in the latest ocidl.h from the
  22. //  Microsoft Platform SDK.
  23. #include <propbag2.h>
  24. #endif
  25. #include <initguid.h>
  26. #include <javaax.h>
  27.  
  28. #if _MSC_VER >= 1100
  29. #define IID_IPropertyBag2               __uuidof(IPropertyBag2)
  30. #define IID_IPersistPropertyBag2        __uuidof(IPersistPropertyBag2)
  31. #endif
  32.  
  33. #define ARRAY_ELEMENTS(rg)              (sizeof(rg) / sizeof((rg)[0]))
  34.  
  35. HINSTANCE g_hInstance = NULL;
  36.  
  37. HRESULT CoDuplicateString(LPCOLESTR pwszSource, LPOLESTR *ppwszDestination)
  38. {
  39.     HRESULT hr;
  40.     int length;
  41.     LPOLESTR pwszDestination;
  42.  
  43.     length = wcslen(pwszSource);
  44.     pwszDestination = (LPOLESTR) CoTaskMemAlloc((length + 1) * sizeof(OLECHAR));
  45.  
  46.     if (pwszDestination != NULL) {
  47.         CopyMemory(pwszDestination, pwszSource, length * sizeof(OLECHAR));
  48.         pwszDestination[length] = L'\0';
  49.         hr = S_OK;
  50.     } else {
  51.         hr = E_OUTOFMEMORY;
  52.     }
  53.  
  54.     *ppwszDestination = pwszDestination;
  55.  
  56.     return hr;
  57. }
  58.  
  59. ///////////////////////////////////////////////////////////////////////////////
  60. //  CPropertyBag2
  61.  
  62. struct NAME_VALUE_PAIR {
  63.     LPOLESTR pwszName;
  64.     LPOLESTR pwszValue;
  65. };
  66.  
  67. class CPropertyBag2: public IPropertyBag2
  68. {
  69. private:
  70.     static NAME_VALUE_PAIR s_HardcodedParameters[];
  71.  
  72.     ULONG m_cRef;
  73.  
  74. public:
  75.     CPropertyBag2() {
  76.         m_cRef = 1;
  77.     }
  78.  
  79.     //  IUnknown methods
  80.  
  81.     STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppvObject);
  82.     STDMETHODIMP_(ULONG) AddRef(void);
  83.     STDMETHODIMP_(ULONG) Release(void);
  84.  
  85.     //  IPropertyBag2 methods
  86.  
  87.     STDMETHODIMP Read(ULONG cProperties, PROPBAG2 *pPropBag, IErrorLog *pErrLog,
  88.         VARIANT *pvarValue, HRESULT *phrError);
  89.     STDMETHODIMP Write(ULONG cProperties, PROPBAG2 *pPropBag, VARIANT *pvarValue);
  90.     STDMETHODIMP CountProperties(ULONG *pcProperties);
  91.     STDMETHODIMP GetPropertyInfo(ULONG iProperty, ULONG cProperties, PROPBAG2
  92.         *pPropBag, ULONG *pcProperties);
  93.     STDMETHODIMP LoadObject(LPCOLESTR pstrName, DWORD dwHint, IUnknown
  94.         *pUnkObject, IErrorLog *pErrLog);
  95. };
  96.  
  97. NAME_VALUE_PAIR CPropertyBag2::s_HardcodedParameters[] = {
  98.     { L"codebase",          L"."                                },
  99.     { L"code",              L"SampleApplet"                     },
  100.     { L"SomeParameter",     L"Some Random Text To Paint"        },
  101. };
  102.  
  103. STDMETHODIMP CPropertyBag2::QueryInterface(REFIID riid, LPVOID *ppvObject)
  104. {
  105.     HRESULT hr;
  106.  
  107.     if (riid == IID_IUnknown || riid == IID_IPropertyBag2) {
  108.         *ppvObject = (IPropertyBag2 *) this;
  109.         AddRef();
  110.         hr = S_OK;
  111.     } else {
  112.         *ppvObject = NULL;
  113.         hr = E_NOINTERFACE;
  114.     }
  115.  
  116.     return hr;
  117. }
  118.  
  119. STDMETHODIMP_(ULONG) CPropertyBag2::AddRef(void)
  120. {
  121.     m_cRef++;
  122.  
  123.     return m_cRef;
  124. }
  125.  
  126. STDMETHODIMP_(ULONG) CPropertyBag2::Release(void)
  127. {
  128.     m_cRef--;
  129.  
  130.     if (m_cRef == 0) {
  131.         delete this;
  132.         return 0;
  133.     }
  134.  
  135.     return m_cRef;
  136. }
  137.  
  138. STDMETHODIMP CPropertyBag2::Read(ULONG cProperties, PROPBAG2 *pPropBag,
  139.     IErrorLog *pErrLog, VARIANT *pvarValue, HRESULT *phrError)
  140. {
  141.     HRESULT hr;
  142.     BOOL fFail;
  143.     ULONG current;
  144.     ULONG match;
  145.     VARIANT varLocal;
  146.  
  147.     fFail = FALSE;
  148.  
  149.     for (current = 0; current < cProperties; current++) {
  150.  
  151.         hr = E_FAIL;
  152.  
  153.         VariantClear(pvarValue);
  154.  
  155.         for (match = 0; match < ARRAY_ELEMENTS(s_HardcodedParameters); match++) {
  156.  
  157.             if (_wcsicmp(pPropBag->pstrName,
  158.                 s_HardcodedParameters[match].pwszName) == 0) {
  159.  
  160.                 varLocal.vt = VT_BSTR;
  161.                 varLocal.bstrVal =
  162.                     ::SysAllocString(s_HardcodedParameters[match].pwszValue);
  163.  
  164.                 if (varLocal.bstrVal != NULL) {
  165.  
  166.                     //  If the caller wanted a BSTR, then just transfer
  167.                     //  ownership of the string to them (saves duplicating the
  168.                     //  string).
  169.                     if (pPropBag->vt == VT_BSTR) {
  170.                         *pvarValue = varLocal;
  171.                         hr = S_OK;
  172.                     } else {
  173.                         hr = VariantChangeTypeEx(pvarValue, &varLocal,
  174.                             LOCALE_USER_DEFAULT, 0, pPropBag->vt);
  175.                         VariantClear(&varLocal);
  176.                     }
  177.  
  178.                 } else {
  179.                     hr = E_OUTOFMEMORY;
  180.                 }
  181.  
  182.                 break;
  183.             }
  184.         }
  185.  
  186.         if (hr != S_OK)
  187.             fFail = TRUE;
  188.  
  189.         if (phrError != NULL) {
  190.             *phrError = hr;
  191.             phrError++;
  192.         }
  193.     }
  194.  
  195.     return fFail ? E_FAIL : S_OK;
  196. }
  197.  
  198. STDMETHODIMP CPropertyBag2::Write(ULONG cProperties, PROPBAG2 *pPropBag, VARIANT
  199.     *pvarValue)
  200. {
  201.     //  The applet control does support IPersistPropertyBag2::Save in which case
  202.     //  it will invoke this method, but since we aren't saving anything, we'll
  203.     //  skip the implementation.
  204.     //
  205.     //  If you were to use IPersistPropertyBag2::Save, then the applet control
  206.     //  calls this method with:
  207.     //      pPropBag: .dwType = PROPBAG2_TYPE_DATA, .vt = VT_BSTR,
  208.     //          .pstrName = the parameter name.
  209.     //      pvarValue: vt = VT_BSTR, bstrVal = the parameter value.
  210.     //
  211.     //  The BSTRs are owned by the applet control and are only valid during this
  212.     //  method execution.
  213.     return E_NOTIMPL;
  214. }
  215.  
  216. STDMETHODIMP CPropertyBag2::CountProperties(ULONG *pcProperties)
  217. {
  218.     //  The applet control will invoke this method to find out how many
  219.     //  properties to read from the list.
  220.     *pcProperties = ARRAY_ELEMENTS(s_HardcodedParameters);
  221.  
  222.     return S_OK;
  223. }
  224.  
  225. STDMETHODIMP CPropertyBag2::GetPropertyInfo(ULONG iProperty, ULONG cProperties,
  226.     PROPBAG2 *pPropBag, ULONG *pcProperties)
  227. {
  228.     HRESULT hr;
  229.     ULONG current;
  230.  
  231.     hr = S_OK;
  232.  
  233.     for (current = iProperty; current < ARRAY_ELEMENTS(s_HardcodedParameters) &&
  234.         current < iProperty + cProperties; current++) {
  235.  
  236.         //  We return a data element of type VT_BSTR.  The hint can be used in
  237.         //  IPropertyBag2::Read to find the requested name more quickly, but is
  238.         //  optional.
  239.         pPropBag->dwType = PROPBAG2_TYPE_DATA;
  240.         pPropBag->vt = VT_BSTR;
  241.         pPropBag->cfType = CF_TEXT;
  242.         pPropBag->dwHint = current;
  243.  
  244.         hr = CoDuplicateString(s_HardcodedParameters[current].pwszName,
  245.             &(pPropBag->pstrName));
  246.  
  247.         if (hr != S_OK)
  248.             break;
  249.  
  250.         pPropBag++;
  251.     }
  252.  
  253.     if (pcProperties != NULL)
  254.         *pcProperties = current - iProperty;
  255.  
  256.     return hr;
  257. }
  258.  
  259. STDMETHODIMP CPropertyBag2::LoadObject(LPCOLESTR pstrName, DWORD dwHint,
  260.     IUnknown *pUnkObject, IErrorLog *pErrLog)
  261. {
  262.     //  The applet control doesn't currently invoke this method.
  263.     return E_NOTIMPL;
  264. }
  265.  
  266. ///////////////////////////////////////////////////////////////////////////////
  267. //  CAppletHostFrame
  268.  
  269. #define DISPID_BASEHREF                 0x00000100
  270.  
  271. class CAppletHostFrame: public IOleClientSite,
  272.                         public IOleControlSite,
  273.                         public IDispatch,
  274.                         public IOleInPlaceSite,
  275.                         public IOleInPlaceFrame,
  276.                         public IPropertyNotifySink
  277. {
  278. private:
  279.     static const LPCSTR s_pszWndClassName;
  280.  
  281.     ULONG m_cRef;
  282.     HWND m_hwnd;
  283.     IOleObject *m_pOleObject;
  284.     IConnectionPoint *m_pPropNotifyConnectionPoint;
  285.     DWORD m_dwPropNotifyConnectionCookie;
  286.  
  287.     BSTR GetDocumentBase();
  288.     void ResizeApplet();
  289.     void CloseApplet();
  290.  
  291. public:
  292.     static HRESULT InitializeClass(void);
  293.  
  294.     static LRESULT WINAPI WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM
  295.         lParam);
  296.  
  297.     CAppletHostFrame() {
  298.         m_cRef = 1;
  299.         m_hwnd = NULL;
  300.         m_pOleObject = NULL;
  301.         m_pPropNotifyConnectionPoint = NULL;
  302.     }
  303.  
  304.     ~CAppletHostFrame() {
  305.         if (m_pPropNotifyConnectionPoint != NULL)
  306.             m_pPropNotifyConnectionPoint->Release();
  307.         if (m_pOleObject != NULL)
  308.             m_pOleObject->Release();
  309.     }
  310.  
  311.     HRESULT Initialize(int nShowCmd);
  312.     void DemonstrateIDispatch(void);
  313.  
  314.     //  IUnknown methods
  315.  
  316.     STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppvObject);
  317.     STDMETHODIMP_(ULONG) AddRef(void);
  318.     STDMETHODIMP_(ULONG) Release(void);
  319.  
  320.     //  IOleClientSite methods
  321.  
  322.     STDMETHODIMP SaveObject(void);
  323.     STDMETHODIMP GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker, IMoniker
  324.         **ppmk);
  325.     STDMETHODIMP GetContainer(IOleContainer **ppContainer);
  326.     STDMETHODIMP ShowObject(void);
  327.     STDMETHODIMP OnShowWindow(BOOL fShow);
  328.     STDMETHODIMP RequestNewObjectLayout(void);
  329.  
  330.     //  IOleControlSite methods
  331.  
  332.     STDMETHODIMP OnControlInfoChanged(void);
  333.     STDMETHODIMP LockInPlaceActive(BOOL fLock);
  334.     STDMETHODIMP GetExtendedControl(IDispatch **ppDisp);
  335.     STDMETHODIMP TransformCoords(POINTL *pPtlHimetric, POINTF *pPtfContainer,
  336.          DWORD dwFlags);
  337.     STDMETHODIMP TranslateAccelerator(MSG *pMsg, DWORD grfModifiers);
  338.     STDMETHODIMP OnFocus(BOOL fGotFocus);
  339.     STDMETHODIMP ShowPropertyFrame(void);
  340.  
  341.     //  IDispatch methods
  342.  
  343.     STDMETHODIMP GetTypeInfoCount(UINT *pctinfo);
  344.     STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo);
  345.     STDMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames,
  346.         LCID lcid, DISPID *rgDispId);
  347.     STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD
  348.         wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO
  349.         *pExcepInfo, UINT *puArgErr);
  350.  
  351.     //  IOleInPlaceSite methods
  352.  
  353.     STDMETHODIMP CanInPlaceActivate(void);
  354.     STDMETHODIMP OnInPlaceActivate(void);
  355.     STDMETHODIMP OnUIActivate(void);
  356.     STDMETHODIMP GetWindowContext(IOleInPlaceFrame **ppFrame, IOleInPlaceUIWindow
  357.         **ppDoc, LPRECT lprcPosRect, LPRECT lprcClipRect, LPOLEINPLACEFRAMEINFO
  358.         lpFrameInfo);
  359.     STDMETHODIMP Scroll(SIZE scrollExtant);
  360.     STDMETHODIMP OnUIDeactivate(BOOL fUndoable);
  361.     STDMETHODIMP OnInPlaceDeactivate(void);
  362.     STDMETHODIMP DiscardUndoState(void);
  363.     STDMETHODIMP DeactivateAndUndo(void);
  364.     STDMETHODIMP OnPosRectChange(LPCRECT lprcPosRect);
  365.  
  366.     //  IOleWindow methods
  367.  
  368.     STDMETHODIMP GetWindow(HWND *phwnd);
  369.     STDMETHODIMP ContextSensitiveHelp(BOOL fEnterMode);
  370.  
  371.     //  IOleInPlaceUIWindow methods
  372.  
  373.     STDMETHODIMP GetBorder(LPRECT lprectBorder);
  374.     STDMETHODIMP RequestBorderSpace(LPCBORDERWIDTHS pborderwidths);
  375.     STDMETHODIMP SetBorderSpace(LPCBORDERWIDTHS pborderwidths);
  376.     STDMETHODIMP SetActiveObject(IOleInPlaceActiveObject *pActiveObject,
  377.         LPCOLESTR pszObjName);
  378.  
  379.     //  IOleInPlaceFrame methods
  380.  
  381.     STDMETHODIMP InsertMenus(HMENU hmenuShared, LPOLEMENUGROUPWIDTHS
  382.         lpMenuWidths);
  383.     STDMETHODIMP SetMenu(HMENU hmenuShared, HOLEMENU holemenu, HWND
  384.         hwndActiveObject);
  385.     STDMETHODIMP RemoveMenus(HMENU hmenuShared);
  386.     STDMETHODIMP SetStatusText(LPCOLESTR pszStatusText);
  387.     STDMETHODIMP EnableModeless(BOOL fEnable);
  388.     STDMETHODIMP TranslateAccelerator(LPMSG lpmsg, WORD wID);
  389.  
  390.     //  IPropertyNotifySink methods
  391.  
  392.     STDMETHODIMP OnChanged(DISPID dispid);
  393.     STDMETHODIMP OnRequestEdit(DISPID dispid);
  394. };
  395.  
  396. const LPCSTR CAppletHostFrame::s_pszWndClassName = "CAppletHostFrame";
  397.  
  398. //
  399. //  CAppletHostFrame::InitializeClass
  400. //
  401. //  Performs any initialization required by this class type.
  402. //
  403.  
  404. HRESULT CAppletHostFrame::InitializeClass(void)
  405. {
  406.     WNDCLASS wc;
  407.  
  408.     ZeroMemory(&wc, sizeof(wc));
  409.     wc.lpfnWndProc = CAppletHostFrame::WndProc;
  410.     wc.hInstance = g_hInstance;
  411.     wc.lpszClassName = s_pszWndClassName;
  412.     wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  413.     wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
  414.  
  415.     return RegisterClass(&wc) != 0 ? S_OK : HRESULT_FROM_WIN32(GetLastError());
  416. }
  417.  
  418. //
  419. //  CAppletHostFrame::WndProc
  420. //
  421.  
  422. LRESULT WINAPI CAppletHostFrame::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam,
  423.     LPARAM lParam)
  424. {
  425.     CAppletHostFrame *pFrame;
  426.  
  427.     if (uMsg == WM_NCCREATE) {
  428.         pFrame = (CAppletHostFrame *) ((LPCREATESTRUCT) lParam)->
  429.             lpCreateParams;
  430.         ::SetWindowLong(hwnd, GWL_USERDATA, (LONG) pFrame);
  431.     } else {
  432.         pFrame = (CAppletHostFrame *) ::GetWindowLong(hwnd, GWL_USERDATA);
  433.     }
  434.  
  435.     switch (uMsg) {
  436.  
  437.         case WM_SIZE:
  438.             pFrame->ResizeApplet();
  439.             break;
  440.  
  441.         case WM_DESTROY:
  442.             pFrame->CloseApplet();
  443.             ::PostQuitMessage(0);
  444.             break;
  445.  
  446.         default:
  447.             return ::DefWindowProc(hwnd, uMsg, wParam, lParam);
  448.     }
  449.  
  450.     return 0;
  451. }
  452.  
  453. HRESULT CAppletHostFrame::Initialize(int nShowCmd)
  454. {
  455.     HRESULT hr;
  456.     CPropertyBag2 *pParameters;
  457.     IConnectionPointContainer *pcpc;
  458.     IPersistPropertyBag2 *ppbag;
  459.     RECT rcClient;
  460.  
  461.     hr = ::CoCreateInstance(CLSID_BrowserAppletControl, NULL,
  462.         CLSCTX_INPROC_SERVER, IID_IOleObject, (LPVOID *) &m_pOleObject);
  463.  
  464.     if (hr == S_OK) {
  465.  
  466.         m_hwnd = ::CreateWindowEx(0, s_pszWndClassName, "", WS_OVERLAPPEDWINDOW,
  467.             CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL,
  468.             NULL, g_hInstance, (LPVOID) this);
  469.  
  470.         if (m_hwnd != NULL) {
  471.  
  472.             hr = m_pOleObject->SetClientSite(this);
  473.  
  474.             if (hr == S_OK) {
  475.  
  476.                 //  Connect to the applet's IPropertyNotifySink events.  The
  477.                 //  applet will fire a DISPID_READYSTATE property change
  478.                 //  notification when the applet has fully loaded and is
  479.                 //  available for use.
  480.                 if (m_pOleObject->QueryInterface(IID_IConnectionPointContainer,
  481.                     (LPVOID *) &pcpc) == S_OK) {
  482.  
  483.                     if (pcpc->FindConnectionPoint(IID_IPropertyNotifySink,
  484.                         &m_pPropNotifyConnectionPoint) == S_OK) {
  485.  
  486.                         if (m_pPropNotifyConnectionPoint->Advise(
  487.                             (IPropertyNotifySink *) this,
  488.                             &m_dwPropNotifyConnectionCookie) != S_OK) {
  489.                             m_pPropNotifyConnectionPoint->Release();
  490.                             m_pPropNotifyConnectionPoint = NULL;
  491.                         }
  492.                     }
  493.  
  494.                     pcpc->Release();
  495.                 }
  496.  
  497.                 hr = m_pOleObject->QueryInterface(IID_IPersistPropertyBag2,
  498.                     (LPVOID *) &ppbag);
  499.  
  500.                 if (hr == S_OK) {
  501.  
  502.                     pParameters = new CPropertyBag2;
  503.  
  504.                     if (pParameters != NULL) {
  505.  
  506.                         hr = ppbag->Load(pParameters, NULL);
  507.                         pParameters->Release();
  508.  
  509.                         if (hr == S_OK) {
  510.  
  511.                             ::GetClientRect(m_hwnd, &rcClient);
  512.  
  513.                             hr = m_pOleObject->DoVerb(OLEIVERB_UIACTIVATE, NULL,
  514.                                 this, 0, m_hwnd, &rcClient);
  515.                         }
  516.  
  517.                     } else {
  518.                         hr = E_OUTOFMEMORY;
  519.                     }
  520.  
  521.                     ppbag->Release();
  522.                 }
  523.             }
  524.  
  525.             ::ShowWindow(m_hwnd, nShowCmd);
  526.             ::UpdateWindow(m_hwnd);
  527.  
  528.         } else {
  529.             hr = HRESULT_FROM_WIN32(GetLastError());
  530.         }
  531.  
  532.         if (hr != S_OK)
  533.             CloseApplet();
  534.     }
  535.  
  536.     return hr;
  537. }
  538.  
  539. //
  540. //  CAppletHostFrame::DemonstrateIDispatch
  541. //
  542. //  Demonstrates the use of IDispatch to access the scripting interface of the
  543. //  hosted applet.
  544. //
  545.  
  546. void CAppletHostFrame::DemonstrateIDispatch(void)
  547. {
  548.     IDispatch *pDispatch;
  549.     LPOLESTR rgszNames[1];
  550.     DISPID dispid;
  551.     DISPPARAMS dispparams;
  552.     VARIANT var;
  553.     DISPID dispidPropertyPut;
  554.     VARIANT varResult;
  555.  
  556.     if (m_pOleObject != NULL) {
  557.  
  558.         if (m_pOleObject->QueryInterface(IID_IDispatch, (LPVOID *)
  559.             &pDispatch) == S_OK) {
  560.  
  561.             VariantInit(&var);
  562.             var.vt = VT_BSTR;
  563.             var.bstrVal = SysAllocString(L"Some More Random Text");
  564.  
  565.             if (var.bstrVal != NULL) {
  566.  
  567.                 rgszNames[0] = L"somestring";
  568.  
  569.                 //  An example of doing a "property put".
  570.                 if (pDispatch->GetIDsOfNames(IID_NULL, rgszNames,
  571.                     ARRAY_ELEMENTS(rgszNames), LOCALE_USER_DEFAULT, &dispid) ==
  572.                     S_OK) {
  573.  
  574.                     dispidPropertyPut = DISPID_PROPERTYPUT;
  575.  
  576.                     dispparams.rgvarg = &var;
  577.                     dispparams.rgdispidNamedArgs = &dispidPropertyPut;
  578.                     dispparams.cArgs = 1;
  579.                     dispparams.cNamedArgs = 1;
  580.  
  581.                     pDispatch->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT,
  582.                         DISPATCH_PROPERTYPUT, &dispparams, NULL, NULL, NULL);
  583.                 }
  584.  
  585.                 rgszNames[0] = L"somemethod";
  586.  
  587.                 //  An example of doing an "invoke".
  588.                 if (pDispatch->GetIDsOfNames(IID_NULL, rgszNames,
  589.                     ARRAY_ELEMENTS(rgszNames), LOCALE_USER_DEFAULT, &dispid) ==
  590.                     S_OK) {
  591.  
  592.                     dispparams.rgvarg = &var;
  593.                     dispparams.rgdispidNamedArgs = NULL;
  594.                     dispparams.cArgs = 1;
  595.                     dispparams.cNamedArgs = 0;
  596.  
  597.                     pDispatch->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT,
  598.                         DISPATCH_METHOD, &dispparams, NULL, NULL, NULL);
  599.                 }
  600.             }
  601.  
  602.             VariantClear(&var);
  603.  
  604.             pDispatch->Release();
  605.         }
  606.     }
  607. }
  608.  
  609. //
  610. //  CAppletHostFrame::GetDocumentBase
  611. //
  612. //  Returns the "document base" for the applet.  We'll use the current working
  613. //  directory.
  614. //
  615.  
  616. BSTR CAppletHostFrame::GetDocumentBase(void)
  617. {
  618.     CHAR szCurrentDirectory[MAX_PATH];
  619.     CHAR szDocumentBaseUrl[MAX_PATH+30];
  620.     WCHAR wszDocumentBaseUrl[MAX_PATH+30];
  621.  
  622.     GetCurrentDirectory(ARRAY_ELEMENTS(szCurrentDirectory), szCurrentDirectory);
  623.     lstrcpy(szDocumentBaseUrl, "file://");
  624.     lstrcat(szDocumentBaseUrl, szCurrentDirectory);
  625.     lstrcat(szDocumentBaseUrl, "/");
  626.  
  627.     MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szDocumentBaseUrl, -1,
  628.         wszDocumentBaseUrl, ARRAY_ELEMENTS(wszDocumentBaseUrl));
  629.  
  630.     return SysAllocString(wszDocumentBaseUrl);
  631. }
  632.  
  633. //
  634. //  CAppletHostFrame::ResizeApplet
  635. //
  636. //  Notifies the contained applet control that its bounding rectangle has
  637. //  changed.
  638. //
  639.  
  640. void CAppletHostFrame::ResizeApplet(void)
  641. {
  642.     RECT rcClient;
  643.     IOleInPlaceObject *pOleInPlaceObject;
  644.  
  645.     if (m_pOleObject != NULL) {
  646.  
  647.         if (m_pOleObject->QueryInterface(IID_IOleInPlaceObject, (LPVOID *)
  648.             &pOleInPlaceObject) == S_OK) {
  649.  
  650.             ::GetClientRect(m_hwnd, &rcClient);
  651.             pOleInPlaceObject->SetObjectRects(&rcClient, &rcClient);
  652.             pOleInPlaceObject->Release();
  653.         }
  654.     }
  655. }
  656.  
  657. //
  658. //  CAppletHostFrame::CloseApplet
  659. //
  660. //  Deactivates and close the contained applet control.
  661. //
  662.  
  663. void CAppletHostFrame::CloseApplet(void)
  664. {
  665.     if (m_pPropNotifyConnectionPoint != NULL) {
  666.  
  667.         m_pPropNotifyConnectionPoint->Unadvise(m_dwPropNotifyConnectionCookie);
  668.         m_pPropNotifyConnectionPoint->Release();
  669.         m_pPropNotifyConnectionPoint = NULL;
  670.     }
  671.  
  672.     if (m_pOleObject != NULL) {
  673.  
  674.         m_pOleObject->Close(OLECLOSE_NOSAVE);
  675.         m_pOleObject->Release();
  676.         m_pOleObject = NULL;
  677.     }
  678. }
  679.  
  680. STDMETHODIMP CAppletHostFrame::QueryInterface(REFIID riid, LPVOID *ppvObject)
  681. {
  682.     HRESULT hr;
  683.  
  684.     if (riid == IID_IUnknown || riid == IID_IOleClientSite) {
  685.         *ppvObject = (LPVOID) (IOleClientSite *) this;
  686.         hr = S_OK;
  687.     } else if (riid == IID_IOleControlSite) {
  688.         *ppvObject = (LPVOID) (IOleControlSite *) this;
  689.         hr = S_OK;
  690.     } else if (riid == IID_IDispatch) {
  691.         *ppvObject = (LPVOID) (IDispatch *) this;
  692.         hr = S_OK;
  693.     } else if (riid == IID_IOleInPlaceSite) {
  694.         *ppvObject = (LPVOID) (IOleInPlaceSite *) this;
  695.         hr = S_OK;
  696.     } else if (riid == IID_IOleWindow || riid == IID_IOleInPlaceUIWindow ||
  697.         riid == IID_IOleInPlaceFrame) {
  698.         *ppvObject = (LPVOID) (IOleInPlaceFrame *) this;
  699.         hr = S_OK;
  700.     } else if (riid == IID_IPropertyNotifySink) {
  701.         *ppvObject = (LPVOID) (IPropertyNotifySink *) this;
  702.         hr = S_OK;
  703.     } else {
  704.         *ppvObject = NULL;
  705.         hr = E_NOINTERFACE;
  706.     }
  707.  
  708.     if (hr == S_OK)
  709.         AddRef();
  710.  
  711.     return hr;
  712. }
  713.  
  714. STDMETHODIMP_(ULONG) CAppletHostFrame::AddRef(void)
  715. {
  716.     m_cRef++;
  717.  
  718.     return m_cRef;
  719. }
  720.  
  721. STDMETHODIMP_(ULONG) CAppletHostFrame::Release(void)
  722. {
  723.     m_cRef--;
  724.  
  725.     if (m_cRef == 0) {
  726.         delete this;
  727.         return 0;
  728.     }
  729.  
  730.     return m_cRef;
  731. }
  732.  
  733. STDMETHODIMP CAppletHostFrame::SaveObject(void)
  734. {
  735.     //  The applet control doesn't currently invoke this method.
  736.     return E_NOTIMPL;
  737. }
  738.  
  739. STDMETHODIMP CAppletHostFrame::GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker, IMoniker
  740.     **ppmk)
  741. {
  742.     //  The applet control doesn't currently invoke this method.
  743.     *ppmk = NULL;
  744.     return E_NOTIMPL;
  745. }
  746.  
  747. STDMETHODIMP CAppletHostFrame::GetContainer(IOleContainer **ppContainer)
  748. {
  749.     //  The applet control doesn't currently invoke this method.
  750.     *ppContainer = NULL;
  751.     return E_NOTIMPL;
  752. }
  753.  
  754. STDMETHODIMP CAppletHostFrame::ShowObject(void)
  755. {
  756.     //  The applet control doesn't currently invoke this method.
  757.     return S_OK;
  758. }
  759.  
  760. STDMETHODIMP CAppletHostFrame::OnShowWindow(BOOL fShow)
  761. {
  762.     //  The applet control doesn't currently invoke this method.
  763.     return S_OK;
  764. }
  765.  
  766. STDMETHODIMP CAppletHostFrame::RequestNewObjectLayout(void)
  767. {
  768.     //  The applet control will invoke this method when running as an <OBJECT>
  769.     //  tag which uses a different binding mechanism not covered in this
  770.     //  example.
  771.     return E_NOTIMPL;
  772. }
  773.  
  774. STDMETHODIMP CAppletHostFrame::OnControlInfoChanged(void)
  775. {
  776.     //  Ignore the notification.
  777.     return S_OK;
  778. }
  779.  
  780. STDMETHODIMP CAppletHostFrame::LockInPlaceActive(BOOL fLock)
  781. {
  782.     //  The applet control doesn't currently invoke this method.
  783.     return E_NOTIMPL;
  784. }
  785.  
  786. STDMETHODIMP CAppletHostFrame::GetExtendedControl(IDispatch **ppDisp)
  787. {
  788.     //  The extended control is implemented directly on this object.
  789.     return this->QueryInterface(IID_IDispatch, (LPVOID *) ppDisp);
  790. }
  791.  
  792. STDMETHODIMP CAppletHostFrame::TransformCoords(POINTL *pPtlHimetric, POINTF
  793.     *pPtfContainer, DWORD dwFlags)
  794. {
  795.     //  The applet control doesn't currently invoke this method.
  796.     return E_NOTIMPL;
  797. }
  798.  
  799. STDMETHODIMP CAppletHostFrame::TranslateAccelerator(MSG *pMsg, DWORD grfModifiers)
  800. {
  801.     //  The applet control doesn't currently invoke this method.
  802.     return E_NOTIMPL;
  803. }
  804.  
  805. STDMETHODIMP CAppletHostFrame::OnFocus(BOOL fGotFocus)
  806. {
  807.     //  Ignore the notification.
  808.     return S_OK;
  809. }
  810.  
  811. STDMETHODIMP CAppletHostFrame::ShowPropertyFrame(void)
  812. {
  813.     //  The applet control doesn't currently invoke this method.
  814.     return E_NOTIMPL;
  815. }
  816.  
  817. STDMETHODIMP CAppletHostFrame::GetTypeInfoCount(UINT *pctinfo)
  818. {
  819.     //  The applet control doesn't currently invoke this method.
  820.     *pctinfo = 0;
  821.     return S_OK;
  822. }
  823.  
  824. STDMETHODIMP CAppletHostFrame::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo
  825.     **ppTInfo)
  826. {
  827.     //  The applet control doesn't currently invoke this method.
  828.     *ppTInfo = NULL;
  829.     return E_FAIL;
  830. }
  831.  
  832. STDMETHODIMP CAppletHostFrame::GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames,
  833.     UINT cNames, LCID lcid, DISPID *rgDispId)
  834. {
  835.     HRESULT hr;
  836.     UINT i;
  837.  
  838.     if (riid == IID_NULL) {
  839.  
  840.         for (i = 0; i < cNames; i++)
  841.             rgDispId[i] = DISPID_UNKNOWN;
  842.  
  843.         //  The applet control will ask for "BaseHref" in order to determine the
  844.         //  URL of the document that's hosting the applet control.  The control
  845.         //  will call IDispatch::Invoke (below) with this dispid.
  846.         if (_wcsicmp(rgszNames[0], L"BaseHref") == 0) {
  847.             rgDispId[0] = DISPID_BASEHREF;
  848.             hr = S_OK;
  849.         } else {
  850.             hr = DISP_E_UNKNOWNNAME;
  851.         }
  852.  
  853.         //  If we were asked for parameter names, too, then these are definitely
  854.         //  not known.
  855.         if (cNames > 1)
  856.             hr = DISP_E_UNKNOWNNAME;
  857.  
  858.     } else {
  859.         hr = DISP_E_UNKNOWNINTERFACE;
  860.     }
  861.  
  862.     return hr;
  863. }
  864.  
  865. STDMETHODIMP CAppletHostFrame::Invoke(DISPID dispIdMember, REFIID riid, LCID
  866.     lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO
  867.     *pExcepInfo, UINT *puArgErr)
  868. {
  869.     HRESULT hr;
  870.  
  871.     if (riid == IID_NULL) {
  872.  
  873.         switch (dispIdMember) {
  874.  
  875.             //  Return the document URL to the applet control.  It's valid to
  876.             //  not support this dispid if a document URL doesn't make any sense
  877.             //  in the context of the container.  This document URL is used as
  878.             //  the default codebase if an explicit codebase is not specified
  879.             //  in the property bag.  Also, the document URL is returned to the
  880.             //  applet through getDocumentBase().
  881.             case DISPID_BASEHREF:
  882.                 if (pVarResult == NULL || pDispParams == NULL) {
  883.                     hr = E_INVALIDARG;
  884.                 } else if (!(wFlags & DISPATCH_PROPERTYGET)) {
  885.                     hr = DISP_E_MEMBERNOTFOUND;
  886.                 } else {
  887.                     pVarResult->vt = VT_BSTR;
  888.                     pVarResult->bstrVal = GetDocumentBase();
  889.                     hr = S_OK;
  890.                 }
  891.                 break;
  892.  
  893.             //  The applet control will do a property get for the locale id.
  894.             //  The locale id controls the locale of the applet (as returned
  895.             //  by Component.getLocale).  This dispid is optional: if the site
  896.             //  does not support this property, then the system default locale
  897.             //  id is used.
  898. #if 0
  899.             case DISPID_AMBIENT_LOCALEID:
  900.                 if (pVarResult == NULL || pDispParams == NULL) {
  901.                     hr = E_INVALIDARG;
  902.                 } else if (!(wFlags & DISPATCH_PROPERTYGET)) {
  903.                     hr = DISP_E_MEMBERNOTFOUND;
  904.                 } else {
  905.                     pVarResult->vt = VT_I4;
  906.                     pVarResult->lVal = ::GetSystemDefaultLCID();
  907.                     hr = S_OK;
  908.                 }
  909.                 break;
  910. #endif
  911.  
  912.             default:
  913.                 hr = DISP_E_MEMBERNOTFOUND;
  914.                 break;
  915.         }
  916.  
  917.     } else {
  918.         hr = DISP_E_UNKNOWNINTERFACE;
  919.     }
  920.  
  921.     return hr;
  922. }
  923.  
  924. STDMETHODIMP CAppletHostFrame::CanInPlaceActivate(void)
  925. {
  926.     //  The applet control will invoke this method before moving into the
  927.     //  "inplace active" state to check if the ActiveX site will allow
  928.     //  activation.  We'll allow activation.
  929.     return S_OK;
  930. }
  931.  
  932. STDMETHODIMP CAppletHostFrame::OnInPlaceActivate(void)
  933. {
  934.     //  The applet control will invoke this method after the control has
  935.     //  formally transitioned to the "inplace active" state (after this site has
  936.     //  called IOleObject::DoVerb(OLEIVERB_INPLACEACTIVATE)).
  937.     return S_OK;
  938. }
  939.  
  940. STDMETHODIMP CAppletHostFrame::OnUIActivate(void)
  941. {
  942.     //  The applet control will invoke this method after the control has
  943.     //  formally transitioned to the "UI active" state (after this site has
  944.     //  called IOleObject::DoVerb(OLEIVERB_UIACTIVATE)).
  945.     return S_OK;
  946. }
  947.  
  948. STDMETHODIMP CAppletHostFrame::GetWindowContext(IOleInPlaceFrame **ppFrame,
  949.     IOleInPlaceUIWindow **ppDoc, LPRECT lprcPosRect, LPRECT lprcClipRect,
  950.     LPOLEINPLACEFRAMEINFO lpFrameInfo)
  951. {
  952.     RECT rcClient;
  953.  
  954.     //  For simplicity, the frame, document, and site windows are all
  955.     //  implemented on the same object.  These could be different objects.  For
  956.     //  example, a single frame and window object may contain several site
  957.     //  objects each of which is hosting a single instance of the applet
  958.     //  control.  Such would be the case in something like Internet Explorer.
  959.     if (ppFrame != NULL) {
  960.         *ppFrame = this;
  961.         AddRef();
  962.     }
  963.  
  964.     if (ppDoc != NULL) {
  965.         *ppDoc = this;
  966.         AddRef();
  967.     }
  968.  
  969.     ::GetClientRect(m_hwnd, &rcClient);
  970.  
  971.     if (lprcPosRect != NULL)
  972.         ::CopyRect(lprcPosRect, &rcClient);
  973.  
  974.     if (lprcClipRect != NULL)
  975.         ::CopyRect(lprcClipRect, &rcClient);
  976.  
  977.     //  The applet control doesn't currently use any of the values in this
  978.     //  structure, but fill it in for possible future use.
  979.     lpFrameInfo->fMDIApp = FALSE;
  980.     lpFrameInfo->hwndFrame = m_hwnd;
  981.     lpFrameInfo->haccel = NULL;
  982.     lpFrameInfo->cAccelEntries = 0;
  983.  
  984.     return S_OK;
  985. }
  986.  
  987. STDMETHODIMP CAppletHostFrame::Scroll(SIZE scrollExtant)
  988. {
  989.     //  The applet control doesn't currently invoke this method.
  990.     return E_NOTIMPL;
  991. }
  992.  
  993. STDMETHODIMP CAppletHostFrame::OnUIDeactivate(BOOL fUndoable)
  994. {
  995.     //  Ignore the notification.
  996.     return S_OK;
  997. }
  998.  
  999. STDMETHODIMP CAppletHostFrame::OnInPlaceDeactivate(void)
  1000. {
  1001.     //  Ignore the notification.
  1002.     return S_OK;
  1003. }
  1004.  
  1005. STDMETHODIMP CAppletHostFrame::DiscardUndoState(void)
  1006. {
  1007.     //  The applet control doesn't currently invoke this method.
  1008.     return E_NOTIMPL;
  1009. }
  1010.  
  1011. STDMETHODIMP CAppletHostFrame::DeactivateAndUndo(void)
  1012. {
  1013.     //  The applet control doesn't currently invoke this method.
  1014.     return E_NOTIMPL;
  1015. }
  1016.  
  1017. STDMETHODIMP CAppletHostFrame::OnPosRectChange(LPCRECT lprcPosRect)
  1018. {
  1019.     //  Ignore the notification.
  1020.     return S_OK;
  1021. }
  1022.  
  1023. STDMETHODIMP CAppletHostFrame::GetWindow(HWND *phwnd)
  1024. {
  1025.     //  Return our window to the applet control.  The applet control's window
  1026.     //  will be a child window of this window.
  1027.     *phwnd = m_hwnd;
  1028.  
  1029.     return S_OK;
  1030. }
  1031.  
  1032. STDMETHODIMP CAppletHostFrame::ContextSensitiveHelp(BOOL fEnterMode)
  1033. {
  1034.     //  The applet control doesn't currently invoke this method.
  1035.     return E_NOTIMPL;
  1036. }
  1037.  
  1038. STDMETHODIMP CAppletHostFrame::GetBorder(LPRECT lprectBorder)
  1039. {
  1040.     //  The applet control doesn't currently invoke this method.
  1041.     return E_NOTIMPL;
  1042. }
  1043.  
  1044. STDMETHODIMP CAppletHostFrame::RequestBorderSpace(LPCBORDERWIDTHS pborderwidths)
  1045. {
  1046.     //  The applet control doesn't currently invoke this method.
  1047.     return E_NOTIMPL;
  1048. }
  1049.  
  1050. STDMETHODIMP CAppletHostFrame::SetBorderSpace(LPCBORDERWIDTHS pborderwidths)
  1051. {
  1052.     //  The applet control doesn't currently invoke this method.
  1053.     return E_NOTIMPL;
  1054. }
  1055.  
  1056. STDMETHODIMP CAppletHostFrame::SetActiveObject(IOleInPlaceActiveObject
  1057.     *pActiveObject, LPCOLESTR pszObjName)
  1058. {
  1059.     //  The applet control will invoke this when it goes into the UI active
  1060.     //  state.  An ActiveX contianer would typically save this object in order
  1061.     //  to forward any accelerator keystrokes or to track tab order.
  1062.     return S_OK;
  1063. }
  1064.  
  1065. STDMETHODIMP CAppletHostFrame::InsertMenus(HMENU hmenuShared, LPOLEMENUGROUPWIDTHS
  1066.     lpMenuWidths)
  1067. {
  1068.     //  The applet control doesn't currently invoke this method.
  1069.     return E_NOTIMPL;
  1070. }
  1071.  
  1072. STDMETHODIMP CAppletHostFrame::SetMenu(HMENU hmenuShared, HOLEMENU holemenu,
  1073.     HWND hwndActiveObject)
  1074. {
  1075.     //  The applet control doesn't currently invoke this method.
  1076.     return E_NOTIMPL;
  1077. }
  1078.  
  1079. STDMETHODIMP CAppletHostFrame::RemoveMenus(HMENU hmenuShared)
  1080. {
  1081.     //  The applet control doesn't currently invoke this method.
  1082.     return E_NOTIMPL;
  1083. }
  1084.  
  1085. STDMETHODIMP CAppletHostFrame::SetStatusText(LPCOLESTR pszStatusText)
  1086. {
  1087.     CHAR szBuffer[512];
  1088.  
  1089.     //  The applet control calls this method whenever the applet calls
  1090.     //  showStatus().
  1091.     if (::WideCharToMultiByte(CP_ACP, 0, pszStatusText, -1, szBuffer,
  1092.         ARRAY_ELEMENTS(szBuffer), NULL, NULL) > 0)
  1093.         ::SetWindowText(m_hwnd, szBuffer);
  1094.  
  1095.     return S_OK;
  1096. }
  1097.  
  1098. STDMETHODIMP CAppletHostFrame::EnableModeless(BOOL fEnable)
  1099. {
  1100.     //  The applet control doesn't currently invoke this method.
  1101.     return E_NOTIMPL;
  1102. }
  1103.  
  1104. STDMETHODIMP CAppletHostFrame::TranslateAccelerator(LPMSG lpmsg, WORD wID)
  1105. {
  1106.     //  The applet control doesn't currently invoke this method.
  1107.     return E_NOTIMPL;
  1108. }
  1109.  
  1110. STDMETHODIMP CAppletHostFrame::OnChanged(DISPID dispid)
  1111. {
  1112.     IDispatch *pDispatch;
  1113.     DISPPARAMS dispparams;
  1114.     VARIANT varResult;
  1115.  
  1116.     //  The applet control will call IPropertyNotifySink::OnChanged with
  1117.     //  DISPID_READYSTATE after the loaded Java object has been created.  The
  1118.     //  applet's init() method has not been called yet.
  1119.     if (dispid == DISPID_READYSTATE) {
  1120.  
  1121.         if (m_pOleObject != NULL && m_pOleObject->QueryInterface(IID_IDispatch,
  1122.             (LPVOID *) &pDispatch) == S_OK) {
  1123.  
  1124.             dispparams.rgvarg = NULL;
  1125.             dispparams.rgdispidNamedArgs = NULL;
  1126.             dispparams.cArgs = 0;
  1127.             dispparams.cNamedArgs = 0;
  1128.  
  1129.             VariantInit(&varResult);
  1130.  
  1131.             if (pDispatch->Invoke(DISPID_READYSTATE, IID_NULL,
  1132.                 LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, &dispparams,
  1133.                 &varResult, NULL, NULL) == S_OK) {
  1134.  
  1135.                 //  Check if the READYSTATE is now READYSTATE_COMPLETE.  If so,
  1136.                 //  we can now safely use IDispatch to access the public methods
  1137.                 //  and properties of the applet and use
  1138.                 //  IConnectionPointContainer to attach to the events of the
  1139.                 //  applet.
  1140.                 if (varResult.vt == VT_I4 && varResult.lVal ==
  1141.                     READYSTATE_COMPLETE) {
  1142.  
  1143.                     //  The applet is now ready to go.  The applet can now be
  1144.                     //  scripted against and it's now possible to connect to the
  1145.                     //  applet's events.
  1146.                     DemonstrateIDispatch();
  1147.                 }
  1148.  
  1149.                 VariantClear(&varResult);
  1150.             }
  1151.  
  1152.             pDispatch->Release();
  1153.         }
  1154.     }
  1155.  
  1156.     return S_OK;
  1157. }
  1158.  
  1159. STDMETHODIMP CAppletHostFrame::OnRequestEdit(DISPID dispid)
  1160. {
  1161.     //  Ignore the notification.
  1162.     return S_OK;
  1163. }
  1164.  
  1165.  
  1166. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR
  1167.     lpszCmdLine, int nShowCmd)
  1168. {
  1169.     CAppletHostFrame *pFrame;
  1170.     MSG msg;
  1171.  
  1172.     g_hInstance = hInstance;
  1173.  
  1174.     if (SUCCEEDED(CoInitialize(NULL))) {
  1175.  
  1176.         if (SUCCEEDED(CAppletHostFrame::InitializeClass())) {
  1177.  
  1178.             pFrame = new CAppletHostFrame();
  1179.  
  1180.             if (pFrame != NULL) {
  1181.  
  1182.                 if (SUCCEEDED(pFrame->Initialize(nShowCmd))) {
  1183.  
  1184.                     while (GetMessage(&msg, NULL, 0, 0)) {
  1185.                         DispatchMessage(&msg);
  1186.                         TranslateMessage(&msg);
  1187.                     }
  1188.                 }
  1189.  
  1190.                 pFrame->Release();
  1191.             }
  1192.         }
  1193.  
  1194.         CoUninitialize();
  1195.     }
  1196.  
  1197.     return 0;
  1198. }
  1199.