commit 4f660b13982b4eaf3c96b85988161d3fc8feb925 Author: mykola2312 <49044616+mykola2312@users.noreply.github.com> Date: Sat Feb 27 17:34:28 2021 +0200 27.02.2021: win32ctrl initial commit. diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..acd792a --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,23 @@ +cmake_minimum_required(VERSION 3.18) +project(win32ctrl) + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +set(SOURCES + win32ctrl.cpp + win32util.cpp +) + +set(HEADERS + win32ctrl.h + win32util.h +) + +add_library(win32ctrl SHARED ${SOURCES} ${HEADERS}) +target_include_directories(win32ctrl PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) +target_link_libraries(win32ctrl PRIVATE + comctl32 +) diff --git a/win32ctrl.cpp b/win32ctrl.cpp new file mode 100644 index 0000000..7bb7a21 --- /dev/null +++ b/win32ctrl.cpp @@ -0,0 +1,511 @@ +#include "win32ctrl.h" +#include "win32util.h" +#include +#include +#include +#include +#include +#include + +/* AppException */ + +AppException::AppException(AppMonitor* app, + const std::string& text) +{ + m_pApp = app; + m_Text = text; + m_dwError = GetLastError(); +} + +static char s_szExcBuf[256] = {0}; + +const char* AppException::what() const noexcept +{ + StringCchPrintfA(s_szExcBuf, 256, "AppMonitor#%05d: %s", + GetApp()->GetAppProcessId(), m_Text.c_str()); + return s_szExcBuf; +} + +/* AppMonitor */ + +void AppMonitor::Init() +{ + InitCommonControls(); +} + +AppMonitor::AppMonitor() + : m_ExePath(L"") +{ + m_hAppProcess = INVALID_HANDLE_VALUE; + m_dwPid = 0; + m_bWow64 = FALSE; +} + +AppMonitor::AppMonitor(const std::wstring& app) + : m_ExePath(app) +{ + m_hAppProcess = INVALID_HANDLE_VALUE; + m_dwPid = 0; + m_bWow64 = FALSE; +} + +AppMonitor::~AppMonitor() +{ + if (m_hAppProcess != INVALID_HANDLE_VALUE) + CloseHandle(m_hAppProcess); +} + +struct _enumapp_s { + AppMonitor* m_pMonitor; + AppMonitor::EnumFunc m_Func; +}; + +BOOL CALLBACK _EnumAppWindows(HWND hWnd, LPARAM lParam) +{ + AppMonitor* app = (AppMonitor*)lParam; + + DWORD dwPid = 0; + GetWindowThreadProcessId(app->m_Tmp.m_hWnd + ? app->m_Tmp.m_hWnd : hWnd, &dwPid); + if (dwPid && dwPid != app->GetAppProcessId()) + return TRUE; + + return app->m_Tmp.m_Func(app, hWnd); +} + +void AppMonitor::EnumAppWindows(EnumFunc func) +{ + m_Tmp.m_hWnd = NULL; + m_Tmp.m_Func = func; + + EnumWindows(_EnumAppWindows, (LPARAM)this); +} + +void AppMonitor::EnumAppControls(HWND hWnd, EnumFunc func) +{ + m_Tmp.m_hWnd = hWnd; + m_Tmp.m_Func = func; + + EnumChildWindows(hWnd, _EnumAppWindows, (LPARAM)this); +} + +HWND AppMonitor::FindAppWindow(const std::string& wndClass) +{ + m_Tmp.m_hWnd = NULL; + m_Tmp.m_Class = wndClass; + + EnumAppWindows( + [](AppMonitor* app, HWND hWnd) { + if (app->GetWindowClass(hWnd) == app->m_Tmp.m_Class) + { + app->m_Tmp.m_hWnd = hWnd; + return false; + } + + return true; + } + ); + + return m_Tmp.m_hWnd; +} + +bool AppMonitor::StartApp(const std::wstring& cmdLine) +{ + if (m_ExePath.empty()) + throw AppException(this, "m_ExePath.empty()"); + + auto pszCmdLine = std::make_unique(MAX_CMDLINE); + StringCchPrintfW(pszCmdLine.get(), MAX_CMDLINE, L"\"%s\" %s", + m_ExePath.c_str(), cmdLine.c_str()); + + PROCESS_INFORMATION pi; + STARTUPINFOW si; + + ZeroMemory(&pi, sizeof(pi)); + ZeroMemory(&si, sizeof(si)); + + si.cb = sizeof(si); + BOOL bCreated = CreateProcessW(m_ExePath.c_str(), pszCmdLine.get(), + NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); + if (!bCreated) + return false; + + m_hAppProcess = pi.hProcess; + m_dwPid = pi.dwProcessId; + + if (!IsWow64Process(m_hAppProcess, &m_bWow64)) + m_bWow64 = FALSE; + + CloseHandle(pi.hThread); + return true; +} + +void AppMonitor::CloseApp() +{ + EnumAppWindows( + [](AppMonitor* app, HWND hWnd) { + SendMessage(hWnd, WM_CLOSE, 0, 0); + return true; + } + ); + + CloseHandle(m_hAppProcess); + m_hAppProcess = INVALID_HANDLE_VALUE; +} + +void AppMonitor::Terminate() +{ + TerminateProcess(m_hAppProcess, 0); + CloseHandle(m_hAppProcess); + m_hAppProcess = INVALID_HANDLE_VALUE; +} + +bool AppMonitor::IsAppRunning() const +{ + DWORD dwWait = WaitForSingleObject(m_hAppProcess, 0); + if (dwWait != WAIT_OBJECT_0) + return false; + + return true; +} + +bool AppMonitor::IsWow64() const +{ + return !!m_bWow64; +} + +bool AppMonitor::WaitAppIdle(DWORD dwInterval) +{ + return WaitForInputIdle(GetAppProcess(), dwInterval) != 0; +} + +void AppMonitor::MonitorSetup() +{ + EnumAppWindows( + [](AppMonitor* app, HWND hWnd) { + app->OnAppWindow(hWnd); + return true; + } + ); +} + +void AppMonitor::OnAppWindow(HWND hWnd) +{ +} + +void AppMonitor::SetExePath(const std::wstring& exePath) +{ + m_ExePath = exePath; +} + +std::string AppMonitor::GetWindowClass(HWND hWnd) +{ + char szClass[64] = {0}; + GetClassNameA(hWnd, szClass, 64); + return std::string(szClass); +} + +HWND AppMonitor::GetChild(HWND hWnd, const std::string& wndClass, + const std::wstring& wndText) +{ + return FindWindowExW(hWnd, NULL, TextToWchar(wndClass).c_str(), + wndText.empty() ? NULL : wndText.c_str()); +} + +AppMem AppMonitor::MemAlloc(unsigned uLen) +{ + void* pThisMem; + void* pAppMem; + + pThisMem = (char*)malloc(uLen); + if (!pThisMem) + throw AppException(this, "!malloc"); + memset(pThisMem, '\0', uLen); + pAppMem = VirtualAllocEx(m_hAppProcess, + NULL, uLen, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + if (!pAppMem) + { + free(pThisMem); + throw AppException(this, "!VirtualAllocEx"); + } + else if (IsWow64() && (uintptr_t)pAppMem > 0xFFFFFFFF) + { + free(pThisMem); + throw AppException(this, "WOW64 VirtualAllocEx >4GB addr"); + } + + return AppMem(pThisMem, pAppMem, uLen); +} + +void AppMonitor::MemFree(AppMem& mem) +{ + free(mem.This()); + VirtualFreeEx(m_hAppProcess, mem.App(), 0, MEM_RELEASE); + mem = AppMem(); +} + +void AppMonitor::MemWriteApp(const AppMem& mem) +{ + SIZE_T szTmp = mem.Size(); + if(!WriteProcessMemory(m_hAppProcess, mem.App(), + mem.This(), mem.Size(), &szTmp)) + { + throw AppException(this, "!WriteProcessMemory"); + } +} + +void AppMonitor::MemReadApp(const AppMem& mem) +{ + SIZE_T szTmp = mem.Size(); + if(!ReadProcessMemory(m_hAppProcess, mem.App(), + mem.This(), mem.Size(), &szTmp)) + { + throw AppException(this, "!ReadProcessMemory"); + } +} + +bool AppMonitor::AppMessage(HWND hWnd, UINT uMsg, + WPARAM wParam, LPARAM lParam, + DWORD_PTR* pResult, + unsigned uTimeOut) +{ + DWORD_PTR dwResult = 0; + LRESULT lResult; + + if (IsWindowUnicode(hWnd)) + { + lResult = SendMessageTimeoutW( + hWnd, uMsg, wParam, lParam, + SMTO_ABORTIFHUNG, uTimeOut, + &dwResult); + } + else + { + lResult = SendMessageTimeoutA( + hWnd, uMsg, wParam, lParam, + SMTO_ABORTIFHUNG, uTimeOut, + &dwResult); + } + + if (pResult) *pResult = dwResult; + + if (lResult) // ок + return true; + else if (GetLastError() == ERROR_TIMEOUT) // таймаут + throw AppTimeOut(this, uMsg); + else // ошибка + { + throw AppException(this, "!SendMessageTimeoutW"); + } +} + +void AppMonitor::AppPostMessage(HWND hWnd, UINT uMsg, + WPARAM wParam, LPARAM lParam) +{ + if (!hWnd) + throw AppException(this, "!hWnd"); + if (!PostMessageW(hWnd, uMsg, wParam, lParam)) + throw AppException(this, "!PostMessageW"); +} + +AppMem AppMonitor::NewString(HWND hWnd, DWORD dwChars) +{ + if (!dwChars) dwChars = 256; + return MemAlloc(IsWindowUnicode(hWnd) + ? sizeof(wchar_t) * dwChars + : sizeof(char) * dwChars + ); +} + +std::wstring AppMonitor::ReadString(HWND hWnd, const AppMem& str) +{ + std::wstring ret; + MemReadApp(str); + + if (IsWindowUnicode(hWnd)) + { + wchar_t* pszText = (wchar_t*)str.This(); + pszText[(uint64_t)(str.Size()-1)/sizeof(wchar_t)] = L'\0'; + ret = std::wstring(pszText); + } + else + { + char* pszText = (char*)str.This(); + pszText[(uint64_t)(str.Size()-1)/sizeof(char)] = '\0'; + ret = AnsiToWchar(pszText); + } + + return ret; +} + +std::wstring AppMonitor::GetWindowTextStr(HWND hWnd) +{ + auto pszText = std::make_unique(MAX_WM_TEXT); + + SetLastError(0); + int iLen = GetWindowTextW(hWnd, pszText.get(), MAX_WM_TEXT); + if (iLen < 0) + throw AppException(this, "!GetWindowTextW"); + + pszText[iLen] = L'\0'; + return std::wstring(pszText.get()); +} + +std::wstring AppMonitor::GetControlTextStr(HWND hWnd) +{ + DWORD_PTR dwLength = 0, dwRead = 0; + AppMessage(hWnd, WM_GETTEXTLENGTH, 0, 0, + &dwLength); + if (dwLength <= 0) + return L""; + + std::wstring ret; + if (IsWindowUnicode(hWnd)) + { + auto pszText = std::make_unique(dwLength * 2); + AppMessage(hWnd, WM_GETTEXT, + (WPARAM)dwLength+1, (LPARAM)pszText.get(), + &dwRead); + //dwRead = (DWORD_PTR)SendMessage(hWnd, WM_GETTEXT, + // (WPARAM)dwLength+1, (LPARAM)pszText.get()); + pszText[dwRead] = L'\0'; + ret = std::wstring(pszText.get()); + } + else + { + auto pszText = std::make_unique(dwLength * 2); + AppMessage(hWnd, WM_GETTEXT, + (WPARAM)dwLength+1, (LPARAM)pszText.get(), + &dwRead); + //dwRead = (DWORD_PTR)SendMessage(hWnd, WM_GETTEXT, + // (WPARAM)dwLength+1, (LPARAM)pszText.get()); + pszText[dwRead] = '\0'; + ret = AnsiToWchar(std::string(pszText.get())); + } + + return ret; +} + +DWORD_PTR AppMonitor::TV_GetNextItem(HWND hTree, DWORD dwFlags, + DWORD_PTR dwItem) +{ + DWORD_PTR dwRetItem = 0; + AppMessage(hTree, TVM_GETNEXTITEM, + (WPARAM)dwFlags, dwItem, &dwRetItem); + return dwRetItem; +} + +typedef struct { + uint32_t mask; + uint32_t hItem; + uint32_t state; + uint32_t stateMask; + uint32_t dwText; + int32_t cchTextMax; + int32_t iImage; + int32_t iSelectedImage; + int32_t cChildren; + uint32_t lParam; +} tvitem32_t; + +std::tuple +AppMonitor::TV_GetItem32(HWND hTree, DWORD_PTR dwItem) +{ + DWORD_PTR dwRet; + AppMem item = MemAlloc(sizeof(tvitem32_t)); + AppMem str = NewString(hTree, MAX_TV_TEXT); + + std::wstring text = L""; + int icon = 0; + + tvitem32_t* tvItem = item.As(); + tvItem->mask = TVIF_HANDLE | TVIF_TEXT | TVIF_IMAGE; + tvItem->hItem = (uint32_t)dwItem; + tvItem->cchTextMax = MAX_TV_TEXT; + tvItem->dwText = (uint32_t)((uintptr_t)str.App()); + + MemWriteApp(item); + AppMessage(hTree, IsWindowUnicode(hTree) + ? TVM_GETITEMW : TVM_GETITEMA, + 0, (LPARAM)item.App(), &dwRet + ); + if ((BOOL)dwRet) + { + MemReadApp(item); + + text = ReadString(hTree, str); + icon = tvItem->iImage; + + MemFree(item); + MemFree(str); + } + else + { + MemFree(item); + MemFree(str); + throw AppException(this, "TVM_GETITEM !dwRet"); + } + + return std::make_tuple(text, icon); +} + +typedef struct { + uint32_t mask; + uint64_t hItem; + uint32_t state; + uint32_t stateMask; + uint64_t dwText; + int32_t cchTextMax; + int32_t iImage; + int32_t iSelectedImage; + int32_t cChildren; + uint64_t lParam; +} tvitem64_t; + +std::tuple +AppMonitor::TV_GetItem64(HWND hTree, DWORD_PTR dwItem) +{ + DWORD_PTR dwRet; + AppMem item = MemAlloc(sizeof(tvitem64_t)); + AppMem str = NewString(hTree, MAX_TV_TEXT); + + std::wstring text = L""; + int icon = 0; + + tvitem64_t* tvItem = item.As(); + tvItem->mask = TVIF_HANDLE | TVIF_TEXT | TVIF_IMAGE; + tvItem->hItem = (uint64_t)dwItem; + tvItem->cchTextMax = MAX_TV_TEXT; + tvItem->dwText = (uint64_t)((uintptr_t)str.App()); + + MemWriteApp(item); + AppMessage(hTree, IsWindowUnicode(hTree) + ? TVM_GETITEMW : TVM_GETITEMA, + 0, (LPARAM)item.App(), &dwRet + ); + if ((BOOL)dwRet) + { + MemReadApp(item); + + text = ReadString(hTree, str); + icon = tvItem->iImage; + + MemFree(item); + MemFree(str); + } + else + { + MemFree(item); + MemFree(str); + throw AppException(this, "TVM_GETITEM !dwRet"); + } + + return std::make_tuple(text, icon); +} + +std::tuple +AppMonitor::TV_GetItem(HWND hTree, DWORD_PTR dwItem) +{ + if (IsWow64()) return TV_GetItem32(hTree, dwItem); + else return TV_GetItem64(hTree, dwItem); +} diff --git a/win32ctrl.h b/win32ctrl.h new file mode 100644 index 0000000..635d720 --- /dev/null +++ b/win32ctrl.h @@ -0,0 +1,170 @@ +#ifndef __WIN32CTRL_H +#define __WIN32CTRL_H + +#include +#include +#include +#include +#include + +class AppMem +{ +public: + AppMem(void* pThisMem = NULL, void* pAppMem = NULL, size_t uLen = 0) + : m_pThisMem(pThisMem), m_pAppMem(pAppMem), m_uMemLen(uLen) + { + } + + inline void Zero() + { + if (m_pThisMem) + ZeroMemory(m_pThisMem, m_uMemLen); + } + + inline void* This() const { return m_pThisMem; } + inline void* App() const { return m_pAppMem; } + inline unsigned Size() const { return m_uMemLen; } + + template + T* As() + { + return (T*)This(); + } +private: + void* m_pThisMem; + void* m_pAppMem; + unsigned m_uMemLen; +}; + +class AppMonitor; + +class AppException : public std::exception +{ +public: + AppException(AppMonitor* app, + const std::string& text); + + virtual AppMonitor* GetApp() const + { + return m_pApp; + } + + virtual DWORD GetError() const + { + return m_dwError; + } + + virtual const char* what() const noexcept; +private: + AppMonitor* m_pApp; + std::string m_Text; + DWORD m_dwError; +}; + +class AppTimeOut : public AppException +{ +public: + AppTimeOut(AppMonitor* app, UINT uMsg) + : AppException(app, "[AppTimeOut]"), + m_uMsg(uMsg) + { + } + + virtual UINT GetMessage() const + { + return m_uMsg; + } +private: + UINT m_uMsg; +}; + +#define MAX_CMDLINE 1024 +#define APP_MSG_TIMEOUT 60*1000 +#define MAX_WM_TEXT 4096 +#define MAX_TV_TEXT 256 + +class AppMonitor +{ +public: + static void Init(); + + AppMonitor(); + AppMonitor(const std::wstring& exePath); + virtual ~AppMonitor(); + + typedef std::function EnumFunc; + + friend BOOL CALLBACK _EnumAppWindows(HWND, LPARAM); + void EnumAppWindows(EnumFunc func); + void EnumAppControls(HWND hWnd, EnumFunc func); + HWND FindAppWindow(const std::string& wndClass); + + virtual HANDLE GetAppProcess() const + { + return m_hAppProcess; + } + + virtual DWORD GetAppProcessId() const + { + return m_dwPid; + } + + virtual bool StartApp(const std::wstring& cmdLine); + virtual void CloseApp(); + virtual void Terminate(); + virtual bool IsAppRunning() const; + virtual bool IsWow64() const; + virtual bool WaitAppIdle(DWORD dwInterval = INFINITE); + + virtual void MonitorSetup(); +protected: + virtual void OnAppWindow(HWND hWnd); + void SetExePath(const std::wstring& exe); +public: + virtual std::string GetWindowClass(HWND hWnd); + virtual HWND GetChild(HWND hWnd, const std::string& wndClass, + const std::wstring& wndText = L""); + + virtual AppMem MemAlloc(unsigned uLen); + virtual void MemFree(AppMem& mem); + virtual void MemWriteApp(const AppMem& mem); + virtual void MemReadApp(const AppMem& mem); + + virtual bool AppMessage(HWND hWnd, UINT uMsg, + WPARAM wParam, LPARAM lParam, + DWORD_PTR* pResult = NULL, + unsigned uTimeOut = APP_MSG_TIMEOUT); + virtual void AppPostMessage(HWND hWnd, UINT uMsg, + WPARAM wParam, LPARAM lParam); + + virtual AppMem NewString(HWND hWnd, DWORD dwChars); + virtual std::wstring ReadString(HWND hWnd, const AppMem& str); + + virtual std::wstring GetWindowTextStr(HWND hWnd); + virtual std::wstring GetControlTextStr(HWND hWnd); + + virtual DWORD_PTR TV_GetNextItem(HWND hTree, DWORD dwFlags, + DWORD_PTR dwItem = 0); +private: + std::tuple + TV_GetItem32(HWND hTree, DWORD_PTR dwItem); + std::tuple + TV_GetItem64(HWND hTree, DWORD_PTR dwItem); +public: + virtual std::tuple + TV_GetItem(HWND hTree, DWORD_PTR dwItem); +private: + std::wstring m_ExePath; + + HANDLE m_hAppProcess; + DWORD m_dwPid; + BOOL m_bWow64; + + struct _app_tmp_s { + EnumFunc m_Func = NULL; + std::string m_Class; + HWND m_hWnd = NULL; + } m_Tmp; +}; + +#endif diff --git a/win32util.cpp b/win32util.cpp new file mode 100644 index 0000000..87fa7b9 --- /dev/null +++ b/win32util.cpp @@ -0,0 +1,190 @@ +#include "win32util.h" +#include +#include +#include +#include +#include +#include + +std::wstring TextToWchar(const std::string& text) +{ + size_t uWcharLen = MultiByteToWideChar(CP_UTF8, 0, + text.c_str(), text.size(), NULL, 0); + auto pszWchar = std::make_unique(uWcharLen+1); + MultiByteToWideChar(CP_UTF8, 0, text.c_str(), text.size(), + pszWchar.get(), uWcharLen); + pszWchar[uWcharLen] = L'\0'; + return std::wstring(pszWchar.get()); +} + +std::string WcharToText(const std::wstring& text) +{ + size_t uMbsLen = WideCharToMultiByte(CP_UTF8, 0, + text.c_str(), text.size(), NULL, 0, NULL, NULL); + auto pszChar = std::make_unique(uMbsLen +1); + WideCharToMultiByte(CP_UTF8, 0, text.c_str(), text.size(), + pszChar.get(), uMbsLen, NULL, NULL); + pszChar[uMbsLen] = '\0'; + return std::string(pszChar.get()); +} + +std::wstring AnsiToWchar(const std::string& text, int cp) +{ + size_t uWcharLen = MultiByteToWideChar(cp, 0, + text.c_str(), text.size(), NULL, 0); + auto pszWchar = std::make_unique(uWcharLen +1); + MultiByteToWideChar(cp, 0, text.c_str(), text.size(), + pszWchar.get(), uWcharLen); + pszWchar[uWcharLen] = L'\0'; + return std::wstring(pszWchar.get()); +} + + +std::string WcharToAnsi(const std::wstring& text, int cp) +{ + size_t uMbsLen = WideCharToMultiByte(cp, 0, + text.c_str(), text.size(), NULL, 0, NULL, NULL); + auto pszChar = std::make_unique(uMbsLen +1); + WideCharToMultiByte(cp, 0, text.c_str(), text.size(), + pszChar.get(), uMbsLen, NULL, NULL); + pszChar[uMbsLen] = '\0'; + return std::string(pszChar.get()); +} + +struct _findwnd_s { + DWORD m_dwPid; + const char* m_pClass; + HWND m_hWnd; + DWORD m_dwTid; +}; + +static BOOL CALLBACK _CheckWindow(HWND hWnd, LPARAM lParam) +{ + struct _findwnd_s* wnd = (struct _findwnd_s*)lParam; + char szClassName[64] = {0}; + + DWORD dwPid; + DWORD dwTid = GetWindowThreadProcessId(hWnd, &dwPid); + if (dwPid != wnd->m_dwPid) + return TRUE; + + GetClassNameA(hWnd, szClassName, 64); + if (!strcmp(szClassName, wnd->m_pClass)) + { + wnd->m_hWnd = hWnd; + wnd->m_dwTid = dwTid; + return FALSE; + } + + return TRUE; +} + +bool FindProcessWindow(DWORD dwPid, const char* pClass, + HWND& hWnd, DWORD& uiThread) +{ + struct _findwnd_s wnd = { 0 }; + + wnd.m_dwPid = dwPid; + wnd.m_pClass = pClass; + wnd.m_hWnd = NULL; + + EnumWindows(_CheckWindow, (LPARAM)&wnd); + if (wnd.m_hWnd) + { + hWnd = wnd.m_hWnd; + uiThread = wnd.m_dwTid; + return true; + } + + return false; +} + +bool ReconnectIO(bool OpenNewConsole) +{ + int hConHandle; + intptr_t iStdHandle; + FILE *fp; + bool MadeConsole; + + MadeConsole=false; + if(!AttachConsole(ATTACH_PARENT_PROCESS)) + { + if(!OpenNewConsole) + return false; + + MadeConsole=true; + if(!AllocConsole()) + return false; + } + + iStdHandle = (intptr_t)GetStdHandle(STD_OUTPUT_HANDLE); + hConHandle = _open_osfhandle(iStdHandle, _O_TEXT); + fp = _fdopen( hConHandle, "w" ); + *stdout = *fp; + setvbuf( stdout, NULL, _IONBF, 0 ); + + iStdHandle = (intptr_t)GetStdHandle(STD_INPUT_HANDLE); + hConHandle = _open_osfhandle(iStdHandle, _O_TEXT); + fp = _fdopen( hConHandle, "r" ); + *stdin = *fp; + setvbuf( stdin, NULL, _IONBF, 0 ); + + iStdHandle = (intptr_t)GetStdHandle(STD_ERROR_HANDLE); + hConHandle = _open_osfhandle(iStdHandle, _O_TEXT); + fp = _fdopen( hConHandle, "w" ); + *stderr = *fp; + setvbuf( stderr, NULL, _IONBF, 0 ); + + std::ios_base::sync_with_stdio(); + + return MadeConsole; +} + +listdir ListDirectory(const std::wstring& path) +{ + auto pFind = std::make_unique(); + std::wstring findPath = path + L"\\*"; + + std::vector files, dirs; + HANDLE hFind = FindFirstFileW(findPath.c_str(), pFind.get()); + if (hFind) + { + do { + if (!wcscmp(pFind->cFileName, L".")) + continue; + if (!wcscmp(pFind->cFileName, L"..")) + continue; + + if (pFind->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + dirs.emplace_back(pFind->cFileName); + else files.emplace_back(pFind->cFileName); + } while (FindNextFileW(hFind, pFind.get())); + FindClose(hFind); + } + + return std::make_tuple(files, dirs); +} + +uint64_t GetDirectorySize(const std::wstring& path) +{ + uint64_t uDirSize = 0; + auto [files, dirs] = ListDirectory(path); + + for (auto& file : files) + { + LARGE_INTEGER fileSize = {0}; + HANDLE hFile = CreateFileW((path + L"\\" + file).c_str(), + GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) + continue; + if (GetFileSizeEx(hFile, &fileSize)) + uDirSize += fileSize.QuadPart; + CloseHandle(hFile); + } + + for (auto& dir : dirs) + uDirSize += GetDirectorySize(path + L"\\" + dir); + + return uDirSize; +} diff --git a/win32util.h b/win32util.h new file mode 100644 index 0000000..6ce61a2 --- /dev/null +++ b/win32util.h @@ -0,0 +1,28 @@ +#ifndef __WIN32UTIL_H +#define __WIN32UTIL_H + +#include +#include +#include +#include +#include + +std::wstring TextToWchar(const std::string& text); +std::string WcharToText(const std::wstring& text); +std::wstring AnsiToWchar(const std::string& text, int cp = CP_THREAD_ACP); +std::string WcharToAnsi(const std::wstring& text, int cp = CP_THREAD_ACP); + +bool FindProcessWindow(DWORD dwPid, const char* pClass, + HWND& hWnd, DWORD& uiThread); + +bool ReconnectIO(bool OpenNewConsole); + +using listdir = std::tuple< + std::vector, + std::vector +>; + +listdir ListDirectory(const std::wstring& path); +uint64_t GetDirectorySize(const std::wstring& path); + +#endif