LunaHook-mirror/LunaHost/GUI/LunaHost.cpp
恍兮惚兮 6e011c5780 hookfind
2024-03-28 19:24:19 +08:00

720 lines
24 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <CommCtrl.h>
#include <TlHelp32.h>
#include<stdio.h>
#include<thread>
#include<fstream>
#include"host.h"
#include"hookcode.h"
#include"textthread.h"
#include"LunaHost.h"
#include"Lang/Lang.h"
auto gmf=[&](DWORD processId)->std::optional<std::wstring>{
//见鬼了GetModuleFileName找不到标识符
std::vector<wchar_t> buffer(MAX_PATH);
if (AutoHandle<> process = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, processId))
if (GetModuleFileNameExW(process, 0, buffer.data(), MAX_PATH)) return buffer.data();
return {};
};
void LunaHost::toclipboard(std::wstring& sentence){
for (int loop = 0; loop < 10; loop++) {
if (OpenClipboard(winId)) {
HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, (sentence.size() + 2) * sizeof(wchar_t));
memcpy(GlobalLock(hMem), sentence.c_str(), (sentence.size() + 2) * sizeof(wchar_t));
EmptyClipboard();
SetClipboardData(CF_UNICODETEXT, hMem);
GlobalUnlock(hMem);
CloseClipboard();
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
}
void LunaHost::on_close(){
savesettings();
delete configs;
for(auto pid:attachedprocess){
Host::DetachProcess(pid);
}
if(attachedprocess.size())
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
void LunaHost::savesettings()
{
configs->set("ToClipboard",check_toclipboard);
configs->set("AutoAttach",autoattach);
configs->set("AutoAttach_SavedOnly",autoattach_savedonly);
configs->set("flushDelay",TextThread::flushDelay);
configs->set("filterRepetition",TextThread::filterRepetition);
configs->set("maxBufferSize",TextThread::maxBufferSize);
configs->set("maxHistorySize",TextThread::maxHistorySize);
configs->set("defaultCodepage",Host::defaultCodepage);
configs->set("autoattachexes",autoattachexes);
configs->set("savedhookcontext",savedhookcontext);
}
void LunaHost::loadsettings(){
check_toclipboard=configs->get("ToClipboard",false);
autoattach=configs->get("AutoAttach",false);
autoattach_savedonly=configs->get("AutoAttach_SavedOnly",true);
TextThread::flushDelay=configs->get("flushDelay",TextThread::flushDelay);
TextThread::filterRepetition=configs->get("filterRepetition",TextThread::filterRepetition);
TextThread::maxBufferSize=configs->get("maxBufferSize",TextThread::maxBufferSize);
TextThread::maxHistorySize=configs->get("maxHistorySize",TextThread::maxHistorySize);
Host::defaultCodepage=configs->get("defaultCodepage",Host::defaultCodepage);
autoattachexes=configs->get("autoattachexes",std::set<std::string>{});
savedhookcontext=configs->get("savedhookcontext",decltype(savedhookcontext){});
}
std::unordered_map<std::wstring,std::vector<int>> getprocesslist();
void LunaHost::doautoattach()
{
if(autoattach==false&&autoattach_savedonly==false)return;
if(autoattachexes.empty())return;
for(auto [pexe,pids ]:getprocesslist())
{
auto&& u8procname=WideStringToString(pexe);
if(autoattachexes.find(u8procname)==autoattachexes.end())continue;
if(autoattach_savedonly && savedhookcontext.find(u8procname)==savedhookcontext.end())continue;
for(auto pid:pids){
if(userdetachedpids.find(pid)!=userdetachedpids.end())continue;
if(attachedprocess.find(pid)==attachedprocess.end())
Host::InjectProcess(pid);
}
break;
}
}
void LunaHost::on_proc_connect(DWORD pid)
{
attachedprocess.insert(pid);
if(auto pexe=GetModuleFilename(pid))
{
autoattachexes.insert(WideStringToString(pexe.value()));
}
}
LunaHost::LunaHost(){
configs=new confighelper;
loadsettings();
std::thread([&]{
while(1){
doautoattach();
std::this_thread::sleep_for(std::chrono::seconds(2));
}
}).detach();
setfont(25);
settext(WndLunaHostGui);
btnshowsettionwindow=new button(this, BtnShowSettingWindow);
g_selectprocessbutton =new button(this,BtnSelectProcess) ;
// btnsavehook=new button(this,BtnSaveHook,10,10,10,10);
// btnsavehook->onclick=std::bind(&LunaHost::btnsavehookscallback,this);
btndetachall=new button(this,BtnDetach);
btndetachall->onclick=[&](){
for(auto pid:attachedprocess){
Host::DetachProcess(pid);
userdetachedpids.insert(pid);
}
};
g_hEdit_userhook = new lineedit(this);
btnplugin=new button(this,BtnPlugin);
plugins=new Pluginmanager(this);
btnplugin->onclick=[&](){
if(pluginwindow==0) pluginwindow=new Pluginwindow(this,plugins);
pluginwindow->show();
};
g_hButton_insert = new button(this,BtnInsertUserHook) ;
btnshowsettionwindow->onclick=[&](){
if(settingwindow==0) settingwindow=new Settingwindow(this);
settingwindow->show();
};
g_selectprocessbutton->onclick=[&](){
if(_processlistwindow==0) _processlistwindow=new processlistwindow(this);
_processlistwindow->show();
};
g_hButton_insert->onclick=[&](){
auto hp = HookCode::Parse(std::move(g_hEdit_userhook->text()));
if(hp){
for(auto _:attachedprocess){
Host::InsertHook(_,hp.value());
}
}
else{
g_showtexts->appendtext(NotifyInvalidHookCode);
}
};
g_hListBox_listtext = new listbox(this);
g_hListBox_listtext->oncurrentchange=[&](int idx){
uint64_t handle = g_hListBox_listtext->getdata(idx);
std::wstring get;
for(auto& _:savetext.at(handle)){
get+=_;
get+=L"\r\n";
}
currentselect=handle;
g_showtexts->settext(get);
g_showtexts->scrolltoend();
};
#define IDM_REMOVE_HOOK 1001
#define IDM_DETACH_PROCESS 1002
#define IDM_COPY_HOOKCODE 1003
#define IDM_REMEMBER_SELECTION 1004
#define IDM_FORGET_SELECTION 1005
g_hListBox_listtext->oncontextmenu=[](){
HMENU hMenu = CreatePopupMenu();
AppendMenu(hMenu, MF_STRING, IDM_COPY_HOOKCODE, MenuCopyHookCode);
AppendMenu(hMenu, MF_STRING, IDM_REMOVE_HOOK, MenuRemoveHook);
AppendMenu(hMenu, MF_STRING, IDM_DETACH_PROCESS, MenuDetachProcess);
AppendMenu(hMenu, MF_STRING, IDM_REMEMBER_SELECTION, MenuRemeberSelect);
AppendMenu(hMenu, MF_STRING, IDM_FORGET_SELECTION, MenuForgetSelect);
return hMenu;
};
g_hListBox_listtext->oncontextmenucallback=[&](WPARAM wparam){
auto handle = g_hListBox_listtext->getdata(g_hListBox_listtext->currentidx());
auto tt=Host::GetThread(handle);
if(tt==0)return;
switch (LOWORD(wparam)) {
case IDM_COPY_HOOKCODE:
toclipboard(std::wstring(tt->hp.hookcode));
break;
case IDM_DETACH_PROCESS:
Host::DetachProcess(tt->tp.processId);
userdetachedpids.insert(tt->tp.processId);
break;
case IDM_REMOVE_HOOK:
Host::RemoveHook(tt->tp.processId,tt->tp.addr);
break;
case IDM_FORGET_SELECTION:
case IDM_REMEMBER_SELECTION:
{
if(auto pexe=gmf(tt->tp.processId))
{
auto pexev=WideStringToString(pexe.value());
if(LOWORD(wparam)==IDM_REMEMBER_SELECTION)
{
savedhookcontext[pexev]={
{"hookcode",WideStringToString(tt->hp.hookcode)},
{"ctx1",tt->tp.ctx},
{"ctx2",tt->tp.ctx2},
};
}
else if(LOWORD(wparam)==IDM_FORGET_SELECTION)
{
savedhookcontext.erase(pexev);
}
}
}
break;
}
};
g_showtexts = new multilineedit(this);
g_showtexts->setreadonly(true);
btnsearchhooks=new button(this,BtnSearchHook);
btnsearchhooks->onclick=[&](){
if(hooksearchwindow==0) hooksearchwindow=new Hooksearchwindow(this);
hooksearchwindow->show();
};
Host::Start(
std::bind(&LunaHost::on_proc_connect,this,std::placeholders::_1),
[&](DWORD pid) {
attachedprocess.erase(pid);
},
std::bind(&LunaHost::on_thread_create,this,std::placeholders::_1),
std::bind(&LunaHost::on_thread_delete,this,std::placeholders::_1),
std::bind(&LunaHost::on_text_recv,this,std::placeholders::_1,std::placeholders::_2)
);
mainlayout=new gridlayout();
mainlayout->addcontrol(g_selectprocessbutton,0,0);
mainlayout->addcontrol(btndetachall,0,1);
mainlayout->addcontrol(btnshowsettionwindow,0,2);
mainlayout->addcontrol(btnplugin,0,3);
mainlayout->addcontrol(g_hEdit_userhook,1,0,1,2);
mainlayout->addcontrol(g_hButton_insert,1,2);
mainlayout->addcontrol(btnsearchhooks,1,3);
mainlayout->addcontrol(g_hListBox_listtext,2,0,1,4);
mainlayout->addcontrol(g_showtexts,3,0,1,4);
mainlayout->setfixedheigth(0,30);
mainlayout->setfixedheigth(1,30);
setlayout(mainlayout);
setcentral(1200,800);
}
void LunaHost::on_text_recv_checkissaved(TextThread& thread)
{
if(onceautoselectthread.find(thread.handle)!=onceautoselectthread.end())return;
onceautoselectthread.insert(thread.handle);
if(auto exe=GetModuleFilename(thread.tp.processId))
{
auto exea=WideStringToString(exe.value());
if(savedhookcontext.find(exea)==savedhookcontext.end())return;
std::string hc= savedhookcontext[exea]["hookcode"];
uint64_t ctx1=savedhookcontext[exea]["ctx1"];
uint64_t ctx2=savedhookcontext[exea]["ctx2"];
if(((ctx1&0xffff)==(thread.tp.ctx&0xffff) )&& (ctx2==thread.tp.ctx2) && (hc==WideStringToString(thread.hp.hookcode)))
{
for(int i=0;i<g_hListBox_listtext->count();i++)
{
auto handle=g_hListBox_listtext->getdata(i);
if(handle==thread.handle)
{
g_hListBox_listtext->setcurrent(i);
break;
}
}
}
}
}
bool LunaHost::on_text_recv(TextThread& thread, std::wstring& output){
std::lock_guard _(settextmutex);
on_text_recv_checkissaved(thread);
if(!plugins->dispatch(thread,output))return false;
strReplace(output,L"\n",L"\r\n");
savetext.at(thread.handle).push_back(output);
if(currentselect==thread.handle){
g_showtexts->scrolltoend();
g_showtexts->appendtext(output);
}
return true;
}
void LunaHost::on_thread_create(TextThread& thread){
wchar_t buff[65535];
swprintf_s(buff,L"[%I64X:%I32X:%I64X:%I64X:%I64X:%s:%s]",
thread.handle,
thread.tp.processId,
thread.tp.addr,
thread.tp.ctx,
thread.tp.ctx2,
thread.name.c_str(),
thread.hp.hookcode
);
savetext.insert({thread.handle,{}});
int index=g_hListBox_listtext->additem(buff);
g_hListBox_listtext->setdata(index,thread.handle);
}
void LunaHost::on_thread_delete(TextThread& thread){
int count = g_hListBox_listtext->count();
for (int i = 0; i < count; i++) {
uint64_t handle = g_hListBox_listtext->getdata(i);
if (handle== thread.handle) {
g_hListBox_listtext->deleteitem(i);
break;
}
}
}
Settingwindow::Settingwindow(LunaHost* host):mainwindow(host){
int height=30;int curry=10;int space=10;
int labelwidth=300;int spinwidth=200;
g_timeout = new spinbox(this,TextThread::flushDelay) ;
g_codepage = new spinbox(this,Host::defaultCodepage) ;
spinmaxbuffsize = new spinbox(this,TextThread::maxBufferSize);
;curry+=height+space;
spinmaxbuffsize->onvaluechange=[=](int v){
TextThread::maxBufferSize=v;
};
spinmaxhistsize = new spinbox(this,TextThread::maxHistorySize) ;
;curry+=height+space;
spinmaxhistsize->onvaluechange=[=](int v){
TextThread::maxHistorySize=v;
};
ckbfilterrepeat=new checkbox(this,LblFilterRepeat);
ckbfilterrepeat->onclick=[=](){
TextThread::filterRepetition=ckbfilterrepeat->ischecked();
};
ckbfilterrepeat->setcheck(TextThread::filterRepetition);
g_check_clipboard =new checkbox(this,BtnToClipboard);
g_check_clipboard->onclick=[=](){
host->check_toclipboard=g_check_clipboard->ischecked();
};
g_check_clipboard->setcheck(host->check_toclipboard);
autoattach =new checkbox(this,LblAutoAttach);
autoattach->onclick=[=](){
host->autoattach=autoattach->ischecked();
};
autoattach->setcheck(host->autoattach);
autoattach_so =new checkbox(this,LblAutoAttach_savedonly);
autoattach_so->onclick=[=](){
host->autoattach_savedonly=autoattach_so->ischecked();
};
autoattach_so->setcheck(host->autoattach_savedonly);
readonlycheck=new checkbox(this,BtnReadOnly);
readonlycheck->onclick=[=](){
host->g_showtexts->setreadonly(readonlycheck->ischecked());
};
readonlycheck->setcheck(true);
g_timeout->onvaluechange=[=](int v){
TextThread::flushDelay=v;
};
g_codepage->onvaluechange=[=](int v){
if(IsValidCodePage(v)){
Host::defaultCodepage= v;
}
};
g_codepage->setminmax(0,CP_UTF8);
mainlayout=new gridlayout();
mainlayout->addcontrol(new label(this,LblFlushDelay),0,0);
mainlayout->addcontrol(g_timeout,0,1);
mainlayout->addcontrol(new label(this,LblCodePage),1,0);
mainlayout->addcontrol(g_codepage,1,1);
mainlayout->addcontrol(new label(this,LblMaxBuff),2,0);
mainlayout->addcontrol(spinmaxbuffsize,2,1);
mainlayout->addcontrol(new label(this,LblMaxHist),3,0);
mainlayout->addcontrol(spinmaxhistsize,3,1);
mainlayout->addcontrol(ckbfilterrepeat,4,0,1,2);
mainlayout->addcontrol(g_check_clipboard,5,0,1,2);
mainlayout->addcontrol(autoattach,6,0,1,2);
mainlayout->addcontrol(autoattach_so,7,0,1,2);
mainlayout->addcontrol(readonlycheck,8,0,1,2);
setlayout(mainlayout);
setcentral(600,500);
settext(WndSetting);
}
void Pluginwindow::on_size(int w,int h){
listplugins->setgeo(10,80,w-20,h-90);
}
Pluginwindow::Pluginwindow(mainwindow*p,Pluginmanager* pl):mainwindow(p){
pluginmanager=pl;
(new label(this,LblPluginNotify))->setgeo(10,10,500,30);
(new label(this,LblPluginRemove))->setgeo( 10,40,500,30);
static auto listadd=[&](const std::wstring& s){
auto idx=listplugins->additem(std::filesystem::path(s).stem());
auto _s=new wchar_t[s.size()+1];wcscpy(_s,s.c_str());
listplugins->setdata(idx,(LONG_PTR)_s);
};
listplugins = new listbox(this);
#define IDM_ADD_PLUGIN 1004
#define IDM_REMOVE_PLUGIN 1006
#define IDM_RANK_UP 1007
#define IDM_RANK_DOWN 1008
listplugins->oncontextmenu=[](){
HMENU hMenu = CreatePopupMenu();
AppendMenu(hMenu, MF_STRING, IDM_ADD_PLUGIN, MenuAddPlugin);
AppendMenu(hMenu, MF_STRING, IDM_REMOVE_PLUGIN, MenuRemovePlugin);
AppendMenu(hMenu, MF_STRING, IDM_RANK_UP, MenuPluginRankUp);
AppendMenu(hMenu, MF_STRING, IDM_RANK_DOWN, MenuPluginRankDown);
return hMenu;
};
listplugins->oncontextmenucallback=[&](WPARAM wparam){
switch (LOWORD(wparam)) {
case IDM_RANK_DOWN:
case IDM_RANK_UP:
{
auto idx=listplugins->currentidx();
if(idx==-1)break;
auto idx2=idx+(
(LOWORD(wparam)==IDM_RANK_UP)?-1:1
);
auto a=min(idx,idx2),b=max(idx,idx2);
if(a<0||b>=listplugins->count())break;
pluginmanager->swaprank(a,b);
auto pa=((LPCWSTR)listplugins->getdata(a));
auto pb=((LPCWSTR)listplugins->getdata(b));
listplugins->deleteitem(a);
listplugins->insertitem(b,std::filesystem::path(pa).stem());
listplugins->setdata(b,(LONG_PTR)pa);
break;
}
case IDM_ADD_PLUGIN:
{
auto f=pluginmanager->selectpluginfile();
if(f.has_value()){
if(pluginmanager->addplugin(f.value())){
listadd(f.value());
}
else{
MessageBoxW(winId,InvalidPlugin,MsgError,0);
}
}
break;
}
case IDM_REMOVE_PLUGIN:
{
auto idx=listplugins->currentidx();
if(idx==-1)break;
pluginmanager->remove((LPCWSTR)listplugins->getdata(idx));
listplugins->deleteitem(idx);
break;
}
}
};
for(int i=0;i<pluginmanager->PluginRank.size();i++){
listadd(pluginmanager->PluginRank[i]);
}
settext(WndPlugins);
setcentral(500,400);
}
void HooksearchText::call(std::set<DWORD>pids){
edittext->settext(L"");
checkok->onclick=[&,pids](){
close();
auto cp=codepage->getcurr();
if(!IsValidCodePage(cp)) return;
SearchParam sp = {};
sp.codepage=cp;
wcsncpy_s(sp.text, edittext->text().c_str(), PATTERN_SIZE - 1);
wprintf(sp.text);
for(auto pid:pids)
Host::FindHooks(pid, sp);
};
show();
}
HooksearchText::HooksearchText(mainwindow* p):mainwindow(p){
codepage=new spinbox(this,Host::defaultCodepage);
codepage->setminmax(0,CP_UTF8);
edittext=new lineedit(this);
checkok=new button(this,BtnOk);
layout=new gridlayout();
layout->addcontrol(new label(this,HS_TEXT),0,0);
layout->addcontrol(new label(this,HS_CODEPAGE),1,0);
layout->addcontrol(edittext,0,1);
layout->addcontrol(codepage,1,1);
layout->addcontrol(checkok,2,1);
setlayout(layout);
setcentral(500,200);
}
std::wstring tohex(BYTE* bs,int len){
std::wstring buffer;
for (int i = 0; i < len; i += 1){
buffer.append(FormatString(L"%02hX ", bs[i]));
}
return buffer;
}
std::wstring addr2hex(uintptr_t addr){
return FormatString(L"%p",addr);
}
void realcallsearchhooks(std::set<DWORD>pids,std::wstring filter,SearchParam sp){
auto hooks = std::make_shared<std::vector<std::wstring>>();
try
{
for(auto processId:pids)
Host::FindHooks(processId, sp,
[hooks, filter](HookParam hp, std::wstring text)
{
std::wsmatch matches;
if (std::regex_search(text, matches, std::wregex(filter))) {
hooks->emplace_back(std::wstring(hp.hookcode)+L"=>"+text);
}
});
}
catch (std::exception &e) {
//std::wcout<<e.what();
return;
}
std::thread([hooks]
{
for (int lastSize = 0; hooks->size() == 0 || hooks->size() != lastSize; Sleep(2000)) lastSize = hooks->size();
std::ofstream of;
of.open("savehooks.txt");
for (auto line:*hooks) of<<WideStringToString(line)<<"\n";
of.close();
hooks->clear();
}).detach();
}
Hooksearchsetting::Hooksearchsetting(mainwindow* p):mainwindow(p){
layout=new gridlayout();
SearchParam sp{};
spinduration=new spinbox(this,sp.searchTime);
spinoffset=new spinbox(this,sp.offset);
spincap=new spinbox(this,sp.maxRecords);
spincodepage=new spinbox(this,Host::defaultCodepage);
editpattern=new lineedit(this);
editpattern->settext(tohex(sp.pattern,sp.length));
editmodule=new lineedit(this);
editmaxaddr=new lineedit(this);
editmaxaddr->settext(addr2hex(sp.maxAddress));
editminaddr=new lineedit(this);
editminaddr->settext(addr2hex(sp.minAddress));
spinpadding=new spinbox(this,0);
editregex=new lineedit(this);
start=new button(this,HS_START_HOOK_SEARCH);
layout->addcontrol(new label(this,HS_SEARCH_PATTERN),0,0);
layout->addcontrol(new label(this,HS_SEARCH_DURATION),1,0);
layout->addcontrol(new label(this,HS_PATTERN_OFFSET),2,0);
layout->addcontrol(new label(this,HS_MAX_HOOK_SEARCH_RECORDS),3,0);
layout->addcontrol(new label(this,HS_CODEPAGE),4,0);
layout->addcontrol(new label(this,HS_SEARCH_MODULE),5,0);
layout->addcontrol(new label(this,HS_MIN_ADDRESS),6,0);
layout->addcontrol(new label(this,HS_MAX_ADDRESS),7,0);
layout->addcontrol(new label(this,HS_STRING_OFFSET),8,0);
layout->addcontrol(new label(this,HS_HOOK_SEARCH_FILTER),9,0);
layout->addcontrol(start,10,1);
layout->addcontrol(editpattern,0,1);
layout->addcontrol(spinduration,1,1);
layout->addcontrol(spinoffset,2,1);
layout->addcontrol(spincap,3,1);
layout->addcontrol(spincodepage,4,1);
layout->addcontrol(editmodule,5,1);
layout->addcontrol(editminaddr,6,1);
layout->addcontrol(editmaxaddr,7,1);
layout->addcontrol(spinpadding,8,1);
layout->addcontrol(editregex,9,1);
setlayout(layout);
setcentral(1000,600);
}
std::vector<BYTE> hexStringToBytes(const std::wstring& hexString_) {
auto hexString=hexString_;
strReplace(hexString,L" ",L"");
strReplace(hexString,L"??",FormatString(L"%02hX",XX));
std::vector<BYTE> bytes;
if (hexString.length() % 2 != 0) {
return {};
}
for (int i = 0; i < hexString.size() / 2; i++) {
auto byteValue = std::stoi(hexString.substr(i*2,2), nullptr, 16);
bytes.push_back(byteValue);
}
return bytes;
}
void Hooksearchsetting::call(std::set<DWORD>pids,std::wstring reg){
if(pids.empty())return;
if(auto filename=gmf(*pids.begin()))
editmodule->settext(std::filesystem::path(filename.value()).filename().wstring());
editregex->settext(reg);
spincodepage->setcurr(Host::defaultCodepage);
start->onclick=[&,pids](){
close();
SearchParam sp{};
sp.searchTime=spinduration->getcurr();
sp.offset=spinoffset->getcurr();
sp.maxRecords=spincap->getcurr();
sp.codepage=spincodepage->getcurr();
if(editpattern->text().find(L".")==std::wstring::npos){
auto hex=hexStringToBytes(editpattern->text());
memcpy(sp.pattern,hex.data(),hex.size());
sp.length=hex.size();
}
else{
wcsncpy_s(sp.exportModule, editpattern->text().c_str(), MAX_MODULE_SIZE - 1);
sp.length = 1;
}
wcscpy(sp.boundaryModule,editmodule->text().c_str());
sp.minAddress=std::stoll(editminaddr->text(), nullptr, 16);
sp.maxAddress=std::stoll(editmaxaddr->text(), nullptr, 16);
sp.padding=spinpadding->getcurr();
realcallsearchhooks(pids,editregex->text(),sp);
};
show();
}
Hooksearchwindow::Hooksearchwindow(LunaHost* host):mainwindow(host){
cjkcheck=new checkbox(this,SEARCH_CJK);
hs_default=new button(this,HS_SEARCH_FOR_TEXT);
hs_text=new button(this,HS_SEARCH_FOR_TEXT);
hs_user=new button(this,HS_SETTINGS);
layout=new gridlayout();
layout->addcontrol(cjkcheck,0,0,1,3);
layout->addcontrol(hs_default,1,0);
layout->addcontrol(hs_text,1,1);
layout->addcontrol(hs_user,1,2);
setlayout(layout);
settext(BtnSearchHook);
setcentral(800,200);
auto dohooksearchdispatch=[&,host](int type)
{
close();
if(type==1)
{
if(hooksearchText==0) hooksearchText=new HooksearchText(this);
hooksearchText->call(host->attachedprocess);
return;
}
auto filter=(cjkcheck->ischecked()?L"[\\u3000-\\ua000]{4,}" : L"[\\u0020-\\u1000]{4,}");
if(type==0)
{
SearchParam sp = {};
sp.codepage = Host::defaultCodepage;
sp.length = 0;
realcallsearchhooks(host->attachedprocess,filter,sp);
}
else if(type==2)
{
if(hooksearchsetting==0) hooksearchsetting=new Hooksearchsetting(this);
hooksearchsetting->call(host->attachedprocess,filter);
return;
}
};
hs_default->onclick=std::bind(dohooksearchdispatch,0);
hs_text->onclick=std::bind(dohooksearchdispatch,1);
hs_user->onclick=std::bind(dohooksearchdispatch,2);
}