转载:http://blog.csdn.net/foruok/article/details/50573612
转载:http://blog.csdn.net/foruok/article/details/50584985
转载:http://blog.csdn.net/mfcing/article/details/44539035
转载:https://github.com/fanfeilong/cefutil/blob/master/doc/CEF_JavaScript_Cpp.md
转载:https://blog.csdn.net/aseseven/article/details/79482515(CEF3加载本地HTML文件时中文路径乱码的问题解决办法)
转载:https://blog.csdn.net/u012778714/article/category/7003599
JS与Native代码交互,是在Render进程中,所以我们要实现CefRenderProcessHandler接口
一、JS 调用 C++
- JavaScript注册函数给Render进程,Render进程保存该JavaScript函数
- Render进程发消息通知Browser进程
- Browser进程处理后,回发消息给Render进程
- Render进程调用之前保存的JavaScript函数
1.带参数没有返回值
自己的APP类要继承于CefRenderProcessHandler
1 #ifndef _CEFBROWSERAPP_H_ 2 #define _CEFBROWSERAPP_H_ 3 #include "include/cef_app.h" 4 #include "CEFV8HandlerEx.h" 5 6 class CCefBrowserApp 7 : public CefApp 8 , public CefBrowserProcessHandler 9 , public CefRenderProcessHandler 10 { 11 public: 12 CCefBrowserApp(); 13 14 virtual ~CCefBrowserApp(); 15 16 public: 17 virtual CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler()OVERRIDE { return this; }; 18 19 public: 20 // CefBrowserProcessHandler methods: 21 virtual void OnContextInitialized(); 22 23 //CefRenderProcessHandler methods 24 virtual void OnWebKitInitialized(); 25 26 CefRefPtr<CefRenderProcessHandler> GetRenderProcessHandler() OVERRIDE{ return this; } 27 28 virtual void OnContextCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context); 29 30 virtual void OnContextReleased(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context); 31 32 protected: 33 34 CefRefPtr<CCEFV8HandlerEx> m_v8Handler; 35 36 IMPLEMENT_REFCOUNTING(CCefBrowserApp); 37 }; 38 #endif //_CEFBROWSERAPP_H_
.cpp
1 #include "CefBrowserApp.h" 2 #include "stdafx.h" 3 4 5 CCefBrowserApp::CCefBrowserApp() 6 :m_v8Handler(new CCEFV8HandlerEx) 7 { 8 } 9 10 CCefBrowserApp::~CCefBrowserApp() 11 { 12 } 13 14 15 void CCefBrowserApp::OnContextInitialized() 16 { 17 // do nothing here, because we will create browser in my own dialog 18 } 19 20 void CCefBrowserApp::OnContextCreated(CefRefPtr<CefBrowser> browser, 21 CefRefPtr<CefFrame> frame, 22 CefRefPtr<CefV8Context> context) 23 { 24 // Retrieve the context's window object. 25 CefRefPtr<CefV8Value> object = context->GetGlobal(); 26 27 // Create the "NativeLogin" function. 28 CefRefPtr<CefV8Value> func = CefV8Value::CreateFunction("NativeLogin", m_v8Handler); 29 30 // Add the "NativeLogin" function to the "window" object. 31 object->SetValue("NativeLogin", func, V8_PROPERTY_ATTRIBUTE_NONE); 32 } 33 34 void CCefBrowserApp::OnWebKitInitialized() 35 { 36 std::string app_code = 37 "var app;" 38 "if (!app)" 39 " app = {};" 40 "(function() {" 41 " app.GetId = function() {" 42 " native function GetId();" 43 " return GetId();" 44 " };" 45 "})();"; 46 47 // Registered Javascript Function, which will be called by Cpp 48 " app.registerJavascriptFunction = function(name,callback) {" 49 " native function registerJavascriptFunction();" 50 " return registerJavascriptFunction(name,callback);" 51 " };" 52 53 "})();"; 54 55 56 CefRegisterExtension("v8/app", app_code, m_v8Handler);//第一个参数不能为空,否则报错,这个名字可以自定义 57 }
注:CefRegisterExtension的注释
// Example JavaScript extension code: // <pre> // // create the 'example' global object if it doesn't already exist. // if (!example) // example = {}; // // create the 'example.test' global object if it doesn't already exist. // if (!example.test) // example.test = {}; // (function() { // // Define the function 'example.test.myfunction'. // example.test.myfunction = function() { // // Call CefV8Handler::Execute() with the function name 'MyFunction' // // and no arguments. // native function MyFunction(); // return MyFunction(); // }; // // Define the getter function for parameter 'example.test.myparam'. // example.test.__defineGetter__('myparam', function() { // // Call CefV8Handler::Execute() with the function name 'GetMyParam' // // and no arguments. // native function GetMyParam(); // return GetMyParam(); // }); // // Define the setter function for parameter 'example.test.myparam'. // example.test.__defineSetter__('myparam', function(b) { // // Call CefV8Handler::Execute() with the function name 'SetMyParam' // // and a single argument. // native function SetMyParam(); // if(b) SetMyParam(b); // }); // // // Extension definitions can also contain normal JavaScript variables // // and functions. // var myint = 0; // example.test.increment = function() { // myint += 1; // return myint; // }; // })(); // </pre> // Example usage in the page: // <pre> // // Call the function. // example.test.myfunction(); // // Set the parameter. // example.test.myparam = value; // // Get the parameter. // value = example.test.myparam; // // Call another function. // example.test.increment(); // </pre> ///
58 59 void CCefBrowserApp::OnContextReleased(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context) 60 { 61 m_v8Handler = nullptr; 62 }
OnContextCreated给window对象绑定了一个NativeLogin函数,这个函数将由ClientV8Handler类来处理,当HTML中的JS代码调用window.NativeLogin时,ClientV8Handler的Execute方法会被调用。
OnWebKitInitialized注册了一个名为app的JS扩展,在这个扩展里为app定义了GetId方法,app.GetId内部调用了native版本的GetId()。HTML中的JS代码可能如下:
alert(app.GetId());
当浏览器执行上面的代码时,CCEFV8HandlerEx的Execute方法会被调用,现在来看CCEFV8HandlerEx的实现
.h
1 #ifndef _CEFV8HANDLEREX_H_ 2 #define _CEFV8HANDLEREX_H_ 3 4 #include "include/cef_v8.h" 5 6 class CCEFV8HandlerEx : public CefV8Handler { 7 public: 8 CCEFV8HandlerEx(); 9 10 ~CCEFV8HandlerEx(); 11 public: 12 virtual bool Execute(const CefString& name, CefRefPtr<CefV8Value> object, const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval, CefString& exception) override; 13 private: 14 // Map of message callbacks. 15 typedef std::map<std::pair<std::string, int>, std::pair<CefRefPtr<CefV8Context>, CefRefPtr<CefV8Value> > >CallbackMap; 16 CallbackMap callback_map_; 17 18 protected: 19 IMPLEMENT_REFCOUNTING(CCEFV8HandlerEx); 20 }; 21 #endif//_CEFV8HANDLEREX_H_
.cpp
1 #include "CEFV8HandlerEx.h" 2 #include "stdafx.h" 3 #include <strsafe.h> 4 5 CCEFV8HandlerEx::CCEFV8HandlerEx() 6 { 7 8 } 9 10 CCEFV8HandlerEx::~CCEFV8HandlerEx() 11 { 12 // Remove any JavaScript callbacks registered for the context that has been released. 13 if (!callback_map_.empty()) { 14 CallbackMap::iterator it = callback_map_.begin(); 15 for (; it != callback_map_.end();) { 16 if (it->second.first->IsSame(it->second.first)) 17 callback_map_.erase(it++); 18 else 19 ++it; 20 } 21 } 22 } 23 24 25 bool CCEFV8HandlerEx::Execute(const CefString& name /*JavaScript调用的C++方法名字*/, CefRefPtr<CefV8Value> object /*JavaScript调用者对象*/, const CefV8ValueList& arguments /*JavaScript传递的参数*/, CefRefPtr<CefV8Value>& retval /*返回给JS的值设置给这个对象*/, CefString& exception/*通知异常信息给JavaScript*/) 26 { 27 if (name == "NativeLogin") 28 {//Window Binding 29 if (arguments.size() == 2) 30 { 31 CefString strUser = arguments.at(0)->GetStringValue(); 32 CefString strPassword = arguments.at(1)->GetStringValue(); 33 34 //TODO: doSomething() in native way 35 36 CefRefPtr<CefProcessMessage> msg = CefProcessMessage::Create("login_msg"); 37 38 // Retrieve the argument list object. 39 CefRefPtr<CefListValue> args = msg->GetArgumentList(); 40 41 // Populate the argument values. 42 args->SetSize(2); 43 args->SetString(0, strUser); 44 args->SetString(1, strPassword); 45 46 // Send the process message to the browser process. 47 CefV8Context::GetCurrentContext()->GetBrowser()->SendProcessMessage(PID_BROWSER, msg); 48 49 50 51 retval = CefV8Value::CreateInt(0);//函数的返回值 我们可以拿这个返回值做判断或者其他操作
//var result = window.NativeLogin(document.getElementById("userName").value, document.getElementById("password").value);
//document.getElementById("text").innerHTML = result
52 } 53 else 54 { 55 retval = CefV8Value::CreateInt(2); 56 } 57 return true; 58 } 59 else if (name == "GetId") 60 {//JS Extensions 61 if (arguments.size() == 0) 62 { 63 // execute javascript 64 // just for test 65 CefRefPtr<CefFrame> frame = CefV8Context::GetCurrentContext()->GetBrowser()->GetMainFrame(); 66 frame->ExecuteJavaScript("alert('Hello, I came from native world.')", frame->GetURL(), 0); 67 68 // return to JS 69 retval = CefV8Value::CreateString("72395678"); 70 return true; 71 } 72 } 73 // Function does not exist. 74 return false; 75 }
在Browser进程中接受Render进程发过来的消息
重写 virtual bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser, CefProcessId source_process,CefRefPtr<CefProcessMessage> message);这个虚函数
我把C++函数都写在了窗口类中,所以我对CCefBrowserEventHandler做了修改,把窗口指针传到Browser中,方便调用
.h
1 #ifndef _CEFBROWSEREVENTHANDLER_H_ 2 #define _CEFBROWSEREVENTHANDLER_H_ 3 #include "include/cef_client.h" 4 #include "include/base/cef_lock.h" //线程安全 5 6 7 class CMainFrameWnd; 8 9 class CCefBrowserEventHandler 10 : public CefClient 11 , public CefDisplayHandler // 显示变化事件 12 , public CefLoadHandler // 加载错误事件 13 , public CefLifeSpanHandler // 声明周期事件 14 //, public CefContextMenuHandler // 上下文菜单事件 15 //, public CefDialogHandler // 对话框事件 16 //, public CefDownloadHandler // 下载事件 17 //, public CefDragHandler // 拖拽事件 18 //, public CefFindHandler // 查找事件 19 //, public ... 20 { 21 public: 22 CCefBrowserEventHandler(CMainFrameWnd* pMainFrame); 23 24 virtual ~CCefBrowserEventHandler(); 25 26 public: 27 // CefClient 事件处理器,如果没有对应处理器则默认使用内部处理器 28 virtual CefRefPtr<CefDisplayHandler> GetDisplayHandler() OVERRIDE; 29 virtual CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() OVERRIDE; 30 virtual CefRefPtr<CefLoadHandler> GetLoadHandler() OVERRIDE; 31 32 public: 33 // display handler method 34 virtual void OnTitleChange(CefRefPtr<CefBrowser> browser, const CefString& title) OVERRIDE; 35 36 public: 37 // load handler method 38 virtual void OnLoadError(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, 39 ErrorCode errorCode, const CefString& errorText, const CefString& failedUrl) OVERRIDE; 40 41 public: 42 // display handler meethod 43 virtual void OnAfterCreated(CefRefPtr<CefBrowser> browser) OVERRIDE; 44 virtual bool DoClose(CefRefPtr<CefBrowser> browser) OVERRIDE; 45 virtual void OnBeforeClose(CefRefPtr<CefBrowser> browser) OVERRIDE; 46 47 48 virtual bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser, 49 CefProcessId source_process, 50 CefRefPtr<CefProcessMessage> message); 51 52 53 bool IsClosing() const { return m_bIsClosing; } 54 55 CefRefPtr<CefBrowser> GetBrowser(){return m_Browser;} 56 57 protected: 58 59 CefRefPtr<CefBrowser> m_Browser; 60 61 bool m_bIsClosing; 62 63 CMainFrameWnd* m_pMainWnd; 64 65 IMPLEMENT_REFCOUNTING(CCefBrowserEventHandler); 66 //由于CEF采用多线程架构,有必要使用锁和闭包来保证在多不同线程安全的传递数据。IMPLEMENT_LOCKING定义提供了Lock()和Unlock()方法以及AutoLock对象来保证不同代码块同步访问 67 IMPLEMENT_LOCKING(CCefBrowserEventHandler);//必须包含#include "include/base/cef_lock.h" 68 }; 69 70 #endif//_CEFBROWSEREVENTHANDLER_H_
.cpp
1 #include "CefBrowserEventHandler.h" 2 #include "stdafx.h" 3 #include <sstream> 4 #include <string> 5 #include "include/cef_app.h" 6 #include "include/wrapper/cef_closure_task.h" 7 #include "include/wrapper/cef_helpers.h" 8 #include "MainFrameWnd.h" 9 10 11 CCefBrowserEventHandler::CCefBrowserEventHandler(CMainFrameWnd* pMainFrame) 12 :m_bIsClosing(false) 13 ,m_pMainWnd(pMainFrame) 14 { 15 16 } 17 18 CCefBrowserEventHandler::~CCefBrowserEventHandler() 19 { 20 21 } 22 23 CefRefPtr<CefDisplayHandler> CCefBrowserEventHandler::GetDisplayHandler() 24 { 25 return this; 26 } 27 28 CefRefPtr<CefLifeSpanHandler> CCefBrowserEventHandler::GetLifeSpanHandler() 29 { 30 return this; 31 } 32 33 CefRefPtr<CefLoadHandler> CCefBrowserEventHandler::GetLoadHandler() 34 { 35 return this; 36 } 37 38 void CCefBrowserEventHandler::OnTitleChange(CefRefPtr<CefBrowser> browser, const CefString& title) 39 { 40 41 } 42 43 void CCefBrowserEventHandler::OnLoadError(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, ErrorCode errorCode, 44 const CefString& errorText, const CefString& failedUrl) 45 { 46 CEF_REQUIRE_UI_THREAD(); 47 if (ERR_ABORTED == errorCode) 48 return ; 49 50 std::stringstream ss; 51 ss << "<html><body bgcolor=\"white\">" 52 "<h2>Failed to load URL " << std::string(failedUrl) << 53 " with error " << std::string(errorText) << " (" << errorCode << 54 ").</h2></body></html>"; 55 frame->LoadString(ss.str(), failedUrl); 56 } 57 58 void CCefBrowserEventHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser) 59 { 60 CEF_REQUIRE_UI_THREAD(); 61 62 //base::AutoLock lock_scope(lock_); 63 64 AutoLock lock_scope(this); 65 66 m_Browser = browser; 67 68 } 69 70 bool CCefBrowserEventHandler::DoClose(CefRefPtr<CefBrowser> browser) 71 { 72 CEF_REQUIRE_UI_THREAD(); 73 74 //base::AutoLock lock_scope(lock_); 75 AutoLock lock_scope(this); 76 77 78 if(m_Browser) 79 { 80 // Set a flag to indicate that the window close should be allowed. 81 m_bIsClosing = true; 82 } 83 84 return false; 85 } 86 87 void CCefBrowserEventHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser) 88 { 89 CEF_REQUIRE_UI_THREAD(); 90 91 //base::AutoLock lock_scope(lock_); 92 AutoLock lock_scope(this); 93 94 if(m_Browser->IsSame(browser)) 95 m_Browser = NULL; 96 } 97 98 bool CCefBrowserEventHandler::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser, 99 CefProcessId source_process, 100 CefRefPtr<CefProcessMessage> message) 101 { 102 const std::string& messageName = message->GetName(); 103 if (messageName == "login_msg") 104 { 105 // extract message 106 CefRefPtr<CefListValue> args = message->GetArgumentList(); 107 CefString strUser = args->GetString(0); 108 CefString strPassword = args->GetString(1); 109 110 m_pMainWnd->CEFLoginJsCallCPP(strUser,strPassword);//窗口类的成员函数 111 112 //如果函数有返回值也可以通过向Render发送消息传递 113 //send reply to render process 114 CefRefPtr<CefProcessMessage> outMsg = CefProcessMessage::Create("login_reply"); 115 116 // Retrieve the argument list object. 117 CefRefPtr<CefListValue> replyArgs = outMsg->GetArgumentList(); 118 119 // Populate the argument values. 120 replyArgs->SetSize(1); 121 replyArgs->SetInt(0, 0); 122 123 // Send the process message to the renderer process. 124 browser->SendProcessMessage(PID_RENDERER, outMsg); 125 126 return true; 127 } 128 129 return false; 130 }
Browser进程处理完后向Render进程发了消息,The render process receives the IPC message处理
.h
1 #ifndef _CEFBROWSERAPP_H_ 2 #define _CEFBROWSERAPP_H_ 3 #include "include/cef_app.h" 4 #include "CEFV8HandlerEx.h" 5 6 class CCefBrowserApp 7 : public CefApp 8 , public CefBrowserProcessHandler 9 , public CefRenderProcessHandler 10 { 11 public: 12 CCefBrowserApp(); 13 14 virtual ~CCefBrowserApp(); 15 16 public: 17 virtual CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler()OVERRIDE { return this; }; 18 19 public: 20 // CefBrowserProcessHandler methods: 21 virtual void OnContextInitialized(); 22 23 //CefRenderProcessHandler methods 24 virtual void OnWebKitInitialized(); 25 26 CefRefPtr<CefRenderProcessHandler> GetRenderProcessHandler() OVERRIDE{ return this; } 27 28 virtual void OnContextCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context); 29 30 virtual void OnContextReleased(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context); 31 32 //收消息 33 virtual bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser, CefProcessId source_process, CefRefPtr<CefProcessMessage> message); 34 35 protected: 36 37 CefRefPtr<CCEFV8HandlerEx> m_v8Handler; 38 39 IMPLEMENT_REFCOUNTING(CCefBrowserApp); 40 }; 41 #endif //_CEFBROWSERAPP_H_
.cpp
1 #include "CefBrowserApp.h" 2 #include "stdafx.h" 3 4 5 CCefBrowserApp::CCefBrowserApp() 6 :m_v8Handler(new CCEFV8HandlerEx) 7 { 8 } 9 10 CCefBrowserApp::~CCefBrowserApp() 11 { 12 } 13 14 15 void CCefBrowserApp::OnContextInitialized() 16 { 17 // do nothing here, because we will create browser in my own dialog 18 } 19 20 void CCefBrowserApp::OnContextCreated(CefRefPtr<CefBrowser> browser, 21 CefRefPtr<CefFrame> frame, 22 CefRefPtr<CefV8Context> context) 23 { 24 // Retrieve the context's window object. 25 CefRefPtr<CefV8Value> object = context->GetGlobal(); 26 27 // Create the "NativeLogin" function. 28 CefRefPtr<CefV8Value> func = CefV8Value::CreateFunction("NativeLogin", m_v8Handler);//第一个参数和SetValue参数保持一致,否则无法调用 29 30 // Add the "NativeLogin" function to the "window" object. 31 object->SetValue("NativeLogin", func, V8_PROPERTY_ATTRIBUTE_NONE); 32 33 // Add the "register" function to the "window" object. 34 object->SetValue("register",CefV8Value::CreateFunction("register", m_v8Handler),V8_PROPERTY_ATTRIBUTE_NONE); 35 } 36 37 void CCefBrowserApp::OnWebKitInitialized() 38 { 39 std::string app_code = 40 "var app;" 41 "if (!app)" 42 " app = {};" 43 "(function() {" 44 " app.GetId = function() {" 45 " native function GetId();" 46 " return GetId();" 47 " };" 48 "})();"; 49 50 // Registered Javascript Function, which will be called by Cpp 51 " app.registerJavascriptFunction = function(name,callback) {" 52 " native function registerJavascriptFunction();" 53 " return registerJavascriptFunction(name,callback);" 54 " };" 55 56 "})();"; 57 58 59 CefRegisterExtension("v8/app", app_code, m_v8Handler);//第一个参数不能为空 60 } 61 62 void CCefBrowserApp::OnContextReleased(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context) 63 { 64 m_v8Handler = nullptr; 65 } 66 67 bool CCefBrowserApp::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,CefProcessId source_process,CefRefPtr<CefProcessMessage> message) 68 { 69 const std::string& messageName = message->GetName(); 70 if (messageName == "login_reply") 71 { 72 // extract message 73 CefRefPtr<CefListValue> args = message->GetArgumentList(); 74 bool status = args->GetBool(0); 75 76 CefRefPtr<CefFrame> frame = browser->GetMainFrame(); 77 78 if (status) 79 { 80 frame->ExecuteJavaScript("IsSuccess();", frame->GetURL(), 0); 81 } 82 83 return true; 84 } 85 86 return false; 87 }
2.JS CallBack
在OnContextCreated()函数中给window绑定函数
1 // Create the "register" function. 2 CefRefPtr<CefV8Value> func = CefV8Value::CreateFunction("register", m_v8Handler);//第一个参数和SetValue参数保持一致,否则无法调用 3 4 // Add the "register" function to the "window" object. 5 object->SetValue("register", func, V8_PROPERTY_ATTRIBUTE_NONE);
在Exectue()函数中处理
else if (name == "register") {if (arguments.size() == 1 && arguments[0]->IsFunction()) {CefRefPtr<CefV8Value> callback_func_ = arguments[0];CefRefPtr<CefV8Context> callback_context_ = CefV8Context::GetCurrentContext();callback_func_->ExecuteFunction(NULL, arguments);//执行回调函数return true;} }
在HTML的JavaScript里这样写
function myFunc()
{// do something in JS.alert("callback");
}//js CALLback
function CallBack()
{window.register(myFunc);
}
3.C++ 调用 JS
C++调用JS函数相对简单多了,因为CEF有接口可以直接使用CefFrame::ExecuteJavaScript,看看注释:
1 /// 2 // Execute a string of JavaScript code in this frame. The |script_url| 3 // parameter is the URL where the script in question can be found, if any. 4 // The renderer may request this URL to show the developer the source of the 5 // error. The |start_line| parameter is the base line number to use for error 6 // reporting. 7 /// 8 /*--cef(optional_param=script_url)--*/ 9 virtual void ExecuteJavaScript(const CefString& code, 10 const CefString& script_url, 11 int start_line) =0;
首先需要获取到我们的浏览器里的主框架对象,code是JS函数和传入参数的字符串,URL可以直接忽略。
1 CefRefPtr<CefFrame> frame = m_handler->GetBrowser()->GetMainFrame(); 2 3 m_handler是我们自己定义的Handler对象 4 5 /C++ 调用js方法 6 //frame->ExecuteJavaScript(L"Test();",frame->GetURL(),0);//提示框 7 //frame->ExecuteJavaScript(L"ModifyValue();",frame->GetURL(),0);//无参数函数 8 frame->ExecuteJavaScript(L"ModifyValue('巴萨牛逼');",frame->GetURL(),0);//有参数函数
9 如果参数是可变的,可以这样
CString strJsCode;
strJsCode.Format(L"setInstallStatus('%s','%s','%d');", lpData->strId.c_str(), strStatus, nPercent);
其中setInstallStatus是js函数,它有三个参数
我在HMTL里写的
function Test()
{alert("js被C++非礼了");
}function ModifyValue( arr)
{//document.getElementById("text").innerHTML = "被修改了";alert(arr);document.getElementById("text").innerHTML = arr;}