27.02.2021: win32ctrl initial commit.

This commit is contained in:
mykola2312 2021-02-27 17:34:28 +02:00
commit 4f660b1398
5 changed files with 922 additions and 0 deletions

23
CMakeLists.txt Normal file
View file

@ -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
)

511
win32ctrl.cpp Normal file
View file

@ -0,0 +1,511 @@
#include "win32ctrl.h"
#include "win32util.h"
#include <commctrl.h>
#include <stdint.h>
#include <string.h>
#include <strsafe.h>
#include <exception>
#include <memory>
/* 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<wchar_t[]>(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<wchar_t[]>(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<wchar_t[]>(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<char[]>(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<std::wstring,int>
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<tvitem32_t>();
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<std::wstring,int>
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<tvitem64_t>();
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<std::wstring,int>
AppMonitor::TV_GetItem(HWND hTree, DWORD_PTR dwItem)
{
if (IsWow64()) return TV_GetItem32(hTree, dwItem);
else return TV_GetItem64(hTree, dwItem);
}

170
win32ctrl.h Normal file
View file

@ -0,0 +1,170 @@
#ifndef __WIN32CTRL_H
#define __WIN32CTRL_H
#include <Windows.h>
#include <functional>
#include <exception>
#include <string>
#include <tuple>
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<typename T>
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<bool(AppMonitor*, HWND)> 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<std::wstring,int>
TV_GetItem32(HWND hTree, DWORD_PTR dwItem);
std::tuple<std::wstring,int>
TV_GetItem64(HWND hTree, DWORD_PTR dwItem);
public:
virtual std::tuple<std::wstring,int>
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

190
win32util.cpp Normal file
View file

@ -0,0 +1,190 @@
#include "win32util.h"
#include <io.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <memory>
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<wchar_t[]>(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<char[]>(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<wchar_t[]>(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<char[]>(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<WIN32_FIND_DATAW>();
std::wstring findPath = path + L"\\*";
std::vector<std::wstring> 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;
}

28
win32util.h Normal file
View file

@ -0,0 +1,28 @@
#ifndef __WIN32UTIL_H
#define __WIN32UTIL_H
#include <Windows.h>
#include <stdint.h>
#include <string>
#include <vector>
#include <tuple>
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::wstring>,
std::vector<std::wstring>
>;
listdir ListDirectory(const std::wstring& path);
uint64_t GetDirectorySize(const std::wstring& path);
#endif