howill2021 发表于 2026-6-6 21:48:22

这个厉害,比使用edg打包方便多了
大佬,对方需要有webview环境或者edg吗?

kanshijian 发表于 2026-6-6 22:07:56

:噜阿噜感谢大佬,先试试

howill2021 发表于 2026-6-6 22:58:54

大佬,有点尴尬,系统没WebView环境还运行不了{:2_25:}

kca 发表于 2026-6-6 23:33:44

66666666666666

3219720339 发表于 2026-6-7 09:22:27

kankan

happer 发表于 2026-6-7 09:40:28

不错                                    

小莫 发表于 2026-6-7 15:59:31

谢谢,看一下

domingo 发表于 2026-6-7 16:28:53

经过测试发现,该库在win2012服务器,安装相应环境后,依然无法打开软件;但是别人的WEBUI程序可以打开。

后面经过和AI一起的分析,分析了大概两个多小时,成功定位到问题:

XHwebUI 当前库强制调用 ICoreWebView2Settings9
Windows Server 2012 R2 上的 WebView2 Runtime 109 不支持该高版本接口
导致原先 创建主窗口() 返回假

解决方案:牺牲一点无边框拖拽高级特性,在UI类的创建webview2中打入相应兼容补丁。

方法 创建webview2 <类型 = 逻辑型 @禁止流程检查 = 真>
    {
      @ if(!g_env)return false;
      @ HANDLE event = CreateEvent(NULL, TRUE, FALSE, NULL);
      @ if (!event) return false;
      @ bool ret = false;
      // 创建控制器和webview2
      @ HRESULT hr = g_env->CreateCoreWebView2Controller(window, Callback<ICoreWebView2CreateCoreWebView2ControllerCompletedHandler>((HRESULT result, ICoreWebView2Controller* controller) -> HRESULT
      @ {
      @   ret = (SUCCEEDED(result) && controller != nullptr);
      @   if(ret)
      @   {
      @         this->controller = controller;
      @         controller->get_CoreWebView2(&this->webview);
      @
      @         RECT bounds;
      @         GetClientRect(this->window, &bounds);
      @         controller->put_Bounds(bounds);
      @         // 唤醒渲染睡眠
      @         controller->put_IsVisible(FALSE);
      @         controller->put_IsVisible(TRUE);
      @         controller->NotifyParentWindowPositionChanged();
      @
      @         // 将本地对象添加到脚本中
      @         VARIANT var = { 0 };
      @         var.vt = VT_DISPATCH;
      @         var.pdispVal = this->hostObj.Get();
      @         ret = SUCCEEDED(webview->AddHostObjectToScript(L"host",&var));
      @   }
      @   SetEvent(event);
      @   return S_OK;
      @ }).Get());

      @ if(FAILED(hr))CloseHandle(event);
      @ else WaitEvent(event, window);

      @ if(!ret)return false;

      // 对webview2进行一些设置
      @ Microsoft::WRL::ComPtr<ICoreWebView2Settings> settings;
      @ hr = webview->get_Settings(&settings);
      @ if(FAILED(hr))return false;
      @ Microsoft::WRL::ComPtr<ICoreWebView2Settings9> settings9;
      @ hr = settings.As(&settings9);
      @ if(SUCCEEDED(hr) && settings9 != nullptr)
      @ {
      @   settings9->put_IsNonClientRegionSupportEnabled(TRUE);
      @ }

      // 非调试版本禁止右键菜单和
      @ #ifndef _DEBUG
      @    // 监听按键
      @   hr = controller->add_AcceleratorKeyPressed(Callback<ICoreWebView2AcceleratorKeyPressedEventHandler>([](ICoreWebView2Controller* controller, ICoreWebView2AcceleratorKeyPressedEventArgs* args) -> HRESULT
      @   {
      @         //检测快捷键
      @         UINT32 virtualKey;
      @         args->get_VirtualKey(&virtualKey);
      @         if (virtualKey == VK_F5 || virtualKey == VK_F7 || virtualKey == VK_F12)//屏蔽刷新和开发者工具
      @         {
      @             args->put_Handled(TRUE);
      @             return S_OK;
      @         }
      @
      @         //检查功能键
      @         if(GetKeyState(VK_CONTROL) < 0)//Ctrl
      @         {
      @             if (virtualKey == 'F' || virtualKey == 'P' || virtualKey == 'R' || virtualKey == 'G' || virtualKey == 'J' || virtualKey == 'U')
      @             {
      @               args->put_Handled(TRUE);
      @               return S_OK;
      @             }
      @
      @             if (GetKeyState(VK_SHIFT) < 0)//Shift
      @             {
      @               if (virtualKey == 'I')
      @               {
      @                     args->put_Handled(TRUE);
      @                     return S_OK;
      @               }
      @             }
      @         }
      @
      @         if (GetKeyState(VK_MENU) < 0)//Alt
      @         {
      @             if(virtualKey == VK_LEFT || virtualKey == VK_RIGHT)
      @             {
      @               args->put_Handled(TRUE);
      @               return S_OK;
      @             }
      @         }
      @
      @         return S_OK;
      @   }).Get(), nullptr);
      @    if(FAILED(hr))return false;
      @
      @   //禁用状态栏
      @   hr = settings->put_IsStatusBarEnabled(false);
      @   if(FAILED(hr))return false;
      @   //禁用开发者工具
      @   settings->put_AreDevToolsEnabled(false);
      @   if(FAILED(hr))return false;
      @   //禁用右键菜单
      @   settings->put_AreDefaultContextMenusEnabled(false);
      @   if(FAILED(hr))return false;
      @
      @ #endif

      // 资源所有过滤
      @ hr = webview->AddWebResourceRequestedFilter(L"*", COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL);
      @ if(FAILED(hr))return false;

      // 设置开始加载事件
      @ hr = webview->add_WebResourceRequested(Callback<ICoreWebView2WebResourceRequestedEventHandler>((ICoreWebView2* sender, ICoreWebView2WebResourceRequestedEventArgs* args) -> HRESULT
      @ {
      @   ComPtr<ICoreWebView2WebResourceRequest> request;
      @   HRESULT hr = args->get_Request(&request);
      @   if (FAILED(hr)) return hr;
      @   LPWSTR uri = nullptr;
      @   hr = request->get_Uri(&uri);
      @   if (FAILED(hr) || uri == nullptr) return hr;
      @   CVolString* str = new CVolString(uri);
      @   if(pUrls->find (uri) != pUrls->end ())
      @   {
      @         hr = args->put_Response((*pUrls).Get());
      @         if(!PostMessageW(this->window, WM_USER + 50, (WPARAM)str, 0))delete str;
      @   }else if(g_urls.find (uri) != g_urls.end ())
      @   {
      @         hr = args->put_Response(g_urls.Get());
      @         if(!PostMessageW(this->window, WM_USER + 50, (WPARAM)str, 1))delete str;
      @   }else
      @   {
      @         if(!PostMessageW(this->window, WM_USER + 50, (WPARAM)str, -1))delete str;
      @   }
      @
      @   CoTaskMemFree(uri);
      @
      @   return hr;
      @ }).Get(), nullptr);


      // 设置加载完成事件
      @ BOOL show = @<窗口可视>;
      @ hr = webview->add_NavigationCompleted(Callback<ICoreWebView2NavigationCompletedEventHandler>((ICoreWebView2* sender, ICoreWebView2NavigationCompletedEventArgs* args) -> HRESULT
      @ {
      @   if(this->cwin != this->window)
      @   {
      @         if(show)ShowWindow(this->window, SW_SHOW);
      @         this->cwin = this->window;
      @   }
      @
      @   LPWSTR url = nullptr;
      @   if (SUCCEEDED(sender->get_Source(&url)) && url != nullptr)
      @   {
      @         int httpStatusCode = 0;
      @         BOOL success = false;
      @         args->get_IsSuccess(&success);
      @         if(success)
      @         {
      @             Microsoft::WRL::ComPtr<ICoreWebView2NavigationCompletedEventArgs2> args2;
      @             if (SUCCEEDED(args->QueryInterface(IID_PPV_ARGS(&args2))))args2->get_HttpStatusCode(&httpStatusCode);
      @         }
      @
      @         sender->ExecuteScript(funcJS.GetText(), nullptr);
      @         CVolString* str = new CVolString(url);
      @         if(!PostMessageW(this->window, WM_USER + 51, (WPARAM)str, httpStatusCode))delete str;
      @         CoTaskMemFree(url);
      @   }
      @
      @   return S_OK;
      @ }).Get(), nullptr);
      @ if(FAILED(hr))return false;

      // 框架页面加载完毕事件
      @ hr = webview->add_FrameNavigationCompleted(Callback<ICoreWebView2NavigationCompletedEventHandler>((ICoreWebView2* sender, ICoreWebView2NavigationCompletedEventArgs* args) -> HRESULT
      @ {
      @   LPWSTR url = nullptr;
      @   if (SUCCEEDED(sender->get_Source(&url)) && url != nullptr)
      @   {
      @         int httpStatusCode = 0;
      @         BOOL success = false;
      @         args->get_IsSuccess(&success);
      @         if(success)
      @         {
      @             Microsoft::WRL::ComPtr<ICoreWebView2NavigationCompletedEventArgs2> args2;
      @             if (SUCCEEDED(args->QueryInterface(IID_PPV_ARGS(&args2))))args2->get_HttpStatusCode(&httpStatusCode);
      @         }
      @
      @         sender->ExecuteScript(funcJS.GetText(), nullptr);
      @         CVolString* str = new CVolString(url);
      @         if(!PostMessageW(this->window, WM_USER + 51, (WPARAM)str, httpStatusCode))delete str;
      @         CoTaskMemFree(url);
      @   }
      @
      @   return S_OK;
      @ }).Get(), nullptr);
      @ if(FAILED(hr))return false;

      // 标题改变事件
      @ hr = webview->add_DocumentTitleChanged(Callback<ICoreWebView2DocumentTitleChangedEventHandler>((ICoreWebView2* sender, IUnknown* args) -> HRESULT
      @ {
      @   LPWSTR title = nullptr;
      @   if (this->window && SUCCEEDED(sender->get_DocumentTitle(&title)) && title != nullptr)
      @   {
      @         SetWindowTextW(this->window, title);
      @         CoTaskMemFree(title);
      @   }
      @   return S_OK;
      @ }).Get(), nullptr);
      @ if(FAILED(hr))return false;

      // 全屏切换事件
      @ hr = webview->add_ContainsFullScreenElementChanged(Callback<ICoreWebView2ContainsFullScreenElementChangedEventHandler>((ICoreWebView2* sender, IUnknown* args) -> HRESULT
      @ {
      @   if (sender && this->window)
      @   {
      @         BOOL isFullScreen = FALSE;
      @         sender->get_ContainsFullScreenElement(&isFullScreen);
      @         RECT rect;
      @         GetWindowRect(this->window, &rect);
      @         *this->pFull =(rect.left == 0 && rect.top ==0 && rect.right == GetSystemMetrics (SM_CXSCREEN) && rect.bottom == GetSystemMetrics (SM_CYSCREEN));
      @         if(*this->pFull == (bool)isFullScreen)return S_OK;
      @
      @         *this->pFull = isFullScreen;
      @         if(*this->pFull )
      @         {
      @             this->oldWndPos.length = sizeof(WINDOWPLACEMENT);
      @             GetWindowPlacement(this->window, &this->oldWndPos);
      @             DWORD style = GetWindowLong(this->window, GWL_STYLE);
      @             this->oldStyle = style;
      @             if((style & WS_CAPTION) == WS_CAPTION)style &= ~WS_CAPTION;
      @             if((style & WS_THICKFRAME) == WS_THICKFRAME)style &= ~WS_THICKFRAME;
      @             SetWindowLongPtr(this->window, GWL_STYLE, style);
      @             SetWindowPos (this->window, NULL, 0, 0, GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN), SWP_NOZORDER);
      @         }
      @         else
      @         {
      @             SetWindowLongPtr(this->window, GWL_STYLE, this->oldStyle);
      @             SetWindowPlacement(this->window, &this->oldWndPos);
      @             SetWindowPos(this->window, NULL, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER);//刷新窗口
      @         }
      @   }
      @   return S_OK;
      @ }).Get(), nullptr);
      @ if(FAILED(hr))return false;

      // // 弹出窗口事件
      // @ webview->add_NewWindowRequested(Callback<ICoreWebView2NewWindowRequestedEventHandler>([](ICoreWebView2* sender, ICoreWebView2NewWindowRequestedEventArgs* args) -> HRESULT
      // @ {
      // @   args->put_Handled(TRUE);//阻止创建
      // @   return S_OK;
      // @ }).Get(), nullptr);

      @ if(!@<首页地址>.IsEmpty ())hr = webview->Navigate(@<首页地址>.GetText());

      @ if(FAILED(hr) || @<首页地址>.IsEmpty ())//载入地址错误或不载入地址需要显示窗口
      @ {
      @   if(@<窗口可视>)ShowWindow(window, SW_SHOW);
      @   cwin = window;
      @ }

      @ return true;
    }


主要改动在这个地方:

1、把 XHwebUI 里 CoreWebView2Settings9 获取失败 → return false

改成

ICoreWebView2Settings9 获取成功才启用非客户区支持

获取失败就跳过,继续创建窗口

对应插入的代码如下:

      // 对webview2进行一些设置
      @ Microsoft::WRL::ComPtr<ICoreWebView2Settings> settings;
      @ hr = webview->get_Settings(&settings);
      @ if(FAILED(hr))return false;
      @ Microsoft::WRL::ComPtr<ICoreWebView2Settings9> settings9;
      @ hr = settings.As(&settings9);
      @ if(SUCCEEDED(hr) && settings9 != nullptr)
      @ {
      @   settings9->put_IsNonClientRegionSupportEnabled(TRUE);
      @ }

      // 非调试版本禁止右键菜单和

touching 发表于 2026-6-7 16:35:40

大佬牛逼{:2_25:}{:2_25:}

huningli38 发表于 2026-6-7 16:44:16

感谢开源
页: 1 2 3 [4] 5 6 7 8 9 10 11
查看完整版本: [0622]webUI库-使用AI写webUI,无需前端知识,简单易用