// Copyright (c) 2008-2009 The Chromium Embedded Framework Authors. All rights // reserved. Use of this source code is governed by a BSD-style license that // can be found in the LICENSE file. #include "stdafx.h" #include "cefclient.h" #include "clientplugin.h" #include "cef.h" #include #define MAX_LOADSTRING 100 #define MAX_URL_LENGTH 255 #define BUTTON_WIDTH 72 #define URLBAR_HEIGHT 24 // Define this value to run CEF with messages processed using the current // application's message loop. #define TEST_SINGLE_THREADED_MESSAGE_LOOP // Global Variables: HINSTANCE hInst; // current instance TCHAR szTitle[MAX_LOADSTRING]; // The title bar text TCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name // Forward declarations of functions included in this code module: ATOM MyRegisterClass(HINSTANCE hInstance); BOOL InitInstance(HINSTANCE, int); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM); // Convert a std::string to a std::wstring std::wstring StringToWString(const std::string& s) { std::wstring temp(s.length(),L' '); std::copy(s.begin(), s.end(), temp.begin()); return temp; } // Implementation of the V8 handler class for the "cef.test" extension. class ClientV8ExtensionHandler : public CefThreadSafeBase { public: ClientV8ExtensionHandler() : test_param_(L"An initial string value.") {} virtual ~ClientV8ExtensionHandler() {} // Execute with the specified argument list and return value. Return true if // the method was handled. virtual bool Execute(const std::wstring& name, CefRefPtr object, const CefV8ValueList& arguments, CefRefPtr& retval, std::wstring& exception) { if(name == L"SetTestParam") { // Handle the SetTestParam native function by saving the string argument // into the local member. if(arguments.size() != 1 || !arguments[0]->IsString()) return false; test_param_ = arguments[0]->GetStringValue(); return true; } else if(name == L"GetTestParam") { // Handle the GetTestParam native function by returning the local member // value. retval = CefV8Value::CreateString(test_param_); return true; } else if(name == L"GetTestObject") { // Handle the GetTestObject native function by creating and returning a // new V8 object. retval = CefV8Value::CreateObject(NULL); // Add a string parameter to the new V8 object. retval->SetValue(L"param", CefV8Value::CreateString( L"Retrieving a parameter on a native object succeeded.")); // Add a function to the new V8 object. retval->SetValue(L"GetMessage", CefV8Value::CreateFunction(L"GetMessage", this)); return true; } else if(name == L"GetMessage") { // Handle the GetMessage object function by returning a string. retval = CefV8Value::CreateString( L"Calling a function on a native object succeeded."); return true; } return false; } private: std::wstring test_param_; }; int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); #ifdef TEST_SINGLE_THREADED_MESSAGE_LOOP // Initialize the CEF with messages processed using the current application's // message loop. CefInitialize(false, std::wstring()); #else // Initialize the CEF with messages processed using a separate UI thread. CefInitialize(true, std::wstring()); #endif // Structure providing information about the client plugin. CefPluginInfo plugin_info; plugin_info.display_name = L"Client Plugin"; plugin_info.unique_name = L"client_plugin"; plugin_info.version = L"1, 0, 0, 1"; plugin_info.description = L"My Example Client Plugin"; CefPluginMimeType mime_type; mime_type.mime_type = L"application/x-client-plugin"; mime_type.file_extensions.push_back(L"*"); plugin_info.mime_types.push_back(mime_type); plugin_info.np_getentrypoints = NP_GetEntryPoints; plugin_info.np_initialize = NP_Initialize; plugin_info.np_shutdown = NP_Shutdown; // Register the internal client plugin CefRegisterPlugin(plugin_info); // Register a V8 extension with the below JavaScript code that calls native // methods implemented in ClientV8ExtensionHandler. std::wstring code = L"var cef;" L"if (!cef)" L" cef = {};" L"if (!cef.test)" L" cef.test = {};" L"(function() {" L" cef.test.__defineGetter__('test_param', function() {" L" native function GetTestParam();" L" return GetTestParam();" L" });" L" cef.test.__defineSetter__('test_param', function(b) {" L" native function SetTestParam();" L" if(b) SetTestParam(b);" L" });" L" cef.test.test_object = function() {" L" native function GetTestObject();" L" return GetTestObject();" L" };" L"})();"; CefRegisterExtension(L"v8/test", code, new ClientV8ExtensionHandler()); MSG msg; HACCEL hAccelTable; // Initialize global strings LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); LoadString(hInstance, IDC_CEFCLIENT, szWindowClass, MAX_LOADSTRING); MyRegisterClass(hInstance); // Perform application initialization if (!InitInstance (hInstance, nCmdShow)) { return FALSE; } hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_CEFCLIENT)); // Main message loop while (GetMessage(&msg, NULL, 0, 0)) { #ifdef TEST_SINGLE_THREADED_MESSAGE_LOOP // Allow the CEF to do its message loop processing. CefDoMessageLoopWork(); #endif if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } // Shut down the CEF CefShutdown(); return (int) msg.wParam; } // // FUNCTION: MyRegisterClass() // // PURPOSE: Registers the window class. // // COMMENTS: // // This function and its usage are only necessary if you want this code // to be compatible with Win32 systems prior to the 'RegisterClassEx' // function that was added to Windows 95. It is important to call this // function so that the application will get 'well formed' small icons // associated with it. // ATOM MyRegisterClass(HINSTANCE hInstance) { WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_CEFCLIENT)); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = MAKEINTRESOURCE(IDC_CEFCLIENT); wcex.lpszClassName = szWindowClass; wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); return RegisterClassEx(&wcex); } // // FUNCTION: InitInstance(HINSTANCE, int) // // PURPOSE: Saves instance handle and creates main window // // COMMENTS: // // In this function, we save the instance handle in a global variable and // create and display the main program window. // BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { HWND hWnd; hInst = hInstance; // Store instance handle in our global variable hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); if (!hWnd) { return FALSE; } ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; } // Load a resource of type BINARY bool LoadBinaryResource(int binaryId, DWORD &dwSize, LPBYTE &pBytes) { HRSRC hRes = FindResource(hInst, MAKEINTRESOURCE(binaryId), MAKEINTRESOURCE(256)); if(hRes) { HGLOBAL hGlob = LoadResource(hInst, hRes); if(hGlob) { dwSize = SizeofResource(hInst, hRes); pBytes = (LPBYTE)LockResource(hGlob); if(dwSize > 0 && pBytes) return true; } } return false; } // Implementation of the V8 handler class for the "window.cef_test.Dump" // function. class ClientV8FunctionHandler : public CefThreadSafeBase { public: ClientV8FunctionHandler() {} virtual ~ClientV8FunctionHandler() {} // Execute with the specified argument list and return value. Return true if // the method was handled. virtual bool Execute(const std::wstring& name, CefRefPtr object, const CefV8ValueList& arguments, CefRefPtr& retval, std::wstring& exception) { if(name == L"Dump") { // The "Dump" function will return a human-readable dump of the input // arguments. std::wstringstream stream; size_t i; for(i = 0; i < arguments.size(); ++i) { stream << L"arg[" << i << L"] = "; PrintValue(arguments[i], stream, 0); stream << L"\n"; } retval = CefV8Value::CreateString(stream.str()); return true; } else if(name == L"Call") { // The "Call" function will execute a function to get an object and then // return the result of calling a function belonging to that object. The // first arument is the function that will return an object and the second // argument is the function that will be called on that returned object. int argSize = arguments.size(); if(argSize < 2 || !arguments[0]->IsFunction() || !arguments[1]->IsString()) return false; CefV8ValueList argList; // Execute the function stored in the first argument to retrieve an // object. CefRefPtr objectPtr; if(!arguments[0]->ExecuteFunction(object, argList, objectPtr, exception)) return false; // Verify that the returned value is an object. if(!objectPtr.get() || !objectPtr->IsObject()) return false; // Retrieve the member function specified by name in the second argument // from the object. CefRefPtr funcPtr = objectPtr->GetValue(arguments[1]->GetStringValue()); // Verify that the returned value is a function. if(!funcPtr.get() || !funcPtr->IsFunction()) return false; // Pass any additional arguments on to the member function. for(int i = 2; i < argSize; ++i) argList.push_back(arguments[i]); // Execute the member function. return funcPtr->ExecuteFunction(arguments[0], argList, retval, exception); } return false; } // Simple function for formatted output of a V8 value. void PrintValue(CefRefPtr value, std::wstringstream &stream, int indent) { std::wstringstream indent_stream; for(int i = 0; i < indent; ++i) indent_stream << L" "; std::wstring indent_str = indent_stream.str(); if(value->IsUndefined()) stream << L"(undefined)"; else if(value->IsNull()) stream << L"(null)"; else if(value->IsBool()) stream << L"(bool) " << (value->GetBoolValue() ? L"true" : L"false"); else if(value->IsInt()) stream << L"(int) " << value->GetIntValue(); else if(value->IsDouble()) stream << L"(double) " << value->GetDoubleValue(); else if(value->IsString()) stream << L"(string) " << value->GetStringValue().c_str(); else if(value->IsFunction()) stream << L"(function) " << value->GetFunctionName().c_str(); else if(value->IsArray()) { stream << L"(array) ["; int len = value->GetArrayLength(); for(int i = 0; i < len; ++i) { stream << L"\n " << indent_str.c_str() << i << L" = "; PrintValue(value->GetValue(i), stream, indent+1); } stream << L"\n" << indent_str.c_str() << L"]"; } else if(value->IsObject()) { stream << L"(object) ["; std::vector keys; if(value->GetKeys(keys)) { for(size_t i = 0; i < keys.size(); ++i) { stream << L"\n " << indent_str.c_str() << keys[i].c_str() << L" = "; PrintValue(value->GetValue(keys[i]), stream, indent+1); } } stream << L"\n" << indent_str.c_str() << L"]"; } } }; // Client implementation of the browser handler class class ClientHandler : public CefThreadSafeBase { public: ClientHandler() { m_MainHwnd = NULL; m_BrowserHwnd = NULL; m_EditHwnd = NULL; m_bLoading = false; m_bCanGoBack = false; m_bCanGoForward = false; } ~ClientHandler() { } // Event called before a new window is created. The |parentBrowser| parameter // will point to the parent browser window, if any. The |popup| parameter // will be true if the new window is a popup window. If you create the window // yourself you should populate the window handle member of |createInfo| and // return RV_HANDLED. Otherwise, return RV_CONTINUE and the framework will // create the window. By default, a newly created window will recieve the // same handler as the parent window. To change the handler for the new // window modify the object that |handler| points to. virtual RetVal HandleBeforeCreated(CefRefPtr parentBrowser, CefWindowInfo& createInfo, bool popup, CefRefPtr& handler, std::wstring& url) { return RV_CONTINUE; } // Event called after a new window is created. The return value is currently // ignored. virtual RetVal HandleAfterCreated(CefRefPtr browser) { Lock(); if(!browser->IsPopup()) { // We need to keep the main child window, but not popup windows m_Browser = browser; m_BrowserHwnd = browser->GetWindowHandle(); } Unlock(); return RV_CONTINUE; } // Event called when the address bar changes. The return value is currently // ignored. virtual RetVal HandleAddressChange(CefRefPtr browser, CefRefPtr frame, const std::wstring& url) { if(m_BrowserHwnd == browser->GetWindowHandle() && frame->IsMain()) { // Set the edit window text SetWindowText(m_EditHwnd, url.c_str()); } return RV_CONTINUE; } // Event called when the page title changes. The return value is currently // ignored. virtual RetVal HandleTitleChange(CefRefPtr browser, const std::wstring& title) { // Set the frame window title bar HWND hwnd = browser->GetWindowHandle(); if(!browser->IsPopup()) { // The frame window will be the parent of the browser window hwnd = GetParent(hwnd); } SetWindowText(hwnd, title.c_str()); return RV_CONTINUE; } // Event called before browser navigation. The client has an opportunity to // modify the |request| object if desired. Return RV_HANDLED to cancel // navigation. virtual RetVal HandleBeforeBrowse(CefRefPtr browser, CefRefPtr frame, CefRefPtr request, NavType navType, bool isRedirect) { return RV_CONTINUE; } // Event called when the browser begins loading a page. The |frame| pointer // will be empty if the event represents the overall load status and not the // load status for a particular frame. The return value is currently ignored. virtual RetVal HandleLoadStart(CefRefPtr browser, CefRefPtr frame) { if(!browser->IsPopup() && !frame.get()) { Lock(); // We've just started loading a page m_bLoading = true; m_bCanGoBack = false; m_bCanGoForward = false; Unlock(); } return RV_CONTINUE; } // Event called when the browser is done loading a page. The |frame| pointer // will be empty if the event represents the overall load status and not the // load status for a particular frame. This event will be generated // irrespective of whether the request completes successfully. The return // value is currently ignored. virtual RetVal HandleLoadEnd(CefRefPtr browser, CefRefPtr frame) { if(!browser->IsPopup() && !frame.get()) { Lock(); // We've just finished loading a page m_bLoading = false; m_bCanGoBack = browser->CanGoBack(); m_bCanGoForward = browser->CanGoForward(); Unlock(); } return RV_CONTINUE; } // Called when the browser fails to load a resource. |errorCode| is the // error code number and |failedUrl| is the URL that failed to load. To // provide custom error text assign the text to |errorText| and return // RV_HANDLED. Otherwise, return RV_CONTINUE for the default error text. virtual RetVal HandleLoadError(CefRefPtr browser, CefRefPtr frame, ErrorCode errorCode, const std::wstring& failedUrl, std::wstring& errorText) { if(errorCode == ERR_CACHE_MISS) { // Usually caused by navigating to a page with POST data via back or // forward buttons. errorText = L"Expired Form Data" L"

