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.

944 lines
30KB

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