Audio plugin host https://kx.studio/carla
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.

1000 lines
33KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE 6 technical preview.
  4. Copyright (c) 2017 - ROLI Ltd.
  5. You may use this code under the terms of the GPL v3
  6. (see www.gnu.org/licenses).
  7. For this technical preview, this file is not subject to commercial licensing.
  8. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  9. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  10. DISCLAIMED.
  11. ==============================================================================
  12. */
  13. namespace juce
  14. {
  15. struct InternalWebViewType
  16. {
  17. InternalWebViewType() {}
  18. virtual ~InternalWebViewType() {}
  19. virtual void createBrowser() = 0;
  20. virtual bool hasBrowserBeenCreated() = 0;
  21. virtual void goToURL (const String&, const StringArray*, const MemoryBlock*) = 0;
  22. virtual void stop() = 0;
  23. virtual void goBack() = 0;
  24. virtual void goForward() = 0;
  25. virtual void refresh() = 0;
  26. virtual void focusGained() {}
  27. virtual void setWebViewSize (int, int) = 0;
  28. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (InternalWebViewType)
  29. };
  30. #if JUCE_MINGW
  31. JUCE_DECLARE_UUID_GETTER (IOleClientSite, "00000118-0000-0000-c000-000000000046")
  32. JUCE_DECLARE_UUID_GETTER (IDispatch, "00020400-0000-0000-c000-000000000046")
  33. #ifndef WebBrowser
  34. class WebBrowser;
  35. #endif
  36. #endif
  37. JUCE_DECLARE_UUID_GETTER (DWebBrowserEvents2, "34A715A0-6587-11D0-924A-0020AFC7AC4D")
  38. JUCE_DECLARE_UUID_GETTER (IConnectionPointContainer, "B196B284-BAB4-101A-B69C-00AA00341D07")
  39. JUCE_DECLARE_UUID_GETTER (IWebBrowser2, "D30C1661-CDAF-11D0-8A3E-00C04FC9E26E")
  40. JUCE_DECLARE_UUID_GETTER (WebBrowser, "8856F961-340A-11D0-A96B-00C04FD705A2")
  41. //==============================================================================
  42. class Win32WebView : public InternalWebViewType,
  43. public ActiveXControlComponent
  44. {
  45. public:
  46. Win32WebView (WebBrowserComponent& owner)
  47. {
  48. owner.addAndMakeVisible (this);
  49. }
  50. ~Win32WebView() override
  51. {
  52. if (connectionPoint != nullptr)
  53. connectionPoint->Unadvise (adviseCookie);
  54. if (browser != nullptr)
  55. browser->Release();
  56. }
  57. void createBrowser() override
  58. {
  59. auto webCLSID = __uuidof (WebBrowser);
  60. createControl (&webCLSID);
  61. auto iidWebBrowser2 = __uuidof (IWebBrowser2);
  62. auto iidConnectionPointContainer = __uuidof (IConnectionPointContainer);
  63. browser = (IWebBrowser2*) queryInterface (&iidWebBrowser2);
  64. if (auto connectionPointContainer = (IConnectionPointContainer*) queryInterface (&iidConnectionPointContainer))
  65. {
  66. connectionPointContainer->FindConnectionPoint (__uuidof (DWebBrowserEvents2), &connectionPoint);
  67. if (connectionPoint != nullptr)
  68. {
  69. auto* owner = dynamic_cast<WebBrowserComponent*> (Component::getParentComponent());
  70. jassert (owner != nullptr);
  71. auto handler = new EventHandler (*owner);
  72. connectionPoint->Advise (handler, &adviseCookie);
  73. handler->Release();
  74. }
  75. }
  76. }
  77. bool hasBrowserBeenCreated() override
  78. {
  79. return browser != nullptr;
  80. }
  81. void goToURL (const String& url, const StringArray* headers, const MemoryBlock* postData) override
  82. {
  83. if (browser != nullptr)
  84. {
  85. VARIANT headerFlags, frame, postDataVar, headersVar; // (_variant_t isn't available in all compilers)
  86. VariantInit (&headerFlags);
  87. VariantInit (&frame);
  88. VariantInit (&postDataVar);
  89. VariantInit (&headersVar);
  90. if (headers != nullptr)
  91. {
  92. V_VT (&headersVar) = VT_BSTR;
  93. V_BSTR (&headersVar) = SysAllocString ((const OLECHAR*) headers->joinIntoString ("\r\n").toWideCharPointer());
  94. }
  95. if (postData != nullptr && postData->getSize() > 0)
  96. {
  97. auto sa = SafeArrayCreateVector (VT_UI1, 0, (ULONG) postData->getSize());
  98. if (sa != nullptr)
  99. {
  100. void* data = nullptr;
  101. SafeArrayAccessData (sa, &data);
  102. jassert (data != nullptr);
  103. if (data != nullptr)
  104. {
  105. postData->copyTo (data, 0, postData->getSize());
  106. SafeArrayUnaccessData (sa);
  107. VARIANT postDataVar2;
  108. VariantInit (&postDataVar2);
  109. V_VT (&postDataVar2) = VT_ARRAY | VT_UI1;
  110. V_ARRAY (&postDataVar2) = sa;
  111. sa = nullptr;
  112. postDataVar = postDataVar2;
  113. }
  114. else
  115. {
  116. SafeArrayDestroy (sa);
  117. }
  118. }
  119. }
  120. auto urlBSTR = SysAllocString ((const OLECHAR*) url.toWideCharPointer());
  121. browser->Navigate (urlBSTR, &headerFlags, &frame, &postDataVar, &headersVar);
  122. SysFreeString (urlBSTR);
  123. VariantClear (&headerFlags);
  124. VariantClear (&frame);
  125. VariantClear (&postDataVar);
  126. VariantClear (&headersVar);
  127. }
  128. }
  129. void stop() override
  130. {
  131. if (browser != nullptr)
  132. browser->Stop();
  133. }
  134. void goBack() override
  135. {
  136. if (browser != nullptr)
  137. browser->GoBack();
  138. }
  139. void goForward() override
  140. {
  141. if (browser != nullptr)
  142. browser->GoForward();
  143. }
  144. void refresh() override
  145. {
  146. if (browser != nullptr)
  147. browser->Refresh();
  148. }
  149. void focusGained() override
  150. {
  151. auto iidOleObject = __uuidof (IOleObject);
  152. auto iidOleWindow = __uuidof (IOleWindow);
  153. if (auto oleObject = (IOleObject*) queryInterface (&iidOleObject))
  154. {
  155. if (auto oleWindow = (IOleWindow*) queryInterface (&iidOleWindow))
  156. {
  157. IOleClientSite* oleClientSite = nullptr;
  158. if (SUCCEEDED (oleObject->GetClientSite (&oleClientSite)))
  159. {
  160. HWND hwnd;
  161. oleWindow->GetWindow (&hwnd);
  162. oleObject->DoVerb (OLEIVERB_UIACTIVATE, nullptr, oleClientSite, 0, hwnd, nullptr);
  163. oleClientSite->Release();
  164. }
  165. oleWindow->Release();
  166. }
  167. oleObject->Release();
  168. }
  169. }
  170. void setWebViewSize (int width, int height) override
  171. {
  172. setSize (width, height);
  173. }
  174. private:
  175. IWebBrowser2* browser = nullptr;
  176. IConnectionPoint* connectionPoint = nullptr;
  177. DWORD adviseCookie = 0;
  178. //==============================================================================
  179. struct EventHandler : public ComBaseClassHelper<IDispatch>,
  180. public ComponentMovementWatcher
  181. {
  182. EventHandler (WebBrowserComponent& w) : ComponentMovementWatcher (&w), owner (w) {}
  183. JUCE_COMRESULT GetTypeInfoCount (UINT*) override { return E_NOTIMPL; }
  184. JUCE_COMRESULT GetTypeInfo (UINT, LCID, ITypeInfo**) override { return E_NOTIMPL; }
  185. JUCE_COMRESULT GetIDsOfNames (REFIID, LPOLESTR*, UINT, LCID, DISPID*) override { return E_NOTIMPL; }
  186. JUCE_COMRESULT Invoke (DISPID dispIdMember, REFIID /*riid*/, LCID /*lcid*/, WORD /*wFlags*/, DISPPARAMS* pDispParams,
  187. VARIANT* /*pVarResult*/, EXCEPINFO* /*pExcepInfo*/, UINT* /*puArgErr*/) override
  188. {
  189. if (dispIdMember == DISPID_BEFORENAVIGATE2)
  190. {
  191. *pDispParams->rgvarg->pboolVal
  192. = owner.pageAboutToLoad (getStringFromVariant (pDispParams->rgvarg[5].pvarVal)) ? VARIANT_FALSE
  193. : VARIANT_TRUE;
  194. return S_OK;
  195. }
  196. if (dispIdMember == 273 /*DISPID_NEWWINDOW3*/)
  197. {
  198. owner.newWindowAttemptingToLoad (pDispParams->rgvarg[0].bstrVal);
  199. *pDispParams->rgvarg[3].pboolVal = VARIANT_TRUE;
  200. return S_OK;
  201. }
  202. if (dispIdMember == DISPID_DOCUMENTCOMPLETE)
  203. {
  204. owner.pageFinishedLoading (getStringFromVariant (pDispParams->rgvarg[0].pvarVal));
  205. return S_OK;
  206. }
  207. if (dispIdMember == 271 /*DISPID_NAVIGATEERROR*/)
  208. {
  209. int statusCode = pDispParams->rgvarg[1].pvarVal->intVal;
  210. *pDispParams->rgvarg[0].pboolVal = VARIANT_FALSE;
  211. // IWebBrowser2 also reports http status codes here, we need
  212. // report only network errors
  213. if (statusCode < 0)
  214. {
  215. LPTSTR messageBuffer = nullptr;
  216. auto size = FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
  217. nullptr, statusCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  218. (LPTSTR) &messageBuffer, 0, nullptr);
  219. String message (messageBuffer, size);
  220. LocalFree (messageBuffer);
  221. if (! owner.pageLoadHadNetworkError (message))
  222. *pDispParams->rgvarg[0].pboolVal = VARIANT_TRUE;
  223. }
  224. return S_OK;
  225. }
  226. if (dispIdMember == 263 /*DISPID_WINDOWCLOSING*/)
  227. {
  228. owner.windowCloseRequest();
  229. // setting this bool tells the browser to ignore the event - we'll handle it.
  230. if (pDispParams->cArgs > 0 && pDispParams->rgvarg[0].vt == (VT_BYREF | VT_BOOL))
  231. *pDispParams->rgvarg[0].pboolVal = VARIANT_TRUE;
  232. return S_OK;
  233. }
  234. return E_NOTIMPL;
  235. }
  236. void componentMovedOrResized (bool, bool) override {}
  237. void componentPeerChanged() override {}
  238. void componentVisibilityChanged() override { owner.visibilityChanged(); }
  239. private:
  240. WebBrowserComponent& owner;
  241. static String getStringFromVariant (VARIANT* v)
  242. {
  243. return (v->vt & VT_BYREF) != 0 ? *v->pbstrVal
  244. : v->bstrVal;
  245. }
  246. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (EventHandler)
  247. };
  248. };
  249. #if JUCE_USE_WINRT_WEBVIEW
  250. extern RTL_OSVERSIONINFOW getWindowsVersionInfo();
  251. using namespace Microsoft::WRL;
  252. using namespace ABI::Windows::Foundation;
  253. using namespace ABI::Windows::Storage::Streams;
  254. using namespace ABI::Windows::Web;
  255. using namespace ABI::Windows::Web::UI;
  256. using namespace ABI::Windows::Web::UI::Interop;
  257. using namespace ABI::Windows::Web::Http;
  258. using namespace ABI::Windows::Web::Http::Headers;
  259. //==============================================================================
  260. class WinRTWebView : public InternalWebViewType,
  261. public Component,
  262. public ComponentMovementWatcher
  263. {
  264. public:
  265. WinRTWebView (WebBrowserComponent& o)
  266. : ComponentMovementWatcher (&o),
  267. owner (o)
  268. {
  269. if (! WinRTWrapper::getInstance()->isInitialised())
  270. throw std::runtime_error ("Failed to initialise the WinRT wrapper");
  271. if (! createWebViewProcess())
  272. throw std::runtime_error ("Failed to create the WebViewControlProcess");
  273. owner.addAndMakeVisible (this);
  274. }
  275. ~WinRTWebView() override
  276. {
  277. if (webViewControl != nullptr)
  278. webViewControl->Stop();
  279. removeEventHandlers();
  280. webViewProcess->Terminate();
  281. }
  282. void createBrowser() override
  283. {
  284. if (webViewControl == nullptr)
  285. createWebViewControl();
  286. }
  287. bool hasBrowserBeenCreated() override
  288. {
  289. return webViewControl != nullptr || isCreating;
  290. }
  291. void goToURL (const String& url, const StringArray* headers, const MemoryBlock* postData) override
  292. {
  293. if (webViewControl != nullptr)
  294. {
  295. if ((headers != nullptr && ! headers->isEmpty())
  296. || (postData != nullptr && postData->getSize() > 0))
  297. {
  298. auto requestMessage = createHttpRequestMessage (url, headers, postData);
  299. webViewControl->NavigateWithHttpRequestMessage (requestMessage.get());
  300. }
  301. else
  302. {
  303. auto uri = createURI (url);
  304. webViewControl->Navigate (uri.get());
  305. }
  306. }
  307. }
  308. void stop() override
  309. {
  310. if (webViewControl != nullptr)
  311. webViewControl->Stop();
  312. }
  313. void goBack() override
  314. {
  315. if (webViewControl != nullptr)
  316. {
  317. boolean canGoBack = false;
  318. webViewControl->get_CanGoBack (&canGoBack);
  319. if (canGoBack)
  320. webViewControl->GoBack();
  321. }
  322. }
  323. void goForward() override
  324. {
  325. if (webViewControl != nullptr)
  326. {
  327. boolean canGoForward = false;
  328. webViewControl->get_CanGoForward (&canGoForward);
  329. if (canGoForward)
  330. webViewControl->GoForward();
  331. }
  332. }
  333. void refresh() override
  334. {
  335. if (webViewControl != nullptr)
  336. webViewControl->Refresh();
  337. }
  338. void setWebViewSize (int width, int height) override
  339. {
  340. setSize (width, height);
  341. }
  342. void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/) override
  343. {
  344. if (auto* peer = owner.getTopLevelComponent()->getPeer())
  345. setControlBounds (peer->getAreaCoveredBy (owner));
  346. }
  347. void componentPeerChanged() override
  348. {
  349. componentMovedOrResized (true, true);
  350. }
  351. void componentVisibilityChanged() override
  352. {
  353. setControlVisible (owner.isShowing());
  354. componentPeerChanged();
  355. owner.visibilityChanged();
  356. }
  357. private:
  358. //==============================================================================
  359. template<typename OperationResultType, typename ResultsType>
  360. static HRESULT waitForCompletion (IAsyncOperation<OperationResultType>* op, ResultsType* results)
  361. {
  362. using OperationType = IAsyncOperation<OperationResultType>;
  363. using DelegateType = IAsyncOperationCompletedHandler<OperationResultType>;
  364. struct EventDelegate : public RuntimeClass<RuntimeClassFlags<RuntimeClassType::Delegate>,
  365. DelegateType,
  366. FtmBase>
  367. {
  368. EventDelegate() = default;
  369. ~EventDelegate()
  370. {
  371. CloseHandle (eventCompleted);
  372. }
  373. HRESULT RuntimeClassInitialize()
  374. {
  375. eventCompleted = CreateEventEx (nullptr, nullptr, 0, EVENT_ALL_ACCESS);
  376. return eventCompleted == nullptr ? HRESULT_FROM_WIN32 (GetLastError()) : S_OK;
  377. }
  378. HRESULT Invoke (OperationType*, AsyncStatus newStatus)
  379. {
  380. status = newStatus;
  381. SetEvent (eventCompleted);
  382. return S_OK;
  383. }
  384. AsyncStatus status = AsyncStatus::Started;
  385. HANDLE eventCompleted = nullptr;
  386. };
  387. WinRTWrapper::ComPtr<OperationType> operation = op;
  388. WinRTWrapper::ComPtr<EventDelegate> eventCallback;
  389. auto hr = MakeAndInitialize<EventDelegate> (eventCallback.resetAndGetPointerAddress());
  390. if (SUCCEEDED (hr))
  391. {
  392. hr = operation->put_Completed (eventCallback.get());
  393. if (SUCCEEDED (hr))
  394. {
  395. HANDLE waitForEvents[1] { eventCallback->eventCompleted };
  396. auto handleCount = (ULONG) ARRAYSIZE (waitForEvents);
  397. DWORD handleIndex = 0;
  398. hr = CoWaitForMultipleHandles (COWAIT_DISPATCH_WINDOW_MESSAGES | COWAIT_DISPATCH_CALLS | COWAIT_INPUTAVAILABLE,
  399. INFINITE, handleCount, waitForEvents, &handleIndex);
  400. if (SUCCEEDED (hr))
  401. {
  402. if (eventCallback->status == AsyncStatus::Completed)
  403. {
  404. hr = operation->GetResults (results);
  405. }
  406. else
  407. {
  408. WinRTWrapper::ComPtr<IAsyncInfo> asyncInfo;
  409. if (SUCCEEDED (operation->QueryInterface (asyncInfo.resetAndGetPointerAddress())))
  410. asyncInfo->get_ErrorCode (&hr);
  411. }
  412. }
  413. }
  414. }
  415. return hr;
  416. }
  417. //==============================================================================
  418. template<class ArgsType>
  419. String getURIStringFromArgs (ArgsType& args)
  420. {
  421. WinRTWrapper::ComPtr<IUriRuntimeClass> uri;
  422. args.get_Uri (uri.resetAndGetPointerAddress());
  423. if (uri != nullptr)
  424. {
  425. HSTRING uriString;
  426. uri->get_AbsoluteUri (&uriString);
  427. return WinRTWrapper::getInstance()->hStringToString (uriString);
  428. }
  429. return {};
  430. }
  431. void addEventHandlers()
  432. {
  433. if (webViewControl != nullptr)
  434. {
  435. webViewControl->add_NavigationStarting (Callback<ITypedEventHandler<IWebViewControl*, WebViewControlNavigationStartingEventArgs*>> (
  436. [this] (IWebViewControl*, IWebViewControlNavigationStartingEventArgs* args)
  437. {
  438. auto uriString = getURIStringFromArgs (*args);
  439. if (uriString.isNotEmpty())
  440. args->put_Cancel (! owner.pageAboutToLoad (uriString));
  441. return S_OK;
  442. }
  443. ).Get(), &navigationStartingToken);
  444. webViewControl->add_NewWindowRequested (Callback<ITypedEventHandler<IWebViewControl*, WebViewControlNewWindowRequestedEventArgs*>> (
  445. [this] (IWebViewControl*, IWebViewControlNewWindowRequestedEventArgs* args)
  446. {
  447. auto uriString = getURIStringFromArgs (*args);
  448. if (uriString.isNotEmpty())
  449. {
  450. owner.newWindowAttemptingToLoad (uriString);
  451. args->put_Handled (true);
  452. }
  453. return S_OK;
  454. }
  455. ).Get(), &newWindowRequestedToken);
  456. webViewControl->add_NavigationCompleted (Callback<ITypedEventHandler<IWebViewControl*, WebViewControlNavigationCompletedEventArgs*>> (
  457. [this] (IWebViewControl*, IWebViewControlNavigationCompletedEventArgs* args)
  458. {
  459. auto uriString = getURIStringFromArgs (*args);
  460. if (uriString.isNotEmpty())
  461. {
  462. boolean success;
  463. args->get_IsSuccess (&success);
  464. if (success)
  465. {
  466. owner.pageFinishedLoading (uriString);
  467. }
  468. else
  469. {
  470. WebErrorStatus status;
  471. args->get_WebErrorStatus (&status);
  472. owner.pageLoadHadNetworkError ("Error code: " + String (status));
  473. }
  474. }
  475. return S_OK;
  476. }
  477. ).Get(), &navigationCompletedToken);
  478. }
  479. }
  480. void removeEventHandlers()
  481. {
  482. if (webViewControl != nullptr)
  483. {
  484. if (navigationStartingToken.value != 0)
  485. webViewControl->remove_NavigationStarting (navigationStartingToken);
  486. if (newWindowRequestedToken.value != 0)
  487. webViewControl->remove_NewWindowRequested (newWindowRequestedToken);
  488. if (navigationCompletedToken.value != 0)
  489. webViewControl->remove_NavigationCompleted (navigationCompletedToken);
  490. }
  491. }
  492. bool createWebViewProcess()
  493. {
  494. auto webViewControlProcessFactory
  495. = WinRTWrapper::getInstance()->getWRLFactory<IWebViewControlProcessFactory> (RuntimeClass_Windows_Web_UI_Interop_WebViewControlProcess);
  496. if (webViewControlProcessFactory == nullptr)
  497. {
  498. jassertfalse;
  499. return false;
  500. }
  501. auto webViewProcessOptions
  502. = WinRTWrapper::getInstance()->activateInstance<IWebViewControlProcessOptions> (RuntimeClass_Windows_Web_UI_Interop_WebViewControlProcessOptions,
  503. __uuidof (IWebViewControlProcessOptions));
  504. webViewProcessOptions->put_PrivateNetworkClientServerCapability (WebViewControlProcessCapabilityState_Enabled);
  505. webViewControlProcessFactory->CreateWithOptions (webViewProcessOptions.get(), webViewProcess.resetAndGetPointerAddress());
  506. return webViewProcess != nullptr;
  507. }
  508. void createWebViewControl()
  509. {
  510. if (auto* peer = getPeer())
  511. {
  512. ScopedValueSetter<bool> svs (isCreating, true);
  513. WinRTWrapper::ComPtr<IAsyncOperation<WebViewControl*>> createWebViewAsyncOperation;
  514. webViewProcess->CreateWebViewControlAsync ((INT64) peer->getNativeHandle(), {},
  515. createWebViewAsyncOperation.resetAndGetPointerAddress());
  516. waitForCompletion (createWebViewAsyncOperation.get(), webViewControl.resetAndGetPointerAddress());
  517. addEventHandlers();
  518. componentMovedOrResized (true, true);
  519. }
  520. }
  521. //==============================================================================
  522. WinRTWrapper::ComPtr<IUriRuntimeClass> createURI (const String& url)
  523. {
  524. auto uriRuntimeFactory
  525. = WinRTWrapper::getInstance()->getWRLFactory <IUriRuntimeClassFactory> (RuntimeClass_Windows_Foundation_Uri);
  526. if (uriRuntimeFactory == nullptr)
  527. {
  528. jassertfalse;
  529. return {};
  530. }
  531. WinRTWrapper::ScopedHString hstr (url);
  532. WinRTWrapper::ComPtr<IUriRuntimeClass> uriRuntimeClass;
  533. uriRuntimeFactory->CreateUri (hstr.get(), uriRuntimeClass.resetAndGetPointerAddress());
  534. return uriRuntimeClass;
  535. }
  536. WinRTWrapper::ComPtr<IHttpContent> getPOSTContent (const MemoryBlock& postData)
  537. {
  538. auto factory = WinRTWrapper::getInstance()->getWRLFactory<IHttpStringContentFactory> (RuntimeClass_Windows_Web_Http_HttpStringContent);
  539. if (factory == nullptr)
  540. {
  541. jassertfalse;
  542. return {};
  543. }
  544. WinRTWrapper::ScopedHString hStr (postData.toString());
  545. WinRTWrapper::ComPtr<IHttpContent> content;
  546. factory->CreateFromString (hStr.get(), content.resetAndGetPointerAddress());
  547. return content;
  548. }
  549. WinRTWrapper::ComPtr<IHttpMethod> getMethod (bool isPOST)
  550. {
  551. auto methodFactory = WinRTWrapper::getInstance()->getWRLFactory<IHttpMethodStatics> (RuntimeClass_Windows_Web_Http_HttpMethod);
  552. if (methodFactory == nullptr)
  553. {
  554. jassertfalse;
  555. return {};
  556. }
  557. WinRTWrapper::ComPtr<IHttpMethod> method;
  558. if (isPOST)
  559. methodFactory->get_Post (method.resetAndGetPointerAddress());
  560. else
  561. methodFactory->get_Get (method.resetAndGetPointerAddress());
  562. return method;
  563. }
  564. void addHttpHeaders (WinRTWrapper::ComPtr<IHttpRequestMessage>& requestMessage, const StringArray& headers)
  565. {
  566. WinRTWrapper::ComPtr<IHttpRequestHeaderCollection> headerCollection;
  567. requestMessage->get_Headers (headerCollection.resetAndGetPointerAddress());
  568. for (int i = 0; i < headers.size(); ++i)
  569. {
  570. WinRTWrapper::ScopedHString headerName (headers[i].upToFirstOccurrenceOf (":", false, false).trim());
  571. WinRTWrapper::ScopedHString headerValue (headers[i].fromFirstOccurrenceOf (":", false, false).trim());
  572. headerCollection->Append (headerName.get(), headerValue.get());
  573. }
  574. }
  575. WinRTWrapper::ComPtr<IHttpRequestMessage> createHttpRequestMessage (const String& url,
  576. const StringArray* headers,
  577. const MemoryBlock* postData)
  578. {
  579. auto requestFactory
  580. = WinRTWrapper::getInstance()->getWRLFactory<IHttpRequestMessageFactory> (RuntimeClass_Windows_Web_Http_HttpRequestMessage);
  581. if (requestFactory == nullptr)
  582. {
  583. jassertfalse;
  584. return {};
  585. }
  586. bool isPOSTRequest = (postData != nullptr && postData->getSize() > 0);
  587. auto method = getMethod (isPOSTRequest);
  588. auto uri = createURI (url);
  589. WinRTWrapper::ComPtr<IHttpRequestMessage> requestMessage;
  590. requestFactory->Create (method.get(), uri.get(), requestMessage.resetAndGetPointerAddress());
  591. if (isPOSTRequest)
  592. {
  593. auto content = getPOSTContent (*postData);
  594. requestMessage->put_Content (content.get());
  595. }
  596. if (headers != nullptr && ! headers->isEmpty())
  597. addHttpHeaders (requestMessage, *headers);
  598. return requestMessage;
  599. }
  600. //==============================================================================
  601. void setControlBounds (Rectangle<int> newBounds) const
  602. {
  603. if (webViewControl != nullptr)
  604. {
  605. #if JUCE_WIN_PER_MONITOR_DPI_AWARE
  606. if (auto* peer = owner.getTopLevelComponent()->getPeer())
  607. newBounds = (newBounds.toDouble() * peer->getPlatformScaleFactor()).toNearestInt();
  608. #endif
  609. WinRTWrapper::ComPtr<IWebViewControlSite> site;
  610. if (SUCCEEDED (webViewControl->QueryInterface (site.resetAndGetPointerAddress())))
  611. site->put_Bounds ({ static_cast<FLOAT> (newBounds.getX()), static_cast<FLOAT> (newBounds.getY()),
  612. static_cast<FLOAT> (newBounds.getWidth()), static_cast<FLOAT> (newBounds.getHeight()) });
  613. }
  614. }
  615. void setControlVisible (bool shouldBeVisible) const
  616. {
  617. if (webViewControl != 0)
  618. {
  619. WinRTWrapper::ComPtr<IWebViewControlSite> site;
  620. if (SUCCEEDED (webViewControl->QueryInterface (site.resetAndGetPointerAddress())))
  621. site->put_IsVisible (shouldBeVisible);
  622. }
  623. }
  624. //==============================================================================
  625. WebBrowserComponent& owner;
  626. WinRTWrapper::ComPtr<IWebViewControlProcess> webViewProcess;
  627. WinRTWrapper::ComPtr<IWebViewControl> webViewControl;
  628. EventRegistrationToken navigationStartingToken { 0 },
  629. newWindowRequestedToken { 0 },
  630. navigationCompletedToken { 0 };
  631. bool isCreating = false;
  632. };
  633. #endif
  634. //==============================================================================
  635. class WebBrowserComponent::Pimpl
  636. {
  637. public:
  638. Pimpl (WebBrowserComponent& owner)
  639. {
  640. #if JUCE_USE_WINRT_WEBVIEW
  641. auto windowsVersionInfo = getWindowsVersionInfo();
  642. if (windowsVersionInfo.dwMajorVersion >= 10 && windowsVersionInfo.dwBuildNumber >= 17763)
  643. {
  644. try
  645. {
  646. internal.reset (new WinRTWebView (owner));
  647. }
  648. catch (std::runtime_error&) {}
  649. }
  650. #endif
  651. if (internal == nullptr)
  652. internal.reset (new Win32WebView (owner));
  653. }
  654. InternalWebViewType& getInternalWebView()
  655. {
  656. return *internal;
  657. }
  658. private:
  659. std::unique_ptr<InternalWebViewType> internal;
  660. };
  661. //==============================================================================
  662. WebBrowserComponent::WebBrowserComponent (bool unloadWhenHidden)
  663. : browser (new Pimpl (*this)),
  664. unloadPageWhenBrowserIsHidden (unloadWhenHidden)
  665. {
  666. setOpaque (true);
  667. }
  668. WebBrowserComponent::~WebBrowserComponent()
  669. {
  670. }
  671. //==============================================================================
  672. void WebBrowserComponent::goToURL (const String& url,
  673. const StringArray* headers,
  674. const MemoryBlock* postData)
  675. {
  676. lastURL = url;
  677. if (headers != nullptr)
  678. lastHeaders = *headers;
  679. else
  680. lastHeaders.clear();
  681. if (postData != nullptr)
  682. lastPostData = *postData;
  683. else
  684. lastPostData.reset();
  685. blankPageShown = false;
  686. if (! browser->getInternalWebView().hasBrowserBeenCreated())
  687. checkWindowAssociation();
  688. browser->getInternalWebView().goToURL (url, headers, postData);
  689. }
  690. void WebBrowserComponent::stop()
  691. {
  692. browser->getInternalWebView().stop();
  693. }
  694. void WebBrowserComponent::goBack()
  695. {
  696. lastURL.clear();
  697. blankPageShown = false;
  698. browser->getInternalWebView().goBack();
  699. }
  700. void WebBrowserComponent::goForward()
  701. {
  702. lastURL.clear();
  703. browser->getInternalWebView().goForward();
  704. }
  705. void WebBrowserComponent::refresh()
  706. {
  707. browser->getInternalWebView().refresh();
  708. }
  709. //==============================================================================
  710. void WebBrowserComponent::paint (Graphics& g)
  711. {
  712. if (! browser->getInternalWebView().hasBrowserBeenCreated())
  713. {
  714. g.fillAll (Colours::white);
  715. checkWindowAssociation();
  716. }
  717. }
  718. void WebBrowserComponent::checkWindowAssociation()
  719. {
  720. if (isShowing())
  721. {
  722. if (! browser->getInternalWebView().hasBrowserBeenCreated() && getPeer() != nullptr)
  723. {
  724. browser->getInternalWebView().createBrowser();
  725. reloadLastURL();
  726. }
  727. else
  728. {
  729. if (blankPageShown)
  730. goBack();
  731. }
  732. }
  733. else
  734. {
  735. if (browser != nullptr && unloadPageWhenBrowserIsHidden && ! blankPageShown)
  736. {
  737. // when the component becomes invisible, some stuff like flash
  738. // carries on playing audio, so we need to force it onto a blank
  739. // page to avoid this..
  740. blankPageShown = true;
  741. browser->getInternalWebView().goToURL ("about:blank", 0, 0);
  742. }
  743. }
  744. }
  745. void WebBrowserComponent::reloadLastURL()
  746. {
  747. if (lastURL.isNotEmpty())
  748. {
  749. goToURL (lastURL, &lastHeaders, &lastPostData);
  750. lastURL.clear();
  751. }
  752. }
  753. void WebBrowserComponent::parentHierarchyChanged()
  754. {
  755. checkWindowAssociation();
  756. }
  757. void WebBrowserComponent::resized()
  758. {
  759. browser->getInternalWebView().setWebViewSize (getWidth(), getHeight());
  760. }
  761. void WebBrowserComponent::visibilityChanged()
  762. {
  763. checkWindowAssociation();
  764. }
  765. void WebBrowserComponent::focusGained (FocusChangeType)
  766. {
  767. browser->getInternalWebView().focusGained();
  768. }
  769. void WebBrowserComponent::clearCookies()
  770. {
  771. HeapBlock<::INTERNET_CACHE_ENTRY_INFOA> entry;
  772. ::DWORD entrySize = sizeof (::INTERNET_CACHE_ENTRY_INFOA);
  773. ::HANDLE urlCacheHandle = ::FindFirstUrlCacheEntryA ("cookie:", entry.getData(), &entrySize);
  774. if (urlCacheHandle == nullptr && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  775. {
  776. entry.realloc (1, entrySize);
  777. urlCacheHandle = ::FindFirstUrlCacheEntryA ("cookie:", entry.getData(), &entrySize);
  778. }
  779. if (urlCacheHandle != nullptr)
  780. {
  781. for (;;)
  782. {
  783. ::DeleteUrlCacheEntryA (entry.getData()->lpszSourceUrlName);
  784. if (::FindNextUrlCacheEntryA (urlCacheHandle, entry.getData(), &entrySize) == 0)
  785. {
  786. if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  787. {
  788. entry.realloc (1, entrySize);
  789. if (::FindNextUrlCacheEntryA (urlCacheHandle, entry.getData(), &entrySize) != 0)
  790. continue;
  791. }
  792. break;
  793. }
  794. }
  795. FindCloseUrlCache (urlCacheHandle);
  796. }
  797. }
  798. } // namespace juce