Expired Form Data

" L"

Your form request has expired. " L"Click reload to re-submit the form data.

" L""; } else { // All other messages. std::wstringstream ss; ss << L"Load Failed" L"

Load Failed

" L"

Load of URL " << failedUrl << L"failed with error code " << static_cast(errorCode) << L".

" L""; errorText = ss.str(); } return RV_HANDLED; } // Event called before a resource is loaded. To allow the resource to load // normally return RV_CONTINUE. To redirect the resource to a new url // populate the |redirectUrl| value and return RV_CONTINUE. To specify // data for the resource return a CefStream object in |resourceStream|, set // 'mimeType| to the resource stream's mime type, and return RV_CONTINUE. // To cancel loading of the resource return RV_HANDLED. virtual RetVal HandleBeforeResourceLoad(CefRefPtr browser, CefRefPtr request, std::wstring& redirectUrl, CefRefPtr& resourceStream, std::wstring& mimeType, int loadFlags) { std::wstring url = request->GetURL(); if(url == L"http://tests/request") { // Show the request contents std::wstringstream ss; ss << L"URL: " << url; ss << L"\nMethod: " << request->GetMethod(); CefRequest::HeaderMap headerMap; request->GetHeaderMap(headerMap); if(headerMap.size() > 0) { ss << L"\nHeaders:"; CefRequest::HeaderMap::const_iterator it = headerMap.begin(); for(; it != headerMap.end(); ++it) { ss << L"\n\t" << (*it).first << L": " << (*it).second; } } CefRefPtr postData = request->GetPostData(); if(postData.get()) { CefPostData::ElementVector elements; postData->GetElements(elements); if(elements.size() > 0) { ss << L"\nPost Data:"; CefRefPtr element; CefPostData::ElementVector::const_iterator it = elements.begin(); for(; it != elements.end(); ++it) { element = (*it); if(element->GetType() == PDE_TYPE_BYTES) { // the element is composed of bytes ss << L"\n\tBytes: "; if(element->GetBytesCount() == 0) ss << L"(empty)"; else { // retrieve the data. size_t size = element->GetBytesCount(); char* bytes = new char[size]; element->GetBytes(size, bytes); ss << StringToWString(std::string(bytes, size)); delete [] bytes; } } else if(element->GetType() == PDE_TYPE_FILE) { ss << L"\n\tFile: " << element->GetFile(); } } } } std::wstring str = ss.str(); resourceStream = CefStreamReader::CreateForData( (void*)str.c_str(), str.size() * sizeof(wchar_t)); mimeType = L"text/plain"; } else if(wcsstr(url.c_str(), L"logo.gif") != NULL) { // Any time we find "logo.gif" in the URL substitute in our own image DWORD dwSize; LPBYTE pBytes; if(LoadBinaryResource(IDS_LOGO, dwSize, pBytes)) { resourceStream = CefStreamReader::CreateForData(pBytes, dwSize); mimeType = L"image/jpg"; } } return RV_CONTINUE; } // Event called before a context menu is displayed. To cancel display of the // default context menu return RV_HANDLED. virtual RetVal HandleBeforeMenu(CefRefPtr browser, const MenuInfo& menuInfo) { return RV_CONTINUE; } // Event called to optionally override the default text for a context menu // item. |label| contains the default text and may be modified to substitute // alternate text. The return value is currently ignored. virtual RetVal HandleGetMenuLabel(CefRefPtr browser, MenuId menuId, std::wstring& label) { return RV_CONTINUE; } // Event called when an option is selected from the default context menu. // Return RV_HANDLED to cancel default handling of the action. virtual RetVal HandleMenuAction(CefRefPtr browser, MenuId menuId) { return RV_CONTINUE; } // Event called to format print headers and footers. |printInfo| contains // platform-specific information about the printer context. |url| is the // URL if the currently printing page, |title| is the title of the currently // printing page, |currentPage| is the current page number and |maxPages| is // the total number of pages. Six default header locations are provided // by the implementation: top left, top center, top right, bottom left, // bottom center and bottom right. To use one of these default locations // just assign a string to the appropriate variable. To draw the header // and footer yourself return RV_HANDLED. Otherwise, populate the approprate // variables and return RV_CONTINUE. virtual RetVal HandlePrintHeaderFooter(CefRefPtr browser, CefRefPtr frame, CefPrintInfo& printInfo, const std::wstring& url, const std::wstring& title, int currentPage, int maxPages, std::wstring& topLeft, std::wstring& topCenter, std::wstring& topRight, std::wstring& bottomLeft, std::wstring& bottomCenter, std::wstring& bottomRight) { // Place the page title at top left topLeft = title; // Place the page URL at top right topRight = url; // Place "Page X of Y" at bottom center std::wstringstream strstream; strstream << L"Page " << currentPage << L" of " << maxPages; bottomCenter = strstream.str(); return RV_CONTINUE; } // Run a JS alert message. Return RV_CONTINUE to display the default alert // or RV_HANDLED if you displayed a custom alert. virtual RetVal HandleJSAlert(CefRefPtr browser, CefRefPtr frame, const std::wstring& message) { return RV_CONTINUE; } // Run a JS confirm request. Return RV_CONTINUE to display the default alert // or RV_HANDLED if you displayed a custom alert. If you handled the alert // set |retval| to true if the user accepted the confirmation. virtual RetVal HandleJSConfirm(CefRefPtr browser, CefRefPtr frame, const std::wstring& message, bool& retval) { return RV_CONTINUE; } // Run a JS prompt request. Return RV_CONTINUE to display the default prompt // or RV_HANDLED if you displayed a custom prompt. If you handled the prompt // set |retval| to true if the user accepted the prompt and request and // |result| to the resulting value. virtual RetVal HandleJSPrompt(CefRefPtr browser, CefRefPtr frame, const std::wstring& message, const std::wstring& defaultValue, bool& retval, std::wstring& result) { return RV_CONTINUE; } // Called just before a window is closed. The return value is currently // ignored. virtual RetVal HandleBeforeWindowClose(CefRefPtr browser) { if(m_BrowserHwnd == browser->GetWindowHandle()) { // Free the browser pointer so that the browser can be destroyed m_Browser = NULL; } return RV_CONTINUE; } // Called when the browser component is about to loose focus. For instance, // if focus was on the last HTML element and the user pressed the TAB key. // The return value is currently ignored. virtual RetVal HandleTakeFocus(CefRefPtr browser, bool reverse) { return RV_CONTINUE; } // Event called for binding to a frame's JavaScript global object. The // return value is currently ignored. virtual RetVal HandleJSBinding(CefRefPtr browser, CefRefPtr frame, CefRefPtr object) { // Create the new V8 object. CefRefPtr testObjPtr = CefV8Value::CreateObject(NULL); // Add the new V8 object to the global window object with the name // "cef_test". object->SetValue(L"cef_test", testObjPtr); // Create an instance of ClientV8FunctionHandler as the V8 handler. CefRefPtr handlerPtr = new ClientV8FunctionHandler(); // Add a new V8 function to the cef_test object with the name "Dump". testObjPtr->SetValue(L"Dump", CefV8Value::CreateFunction(L"Dump", handlerPtr)); // Add a new V8 function to the cef_test object with the name "Call". testObjPtr->SetValue(L"Call", CefV8Value::CreateFunction(L"Call", handlerPtr)); return RV_HANDLED; } // Called when the browser component is requesting focus. |isWidget| will be // true if the focus is requested for a child widget of the browser window. // Return RV_CONTINUE to allow the focus to be set or RV_HANDLED to cancel // setting the focus. virtual RetVal HandleSetFocus(CefRefPtr browser, bool isWidget) { return RV_CONTINUE; } // Retrieve the current navigation state flags void GetNavState(bool &isLoading, bool &canGoBack, bool &canGoForward) { Lock(); isLoading = m_bLoading; canGoBack = m_bCanGoBack; canGoForward = m_bCanGoForward; Unlock(); } void SetMainHwnd(HWND hwnd) { Lock(); m_MainHwnd = hwnd; Unlock(); } void SetEditHwnd(HWND hwnd) { Lock(); m_EditHwnd = hwnd; Unlock(); } CefRefPtr GetBrowser() { return m_Browser; } HWND GetBrowserHwnd() { return m_BrowserHwnd; } protected: // The child browser window CefRefPtr m_Browser; // The main frame window handle HWND m_MainHwnd; // The child browser window handle HWND m_BrowserHwnd; // The edit window handle HWND m_EditHwnd; // True if the page is currently loading bool m_bLoading; // True if the user can navigate backwards bool m_bCanGoBack; // True if the user can navigate forwards bool m_bCanGoForward; }; // // FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM) // // PURPOSE: Processes messages for the main window. // LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { static CefRefPtr handler; static HWND backWnd = NULL, forwardWnd = NULL, reloadWnd = NULL, stopWnd = NULL, editWnd = NULL; static WNDPROC editWndOldProc = NULL; int wmId, wmEvent; PAINTSTRUCT ps; HDC hdc; if(hWnd == editWnd) { // Callback for the edit window switch (message) { case WM_CHAR: if (wParam == VK_RETURN && handler.get()) { // When the user hits the enter key load the URL CefRefPtr browser = handler->GetBrowser(); wchar_t strPtr[MAX_URL_LENGTH] = {0}; *((LPWORD)strPtr) = MAX_URL_LENGTH; LRESULT strLen = SendMessage(hWnd, EM_GETLINE, 0, (LPARAM)strPtr); if (strLen > 0) { strPtr[strLen] = 0; browser->GetMainFrame()->LoadURL(strPtr); } return 0; } } return (LRESULT)CallWindowProc(editWndOldProc, hWnd, message, wParam, lParam); } else { // Callback for the main window switch (message) { case WM_CREATE: { // Create the single static handler class instance handler = new ClientHandler(); handler->SetMainHwnd(hWnd); // Create the child windows used for navigation RECT rect; int x = 0; GetClientRect(hWnd, &rect); backWnd = CreateWindow(L"BUTTON", L"Back", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_DISABLED, x, 0, BUTTON_WIDTH, URLBAR_HEIGHT, hWnd, (HMENU) IDC_NAV_BACK, hInst, 0); x += BUTTON_WIDTH; forwardWnd = CreateWindow(L"BUTTON", L"Forward", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_DISABLED, x, 0, BUTTON_WIDTH, URLBAR_HEIGHT, hWnd, (HMENU) IDC_NAV_FORWARD, hInst, 0); x += BUTTON_WIDTH; reloadWnd = CreateWindow(L"BUTTON", L"Reload", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_DISABLED, x, 0, BUTTON_WIDTH, URLBAR_HEIGHT, hWnd, (HMENU) IDC_NAV_RELOAD, hInst, 0); x += BUTTON_WIDTH; stopWnd = CreateWindow(L"BUTTON", L"Stop", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_DISABLED, x, 0, BUTTON_WIDTH, URLBAR_HEIGHT, hWnd, (HMENU) IDC_NAV_STOP, hInst, 0); x += BUTTON_WIDTH; editWnd = CreateWindow(L"EDIT", 0, WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT | ES_AUTOVSCROLL | ES_AUTOHSCROLL| WS_DISABLED, x, 0, rect.right - BUTTON_WIDTH * 4, URLBAR_HEIGHT, hWnd, 0, hInst, 0); // Assign the edit window's WNDPROC to this function so that we can // capture the enter key editWndOldProc = reinterpret_cast(GetWindowLongPtr(editWnd, GWLP_WNDPROC)); SetWindowLongPtr(editWnd, GWLP_WNDPROC, reinterpret_cast(WndProc)); handler->SetEditHwnd(editWnd); rect.top += URLBAR_HEIGHT; CefWindowInfo info; // Initialize window info to the defaults for a child window info.SetAsChild(hWnd, rect); // Creat the new child child browser window CefBrowser::CreateBrowser(info, false, static_cast>(handler), L"http://www.google.com"); // Start the timer that will be used to update child window state SetTimer(hWnd, 1, 250, NULL); } return 0; case WM_TIMER: if(handler.get() && handler->GetBrowserHwnd()) { // Retrieve the current navigation state bool isLoading, canGoBack, canGoForward; handler->GetNavState(isLoading, canGoBack, canGoForward); // Update the status of child windows EnableWindow(editWnd, TRUE); EnableWindow(backWnd, canGoBack); EnableWindow(forwardWnd, canGoForward); EnableWindow(reloadWnd, !isLoading); EnableWindow(stopWnd, isLoading); } return 0; case WM_COMMAND: { CefRefPtr browser; if(handler.get()) browser = handler->GetBrowser(); wmId = LOWORD(wParam); wmEvent = HIWORD(wParam); // Parse the menu selections: switch (wmId) { case IDM_ABOUT: DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); return 0; case IDM_EXIT: DestroyWindow(hWnd); return 0; case IDC_NAV_BACK: // Back button if(browser.get()) browser->GoBack(); return 0; case IDC_NAV_FORWARD: // Forward button if(browser.get()) browser->GoForward(); return 0; case IDC_NAV_RELOAD: // Reload button if(browser.get()) browser->Reload(); return 0; case IDC_NAV_STOP: // Stop button if(browser.get()) browser->StopLoad(); return 0; case ID_TESTS_JAVASCRIPT_HANDLER: // Test the V8 function handler if(browser.get()) { std::wstring html = L"ClientV8FunctionHandler says:
"
              L""
              L"
