用visual studio 2022编译苹果开源webkit浏览器内核
界面用网易的开源duilib-netease
github仓库 简单的浏览器源码
m_patch = (++m_patch) % 2;用来强制刷新webkit view
(
S
o
l
u
t
i
o
n
D
i
r
)
(SolutionDir)
(SolutionDir)(Platform)$(Configuration)
#####solunar项目##################################################
(
S
o
l
u
t
i
o
n
D
i
r
)
(SolutionDir)
(SolutionDir)(Platform)$(Configuration)
$(ProjectName)
把webkit项目中MiniBrowser的附加库目录复制到solunar项目中,点击编辑框ctrl+a复制所有
同样的复制附加依赖,最后一项添加分号;
中间目录$(Platform)$(Configuration)
把文件复制到D:\VSProject\solunar\x64\Debug,两个文件夹也要复制
复制duilib-netease的resources
<?xml version="1.0" encoding="UTF-8"?>
<Window size="600,700" caption="0,0,0,35" shadowattached="false">
<VBox bkcolor="bk_wnd_darkcolor" bordercolor="purple" bordersize="2">
<HBox width="stretch" height="35">
<Label name="tooltip" text="同辉" font="system_bold_18" normaltextcolor="white" margin="10,6,0,0"/>
<Control />
<Button class="btn_wnd_min" name="minbtn" margin="4,6,0,0"/>
<Box width="21" margin="4,6,0,0">
<Button class="btn_wnd_max" name="maxbtn"/>
<Button class="btn_wnd_restore" name="restorebtn" visible="false"/>
</Box>
<Button class="btn_wnd_close" name="closebtn" margin="4,6,8,0"/>
</HBox>
<VBox>
<HBox height="35" >
<Option class="btn_global_blue_80x30" name="option_baidu" selectedforenormalimage="../public/button/btn_wnd_gray_min_pushed.png" margin="4,0,4,0" text="百度" selected="true" group="quickbar"/>
<Option class="btn_global_blue_80x30" name="option_douyin" selectedforenormalimage="../public/button/btn_wnd_gray_min_pushed.png" margin="4,0,4,0" text="抖音" group="quickbar"/>
</HBox>
<TabBox name="tab_browser">
<VBox>
<Progress class="progress_blue" name="progress_baidu" height="5" value="0" margin="6,0,6,0"/>
<WebkitBrowser name="wb_baidu" bkcolor="purple" margin="6,6,6,6"/>
</VBox>
<VBox>
<Progress class="progress_blue" name="progress_douyin" height="5" value="0" margin="6,0,6,0"/>
<WebkitBrowser name="wb_douyin" bkcolor="purple" margin="6,6,6,6"/>
</VBox>
</TabBox>
</VBox>
</VBox>
</Window>
global.xml
<?xml version="1.0" encoding="UTF-8"?>
<Global>
<!--所有字体-->
<Font id="system_12" name="system" size="12" default="true"/>
<Font id="system_14" name="system" size="14"/>
<Font id="system_16" name="system" size="16"/>
<Font id="system_18" name="system" size="18"/>
<Font id="system_20" name="system" size="20"/>
<Font id="system_22" name="system" size="22"/>
<Font id="system_bold_12" name="system" size="12" bold="true"/>
<Font id="system_bold_14" name="system" size="14" bold="true"/>
<Font id="system_bold_16" name="system" size="16" bold="true"/>
<Font id="system_bold_18" name="system" size="18" bold="true"/>
<Font id="system_bold_20" name="system" size="20" bold="true"/>
<Font id="system_bold_22" name="system" size="22" bold="true"/>
<Font id="arial_12" name="arial" size="12"/>
<Font id="arial_14" name="arial" size="14"/>
<Font id="arial_16" name="arial" size="16"/>
<Font id="arial_18" name="arial" size="18"/>
<Font id="arial_20" name="arial" size="20"/>
<Font id="arial_22" name="arial" size="22"/>
<Font id="arial_bold_12" name="arial" size="12" bold="true"/>
<Font id="arial_bold_14" name="arial" size="14" bold="true"/>
<Font id="arial_bold_16" name="arial" size="16" bold="true"/>
<Font id="arial_bold_18" name="arial" size="18" bold="true"/>
<Font id="arial_bold_20" name="arial" size="20" bold="true"/>
<Font id="arial_bold_22" name="arial" size="22" bold="true"/>
<Font id="system_underline_12" name="system" size="12" underline="true"/>
<Font id="system_underline_14" name="system" size="14" underline="true"/>
<Font id="system_underline_16" name="system" size="16" underline="true"/>
<Font id="system_underline_18" name="system" size="18" underline="true"/>
<Font id="system_underline_20" name="system" size="20" underline="true"/>
<Font id="system_underline_22" name="system" size="22" underline="true"/>
<!--一些常规固定颜色-->
<TextColor name="white" value="#ffffffff"/>
<TextColor name="black" value="#ff000000"/>
<TextColor name="darkcolor" value="#ff333333"/>
<TextColor name="lightcolor" value="#ff888888"/>
<TextColor name="gray" value="#ff8e99a6"/>
<TextColor name="light_gray" value="#ffa8a8a8"/>
<TextColor name="dark_gray" value="#ff72797f"/>
<TextColor name="green" value="#ff00bb96"/>
<TextColor name="light_green" value="#ff21c7a6"/>
<TextColor name="blue" value="#ff006DD9"/>
<TextColor name="red" value="#ffC63535"/>
<TextColor name="purple" value="#ff7160e8"/>
<!--文字色值,不带透明层-->
<TextColor name="textdefaultcolor" value="#ff333333"/>
<TextColor name="textdefaultdisablecolor" value="#ffa1aebc"/>
<!--窗口常用背景色-->
<TextColor name="bk_main_wnd_title" value="#ff238efa"/>
<TextColor name="bk_main_wnd_search" value="#ff1e7ad7"/>
<TextColor name="bk_wnd_darkcolor" value="#ff1f1f1f"/>
<TextColor name="bk_wnd_lightcolor" value="#ffffffff"/>
<TextColor name="bk_menuitem_hovered" value="#ffe1e6eb"/>
<TextColor name="bk_menuitem_selected" value="#ffced4db"/>
<TextColor name="bk_listitem_hovered" value="#fff0f2f5"/>
<TextColor name="bk_listitem_selected" value="#ffe4e7eb"/>
<!--置顶项的背景颜色-->
<TextColor name="bk_topitem_normal" value="#ffffffe0"/>
<TextColor name="bk_topitem_hovered" value="#ffffffeb"/>
<TextColor name="bk_topitem_selected" value="#fffafacd"/>
<!--进度条专用-->
<TextColor name="bk_progress_bk" value="#ffe3ecf5"/>
<TextColor name="bk_progress_progress" value="#ff2aceae"/>
<!--背景色值,半透明-->
<TextColor name="transbkblack" value="#80000000"/>
<!--第一级分割线,较深-->
<TextColor name="splitline_level1" value="#ffd2d4d6"/>
<!--第二级分割线,较浅-->
<TextColor name="splitline_level2" value="#ffebedf0"/>
<!--调色板色值-->
<TextColor name="color_palette1" value="#ffff2600"/>
<TextColor name="color_palette2" value="#ffffeb00"/>
<TextColor name="color_palette3" value="#ff61ed00"/>
<TextColor name="color_palette4" value="#ff00b4ff"/>
<TextColor name="color_palette5" value="#ffa100ff"/>
<TextColor name="color_palette6" value="#ff000000"/>
<TextColor name="color_palette7" value="#ff545454"/>
<TextColor name="color_palette8" value="#ffa8a8a8"/>
<TextColor name="color_palette9" value="#ffffffff"/>
<!--字体大小-->
<Class name="font_title" font="system_14"/>
<!--标题栏-->
<Class name="caption" height="34" bkimage="file='../public/caption/caption_public.png' corner='0,0,0,1'" padding="10,0,5,0" />
<!--滚动条-->
<Class name="vscrollbar" width="14" fadealpha="true" thumbnormalimage="file='../public/vscrollbar/thumb_normal.png' corner='0,8,0,8'" thumbhotimage="file='../public/vscrollbar/thumb_hovered.png' corner='0,8,0,8'" bkhotimage="file='../public/vscrollbar/bk_hovered.png' corner='0,4,0,4'" showbutton1="false" showbutton2="false" />
<Class name="hscrollbar" height="14" fadealpha="true" thumbnormalimage="file='../public/hscrollbar/thumb_normal.png' corner='8,0,8,0'" thumbhotimage="file='../public/hscrollbar/thumb_hovered.png' corner='8,0,8,0'" bkhotimage="file='../public/hscrollbar/bk_hovered.png' corner='4,0,4,0'" showbutton1="false" showbutton2="false"/>
<!--单选框-->
<Class name="option" selectednormalimage="../public/option/selected.png" selectedhotimage="../public/option/selectedhover.png" selectedpushedimage="../public/option/selectedhover.png"/>
<Class name="circle_option" normalimage="../public/option/circle_unselected.png" disabledimage="../public/option/circle_unselected_disabled.png"/>
<Class name="circle_option_2" height="18" textpadding="25,0,0,0" font="system_12" normaltextcolor="darkcolor" normalimage="file='../public/option/circle_unselected.png' dest='0,0,18,18'" selectednormalimage="file='../public/option/circle_selected.png' dest='0,0,18,18'"/>
<!--复选框-->
<Class name="checkbox_font12" height="16" textpadding="20,0,0,0" font="system_12" normaltextcolor="darkcolor" normalimage="file='../public/CheckBox/check_no.png' dest='0,0,16,16'" disabledimage="file='../public/CheckBox/check_no.png' dest='0,0,16,16' fade='80'" selectednormalimage="file='../public/CheckBox/check_yes.png' dest='0,0,16,16'" selecteddisabledimage="file='../public/CheckBox/check_yes.png' dest='0,0,16,16' fade='80'"/>
<Class name="checkbox_font14" height="20" textpadding="20,0,0,0" font="system_14" normaltextcolor="darkcolor" normalimage="file='../public/CheckBox/check_no.png' dest='0,2,16,18'" disabledimage="file='../public/CheckBox/check_no.png' dest='0,2,16,18' fade='80'" selectednormalimage="file='../public/CheckBox/check_yes.png' dest='0,2,16,18'" selecteddisabledimage="file='../public/CheckBox/check_yes.png' dest='0,2,16,18' fade='80'"/>
<Class name="checkbox_green" normalimage="file='../public/CheckBox/check_green_no.png'" disabledimage="file='../public/CheckBox/check_green_no.png' fade='80'" selectednormalimage="file='../public/CheckBox/check_green_yes.png'" selecteddisabledimage="file='../public/CheckBox/check_green_yes.png' fade='80'"/>
<!--按钮-->
<Class name="btn_global_blue_80x30" font="system_bold_14" normaltextcolor="white" normalimage="file='../public/button/btn_global_blue_80x30_normal.png'" hotimage="file='../public/button/btn_global_blue_80x30_hovered.png'" pushedimage="file='../public/button/btn_global_blue_80x30_pushed.png'" disabledimage="file='../public/button/btn_global_blue_80x30_normal.png' fade='80'"/>
<Class name="btn_global_white_80x30" font="system_bold_14" normaltextcolor="dark_gray" normalimage="file='../public/button/btn_global_white_80x30_normal.png'" hotimage="file='../public/button/btn_global_white_80x30_hovered.png'" pushedimage="file='../public/button/btn_global_white_80x30_pushed.png'" disabledimage="file='../public/button/btn_global_white_80x30_normal.png' fade='128'"/>
<Class name="btn_global_red_80x30" font="system_bold_14" normaltextcolor="white" normalimage="file='../public/button/btn_global_red_80x30_normal.png'" hotimage="file='../public/button/btn_global_red_80x30_hovered.png'" pushedimage="file='../public/button/btn_global_red_80x30_pushed.png'" disabledimage="file='../public/button/btn_global_red_80x30_normal.png' fade='80'"/>
<!--窗口右上角按钮 灰色版 -->
<Class name="btn_wnd_min" width="auto" height="auto" forenormalimage="file='../public/button/btn_wnd_gray_min.png' dest='4,4,16,16'" normalimage="" hotimage="../public/button/btn_wnd_gray_min_hovered.png" pushedimage="../public/button/btn_wnd_gray_min_pushed.png"/>
<Class name="btn_wnd_close" width="20" height="20" normalimage="file='../public/button/btn_wnd_gray_close.png' dest='4,4,16,16'" hotimage="../public/button/btn_wnd_white_close_hovered.png" pushedimage="../public/button/btn_wnd_white_close_pushed.png" fadehot="false"/>
<Class name="btn_wnd_max" width="auto" height="auto" forenormalimage="file='../public/button/btn_wnd_gray_max.png' dest='4,4,16,16'" normalimage="" hotimage="../public/button/btn_wnd_gray_max_hovered.png" pushedimage="../public/button/btn_wnd_gray_max_pushed.png"/>
<Class name="btn_wnd_restore" width="auto" height="auto" forenormalimage="file='../public/button/btn_wnd_gray_restore.png' dest='4,4,16,16'" normalimage="" hotimage="../public/button/btn_wnd_gray_restore_hovered.png" pushedimage="../public/button/btn_wnd_gray_restore_pushed.png"/>
<Class name="btn_wnd_settings" width="auto" height="auto" forenormalimage="file='../public/button/btn_wnd_settings.png' source='1,1,21,21'" hotimage="../public/button/btn_wnd_bk_hovered.png" pushedimage="../public/button/btn_wnd_bk_pushed.png"/>
<!--窗口右上角按钮 白色版 -->
<Class name="btn_wnd_white_min" width="auto" height="auto" forenormalimage="file='../public/button/btn_wnd_white_min.png'" normalimage="" hotimage="../public/button/btn_wnd_white_min_hovered.png" pushedimage="../public/button/btn_wnd_white_min_pushed.png"/>
<Class name="btn_wnd_white_close" width="auto" height="auto" forenormalimage="file='../public/button/btn_wnd_white_close.png'" normalimage="" hotimage="../public/button/btn_wnd_white_close_hovered.png" pushedimage="../public/button/btn_wnd_white_close_pushed.png"/>
<Class name="btn_wnd_white_max" width="auto" height="auto" forenormalimage="file='../public/button/btn_wnd_white_max.png' dest='4,4,16,16'" normalimage="" hotimage="../public/button/btn_wnd_white_max_hovered.png" pushedimage="../public/button/btn_wnd_white_max_pushed.png"/>
<Class name="btn_wnd_white_menu" width="auto" height="auto" forenormalimage="file='../public/button/btn_wnd_white_menu.png' dest='4,5,16,15'" normalimage="" hotimage="../public/button/btn_wnd_white_menu_hovered.png" pushedimage="../public/button/btn_wnd_white_menu_pushed.png"/>
<!--删除按钮通用样式-->
<Class name="btn_delete" normalimage="file='../public/button/funcicon.png' source='0,0,26,26'" hotimage="file='../public/button/funcicon.png' source='31,0,57,26'" pushedimage="file='../public/button/funcicon.png' source='62,0,88,26'" disabledimage="file='../public/button/funcicon.png' source='93,0,119,26'"/>
<Class name="btn_recycle" width="auto" height="auto" normalimage="file='../public/button/btn_recycle_normal.png'" hotimage="file='../public/button/btn_recycle_hovered.png'" pushedimage="file='../public/button/btn_recycle_pushed.png'" disabledimage="file='../public/button/btn_recycle_normal.png' fade='80'"/>
<Class name="btn_refresh" width="auto" height="auto" normalimage="file='../public/button/btn_refresh_normal.png'" hotimage="file='../public/button/btn_refresh_hovered.png'" pushedimage="file='../public/button/btn_refresh_pushed.png'" disabledimage="file='../public/button/btn_refresh_normal.png' fade='80'"/>
<Class name="btn_del_search" normalimage="../public/button/btn_del_search_normal_gray.png" hotimage="../public/button/btn_del_search_hover_gray.png" pushedimage="../public/button/btn_del_search_pushed_gray.png"/>
<!--列表通用样式-->
<Class name="list" bkcolor="bk_wnd_lightcolor" vscrollbar="true"/>
<Class name="listitem" hotcolor="bk_listitem_hovered" pushedcolor="bk_listitem_selected" selectednormalcolor="bk_listitem_selected" fadehot="false"/>
<Class name="list_topitem" normalcolor="bk_topitem_normal" hotcolor="bk_topitem_hovered" pushedcolor="bk_topitem_selected" selectednormalcolor="bk_topitem_selected" fadehot="false"/>
<!--进度条通用样式, 注意进度条的值使用`_value`属性-->
<Class name="progress_blue" valign="center" _value="0" bkimage="../public/progress/progress_blue_bg.png" height="3" width="stretch" hor="true" max="100" min="0" progressimage="../public/progress/progress_blue_fg.png"/>
<Class name="slider_green" width="stretch" height="14" margin="4,0,0,0" valign="center" thumbsize="14,14" min="0" max="255" progressbarpadding="0,6,0,6" bkimage="file='../public/slider/slider_hor_bk.png' dest='0,6,1000,8'" progresscolor="bk_progress_progress" thumbnormalimage="../public/slider/slider_thumb.png"/>
<!--菜单通用样式-->
<Class name="menu" width="auto" height="auto" bkcolor="bk_wnd_lightcolor"/>
<Class name="menu_element" padding="20,0,20,0" height="40" hotcolor="bk_menuitem_hovered" pushedcolor="bk_menuitem_selected" selectednormalcolor="bk_menuitem_selected"/>
<Class name="menu_text" normaltextcolor="darkcolor" font="system_14" valign="center"/>
<!--分割线通用样式-->
<Class name="splitline_hor_level1" bkcolor="splitline_level1" height="1"/>
<Class name="splitline_hor_level2" bkcolor="splitline_level2" height="1"/>
<Class name="splitline_ver_level1" bkcolor="splitline_level1" width="1"/>
<!--富文本控件通用样式-->
<Class name="simple" multiline="false" autohscroll="true" wantreturnmsg="true" wanttab="false" rich="false" normaltextcolor="darkcolor" disabledtextcolor="textdefaultdisablecolor"/>
<Class name="prompt" promptmode="true" promptcolor="light_gray"/>
<Class name="edit" hotimage="file='../public/edit/edit1.png' corner='10,10,10,10'" focusedimage="file='../public/edit/edit2.png' corner='10,10,10,10'"/>
<Class name="input" normalimage="file='../public/edit/edit0.png' corner='10,10,10,10'" hotimage="file='../public/edit/edit0.png' corner='10,10,10,10'" focusedimage="file='../public/edit/edit0.png' corner='10,10,10,10'" disabledimage="file='../public/edit/edit0.png' corner='10,10,10,10' fade='80'"/>
<!--头像蒙版-->
<Class name="icon_headimage_mask_40x40" width="40" height="40" bkimage="../public/headmask/icon_headimage_mask_40x40_normal.png"/>
</Global>
stdafx.h
#pragma once
#include <assert.h>
#include <comdef.h>
#include <comip.h>
#include <commctrl.h>
#include <commdlg.h>
#include <comutil.h>
#include <malloc.h>
#include <memory.h>
#include <objbase.h>
#include <shellapi.h>
#include <shlwapi.h>
#include <stdlib.h>
#include <string>
#include <tchar.h>
#include <windows.h>
#include <wininet.h>
#include <wtf/Platform.h>
#include <JavaScriptCore/JSExportMacros.h>
#include <WebCore/PlatformExportMacros.h>
Common.h
#pragma once
#include "stdafx.h"
#include "MainWindow.h"
#include <knownfolders.h>
Common2.h
#pragma once
#include <WebKit/WKRetainPtr.h>
#include <WebKit/WKString.h>
std::wstring createString(WKStringRef);
MainWindow.h
#pragma once
#include "BrowserWindow.h"
#include <functional>
#include <memory>
#include <string>
#include <wtf/RefPtr.h>
class MainWindow final : public RefCounted<MainWindow>, public BrowserWindowClient {
public:
using BrowserWindowFactory = std::function<Ref<BrowserWindow>(BrowserWindowClient&, HWND mainWnd)>;
static Ref<MainWindow> create();
bool init(BrowserWindowFactory, HWND);
HWND hwnd() const { return m_hMainWnd; }
HWND browserHwnd() const { return m_browserWindow->hwnd(); }
BrowserWindow* browserWindow() const { return m_browserWindow.get(); }
void resetZoom();
void loadURL(std::wstring);
// BrowserWindowClient
void progressChanged(double) final;
void progressFinished() final;
void activeURLChanged(std::wstring) final;
private:
HWND m_hMainWnd{ nullptr };
RefPtr<BrowserWindow> m_browserWindow;
};
WebKitBrowserWindow.h
#pragma once
#include "BrowserWindow.h"
#include "Common.h"
#include <WebKit/WKRetainPtr.h>
#include <WebKit/WebKit2_C.h>
#include <unordered_map>
#include <wtf/Ref.h>
class WebKitBrowserWindow : public BrowserWindow {
public:
static Ref<BrowserWindow> create(BrowserWindowClient&, HWND mainWnd);
void resetZoom() override;
private:
WebKitBrowserWindow(BrowserWindowClient&, WKPageConfigurationRef, HWND mainWnd);
HWND hwnd() override;
HRESULT loadURL(const BSTR& url) override;
void reload() override;
void setUserAgent(_bstr_t&) override;
static void didChangeTitle(const void*);
static void didChangeIsLoading(const void*);
static void didChangeEstimatedProgress(const void*);
static void didChangeActiveURL(const void*);
static void close(WKPageRef, const void*);
static void didNotHandleKeyEvent(WKPageRef, WKNativeEventPtr, const void*);
static WKRect getWindowFrame(WKPageRef, const void*);
static void runJavaScriptAlert(WKPageRef, WKStringRef, WKFrameRef, WKSecurityOriginRef, WKPageRunJavaScriptAlertResultListenerRef, const void*);
static void runJavaScriptConfirm(WKPageRef, WKStringRef, WKFrameRef, WKSecurityOriginRef, WKPageRunJavaScriptConfirmResultListenerRef, const void*);
static void runJavaScriptPrompt(WKPageRef, WKStringRef, WKStringRef, WKFrameRef, WKSecurityOriginRef, WKPageRunJavaScriptPromptResultListenerRef, const void*);
BrowserWindowClient& m_client;
WKRetainPtr<WKViewRef> m_view;
HWND m_hMainWnd{ nullptr };
};
BrowserWindow.h
#pragma once
#include <windows.h>
#include <wtf/RefCounted.h>
class BrowserWindowClient {
public:
virtual void progressChanged(double) = 0;
virtual void progressFinished() = 0;
virtual void activeURLChanged(std::wstring) = 0;
};
class BrowserWindow : public RefCounted<BrowserWindow> {
public:
enum class FeatureType { Experimental, InternalDebug };
virtual ~BrowserWindow() { };
virtual HWND hwnd() = 0;
virtual HRESULT loadURL(const BSTR& passedURL) = 0;
virtual void reload() = 0;
virtual bool usesLayeredWebView() const { return false; }
void setUserAgent();
virtual void setUserAgent(_bstr_t& customUAString) = 0;
virtual void resetZoom() = 0;
};
WebkitBrowser.h
#pragma once
#define WM_PROGRESS_CHANGE (WM_USER + 1)
class BrowserMiddleware {
public:
BrowserMiddleware(HWND parentHWND);
HWND WINAPI GetParentHWND() {
return m_parentHWND;
};
HWND WINAPI GetBrowserHWND();
void WINAPI loadURL(std::wstring url);
void resetZoom();
private:
HWND m_parentHWND{ nullptr };
void* m_mainWindow{ nullptr };
};
Common2.cpp
#include "stdafx.h"
#include "Common2.h"
#include <vector>
std::wstring createString(WKStringRef wkString)
{
size_t maxSize = WKStringGetLength(wkString);
std::vector<WKChar> wkCharBuffer(maxSize);
size_t actualLength = WKStringGetCharacters(wkString, wkCharBuffer.data(), maxSize);
return std::wstring(wkCharBuffer.data(), actualLength);
}
MainWindow.cpp
#include "stdafx.h"
#include "MainWindow.h"
#include "WebkitBrowser.h"
#include "Common.h"
#include "WebKitBrowserWindow.h"
#include <sstream>
static const wchar_t* kMiniBrowserRegistryKey = L"Software\\WebKit\\MiniBrowser";
Ref<MainWindow> MainWindow::create()
{
return adoptRef(*new MainWindow());
}
bool MainWindow::init(BrowserWindowFactory factory, HWND hwnd)
{
m_hMainWnd = hwnd;
if (!m_hMainWnd)
return false;
m_browserWindow = factory(*this, m_hMainWnd);
if (!m_browserWindow)
return false;
m_browserWindow->setUserAgent();
return true;
}
void MainWindow::resetZoom()
{
m_browserWindow->resetZoom();
}
void MainWindow::loadURL(std::wstring url)
{
if (::PathFileExists(url.c_str()) || ::PathIsUNC(url.c_str())) {
wchar_t fileURL[INTERNET_MAX_URL_LENGTH];
DWORD fileURLLength = _countof(fileURL);
if (SUCCEEDED(::UrlCreateFromPath(url.c_str(), fileURL, &fileURLLength, 0)))
url = fileURL;
}
if (url.find(L"://") == url.npos)
url = L"http://" + url;
if (FAILED(m_browserWindow->loadURL(_bstr_t(url.c_str()))))
return;
SetFocus(m_browserWindow->hwnd());
}
void MainWindow::progressChanged(double progress)
{
::SendMessage(m_hMainWnd, WM_PROGRESS_CHANGE, progress * 100, (LPARAM)browserHwnd());
}
void MainWindow::progressFinished()
{
}
void MainWindow::activeURLChanged(std::wstring url)
{
}
WebKitBrowserWindow.cpp
#include "stdafx.h"
#include "WebKitBrowserWindow.h"
#include "Common.h"
#include "Common2.h"
#include <WebCore/GDIUtilities.h>
#include <WebKit/WKAuthenticationChallenge.h>
#include <WebKit/WKAuthenticationDecisionListener.h>
#include <WebKit/WKCertificateInfoCurl.h>
#include <WebKit/WKContextConfigurationRef.h>
#include <WebKit/WKCredential.h>
#include <WebKit/WKDownloadClient.h>
#include <WebKit/WKDownloadRef.h>
#include <WebKit/WKFrameInfoRef.h>
#include <WebKit/WKHTTPCookieStoreRef.h>
#include <WebKit/WKInspector.h>
#include <WebKit/WKNavigationResponseRef.h>
#include <WebKit/WKPreferencesRefPrivate.h>
#include <WebKit/WKProtectionSpace.h>
#include <WebKit/WKProtectionSpaceCurl.h>
#include <WebKit/WKSecurityOriginRef.h>
#include <WebKit/WKURLResponse.h>
#include <WebKit/WKWebsiteDataStoreConfigurationRef.h>
#include <WebKit/WKWebsiteDataStoreRef.h>
#include <WebKit/WKWebsiteDataStoreRefCurl.h>
#include <filesystem>
#include <sstream>
#include <vector>
std::wstring createString(WKURLRef wkURL)
{
if (!wkURL)
return { };
WKRetainPtr<WKStringRef> url = adoptWK(WKURLCopyString(wkURL));
return createString(url.get());
}
std::string createUTF8String(const wchar_t* src, size_t srcLength)
{
int length = WideCharToMultiByte(CP_UTF8, 0, src, srcLength, 0, 0, nullptr, nullptr);
std::vector<char> buffer(length);
size_t actualLength = WideCharToMultiByte(CP_UTF8, 0, src, srcLength, buffer.data(), length, nullptr, nullptr);
return { buffer.data(), actualLength };
}
WKRetainPtr<WKStringRef> createWKString(_bstr_t str)
{
auto utf8 = createUTF8String(str, str.length());
return adoptWK(WKStringCreateWithUTF8CString(utf8.data()));
}
WKRetainPtr<WKStringRef> createWKString(const std::wstring& str)
{
auto utf8 = createUTF8String(str.c_str(), str.length());
return adoptWK(WKStringCreateWithUTF8CString(utf8.data()));
}
WKRetainPtr<WKStringRef> createWKString(const wchar_t* str)
{
return createWKString(std::wstring(str));
}
WKRetainPtr<WKURLRef> createWKURL(_bstr_t str)
{
auto utf8 = createUTF8String(str, str.length());
return adoptWK(WKURLCreateWithUTF8CString(utf8.data()));
}
WKRetainPtr<WKURLRef> createWKURL(const std::wstring& str)
{
auto utf8 = createUTF8String(str.c_str(), str.length());
return adoptWK(WKURLCreateWithUTF8CString(utf8.data()));
}
WKRetainPtr<WKStringRef> injectedBundlePath()
{
auto module = GetModuleHandle(nullptr);
std::wstring path;
for (;;) {
path.resize(path.size() + MAX_PATH);
auto copied = GetModuleFileName(module, path.data(), path.size());
if (copied < path.size()) {
path.resize(copied);
break;
}
}
path = std::filesystem::path(path).replace_filename("MiniBrowserInjectedBundle.dll");
return createWKString(path);
}
Ref<BrowserWindow> WebKitBrowserWindow::create(BrowserWindowClient& client, HWND mainWnd)
{
auto websiteDataStoreConf = adoptWK(WKWebsiteDataStoreConfigurationCreate());
auto websiteDataStore = adoptWK(WKWebsiteDataStoreCreateWithConfiguration(websiteDataStoreConf.get()));
auto contextConf = adoptWK(WKContextConfigurationCreate());
WKContextConfigurationSetInjectedBundlePath(contextConf.get(), injectedBundlePath().get());
auto context = adoptWK(WKContextCreateWithConfiguration(contextConf.get()));
auto preferences = adoptWK(WKPreferencesCreate());
WKPreferencesSetMediaCapabilitiesEnabled(preferences.get(), false);
WKPreferencesSetDeveloperExtrasEnabled(preferences.get(), true);
WKPreferencesSetAcceleratedCompositingEnabled(preferences.get(), true);
WKPreferencesSetAcceleratedDrawingEnabled(preferences.get(), true);
WKPreferencesSetAccelerated2DCanvasEnabled(preferences.get(), true);
auto pageConf = adoptWK(WKPageConfigurationCreate());
WKPageConfigurationSetWebsiteDataStore(pageConf.get(), websiteDataStore.get());
WKPageConfigurationSetContext(pageConf.get(), context.get());
WKPageConfigurationSetPreferences(pageConf.get(), preferences.get());
return adoptRef(*new WebKitBrowserWindow(client, pageConf.get(), mainWnd));
}
void WebKitBrowserWindow::resetZoom()
{
auto page = WKViewGetPage(m_view.get());
WKPageSetPageZoomFactor(page, WebCore::deviceScaleFactorForWindow(hwnd()));
}
WebKitBrowserWindow::WebKitBrowserWindow(BrowserWindowClient& client, WKPageConfigurationRef pageConf, HWND mainWnd)
: m_client(client)
, m_hMainWnd(mainWnd)
{
RECT rect = { };
m_view = adoptWK(WKViewCreate(rect, pageConf, mainWnd));
WKViewSetIsInWindow(m_view.get(), true);
auto page = WKViewGetPage(m_view.get());
WKPageUIClientV13 uiClient = { };
uiClient.base.version = 13;
uiClient.base.clientInfo = this;
uiClient.createNewPage = nullptr;
uiClient.close = close;
uiClient.didNotHandleKeyEvent = didNotHandleKeyEvent;
uiClient.getWindowFrame = getWindowFrame;
uiClient.runJavaScriptAlert = runJavaScriptAlert;
uiClient.runJavaScriptConfirm = runJavaScriptConfirm;
uiClient.runJavaScriptPrompt = runJavaScriptPrompt;
WKPageSetPageUIClient(page, &uiClient.base);
WKPageStateClientV0 stateClient = { };
stateClient.base.version = 0;
stateClient.base.clientInfo = this;
stateClient.didChangeTitle = didChangeTitle;
stateClient.didChangeIsLoading = didChangeIsLoading;
stateClient.didChangeEstimatedProgress = didChangeEstimatedProgress;
stateClient.didChangeActiveURL = didChangeActiveURL;
WKPageSetPageStateClient(page, &stateClient.base);
resetZoom();
}
HWND WebKitBrowserWindow::hwnd()
{
return WKViewGetWindow(m_view.get());
}
HRESULT WebKitBrowserWindow::loadURL(const BSTR& url)
{
auto page = WKViewGetPage(m_view.get());
WKPageLoadURL(page, createWKURL(_bstr_t(url)).get());
return true;
}
void WebKitBrowserWindow::reload()
{
auto page = WKViewGetPage(m_view.get());
WKPageReload(page);
}
void WebKitBrowserWindow::setUserAgent(_bstr_t& customUAString)
{
auto page = WKViewGetPage(m_view.get());
auto ua = createWKString(customUAString);
WKPageSetCustomUserAgent(page, ua.get());
}
static WebKitBrowserWindow& toWebKitBrowserWindow(const void* clientInfo)
{
return *const_cast<WebKitBrowserWindow*>(static_cast<const WebKitBrowserWindow*>(clientInfo));
}
void WebKitBrowserWindow::didChangeTitle(const void* clientInfo)
{
auto& thisWindow = toWebKitBrowserWindow(clientInfo);
auto page = WKViewGetPage(thisWindow.m_view.get());
WKRetainPtr<WKStringRef> title = adoptWK(WKPageCopyTitle(page));
std::wstring titleString = createString(title.get()) + L" [WebKit]";
SetWindowText(thisWindow.m_hMainWnd, titleString.c_str());
}
void WebKitBrowserWindow::didChangeIsLoading(const void* clientInfo)
{
auto& thisWindow = toWebKitBrowserWindow(clientInfo);
thisWindow.m_client.progressFinished();
}
void WebKitBrowserWindow::didChangeEstimatedProgress(const void* clientInfo)
{
auto& thisWindow = toWebKitBrowserWindow(clientInfo);
auto page = WKViewGetPage(thisWindow.m_view.get());
thisWindow.m_client.progressChanged(WKPageGetEstimatedProgress(page));
}
void WebKitBrowserWindow::didChangeActiveURL(const void* clientInfo)
{
auto& thisWindow = toWebKitBrowserWindow(clientInfo);
auto page = WKViewGetPage(thisWindow.m_view.get());
WKRetainPtr<WKURLRef> url = adoptWK(WKPageCopyActiveURL(page));
thisWindow.m_client.activeURLChanged(createString(url.get()));
}
void WebKitBrowserWindow::close(WKPageRef, const void* clientInfo)
{
auto& thisWindow = toWebKitBrowserWindow(clientInfo);
PostMessage(thisWindow.hwnd(), WM_CLOSE, 0, 0);
}
void WebKitBrowserWindow::didNotHandleKeyEvent(WKPageRef, WKNativeEventPtr event, const void* clientInfo)
{
auto& thisWindow = toWebKitBrowserWindow(clientInfo);
PostMessage(thisWindow.m_hMainWnd, event->message, event->wParam, event->lParam);
}
WKRect WebKitBrowserWindow::getWindowFrame(WKPageRef, const void* clientInfo)
{
auto& thisWindow = toWebKitBrowserWindow(clientInfo);
RECT rect;
GetWindowRect(thisWindow.hwnd(), &rect);
return WKRectMake(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
}
void WebKitBrowserWindow::runJavaScriptAlert(WKPageRef, WKStringRef alertText, WKFrameRef, WKSecurityOriginRef securityOrigin, WKPageRunJavaScriptAlertResultListenerRef listener, const void* clientInfo)
{
auto& thisWindow = toWebKitBrowserWindow(clientInfo);
std::wstring title = L"Alert: ";
title += createString(adoptWK(WKSecurityOriginCopyToString(securityOrigin)).get());
auto text = createString(alertText);
MessageBox(thisWindow.m_hMainWnd, text.c_str(), title.c_str(), MB_OK);
WKPageRunJavaScriptAlertResultListenerCall(listener);
}
void WebKitBrowserWindow::runJavaScriptConfirm(WKPageRef, WKStringRef message, WKFrameRef, WKSecurityOriginRef securityOrigin, WKPageRunJavaScriptConfirmResultListenerRef listener, const void* clientInfo)
{
auto& thisWindow = toWebKitBrowserWindow(clientInfo);
std::wstring title = L"Confirm: ";
title += createString(adoptWK(WKSecurityOriginCopyToString(securityOrigin)).get());
auto text = createString(message);
bool result = MessageBox(thisWindow.m_hMainWnd, text.c_str(), title.c_str(), MB_OKCANCEL) == IDOK;
WKPageRunJavaScriptConfirmResultListenerCall(listener, result);
}
void WebKitBrowserWindow::runJavaScriptPrompt(WKPageRef, WKStringRef message, WKStringRef defaultValue, WKFrameRef, WKSecurityOriginRef securityOrigin, WKPageRunJavaScriptPromptResultListenerRef listener, const void* clientInfo)
{
auto& thisWindow = toWebKitBrowserWindow(clientInfo);
std::wstring title = L"Prompt: ";
title += createString(adoptWK(WKSecurityOriginCopyToString(securityOrigin)).get());
auto text = createString(message);
text += L"\nDefault Value: " + createString(defaultValue);
MessageBox(thisWindow.m_hMainWnd, text.c_str(), title.c_str(), MB_OK);
WKPageRunJavaScriptPromptResultListenerCall(listener, defaultValue);
}
BrowserWindow.cpp
#include "stdafx.h"
#include "BrowserWindow.h"
void BrowserWindow::setUserAgent()
{
_bstr_t customUserAgent;
customUserAgent = L"Mozilla/5.0 (iPhone; CPU iPhone OS 14_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1";
setUserAgent(customUserAgent);
}
WebkitBrowser.cpp
#include "stdafx.h"
#include "Common.h"
#include "WebKitBrowserWindow.h"
#include <wtf/win/SoftLinking.h>
#include "WebkitBrowser.h"
BrowserMiddleware::BrowserMiddleware(HWND parentHWND):m_parentHWND(parentHWND)
{
::SetProcessDPIAware();
auto factory = WebKitBrowserWindow::create;
m_mainWindow = &MainWindow::create().leakRef();
static_cast<MainWindow*>(m_mainWindow)->init(factory, m_parentHWND);
}
HWND WINAPI BrowserMiddleware::GetBrowserHWND()
{
if (m_mainWindow) {
return static_cast<MainWindow*>(m_mainWindow)->browserHwnd();
}
else {
return nullptr;
}
}
void WINAPI BrowserMiddleware::loadURL(std::wstring url)
{
if(m_mainWindow){
static_cast<MainWindow*>(m_mainWindow)->loadURL(url);
}
}
void BrowserMiddleware::resetZoom()
{
if (m_mainWindow) {
static_cast<MainWindow*>(m_mainWindow)->resetZoom();
}
}
#########solunar项目##############################################
stdafx.h
#pragma once
// C runtime header
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>
// base header
#include "base/base.h"
solunar_form.h
#pragma once
class SolunarForm : public ui::WindowImplBase
{
public:
SolunarForm();
~SolunarForm();
virtual std::wstring GetSkinFolder() override;
virtual std::wstring GetSkinFile() override;
virtual std::wstring GetWindowClassName() const override;
virtual LRESULT OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
virtual ui::Control* CreateControl(const std::wstring& pstrClass);
virtual void InitWindow() override;
virtual LRESULT MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) override;
static const std::wstring kClassName;
private:
bool OnSelected(ui::EventArgs* arg);
};
webkit_browser.h
#pragma once
#include "/VSProject/solunar/MiniBrowser/WebkitBrowser.h"
class WebkitBrowser : public ui::Control
{
public:
WebkitBrowser(HWND hwnd);
~WebkitBrowser();
virtual void SetInternVisible(bool bVisible = true);
virtual void SetPos(ui::UiRect rc) override;
void SetUrl(std::wstring url, ui::Progress *progress);
void resetZoom();
bool isPage(HWND hwnd, int value);
virtual void Paint(ui::IRenderContext* pRender, const ui::UiRect& rcPaint);
protected:
HWND m_hWnd{ nullptr };
private:
int m_patch{ 0 };
BrowserMiddleware* m_browsermiddleware{ nullptr };
std::wstring m_url;
ui::Progress* m_progress{nullptr};
};
main.h
#pragma once
class MainThread : public nbase::FrameworkThread
{
public:
MainThread() : nbase::FrameworkThread("MainThread") {}
virtual ~MainThread() {}
private:
/**
* 虚函数,初始化主线程
* @return void 无返回值
*/
virtual void Init() override;
/**
* 虚函数,主线程退出时,做一些清理工作
* @return void 无返回值
*/
virtual void Cleanup() override;
};
solunar_form.cpp
#include "duilib/UIlib.h"
#include "solunar_form.h"
#include "webkit_browser.h"
const std::wstring SolunarForm::kClassName = L"Solunar";
SolunarForm::SolunarForm()
{
}
SolunarForm::~SolunarForm()
{
}
std::wstring SolunarForm::GetSkinFolder()
{
return L"solunar";
}
std::wstring SolunarForm::GetSkinFile()
{
return L"solunar.xml";
}
std::wstring SolunarForm::GetWindowClassName() const
{
return kClassName;
}
LRESULT SolunarForm::OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
PostQuitMessage(0L);
return __super::OnClose(uMsg, wParam, lParam, bHandled);
}
ui::Control* SolunarForm::CreateControl(const std::wstring& pstrClass) {
if (pstrClass == L"WebkitBrowser")
{
return new WebkitBrowser(GetHWND());
}
return NULL;
}
void SolunarForm::InitWindow()
{
auto wb_baidu = static_cast<WebkitBrowser*>(FindControl(L"wb_baidu"));
auto wb_douyin = static_cast<WebkitBrowser*>(FindControl(L"wb_douyin"));
auto progress_baidu = static_cast<ui::Progress*>(FindControl(L"progress_baidu"));
auto progress_douyin = static_cast<ui::Progress*>(FindControl(L"progress_douyin"));
wb_baidu->SetUrl(L"http://baidu.com/", progress_baidu);
wb_douyin->SetUrl(L"http://douyin.com/", progress_douyin);
auto option_baidu = static_cast<ui::Option*>(FindControl(L"option_baidu"));
auto option_douyin = static_cast<ui::Option*>(FindControl(L"option_douyin"));
option_baidu->AttachSelect(nbase::Bind(&SolunarForm::OnSelected, this, std::placeholders::_1));
option_douyin->AttachSelect(nbase::Bind(&SolunarForm::OnSelected, this, std::placeholders::_1));
AddMessageFilter(this);
}
#define IDT_TIMER 1
LRESULT SolunarForm::MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
switch (uMsg)
{
case WM_PROGRESS_CHANGE: {
auto wb_baidu = static_cast<WebkitBrowser*>(FindControl(L"wb_baidu"));
auto wb_douyin = static_cast<WebkitBrowser*>(FindControl(L"wb_douyin"));
if (wb_baidu->isPage((HWND)lParam, wParam));
else if (wb_douyin->isPage((HWND)lParam, wParam));
}
break;
case WM_MOVE: {
static bool flag = false;
RECT rect;
GetWindowRect(GetHWND(), &rect);
int screenWidth = GetSystemMetrics(SM_CXSCREEN);
int screenHeight = GetSystemMetrics(SM_CYSCREEN);
if (rect.left < 0 || rect.top < 0 || rect.right > screenWidth || rect.bottom > screenHeight) {
if (flag) {
KillTimer(GetHWND(), IDT_TIMER);
flag = false;
}
flag = true;
SetTimer(GetHWND(), IDT_TIMER, 200, NULL);
}
}
break;
case WM_TIMER:
if (wParam == IDT_TIMER) {
KillTimer(GetHWND(), IDT_TIMER);
auto wb_baidu = static_cast<WebkitBrowser*>(FindControl(L"wb_baidu"));
auto wb_douyin = static_cast<WebkitBrowser*>(FindControl(L"wb_douyin"));
wb_baidu->SetPos(wb_baidu->GetPos());
wb_douyin->SetPos(wb_douyin->GetPos());
}
break;
default:
break;
}
return false;
}
bool SolunarForm::OnSelected(ui::EventArgs* arg)
{
auto option = static_cast<ui::Option*>(arg->pSender);
std::wstring text = option->GetText();
auto tab_browser = static_cast<ui::TabBox*>(FindControl(L"tab_browser"));
if (text == L"百度") {
tab_browser->SelectItem(0);
}
else if (text == L"抖音") {
tab_browser->SelectItem(1);
}
return true;
}
webkit_browser.cpp
#include "duilib/UIlib.h"
#include "/VSProject/solunar/MiniBrowser/WebkitBrowser.h"
#include "webkit_browser.h"
#pragma comment(lib, "D:/VSProject/duilib-netease/libs/x64/base_d.lib")
#pragma comment(lib, "D:/VSProject/duilib-netease/libs/x64/duilib_d.lib")
#pragma comment(lib, "D:/VSProject/solunar/x64/Debug/webkitbrowser.lib")
WebkitBrowser::WebkitBrowser(HWND hwnd)
{
m_browsermiddleware = new BrowserMiddleware(hwnd);
if (m_browsermiddleware)
m_hWnd = m_browsermiddleware->GetBrowserHWND();
}
WebkitBrowser::~WebkitBrowser()
{
if (m_browsermiddleware)
delete m_browsermiddleware;
}
void WebkitBrowser::SetInternVisible(bool bVisible)
{
__super::SetInternVisible(bVisible);
if (m_hWnd) {
::ShowWindow(m_hWnd, bVisible);
}
}
void WebkitBrowser::SetPos(ui::UiRect rc)
{
__super::SetPos(rc);
if (m_hWnd) {
::MoveWindow(m_hWnd, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top + m_patch, true);
m_patch = (++m_patch) % 2;
}
}
void WebkitBrowser::SetUrl(std::wstring url, ui::Progress *progress)
{
m_url = url;
m_progress = progress;
if (m_browsermiddleware)
m_browsermiddleware->loadURL(url);
}
void WebkitBrowser::resetZoom()
{
if (m_browsermiddleware)
m_browsermiddleware->resetZoom();
}
bool WebkitBrowser::isPage(HWND hwnd, int value)
{
if (m_hWnd == hwnd) {
if (m_progress) {
wchar_t progress[200];
swprintf_s(progress, L"%s %lld\n", m_url.c_str(), value);
OutputDebugString(progress);
m_progress->SetValue(value);
}
return true;
}
return false;
}
void WebkitBrowser::Paint(ui::IRenderContext* pRender, const ui::UiRect& rcPaint)
{
if( !::IntersectRect(&m_rcPaint, &rcPaint, &m_rcItem) ) return;
if (m_hWnd) {
HDC hDC = pRender->GetDC();
HDC hdcSrc = ::GetDC(m_hWnd);
::StretchBlt(hDC, m_rcItem.left, m_rcItem.top, m_rcItem.right - m_rcItem.left, m_rcItem.bottom - m_rcItem.top,
hdcSrc, 0, 0, m_rcItem.right - m_rcItem.left, m_rcItem.bottom - m_rcItem.top, SRCCOPY);
::ReleaseDC(m_hWnd, hdcSrc);
}
return;
}
main.cpp
#include "stdafx.h"
#include "duilib/UIlib.h"
#include "main.h"
#include "Solunar_form.h"
enum ThreadId
{
kThreadUI
};
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// 创建主线程
MainThread thread;
// 执行主线程循环
thread.RunOnCurrentThreadWithLoop(nbase::MessageLoop::kUIMessageLoop);
return 0;
}
void MainThread::Init()
{
INITCOMMONCONTROLSEX InitCtrlEx;
InitCtrlEx.dwSize = sizeof(INITCOMMONCONTROLSEX);
InitCtrlEx.dwICC = 0x00004000; // ICC_STANDARD_CLASSES;
InitCommonControlsEx(&InitCtrlEx);
// Init COM
OleInitialize(nullptr);
nbase::ThreadManager::RegisterThread(kThreadUI);
// 获取资源路径,初始化全局参数
std::wstring theme_dir = nbase::win32::GetCurrentModuleDirectory();
#ifdef _DEBUG
// Debug 模式下使用本地文件夹作为资源
// 默认皮肤使用 resources\\themes\\default
// 默认语言使用 resources\\lang\\zh_CN
// 如需修改请指定 Startup 最后两个参数
ui::GlobalManager::Startup(theme_dir + L"resources\\", ui::CreateControlCallback(), true);
#else
// Release 模式下使用资源中的压缩包作为资源
// 资源被导入到资源列表分类为 THEME,资源名称为 IDR_THEME
// 如果资源使用的是本地的 zip 文件而非资源中的 zip 压缩包
// 可以使用 OpenResZip 另一个重载函数打开本地的资源压缩包
ui::GlobalManager::OpenResZip(MAKEINTRESOURCE(IDR_THEME), L"THEME", "");
// ui::GlobalManager::OpenResZip(L"resources.zip", "");
ui::GlobalManager::Startup(L"resources\\", ui::CreateControlCallback(), false);
#endif
SolunarForm* window = new SolunarForm();
window->Create(NULL, SolunarForm::kClassName.c_str(), WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX, 0, false);
window->CenterWindow();
window->ShowWindow();
}
void MainThread::Cleanup()
{
ui::GlobalManager::Shutdown();
SetThreadWasQuitProperly(true);
nbase::ThreadManager::UnregisterThread();
// Shut down COM.
OleUninitialize();
}