Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

336 lines
9.3 KiB

  1. // builds an ocx out of the embedding in shembed.c
  2. #include "priv.h"
  3. #include "sccls.h"
  4. #include "olectl.h"
  5. #include "stdenum.h"
  6. #include "shocx.h"
  7. #include "resource.h"
  8. LCID g_lcidLocale = MAKELCID(LANG_USER_DEFAULT, SORT_DEFAULT);
  9. #define SUPERCLASS CShellEmbedding
  10. CShellOcx::CShellOcx(IUnknown* punkOuter, LPCOBJECTINFO poi, const OLEVERB* pverbs, const OLEVERB* pdesignverbs) :
  11. CShellEmbedding(punkOuter, poi, pverbs),
  12. _pDesignVerbs(pdesignverbs),
  13. CImpIDispatch(LIBID_SHDocVw, 1, 1, *(poi->piid))
  14. {
  15. // CShellEmbedding class handles the DllAddRef / DllRelease
  16. m_cpEvents.SetOwner(_GetInner(), poi->piidEvents);
  17. m_cpPropNotify.SetOwner(_GetInner(), &IID_IPropertyNotifySink);
  18. _nDesignMode = MODE_UNKNOWN;
  19. }
  20. CShellOcx::~CShellOcx()
  21. {
  22. // Should have been released when cllient site was set to NULL.... Don't release
  23. // it here as this will cause some applications like VC5 to fault...
  24. ASSERT(_pDispAmbient==NULL);
  25. if (_pClassTypeInfo)
  26. _pClassTypeInfo->Release();
  27. }
  28. //
  29. // We have a different set of verbs in design mode
  30. //
  31. HRESULT CShellOcx::EnumVerbs(IEnumOLEVERB **ppEnumOleVerb)
  32. {
  33. TraceMsg(TF_SHDCONTROL, "sho: EnumVerbs");
  34. if (_IsDesignMode())
  35. {
  36. *ppEnumOleVerb = new CSVVerb(_pDesignVerbs);
  37. if (*ppEnumOleVerb)
  38. return S_OK;
  39. }
  40. return SUPERCLASS::EnumVerbs(ppEnumOleVerb);
  41. }
  42. //
  43. // For the interfaces we support here
  44. //
  45. HRESULT CShellOcx::v_InternalQueryInterface(REFIID riid, void **ppvObj)
  46. {
  47. static const QITAB qit[] = {
  48. QITABENT(CShellOcx, IDispatch),
  49. QITABENT(CShellOcx, IOleControl),
  50. QITABENT(CShellOcx, IConnectionPointContainer),
  51. QITABENT(CShellOcx, IPersistStreamInit),
  52. QITABENTMULTI(CShellOcx, IPersistStream, IPersistStreamInit),
  53. QITABENT(CShellOcx, IPersistPropertyBag),
  54. QITABENT(CShellOcx, IProvideClassInfo2),
  55. QITABENTMULTI(CShellOcx, IProvideClassInfo, IProvideClassInfo2),
  56. { 0 },
  57. };
  58. HRESULT hr = QISearch(this, qit, riid, ppvObj);
  59. if (FAILED(hr))
  60. hr = SUPERCLASS::v_InternalQueryInterface(riid, ppvObj);
  61. return hr;
  62. }
  63. //
  64. // On a SetClientSite, we need to discard everything created from _pcli
  65. // because shembed frees _pcli
  66. //
  67. HRESULT CShellOcx::SetClientSite(IOleClientSite *pClientSite)
  68. {
  69. if (_pDispAmbient)
  70. {
  71. _pDispAmbient->Release();
  72. _pDispAmbient = NULL;
  73. }
  74. return SUPERCLASS::SetClientSite(pClientSite);
  75. }
  76. HRESULT CShellOcx::Draw(
  77. DWORD dwDrawAspect,
  78. LONG lindex,
  79. void *pvAspect,
  80. DVTARGETDEVICE *ptd,
  81. HDC hdcTargetDev,
  82. HDC hdcDraw,
  83. LPCRECTL lprcBounds,
  84. LPCRECTL lprcWBounds,
  85. BOOL ( __stdcall *pfnContinue )(ULONG_PTR dwContinue),
  86. ULONG_PTR dwContinue)
  87. {
  88. if (_IsDesignMode())
  89. {
  90. HBRUSH hbrOld = (HBRUSH)SelectObject(hdcDraw, (HBRUSH)GetStockObject(WHITE_BRUSH));
  91. HPEN hpenOld = (HPEN)SelectObject(hdcDraw, (HPEN)GetStockObject(BLACK_PEN));
  92. Rectangle(hdcDraw, lprcBounds->left, lprcBounds->top, lprcBounds->right, lprcBounds->bottom);
  93. MoveToEx(hdcDraw, lprcBounds->left, lprcBounds->top, NULL);
  94. LineTo(hdcDraw, lprcBounds->right, lprcBounds->bottom);
  95. MoveToEx(hdcDraw, lprcBounds->left, lprcBounds->bottom, NULL);
  96. LineTo(hdcDraw, lprcBounds->right, lprcBounds->top);
  97. SelectObject(hdcDraw, hbrOld);
  98. SelectObject(hdcDraw, hpenOld);
  99. return S_OK;
  100. }
  101. return SUPERCLASS::Draw(dwDrawAspect, lindex, pvAspect, ptd, hdcTargetDev, hdcDraw,
  102. lprcBounds, lprcWBounds, pfnContinue, dwContinue);
  103. }
  104. // IPersistStream
  105. HRESULT CShellOcx::GetSizeMax(ULARGE_INTEGER *pcbSize)
  106. {
  107. // REVIEW: this is overly large, I believe E_NOTIMPL is a valid
  108. // return from this and it tells the container that we don't know how big we are.
  109. ULARGE_INTEGER cbMax = { 1028 * 8, 0 }; // isn't this overly large?
  110. *pcbSize = cbMax;
  111. return S_OK;
  112. }
  113. // IOleControl
  114. STDMETHODIMP CShellOcx::GetControlInfo(LPCONTROLINFO pCI)
  115. {
  116. return E_NOTIMPL; // for mnemonics
  117. }
  118. STDMETHODIMP CShellOcx::OnMnemonic(LPMSG pMsg)
  119. {
  120. return E_NOTIMPL; // for mnemonics
  121. }
  122. STDMETHODIMP CShellOcx::OnAmbientPropertyChange(DISPID dispid)
  123. {
  124. switch (dispid)
  125. {
  126. case DISPID_AMBIENT_USERMODE: // design mode vs run mode
  127. case DISPID_UNKNOWN:
  128. _nDesignMode = MODE_UNKNOWN;
  129. break;
  130. }
  131. return S_OK;
  132. }
  133. STDMETHODIMP CShellOcx::FreezeEvents(BOOL bFreeze)
  134. {
  135. _fEventsFrozen = bFreeze;
  136. return S_OK;
  137. }
  138. HRESULT CShellOcx::GetIDsOfNames(REFIID riid, OLECHAR **rgszNames, UINT cNames, LCID lcid, DISPID *rgdispid)
  139. {
  140. // This is gross, for some reason from VBScript in a page can not get "Document" through so try "Doc" and map
  141. HRESULT hres = CImpIDispatch::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);
  142. if (FAILED(hres) && (cNames == 1) && rgszNames)
  143. {
  144. OLECHAR const *c_pwszDocument = L"Document";
  145. if (StrCmpIW(*rgszNames, L"Doc") == 0)
  146. hres = CImpIDispatch::GetIDsOfNames(riid, (OLECHAR**)&c_pwszDocument, cNames, lcid, rgdispid);
  147. }
  148. return hres;
  149. }
  150. // ConnectionPointContainer
  151. CConnectionPoint* CShellOcx::_FindCConnectionPointNoRef(BOOL fdisp, REFIID iid)
  152. {
  153. CConnectionPoint* pccp;
  154. if (IsEqualIID(iid, EVENTIIDOFCONTROL(this)) ||
  155. (fdisp && IsEqualIID(iid, IID_IDispatch)))
  156. {
  157. pccp = &m_cpEvents;
  158. }
  159. else if (IsEqualIID(iid, IID_IPropertyNotifySink))
  160. {
  161. pccp = &m_cpPropNotify;
  162. }
  163. else
  164. {
  165. pccp = NULL;
  166. }
  167. return pccp;
  168. }
  169. STDMETHODIMP CShellOcx::EnumConnectionPoints(LPENUMCONNECTIONPOINTS * ppEnum)
  170. {
  171. return CreateInstance_IEnumConnectionPoints(ppEnum, 2,
  172. m_cpEvents.CastToIConnectionPoint(),
  173. m_cpPropNotify.CastToIConnectionPoint());
  174. }
  175. // IProvideClassInfo2
  176. STDMETHODIMP CShellOcx::GetClassInfo(LPTYPEINFO * ppTI)
  177. {
  178. if (!_pClassTypeInfo)
  179. GetTypeInfoFromLibId(LANGIDFROMLCID(g_lcidLocale),
  180. LIBID_SHDocVw, 1, 1, CLSIDOFOBJECT(this), &_pClassTypeInfo);
  181. if (_pClassTypeInfo)
  182. {
  183. _pClassTypeInfo->AddRef();
  184. *ppTI = _pClassTypeInfo;
  185. return S_OK;
  186. }
  187. ppTI = NULL;
  188. return E_FAIL;
  189. }
  190. // IProvideClassInfo2
  191. STDMETHODIMP CShellOcx::GetGUID(DWORD dwGuidKind, GUID *pGUID)
  192. {
  193. if (pGUID == NULL)
  194. return E_POINTER;
  195. if ( (dwGuidKind == GUIDKIND_DEFAULT_SOURCE_DISP_IID)
  196. && _pObjectInfo->piidEvents)
  197. {
  198. *pGUID = EVENTIIDOFCONTROL(this);
  199. return S_OK;
  200. }
  201. *pGUID = GUID_NULL;
  202. return E_FAIL;
  203. }
  204. // returns TRUE iff MODE_DESIGN
  205. BOOL CShellOcx::_IsDesignMode(void)
  206. {
  207. if (_nDesignMode == MODE_UNKNOWN)
  208. {
  209. VARIANT_BOOL fBool;
  210. if (_GetAmbientProperty(DISPID_AMBIENT_USERMODE, VT_BOOL, &fBool))
  211. {
  212. _nDesignMode = fBool ? MODE_FALSE : MODE_TRUE;
  213. }
  214. else
  215. _nDesignMode = MODE_FALSE;
  216. }
  217. return _nDesignMode == MODE_TRUE;
  218. }
  219. // this table is used for copying data around, and persisting properties.
  220. // basically, it contains the size of a given data type
  221. //
  222. const BYTE g_rgcbDataTypeSize[] = {
  223. 0, // VT_EMPTY = 0,
  224. 0, // VT_NULL = 1,
  225. sizeof(short), // VT_I2 = 2,
  226. sizeof(long), // VT_I4 = 3,
  227. sizeof(float), // VT_R4 = 4,
  228. sizeof(double), // VT_R8= 5,
  229. sizeof(CURRENCY), // VT_CY= 6,
  230. sizeof(DATE), // VT_DATE = 7,
  231. sizeof(BSTR), // VT_BSTR = 8,
  232. sizeof(IDispatch *), // VT_DISPATCH = 9,
  233. sizeof(SCODE), // VT_ERROR = 10,
  234. sizeof(VARIANT_BOOL), // VT_BOOL = 11,
  235. sizeof(VARIANT), // VT_VARIANT = 12,
  236. sizeof(IUnknown *), // VT_UNKNOWN = 13,
  237. };
  238. // returns the value of an ambient property
  239. //
  240. // Parameters:
  241. // DISPID - [in] property to get
  242. // VARTYPE - [in] type of desired data
  243. // void * - [out] where to put the data
  244. //
  245. // Output:
  246. // BOOL - FALSE means didn't work.
  247. //
  248. // Notes:
  249. //
  250. BOOL CShellOcx::_GetAmbientProperty(DISPID dispid, VARTYPE vt, void *pData)
  251. {
  252. // IE30's WebBrowser OC never requested ambient properties.
  253. // IE40's does and we're finding that apps implemented some of
  254. // the properties we care about incorrectly. Assume old classid
  255. // means this is an old app and fail. The code that calls this
  256. // is smart enough to deal with failure.
  257. //
  258. if (_pObjectInfo->pclsid == &CLSID_WebBrowser_V1)
  259. return FALSE;
  260. HRESULT hr = E_FAIL;
  261. if (!_pDispAmbient && _pcli)
  262. _pcli->QueryInterface(IID_PPV_ARG(IDispatch, &_pDispAmbient));
  263. if (_pDispAmbient)
  264. {
  265. DISPPARAMS dispparams = {0};
  266. VARIANT v;
  267. VariantInit(&v);
  268. hr = _pDispAmbient->Invoke(dispid, IID_NULL, 0, DISPATCH_PROPERTYGET, &dispparams, &v, NULL, NULL);
  269. if (SUCCEEDED(hr))
  270. {
  271. VARIANT vDest;
  272. VariantInit(&vDest);
  273. // we've got the variant, so now go an coerce it to the type
  274. // that the user wants.
  275. //
  276. hr = VariantChangeType(&vDest, &v, 0, vt);
  277. if (SUCCEEDED(hr))
  278. {
  279. // copy the data to where the user wants it
  280. //
  281. CopyMemory(pData, &vDest.lVal, g_rgcbDataTypeSize[vt]);
  282. VariantClear(&vDest);
  283. }
  284. VariantClear(&v);
  285. }
  286. }
  287. return SUCCEEDED(hr);
  288. }