"; browser->GetMainFrame()->LoadString(html, L"about:blank"); } return 0; case ID_TESTS_JAVASCRIPT_HANDLER2: // Test the V8 extension handler if(browser.get()) { std::wstring html = L"ClientV8ExtensionHandler says:
"
              L""
              L"
"; browser->GetMainFrame()->LoadString(html, L"about:blank"); } return 0; case ID_TESTS_JAVASCRIPT_EXECUTE: // Test execution of javascript if(browser.get()) { browser->GetMainFrame()->ExecuteJavaScript( L"alert('JavaScript execute works!');", L"about:blank", 0); } return 0; case ID_TESTS_PLUGIN: // Test the custom plugin if(browser.get()) { std::wstring html = L"Client Plugin:
" L"" L""; browser->GetMainFrame()->LoadString(html, L"about:blank"); } return 0; case ID_TESTS_POPUP: // Test a popup window if(browser.get()) { browser->GetMainFrame()->ExecuteJavaScript( L"window.open('http://www.google.com');", L"about:blank", 0); } return 0; case ID_TESTS_REQUEST: // Test a request if(browser.get()) { // Create a new request CefRefPtr request(CefRequest::CreateRequest()); // Set the request URL request->SetURL(L"http://tests/request"); // Add post data to the request. The correct method and content- // type headers will be set by CEF. CefRefPtr postDataElement( CefPostDataElement::CreatePostDataElement()); std::string data = "arg1=val1&arg2=val2"; postDataElement->SetToBytes(data.length(), data.c_str()); CefRefPtr postData(CefPostData::CreatePostData()); postData->AddElement(postDataElement); request->SetPostData(postData); // Add a custom header CefRequest::HeaderMap headerMap; headerMap.insert( std::make_pair(L"X-My-Header", L"My Header Value")); request->SetHeaderMap(headerMap); // Load the request browser->GetMainFrame()->LoadRequest(request); } return 0; } } break; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); EndPaint(hWnd, &ps); return 0; case WM_SETFOCUS: if(handler.get() && handler->GetBrowserHwnd()) { // Pass focus to the browser window PostMessage(handler->GetBrowserHwnd(), WM_SETFOCUS, wParam, NULL); } return 0; case WM_SIZE: if(handler.get() && handler->GetBrowserHwnd()) { // Resize the browser window and address bar to match the new frame // window size RECT rect; GetClientRect(hWnd, &rect); rect.top += URLBAR_HEIGHT; int urloffset = rect.left + BUTTON_WIDTH * 4; HDWP hdwp = BeginDeferWindowPos(1); hdwp = DeferWindowPos(hdwp, editWnd, NULL, urloffset, 0, rect.right - urloffset, URLBAR_HEIGHT, SWP_NOZORDER); hdwp = DeferWindowPos(hdwp, handler->GetBrowserHwnd(), NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER); EndDeferWindowPos(hdwp); } break; case WM_ERASEBKGND: if(handler.get() && handler->GetBrowserHwnd()) { // Dont erase the background if the browser window has been loaded // (this avoids flashing) return 0; } break; case WM_DESTROY: // The frame window has exited KillTimer(hWnd, 1); PostQuitMessage(0); return 0; } return DefWindowProc(hWnd, message, wParam, lParam); } } // Message handler for about box. INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { UNREFERENCED_PARAMETER(lParam); switch (message) { case WM_INITDIALOG: return (INT_PTR)TRUE; case WM_COMMAND: if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) { EndDialog(hDlg, LOWORD(wParam)); return (INT_PTR)TRUE; } break; } return (INT_PTR)FALSE; }