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.

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