The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
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.

945 lines
31KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. //==============================================================================
  19. /*
  20. This file contains all the gubbins to create an ActiveX browser plugin that
  21. wraps your BrowserPluginComponent object.
  22. */
  23. //==============================================================================
  24. #if _MSC_VER
  25. //==============================================================================
  26. #include <olectl.h>
  27. #include <objsafe.h>
  28. #include <exdisp.h>
  29. #pragma warning (disable:4584)
  30. #include "../juce_browser_plugin.h"
  31. using namespace juce;
  32. #include "juce_BrowserPluginComponent.h"
  33. #ifndef JuceBrowserPlugin_ActiveXCLSID
  34. #error "For an activeX plugin, you need to define JuceBrowserPlugin_ActiveXCLSID in your BrowserPluginCharacteristics.h file!"
  35. #endif
  36. //==============================================================================
  37. #if JUCE_DEBUG
  38. static int numDOWID = 0, numJuceSO = 0;
  39. #endif
  40. #define log(a) DBG(a)
  41. // Cunning trick used to add functions to export list without messing about with .def files.
  42. #define EXPORTED_FUNCTION comment(linker, "/EXPORT:" __FUNCTION__ "=" __FUNCDNAME__)
  43. //==============================================================================
  44. static void juceVarToVariant (const var& v, VARIANT& dest);
  45. static var variantTojuceVar (const VARIANT& v);
  46. //==============================================================================
  47. // Takes care of the logic in invoking var methods from IDispatch callbacks.
  48. class IDispatchHelper
  49. {
  50. public:
  51. IDispatchHelper() {}
  52. String getStringFromDISPID (const DISPID hash) const
  53. {
  54. for (int i = identifierPool.size(); --i >= 0;)
  55. if (getHashFromString (identifierPool[i]) == hash)
  56. return identifierPool[i];
  57. return String::empty;
  58. }
  59. HRESULT doGetIDsOfNames (LPOLESTR* rgszNames, UINT cNames, DISPID* rgDispId)
  60. {
  61. for (unsigned int i = 0; i < cNames; ++i)
  62. rgDispId[i] = getHashFromString (identifierPool.getPooledString (String (rgszNames[i])));
  63. return S_OK;
  64. }
  65. HRESULT doInvoke (const var& v,
  66. DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams,
  67. VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr)
  68. {
  69. const Identifier memberId (getStringFromDISPID (dispIdMember));
  70. DynamicObject* const object = v.getDynamicObject();
  71. if (memberId.toString().isEmpty() || object == nullptr)
  72. return DISP_E_MEMBERNOTFOUND;
  73. if ((wFlags & DISPATCH_METHOD) != 0)
  74. {
  75. if (! object->hasMethod (memberId))
  76. return DISP_E_MEMBERNOTFOUND;
  77. const int numArgs = pDispParams == nullptr ? 0 : pDispParams->cArgs;
  78. var result;
  79. if (numArgs == 0)
  80. {
  81. result = v.call (memberId);
  82. }
  83. else
  84. {
  85. Array<var> args;
  86. for (int j = numArgs; --j >= 0;)
  87. args.add (variantTojuceVar (pDispParams->rgvarg[j]));
  88. result = v.invoke (memberId, numArgs == 0 ? 0 : args.getRawDataPointer(), numArgs);
  89. }
  90. if (pVarResult != nullptr)
  91. juceVarToVariant (result, *pVarResult);
  92. return S_OK;
  93. }
  94. else if ((wFlags & DISPATCH_PROPERTYGET) != 0)
  95. {
  96. if (! object->hasProperty (memberId))
  97. return DISP_E_MEMBERNOTFOUND;
  98. if (pVarResult != nullptr)
  99. {
  100. juceVarToVariant (object->getProperty (memberId), *pVarResult);
  101. return S_OK;
  102. }
  103. }
  104. else if ((wFlags & DISPATCH_PROPERTYPUT) != 0)
  105. {
  106. if (pDispParams != nullptr && pDispParams->cArgs > 0)
  107. {
  108. object->setProperty (memberId, variantTojuceVar (pDispParams->rgvarg[0]));
  109. return S_OK;
  110. }
  111. }
  112. return DISP_E_MEMBERNOTFOUND;
  113. }
  114. private:
  115. StringPool identifierPool;
  116. static DISPID getHashFromString (const String::CharPointerType& s) noexcept
  117. {
  118. return (DISPID) (pointer_sized_int) s.getAddress();
  119. }
  120. JUCE_DECLARE_NON_COPYABLE (IDispatchHelper);
  121. };
  122. //==============================================================================
  123. // Makes a var look like an IDispatch
  124. class IDispatchWrappingDynamicObject : public IDispatch
  125. {
  126. public:
  127. IDispatchWrappingDynamicObject (const var& object_)
  128. : object (object_),
  129. refCount (1)
  130. {
  131. DBG ("num Juce wrapper objs: " + String (++numJuceSO));
  132. }
  133. virtual ~IDispatchWrappingDynamicObject()
  134. {
  135. DBG ("num Juce wrapper objs: " + String (--numJuceSO));
  136. }
  137. HRESULT __stdcall QueryInterface (REFIID id, void __RPC_FAR* __RPC_FAR* result)
  138. {
  139. if (id == IID_IUnknown) { AddRef(); *result = (IUnknown*) this; return S_OK; }
  140. else if (id == IID_IDispatch) { AddRef(); *result = (IDispatch*) this; return S_OK; }
  141. *result = 0;
  142. return E_NOINTERFACE;
  143. }
  144. ULONG __stdcall AddRef() { return ++refCount; }
  145. ULONG __stdcall Release() { const int r = --refCount; if (r == 0) delete this; return r; }
  146. HRESULT __stdcall GetTypeInfoCount (UINT*) { return E_NOTIMPL; }
  147. HRESULT __stdcall GetTypeInfo (UINT, LCID, ITypeInfo**) { return E_NOTIMPL; }
  148. HRESULT __stdcall GetIDsOfNames (REFIID riid, LPOLESTR* rgszNames, UINT cNames,
  149. LCID lcid, DISPID* rgDispId)
  150. {
  151. return iDispatchHelper.doGetIDsOfNames (rgszNames, cNames, rgDispId);
  152. }
  153. HRESULT __stdcall Invoke (DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags,
  154. DISPPARAMS* pDispParams, VARIANT* pVarResult,
  155. EXCEPINFO* pExcepInfo, UINT* puArgErr)
  156. {
  157. return iDispatchHelper.doInvoke (object, dispIdMember, riid, lcid, wFlags, pDispParams,
  158. pVarResult, pExcepInfo, puArgErr);
  159. }
  160. private:
  161. //==============================================================================
  162. var object;
  163. int refCount;
  164. IDispatchHelper iDispatchHelper;
  165. JUCE_DECLARE_NON_COPYABLE (IDispatchWrappingDynamicObject);
  166. };
  167. //==============================================================================
  168. // Makes an IDispatch look like a var
  169. class DynamicObjectWrappingIDispatch : public DynamicObject
  170. {
  171. public:
  172. DynamicObjectWrappingIDispatch (IDispatch* const source_)
  173. : source (source_)
  174. {
  175. source->AddRef();
  176. log ("num IDispatch wrapper objs: " + String (++numDOWID));
  177. }
  178. ~DynamicObjectWrappingIDispatch()
  179. {
  180. source->Release();
  181. log ("num IDispatch wrapper objs: " + String (--numDOWID));
  182. }
  183. var getProperty (const Identifier& propertyName) const
  184. {
  185. const String nameCopy (propertyName.toString());
  186. LPCOLESTR name = nameCopy.toUTF16();
  187. DISPID id = 0;
  188. if (source->GetIDsOfNames (IID_NULL, (LPOLESTR*) &name, 1, 0, &id) == S_OK)
  189. {
  190. EXCEPINFO excepInfo;
  191. DISPPARAMS params;
  192. zerostruct (params);
  193. UINT argError;
  194. VARIANT result;
  195. zerostruct (result);
  196. if (source->Invoke (id, IID_NULL, 0, DISPATCH_PROPERTYGET,
  197. &params, &result, &excepInfo, &argError) == S_OK)
  198. {
  199. var v (variantTojuceVar (result));
  200. VariantClear (&result);
  201. return v;
  202. }
  203. }
  204. return var::null;
  205. }
  206. bool hasProperty (const Identifier& propertyName) const
  207. {
  208. const String nameCopy (propertyName.toString());
  209. LPCOLESTR name = nameCopy.toUTF16();
  210. DISPID id = 0;
  211. return source->GetIDsOfNames (IID_NULL, (LPOLESTR*) &name, 1, 0, &id) == S_OK;
  212. }
  213. void setProperty (const Identifier& propertyName, const var& newValue)
  214. {
  215. const String nameCopy (propertyName.toString());
  216. LPCOLESTR name = nameCopy.toUTF16();
  217. DISPID id = 0;
  218. if (source->GetIDsOfNames (IID_NULL, (LPOLESTR*) &name, 1, 0, &id) == S_OK)
  219. {
  220. VARIANT param;
  221. zerostruct (param);
  222. juceVarToVariant (newValue, param);
  223. DISPPARAMS dispParams;
  224. zerostruct (dispParams);
  225. dispParams.cArgs = 1;
  226. dispParams.rgvarg = &param;
  227. EXCEPINFO excepInfo;
  228. zerostruct (excepInfo);
  229. VARIANT result;
  230. zerostruct (result);
  231. UINT argError = 0;
  232. if (source->Invoke (id, IID_NULL, 0, DISPATCH_PROPERTYPUT,
  233. &dispParams, &result, &excepInfo, &argError) == S_OK)
  234. {
  235. VariantClear (&result);
  236. }
  237. VariantClear (&param);
  238. }
  239. }
  240. void removeProperty (const Identifier& propertyName)
  241. {
  242. setProperty (propertyName, var::null);
  243. }
  244. bool hasMethod (const Identifier& methodName) const
  245. {
  246. const String nameCopy (methodName.toString());
  247. LPCOLESTR name = nameCopy.toUTF16();
  248. DISPID id = 0;
  249. return source->GetIDsOfNames (IID_NULL, (LPOLESTR*) &name, 1, 0, &id) == S_OK;
  250. }
  251. var invokeMethod (const Identifier& methodName, const var* parameters, int numParameters)
  252. {
  253. var returnValue;
  254. const String nameCopy (methodName.toString());
  255. LPCOLESTR name = nameCopy.toUTF16();
  256. DISPID id = 0;
  257. if (source->GetIDsOfNames (IID_NULL, (LPOLESTR*) &name, 1, 0, &id) == S_OK)
  258. {
  259. HeapBlock <VARIANT> params;
  260. params.calloc (numParameters + 1);
  261. for (int i = 0; i < numParameters; ++i)
  262. juceVarToVariant (parameters[(numParameters - 1) - i], params[i]);
  263. DISPPARAMS dispParams;
  264. zerostruct (dispParams);
  265. dispParams.cArgs = numParameters;
  266. dispParams.rgvarg = params;
  267. EXCEPINFO excepInfo;
  268. zerostruct (excepInfo);
  269. VARIANT result;
  270. zerostruct (result);
  271. UINT argError = 0;
  272. if (source->Invoke (id, IID_NULL, 0, DISPATCH_METHOD,
  273. &dispParams, &result, &excepInfo, &argError) == S_OK)
  274. {
  275. returnValue = variantTojuceVar (result);
  276. VariantClear (&result);
  277. }
  278. }
  279. return returnValue;
  280. }
  281. private:
  282. IDispatch* const source;
  283. JUCE_DECLARE_NON_COPYABLE (DynamicObjectWrappingIDispatch);
  284. };
  285. //==============================================================================
  286. void juceVarToVariant (const var& v, VARIANT& dest)
  287. {
  288. if (v.isVoid())
  289. {
  290. dest.vt = VT_EMPTY;
  291. }
  292. else if (v.isInt())
  293. {
  294. dest.vt = VT_INT;
  295. dest.intVal = (int) v;
  296. }
  297. else if (v.isBool())
  298. {
  299. dest.vt = VT_BOOL;
  300. dest.boolVal = (int) v;
  301. }
  302. else if (v.isDouble())
  303. {
  304. dest.vt = VT_R8;
  305. dest.dblVal = (double) v;
  306. }
  307. else if (v.isString())
  308. {
  309. dest.vt = VT_BSTR;
  310. dest.bstrVal = SysAllocString (v.toString().toUTF16());
  311. }
  312. else if (v.getDynamicObject() != nullptr)
  313. {
  314. dest.vt = VT_DISPATCH;
  315. dest.pdispVal = new IDispatchWrappingDynamicObject (v);
  316. }
  317. else if (v.isMethod())
  318. {
  319. dest.vt = VT_EMPTY;
  320. }
  321. }
  322. var variantTojuceVar (const VARIANT& v)
  323. {
  324. if ((v.vt & VT_ARRAY) != 0)
  325. {
  326. //xxx
  327. }
  328. else
  329. {
  330. switch (v.vt & ~VT_BYREF)
  331. {
  332. case VT_VOID:
  333. case VT_EMPTY: return var::null;
  334. case VT_I1: return var ((int) v.cVal);
  335. case VT_I2: return var ((int) v.iVal);
  336. case VT_I4: return var ((int) v.lVal);
  337. case VT_I8: return var (String (v.llVal));
  338. case VT_UI1: return var ((int) v.bVal);
  339. case VT_UI2: return var ((int) v.uiVal);
  340. case VT_UI4: return var ((int) v.ulVal);
  341. case VT_UI8: return var (String (v.ullVal));
  342. case VT_INT: return var ((int) v.intVal);
  343. case VT_UINT: return var ((int) v.uintVal);
  344. case VT_R4: return var ((double) v.fltVal);
  345. case VT_R8: return var ((double) v.dblVal);
  346. case VT_BSTR: return var (String (v.bstrVal));
  347. case VT_BOOL: return var (v.boolVal ? true : false);
  348. case VT_DISPATCH: return var (new DynamicObjectWrappingIDispatch (v.pdispVal));
  349. default: break;
  350. }
  351. }
  352. return var::null;
  353. }
  354. //==============================================================================
  355. // This acts as the embedded HWND
  356. class AXBrowserPluginHolderComponent : public Component
  357. {
  358. public:
  359. AXBrowserPluginHolderComponent()
  360. : parentHWND (0),
  361. browser (nullptr)
  362. {
  363. setOpaque (true);
  364. setWantsKeyboardFocus (false);
  365. addAndMakeVisible (child = createBrowserPlugin());
  366. jassert (child != nullptr); // You have to create one of these!
  367. }
  368. ~AXBrowserPluginHolderComponent()
  369. {
  370. setWindow (nullptr);
  371. child = nullptr;
  372. }
  373. //==============================================================================
  374. void paint (Graphics& g)
  375. {
  376. if (child == nullptr || ! child->isOpaque())
  377. g.fillAll (Colours::white);
  378. }
  379. void resized()
  380. {
  381. if (child != nullptr)
  382. child->setBounds (0, 0, getWidth(), getHeight());
  383. }
  384. var getObject() { return child->getJavascriptObject(); }
  385. void setWindow (IOleInPlaceSite* site)
  386. {
  387. if (browser != nullptr)
  388. {
  389. browser->Release();
  390. browser = nullptr;
  391. }
  392. HWND newHWND = 0;
  393. if (site != nullptr)
  394. {
  395. site->GetWindow (&newHWND);
  396. IServiceProvider* sp = nullptr;
  397. site->QueryInterface (IID_IServiceProvider, (void**) &sp);
  398. if (sp != nullptr)
  399. {
  400. sp->QueryService (IID_IWebBrowserApp, IID_IWebBrowser2, (void**) &browser);
  401. sp->Release();
  402. }
  403. }
  404. if (parentHWND != newHWND)
  405. {
  406. removeFromDesktop();
  407. setVisible (false);
  408. parentHWND = newHWND;
  409. if (parentHWND != 0)
  410. {
  411. addToDesktop (0);
  412. HWND ourHWND = (HWND) getWindowHandle();
  413. SetParent (ourHWND, parentHWND);
  414. DWORD val = GetWindowLong (ourHWND, GWL_STYLE);
  415. val = (val & ~WS_POPUP) | WS_CHILD;
  416. SetWindowLong (ourHWND, GWL_STYLE, val);
  417. setVisible (true);
  418. }
  419. }
  420. if (site != nullptr)
  421. site->OnInPlaceActivate();
  422. }
  423. String getBrowserURL() const
  424. {
  425. if (browser == nullptr)
  426. return String::empty;
  427. BSTR url = nullptr;
  428. browser->get_LocationURL (&url);
  429. return URL::removeEscapeChars (url);
  430. }
  431. private:
  432. //==============================================================================
  433. ScopedPointer<BrowserPluginComponent> child;
  434. HWND parentHWND;
  435. IWebBrowser2* browser;
  436. JUCE_DECLARE_NON_COPYABLE (AXBrowserPluginHolderComponent);
  437. };
  438. //==============================================================================
  439. extern String browserVersionDesc;
  440. static String getExePath()
  441. {
  442. TCHAR moduleFile [2048] = { 0 };
  443. GetModuleFileName (0, moduleFile, 2048);
  444. return moduleFile;
  445. }
  446. static String getExeVersion (const String& exeFileName, const String& fieldName)
  447. {
  448. DWORD pointlessWin32Variable;
  449. DWORD size = GetFileVersionInfoSize (exeFileName.toUTF16(), &pointlessWin32Variable);
  450. if (size > 0)
  451. {
  452. HeapBlock <char> exeInfo;
  453. exeInfo.calloc (size);
  454. if (GetFileVersionInfo (exeFileName.toUTF16(), 0, size, exeInfo))
  455. {
  456. TCHAR* result = nullptr;
  457. unsigned int resultLen = 0;
  458. // try the 1200 codepage (Unicode)
  459. String queryStr ("\\StringFileInfo\\040904B0\\" + fieldName);
  460. if (! VerQueryValue (exeInfo, (LPTSTR) queryStr.toUTF16().getAddress(), (void**) &result, &resultLen))
  461. {
  462. // try the 1252 codepage (Windows Multilingual)
  463. queryStr = "\\StringFileInfo\\040904E4\\" + fieldName;
  464. VerQueryValue (exeInfo, (LPTSTR) queryStr.toUTF16().getAddress(), (void**) &result, &resultLen);
  465. }
  466. return String (result, resultLen);
  467. }
  468. }
  469. return String::empty;
  470. }
  471. static int numActivePlugins = 0;
  472. class JuceActiveXObject : public IUnknown,
  473. public IDispatch,
  474. public IObjectWithSite,
  475. public IObjectSafety,
  476. public IOleInPlaceObject
  477. {
  478. public:
  479. JuceActiveXObject()
  480. : site (nullptr), refCount (0)
  481. {
  482. log ("JuceActiveXObject");
  483. }
  484. ~JuceActiveXObject()
  485. {
  486. log ("~JuceActiveXObject");
  487. holderComp = nullptr;
  488. }
  489. HRESULT __stdcall QueryInterface (REFIID id, void __RPC_FAR* __RPC_FAR* result)
  490. {
  491. if (id == IID_IUnknown) { AddRef(); *result = (IUnknown*) this; return S_OK; }
  492. else if (id == IID_IDispatch) { AddRef(); *result = (IDispatch*) this; return S_OK; }
  493. else if (id == IID_IObjectWithSite) { AddRef(); *result = (IObjectWithSite*) this; return S_OK; }
  494. else if (id == IID_IObjectSafety) { AddRef(); *result = (IObjectSafety*) this; return S_OK; }
  495. else if (id == IID_IOleInPlaceObject) { AddRef(); *result = (IOleInPlaceObject*) this; return S_OK; }
  496. else if (id == IID_IOleWindow) { AddRef(); *result = (IOleWindow*) (IOleInPlaceObject*) this; return S_OK; }
  497. *result = 0;
  498. return E_NOINTERFACE;
  499. }
  500. ULONG __stdcall AddRef() { return ++refCount; }
  501. ULONG __stdcall Release() { const int r = --refCount; if (r == 0) delete this; return r; }
  502. HRESULT __stdcall GetTypeInfoCount (UINT* pctinfo) { return E_NOTIMPL; }
  503. HRESULT __stdcall GetTypeInfo (UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) { return E_NOTIMPL; }
  504. HRESULT __stdcall GetIDsOfNames (REFIID riid, LPOLESTR* rgszNames, UINT cNames,
  505. LCID lcid, DISPID* rgDispId)
  506. {
  507. return iDispatchHelper.doGetIDsOfNames (rgszNames, cNames, rgDispId);
  508. }
  509. HRESULT __stdcall Invoke (DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags,
  510. DISPPARAMS* pDispParams, VARIANT* pVarResult,
  511. EXCEPINFO* pExcepInfo, UINT* puArgErr)
  512. {
  513. if (holderComp == nullptr)
  514. return DISP_E_MEMBERNOTFOUND;
  515. return iDispatchHelper.doInvoke (holderComp->getObject(),
  516. dispIdMember, riid, lcid, wFlags, pDispParams,
  517. pVarResult, pExcepInfo, puArgErr);
  518. }
  519. HRESULT __stdcall SetSite (IUnknown* newSite)
  520. {
  521. if (newSite != site)
  522. {
  523. if (site != nullptr)
  524. site->Release();
  525. site = newSite;
  526. if (site != nullptr)
  527. {
  528. site->AddRef();
  529. IOleInPlaceSite* inPlaceSite = nullptr;
  530. site->QueryInterface (IID_IOleInPlaceSite, (void**) &inPlaceSite);
  531. if (inPlaceSite != nullptr)
  532. {
  533. createHolderComp();
  534. holderComp->setWindow (inPlaceSite);
  535. inPlaceSite->Release();
  536. }
  537. else
  538. {
  539. deleteHolderComp();
  540. }
  541. }
  542. else
  543. {
  544. deleteHolderComp();
  545. }
  546. }
  547. return S_OK;
  548. }
  549. void createHolderComp()
  550. {
  551. if (holderComp == nullptr)
  552. {
  553. if (numActivePlugins++ == 0)
  554. {
  555. log ("initialiseJuce_GUI()");
  556. initialiseJuce_GUI();
  557. browserVersionDesc = "Internet Explorer " + getExeVersion (getExePath(), "FileVersion");
  558. }
  559. holderComp = new AXBrowserPluginHolderComponent();
  560. }
  561. }
  562. void deleteHolderComp()
  563. {
  564. if (holderComp != nullptr)
  565. {
  566. holderComp = nullptr;
  567. if (--numActivePlugins == 0)
  568. {
  569. log ("shutdownJuce_GUI()");
  570. shutdownJuce_GUI();
  571. }
  572. }
  573. }
  574. HRESULT __stdcall GetSite (REFIID riid, void **ppvSite)
  575. {
  576. *ppvSite = site;
  577. return S_OK;
  578. }
  579. //==============================================================================
  580. HRESULT __stdcall SetObjectRects (LPCRECT r, LPCRECT c)
  581. {
  582. if (holderComp != nullptr)
  583. holderComp->setBounds (r->left, r->top, r->right - r->left, r->bottom - r->top);
  584. return S_OK;
  585. }
  586. HRESULT __stdcall GetWindow (HWND* phwnd)
  587. {
  588. if (holderComp == nullptr)
  589. return E_NOTIMPL;
  590. *phwnd = (HWND) holderComp->getWindowHandle();
  591. return S_OK;
  592. }
  593. //==============================================================================
  594. HRESULT __stdcall ContextSensitiveHelp (BOOL fEnterMode) { return E_NOTIMPL; }
  595. HRESULT __stdcall InPlaceDeactivate() { return E_NOTIMPL; }
  596. HRESULT __stdcall UIDeactivate() { return E_NOTIMPL; }
  597. HRESULT __stdcall ReactivateAndUndo() { return E_NOTIMPL; }
  598. //==============================================================================
  599. HRESULT __stdcall GetInterfaceSafetyOptions (REFIID riid, DWORD *pdwSupportedOptions, DWORD *pdwEnabledOptions)
  600. {
  601. *pdwSupportedOptions = *pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA;
  602. return S_OK;
  603. }
  604. HRESULT __stdcall SetInterfaceSafetyOptions (REFIID, DWORD, DWORD) { return S_OK; }
  605. private:
  606. IUnknown* site;
  607. int refCount;
  608. ScopedPointer<AXBrowserPluginHolderComponent> holderComp;
  609. IDispatchHelper iDispatchHelper;
  610. JUCE_DECLARE_NON_COPYABLE (JuceActiveXObject);
  611. };
  612. //==============================================================================
  613. class JuceActiveXObjectFactory : public IUnknown,
  614. public IClassFactory
  615. {
  616. public:
  617. JuceActiveXObjectFactory() : refCount (0) {}
  618. HRESULT __stdcall QueryInterface (REFIID id, void __RPC_FAR* __RPC_FAR* result)
  619. {
  620. if (id == IID_IUnknown) { AddRef(); *result = (IUnknown*) this; return S_OK; }
  621. else if (id == IID_IClassFactory) { AddRef(); *result = (IClassFactory*) this; return S_OK; }
  622. *result = nullptr;
  623. return E_NOINTERFACE;
  624. }
  625. ULONG __stdcall AddRef() { return ++refCount; }
  626. ULONG __stdcall Release() { const int r = --refCount; if (r == 0) delete this; return r; }
  627. HRESULT __stdcall CreateInstance (IUnknown* pUnkOuter, REFIID riid, void** ppvObject)
  628. {
  629. *ppvObject = nullptr;
  630. if (pUnkOuter != nullptr && riid != IID_IUnknown)
  631. return CLASS_E_NOAGGREGATION;
  632. JuceActiveXObject* ax = new JuceActiveXObject();
  633. return ax->QueryInterface (riid, ppvObject);
  634. }
  635. HRESULT __stdcall LockServer (BOOL /*fLock*/) { return S_OK; }
  636. private:
  637. int refCount;
  638. JUCE_DECLARE_NON_COPYABLE (JuceActiveXObjectFactory);
  639. };
  640. //==============================================================================
  641. String getActiveXBrowserURL (const BrowserPluginComponent* comp)
  642. {
  643. AXBrowserPluginHolderComponent* const ax = dynamic_cast <AXBrowserPluginHolderComponent*> (comp->getParentComponent());
  644. return ax != nullptr ? ax->getBrowserURL() : String::empty;
  645. }
  646. //==============================================================================
  647. extern "C" BOOL WINAPI DllMain (HANDLE instance, DWORD reason, LPVOID)
  648. {
  649. #pragma EXPORTED_FUNCTION
  650. switch (reason)
  651. {
  652. case DLL_PROCESS_ATTACH:
  653. log ("DLL_PROCESS_ATTACH");
  654. Process::setCurrentModuleInstanceHandle (instance);
  655. break;
  656. case DLL_PROCESS_DETACH:
  657. log ("DLL_PROCESS_DETACH");
  658. browserVersionDesc = String::empty;
  659. // IE has a tendency to leak our objects, so although none of this should be
  660. // necessary, it's best to make sure..
  661. jassert (numActivePlugins == 0);
  662. shutdownJuce_GUI();
  663. break;
  664. default:
  665. break;
  666. }
  667. return TRUE;
  668. }
  669. static String CLSIDToJuceString (REFCLSID clsid)
  670. {
  671. LPWSTR s = nullptr;
  672. StringFromIID (clsid, &s);
  673. if (s == nullptr)
  674. return String::empty;
  675. const String result (s);
  676. LPMALLOC malloc;
  677. CoGetMalloc (1, &malloc);
  678. if (malloc != nullptr)
  679. {
  680. malloc->Free (s);
  681. malloc->Release();
  682. }
  683. return result.removeCharacters ("{}").trim();
  684. }
  685. STDAPI DllGetClassObject (REFCLSID rclsid, REFIID riid, LPVOID* ppv)
  686. {
  687. #pragma EXPORTED_FUNCTION
  688. *ppv = nullptr;
  689. if (CLSIDToJuceString (rclsid).equalsIgnoreCase (String (JuceBrowserPlugin_ActiveXCLSID)))
  690. {
  691. JuceActiveXObjectFactory* afx = new JuceActiveXObjectFactory();
  692. if (afx->QueryInterface (riid, ppv) == S_OK)
  693. return S_OK;
  694. delete afx;
  695. }
  696. return CLASS_E_CLASSNOTAVAILABLE;
  697. }
  698. STDAPI DllCanUnloadNow()
  699. {
  700. #pragma EXPORTED_FUNCTION
  701. return S_OK;
  702. }
  703. //==============================================================================
  704. static String makeLegalRegistryName (const String& s)
  705. {
  706. return s.retainCharacters ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.");
  707. }
  708. static HRESULT doRegistration (const bool unregister)
  709. {
  710. const String company (makeLegalRegistryName (JuceBrowserPlugin_Company));
  711. const String plugin (makeLegalRegistryName (JuceBrowserPlugin_Name));
  712. const String clsID ("{" + String (JuceBrowserPlugin_ActiveXCLSID).toUpperCase() + "}");
  713. const String root ("HKEY_CLASSES_ROOT\\");
  714. const String companyDotPlugin (company + "." + plugin);
  715. const String companyDotPluginCur (companyDotPlugin + ".1");
  716. const String clsIDRoot (root + "CLSID\\" + clsID + "\\");
  717. const String dllPath (File::getSpecialLocation (File::currentApplicationFile).getFullPathName());
  718. StringPairArray settings;
  719. settings.set (root + companyDotPluginCur + "\\", JuceBrowserPlugin_Name);
  720. settings.set (root + companyDotPluginCur + "\\CLSID\\", clsID);
  721. settings.set (root + companyDotPlugin + "\\", JuceBrowserPlugin_Name);
  722. settings.set (root + companyDotPlugin + "\\CLSID\\", clsID);
  723. settings.set (root + companyDotPlugin + "\\CurVer\\", companyDotPluginCur);
  724. settings.set (clsIDRoot, JuceBrowserPlugin_Name);
  725. settings.set (clsIDRoot + "Implemented Categories\\{7DD95801-9882-11CF-9FA9-00AA006C42C4}\\", String::empty);
  726. settings.set (clsIDRoot + "Implemented Categories\\{7DD95802-9882-11CF-9FA9-00AA006C42C4}\\", String::empty);
  727. settings.set (clsIDRoot + "ProgID\\", companyDotPluginCur);
  728. settings.set (clsIDRoot + "VersionIndependentProgID\\", companyDotPlugin);
  729. settings.set (clsIDRoot + "Programmable\\", String::empty);
  730. settings.set (clsIDRoot + "InProcServer32\\", dllPath);
  731. settings.set (clsIDRoot + "InProcServer32\\ThreadingModel", "Apartment");
  732. settings.set (clsIDRoot + "Control\\", String::empty);
  733. settings.set (clsIDRoot + "Insertable\\", String::empty);
  734. settings.set (clsIDRoot + "ToolboxBitmap32\\", dllPath + ", 101");
  735. settings.set (clsIDRoot + "TypeLib\\", "");
  736. settings.set (clsIDRoot + "Version\\", JuceBrowserPlugin_Version);
  737. if (unregister)
  738. {
  739. for (int i = 0; i < settings.getAllKeys().size(); ++i)
  740. WindowsRegistry::deleteValue (settings.getAllKeys()[i]);
  741. WindowsRegistry::deleteKey (root + companyDotPluginCur);
  742. WindowsRegistry::deleteKey (root + companyDotPlugin);
  743. WindowsRegistry::deleteKey (clsIDRoot);
  744. if (WindowsRegistry::valueExists (clsIDRoot + "InProcServer32"))
  745. return SELFREG_E_CLASS;
  746. }
  747. else
  748. {
  749. WindowsRegistry::deleteKey (clsIDRoot);
  750. for (int i = 0; i < settings.getAllKeys().size(); ++i)
  751. WindowsRegistry::setValue (settings.getAllKeys()[i],
  752. settings [settings.getAllKeys()[i]]);
  753. // check whether the registration actually worked - if not, we probably don't have
  754. // enough privileges to write to the registry..
  755. if (WindowsRegistry::getValue (clsIDRoot + "InProcServer32\\") != dllPath)
  756. return SELFREG_E_CLASS;
  757. }
  758. return S_OK;
  759. }
  760. STDAPI DllRegisterServer()
  761. {
  762. #pragma EXPORTED_FUNCTION
  763. return doRegistration (false);
  764. }
  765. STDAPI DllUnregisterServer()
  766. {
  767. #pragma EXPORTED_FUNCTION
  768. return doRegistration (true);
  769. }
  770. #endif