PageRenderTime 356ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/CefSharp/WebBrowserExtensions.cs

https://github.com/cefsharp/CefSharp
C# | 1611 lines | 716 code | 208 blank | 687 comment | 62 complexity | 80ee067feb3def19d73000f9d86d70a1 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. // Copyright © 2015 The CefSharp Authors. All rights reserved.
  2. //
  3. // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
  4. using System;
  5. using System.Collections.Specialized;
  6. using System.ComponentModel;
  7. using System.Globalization;
  8. using System.IO;
  9. using System.Text;
  10. using System.Threading.Tasks;
  11. using CefSharp.Internals;
  12. using CefSharp.Web;
  13. namespace CefSharp
  14. {
  15. /// <summary>
  16. /// WebBrowser extensions - These methods make performing common tasks easier.
  17. /// </summary>
  18. public static class WebBrowserExtensions
  19. {
  20. public const string BrowserNullExceptionString = "IBrowser instance is null. Browser has likely not finished initializing or is in the process of disposing.";
  21. public const string BrowserHostNullExceptionString = "IBrowserHost instance is null. Browser has likely not finished initializing or is in the process of disposing.";
  22. public const string FrameNullExceptionString = "IFrame instance is null. Browser has likely not finished initializing or is in the process of disposing.";
  23. #region Legacy Javascript Binding
  24. /// <summary>
  25. /// Registers a Javascript object in this specific browser instance.
  26. /// </summary>
  27. /// <param name="webBrowser">The browser to perform the registering on.</param>
  28. /// <param name="name">The name of the object. (e.g. "foo", if you want the object to be accessible as window.foo).</param>
  29. /// <param name="objectToBind">The object to be made accessible to Javascript.</param>
  30. /// <param name="options">(Optional) binding options - camelCaseJavascriptNames default to true.</param>
  31. /// <exception cref="Exception">Browser is already initialized. RegisterJsObject must be +
  32. /// called before the underlying CEF browser is created.</exception>
  33. [Obsolete("This method has been removed, see https://github.com/cefsharp/CefSharp/issues/2990 for details on migrating your code.")]
  34. [EditorBrowsable(EditorBrowsableState.Never)]
  35. public static void RegisterJsObject(this IWebBrowser webBrowser, string name, object objectToBind, BindingOptions options = null)
  36. {
  37. throw new NotImplementedException("This method has been removed, see https://github.com/cefsharp/CefSharp/issues/2990 for details on migrating your code.");
  38. }
  39. /// <summary>
  40. /// <para>Asynchronously registers a Javascript object in this specific browser instance.</para>
  41. /// <para>Only methods of the object will be availabe.</para>
  42. /// </summary>
  43. /// <param name="webBrowser">The browser to perform the registering on</param>
  44. /// <param name="name">The name of the object. (e.g. "foo", if you want the object to be accessible as window.foo).</param>
  45. /// <param name="objectToBind">The object to be made accessible to Javascript.</param>
  46. /// <param name="options">binding options - camelCaseJavascriptNames default to true </param>
  47. /// <exception cref="Exception">Browser is already initialized. RegisterJsObject must be +
  48. /// called before the underlying CEF browser is created.</exception>
  49. /// <remarks>The registered methods can only be called in an async way, they will all return immediately and the resulting
  50. /// object will be a standard javascript Promise object which is usable to wait for completion or failure.</remarks>
  51. [Obsolete("This method has been removed, see https://github.com/cefsharp/CefSharp/issues/2990 for details on migrating your code.")]
  52. [EditorBrowsable(EditorBrowsableState.Never)]
  53. public static void RegisterAsyncJsObject(this IWebBrowser webBrowser, string name, object objectToBind, BindingOptions options = null)
  54. {
  55. throw new NotImplementedException("This method has been removed, see https://github.com/cefsharp/CefSharp/issues/2990 for details on migrating your code.");
  56. }
  57. #endregion
  58. /// <summary>
  59. /// Returns the main (top-level) frame for the browser window.
  60. /// </summary>
  61. /// <param name="browser">the ChromiumWebBrowser instance.</param>
  62. /// <returns> the main frame. </returns>
  63. public static IFrame GetMainFrame(this IChromiumWebBrowserBase browser)
  64. {
  65. var cefBrowser = browser.BrowserCore;
  66. cefBrowser.ThrowExceptionIfBrowserNull();
  67. return cefBrowser.MainFrame;
  68. }
  69. /// <summary>
  70. /// Returns the focused frame for the browser window.
  71. /// </summary>
  72. /// <param name="browser">the ChromiumWebBrowser instance.</param>
  73. /// <returns>the focused frame.</returns>
  74. public static IFrame GetFocusedFrame(this IChromiumWebBrowserBase browser)
  75. {
  76. var cefBrowser = browser.BrowserCore;
  77. cefBrowser.ThrowExceptionIfBrowserNull();
  78. return cefBrowser.FocusedFrame;
  79. }
  80. /// <summary>
  81. /// Execute Undo on the focused frame.
  82. /// </summary>
  83. /// <param name="browser">The ChromiumWebBrowser instance this method extends.</param>
  84. public static void Undo(this IChromiumWebBrowserBase browser)
  85. {
  86. browser.BrowserCore.Undo();
  87. }
  88. /// <summary>
  89. /// Execute Undo on the focused frame.
  90. /// </summary>
  91. /// <param name="browser">The IBrowser instance this method extends.</param>
  92. public static void Undo(this IBrowser browser)
  93. {
  94. browser.ThrowExceptionIfBrowserNull();
  95. using (var frame = browser.FocusedFrame)
  96. {
  97. ThrowExceptionIfFrameNull(frame);
  98. frame.Undo();
  99. }
  100. }
  101. /// <summary>
  102. /// Execute Redo on the focused frame.
  103. /// </summary>
  104. /// <param name="browser">The ChromiumWebBrowser instance this method extends.</param>
  105. public static void Redo(this IChromiumWebBrowserBase browser)
  106. {
  107. browser.BrowserCore.Redo();
  108. }
  109. /// <summary>
  110. /// Execute Redo on the focused frame.
  111. /// </summary>
  112. /// <param name="browser">The IBrowser instance this method extends.</param>
  113. public static void Redo(this IBrowser browser)
  114. {
  115. browser.ThrowExceptionIfBrowserNull();
  116. using (var frame = browser.FocusedFrame)
  117. {
  118. ThrowExceptionIfFrameNull(frame);
  119. frame.Redo();
  120. }
  121. }
  122. /// <summary>
  123. /// Execute Cut on the focused frame.
  124. /// </summary>
  125. /// <param name="browser">The ChromiumWebBrowser instance this method extends.</param>
  126. public static void Cut(this IChromiumWebBrowserBase browser)
  127. {
  128. browser.BrowserCore.Cut();
  129. }
  130. /// <summary>
  131. /// Execute Cut on the focused frame.
  132. /// </summary>
  133. /// <param name="browser">The IBrowser instance this method extends.</param>
  134. public static void Cut(this IBrowser browser)
  135. {
  136. browser.ThrowExceptionIfBrowserNull();
  137. using (var frame = browser.FocusedFrame)
  138. {
  139. ThrowExceptionIfFrameNull(frame);
  140. frame.Cut();
  141. }
  142. }
  143. /// <summary>
  144. /// Execute Copy on the focused frame.
  145. /// </summary>
  146. /// <param name="browser">The ChromiumWebBrowser instance this method extends.</param>
  147. public static void Copy(this IChromiumWebBrowserBase browser)
  148. {
  149. browser.BrowserCore.Copy();
  150. }
  151. /// <summary>
  152. /// Execute Copy on the focused frame.
  153. /// </summary>
  154. /// <param name="browser">The IBrowser instance this method extends.</param>
  155. public static void Copy(this IBrowser browser)
  156. {
  157. browser.ThrowExceptionIfBrowserNull();
  158. using (var frame = browser.FocusedFrame)
  159. {
  160. ThrowExceptionIfFrameNull(frame);
  161. frame.Copy();
  162. }
  163. }
  164. /// <summary>
  165. /// Execute Paste on the focused frame.
  166. /// </summary>
  167. /// <param name="browser">The ChromiumWebBrowser instance this method extends.</param>
  168. public static void Paste(this IChromiumWebBrowserBase browser)
  169. {
  170. browser.BrowserCore.Paste();
  171. }
  172. /// <summary>
  173. /// Execute Paste on the focused frame.
  174. /// </summary>
  175. /// <param name="browser">The IBrowser instance this method extends.</param>
  176. public static void Paste(this IBrowser browser)
  177. {
  178. browser.ThrowExceptionIfBrowserNull();
  179. using (var frame = browser.FocusedFrame)
  180. {
  181. ThrowExceptionIfFrameNull(frame);
  182. frame.Paste();
  183. }
  184. }
  185. /// <summary>
  186. /// Execute Delete on the focused frame.
  187. /// </summary>
  188. /// <param name="browser">The ChromiumWebBrowser instance this method extends.</param>
  189. public static void Delete(this IChromiumWebBrowserBase browser)
  190. {
  191. browser.BrowserCore.Delete();
  192. }
  193. /// <summary>
  194. /// Execute Delete on the focused frame.
  195. /// </summary>
  196. /// <param name="browser">The IBrowser instance this method extends.</param>
  197. public static void Delete(this IBrowser browser)
  198. {
  199. browser.ThrowExceptionIfBrowserNull();
  200. using (var frame = browser.FocusedFrame)
  201. {
  202. ThrowExceptionIfFrameNull(frame);
  203. frame.Delete();
  204. }
  205. }
  206. /// <summary>
  207. /// Execute SelectAll on the focused frame.
  208. /// </summary>
  209. /// <param name="browser">The ChromiumWebBrowser instance this method extends.</param>
  210. public static void SelectAll(this IChromiumWebBrowserBase browser)
  211. {
  212. browser.BrowserCore.SelectAll();
  213. }
  214. /// <summary>
  215. /// Execute SelectAll on the focused frame.
  216. /// </summary>
  217. /// <param name="browser">The IBrowser instance this method extends.</param>
  218. public static void SelectAll(this IBrowser browser)
  219. {
  220. browser.ThrowExceptionIfBrowserNull();
  221. using (var frame = browser.FocusedFrame)
  222. {
  223. ThrowExceptionIfFrameNull(frame);
  224. frame.SelectAll();
  225. }
  226. }
  227. /// <summary>
  228. /// Opens up a new program window (using the default text editor) where the source code of the currently displayed web page is
  229. /// shown.
  230. /// </summary>
  231. /// <param name="browser">The ChromiumWebBrowser instance this method extends.</param>
  232. public static void ViewSource(this IChromiumWebBrowserBase browser)
  233. {
  234. browser.BrowserCore.ViewSource();
  235. }
  236. /// <summary>
  237. /// Opens up a new program window (using the default text editor) where the source code of the currently displayed web page is
  238. /// shown.
  239. /// </summary>
  240. /// <param name="browser">The IBrowser instance this method extends.</param>
  241. public static void ViewSource(this IBrowser browser)
  242. {
  243. browser.ThrowExceptionIfBrowserNull();
  244. using (var frame = browser.MainFrame)
  245. {
  246. ThrowExceptionIfFrameNull(frame);
  247. frame.ViewSource();
  248. }
  249. }
  250. /// <summary>
  251. /// Retrieve the main frame's HTML source using a <see cref="Task{String}"/>.
  252. /// </summary>
  253. /// <param name="browser">The ChromiumWebBrowser instance this method extends.</param>
  254. /// <returns>
  255. /// <see cref="Task{String}"/> that when executed returns the main frame source as a string.
  256. /// </returns>
  257. public static Task<string> GetSourceAsync(this IChromiumWebBrowserBase browser)
  258. {
  259. return browser.BrowserCore.GetSourceAsync();
  260. }
  261. /// <summary>
  262. /// Retrieve the main frame's HTML source using a <see cref="Task{String}"/>.
  263. /// </summary>
  264. /// <param name="browser">The IBrowser instance this method extends.</param>
  265. /// <returns>
  266. /// <see cref="Task{String}"/> that when executed returns the main frame source as a string.
  267. /// </returns>
  268. public static Task<string> GetSourceAsync(this IBrowser browser)
  269. {
  270. browser.ThrowExceptionIfBrowserNull();
  271. using (var frame = browser.FocusedFrame)
  272. {
  273. ThrowExceptionIfFrameNull(frame);
  274. return frame.GetSourceAsync();
  275. }
  276. }
  277. /// <summary>
  278. /// Retrieve the main frame's display text using a <see cref="Task{String}"/>.
  279. /// </summary>
  280. /// <param name="browser">The ChromiumWebBrowser instance this method extends.</param>
  281. /// <returns>
  282. /// <see cref="Task{String}"/> that when executed returns the main frame display text as a string.
  283. /// </returns>
  284. public static Task<string> GetTextAsync(this IChromiumWebBrowserBase browser)
  285. {
  286. return browser.BrowserCore.GetTextAsync();
  287. }
  288. /// <summary>
  289. /// Retrieve the main frame's display text using a <see cref="Task{String}"/>.
  290. /// </summary>
  291. /// <param name="browser">The IBrowser instance this method extends.</param>
  292. /// <returns>
  293. /// <see cref="Task{String}"/> that when executed returns the main frame display text as a string.
  294. /// </returns>
  295. public static Task<string> GetTextAsync(this IBrowser browser)
  296. {
  297. browser.ThrowExceptionIfBrowserNull();
  298. using (var frame = browser.FocusedFrame)
  299. {
  300. ThrowExceptionIfFrameNull(frame);
  301. return frame.GetTextAsync();
  302. }
  303. }
  304. /// <summary>
  305. /// Download the file at url using <see cref="IDownloadHandler"/>.
  306. /// </summary>
  307. /// <param name="browser">The ChromiumWebBrowser instance this method extends.</param>
  308. /// <param name="url">url to download</param>
  309. public static void StartDownload(this IChromiumWebBrowserBase browser, string url)
  310. {
  311. browser.BrowserCore.StartDownload(url);
  312. }
  313. /// <summary>
  314. /// Download the file at url using <see cref="IDownloadHandler"/>.
  315. /// </summary>
  316. /// <param name="browser">The IBrowser instance this method extends.</param>
  317. /// <param name="url">url to download</param>
  318. public static void StartDownload(this IBrowser browser, string url)
  319. {
  320. browser.ThrowExceptionIfBrowserNull();
  321. var host = browser.GetHost();
  322. ThrowExceptionIfBrowserHostNull(host);
  323. host.StartDownload(url);
  324. }
  325. /// <summary>
  326. /// See <see cref="IChromiumWebBrowserBase.LoadUrlAsync(string)"/> for details
  327. /// </summary>
  328. /// <param name="chromiumWebBrowser">ChromiumWebBrowser instance (cannot be null)</param>
  329. /// <summary>
  330. /// Load the <paramref name="url"/> in the main frame of the browser
  331. /// </summary>
  332. /// <param name="url">url to load</param>
  333. /// <returns>See <see cref="IChromiumWebBrowserBase.LoadUrlAsync(string)"/> for details</returns>
  334. public static Task<LoadUrlAsyncResponse> LoadUrlAsync(IChromiumWebBrowserBase chromiumWebBrowser, string url)
  335. {
  336. if(string.IsNullOrEmpty(url))
  337. {
  338. throw new ArgumentNullException(nameof(url));
  339. }
  340. var tcs = new TaskCompletionSource<LoadUrlAsyncResponse>();
  341. EventHandler<LoadErrorEventArgs> loadErrorHandler = null;
  342. EventHandler<LoadingStateChangedEventArgs> loadingStateChangeHandler = null;
  343. loadErrorHandler = (sender, args) =>
  344. {
  345. //Actions that trigger a download will raise an aborted error.
  346. //Generally speaking Aborted is safe to ignore
  347. if (args.ErrorCode == CefErrorCode.Aborted)
  348. {
  349. return;
  350. }
  351. //If LoadError was called then we'll remove both our handlers
  352. //as we won't need to capture LoadingStateChanged, we know there
  353. //was an error
  354. chromiumWebBrowser.LoadError -= loadErrorHandler;
  355. chromiumWebBrowser.LoadingStateChanged -= loadingStateChangeHandler;
  356. //Ensure our continuation is executed on the ThreadPool
  357. //For the .Net Core implementation we could use
  358. //TaskCreationOptions.RunContinuationsAsynchronously
  359. tcs.TrySetResultAsync(new LoadUrlAsyncResponse(args.ErrorCode, -1));
  360. };
  361. loadingStateChangeHandler = (sender, args) =>
  362. {
  363. //Wait for IsLoading = false
  364. if (!args.IsLoading)
  365. {
  366. //If LoadingStateChanged was called then we'll remove both our handlers
  367. //as LoadError won't be called, our site has loaded with a valid HttpStatusCode
  368. //HttpStatusCodes can still be for example 404, this is considered a successful request,
  369. //the server responded, it just didn't have the page you were after.
  370. chromiumWebBrowser.LoadError -= loadErrorHandler;
  371. chromiumWebBrowser.LoadingStateChanged -= loadingStateChangeHandler;
  372. var host = args.Browser.GetHost();
  373. var navEntry = host?.GetVisibleNavigationEntry();
  374. int statusCode = navEntry?.HttpStatusCode ?? -1;
  375. //By default 0 is some sort of error, we map that to -1
  376. //so that it's clearer that something failed.
  377. if (statusCode == 0)
  378. {
  379. statusCode = -1;
  380. }
  381. //Ensure our continuation is executed on the ThreadPool
  382. //For the .Net Core implementation we could use
  383. //TaskCreationOptions.RunContinuationsAsynchronously
  384. tcs.TrySetResultAsync(new LoadUrlAsyncResponse(CefErrorCode.None, statusCode));
  385. }
  386. };
  387. chromiumWebBrowser.LoadError += loadErrorHandler;
  388. chromiumWebBrowser.LoadingStateChanged += loadingStateChangeHandler;
  389. chromiumWebBrowser.LoadUrl(url);
  390. return tcs.Task;
  391. }
  392. /// <summary>
  393. /// Execute Javascript code in the context of this Browser. As the method name implies, the script will be executed
  394. /// asynchronously, and the method therefore returns before the script has actually been executed. This simple helper extension
  395. /// will encapsulate params in single quotes (unless int, uint, etc)
  396. /// </summary>
  397. /// <param name="browser">The ChromiumWebBrowser instance this method extends.</param>
  398. /// <param name="methodName">The javascript method name to execute.</param>
  399. /// <param name="args">the arguments to be passed as params to the method. Args are encoded using
  400. /// <see cref="EncodeScriptParam"/>, you can provide a custom implementation if you require one.</param>
  401. public static void ExecuteScriptAsync(this IChromiumWebBrowserBase browser, string methodName, params object[] args)
  402. {
  403. browser.BrowserCore.ExecuteScriptAsync(methodName, args);
  404. }
  405. /// <summary>
  406. /// Execute Javascript code in the context of this WebBrowser. As the method name implies, the script will be executed
  407. /// asynchronously, and the method therefore returns before the script has actually been executed. This simple helper extension
  408. /// will encapsulate params in single quotes (unless int, uint, etc)
  409. /// </summary>
  410. /// <param name="browser">The IBrowser instance this method extends.</param>
  411. /// <param name="methodName">The javascript method name to execute.</param>
  412. /// <param name="args">the arguments to be passed as params to the method. Args are encoded using
  413. /// <see cref="EncodeScriptParam"/>, you can provide a custom implementation if you require one.</param>
  414. public static void ExecuteScriptAsync(this IBrowser browser, string methodName, params object[] args)
  415. {
  416. var script = GetScriptForJavascriptMethodWithArgs(methodName, args);
  417. browser.ExecuteScriptAsync(script);
  418. }
  419. /// <summary>
  420. /// Execute Javascript in the context of this Browsers Main Frame. As the method name implies, the script will be executed
  421. /// asynchronously, and the method therefore returns before the script has actually been executed.
  422. /// </summary>
  423. /// <param name="browser">The ChromiumWebBrowser instance this method extends.</param>
  424. /// <param name="script">The Javascript code that should be executed.</param>
  425. public static void ExecuteScriptAsync(this IChromiumWebBrowserBase browser, string script)
  426. {
  427. using (var frame = browser.GetMainFrame())
  428. {
  429. ThrowExceptionIfFrameNull(frame);
  430. frame.ExecuteJavaScriptAsync(script);
  431. }
  432. }
  433. /// <summary>
  434. /// Execute Javascript in the context of this Browser Main Frame. As the method name implies, the script will be executed
  435. /// asynchronously, and the method therefore returns before the script has actually been executed.
  436. /// </summary>
  437. /// <param name="browser">The IBrowser instance this method extends.</param>
  438. /// <param name="script">The Javascript code that should be executed.</param>
  439. public static void ExecuteScriptAsync(this IBrowser browser, string script)
  440. {
  441. browser.ThrowExceptionIfBrowserNull();
  442. using (var frame = browser.MainFrame)
  443. {
  444. ThrowExceptionIfFrameNull(frame);
  445. frame.ExecuteJavaScriptAsync(script);
  446. }
  447. }
  448. /// <summary>
  449. /// Execute Javascript code in the context of this Browsers Main Frame. This extension method uses the LoadingStateChanged event. As the
  450. /// method name implies, the script will be executed asynchronously, and the method therefore returns before the script has
  451. /// actually been executed.
  452. /// </summary>
  453. /// <remarks>
  454. /// Best effort is made to make sure the script is executed, there are likely a few edge cases where the script won't be executed,
  455. /// if you suspect your script isn't being executed, then try executing in the LoadingStateChanged event handler to confirm that
  456. /// it does indeed get executed.
  457. /// </remarks>
  458. /// <param name="webBrowser">The ChromiumWebBrowser instance this method extends.</param>
  459. /// <param name="script">The Javascript code that should be executed.</param>
  460. /// <param name="oneTime">(Optional) The script will only be executed on first page load, subsequent page loads will be ignored.</param>
  461. public static void ExecuteScriptAsyncWhenPageLoaded(this IChromiumWebBrowserBase webBrowser, string script, bool oneTime = true)
  462. {
  463. var useLoadingStateChangedEventHandler = webBrowser.IsBrowserInitialized == false || oneTime == false;
  464. //Browser has been initialized, we check if there is a valid document and we're not loading
  465. if (webBrowser.IsBrowserInitialized)
  466. {
  467. //CefBrowser wrapper
  468. var browser = webBrowser.BrowserCore;
  469. if (browser.HasDocument && browser.IsLoading == false)
  470. {
  471. webBrowser.ExecuteScriptAsync(script);
  472. }
  473. else
  474. {
  475. useLoadingStateChangedEventHandler = true;
  476. }
  477. }
  478. //If the browser hasn't been initialized we can just wire up the LoadingStateChanged event
  479. //If the script has already been executed and oneTime is false will be hooked up next page load.
  480. if (useLoadingStateChangedEventHandler)
  481. {
  482. EventHandler<LoadingStateChangedEventArgs> handler = null;
  483. handler = (sender, args) =>
  484. {
  485. //Wait for while page to finish loading not just the first frame
  486. if (!args.IsLoading)
  487. {
  488. if (oneTime)
  489. {
  490. webBrowser.LoadingStateChanged -= handler;
  491. }
  492. webBrowser.ExecuteScriptAsync(script);
  493. }
  494. };
  495. webBrowser.LoadingStateChanged += handler;
  496. }
  497. }
  498. /// <summary>
  499. /// Creates a new instance of IRequest with the specified Url and Method = POST and then calls
  500. /// <see cref="IFrame.LoadRequest(IRequest)"/>.
  501. /// </summary>
  502. /// <param name="browser">browser this method extends</param>
  503. /// <param name="url">url to load</param>
  504. /// <param name="postDataBytes">post data as byte array</param>
  505. /// <param name="contentType">(Optional) if set the Content-Type header will be set</param>
  506. public static void LoadUrlWithPostData(this IChromiumWebBrowserBase browser, string url, byte[] postDataBytes, string contentType = null)
  507. {
  508. browser.BrowserCore.LoadUrlWithPostData(url, postDataBytes, contentType);
  509. }
  510. /// <summary>
  511. /// Creates a new instance of IRequest with the specified Url and Method = POST and then calls
  512. /// <see cref="IFrame.LoadRequest(IRequest)"/>.
  513. /// </summary>
  514. /// <param name="browser">browser this method extends</param>
  515. /// <param name="url">url to load</param>
  516. /// <param name="postDataBytes">post data as byte array</param>
  517. /// <param name="contentType">(Optional) if set the Content-Type header will be set</param>
  518. public static void LoadUrlWithPostData(this IBrowser browser, string url, byte[] postDataBytes, string contentType = null)
  519. {
  520. browser.ThrowExceptionIfBrowserNull();
  521. using (var frame = browser.MainFrame)
  522. {
  523. ThrowExceptionIfFrameNull(frame);
  524. //Initialize Request with PostData
  525. var request = frame.CreateRequest(initializePostData: true);
  526. request.Url = url;
  527. request.Method = "POST";
  528. //Add AllowStoredCredentials as per suggestion linked in
  529. //https://github.com/cefsharp/CefSharp/issues/2705#issuecomment-476819788
  530. request.Flags = UrlRequestFlags.AllowStoredCredentials;
  531. request.PostData.AddData(postDataBytes);
  532. if (!string.IsNullOrEmpty(contentType))
  533. {
  534. var headers = new NameValueCollection();
  535. headers.Add("Content-Type", contentType);
  536. request.Headers = headers;
  537. }
  538. frame.LoadRequest(request);
  539. }
  540. }
  541. /// <summary>
  542. /// Registers and loads a <see cref="ResourceHandler"/> that represents the HTML content.
  543. /// </summary>
  544. /// <remarks>
  545. /// `Cef` Native `LoadHtml` is unpredictable and only works sometimes, this method wraps the provided HTML in a
  546. /// <see cref="ResourceHandler"/> and loads the provided url using the <see cref="IWebBrowser.Load"/> method. Defaults to using
  547. /// <see cref="Encoding.UTF8"/> for character encoding The url must start with a valid schema, other uri's such as about:blank
  548. /// are invalid A valid example looks like http://test/page.
  549. /// </remarks>
  550. /// <param name="browser">The ChromiumWebBrowser instance this method extends.</param>
  551. /// <param name="html">The HTML content.</param>
  552. /// <param name="url">The URL that will be treated as the address of the content.</param>
  553. /// <returns>
  554. /// returns false if the Url was not successfully parsed into a Uri.
  555. /// </returns>
  556. public static bool LoadHtml(this IWebBrowser browser, string html, string url)
  557. {
  558. return browser.LoadHtml(html, url, Encoding.UTF8);
  559. }
  560. /// <summary>
  561. /// Loads html as Data Uri See https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs for details If
  562. /// base64Encode is false then html will be Uri encoded.
  563. /// </summary>
  564. /// <param name="browser">The ChromiumWebBrowser instance this method extends.</param>
  565. /// <param name="html">Html to load as data uri.</param>
  566. /// <param name="base64Encode">(Optional) if true the html string will be base64 encoded using UTF8 encoding.</param>
  567. public static void LoadHtml(this IChromiumWebBrowserBase browser, string html, bool base64Encode = false)
  568. {
  569. var htmlString = new HtmlString(html, base64Encode);
  570. browser.LoadUrl(htmlString.ToDataUriString());
  571. }
  572. /// <summary>
  573. /// Loads html as Data Uri See https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs for details If
  574. /// base64Encode is false then html will be Uri encoded.
  575. /// </summary>
  576. /// <param name="frame">The <seealso cref="IFrame"/> instance this method extends.</param>
  577. /// <param name="html">Html to load as data uri.</param>
  578. /// <param name="base64Encode">(Optional) if true the html string will be base64 encoded using UTF8 encoding.</param>
  579. public static void LoadHtml(this IFrame frame, string html, bool base64Encode = false)
  580. {
  581. var htmlString = new HtmlString(html, base64Encode);
  582. frame.LoadUrl(htmlString.ToDataUriString());
  583. }
  584. /// <summary>
  585. /// Registers and loads a <see cref="ResourceHandler"/> that represents the HTML content.
  586. /// </summary>
  587. /// <remarks>
  588. /// `Cef` Native `LoadHtml` is unpredictable and only works sometimes, this method wraps the provided HTML in a
  589. /// <see cref="ResourceHandler"/> and loads the provided url using the <see cref="IWebBrowser.Load"/> method.
  590. /// </remarks>
  591. /// <exception cref="Exception">Thrown when an exception error condition occurs.</exception>
  592. /// <param name="browser">The ChromiumWebBrowser instance this method extends.</param>
  593. /// <param name="html">The HTML content.</param>
  594. /// <param name="url">The URL that will be treated as the address of the content.</param>
  595. /// <param name="encoding">Character Encoding.</param>
  596. /// <param name="oneTimeUse">(Optional) Whether or not the handler should be used once (true) or until manually unregistered
  597. /// (false)</param>
  598. /// <returns>
  599. /// returns false if the Url was not successfully parsed into a Uri.
  600. /// </returns>
  601. public static bool LoadHtml(this IWebBrowser browser, string html, string url, Encoding encoding, bool oneTimeUse = false)
  602. {
  603. if (browser.ResourceRequestHandlerFactory == null)
  604. {
  605. browser.ResourceRequestHandlerFactory = new ResourceRequestHandlerFactory();
  606. }
  607. var handler = browser.ResourceRequestHandlerFactory as ResourceRequestHandlerFactory;
  608. if (handler == null)
  609. {
  610. throw new Exception("LoadHtml can only be used with the default IResourceRequestHandlerFactory(DefaultResourceRequestHandlerFactory) implementation");
  611. }
  612. if (handler.RegisterHandler(url, ResourceHandler.GetByteArray(html, encoding, true), ResourceHandler.DefaultMimeType, oneTimeUse))
  613. {
  614. browser.Load(url);
  615. return true;
  616. }
  617. return false;
  618. }
  619. /// <summary>
  620. /// Register a ResourceHandler. Can only be used when browser.ResourceHandlerFactory is an instance of
  621. /// DefaultResourceHandlerFactory.
  622. /// </summary>
  623. /// <exception cref="Exception">Thrown when an exception error condition occurs.</exception>
  624. /// <param name="browser">The ChromiumWebBrowser instance this method extends.</param>
  625. /// <param name="url">the url of the resource to unregister.</param>
  626. /// <param name="stream">Stream to be registered, the stream should not be shared with any other instances of
  627. /// DefaultResourceHandlerFactory.</param>
  628. /// <param name="mimeType">(Optional) the mimeType.</param>
  629. /// <param name="oneTimeUse">(Optional) Whether or not the handler should be used once (true) or until manually unregistered
  630. /// (false). If true the Stream will be Diposed of when finished.</param>
  631. public static void RegisterResourceHandler(this IWebBrowser browser, string url, Stream stream, string mimeType = ResourceHandler.DefaultMimeType,
  632. bool oneTimeUse = false)
  633. {
  634. if (browser.ResourceRequestHandlerFactory == null)
  635. {
  636. browser.ResourceRequestHandlerFactory = new ResourceRequestHandlerFactory();
  637. }
  638. var handler = browser.ResourceRequestHandlerFactory as ResourceRequestHandlerFactory;
  639. if (handler == null)
  640. {
  641. throw new Exception("RegisterResourceHandler can only be used with the default IResourceRequestHandlerFactory(DefaultResourceRequestHandlerFactory) implementation");
  642. }
  643. using (var ms = new MemoryStream())
  644. {
  645. stream.CopyTo(ms);
  646. handler.RegisterHandler(url, ms.ToArray(), mimeType, oneTimeUse);
  647. }
  648. }
  649. /// <summary>
  650. /// Unregister a ResourceHandler. Can only be used when browser.ResourceHandlerFactory is an instance of
  651. /// DefaultResourceHandlerFactory.
  652. /// </summary>
  653. /// <exception cref="Exception">Thrown when an exception error condition occurs.</exception>
  654. /// <param name="browser">The ChromiumWebBrowser instance this method extends.</param>
  655. /// <param name="url">the url of the resource to unregister.</param>
  656. public static void UnRegisterResourceHandler(this IWebBrowser browser, string url)
  657. {
  658. var handler = browser.ResourceRequestHandlerFactory as ResourceRequestHandlerFactory;
  659. if (handler == null)
  660. {
  661. throw new Exception("UnRegisterResourceHandler can only be used with the default IResourceRequestHandlerFactory(DefaultResourceRequestHandlerFactory) implementation");
  662. }
  663. handler.UnregisterHandler(url);
  664. }
  665. /// <summary>
  666. /// Stops loading the current page.
  667. /// </summary>
  668. /// <param name="browser">The ChromiumWebBrowser instance this method extends.</param>
  669. public static void Stop(this IChromiumWebBrowserBase browser)
  670. {
  671. browser.BrowserCore.Stop();
  672. }
  673. /// <summary>
  674. /// Stops loading the current page.
  675. /// </summary>
  676. /// <param name="browser">The IBrowser instance this method extends.</param>
  677. public static void Stop(this IBrowser browser)
  678. {
  679. browser.ThrowExceptionIfBrowserNull();
  680. browser.StopLoad();
  681. }
  682. /// <summary>
  683. /// Navigates back, must check <see cref="IChromiumWebBrowserBase.CanGoBack"/> before calling this method.
  684. /// </summary>
  685. /// <param name="browser">The ChromiumWebBrowser instance this method extends.</param>
  686. public static void Back(this IChromiumWebBrowserBase browser)
  687. {
  688. browser.BrowserCore.Back();
  689. }
  690. /// <summary>
  691. /// Navigates back, must check <see cref="IBrowser.CanGoBack"/> before calling this method.
  692. /// </summary>
  693. /// <param name="browser">The IBrowser instance this method extends.</param>
  694. public static void Back(this IBrowser browser)
  695. {
  696. browser.ThrowExceptionIfBrowserNull();
  697. browser.GoBack();
  698. }
  699. /// <summary>
  700. /// Navigates forward, must check <see cref="IChromiumWebBrowserBase.CanGoForward"/> before calling this method.
  701. /// </summary>
  702. /// <param name="browser">The ChromiumWebBrowser instance this method extends.</param>
  703. public static void Forward(this IChromiumWebBrowserBase browser)
  704. {
  705. browser.BrowserCore.Forward();
  706. }
  707. /// <summary>
  708. /// Navigates forward, must check <see cref="IBrowser.CanGoForward"/> before calling this method.
  709. /// </summary>
  710. /// <param name="browser">The IBrowser instance this method extends.</param>
  711. public static void Forward(this IBrowser browser)
  712. {
  713. browser.ThrowExceptionIfBrowserNull();
  714. browser.GoForward();
  715. }
  716. /// <summary>
  717. /// Reloads the page being displayed. This method will use data from the browser's cache, if available.
  718. /// </summary>
  719. /// <param name="browser">The ChromiumWebBrowser instance this method extends.</param>
  720. public static void Reload(this IChromiumWebBrowserBase browser)
  721. {
  722. browser.Reload(false);
  723. }
  724. /// <summary>
  725. /// Reloads the page being displayed, optionally ignoring the cache (which means the whole page including all .css, .js etc.
  726. /// resources will be re-fetched).
  727. /// </summary>
  728. /// <param name="browser">The ChromiumWebBrowser instance this method extends.</param>
  729. /// <param name="ignoreCache"><c>true</c> A reload is performed ignoring browser cache; <c>false</c> A reload is performed using
  730. /// files from the browser cache, if available.</param>
  731. public static void Reload(this IChromiumWebBrowserBase browser, bool ignoreCache)
  732. {
  733. browser.BrowserCore.Reload(ignoreCache);
  734. }
  735. /// <summary>
  736. /// Reloads the page being displayed, optionally ignoring the cache (which means the whole page including all .css, .js etc.
  737. /// resources will be re-fetched).
  738. /// </summary>
  739. /// <param name="browser">The IBrowser instance this method extends.</param>
  740. /// <param name="ignoreCache"><c>true</c> A reload is performed ignoring browser cache; <c>false</c> A reload is performed using
  741. /// files from the browser cache, if available.</param>
  742. public static void Reload(this IBrowser browser, bool ignoreCache = false)
  743. {
  744. browser.ThrowExceptionIfBrowserNull();
  745. browser.Reload(ignoreCache);
  746. }
  747. /// <summary>
  748. /// Gets the default cookie manager associated with the <see cref="IChromiumWebBrowserBase"/> instance.
  749. /// </summary>
  750. /// <exception cref="Exception">Thrown when an exception error condition occurs.</exception>
  751. /// <param name="browser">The ChromiumWebBrowser instance this method extends.</param>
  752. /// <param name="callback">(Optional) If not null it will be executed asynchronously on the CEF IO thread after the manager's
  753. /// storage has been initialized.</param>
  754. /// <returns>
  755. /// Cookie Manager.
  756. /// </returns>
  757. public static ICookieManager GetCookieManager(this IChromiumWebBrowserBase browser, ICompletionCallback callback = null)
  758. {
  759. var host = browser.GetBrowserHost();
  760. ThrowExceptionIfBrowserHostNull(host);
  761. var requestContext = host.RequestContext;
  762. if (requestContext == null)
  763. {
  764. throw new Exception("RequestContext is null, unable to obtain cookie manager");
  765. }
  766. return requestContext.GetCookieManager(callback);
  767. }
  768. /// <summary>
  769. /// Asynchronously gets the current Zoom Level.
  770. /// </summary>
  771. /// <param name="cefBrowser">The ChromiumWebBrowser instance this method extends.</param>
  772. /// <returns>
  773. /// An asynchronous result that yields the zoom level.
  774. /// </returns>
  775. public static Task<double> GetZoomLevelAsync(this IBrowser cefBrowser)
  776. {
  777. var host = cefBrowser.GetHost();
  778. ThrowExceptionIfBrowserHostNull(host);
  779. return host.GetZoomLevelAsync();
  780. }
  781. /// <summary>
  782. /// Asynchronously gets the current Zoom Level.
  783. /// </summary>
  784. /// <param name="browser">the ChromiumWebBrowser instance.</param>
  785. /// <returns>
  786. /// An asynchronous result that yields the zoom level.
  787. /// </returns>
  788. public static Task<double> GetZoomLevelAsync(this IChromiumWebBrowserBase browser)
  789. {
  790. return browser.BrowserCore.GetZoomLevelAsync();
  791. }
  792. /// <summary>
  793. /// Change the ZoomLevel to the specified value. Can be set to 0.0 to clear the zoom level.
  794. /// </summary>
  795. /// <remarks>
  796. /// If called on the CEF UI thread the change will be applied immediately. Otherwise, the change will be applied asynchronously
  797. /// on the CEF UI thread. The CEF UI thread is different to the WPF/WinForms UI Thread.
  798. /// </remarks>
  799. /// <param name="cefBrowser">The ChromiumWebBrowser instance this method extends.</param>
  800. /// <param name="zoomLevel">zoom level.</param>
  801. public static void SetZoomLevel(this IBrowser cefBrowser, double zoomLevel)
  802. {
  803. cefBrowser.ThrowExceptionIfBrowserNull();
  804. var host = cefBrowser.GetHost();
  805. ThrowExceptionIfBrowserHostNull(host);
  806. host.SetZoomLevel(zoomLevel);
  807. }
  808. /// <summary>
  809. /// Change the ZoomLevel to the specified value. Can be set to 0.0 to clear the zoom level.
  810. /// </summary>
  811. /// <remarks>
  812. /// If called on the CEF UI thread the change will be applied immediately. Otherwise, the change will be applied asynchronously
  813. /// on the CEF UI thread. The CEF UI thread is different to the WPF/WinForms UI Thread.
  814. /// </remarks>
  815. /// <param name="browser">The ChromiumWebBrowser instance this method extends.</param>
  816. /// <param name="zoomLevel">zoom level.</param>
  817. public static void SetZoomLevel(this IChromiumWebBrowserBase browser, double zoomLevel)
  818. {
  819. browser.BrowserCore.SetZoomLevel(zoomLevel);
  820. }
  821. /// <summary>
  822. /// Search for text within the current page.
  823. /// </summary>
  824. /// <param name="cefBrowser">The ChromiumWebBrowser instance this method extends.</param>
  825. /// <param name="searchText">search text.</param>
  826. /// <param name="forward">indicates whether to search forward or backward within the page.</param>
  827. /// <param name="matchCase">indicates whether the search should be case-sensitive.</param>
  828. /// <param name="findNext">indicates whether this is the first request or a follow-up.</param>
  829. public static void Find(this IBrowser cefBrowser, string searchText, bool forward, bool matchCase, bool findNext)
  830. {
  831. var host = cefBrowser.GetHost();
  832. ThrowExceptionIfBrowserHostNull(host);
  833. host.Find(searchText, forward, matchCase, findNext);
  834. }
  835. /// <summary>
  836. /// Search for text within the current page.
  837. /// </summary>
  838. /// <param name="browser">The ChromiumWebBrowser instance this method extends.</param>
  839. /// <param name="searchText">search text.</param>
  840. /// <param name="forward">indicates whether to search forward or backward within the page.</param>
  841. /// <param name="matchCase">indicates whether the search should be case-sensitive.</param>
  842. /// <param name="findNext">indicates whether this is the first request or a follow-up.</param>
  843. public static void Find(this IChromiumWebBrowserBase browser, string searchText, bool forward, bool matchCase, bool findNext)
  844. {
  845. var cefBrowser = browser.BrowserCore;
  846. cefBrowser.ThrowExceptionIfBrowserNull();
  847. cefBrowser.Find(searchText, forward, matchCase, findNext);
  848. }
  849. /// <summary>
  850. /// Cancel all searches that are currently going on.
  851. /// </summary>
  852. /// <param name="cefBrowser">The ChromiumWebBrowser instance this method extends.</param>
  853. /// <param name="clearSelection">clear the current search selection.</param>
  854. public static void StopFinding(this IBrowser cefBrowser, bool clearSelection)
  855. {
  856. cefBrowser.ThrowExceptionIfBrowserNull();
  857. var host = cefBrowser.GetHost();
  858. ThrowExceptionIfBrowserHostNull(host);
  859. host.StopFinding(clearSelection);
  860. }
  861. /// <summary>
  862. /// Cancel all searches that are currently going on.
  863. /// </summary>
  864. /// <param name="browser">The ChromiumWebBrowser instance this method extends.</param>
  865. /// <param name="clearSelection">clear the current search selection.</param>
  866. public static void StopFinding(this IChromiumWebBrowserBase browser, bool clearSelection)
  867. {
  868. browser.BrowserCore.StopFinding(clearSelection);
  869. }
  870. /// <summary>
  871. /// Opens a Print Dialog which if used (can be user cancelled) will print the browser contents.
  872. /// </summary>
  873. /// <param name="cefBrowser">The ChromiumWebBrowser instance this method extends.</param>
  874. public static void Print(this IBrowser cefBrowser)
  875. {
  876. var host = cefBrowser.GetHost();
  877. ThrowExceptionIfBrowserHostNull(host);
  878. host.Print();
  879. }
  880. /// <summary>
  881. /// Asynchronously prints the current browser contents to the PDF file specified. The caller is responsible for deleting the file
  882. /// when done.
  883. /// </summary>
  884. /// <param name="cefBrowser">The <see cref="IBrowser"/> object this method extends.</param>
  885. /// <param name="path">Output file location.</param>
  886. /// <param name="settings">(Optional) Print Settings.</param>
  887. /// <returns>
  888. /// A task that represents the asynchronous print operation. The result is true on success or false on failure to generate the
  889. /// Pdf.
  890. /// </returns>
  891. public static Task<bool> PrintToPdfAsync(this IBrowser cefBrowser, string path, PdfPrintSettings settings = null)
  892. {
  893. var host = cefBrowser.GetHost();
  894. ThrowExceptionIfBrowserHostNull(host);
  895. var callback = new TaskPrintToPdfCallback();
  896. host.PrintToPdf(path, settings, callback);
  897. return callback.Task;
  898. }
  899. /// <summary>
  900. /// Opens a Print Dialog which if used (can be user cancelled) will print the browser contents.
  901. /// </summary>
  902. /// <param name="browser">The ChromiumWebBrowser instance this method extends.</param>
  903. public static void Print(this IChromiumWebBrowserBase browser)
  904. {
  905. var cefBrowser = browser.BrowserCore;
  906. cefBrowser.ThrowExceptionIfBrowserNull();
  907. cefBrowser.Print();
  908. }
  909. /// <summary>
  910. /// Asynchronously prints the current browser contents to the PDF file specified. The caller is responsible for deleting the file
  911. /// when done.
  912. /// </summary>
  913. /// <param name="browser">The ChromiumWebBrowser instance this method extends.</param>
  914. /// <param name="path">Output file location.</param>
  915. /// <param name="settings">(Optional) Print Settings.</param>
  916. /// <returns>
  917. /// A task that represents the asynchronous print operation. The result is true on success or false on failure to generate the
  918. /// Pdf.
  919. /// </returns>
  920. public static Task<bool> PrintToPdfAsync(this IChromiumWebBrowserBase browser, string path, PdfPrintSettings settings = null)
  921. {
  922. return browser.BrowserCore.PrintToPdfAsync(path, settings);
  923. }
  924. /// <summary>
  925. /// Open developer tools in its own window.
  926. /// </summary>
  927. /// <param name="cefBrowser">The ChromiumWebBrowser instance this method extends.</param>
  928. /// <param name="windowInfo">(Optional) window info used for showing dev tools.</param>
  929. /// <param name="inspectElementAtX">(Optional) x coordinate (used for inspectElement)</param>
  930. /// <param name="inspectElementAtY">(Optional) y coordinate (used for inspectElement)</param>
  931. public static void ShowDevTools(this IBrowser cefBrowser, IWindowInfo windowInfo = null, int inspectElementAtX = 0, int inspectElementAtY = 0)
  932. {
  933. var host = cefBrowser.GetHost();
  934. ThrowExceptionIfBrowserHostNull(host);
  935. host.ShowDevTools(windowInfo, inspectElementAtX, inspectElementAtY);
  936. }
  937. /// <summary>
  938. /// Open developer tools in its own window.
  939. /// </summary>
  940. /// <param name="browser">The ChromiumWebBrowser instance this method extends.</param>
  941. /// <param name="windowInfo">(Optional) window info used for showing dev tools.</param>
  942. /// <param name="inspectElementAtX">(Optional) x coordinate (used for inspectElement)</param>
  943. /// <param name="inspectElementAtY">(Optional) y coordinate (used for inspectElement)</param>
  944. public static void ShowDevTools(this IChromiumWebBrowserBase browser, IWindowInfo windowInfo = null, int inspectElementAtX = 0, int inspectElementAtY = 0)
  945. {
  946. browser.BrowserCore.ShowDevTools(windowInfo, inspectElementAtX, inspectElementAtY);
  947. }
  948. /// <summary>
  949. /// Explicitly close the developer tools window if one exists for this browser instance.
  950. /// </summary>
  951. /// <param name="cefBrowser">The ChromiumWebBrowser instance this method extends.</param>
  952. public static void CloseDevTools(this IBrowser cefBrowser)
  953. {
  954. var host = cefBrowser.GetHost();
  955. ThrowExceptionIfBrowserHostNull(host);
  956. host.CloseDevTools();
  957. }
  958. /// <summary>
  959. /// Explicitly close the developer tools window if one exists for this browser instance.
  960. /// </summary>
  961. /// <param name="browser">The ChromiumWebBrowser instance this method extends.</param>
  962. public static void CloseDevTools(this IChromiumWebBrowserBase browser)
  963. {
  964. browser.BrowserCore.CloseDevTools();
  965. }
  966. /// <summary>
  967. /// If a misspelled word is currently selected in an editable node calling this method will replace it with the specified word.
  968. /// </summary>
  969. /// <param name="cefBrowser">The ChromiumWebBrowser instance this method extends.</param>
  970. /// <param name="word">The new word that will replace the currently selected word.</param>
  971. public static void ReplaceMisspelling(this IBrowser cefBrowser, string word)
  972. {
  973. var host = cefBrowser.GetHost();
  974. ThrowExceptionIfBrowserHostNull(host);
  975. host.ReplaceMisspelling(word);
  976. }
  977. /// <summary>
  978. /// If a misspelled word is currently selected in an editable node calling this method will replace it with the specified word.
  979. /// </summary>
  980. /// <param name="browser">The ChromiumWebBrowser instance this method extends.</param>
  981. /// <param name="word">The new word that will replace the currently selected word.</param>
  982. public static void ReplaceMisspelling(this IChromiumWebBrowserBase browser, string word)
  983. {
  984. browser.BrowserCore.ReplaceMisspelling(word);
  985. }
  986. /// <summary>
  987. /// Add the specified word to the spelling dictionary.
  988. /// </summary>
  989. /// <param name="cefBrowser">The ChromiumWebBrowser instance this method extends.</param>
  990. /// <param name="word">The new word that will be added to the dictionary.</param>
  991. public static void AddWordToDictionary(this IBrowser cefBrowser, string word)
  992. {
  993. var host = cefBrowser.GetHost();
  994. ThrowExceptionIfBrowserHostNull(host);
  995. host.AddWordToDictionary(word);
  996. }
  997. /// <summary>
  998. /// Shortcut method to get the browser IBrowserHost.
  999. /// </summary>
  1000. /// <param name="browser">The ChromiumWebBrowser instance this method extends.</param>
  1001. /// <returns>
  1002. /// browserHost or null.
  1003. /// </returns>
  1004. public static IBrowserHost GetBrowserHost(this IChromiumWebBrowserBase browser)
  1005. {
  1006. var cefBrowser = browser.BrowserCore;
  1007. return cefBrowser == null ? null : cefBrowser.GetHost();
  1008. }
  1009. /// <summary>
  1010. /// Add the specified word to the spelling dictionary.
  1011. /// </summary>
  1012. /// <param name="browser">The ChromiumWebBrowser instance this method extends.</param>
  1013. /// <param name="word">The new word that will be added to the dictionary.</param>
  1014. public static void AddWordToDictionary(this IChromiumWebBrowserBase browser, string word)
  1015. {
  1016. browser.BrowserCore.AddWordToDictionary(word);
  1017. }
  1018. /// <summary>
  1019. /// Send a mouse wheel event to the browser.
  1020. /// </summary>
  1021. /// <param name="browser">The ChromiumWebBrowser instance this method extends.</param>
  1022. /// <param name="x">The x coordinate relative to upper-left corner of view.</param>
  1023. /// <param name="y">The y coordinate relative to upper-left corner of view.</param>
  1024. /// <param name="deltaX">The delta x coordinate.</param>
  1025. /// <param name="deltaY">The delta y coordinate.</param>
  1026. /// <param name="modifiers">The modifiers.</param>
  1027. public static void SendMouseWheelEvent(this IChromiumWebBrowserBase browser, int x, int y, int deltaX, int deltaY, CefEventFlags modifiers)
  1028. {
  1029. browser.BrowserCore.SendMouseWheelEvent(x, y, deltaX, deltaY, modifiers);
  1030. }
  1031. /// <summary>
  1032. /// Send a mouse wheel event to the browser.
  1033. /// </summary>
  1034. /// <param name="browser">The ChromiumWebBrowser instance this method extends.</param>
  1035. /// <param name="x">The x coordinate relative to upper-left corner of view.</param>
  1036. /// <param name="y">The y coordinate relative to upper-left corner of view.</param>
  1037. /// <param name="deltaX">The delta x coordinate.</param>
  1038. /// <param name="deltaY">The delta y coordinate.</param>
  1039. /// <param name="modifiers">The modifiers.</param>
  1040. public static void SendMouseWheelEvent(this IBrowser browser, int x, int y, int deltaX, int deltaY, CefEventFlags modifiers)
  1041. {
  1042. browser.ThrowExceptionIfBrowserNull();
  1043. var host = browser.GetHost();
  1044. ThrowExceptionIfBrowserHostNull(host);
  1045. host.SendMouseWheelEvent(new MouseEvent(x, y, modifiers), deltaX, deltaY);
  1046. }
  1047. /// <summary>
  1048. /// Send a mouse wheel event to the browser.
  1049. /// </summary>
  1050. /// <param name="host">browserHost.</param>
  1051. /// <param name="x">The x coordinate relative to upper-left corner of view.</param>
  1052. /// <param name="y">The y coordinate relative to upper-left corner of view.</param>
  1053. /// <param name="deltaX">The delta x coordinate.</param>
  1054. /// <param name="deltaY">The delta y coordinate.</param>
  1055. /// <param name="modifiers">The modifiers.</param>
  1056. public static void SendMouseWheelEvent(this IBrowserHost host, int x, int y, int deltaX, int deltaY, CefEventFlags modifiers)
  1057. {
  1058. ThrowExceptionIfBrowserHostNull(host);
  1059. host.SendMouseWheelEvent(new MouseEvent(x, y, modifiers), deltaX, deltaY);
  1060. }
  1061. /// <summary>
  1062. /// Send a mouse click event to the browser.
  1063. /// </summary>
  1064. /// <param name="host">browserHost.</param>
  1065. /// <param name="x">The x coordinate relative to upper-left corner of view.</param>
  1066. /// <param name="y">The y coordinate relative to upper-left corner of view.</param>
  1067. /// <param name="mouseButtonType">Type of the mouse button.</param>
  1068. /// <param name="mouseUp">True to mouse up.</param>
  1069. /// <param name="clickCount">Number of clicks.</param>
  1070. /// <param name="modifiers">The modifiers.</param>
  1071. public static void SendMouseClickEvent(this IBrowserHost host, int x, int y, MouseButtonType mouseButtonType, bool mouseUp, int clickCount, CefEventFlags modifiers)
  1072. {
  1073. ThrowExceptionIfBrowserHostNull(host);
  1074. host.SendMouseClickEvent(new MouseEvent(x, y, modifiers), mouseButtonType, mouseUp, clickCount);
  1075. }
  1076. /// <summary>
  1077. /// Send a mouse move event to the browser.
  1078. /// </summary>
  1079. /// <param name="host">browserHost.</param>
  1080. /// <param name="x">The x coordinate relative to upper-left corner of view.</param>
  1081. /// <param name="y">The y coordinate relative to upper-left corner of view.</param>
  1082. /// <param name="mouseLeave">mouse leave.</param>
  1083. /// <param name="modifiers">The modifiers.</param>
  1084. public static void SendMouseMoveEvent(this IBrowserHost host, int x, int y, bool mouseLeave, CefEventFlags modifiers)
  1085. {
  1086. ThrowExceptionIfBrowserHostNull(host);
  1087. host.SendMouseMoveEvent(new MouseEvent(x, y, modifiers), mouseLeave);
  1088. }
  1089. /// <summary>
  1090. /// Evaluate Javascript in the context of the MainFrame of the ChromiumWebBrowser. The script will be executed
  1091. /// asynchronously and the method returns a Task encapsulating the response from the Javascript. The result of the script execution
  1092. /// in javascript is Promise.resolve so even no promise values will be treated as a promise. Your javascript should return a value.
  1093. /// The javascript will be wrapped in an Immediately Invoked Function Expression.
  1094. /// When the promise either trigger then/catch this returned Task will be completed.
  1095. /// </summary>
  1096. /// <exception cref="ArgumentOutOfRangeException">Thrown when one or more arguments are outside the required range.</exception>
  1097. /// <param name="chromiumWebBrowser">The ChromiumWebBrowser instance this method extends.</param>
  1098. /// <param name="script">The Javascript code that should be executed.</param>
  1099. /// <param name="timeout">(Optional) The timeout after which the Javascript code execution should be aborted.</param>
  1100. /// <returns>
  1101. /// <see cref="Task{JavascriptResponse}"/> that can be awaited to perform the script execution.
  1102. /// </returns>
  1103. public static Task<JavascriptResponse> EvaluateScriptAsPromiseAsync(this IWebBrowser chromiumWebBrowser, string script, TimeSpan? timeout = null)
  1104. {
  1105. var jsbSettings = chromiumWebBrowser.JavascriptObjectRepository.Settings;
  1106. var promiseHandlerScript = GetPromiseHandlerScript(script, jsbSettings.JavascriptBindingApiGlobalObjectName);
  1107. return chromiumWebBrowser.EvaluateScriptAsync(promiseHandlerScript, timeout: timeout, useImmediatelyInvokedFuncExpression: true);
  1108. }
  1109. /// <summary>
  1110. /// Evaluate Javascript in the context of this Browsers Main Frame. The script will be executed
  1111. /// asynchronously and the method returns a Task encapsulating the response from the Javascript. The result of the script execution
  1112. /// in javascript is Promise.resolve so even no promise values will be treated as a promise. Your javascript should return a value.
  1113. /// The javascript will be wrapped in an Immediately Invoked Function Expression.
  1114. /// When the promise either trigger then/catch this returned Task will be completed.
  1115. /// </summary>
  1116. /// <exception cref="ArgumentOutOfRangeException">Thrown when one or more arguments are outside the required range.</exception>
  1117. /// <param name="browser">The IBrowser instance this method extends.</param>
  1118. /// <param name="script">The Javascript code that should be executed.</param>
  1119. /// <param name="timeout">(Optional) The timeout after which the Javascript code execution should be aborted.</param>
  1120. /// <returns>
  1121. /// <see cref="Task{JavascriptResponse}"/> that can be awaited to perform the script execution.
  1122. /// </returns>
  1123. public static Task<JavascriptResponse> EvaluateScriptAsPromiseAsync(this IBrowser browser, string script, TimeSpan? timeout = null)
  1124. {
  1125. var promiseHandlerScript = GetPromiseHandlerScript(script, null);
  1126. return browser.EvaluateScriptAsync(promiseHandlerScript, timeout: timeout, useImmediatelyInvokedFuncExpression: true);
  1127. }
  1128. /// <summary>
  1129. /// Evaluate Javascript in the context of this Browsers Main Frame. The script will be executed
  1130. /// asynchronously and the method returns a Task encapsulating the response from the Javascript. The result of the script execution
  1131. /// in javascript is Promise.resolve so even no promise values will be treated as a promise. Your javascript should return a value.
  1132. /// The javascript will be wrapped in an Immediately Invoked Function Expression.
  1133. /// When the promise either trigger then/catch this returned Task will be completed.
  1134. /// </summary>
  1135. /// <exception cref="ArgumentOutOfRangeException">Thrown when one or more arguments are outside the required range.</exception>
  1136. /// <param name="frame">The <seealso cref="IFrame"/> instance this method extends.</param>
  1137. /// <param name="script">The Javascript code that should be executed.</param>
  1138. /// <param name="timeout">(Optional) The timeout after which the Javascript code execution should be aborted.</param>
  1139. /// <param name="javascriptBindingApiGlobalObjectName">
  1140. /// Only required if a custom value was specified for <see cref="JavascriptBinding.JavascriptBindingSettings.JavascriptBindingApiGlobalObjectName"/>
  1141. /// then this param must match that value. Otherwise exclude passing a value for this param or pass in null.
  1142. /// </param>
  1143. /// <returns>
  1144. /// <see cref="Task{JavascriptResponse}"/> that can be awaited to perform the script execution.
  1145. /// </returns>
  1146. public static Task<JavascriptResponse> EvaluateScriptAsPromiseAsync(this IFrame frame, string script, TimeSpan? timeout = null, string javascriptBindingApiGlobalObjectName = null)
  1147. {
  1148. var promiseHandlerScript = GetPromiseHandlerScript(script, javascriptBindingApiGlobalObjectName);
  1149. return frame.EvaluateScriptAsync(promiseHandlerScript, timeout: timeout, useImmediatelyInvokedFuncExpression: true);
  1150. }
  1151. private static string GetPromiseHandlerScript(string script, string javascriptBindingApiGlobalObjectName)
  1152. {
  1153. var internalJsFunctionName = "cefSharp.sendEvalScriptResponse";
  1154. //If the user chose to customise the name of the object CefSharp
  1155. //creates in Javascript then we'll workout what the name should be.
  1156. if (!string.IsNullOrWhiteSpace(javascriptBindingApiGlobalObjectName))
  1157. {
  1158. internalJsFunctionName = javascriptBindingApiGlobalObjectName;
  1159. if (char.IsLower(internalJsFunctionName[0]))
  1160. {
  1161. internalJsFunctionName += ".sendEvalScriptResponse";
  1162. }
  1163. else
  1164. {
  1165. internalJsFunctionName += ".SendEvalScriptResponse";
  1166. }
  1167. }
  1168. var promiseHandlerScript = "let innerImmediatelyInvokedFuncExpression = (async function() { " + script + " })(); Promise.resolve(innerImmediatelyInvokedFuncExpression).then((val) => " + internalJsFunctionName + "(cefSharpInternalCallbackId, true, val, false)).catch ((reason) => " + internalJsFunctionName + "(cefSharpInternalCallbackId, false, String(reason), false)); return 'CefSharpDefEvalScriptRes';";
  1169. return promiseHandlerScript;
  1170. }
  1171. /// <summary>
  1172. /// Evaluate Javascript in the context of this Browsers Main Frame. The script will be executed
  1173. /// asynchronously and the method returns a Task encapsulating the response from the Javascript
  1174. /// </summary>
  1175. /// <exception cref="ArgumentOutOfRangeException">Thrown when one or more arguments are outside the required range.</exception>
  1176. /// <param name="browser">The ChromiumWebBrowser instance this method extends.</param>
  1177. /// <param name="script">The Javascript code that should be executed.</param>
  1178. /// <param name="timeout">(Optional) The timeout after which the Javascript code execution should be aborted.</param>
  1179. /// <param name="useImmediatelyInvokedFuncExpression">When true the script is wrapped in a self executing function.
  1180. /// Make sure to use a return statement in your javascript. e.g. (function () { return 42; })();
  1181. /// When false don't include a return statement e.g. 42;
  1182. /// </param>
  1183. /// <returns>
  1184. /// <see cref="Task{JavascriptResponse}"/> that can be awaited to obtain the result of the script execution.
  1185. /// </returns>
  1186. public static Task<JavascriptResponse> EvaluateScriptAsync(this IChromiumWebBrowserBase browser, string script, TimeSpan? timeout = null, bool useImmediatelyInvokedFuncExpression = false)
  1187. {
  1188. if (browser is IWebBrowser b)
  1189. {
  1190. if (b.CanExecuteJavascriptInMainFrame == false)
  1191. {
  1192. ThrowExceptionIfCanExecuteJavascriptInMainFrameFalse();
  1193. }
  1194. }
  1195. return browser.BrowserCore.EvaluateScriptAsync(script, timeout, useImmediatelyInvokedFuncExpression);
  1196. }
  1197. /// <summary>
  1198. /// Evaluate some Javascript code in the context of the MainFrame of the ChromiumWebBrowser. The script will be executed
  1199. /// asynchronously and the method returns a Task encapsulating the response from the Javascript
  1200. /// </summary>
  1201. /// <exception cref="ArgumentOutOfRangeException">Thrown when one or more arguments are outside the required range.</exception>
  1202. /// <param name="browser">The IBrowser instance this method extends.</param>
  1203. /// <param name="script">The Javascript code that should be executed.</param>
  1204. /// <param name="timeout">(Optional) The timeout after which the Javascript code execution should be aborted.</param>
  1205. /// <param name="useImmediatelyInvokedFuncExpression">When true the script is wrapped in a self executing function.
  1206. /// Make sure to use a return statement in your javascript. e.g. (function () { return 42; })();
  1207. /// When false don't include a return statement e.g. 42;
  1208. /// </param>
  1209. /// <returns>
  1210. /// <see cref="Task{JavascriptResponse}"/> that can be awaited to obtain the result of the script execution.
  1211. /// </returns>
  1212. public static Task<JavascriptResponse> EvaluateScriptAsync(this IBrowser browser, string script, TimeSpan? timeout = null, bool useImmediatelyInvokedFuncExpression = false)
  1213. {
  1214. if (timeout.HasValue && timeout.Value.TotalMilliseconds > UInt32.MaxValue)
  1215. {
  1216. throw new ArgumentOutOfRangeException("timeout", "Timeout greater than Maximum allowable value of " + UInt32.MaxValue);
  1217. }
  1218. browser.ThrowExceptionIfBrowserNull();
  1219. using (var frame = browser.MainFrame)
  1220. {
  1221. ThrowExceptionIfFrameNull(frame);
  1222. return frame.EvaluateScriptAsync(script, timeout: timeout, useImmediatelyInvokedFuncExpression: useImmediatelyInvokedFuncExpression);
  1223. }
  1224. }
  1225. /// <summary>
  1226. /// Evaluate some Javascript code in the context of this WebBrowser. The script will be executed asynchronously and the method
  1227. /// returns a Task encapsulating the response from the Javascript This simple helper extension will encapsulate params in single
  1228. /// quotes (unless int, uint, etc)
  1229. /// </summary>
  1230. /// <param name="browser">The ChromiumWebBrowser instance this method extends.</param>
  1231. /// <param name="methodName">The javascript method name to execute.</param>
  1232. /// <param name="args">the arguments to be passed as params to the method.</param>
  1233. /// <returns>
  1234. /// <see cref="Task{JavascriptResponse}"/> that can be awaited to obtain the result of the script execution.
  1235. /// </returns>
  1236. public static Task<JavascriptResponse> EvaluateScriptAsync(this IChromiumWebBrowserBase browser, string methodName, params object[] args)
  1237. {
  1238. return browser.EvaluateScriptAsync(null, methodName, args);
  1239. }
  1240. /// <summary>
  1241. /// Evaluate Javascript code in the context of this WebBrowser using the specified timeout. The script will be executed
  1242. /// asynchronously and the method returns a Task encapsulating the response from the Javascript This simple helper extension will
  1243. /// encapsulate params in single quotes (unless int, uint, etc).
  1244. /// </summary>
  1245. /// <param name="browser">The ChromiumWebBrowser instance this method extends.</param>
  1246. /// <param name="timeout">The timeout after which the Javascript code execution should be aborted.</param>
  1247. /// <param name="methodName">The javascript method name to execute.</param>
  1248. /// <param name="args">the arguments to be passed as params to the method. Args are encoded using
  1249. /// <see cref="EncodeScriptParam"/>, you can provide a custom implementation if you require a custom implementation.</param>
  1250. /// <returns>
  1251. /// <see cref="Task{JavascriptResponse}"/> that can be awaited to perform the script execution.
  1252. /// </returns>
  1253. public static Task<JavascriptResponse> EvaluateScriptAsync(this IChromiumWebBrowserBase browser, TimeSpan? timeout, string methodName, params object[] args)
  1254. {
  1255. var script = GetScriptForJavascriptMethodWithArgs(methodName, args);
  1256. return browser.EvaluateScriptAsync(script, timeout);
  1257. }
  1258. /// <summary>
  1259. /// An IWebBrowser extension method that sets the <see cref="IWebBrowserInternal.HasParent"/>
  1260. /// property used when passing a ChromiumWebBrowser instance to <see cref="ILifeSpanHandler.OnBeforePopup"/>
  1261. /// </summary>
  1262. /// <param name="browser">The ChromiumWebBrowser instance this method extends.</param>
  1263. public static void SetAsPopup(this IWebBrowser browser)
  1264. {
  1265. var internalBrowser = (IWebBrowserInternal)browser;
  1266. internalBrowser.HasParent = true;
  1267. }
  1268. /// <summary>
  1269. /// Function used to encode the params passed to <see cref="ExecuteScriptAsync(IWebBrowser, string, object[])"/>,
  1270. /// <see cref="EvaluateScriptAsync(IWebBrowser, string, object[])"/> and
  1271. /// <see cref="EvaluateScriptAsync(IWebBrowser, TimeSpan?, string, object[])"/>
  1272. /// Provide your own custom function to perform custom encoding. You can use your choice of JSON encoder here if you should so
  1273. /// choose.
  1274. /// </summary>
  1275. /// <value>
  1276. /// A function delegate that yields a string.
  1277. /// </value>
  1278. public static Func<string, string> EncodeScriptParam { get; set; } = (str) =>
  1279. {
  1280. return str.Replace("\\", "\\\\")
  1281. .Replace("'", "\\'")
  1282. .Replace("\t", "\\t")
  1283. .Replace("\r", "\\r")
  1284. .Replace("\n", "\\n");
  1285. };
  1286. /// <summary>
  1287. /// Checks if the given object is a numerical object.
  1288. /// </summary>
  1289. /// <param name="value">The object to check.</param>
  1290. /// <returns>
  1291. /// True if numeric, otherwise false.
  1292. /// </returns>
  1293. private static bool IsNumeric(this object value)
  1294. {
  1295. return value is sbyte
  1296. || value is byte
  1297. || value is short
  1298. || value is ushort
  1299. || value is int
  1300. || value is uint
  1301. || value is long
  1302. || value is ulong
  1303. || value is float
  1304. || value is double
  1305. || value is decimal;
  1306. }
  1307. /// <summary>
  1308. /// Transforms the methodName and arguments into valid Javascript code. Will encapsulate params in single quotes (unless int,
  1309. /// uint, etc)
  1310. /// </summary>
  1311. /// <param name="methodName">The javascript method name to execute.</param>
  1312. /// <param name="args">the arguments to be passed as params to the method.</param>
  1313. /// <returns>
  1314. /// The Javascript code.
  1315. /// </returns>
  1316. public static string GetScriptForJavascriptMethodWithArgs(string methodName, object[] args)
  1317. {
  1318. var stringBuilder = new StringBuilder();
  1319. stringBuilder.Append(methodName);
  1320. stringBuilder.Append("(");
  1321. if (args.Length > 0)
  1322. {
  1323. for (int i = 0; i < args.Length; i++)
  1324. {
  1325. var obj = args[i];
  1326. if (obj == null)
  1327. {
  1328. stringBuilder.Append("null");
  1329. }
  1330. else if (obj.IsNumeric())
  1331. {
  1332. stringBuilder.Append(Convert.ToString(args[i], CultureInfo.InvariantCulture));
  1333. }
  1334. else if (obj is bool)
  1335. {
  1336. stringBuilder.Append(args[i].ToString().ToLowerInvariant());
  1337. }
  1338. else
  1339. {
  1340. stringBuilder.Append("'");
  1341. stringBuilder.Append(EncodeScriptParam(obj.ToString()));
  1342. stringBuilder.Append("'");
  1343. }
  1344. stringBuilder.Append(", ");
  1345. }
  1346. //Remove the trailing comma
  1347. stringBuilder.Remove(stringBuilder.Length - 2, 2);
  1348. }
  1349. stringBuilder.Append(");");
  1350. return stringBuilder.ToString();
  1351. }
  1352. /// <summary>
  1353. /// Throw exception if frame null.
  1354. /// </summary>
  1355. /// <exception cref="Exception">Thrown when an exception error condition occurs.</exception>
  1356. /// <param name="frame">The <seealso cref="IFrame"/> instance this method extends.</param>
  1357. private static void ThrowExceptionIfFrameNull(IFrame frame)
  1358. {
  1359. if (frame == null)
  1360. {
  1361. throw new Exception(FrameNullExceptionString);
  1362. }
  1363. }
  1364. /// <summary>
  1365. /// An IBrowser extension method that throw exception if browser null.
  1366. /// </summary>
  1367. /// <exception cref="Exception">Thrown when an exception error condition occurs.</exception>
  1368. /// <param name="browser">The ChromiumWebBrowser instance this method extends.</param>
  1369. internal static void ThrowExceptionIfBrowserNull(this IBrowser browser)
  1370. {
  1371. if (browser == null)
  1372. {
  1373. throw new Exception(BrowserNullExceptionString);
  1374. }
  1375. }
  1376. /// <summary>
  1377. /// Throw exception if browser host null.
  1378. /// </summary>
  1379. /// <exception cref="Exception">Thrown when an exception error condition occurs.</exception>
  1380. /// <param name="browserHost">The browser host.</param>
  1381. public static void ThrowExceptionIfBrowserHostNull(IBrowserHost browserHost)
  1382. {
  1383. if (browserHost == null)
  1384. {
  1385. throw new Exception(BrowserHostNullExceptionString);
  1386. }
  1387. }
  1388. /// <summary>
  1389. /// Throw exception if can execute javascript in main frame false.
  1390. /// </summary>
  1391. /// <exception cref="Exception">Thrown when an exception error condition occurs.</exception>
  1392. private static void ThrowExceptionIfCanExecuteJavascriptInMainFrameFalse()
  1393. {
  1394. throw new Exception("Unable to execute javascript at this time, scripts can only be executed within a V8Context. " +
  1395. "Use the IWebBrowser.CanExecuteJavascriptInMainFrame property to guard against this exception. " +
  1396. "See https://github.com/cefsharp/CefSharp/wiki/General-Usage#when-can-i-start-executing-javascript " +
  1397. "for more details on when you can execute javascript. For frames that do not contain Javascript then no " +
  1398. "V8Context will be created. Executing a script once the frame has loaded it's possible to create a V8Context. " +
  1399. "You can use browser.GetMainFrame().ExecuteJavaScriptAsync(script) or browser.GetMainFrame().EvaluateScriptAsync " +
  1400. "to bypass these checks (advanced users only).");
  1401. }
  1402. }
  1403. }