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.

962 lines
31KB

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