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.

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