[{"data":1,"prerenderedAt":1159},["ShallowReactive",2],{"doc-\u002Fdocs\u002Fapi\u002Feduwin-webview-api":3},{"id":4,"title":5,"body":6,"description":154,"extension":1153,"meta":1154,"navigation":577,"path":1155,"seo":1156,"stem":1157,"__hash__":1158},"content\u002Fdocs\u002Fapi\u002Feduwin-webview-api.md","eduwin WebView2 模块 API",{"type":7,"value":8,"toc":1137},"minimark",[9,13,29,32,38,97,143,148,177,186,203,213,311,315,324,343,354,369,373,388,401,411,418,447,450,465,476,480,483,488,508,520,534,589,592,703,707,714,723,734,749,764,793,853,863,866,886,889,892,907,914,938,942,949,958,972,1001,1010,1013,1016,1030,1033,1040,1051,1115,1118,1126,1133],[10,11,5],"h1",{"id":12},"eduwin-webview2-模块-api",[14,15,16],"blockquote",{},[17,18,19,20,24,25,28],"p",{},"头文件：通过 ",[21,22,23],"code",{},"eduwin.h"," 统一引用（",[21,26,27],{},"@public_api"," 已自动合并）",[17,30,31],{},"封装 Microsoft Edge WebView2，在 Eduwin 窗口中嵌入现代浏览器引擎。纯 C 实现，通过 COM lpVtbl + 手写 vtable 回调接入 WebView2 的三层 API（Loader flat 入口 \u002F ICoreWebView2 接口调用 \u002F 异步 CompletedHandler 回调）。",[17,33,34],{},[35,36,37],"strong",{},"两种 Runtime 模式：",[39,40,41,60],"table",{},[42,43,44],"thead",{},[45,46,47,51,54,57],"tr",{},[48,49,50],"th",{},"模式",[48,52,53],{},"Runtime 来源",[48,55,56],{},"包体",[48,58,59],{},"客户端要求",[61,62,63,81],"tbody",{},[45,64,65,72,75,78],{},[66,67,68,71],"td",{},[35,69,70],{},"Evergreen","（默认）",[66,73,74],{},"系统共享",[66,76,77],{},"—",[66,79,80],{},"需预装 Runtime",[45,82,83,88,91,94],{},[66,84,85],{},[35,86,87],{},"Fixed Version",[66,89,90],{},"应用本地打包",[66,92,93],{},"~150MB",[66,95,96],{},"零依赖",[14,98,99,109,140],{},[17,100,101,104,105,108],{},[35,102,103],{},"⚠️ Runtime 获取："," ",[21,106,107],{},"eduwin_pub.zip"," 不含 WebView2 Runtime（体积过大）。",[110,111,112,127],"ul",{},[113,114,115,118,119,126],"li",{},[35,116,117],{},"Evergreen（推荐开发\u002F测试用）","：下载 ",[120,121,125],"a",{"href":122,"rel":123},"https:\u002F\u002Fdeveloper.microsoft.com\u002Fmicrosoft-edge\u002Fwebview2\u002F",[124],"nofollow","Evergreen Bootstrapper","（约 2MB），双击安装，重启即可",[113,128,129,118,132,136,137],{},[35,130,131],{},"Fixed Version（推荐分发用）",[120,133,135],{"href":122,"rel":134},[124],"Fixed Version Runtime","（x64，约 150MB），解压后目录传给 ",[21,138,139],{},"webview_set_runtime_path()",[17,141,142],{},"两种下载均在同一页面，选择 \"Evergreen Bootstrapper\" 或 \"Fixed Version\" → 架构选 x64。",[144,145,147],"h2",{"id":146},"初始化-清理","初始化 \u002F 清理",[149,150,155],"pre",{"className":151,"code":152,"language":153,"meta":154,"style":154},"language-c shiki shiki-themes github-light github-dark","void webview_set_runtime_path(const WCHAR *path);  \u002F* 必须在 webview_init() 之前 *\u002F\nint  webview_init(void);\nvoid webview_cleanup(void);\n","c","",[21,156,157,165,171],{"__ignoreMap":154},[158,159,162],"span",{"class":160,"line":161},"line",1,[158,163,164],{},"void webview_set_runtime_path(const WCHAR *path);  \u002F* 必须在 webview_init() 之前 *\u002F\n",[158,166,168],{"class":160,"line":167},2,[158,169,170],{},"int  webview_init(void);\n",[158,172,174],{"class":160,"line":173},3,[158,175,176],{},"void webview_cleanup(void);\n",[17,178,179,181,182,185],{},[21,180,139],{}," 设置 Runtime 路径。",[21,183,184],{},"NULL"," = Evergreen 模式（默认），传路径 = Fixed Version 模式。",[17,187,188,191,192,104,195,198,199,202],{},[21,189,190],{},"webview_init()"," 必须在 ",[21,193,194],{},"init_app()",[35,196,197],{},"之前","调用。返回值 ",[21,200,201],{},"0"," 成功，非零失败。",[17,204,205,208,209,212],{},[21,206,207],{},"webview_cleanup()"," 在 ",[21,210,211],{},"run_app()"," 返回后调用，释放全局 COM 环境。",[149,214,216],{"className":151,"code":215,"language":153,"meta":154,"style":154},"\u002F* Fixed Version：客户端零依赖 *\u002F\nwebview_set_runtime_path(L\"..\u002Fruntime\u002F\");\nif (webview_init() != 0) {\n    init_app();\n    alert(L\"错误\", L\"WebView2 Runtime 初始化失败\");\n    return 1;\n}\n\u002F*\n * Evergreen（默认）：\n *   不调 webview_set_runtime_path，webview_init() 自动用系统 Runtime。\n *   Windows 11 已预装，Windows 10 需手动安装。\n *\u002F\ninit_app();\n\u002F\u002F ... 创建 WebView 窗口 ...\nrun_app();\nwebview_cleanup();\n",[21,217,218,223,228,233,239,245,251,257,263,269,275,281,287,293,299,305],{"__ignoreMap":154},[158,219,220],{"class":160,"line":161},[158,221,222],{},"\u002F* Fixed Version：客户端零依赖 *\u002F\n",[158,224,225],{"class":160,"line":167},[158,226,227],{},"webview_set_runtime_path(L\"..\u002Fruntime\u002F\");\n",[158,229,230],{"class":160,"line":173},[158,231,232],{},"if (webview_init() != 0) {\n",[158,234,236],{"class":160,"line":235},4,[158,237,238],{},"    init_app();\n",[158,240,242],{"class":160,"line":241},5,[158,243,244],{},"    alert(L\"错误\", L\"WebView2 Runtime 初始化失败\");\n",[158,246,248],{"class":160,"line":247},6,[158,249,250],{},"    return 1;\n",[158,252,254],{"class":160,"line":253},7,[158,255,256],{},"}\n",[158,258,260],{"class":160,"line":259},8,[158,261,262],{},"\u002F*\n",[158,264,266],{"class":160,"line":265},9,[158,267,268],{}," * Evergreen（默认）：\n",[158,270,272],{"class":160,"line":271},10,[158,273,274],{}," *   不调 webview_set_runtime_path，webview_init() 自动用系统 Runtime。\n",[158,276,278],{"class":160,"line":277},11,[158,279,280],{}," *   Windows 11 已预装，Windows 10 需手动安装。\n",[158,282,284],{"class":160,"line":283},12,[158,285,286],{}," *\u002F\n",[158,288,290],{"class":160,"line":289},13,[158,291,292],{},"init_app();\n",[158,294,296],{"class":160,"line":295},14,[158,297,298],{},"\u002F\u002F ... 创建 WebView 窗口 ...\n",[158,300,302],{"class":160,"line":301},15,[158,303,304],{},"run_app();\n",[158,306,308],{"class":160,"line":307},16,[158,309,310],{},"webview_cleanup();\n",[144,312,314],{"id":313},"创建-webview","创建 WebView",[149,316,318],{"className":151,"code":317,"language":153,"meta":154,"style":154},"HWND create_webview(HWND parent, int x, int y, int w, int h);\n",[21,319,320],{"__ignoreMap":154},[158,321,322],{"class":160,"line":161},[158,323,317],{},[17,325,326,327,330,331,334,335,338,339,342],{},"在父窗口中创建 WebView2 子控件。参数与 ",[21,328,329],{},"create_button"," \u002F ",[21,332,333],{},"create_label"," 一致：",[21,336,337],{},"(x, y)"," 左上角坐标，",[21,340,341],{},"(w, h)"," 宽高。",[17,344,345,346,349,350,353],{},"WebView 的 Environment 和 Controller 是",[35,347,348],{},"异步创建","的，函数返回后 WebView 尚未就绪——需配合 ",[21,351,352],{},"on_webview_ready"," 回调使用。",[149,355,357],{"className":151,"code":356,"language":153,"meta":154,"style":154},"HWND win = create_window(L\"WebView Demo\", 960, 640);\nHWND wv = create_webview(win, 0, 0, 960, 600);\n",[21,358,359,364],{"__ignoreMap":154},[158,360,361],{"class":160,"line":161},[158,362,363],{},"HWND win = create_window(L\"WebView Demo\", 960, 640);\n",[158,365,366],{"class":160,"line":167},[158,367,368],{},"HWND wv = create_webview(win, 0, 0, 960, 600);\n",[144,370,372],{"id":371},"导航-内容","导航 & 内容",[149,374,376],{"className":151,"code":375,"language":153,"meta":154,"style":154},"void webview_navigate(HWND hwv, const WCHAR *url);\nvoid webview_load_html(HWND hwv, const WCHAR *html);\n",[21,377,378,383],{"__ignoreMap":154},[158,379,380],{"class":160,"line":161},[158,381,382],{},"void webview_navigate(HWND hwv, const WCHAR *url);\n",[158,384,385],{"class":160,"line":167},[158,386,387],{},"void webview_load_html(HWND hwv, const WCHAR *html);\n",[17,389,390,393,394,400],{},[21,391,392],{},"webview_navigate"," 导航到指定 URL。",[35,395,396,397,399],{},"通常在 ",[21,398,352],{}," 回调中调用","，确保 WebView 已就绪。",[17,402,403,406,407,410],{},[21,404,405],{},"webview_load_html"," 加载 HTML 字符串（",[21,408,409],{},"\u003Chtml>...\u003C\u002Fhtml>","）。",[17,412,413,414,417],{},"如果在 ",[21,415,416],{},"ready"," 之前调用，请求会自动排队，WebView 就绪后执行。",[149,419,421],{"className":151,"code":420,"language":153,"meta":154,"style":154},"static void on_ready(HWND hwv, void *data) {\n    webview_navigate(hwv, L\"https:\u002F\u002Fwww.bing.com\");\n    \u002F\u002F 或：\n    \u002F\u002F webview_load_html(hwv, L\"\u003Chtml>\u003Cbody>\u003Ch1>Hello\u003C\u002Fh1>\u003C\u002Fbody>\u003C\u002Fhtml>\");\n}\n",[21,422,423,428,433,438,443],{"__ignoreMap":154},[158,424,425],{"class":160,"line":161},[158,426,427],{},"static void on_ready(HWND hwv, void *data) {\n",[158,429,430],{"class":160,"line":167},[158,431,432],{},"    webview_navigate(hwv, L\"https:\u002F\u002Fwww.bing.com\");\n",[158,434,435],{"class":160,"line":173},[158,436,437],{},"    \u002F\u002F 或：\n",[158,439,440],{"class":160,"line":235},[158,441,442],{},"    \u002F\u002F webview_load_html(hwv, L\"\u003Chtml>\u003Cbody>\u003Ch1>Hello\u003C\u002Fh1>\u003C\u002Fbody>\u003C\u002Fhtml>\");\n",[158,444,445],{"class":160,"line":241},[158,446,256],{},[144,448,449],{"id":449},"就绪回调",[149,451,453],{"className":151,"code":452,"language":153,"meta":154,"style":154},"typedef void (*webview_ready_fn)(HWND hwv, void *data);\nvoid on_webview_ready(HWND hwv, webview_ready_fn cb, void *data);\n",[21,454,455,460],{"__ignoreMap":154},[158,456,457],{"class":160,"line":161},[158,458,459],{},"typedef void (*webview_ready_fn)(HWND hwv, void *data);\n",[158,461,462],{"class":160,"line":167},[158,463,464],{},"void on_webview_ready(HWND hwv, webview_ready_fn cb, void *data);\n",[17,466,467,468,330,470,330,472,475],{},"WebView2 异步初始化完成后触发。这是安全调用 ",[21,469,392],{},[21,471,405],{},[21,473,474],{},"webview_post_message"," 的时机。",[144,477,479],{"id":478},"js-双向通信","JS 双向通信",[17,481,482],{},"C 与 WebView 中页面可通过以下两种方式进行双向通信。",[484,485,487],"h3",{"id":486},"方式一原始-postmessage","方式一：原始 postMessage",[149,489,491],{"className":151,"code":490,"language":153,"meta":154,"style":154},"typedef void (*webview_message_fn)(HWND hwv, const char *json, void *data);\nvoid on_webview_message(HWND hwv, webview_message_fn cb, void *data);\nvoid webview_post_message(HWND hwv, const char *json);\n",[21,492,493,498,503],{"__ignoreMap":154},[158,494,495],{"class":160,"line":161},[158,496,497],{},"typedef void (*webview_message_fn)(HWND hwv, const char *json, void *data);\n",[158,499,500],{"class":160,"line":167},[158,501,502],{},"void on_webview_message(HWND hwv, webview_message_fn cb, void *data);\n",[158,504,505],{"class":160,"line":173},[158,506,507],{},"void webview_post_message(HWND hwv, const char *json);\n",[17,509,510,104,513,515,516,519],{},[35,511,512],{},"C → JS：",[21,514,474],{}," 向 WebView 中页面发送 JSON 字符串。页面通过 ",[21,517,518],{},"window.chrome.webview.addEventListener('message', ...)"," 接收。",[17,521,522,525,526,529,530,533],{},[35,523,524],{},"JS → C："," 页面通过 ",[21,527,528],{},"window.chrome.webview.postMessage(json)"," 发送消息，C 端通过 ",[21,531,532],{},"on_webview_message"," 注册的回调接收。",[149,535,537],{"className":151,"code":536,"language":153,"meta":154,"style":154},"\u002F\u002F C 端接收 JS 消息\nstatic void on_msg(HWND hwv, const char *json, void *data) {\n    \u002F\u002F json 是从 JS 发来的字符串\n    log_info(L\"收到 JS 消息\");\n    \u002F\u002F 回复消息给 JS\n    webview_post_message(hwv, \"{\\\"reply\\\": \\\"你好 JS\\\"}\");\n}\n\n\u002F\u002F 注册\non_webview_message(wv, on_msg, NULL);\n",[21,538,539,544,549,554,559,564,569,573,579,584],{"__ignoreMap":154},[158,540,541],{"class":160,"line":161},[158,542,543],{},"\u002F\u002F C 端接收 JS 消息\n",[158,545,546],{"class":160,"line":167},[158,547,548],{},"static void on_msg(HWND hwv, const char *json, void *data) {\n",[158,550,551],{"class":160,"line":173},[158,552,553],{},"    \u002F\u002F json 是从 JS 发来的字符串\n",[158,555,556],{"class":160,"line":235},[158,557,558],{},"    log_info(L\"收到 JS 消息\");\n",[158,560,561],{"class":160,"line":241},[158,562,563],{},"    \u002F\u002F 回复消息给 JS\n",[158,565,566],{"class":160,"line":247},[158,567,568],{},"    webview_post_message(hwv, \"{\\\"reply\\\": \\\"你好 JS\\\"}\");\n",[158,570,571],{"class":160,"line":253},[158,572,256],{},[158,574,575],{"class":160,"line":259},[158,576,578],{"emptyLinePlaceholder":577},true,"\n",[158,580,581],{"class":160,"line":265},[158,582,583],{},"\u002F\u002F 注册\n",[158,585,586],{"class":160,"line":271},[158,587,588],{},"on_webview_message(wv, on_msg, NULL);\n",[17,590,591],{},"页面端示例：",[149,593,597],{"className":594,"code":595,"language":596,"meta":154,"style":154},"language-js shiki shiki-themes github-light github-dark","\u002F\u002F JS 端发送消息到 C\nwindow.chrome.webview.postMessage(JSON.stringify({ type: \"click\", value: 42 }));\n\n\u002F\u002F JS 端接收 C 消息\nwindow.chrome.webview.addEventListener(\"message\", (e) => {\n    console.log(\"C 发来:\", e.data);\n});\n","js",[21,598,599,605,644,648,653,682,698],{"__ignoreMap":154},[158,600,601],{"class":160,"line":161},[158,602,604],{"class":603},"sJ8bj","\u002F\u002F JS 端发送消息到 C\n",[158,606,607,611,615,618,622,625,628,631,635,638,641],{"class":160,"line":167},[158,608,610],{"class":609},"sVt8B","window.chrome.webview.",[158,612,614],{"class":613},"sScJk","postMessage",[158,616,617],{"class":609},"(",[158,619,621],{"class":620},"sj4cs","JSON",[158,623,624],{"class":609},".",[158,626,627],{"class":613},"stringify",[158,629,630],{"class":609},"({ type: ",[158,632,634],{"class":633},"sZZnC","\"click\"",[158,636,637],{"class":609},", value: ",[158,639,640],{"class":620},"42",[158,642,643],{"class":609}," }));\n",[158,645,646],{"class":160,"line":173},[158,647,578],{"emptyLinePlaceholder":577},[158,649,650],{"class":160,"line":235},[158,651,652],{"class":603},"\u002F\u002F JS 端接收 C 消息\n",[158,654,655,657,660,662,665,668,672,675,679],{"class":160,"line":241},[158,656,610],{"class":609},[158,658,659],{"class":613},"addEventListener",[158,661,617],{"class":609},[158,663,664],{"class":633},"\"message\"",[158,666,667],{"class":609},", (",[158,669,671],{"class":670},"s4XuR","e",[158,673,674],{"class":609},") ",[158,676,678],{"class":677},"szBVR","=>",[158,680,681],{"class":609}," {\n",[158,683,684,687,690,692,695],{"class":160,"line":247},[158,685,686],{"class":609},"    console.",[158,688,689],{"class":613},"log",[158,691,617],{"class":609},[158,693,694],{"class":633},"\"C 发来:\"",[158,696,697],{"class":609},", e.data);\n",[158,699,700],{"class":160,"line":253},[158,701,702],{"class":609},"});\n",[484,704,706],{"id":705},"方式二bridge推荐","方式二：Bridge（推荐）",[17,708,709,710,713],{},"Bridge 在页面启动时自动注入 ",[21,711,712],{},"window.eduwin"," 对象，封装了原始 postMessage，提供更简洁的双向调用方式。",[149,715,717],{"className":151,"code":716,"language":153,"meta":154,"style":154},"void webview_bridge_init(HWND hwv);\n",[21,718,719],{"__ignoreMap":154},[158,720,721],{"class":160,"line":161},[158,722,716],{},[17,724,725,726,729,730,733],{},"启用 Bridge。调用后 WebView 中所有页面自动获得 ",[21,727,728],{},"window.eduwin.on_message(cb)"," 和 ",[21,731,732],{},"window.eduwin.call(func, params, callback)"," 方法。",[149,735,737],{"className":151,"code":736,"language":153,"meta":154,"style":154},"typedef void (*webview_bridge_fn)(HWND hwv, const char *func_name, const char *params_json, void *data);\nvoid webview_bridge_register(const char *func_name, webview_bridge_fn cb, void *data);\n",[21,738,739,744],{"__ignoreMap":154},[158,740,741],{"class":160,"line":161},[158,742,743],{},"typedef void (*webview_bridge_fn)(HWND hwv, const char *func_name, const char *params_json, void *data);\n",[158,745,746],{"class":160,"line":167},[158,747,748],{},"void webview_bridge_register(const char *func_name, webview_bridge_fn cb, void *data);\n",[17,750,751,752,755,756,759,760,763],{},"注册一个 C 端 bridge 处理函数，供 JS 通过 ",[21,753,754],{},"eduwin.call(func_name, params)"," 调用。",[21,757,758],{},"params_json"," 是参数字符串（JSON 格式），如 ",[21,761,762],{},"{\"name\":\"eduwin\"}","。",[149,765,767],{"className":151,"code":766,"language":153,"meta":154,"style":154},"\u002F* C 端注册 *\u002F\nstatic void on_hello(HWND hwv, const char *func, const char *params, void *d) {\n    webview_post_message(hwv, \"{\\\"reply\\\":\\\"你好！\\\"}\");\n}\nwebview_bridge_register(\"hello\", on_hello, NULL);\n",[21,768,769,774,779,784,788],{"__ignoreMap":154},[158,770,771],{"class":160,"line":161},[158,772,773],{},"\u002F* C 端注册 *\u002F\n",[158,775,776],{"class":160,"line":167},[158,777,778],{},"static void on_hello(HWND hwv, const char *func, const char *params, void *d) {\n",[158,780,781],{"class":160,"line":173},[158,782,783],{},"    webview_post_message(hwv, \"{\\\"reply\\\":\\\"你好！\\\"}\");\n",[158,785,786],{"class":160,"line":235},[158,787,256],{},[158,789,790],{"class":160,"line":241},[158,791,792],{},"webview_bridge_register(\"hello\", on_hello, NULL);\n",[149,794,796],{"className":594,"code":795,"language":596,"meta":154,"style":154},"\u002F* JS 端调用 *\u002F\neduwin.call(\"hello\", { name: \"eduwin\" }, function (r) {\n    console.log(r.reply); \u002F\u002F \"你好！\"\n});\n",[21,797,798,803,837,849],{"__ignoreMap":154},[158,799,800],{"class":160,"line":161},[158,801,802],{"class":603},"\u002F* JS 端调用 *\u002F\n",[158,804,805,808,811,813,816,819,822,825,828,831,834],{"class":160,"line":167},[158,806,807],{"class":609},"eduwin.",[158,809,810],{"class":613},"call",[158,812,617],{"class":609},[158,814,815],{"class":633},"\"hello\"",[158,817,818],{"class":609},", { name: ",[158,820,821],{"class":633},"\"eduwin\"",[158,823,824],{"class":609}," }, ",[158,826,827],{"class":677},"function",[158,829,830],{"class":609}," (",[158,832,833],{"class":670},"r",[158,835,836],{"class":609},") {\n",[158,838,839,841,843,846],{"class":160,"line":173},[158,840,686],{"class":609},[158,842,689],{"class":613},[158,844,845],{"class":609},"(r.reply); ",[158,847,848],{"class":603},"\u002F\u002F \"你好！\"\n",[158,850,851],{"class":160,"line":235},[158,852,702],{"class":609},[17,854,855,856,859,860,862],{},"Bridge 的底层仍基于 postMessage，消息类型为 ",[21,857,858],{},"{ type: \"bridge_call\", func, params, id }","。C 端自动路由到已注册的处理函数，未被识别为 bridge 的消息仍会传给 ",[21,861,532],{}," 回调。",[144,864,865],{"id":865},"导航控制",[149,867,869],{"className":151,"code":868,"language":153,"meta":154,"style":154},"void webview_back(HWND hwv);\nvoid webview_forward(HWND hwv);\nvoid webview_reload(HWND hwv);\n",[21,870,871,876,881],{"__ignoreMap":154},[158,872,873],{"class":160,"line":161},[158,874,875],{},"void webview_back(HWND hwv);\n",[158,877,878],{"class":160,"line":167},[158,879,880],{},"void webview_forward(HWND hwv);\n",[158,882,883],{"class":160,"line":173},[158,884,885],{},"void webview_reload(HWND hwv);\n",[17,887,888],{},"浏览器的后退、前进、刷新操作。仅在 WebView 就绪后有效。",[144,890,891],{"id":891},"导航完成回调",[149,893,895],{"className":151,"code":894,"language":153,"meta":154,"style":154},"typedef void (*webview_nav_complete_fn)(HWND hwv, int success, int status_code, void *data);\nvoid on_navigation_completed(HWND hwv, webview_nav_complete_fn cb, void *data);\n",[21,896,897,902],{"__ignoreMap":154},[158,898,899],{"class":160,"line":161},[158,900,901],{},"typedef void (*webview_nav_complete_fn)(HWND hwv, int success, int status_code, void *data);\n",[158,903,904],{"class":160,"line":167},[158,905,906],{},"void on_navigation_completed(HWND hwv, webview_nav_complete_fn cb, void *data);\n",[17,908,909,910,913],{},"注册导航完成回调。页面加载完成后触发，",[21,911,912],{},"success"," 为 1 表示成功，0 表示失败。",[149,915,917],{"className":151,"code":916,"language":153,"meta":154,"style":154},"static void on_nav(HWND hwv, int success, int code, void *d) {\n    set_text(g_status, success ? L\"Done\" : L\"Failed\");\n}\non_navigation_completed(wv, on_nav, NULL);\n",[21,918,919,924,929,933],{"__ignoreMap":154},[158,920,921],{"class":160,"line":161},[158,922,923],{},"static void on_nav(HWND hwv, int success, int code, void *d) {\n",[158,925,926],{"class":160,"line":167},[158,927,928],{},"    set_text(g_status, success ? L\"Done\" : L\"Failed\");\n",[158,930,931],{"class":160,"line":173},[158,932,256],{},[158,934,935],{"class":160,"line":235},[158,936,937],{},"on_navigation_completed(wv, on_nav, NULL);\n",[144,939,941],{"id":940},"virtual-host-加载本地网页文件","Virtual Host — 加载本地网页文件",[17,943,944,945,948],{},"将本地文件夹映射为虚拟域名，绕过 ",[21,946,947],{},"file:\u002F\u002F\u002F"," 的限制，正常加载外部 HTML\u002FCSS\u002FJS。",[149,950,952],{"className":151,"code":951,"language":153,"meta":154,"style":154},"void webview_set_virtual_host(HWND hwv, const WCHAR *host_name, const WCHAR *folder_path);\n",[21,953,954],{"__ignoreMap":154},[158,955,956],{"class":160,"line":161},[158,957,951],{},[17,959,960,963,964,967,968,971],{},[21,961,962],{},"host_name"," 为虚拟域名（如 ",[21,965,966],{},"L\"eduwin.local\"","），",[21,969,970],{},"folder_path"," 为本地文件夹路径（相对路径基于 exe 所在目录，也支持绝对路径）。",[149,973,975],{"className":151,"code":974,"language":153,"meta":154,"style":154},"\u002F* 映射当前 exe 目录到 eduwin.local *\u002F\nwebview_set_virtual_host(hwv, L\"eduwin.local\", L\".\");\n\n\u002F* 然后通过 https 访问本地文件 *\u002F\nwebview_navigate(hwv, L\"https:\u002F\u002Feduwin.local\u002Findex.html\");\n",[21,976,977,982,987,991,996],{"__ignoreMap":154},[158,978,979],{"class":160,"line":161},[158,980,981],{},"\u002F* 映射当前 exe 目录到 eduwin.local *\u002F\n",[158,983,984],{"class":160,"line":167},[158,985,986],{},"webview_set_virtual_host(hwv, L\"eduwin.local\", L\".\");\n",[158,988,989],{"class":160,"line":173},[158,990,578],{"emptyLinePlaceholder":577},[158,992,993],{"class":160,"line":235},[158,994,995],{},"\u002F* 然后通过 https 访问本地文件 *\u002F\n",[158,997,998],{"class":160,"line":241},[158,999,1000],{},"webview_navigate(hwv, L\"https:\u002F\u002Feduwin.local\u002Findex.html\");\n",[14,1002,1003],{},[17,1004,1005,1006,1009],{},"Virtual Host 的访问权限为 ",[21,1007,1008],{},"COREWEBVIEW2_HOST_RESOURCE_ACCESS_KIND_DENY_CORS","，禁止跨域请求但允许正常加载同域资源。",[144,1011,1012],{"id":1012},"完整示例",[17,1014,1015],{},"参见：",[110,1017,1018,1024],{},[113,1019,1020,1023],{},[21,1021,1022],{},"samples\u002Fwebview_browser\u002F"," —— 简易浏览器（工具栏 + 地址栏 + 状态栏）",[113,1025,1026,1029],{},[21,1027,1028],{},"samples\u002Fwebview_bridge\u002F"," —— Bridge 演示（C ↔ JS 双向通信 + 外部 HTML\u002FCSS\u002FJS 加载）",[144,1031,1032],{"id":1032},"链接库",[17,1034,1035,1036,1039],{},"使用 WebView2 模块时，",[21,1037,1038],{},"build.bat"," 需额外链接：",[149,1041,1045],{"className":1042,"code":1043,"language":1044,"meta":154,"style":154},"language-bat shiki shiki-themes github-light github-dark","link ... WebView2LoaderStatic.lib ole32.lib oleaut32.lib version.lib advapi32.lib\n","bat",[21,1046,1047],{"__ignoreMap":154},[158,1048,1049],{"class":160,"line":161},[158,1050,1043],{},[39,1052,1053,1063],{},[42,1054,1055],{},[45,1056,1057,1060],{},[48,1058,1059],{},"库",[48,1061,1062],{},"用途",[61,1064,1065,1075,1085,1095,1105],{},[45,1066,1067,1072],{},[66,1068,1069],{},[21,1070,1071],{},"WebView2LoaderStatic.lib",[66,1073,1074],{},"WebView2 环境加载器",[45,1076,1077,1082],{},[66,1078,1079],{},[21,1080,1081],{},"ole32.lib",[66,1083,1084],{},"COM 基础（CoInitializeEx 等）",[45,1086,1087,1092],{},[66,1088,1089],{},[21,1090,1091],{},"oleaut32.lib",[66,1093,1094],{},"COM 自动化",[45,1096,1097,1102],{},[66,1098,1099],{},[21,1100,1101],{},"version.lib",[66,1103,1104],{},"版本信息查询",[45,1106,1107,1112],{},[66,1108,1109],{},[21,1110,1111],{},"advapi32.lib",[66,1113,1114],{},"注册表（检测 WebView2 Runtime）",[144,1116,1117],{"id":1117},"实现架构",[149,1119,1124],{"className":1120,"code":1122,"language":1123},[1121],"language-text","eduwin_webview.c (纯 C)\n├── 模式 A: Flat API ── CreateCoreWebView2EnvironmentWithOptions(...)\n├── 模式 B: lpVtbl ──── controller->lpVtbl->put_Bounds(...)\n│                       webview->lpVtbl->Navigate(...)\n└── 模式 C: 回调 vtable ─ env_handler_t \u002F ctrl_handler_t \u002F msg_handler_t\n                         (手写 QueryInterface \u002F AddRef \u002F Release \u002F Invoke)\n","text",[21,1125,1122],{"__ignoreMap":154},[17,1127,1128,1129,1132],{},"三种 COM 互操作模式全部在纯 C 中完成，未引入 ",[21,1130,1131],{},".cpp"," 文件。",[1134,1135,1136],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}",{"title":154,"searchDepth":167,"depth":167,"links":1138},[1139,1140,1141,1142,1143,1147,1148,1149,1150,1151,1152],{"id":146,"depth":167,"text":147},{"id":313,"depth":167,"text":314},{"id":371,"depth":167,"text":372},{"id":449,"depth":167,"text":449},{"id":478,"depth":167,"text":479,"children":1144},[1145,1146],{"id":486,"depth":173,"text":487},{"id":705,"depth":173,"text":706},{"id":865,"depth":167,"text":865},{"id":891,"depth":167,"text":891},{"id":940,"depth":167,"text":941},{"id":1012,"depth":167,"text":1012},{"id":1032,"depth":167,"text":1032},{"id":1117,"depth":167,"text":1117},"md",{},"\u002Fdocs\u002Fapi\u002Feduwin-webview-api",{"title":5,"description":154},"docs\u002Fapi\u002Feduwin-webview-api","CethnAkaGczUX39tfUygDsrORxHeg95Udju0uuDw8J4",1782488679850]