view win/edge.cpp @ 1999:4e808c4cadfb

Win: Add initial support for Microsoft Edge (Chromium) embedding. Only works with Visual Studio currently due to the SDK being a nuget package.
author bsmith@81767d24-ef19-dc11-ae90-00e081727c95
date Thu, 31 Oct 2019 07:01:35 +0000
parents
children 77e43d71eaa7
line wrap: on
line source

/* edge.cpp
 *
 * Allows dw_html_new() to embed a Microsoft Edge (Chromium) browser.
 *
 * Requires Windows 10, 8 or 7 with Microsoft Edge (Chromium) installed.
 * 
 * Only included when BUILD_EDGE is defined, will fall back to embedded IE.
 *
 * Currently only buildable with Visual Studio since it requires the EDGE
 * SDK which is currently distributed as a nuget package. 
 */
#include "dw.h"
#include "webview2.h"

#define _DW_HTML_DATA_NAME (char *)"_dw_edge"

BOOL _dw_edge_detect(VOID)
{
	return TRUE;
}

/******************************* dw_html_action() **************************
 * Implements the functionality of a "Back". "Forward", "Home", "Search",
 * "Refresh", or "Stop" button.
 *
 * hwnd =		Handle to the window hosting the browser object.
 * action =		One of the following:
 *				0 = Move back to the previously viewed web page.
 *				1 = Move forward to the previously viewed web page.
 *				2 = Move to the home page.
 *				3 = Search.
 *				4 = Refresh the page.
 *				5 = Stop the currently loading page.
 *
 * NOTE: EmbedBrowserObject() must have been successfully called once with the
 * specified window, prior to calling this function. You need call
 * EmbedBrowserObject() once only, and then you can make multiple calls to
 * this function to display numerous pages in the specified window.
 */

void _dw_edge_action(HWND hwnd, int action)
{
	IWebView2WebView* webview;

	// Retrieve the browser object's pointer we stored in our window's GWL_USERDATA when
	// we initially attached the browser object to this window.

	webview = *((IWebView2WebView**)dw_window_get_data(hwnd, _DW_HTML_DATA_NAME));
	// We want to get the base address (ie, a pointer) to the IWebBrowser2 object embedded within the browser
	// object, so we can call some of the functions in the former's table.
	if (webview)
	{
		// Ok, now the pointer to our IWebBrowser2 object is in 'webBrowser2', and so its VTable is
		// webBrowser2->lpVtbl.

		// Call the desired function
		switch (action)
		{
			case DW_HTML_GOBACK:
			{
				// Call the IWebBrowser2 object's GoBack function.
				webview->GoBack();
				break;
			}

			case DW_HTML_GOFORWARD:
			{
				// Call the IWebBrowser2 object's GoForward function.
				webview->GoForward();
				break;
			}

			case DW_HTML_GOHOME:
			{
				// Call the IWebBrowser2 object's GoHome function.
				//webview->GoHome();
				break;
			}

			case DW_HTML_SEARCH:
			{
				// Call the IWebBrowser2 object's GoSearch function.
				//webview->GoSearch();
				break;
			}

			case DW_HTML_RELOAD:
			{
				// Call the IWebBrowser2 object's Refresh function.
				webview->Reload();
			}

			case DW_HTML_STOP:
			{
				// Call the IWebBrowser2 object's Stop function.
				//webview->Stop();
			}
		}
	}
}

/******************************* dw_html_raw() ****************************
 * Takes a string containing some HTML BODY, and displays it in the specified
 * window. For example, perhaps you want to display the HTML text of...
 *
 * <P>This is a picture.<P><IMG src="mypic.jpg">
 *
 * hwnd =		Handle to the window hosting the browser object.
 * string =		Pointer to nul-terminated string containing the HTML BODY.
 *				(NOTE: No <BODY></BODY> tags are required in the string).
 *
 * RETURNS: 0 if success, or non-zero if an error.
 *
 * NOTE: EmbedBrowserObject() must have been successfully called once with the
 * specified window, prior to calling this function. You need call
 * EmbedBrowserObject() once only, and then you can make multiple calls to
 * this function to display numerous pages in the specified window.
 */

