260 lines
7.9 KiB
C++
260 lines
7.9 KiB
C++
#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());
|
||
}
|
||
|
||
}; |