转载: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;
}
来源:https://www.cnblogs.com/chechen/p/6138167.html