int _dw_edge_raw(HWND hwnd, LPCWSTR string)
{
	IWebView2WebView* webview;

	// Retrieve the browser object's pointer we stored in our window's GWL_USERDATA when
	// we initially attached the browser object to this window.
	webview = *((IWebView2WebView**)dw_window_get_data(hwnd, _DW_HTML_DATA_NAME));

	if (webview)
	{
		return DW_ERROR_NONE;
	}
	return DW_ERROR_UNKNOWN;
}

/******************************* dw_html_url() ****************************
 * Displays a URL, or HTML file on disk.
 *
 * hwnd =		Handle to the window hosting the browser object.
 * webPageName =	Pointer to nul-terminated name of the URL/file.
 *
 * RETURNS: 0 if success, or non-zero if an error.
 *
 * NOTE: EmbedBrowserObject() must have been successfully called once with the
 * specified window, prior to calling this function. You need call
 * EmbedBrowserObject() once only, and then you can make multiple calls to
 * this function to display numerous pages in the specified window.
 */

int _dw_edge_url(HWND hwnd, LPCWSTR url)
{
	IWebView2WebView * webview;

	// Retrieve the browser object's pointer we stored in our window's GWL_USERDATA when
	// we initially attached the browser object to this window.
	webview = *((IWebView2WebView**)dw_window_get_data(hwnd, _DW_HTML_DATA_NAME));

	if (webview)
	{
		webview->Navigate(url);
		return DW_ERROR_NONE;
	}
	return DW_ERROR_UNKNOWN;
}

/************************** browserWindowProc() *************************
 * Our message handler for our window to host the browser.
 */

LRESULT CALLBACK _edgeWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg)
	{
		case WM_SIZE:
		{
			// Resize the browser object to fit the window
			RECT bounds;
			IWebView2WebView* webview;

			// Retrieve the browser object's pointer we stored in our window's GWL_USERDATA when
			// we initially attached the browser object to this window.
			webview = *((IWebView2WebView**)dw_window_get_data(hWnd, _DW_HTML_DATA_NAME));
			GetClientRect(hWnd, &bounds);
			// Resize WebView to fit the bounds of the parent window
			if(webview)
				webview->put_Bounds(bounds);
			return(0);
		}

		case WM_CREATE:
		{
			// Step 3 - Create a single WebView within the parent window
			// Locate the browser and set up the environment for WebView
			CreateWebView2EnvironmentWithDetails(nullptr, nullptr, nullptr,
				Callback<IWebView2CreateWebView2EnvironmentCompletedHandler>(
					[hWnd](HRESULT result, IWebView2Environment* env) -> HRESULT {

						// Create a WebView, whose parent is the main window hWnd
						env->CreateWebView(hWnd, Callback<IWebView2CreateWebViewCompletedHandler>(
							[hWnd](HRESULT result, IWebView2WebView* webview) -> HRESULT {
								if (webview != nullptr) {
									dw_window_set_data(hWnd, _DW_HTML_DATA_NAME, DW_POINTER(webview));
								}

								// Add a few settings for the webview
								// this is a redundant demo step as they are the default settings values
								IWebView2Settings* Settings;
								webview->get_Settings(&Settings);
								Settings->put_IsScriptEnabled(TRUE);
								Settings->put_AreDefaultScriptDialogsEnabled(TRUE);
								Settings->put_IsWebMessageEnabled(TRUE);

								// Resize WebView to fit the bounds of the parent window
								RECT bounds;
								GetClientRect(hWnd, &bounds);
								webview->put_Bounds(bounds);
								return S_OK;
							}).Get());
						return S_OK;
					}).Get());

			// Success
			return(0);
		}

		case WM_DESTROY:
		{
			// Detach the browser object from this window, and free resources.
			IWebView2WebView* webview;

			// Retrieve the browser object's pointer we stored in our window's GWL_USERDATA when
			// we initially attached the browser object to this window.
			webview = *((IWebView2WebView**)dw_window_get_data(hWnd, _DW_HTML_DATA_NAME));
			if (webview)
			{
				dw_window_set_data(hWnd, _DW_HTML_DATA_NAME, NULL);
				webview->Close();

			}
			return(TRUE);
		}
	}

	return(DefWindowProc(hWnd, uMsg, wParam, lParam));
}