Files
EzUI/sources/Application.cpp

260 lines
7.9 KiB
C++
Raw Permalink Normal View History

2026-01-24 22:42:46 +08:00
#include "Application.h"
#include "LayeredWindow.h"
#include "UIManager.h"
#include <CommCtrl.h>
#undef FindResource
namespace ezui {
bool g_comInitialized = false;//标记是否由我初始化
std::list<HWND> g_hWnds;//存储所有使用本框架产生的窗口句柄
// 内部使用:枚举名称时的上下文
struct ResourceContext {
UIString rcIDName;
HRSRC hResource = NULL;
UIString rcType;
};
// 回调:枚举资源名称
BOOL CALLBACK EnumNamesProc(HMODULE hModule, LPCWSTR lpszType, LPWSTR lpszName, LONG_PTR lParam) {
ResourceContext* ctx = (ResourceContext*)(lParam);
UIString resName = UIString(lpszName).toLower();
if (!IS_INTRESOURCE(lpszName) && ctx->rcIDName.toLower() == resName) {
ctx->hResource = FindResourceW(hModule, lpszName, lpszType);
ctx->rcType = (wchar_t*)lpszType;
return FALSE; // 找到就停止
}
return TRUE; // 继续
}
//通过资源名称查找windows嵌套资源
HRSRC FindResource(const UIString& rcIDName)
{
HMODULE hModule = ezui::__EzUI__HINSTANCE;
ResourceContext ctx;
ctx.rcIDName = rcIDName;
EnumResourceTypesW(hModule, [](HMODULE hModule, LPWSTR lpszType, LONG_PTR lParam)->BOOL {
return EnumResourceNamesW(hModule, lpszType, EnumNamesProc, lParam);
}, (LONG_PTR)&ctx);
return ctx.hResource;
}
}
namespace ezui {
LRESULT CALLBACK __EzUI__WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
if (message == WM_CREATE) {
g_hWnds.push_back(hWnd);
}
else if (message == WM_DESTROY) {
auto itor = std::find(g_hWnds.begin(), g_hWnds.end(), hWnd);
if (itor != g_hWnds.end()) {
g_hWnds.erase(itor);
}
}
WindowData* wndData = (WindowData*)UI_GET_USERDATA(hWnd);
//执行消息过程
if (wndData && wndData->WndProc) {
return wndData->WndProc(hWnd, message, wParam, lParam);
}
return ::DefWindowProc(hWnd, message, wParam, lParam);
}
void InitInvoker() {
if (!ezui::__EzUI_MessageWnd) {
::WNDCLASSEXW wcex = {};
wcex.cbSize = sizeof(wcex);
wcex.lpfnWndProc = [](HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -> LRESULT {
if (msg == WM_GUI_SYSTEM) {
if (wParam == WM_GUI_BEGININVOKE || wParam == WM_GUI_INVOKE) {
using Func = std::function<void()>;
Func* callback = (Func*)lParam;
(*callback)();
if (wParam == WM_GUI_BEGININVOKE) {
delete callback;
}
}
return 0;
}
return ::DefWindowProc(hwnd, msg, wParam, lParam);
};
wcex.hInstance = ezui::__EzUI__HINSTANCE;
wcex.lpszClassName = EZUI_INVOKER_WINDOW_CLASS;
RegisterClassExW(&wcex);
ezui::__EzUI_MessageWnd = CreateWindowEx(
WS_EX_LAYERED | WS_EX_NOACTIVATE | WS_EX_TOOLWINDOW,
EZUI_INVOKER_WINDOW_CLASS, // 上面注册的类名
L"", // 窗口名(无用)
0, // 样式设为 0无 WS_VISIBLE
0, 0, 0, 0, // 尺寸全为 0
NULL, NULL, ezui::__EzUI__HINSTANCE, NULL
);
}
}
//销毁多线程通讯窗口
void DestroyInvoker() {
//销毁用于通讯的不可见窗口
if (ezui::__EzUI_MessageWnd) {
::DestroyWindow(ezui::__EzUI_MessageWnd);
ezui::__EzUI_MessageWnd = NULL;
BOOL ret = UnregisterClassW(EZUI_INVOKER_WINDOW_CLASS, ezui::__EzUI__HINSTANCE);
}
}
void Application::EnableHighDpi() {
ezui::GetMonitor((std::list<MonitorInfo>*) & ezui::__EzUI__MonitorInfos);//获取一次显示器信息
//DPI感知相关
//不跟随系统放大无法接收WM_DISPLAYCHANGED消息
//bool b = SetProcessDPIAware();
//SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);
//会进入WM_DPICHANGED消息可进行自行控制缩放
HMODULE hModNtdll = NULL;
if (hModNtdll = ::LoadLibraryW(L"User32.dll")) {
typedef void (WINAPI* Func_SetProcessDpiAwarenessContext)(void*);
Func_SetProcessDpiAwarenessContext setProcessDpiAwarenessContext;
setProcessDpiAwarenessContext = (Func_SetProcessDpiAwarenessContext)::GetProcAddress(hModNtdll, "SetProcessDpiAwarenessContext");
if (setProcessDpiAwarenessContext)
{
//SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);//高版本sdk直接用
setProcessDpiAwarenessContext((void*)-4);//函数指针方式是为了兼容win7
}
else {
::SetProcessDPIAware();
}
::FreeLibrary(hModNtdll);
}
}
bool Application::SetResource(const UIString& localOrResName) {
//只允许有一个资源文件
if (ezui::__EzUI__Resource) {
delete ezui::__EzUI__Resource;
ezui::__EzUI__Resource = NULL;
}
//先从vs中的资源里面查找
bool found = false;
HRSRC hRsrc = ezui::FindResource(localOrResName);
if (hRsrc) {
ezui::__EzUI__Resource = new Resource(hRsrc);
found = true;
}
else {
//本地文件中获取
std::wstring wstr = localOrResName.unicode();
DWORD dwAttr = GetFileAttributesW(wstr.c_str());
if (dwAttr && (dwAttr != -1) && (dwAttr & FILE_ATTRIBUTE_ARCHIVE)) {
ezui::__EzUI__Resource = new Resource(localOrResName);
found = true;
}
}
#ifdef _DEBUG
if (!found) {
::MessageBoxW(NULL, localOrResName.unicode().c_str(), L"Failed to open Resource", MB_OK | MB_ICONINFORMATION);
}
#endif
return found;
}
Application::Application(HINSTANCE hInstance) {
//存入全局实例
ezui::__EzUI__HINSTANCE = hInstance == NULL ? ::GetModuleHandleW(NULL) : hInstance;
ezui::__EzUI__ThreadId = ::GetCurrentThreadId();
//设计窗口
::WNDCLASSEXW wcex = {};
wcex.cbSize = sizeof(wcex);
wcex.style = CS_HREDRAW | CS_VREDRAW;//宽高改变窗口触发重绘
wcex.lpfnWndProc = __EzUI__WndProc;//窗口过程
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = ezui::__EzUI__HINSTANCE;//
wcex.hIcon = NULL;//(大图标)用于窗口标题栏、Alt+Tab 切换界面、任务栏预览等显示大图标的地方
wcex.hIconSm = NULL;//(小图标)用于任务栏按钮、系统托盘(部分情况下)以及 Alt+Tab 小图标显示等
wcex.hCursor = LoadCursorW(NULL, IDC_ARROW);//光标
wcex.hbrBackground = NULL; // 窗口背景
wcex.lpszMenuName = NULL;
wcex.lpszClassName = EZUI_WINDOW_CLASS;//类名
if (!RegisterClassExW(&wcex)) //注册窗口
{
::MessageBoxW(NULL, L"This program requires Windows NT !",
wcex.lpszClassName, MB_ICONERROR);
return;
}
//注册一个窗口类并创建隐形窗口用于UI直接的多线程通讯
InitInvoker();
//为程序设置工作目录
std::wstring startPath = Application::StartPath().unicode();
::SetCurrentDirectoryW(startPath.c_str());
if (!g_comInitialized) {
auto ret = ::CoInitialize(NULL);//初始化com
if (ret == S_OK) {
g_comInitialized = true;//由我初始化的
}
}
RenderInitialize();//初始化图形绘制库 D2D/GDI/GDI+
InitControls();//注册基础控件
}
//销毁所有窗口
void DestroyAllWindows() {
while (ezui::g_hWnds.size() > 0)
{
auto itor = ezui::g_hWnds.begin();
if (itor != ezui::g_hWnds.end()) {
HWND hwnd = *itor;
g_hWnds.erase(itor);
::DestroyWindow(hwnd);
}
}
}
Application::~Application() {
//销毁通讯窗口
DestroyInvoker();
//销毁所有窗口
DestroyAllWindows();
//取消窗口注册的类
BOOL ret = UnregisterClassW(EZUI_WINDOW_CLASS, ezui::__EzUI__HINSTANCE);
RenderUnInitialize();
if (g_comInitialized) {
::CoUninitialize();
g_comInitialized = false;
}
if (ezui::__EzUI__Resource) {
delete ezui::__EzUI__Resource;
ezui::__EzUI__Resource = NULL;
}
}
int Application::Exec()
{
MSG msg;
while (::GetMessage(&msg, NULL, 0, 0)) {
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
return msg.wParam;
}
void Application::Exit(int exitCode) {
//销毁用于通讯的不可见窗口
DestroyInvoker();
//销毁所有窗口
DestroyAllWindows();
//退出消息循环
::PostQuitMessage(exitCode);
}
UIString Application::StartPath()
{
std::vector<wchar_t> wPath(32768);
DWORD count = ::GetModuleFileNameW(__EzUI__HINSTANCE, wPath.data(), (DWORD)wPath.size());
for (int i = count - 1; i > -1; i--)
{
if (wPath[i] == L'\\') {
wPath[i] = 0;
break;
}
}
return UIString(wPath.data());
}
};