I have make a javascript extension in OnWebKitInitialized,
- Code: Select all
void CSimpleBrowserApp::OnWebKitInitialized() {
// Register the aot shell extension.
std::string extension_code = "var aotshell;if(!aotshell){aotshell={}}if(!aotshell.fs){aotshell.fs={}}if(!aotshell.app){aotshell.app={}}...more code here";
CefRefPtr<CefV8Handler> handler(new CShellExtensionHandler(this));
CefRegisterExtension("shell", extension_code, handler);
RenderDelegateSet::iterator it = render_delegates_.begin();
for (; it != render_delegates_.end(); ++it)
(*it)->OnWebKitInitialized(this);
}
CShellExtensionHandler send handler message to the browser process and has the following implementation:
- Code: Select all
class CShellExtensionHandler : public CefV8Handler {
public:
explicit CShellExtensionHandler(CefRefPtr<CBrowserApp> client_app)
: client_app_(client_app)
, messageId(0) {
}
virtual bool Execute(const CefString& name,
CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments,
CefRefPtr<CefV8Value>& retval,
CefString& exception) {
if (name == "XXXXXXXXX") {
// Whenever a native function is called, CShellExtensionHandler::Execute() is invoked.
// This code runs in the render process, so only the most trivial extension code should be executed here.
//retval = CefV8Value::CreateDouble(client_app_->XXXXXXXXX());
} else {
// Pass all messages to the browser process.
CefRefPtr<CefBrowser> browser = CefV8Context::GetCurrentContext()->GetBrowser();
if (!browser.get()) {
// If we don't have a browser, we can't handle the command.
return false;
}
CefRefPtr<CefProcessMessage> message = CefProcessMessage::Create(name);
CefRefPtr<CefListValue> messageArgs = message->GetArgumentList();
// The first argument must be a callback function
if (arguments.size() > 0 && !arguments[0]->IsFunction()) {
std::string functionName = name;
fprintf(stderr, "Function called without callback param: %s\n", functionName.c_str());
return false;
}
if (arguments.size() > 0) {
// The first argument is the message id
client_app_->AddCallback(messageId, CefV8Context::GetCurrentContext(), arguments[0]);
CefSetListValue(messageArgs, 0, CefV8Value::CreateInt(messageId));
}
// Pass the rest of the arguments
for (unsigned int i = 1; i < arguments.size(); i++)
CefSetListValue(messageArgs, i, arguments[i]);
browser->SendProcessMessage(PID_BROWSER, message);
messageId++;
}
return true;
}
private:
CefRefPtr<CBrowserApp> client_app_;
int32 messageId;
IMPLEMENT_REFCOUNTING(CShellExtensionHandler);
};
In CBrowserHandler::OnProcessMessageReceived I handled the message and run the native code for the registered javascript function, once the native code is done, send callback message to the render process, and in the last step CBrowserApp::OnProcessMessageReceived will handle the callback of the registered javascript function if there is any.
The whole story is described in https://github.com/adobe/brackets-shell/wiki/Writing-V8-Extensions
Ok, here comes my question, when I using my CBrowserApp and CBrowserHandler in a MFC dialog based application and set appSettings.multi_threaded_message_loop = true;(Using MFC message loop) I cannot call the javascript extension code in the page that loaded in, here is the page example:
- Code: Select all
<html>
<head>
<script>
function on_btn_cef_js_showOSFolder()
{
alert("invoke: on_btn_cef_js_showOSFolder()");
aotshell.app.showOSFolder("c:\\", null);
alert("invoke: on_btn_cef_js_showOSFolder() done");
}
</script>
</head>
<body>
<input type="button" value="cef js test" onclick="on_btn_cef_js_showOSFolder()">
</body>
</html>
The error message in the debug.log is:
[0701/145015:INFO:CONSOLE(7)] "Uncaught ReferenceError: aotshell is not defined", source: file:///C:/Users/forhappy/Documents/cef_js_showOSFolder.html (7)
But on the other hand, if I use the following demo to load the page the extension javascript can be called normally:
- Code: Select all
int APIENTRY wWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow) {
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// Provide CEF with command-line arguments.
CefMainArgs main_args(hInstance);
CefRefPtr<CBrowserApp> app(new CBrowserApp);
int exit_code = CefExecuteProcess(main_args, app.get());
if (exit_code >= 0) {
// The sub-process has completed so return here.
return exit_code;
}
// Specify CEF global settings here.
CefSettings settings;
// Initialize CEF.
CefInitialize(main_args, settings, app.get());
CefWindowInfo window_info;
#if defined(OS_WIN)
window_info.SetAsPopup(NULL, "Browser");
#endif
// SimpleHandler implements browser-level callbacks.
CefRefPtr<CBrowserHandler> handler(new CBrowserHandler());
// Specify CEF browser settings here.
CefBrowserSettings browser_settings;
std::string url = "file://C:\\Users\\forhappy\\Documents\\cef_js_showOSFolder.html";
// Create the first browser window.
CefBrowserHost::CreateBrowser(window_info, handler.get(), url,
browser_settings, NULL);
CefRunMessageLoop();
CefShutdown();
return 0;
}
The only difference is in the first example I use MFC message loop and in the second example I use CEF message loop, the javascript extension code are the same, but the first example failed to call javasript extension code and the second one did the right thing I expected, what is the difference, can anybody help me ?
Thanks very much