27.02.2021: win32ctrl initial commit.
This commit is contained in:
commit
4f660b1398
5 changed files with 922 additions and 0 deletions
23
CMakeLists.txt
Normal file
23
CMakeLists.txt
Normal 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
511
win32ctrl.cpp
Normal 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
170
win32ctrl.h
Normal 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
190
win32util.cpp
Normal 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
28
win32util.h
Normal 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
|
||||
Loading…
Add table
Reference in a new issue