Переглянути джерело

【模块名称】
GM模块
【问题原因】
临时提交。
【修改描述】

【测试结果】

sat23 4 роки тому
батько
коміт
07c4b7f0eb
6 змінених файлів з 1854 додано та 16 видалено
  1. 19 0
      gm/gm/dllmain.cpp
  2. 1269 0
      gm/gm/gm.cpp
  3. 293 0
      gm/gm/gm.h
  4. 31 15
      gm/gm/winapi/Injecter.cpp
  5. 6 1
      gm/gm/winapi/Injecter.h
  6. 236 0
      gm/gm/注入dll.cpp

+ 19 - 0
gm/gm/dllmain.cpp

@@ -0,0 +1,19 @@
+// dllmain.cpp : 定义 DLL 应用程序的入口点。
+#include "framework.h"
+
+BOOL APIENTRY DllMain( HMODULE hModule,
+                       DWORD  ul_reason_for_call,
+                       LPVOID lpReserved
+                     )
+{
+    switch (ul_reason_for_call)
+    {
+    case DLL_PROCESS_ATTACH:
+    case DLL_THREAD_ATTACH:
+    case DLL_THREAD_DETACH:
+    case DLL_PROCESS_DETACH:
+        break;
+    }
+    return TRUE;
+}
+

+ 1269 - 0
gm/gm/gm.cpp

@@ -0,0 +1,1269 @@
+// OpInterface.cpp: OpInterface 的实现
+#include "gm.h"
+#include "./core/optype.h"
+#include "./core/globalVar.h"
+#include "./core/helpfunc.h"
+#include "./core/opEnv.h"
+#include "./winapi/WinApi.h"
+#include "./background/opBackground.h"
+#include "./ImageProc/ImageProc.h"
+#include "./core/Cmder.h"
+#include "./winapi/Injecter.h"
+#include "./algorithm/AStar.hpp"
+#include "./winapi/MemoryEx.h"
+#include <fstream>
+#include <filesystem>
+#include <regex>
+
+#undef FindWindow
+#undef FindWindowEx
+#undef SetWindowText
+
+const int small_block_size = 10;
+
+libgm::libgm()
+{
+	_winapi = new WinApi;
+	_bkproc = new opBackground;
+	_image_proc = new ImageProc;
+
+	//初始化目录
+	wchar_t buff[256];
+	::GetCurrentDirectoryW(256, buff);
+	_curr_path = buff;
+	_image_proc->_curr_path = _curr_path;
+	//初始化键码表
+	_vkmap[L"back"] = VK_BACK;
+	_vkmap[L"ctrl"] = VK_CONTROL;
+	_vkmap[L"alt"] = 18;
+	_vkmap[L"shift"] = VK_SHIFT;
+	_vkmap[L"win"] = VK_LWIN;
+	_vkmap[L"space"] = L' ';
+	_vkmap[L"tab"] = VK_TAB;
+	_vkmap[L"esc"] = VK_CANCEL;
+	_vkmap[L"enter"] = L'\r';
+	_vkmap[L"up"] = VK_UP;
+	_vkmap[L"down"] = VK_DOWN;
+	_vkmap[L"left"] = VK_LEFT;
+	_vkmap[L"right"] = VK_RIGHT;
+	_vkmap[L"f1"] = VK_F1;
+	_vkmap[L"f2"] = VK_F2;
+	_vkmap[L"f3"] = VK_F3;
+	_vkmap[L"f4"] = VK_F4;
+	_vkmap[L"f5"] = VK_F5;
+	_vkmap[L"f6"] = VK_F6;
+	_vkmap[L"f7"] = VK_F7;
+	_vkmap[L"f8"] = VK_F8;
+	_vkmap[L"f9"] = VK_F9;
+	_vkmap[L"f10"] = VK_F10;
+	_vkmap[L"f11"] = VK_F11;
+	_vkmap[L"f12"] = VK_F12;
+
+	m_opPath = opEnv::getBasePath();
+}
+
+libgm::~libgm()
+{
+	delete _winapi;
+	delete _bkproc;
+	delete _image_proc;
+}
+
+std::wstring libgm::Ver()
+{
+
+	//Tool::setlog("address=%d,str=%s", ver, ver);
+	return _T(OP_VERSION);
+}
+
+void libgm::SetPath(const wchar_t* path, long* ret)
+{
+	wstring fpath = path;
+	replacew(fpath, L"/", L"\\");
+	if (fpath.find(L'\\') != -1 && ::PathFileExistsW(fpath.data()))
+	{
+		_curr_path = fpath;
+		_image_proc->_curr_path = _curr_path;
+		_bkproc->_curr_path = _curr_path;
+		*ret = 1;
+	}
+	else
+	{
+		if (!fpath.empty() && fpath[0] != L'\\')
+			fpath = _curr_path + L'\\' + fpath;
+		else
+			fpath = _curr_path + fpath;
+		if (::PathFileExistsW(fpath.data()))
+		{
+			_curr_path = path;
+			_image_proc->_curr_path = _curr_path;
+			_bkproc->_curr_path = _curr_path;
+			*ret = 1;
+		}
+		else
+			*ret = 0;
+	}
+}
+
+void libgm::GetPath(std::wstring& path)
+{
+	path = _curr_path;
+}
+
+void libgm::GetBasePath(std::wstring& path)
+{
+	path = opEnv::getBasePath();
+}
+
+void libgm::GetID(long* ret)
+{
+	*ret = (long)this;
+}
+
+void libgm::GetLastError(long* ret)
+{
+	*ret = ::GetLastError();
+}
+
+void libgm::SetShowErrorMsg(long show_type, long* ret)
+{
+	opEnv::m_showErrorMsg = show_type;
+	*ret = 1;
+}
+
+void libgm::Sleep(long millseconds, long* ret)
+{
+	::Sleep(millseconds);
+	*ret = 1;
+}
+
+void libgm::InjectDll(const wchar_t* process_name, const wchar_t* dll_name, long* ret)
+{
+	auto proc = _ws2string(process_name);
+	auto dll = _ws2string(dll_name);
+	long hwnd;
+	FindWindowByProcess(process_name, L"", L"", &hwnd);
+	long pid;
+	GetWindowProcessId(hwnd, &pid);
+	*ret = 0;
+	if (Injecter::EnablePrivilege(TRUE))
+	{
+		long error_code = 0;
+		*ret = Injecter::InjectDll(pid, dll_name, error_code);
+	}
+	else
+	{
+		setlog("EnablePrivilege false erro_code=%08X ", ::GetLastError());
+	}
+}
+
+void libgm::EnablePicCache(long enable, long* ret)
+{
+	_image_proc->_enable_cache = enable;
+	*ret = 1;
+}
+
+void libgm::CapturePre(const wchar_t* file, LONG* ret)
+{
+	*ret = _image_proc->Capture(file);
+}
+
+void libgm::AStarFindPath(long mapWidth, long mapHeight, const wchar_t* disable_points, long beginX, long beginY, long endX, long endY, std::wstring& path)
+{
+	AStar as;
+	using Vec2i = AStar::Vec2i;
+	vector<Vec2i> walls;
+	vector<wstring> vstr;
+	Vec2i tp;
+	split(disable_points, vstr, L"|");
+	for (auto& it : vstr)
+	{
+		if (swscanf(it.c_str(), L"%d,%d", &tp.x, &tp.y) != 2)
+			break;
+		walls.push_back(tp);
+	}
+	list<Vec2i> paths;
+
+	as.set_map(mapWidth, mapHeight, walls);
+	as.findpath(beginX, beginY, endX, endY, paths);
+	wstring pathstr;
+	wchar_t buf[20];
+	for (auto it = paths.rbegin(); it != paths.rend(); ++it)
+	{
+		auto v = *it;
+		wsprintf(buf, L"%d,%d", v.x, v.y);
+		pathstr += buf;
+		pathstr.push_back(L'|');
+	}
+	if (!pathstr.empty())
+		pathstr.pop_back();
+}
+
+void libgm::FindNearestPos(const wchar_t* all_pos, long type, long x, long y, std::wstring& ret)
+{
+	const wchar_t* p = 0;
+	wchar_t buf[256] = { 0 };
+	wchar_t rs[256] = { 0 };
+	double old = 1e9;
+	long rx = -1, ry = -1;
+	std::wstring s = std::regex_replace(all_pos, std::wregex(L","), L" ");
+	p = s.data();
+	while (*p)
+	{
+		long x2, y2;
+		bool ok = false;
+		if (type == 1)
+		{
+
+			if (swscanf(p, L"%d %d", &x2, &y2) == 2)
+			{
+				ok = true;
+			}
+		}
+		else
+		{
+			if (swscanf(p, L"%s %d %d", buf, &x2, &y2) == 3)
+			{
+				ok = true;
+			}
+		}
+		if (ok)
+		{
+			double compareDis = (x - x2) * (x - x2) + (y - y2) * (y - y2);
+			if (compareDis < old)
+			{
+				rx = x2;
+				ry = y2;
+				old = compareDis;
+				wcscpy(rs, buf);
+			}
+		}
+		while (*p && *p != L'|')
+			++p;
+		if (*p)
+			++p;
+	}
+	if (rs[0])
+	{
+		wcscpy(buf, rs);
+		wsprintf(rs, L"%s,%d,%d", buf, rx, ry);
+	}
+	else if (type == 1 && rx != -1)
+	{
+		wsprintf(rs, L"%d,%d", rx, ry);
+	}
+	ret = rs;
+}
+
+void libgm::EnumWindow(long parent, const wchar_t* title, const wchar_t* class_name, long filter, std::wstring& retstr)
+{
+	// TODO: 在此添加实现代码
+	std::unique_ptr<wchar_t> retstring(new wchar_t[MAX_PATH * 200]);
+	memset(retstring.get(), 0, sizeof(wchar_t) * MAX_PATH * 200);
+	_winapi->EnumWindow((HWND)parent, title, class_name, filter, retstring.get());
+	//*retstr=_bstr_t(retstring);
+	retstr = retstring.get();
+}
+
+void libgm::EnumWindowByProcess(const wchar_t* process_name, const wchar_t* title, const wchar_t* class_name, long filter, std::wstring& retstring)
+{
+	// TODO: 在此添加实现代码
+	std::unique_ptr<wchar_t> retstr(new wchar_t[MAX_PATH * 200]);
+	memset(retstr.get(), 0, sizeof(wchar_t) * MAX_PATH * 200);
+	_winapi->EnumWindow((HWND)0, title, class_name, filter, retstr.get(), process_name);
+	//*retstring=_bstr_t(retstr);
+
+	retstring = retstr.get();
+}
+
+void libgm::EnumProcess(const wchar_t* name, std::wstring& retstring)
+{
+	// TODO: 在此添加实现代码
+	std::unique_ptr<wchar_t> retstr(new wchar_t[MAX_PATH * 200]);
+	memset(retstr.get(), 0, sizeof(wchar_t) * MAX_PATH * 200);
+	_winapi->EnumProcess(name, retstr.get());
+	//*retstring=_bstr_t(retstr);
+	retstring = retstr.get();
+}
+
+void libgm::ClientToScreen(long ClientToScreen, long* x, long* y, long* bret)
+{
+	// TODO: 在此添加实现代码
+
+	*bret = _winapi->ClientToScreen(ClientToScreen, *x, *y);
+}
+
+void libgm::FindWindow(const wchar_t* class_name, const wchar_t* title, long* rethwnd)
+{
+	// TODO: 在此添加实现代码
+	*rethwnd = _winapi->FindWindow(class_name, title);
+}
+
+void libgm::FindWindowByProcess(const wchar_t* process_name, const wchar_t* class_name, const wchar_t* title, long* rethwnd)
+{
+	// TODO: 在此添加实现代码
+	_winapi->FindWindowByProcess(class_name, title, *rethwnd, process_name);
+}
+
+void libgm::FindWindowByProcessId(long process_id, const wchar_t* class_name, const wchar_t* title, long* rethwnd)
+{
+	// TODO: 在此添加实现代码
+	_winapi->FindWindowByProcess(class_name, title, *rethwnd, NULL, process_id);
+}
+
+void libgm::FindWindowEx(long parent, const wchar_t* class_name, const wchar_t* title, long* rethwnd)
+{
+	// TODO: 在此添加实现代码
+	*rethwnd = _winapi->FindWindowEx(parent, class_name, title);
+}
+
+void libgm::GetClientRect(long hwnd, long* x1, long* y1, long* x2, long* y2, long* nret)
+{
+	// TODO: 在此添加实现代码
+
+	*nret = _winapi->GetClientRect(hwnd, *x1, *y1, *x2, *y2);
+}
+
+void libgm::GetClientSize(long hwnd, long* width, long* height, long* nret)
+{
+	// TODO: 在此添加实现代码
+
+	*nret = _winapi->GetClientSize(hwnd, *width, *height);
+}
+
+void libgm::GetForegroundFocus(long* rethwnd)
+{
+	// TODO: 在此添加实现代码
+	*rethwnd = (LONG)::GetFocus();
+}
+
+void libgm::GetForegroundWindow(long* rethwnd)
+{
+	// TODO: 在此添加实现代码
+	*rethwnd = (LONG)::GetForegroundWindow();
+}
+
+void libgm::GetMousePointWindow(long* rethwnd)
+{
+	// TODO: 在此添加实现代码
+	//::Sleep(2000);
+	_winapi->GetMousePointWindow(*rethwnd);
+}
+
+void libgm::GetPointWindow(long x, long y, long* rethwnd)
+{
+	// TODO: 在此添加实现代码
+	_winapi->GetMousePointWindow(*rethwnd, x, y);
+}
+
+void libgm::GetProcessInfo(long pid, std::wstring& retstring)
+{
+	// TODO: 在此添加实现代码
+
+	wchar_t retstr[MAX_PATH] = { 0 };
+	_winapi->GetProcessInfo(pid, retstr);
+	//* retstring=_bstr_t(retstr);
+
+	retstring = retstr;
+}
+
+void libgm::GetSpecialWindow(long flag, long* rethwnd)
+{
+	// TODO: 在此添加实现代码
+	*rethwnd = 0;
+	if (flag == 0)
+		*rethwnd = (LONG)GetDesktopWindow();
+	else if (flag == 1)
+	{
+		*rethwnd = (LONG)::FindWindowW(L"Shell_TrayWnd", NULL);
+	}
+}
+
+void libgm::GetWindow(long hwnd, long flag, long* nret)
+{
+	// TODO: 在此添加实现代码
+	_winapi->GetWindow(hwnd, flag, *nret);
+}
+
+void libgm::GetWindowClass(long hwnd, std::wstring& retstring)
+{
+	// TODO: 在此添加实现代码
+	wchar_t classname[MAX_PATH] = { 0 };
+	::GetClassName((HWND)hwnd, classname, MAX_PATH);
+	//* retstring=_bstr_t(classname);
+
+	retstring = classname;
+}
+
+void libgm::GetWindowProcessId(long hwnd, long* nretpid)
+{
+	// TODO: 在此添加实现代码
+	DWORD pid = 0;
+	::GetWindowThreadProcessId((HWND)hwnd, &pid);
+	*nretpid = pid;
+}
+
+void libgm::GetWindowProcessPath(long hwnd, std::wstring& retstring)
+{
+	// TODO: 在此添加实现代码
+	DWORD pid = 0;
+	::GetWindowThreadProcessId((HWND)hwnd, &pid);
+	wchar_t process_path[MAX_PATH] = { 0 };
+	_winapi->GetProcesspath(pid, process_path);
+	//* retstring=_bstr_t(process_path);
+
+	retstring = process_path;
+}
+
+void libgm::GetWindowRect(long hwnd, long* x1, long* y1, long* x2, long* y2, long* nret)
+{
+	// TODO: 在此添加实现代码
+	RECT winrect;
+	*nret = ::GetWindowRect((HWND)hwnd, &winrect);
+	*x1 = winrect.left;
+	*y1 = winrect.top;
+	*x2 = winrect.right;
+	*y2 = winrect.bottom;
+}
+
+void libgm::GetWindowState(long hwnd, long flag, long* rethwnd)
+{
+	// TODO: 在此添加实现代码
+	*rethwnd = _winapi->GetWindowState(hwnd, flag);
+}
+
+void libgm::GetWindowTitle(long hwnd, std::wstring& rettitle)
+{
+	// TODO: 在此添加实现代码
+	wchar_t title[MAX_PATH] = { 0 };
+	::GetWindowTextW((HWND)hwnd, title, MAX_PATH);
+	//* rettitle=_bstr_t(title);
+
+	rettitle = title;
+}
+
+void libgm::MoveWindow(long hwnd, long x, long y, long* nret)
+{
+	// TODO: 在此添加实现代码
+	RECT winrect;
+	::GetWindowRect((HWND)hwnd, &winrect);
+	int width = winrect.right - winrect.left;
+	int hight = winrect.bottom - winrect.top;
+	*nret = ::MoveWindow((HWND)hwnd, x, y, width, hight, false);
+}
+
+void libgm::ScreenToClient(long hwnd, long* x, long* y, long* nret)
+{
+	// TODO: 在此添加实现代码
+
+	POINT point;
+	*nret = ::ScreenToClient((HWND)hwnd, &point);
+	*x = point.x;
+	*y = point.y;
+}
+
+void libgm::SendPaste(long hwnd, long* nret)
+{
+	// TODO: 在此添加实现代码
+	*nret = _winapi->SendPaste(hwnd);
+}
+
+void libgm::SetClientSize(long hwnd, long width, long hight, long* nret)
+{
+	// TODO: 在此添加实现代码
+	*nret = _winapi->SetWindowSize(hwnd, width, hight);
+}
+
+void libgm::SetWindowState(long hwnd, long flag, long* nret)
+{
+	// TODO: 在此添加实现代码
+	*nret = _winapi->SetWindowState(hwnd, flag);
+}
+
+void libgm::SetWindowSize(long hwnd, long width, long height, long* nret)
+{
+	// TODO: 在此添加实现代码
+	*nret = _winapi->SetWindowSize(hwnd, width, height, 1);
+}
+
+void libgm::SetWindowText(long hwnd, const wchar_t* title, long* nret)
+{
+	// TODO: 在此添加实现代码
+	//*nret=gWindowObj.TSSetWindowState(hwnd,flag);
+	*nret = ::SetWindowTextW((HWND)hwnd, title);
+}
+
+void libgm::SetWindowTransparent(long hwnd, long trans, long* nret)
+{
+	// TODO: 在此添加实现代码
+	*nret = _winapi->SetWindowTransparent(hwnd, trans);
+}
+
+void libgm::SendString(long hwnd, const wchar_t* str, long* ret)
+{
+	*ret = _winapi->SendString((HWND)hwnd, str);
+}
+
+void libgm::SendStringIme(long hwnd, const wchar_t* str, long* ret)
+{
+	*ret = _winapi->SendStringIme((HWND)hwnd, str);
+}
+
+void libgm::RunApp(const wchar_t* cmdline, long mode, long* ret)
+{
+	*ret = _winapi->RunApp(cmdline, mode);
+}
+
+void libgm::WinExec(const wchar_t* cmdline, long cmdshow, long* ret)
+{
+	auto str = _ws2string(cmdline);
+	*ret = ::WinExec(str.c_str(), cmdshow) > 31 ? 1 : 0;
+}
+
+void libgm::GetCmdStr(const wchar_t* cmd, long millseconds, std::wstring& retstr)
+{
+	auto strcmd = _ws2string(cmd);
+	Cmder cd;
+	auto str = cd.GetCmdStr(strcmd, millseconds <= 0 ? 5 : millseconds);
+	retstr = _s2wstring(str);
+}
+
+void libgm::BindWindow(long hwnd, const wchar_t* display, const wchar_t* mouse, const wchar_t* keypad, long mode, long* ret)
+{
+	if (_bkproc->IsBind())
+		_bkproc->UnBindWindow();
+	*ret = _bkproc->BindWindow(hwnd, display, mouse, keypad, mode);
+	if (*ret == 1)
+	{
+		//_image_proc->set_offset(_bkproc->_pbkdisplay->_client_x, _bkproc->_pbkdisplay->_client_y);
+	}
+}
+
+void libgm::UnBindWindow(long* ret)
+{
+	*ret = _bkproc->UnBindWindow();
+}
+
+void libgm::GetCursorPos(long* x, long* y, long* ret)
+{
+
+	*ret = _bkproc->_bkmouse->GetCursorPos(*x, *y);
+}
+
+void libgm::MoveR(long x, long y, long* ret)
+{
+	*ret = _bkproc->_bkmouse->MoveR(x, y);
+}
+//把鼠标移动到目的点(x,y)
+void libgm::MoveTo(long x, long y, long* ret)
+{
+	*ret = _bkproc->_bkmouse->MoveTo(x, y);
+}
+
+void libgm::MoveToEx(long x, long y, long w, long h, long* ret)
+{
+	*ret = _bkproc->_bkmouse->MoveToEx(x, y, w, h);
+}
+
+void libgm::LeftClick(long* ret)
+{
+	*ret = _bkproc->_bkmouse->LeftClick();
+}
+
+void libgm::LeftDoubleClick(long* ret)
+{
+	*ret = _bkproc->_bkmouse->LeftDoubleClick();
+}
+
+void libgm::LeftDown(long* ret)
+{
+	*ret = _bkproc->_bkmouse->LeftDown();
+}
+
+void libgm::LeftUp(long* ret)
+{
+	*ret = _bkproc->_bkmouse->LeftUp();
+}
+
+void libgm::MiddleClick(long* ret)
+{
+	*ret = _bkproc->_bkmouse->MiddleClick();
+}
+
+void libgm::MiddleDown(long* ret)
+{
+	*ret = _bkproc->_bkmouse->MiddleDown();
+}
+
+void libgm::MiddleUp(long* ret)
+{
+	*ret = _bkproc->_bkmouse->MiddleUp();
+}
+
+void libgm::RightClick(long* ret)
+{
+	*ret = _bkproc->_bkmouse->RightClick();
+}
+
+void libgm::RightDown(long* ret)
+{
+	*ret = _bkproc->_bkmouse->RightDown();
+}
+
+void libgm::RightUp(long* ret)
+{
+	*ret = _bkproc->_bkmouse->RightUp();
+}
+
+void libgm::WheelDown(long* ret)
+{
+	*ret = _bkproc->_bkmouse->WheelDown();
+}
+
+void libgm::WheelUp(long* ret)
+{
+	*ret = _bkproc->_bkmouse->WheelUp();
+}
+
+void libgm::GetKeyState(long vk_code, long* ret)
+{
+	*ret = _bkproc->_keypad->GetKeyState(vk_code);
+}
+
+void libgm::KeyDown(long vk_code, long* ret)
+{
+	*ret = _bkproc->_keypad->KeyDown(vk_code);
+}
+
+void libgm::KeyDownChar(const wchar_t* vk_code, long* ret)
+{
+	auto nlen = wcslen(vk_code);
+	*ret = 0;
+	if (nlen > 0)
+	{
+		wstring s = vk_code;
+		wstring2lower(s);
+		long vk = _vkmap.count(s) ? _vkmap[s] : vk_code[0];
+		*ret = _bkproc->_keypad->KeyDown(vk);
+	}
+}
+
+void libgm::KeyUp(long vk_code, long* ret)
+{
+	*ret = _bkproc->_keypad->KeyUp(vk_code);
+}
+
+void libgm::KeyUpChar(const wchar_t* vk_code, long* ret)
+{
+	auto nlen = wcslen(vk_code);
+	*ret = 0;
+	if (nlen > 0)
+	{
+		wstring s = vk_code;
+		wstring2lower(s);
+		long vk = _vkmap.count(s) ? _vkmap[s] : vk_code[0];
+		*ret = _bkproc->_keypad->KeyUp(vk);
+	}
+}
+
+void libgm::WaitKey(long vk_code, long time_out, long* ret)
+{
+	if (time_out < 0)
+		time_out = 0;
+	*ret = _bkproc->_keypad->WaitKey(vk_code, time_out);
+}
+
+void libgm::KeyPress(long vk_code, long* ret)
+{
+
+	*ret = _bkproc->_keypad->KeyPress(vk_code);
+}
+
+void libgm::KeyPressChar(const wchar_t* vk_code, long* ret)
+{
+	auto nlen = wcslen(vk_code);
+	*ret = 0;
+	if (nlen > 0)
+	{
+		//setlog(vk_code);
+		wstring s = vk_code;
+		wstring2lower(s);
+		long vk = _vkmap.count(s) ? _vkmap[s] : vk_code[0];
+		*ret = _bkproc->_keypad->KeyPress(vk);
+	}
+}
+
+//抓取指定区域(x1, y1, x2, y2)的图像, 保存为file
+void libgm::Capture(long x1, long y1, long x2, long y2, const wchar_t* file_name, long* ret)
+{
+
+	*ret = 0;
+
+	if (_bkproc->check_bind() && _bkproc->RectConvert(x1, y1, x2, y2))
+	{
+		if (!_bkproc->requestCapture(x1, y1, x2 - x1, y2 - y1, _image_proc->_src))
+		{
+			setlog("error requestCapture");
+		}
+		else
+		{
+			_image_proc->set_offset(x1, y1);
+
+			*ret = _image_proc->Capture(file_name);
+		}
+	}
+}
+
+//比较指定坐标点(x,y)的颜色
+void libgm::CmpColor(long x, long y, const wchar_t* color, DOUBLE sim, long* ret)
+{
+	//LONG rx = -1, ry = -1;
+	long tx = x + small_block_size, ty = y + small_block_size;
+	*ret = 0;
+	if (_bkproc->check_bind() && _bkproc->RectConvert(x, y, tx, ty))
+	{
+		if (!_bkproc->requestCapture(x, y, small_block_size, small_block_size, _image_proc->_src))
+		{
+			setlog("error requestCapture");
+		}
+		else
+		{
+			_image_proc->set_offset(x, y);
+			*ret = _image_proc->CmpColor(x, y, color, sim);
+		}
+	}
+}
+
+//查找指定区域内的颜色
+void libgm::FindColor(long x1, long y1, long x2, long y2, const wchar_t* color, DOUBLE sim, long dir, long* x, long* y, long* ret)
+{
+
+	*ret = 0;
+	*x = *y = -1;
+
+	if (_bkproc->check_bind() && _bkproc->RectConvert(x1, y1, x2, y2))
+	{
+		if (!_bkproc->requestCapture(x1, y1, x2 - x1, y2 - y1, _image_proc->_src))
+		{
+			setlog("error requestCapture");
+		}
+		else
+		{
+			_image_proc->set_offset(x1, y1);
+			*ret = _image_proc->FindColor(color, sim, dir, *x, *y);
+		}
+	}
+}
+
+//查找指定区域内的所有颜色
+void libgm::FindColorEx(long x1, long y1, long x2, long y2, const wchar_t* color, DOUBLE sim, long dir, std::wstring& retstr)
+{
+	//wstring str;
+	retstr.clear();
+	if (_bkproc->check_bind() && _bkproc->RectConvert(x1, y1, x2, y2))
+	{
+		if (!_bkproc->requestCapture(x1, y1, x2 - x1, y2 - y1, _image_proc->_src))
+		{
+			setlog("error requestCapture");
+		}
+		else
+		{
+			_image_proc->set_offset(x1, y1);
+			_image_proc->FindColoEx(color, sim, dir, retstr);
+		}
+	}
+
+}
+
+//根据指定的多点查找颜色坐标
+void libgm::FindMultiColor(long x1, long y1, long x2, long y2, const wchar_t* first_color, const wchar_t* offset_color, DOUBLE sim, long dir, long* x, long* y, long* ret)
+{
+
+	*ret = 0;
+	*x = *y = -1;
+
+	if (_bkproc->check_bind() && _bkproc->RectConvert(x1, y1, x2, y2))
+	{
+		if (!_bkproc->requestCapture(x1, y1, x2 - x1, y2 - y1, _image_proc->_src))
+		{
+			setlog("error requestCapture");
+		}
+		else
+		{
+			_image_proc->set_offset(x1, y1);
+			*ret = _image_proc->FindMultiColor(first_color, offset_color, sim, dir, *x, *y);
+		}
+
+		/*if (*ret) {
+			rx += x1; ry += y1;
+			rx -= _bkproc->_pbkdisplay->_client_x;
+			ry -= _bkproc->_pbkdisplay->_client_y;
+		}*/
+	}
+}
+
+//根据指定的多点查找所有颜色坐标
+void libgm::FindMultiColorEx(long x1, long y1, long x2, long y2, const wchar_t* first_color, const wchar_t* offset_color, DOUBLE sim, long dir, std::wstring& retstr)
+{
+	retstr.clear();
+	if (_bkproc->check_bind() && _bkproc->RectConvert(x1, y1, x2, y2))
+	{
+		if (!_bkproc->requestCapture(x1, y1, x2 - x1, y2 - y1, _image_proc->_src))
+		{
+			setlog("error requestCapture");
+		}
+		else
+		{
+			_image_proc->set_offset(x1, y1);
+			_image_proc->FindMultiColorEx(first_color, offset_color, sim, dir, retstr);
+		}
+	}
+	//retstr = str;
+}
+
+//查找指定区域内的图片
+void libgm::FindPic(long x1, long y1, long x2, long y2, const wchar_t* files, const wchar_t* delta_color, DOUBLE sim, long dir, long* x, long* y, long* ret)
+{
+
+	*ret = 0;
+	*x = *y = -1;
+
+	if (_bkproc->check_bind() && _bkproc->RectConvert(x1, y1, x2, y2))
+	{
+		if (!_bkproc->requestCapture(x1, y1, x2 - x1, y2 - y1, _image_proc->_src))
+		{
+			setlog("error requestCapture");
+		}
+		else
+		{
+			_image_proc->set_offset(x1, y1);
+			*ret = _image_proc->FindPic(files, delta_color, sim, 0, *x, *y);
+		}
+
+		/*if (*ret) {
+			rx += x1; ry += y1;
+			rx -= _bkproc->_pbkdisplay->_client_x;
+			ry -= _bkproc->_pbkdisplay->_client_y;
+		}*/
+	}
+}
+
+//查找多个图片
+void libgm::FindPicEx(long x1, long y1, long x2, long y2, const wchar_t* files, const wchar_t* delta_color, DOUBLE sim, long dir, std::wstring& retstr)
+{
+
+	//wstring str;
+	if (_bkproc->check_bind() && _bkproc->RectConvert(x1, y1, x2, y2))
+	{
+		if (!_bkproc->requestCapture(x1, y1, x2 - x1, y2 - y1, _image_proc->_src))
+		{
+			setlog("error requestCapture");
+		}
+		else
+		{
+			_image_proc->set_offset(x1, y1);
+			_image_proc->FindPicEx(files, delta_color, sim, dir, retstr);
+		}
+	}
+	//retstr = str;
+}
+
+void libgm::FindPicExS(long x1, long y1, long x2, long y2, const wchar_t* files, const wchar_t* delta_color, double sim, long dir, std::wstring& retstr)
+{
+	//wstring str;
+	if (_bkproc->check_bind() && _bkproc->RectConvert(x1, y1, x2, y2))
+	{
+		if (!_bkproc->requestCapture(x1, y1, x2 - x1, y2 - y1, _image_proc->_src))
+		{
+			setlog("error requestCapture");
+		}
+		else
+		{
+			_image_proc->set_offset(x1, y1);
+			_image_proc->FindPicEx(files, delta_color, sim, dir, retstr, false);
+		}
+	}
+	//retstr = str;
+}
+
+void libgm::FindColorBlock(long x1, long y1, long x2, long y2, const wchar_t* color, double sim, long count, long height, long width, long* x, long* y, long* ret)
+{
+	*ret = 0;
+	if (_bkproc->check_bind() && _bkproc->RectConvert(x1, y1, x2, y2))
+	{
+		if (!_bkproc->requestCapture(x1, y1, x2 - x1, y2 - y1, _image_proc->_src))
+		{
+			setlog("error requestCapture");
+		}
+		else
+		{
+			_image_proc->set_offset(x1, y1);
+			*ret = _image_proc->FindColorBlock(color, sim, count, height, width, *x, *y);
+		}
+	}
+}
+
+void libgm::FindColorBlockEx(long x1, long y1, long x2, long y2, const wchar_t* color, double sim, long count, long height, long width, std::wstring& retstr)
+{
+
+	if (_bkproc->check_bind() && _bkproc->RectConvert(x1, y1, x2, y2))
+	{
+		if (!_bkproc->requestCapture(x1, y1, x2 - x1, y2 - y1, _image_proc->_src))
+		{
+			setlog("error requestCapture");
+		}
+		else
+		{
+			_image_proc->set_offset(x1, y1);
+			_image_proc->FindColorBlockEx(color, sim, count, height, width, retstr);
+		}
+	}
+}
+
+//获取(x,y)的颜色
+void libgm::GetColor(long x, long y, std::wstring& ret)
+{
+	color_t cr;
+	auto tx = x + small_block_size, ty = y + small_block_size;
+	if (_bkproc->check_bind() && _bkproc->RectConvert(x, y, tx, ty))
+	{
+		if (_bkproc->requestCapture(x, y, small_block_size, small_block_size, _image_proc->_src))
+		{
+			_image_proc->set_offset(x, y);
+			cr = _image_proc->_src.at<color_t>(0, 0);
+		}
+		else
+		{
+			setlog("error requestCapture");
+		}
+	}
+	else
+	{
+		//setlog("")
+	}
+
+	ret = cr.towstr();
+}
+
+void libgm::SetDisplayInput(const wchar_t* mode, long* ret)
+{
+	*ret = _bkproc->set_display_method(mode);
+}
+
+void libgm::LoadPic(const wchar_t* file_name, long* ret)
+{
+	*ret = _image_proc->LoadPic(file_name);
+}
+
+void libgm::FreePic(const wchar_t* file_name, long* ret)
+{
+	*ret = _image_proc->FreePic(file_name);
+}
+
+void libgm::LoadMemPic(const wchar_t* file_name, void* data, long size, long* ret)
+{
+	*ret = _image_proc->LoadMemPic(file_name, data, size);
+}
+
+void libgm::GetScreenData(long x1, long y1, long x2, long y2, void** data, long* ret)
+{
+	*data = nullptr;
+	*ret = 0;
+	auto& img = _image_proc->_src;
+	if (_bkproc->check_bind() && _bkproc->RectConvert(x1, y1, x2, y2))
+	{
+		if (!_bkproc->requestCapture(x1, y1, x2 - x1, y2 - y1, _image_proc->_src))
+		{
+			setlog("error requestCapture");
+		}
+		else
+		{
+			_image_proc->set_offset(x1, y1);
+			_screenData.resize(img.size() * 4);
+			//memcpy(_screenData.data(), img.pdata, img.size()*4);
+			for (int i = 0; i < img.height; i++)
+			{
+				memcpy(_screenData.data() + i * img.width * 4, img.ptr<char>(img.height - 1 - i), img.width * 4);
+			}
+			*data = _screenData.data();
+			*ret = 1;
+		}
+	}
+}
+
+void libgm::GetScreenDataBmp(long x1, long y1, long x2, long y2, void** data, long* size, long* ret)
+{
+	*data = 0;
+	*ret = 0;
+	if (_bkproc->check_bind() && _bkproc->RectConvert(x1, y1, x2, y2))
+	{
+		if (!_bkproc->requestCapture(x1, y1, x2 - x1, y2 - y1, _image_proc->_src))
+		{
+			setlog("rerror requestCapture");
+		}
+		else
+		{
+			_image_proc->set_offset(x1, y1);
+			auto& img = _image_proc->_src;
+
+			BITMAPFILEHEADER bfh = { 0 }; //bmp file header
+			BITMAPINFOHEADER bih = { 0 }; //bmp info header
+			const int szBfh = sizeof(BITMAPFILEHEADER);
+			const int szBih = sizeof(BITMAPINFOHEADER);
+			bfh.bfOffBits = szBfh + szBih;
+			bfh.bfSize = bfh.bfOffBits + img.width * img.height * 4;
+			bfh.bfType = static_cast<WORD>(0x4d42);
+
+			bih.biBitCount = 32; //每个像素字节大小
+			bih.biCompression = BI_RGB;
+			//bih.biHeight = -img.height;//高度 反
+			bih.biHeight = img.height; //高度
+			bih.biPlanes = 1;
+			bih.biSize = sizeof(BITMAPINFOHEADER);
+			bih.biSizeImage = img.width * 4 * img.height; //图像数据大小
+			bih.biWidth = img.width;					  //宽度
+
+			_screenDataBmp.resize(bfh.bfSize);
+			/*	std::ofstream f;
+		f.open("xx.bmp",std::ios::binary);
+		if (f) {
+			f.write((char*)&bfh, sizeof(bfh));
+			f.write((char*)&bih, sizeof(bih));
+			f.write((char*)img.pdata, img.size() * 4);
+		}
+
+		f.close();*/
+			auto dst = _screenDataBmp.data();
+
+			memcpy(dst, &bfh, sizeof(bfh));
+			memcpy(dst + sizeof(bfh), &bih, sizeof(bih));
+			dst += sizeof(bfh) + sizeof(bih);
+			for (int i = 0; i < img.height; i++)
+			{
+				memcpy(dst + i * img.width * 4, img.ptr<char>(img.height - 1 - i), img.width * 4);
+			}
+			//memcpy(dst + sizeof(bfh)+sizeof(bih), img.pdata, img.size()*4);
+			*data = _screenDataBmp.data();
+			*size = bfh.bfSize;
+			*ret = 1;
+		}
+	}
+}
+
+void libgm::GetScreenFrameInfo(long* frame_id, long* time)
+{
+	FrameInfo info = {};
+	if (_bkproc->IsBind())
+	{
+		_bkproc->_pbkdisplay->getFrameInfo(info);
+	}
+	*frame_id = info.frameId;
+	*time = info.time;
+}
+
+void libgm::MatchPicName(const wchar_t* pic_name, std::wstring& retstr)
+{
+	retstr.clear();
+	std::wstring s(pic_name);
+	if (s.find(L'/') != s.npos || s.find(L'\\') != s.npos)
+	{
+		setlog("invalid pic_name");
+	}
+
+	s = std::regex_replace(s, std::wregex(L"(\\.|\\(|\\)|\\[|\\]|\\{|\\})"), L"\\$1");
+	/*s = std::regex_replace(s, std::wregex(L"\\("), L"\\(");
+	s = std::regex_replace(s, std::wregex(L"\\)"), L"\\)");
+	s = std::regex_replace(s, std::wregex(L"\\["), L"\\[");
+	s = std::regex_replace(s, std::wregex(L"\\]"), L"\\]");*/
+	s = std::regex_replace(s, std::wregex(L"\\*"), L".*?");
+	s = std::regex_replace(s, std::wregex(L"\\?"), L".?");
+
+	//setlog(s.data());
+	namespace fs = std::filesystem;
+	fs::path path(_curr_path);
+	if (fs::exists(path))
+	{
+		fs::directory_iterator iter(path);
+		std::wstring tmp;
+		std::wregex e(s);
+		for (auto& it : iter)
+		{
+			if (it.status().type() == fs::file_type::regular)
+			{
+				tmp = it.path().filename();
+				try
+				{
+					if (std::regex_match(tmp, e))
+					{
+						retstr += tmp;
+						retstr += L"|";
+					}
+				}
+				catch (...)
+				{
+					setlog("exception!");
+				}
+			}
+		}
+		if (!retstr.empty() && retstr.back() == L'|')
+			retstr.pop_back();
+	}
+}
+
+//设置字库文件
+void libgm::SetDict(long idx, const wchar_t* file_name, long* ret)
+{
+	*ret = _image_proc->SetDict(idx, file_name);
+}
+
+//设置内存字库文件
+void libgm::SetMemDict(long idx, const wchar_t* data, long size, long* ret)
+{
+	*ret = _image_proc->SetMemDict(idx, (void*)data, size);
+}
+
+//使用哪个字库文件进行识别
+void libgm::UseDict(long idx, long* ret)
+{
+	*ret = _image_proc->UseDict(idx);
+}
+
+//识别屏幕范围(x1,y1,x2,y2)内符合color_format的字符串,并且相似度为sim,sim取值范围(0.1-1.0),
+void libgm::Ocr(long x1, long y1, long x2, long y2, const wchar_t* color, DOUBLE sim, std::wstring& retstr)
+{
+	wstring str;
+	if (_bkproc->check_bind() && _bkproc->RectConvert(x1, y1, x2, y2))
+	{
+		if (!_bkproc->requestCapture(x1, y1, x2 - x1, y2 - y1, _image_proc->_src))
+		{
+			setlog("error requestCapture");
+		}
+		else
+		{
+			_image_proc->set_offset(x1, y1);
+			_image_proc->OCR(color, sim, str);
+		}
+	}
+	retstr = str;
+}
+
+//回识别到的字符串,以及每个字符的坐标.
+void libgm::OcrEx(long x1, long y1, long x2, long y2, const wchar_t* color, DOUBLE sim, std::wstring& retstr)
+{
+	wstring str;
+	if (_bkproc->check_bind() && _bkproc->RectConvert(x1, y1, x2, y2))
+	{
+		if (!_bkproc->requestCapture(x1, y1, x2 - x1, y2 - y1, _image_proc->_src))
+		{
+			setlog("error requestCapture");
+		}
+		else
+		{
+			_image_proc->set_offset(x1, y1);
+			_image_proc->OcrEx(color, sim, str);
+		}
+	}
+	retstr = str;
+}
+
+//在屏幕范围(x1,y1,x2,y2)内,查找string(可以是任意个字符串的组合),并返回符合color_format的坐标位置
+void libgm::FindStr(long x1, long y1, long x2, long y2, const wchar_t* strs, const wchar_t* color, DOUBLE sim, long* retx, long* rety, long* ret)
+{
+	wstring str;
+	*retx = *rety = -1;
+	if (_bkproc->check_bind() && _bkproc->RectConvert(x1, y1, x2, y2))
+	{
+		if (!_bkproc->requestCapture(x1, y1, x2 - x1, y2 - y1, _image_proc->_src))
+		{
+			setlog("error requestCapture");
+		}
+		else
+		{
+			_image_proc->set_offset(x1, y1);
+			*ret = _image_proc->FindStr(strs, color, sim, *retx, *rety);
+		}
+	}
+}
+
+//返回符合color_format的所有坐标位置
+void libgm::FindStrEx(long x1, long y1, long x2, long y2, const wchar_t* strs, const wchar_t* color, DOUBLE sim, std::wstring& retstr)
+{
+	wstring str;
+	if (_bkproc->check_bind() && _bkproc->RectConvert(x1, y1, x2, y2))
+	{
+		if (!_bkproc->requestCapture(x1, y1, x2 - x1, y2 - y1, _image_proc->_src))
+		{
+			setlog("error requestCapture");
+		}
+		else
+		{
+			_image_proc->set_offset(x1, y1);
+			_image_proc->FindStrEx(strs, color, sim, str);
+		}
+	}
+	retstr = str;
+}
+
+void libgm::OcrAuto(long x1, long y1, long x2, long y2, DOUBLE sim, std::wstring& retstr)
+{
+	wstring str;
+	if (_bkproc->check_bind() && _bkproc->RectConvert(x1, y1, x2, y2))
+	{
+		if (!_bkproc->requestCapture(x1, y1, x2 - x1, y2 - y1, _image_proc->_src))
+		{
+			setlog("error requestCapture");
+		}
+		else
+		{
+			_image_proc->set_offset(x1, y1);
+			_image_proc->OcrAuto(sim, str);
+		}
+	}
+	retstr = str;
+}
+
+//从文件中识别图片
+void libgm::OcrFromFile(const wchar_t* file_name, const wchar_t* color_format, DOUBLE sim, std::wstring& retstr)
+{
+	wstring str;
+	_image_proc->OcrFromFile(file_name, color_format, sim, str);
+	retstr = str;
+}
+
+//从文件中识别图片,无需指定颜色
+void libgm::OcrAutoFromFile(const wchar_t* file_name, DOUBLE sim, std::wstring& retstr)
+{
+	wstring str;
+	_image_proc->OcrAutoFromFile(file_name, sim, str);
+	retstr = str;
+}
+
+void libgm::FindLine(long x1, long y1, long x2, long y2, const wchar_t* color, double sim, wstring& retstr)
+{
+	if (_bkproc->check_bind() && _bkproc->RectConvert(x1, y1, x2, y2))
+	{
+		if (!_bkproc->requestCapture(x1, y1, x2 - x1, y2 - y1, _image_proc->_src))
+		{
+			setlog("error requestCapture");
+		}
+		else
+		{
+			_image_proc->set_offset(x1, y1);
+			_image_proc->FindLine(color, sim, retstr);
+		}
+	}
+}
+
+void libgm::WriteData(long hwnd, const wchar_t* address, const wchar_t* data, long size, long* ret)
+{
+	*ret = 0;
+	MemoryEx mem;
+	*ret = mem.WriteData((HWND)hwnd, address, data, size);
+}
+
+//读取数据
+void libgm::ReadData(long hwnd, const wchar_t* address, long size, std::wstring& retstr)
+{
+	MemoryEx mem;
+	retstr = mem.ReadData((HWND)hwnd, address, size);
+}

+ 293 - 0
gm/gm/gm.h

@@ -0,0 +1,293 @@
+#pragma once
+
+#include <string>
+#include<map>
+#include<vector>
+//forward declare
+class WinApi;
+class opBackground;
+class ImageProc;
+
+using bytearray = std::vector<unsigned char>;
+
+// 使用静态库;
+#ifdef U_STATIC_LIB
+	#define GM_API
+#else
+	#ifndef GM_API 
+		// 使用动态库;
+		#if defined(GM_EXPORTS)
+			#define GM_API __declspec(dllexport)
+		#else
+			#define GM_API __declspec(dllimport)
+		#endif
+	#endif
+#endif
+
+// libgm
+#undef FindWindow
+#undef FindWindowEx
+#undef SetWindowText
+
+class GM_API libgm
+{
+public:
+	libgm();
+	~libgm();
+	//复制构造
+	libgm(libgm const&) = delete;
+	libgm& operator=(libgm const rhs) = delete;
+
+private:
+	//一些共用变量
+	//1. Windows API
+	WinApi* _winapi;
+	// background module
+	opBackground* _bkproc;
+	//image process
+	ImageProc* _image_proc;
+	// work path
+	std::wstring _curr_path;
+
+	std::map<std::wstring, long> _vkmap;
+	bytearray _screenData;
+	bytearray _screenDataBmp;
+	std::wstring m_opPath;
+public:
+	//---------------基本设置/属性-------------------
+
+	//1.版本号Version
+	std::wstring Ver();
+	//设置目录
+	void SetPath(const wchar_t* path, long* ret);
+	//获取目录
+	void GetPath(std::wstring& ret);
+	//获取插件目录
+	void GetBasePath(std::wstring& ret);
+	//返回当前对象的ID值,这个值对于每个对象是唯一存在的。可以用来判定两个对象是否一致
+	void GetID(long* ret);
+	//
+	void GetLastError(long* ret);
+	//设置是否弹出错误信息,默认是打开 0:关闭,1:显示为信息框,2:保存到文件,3:输出到标准输出
+	void SetShowErrorMsg(long show_type, long* ret);
+
+	//sleep
+	void Sleep(long millseconds, long* ret);
+	//Process
+	//inject dll
+	void InjectDll(const wchar_t* process_name, const wchar_t* dll_name, long* ret);
+	//设置是否开启或者关闭插件内部的图片缓存机制
+	void EnablePicCache(long enable, long* ret);
+	//取上次操作的图色区域,保存为file(24位位图)
+	void CapturePre(const wchar_t* file_name, long* ret);
+	//---------------------algorithm-------------------------------
+	//A星算法
+	void AStarFindPath(long mapWidth, long mapHeight, const wchar_t* disable_points, long beginX, long beginY, long endX, long endY, std::wstring& ret);
+	//
+	void FindNearestPos(const wchar_t* all_pos, long type, long x, long y, std::wstring& ret);
+	//--------------------windows api------------------------------
+	//根据指定条件,枚举系统中符合条件的窗口
+	void EnumWindow(long parent, const wchar_t* title, const wchar_t* class_name, long filter, std::wstring& ret);
+	//根据指定进程以及其它条件,枚举系统中符合条件的窗口
+	void EnumWindowByProcess(const wchar_t* process_name, const wchar_t* title, const wchar_t* class_name, long filter, std::wstring& ret);
+	//根据指定进程名,枚举系统中符合条件的进程PID
+	void EnumProcess(const wchar_t* name, std::wstring& ret);
+	//把窗口坐标转换为屏幕坐标
+	void ClientToScreen(long ClientToScreen, long* x, long* y, long* bret);
+	//查找符合类名或者标题名的顶层可见窗口
+	void FindWindow(const wchar_t* class_name, const wchar_t* title, long* ret);
+	//根据指定的进程名字,来查找可见窗口
+	void FindWindowByProcess(const wchar_t* process_name, const wchar_t* class_name, const wchar_t* title, long* ret);
+	//根据指定的进程Id,来查找可见窗口
+	void FindWindowByProcessId(long process_id, const wchar_t* class_name, const wchar_t* title, long* ret);
+	//查找符合类名或者标题名的顶层可见窗口,如果指定了parent,则在parent的第一层子窗口中查找
+	void FindWindowEx(long parent, const wchar_t* class_name, const wchar_t* title, long* ret);
+	//获取窗口客户区域在屏幕上的位置
+	void GetClientRect(long hwnd, long* x1, long* y1, long* x2, long* y2, long* ret);
+	//获取窗口客户区域的宽度和高度
+	void GetClientSize(long hwnd, long* width, long* height, long* ret);
+	//获取顶层活动窗口中具有输入焦点的窗口句柄
+	void GetForegroundFocus(long* ret);
+	//获取顶层活动窗口,可以获取到按键自带插件无法获取到的句柄
+	void GetForegroundWindow(long* ret);
+	//获取鼠标指向的可见窗口句柄
+	void GetMousePointWindow(long* ret);
+	//获取给定坐标的可见窗口句柄
+	void GetPointWindow(long x, long y, long* ret);
+	//根据指定的pid获取进程详细信息
+	void GetProcessInfo(long pid, std::wstring& ret);
+	//获取特殊窗口
+	void GetSpecialWindow(long flag, long* ret);
+	//获取给定窗口相关的窗口句柄
+	void GetWindow(long hwnd, long flag, long* ret);
+	//获取窗口的类名
+	void GetWindowClass(long hwnd, std::wstring& ret);
+	//获取指定窗口所在的进程ID
+	void GetWindowProcessId(long hwnd, long* ret);
+	//获取指定窗口所在的进程的exe文件全路径
+	void GetWindowProcessPath(long hwnd, std::wstring& ret);
+	//获取窗口在屏幕上的位置
+	void GetWindowRect(long hwnd, long* x1, long* y1, long* x2, long* y2, long* ret);
+	//获取指定窗口的一些属性
+	void GetWindowState(long hwnd, long flag, long* ret);
+	//获取窗口的标题
+	void GetWindowTitle(long hwnd, std::wstring& rettitle);
+	//移动指定窗口到指定位置
+	void MoveWindow(long hwnd, long x, long y, long* ret);
+	//把屏幕坐标转换为窗口坐标
+	void ScreenToClient(long hwnd, long* x, long* y, long* ret);
+	//向指定窗口发送粘贴命令
+	void SendPaste(long hwnd, long* ret);
+	//设置窗口客户区域的宽度和高度
+	void SetClientSize(long hwnd, long width, long hight, long* ret);
+	//设置窗口的状态
+	void SetWindowState(long hwnd, long flag, long* ret);
+	//设置窗口的大小
+	void SetWindowSize(long hwnd, long width, long height, long* ret);
+	//设置窗口的标题
+	void SetWindowText(long hwnd, const wchar_t* title, long* ret);
+	//设置窗口的透明度
+	void SetWindowTransparent(long hwnd, long trans, long* ret);
+	//向指定窗口发送文本数据
+	void SendString(long hwnd, const wchar_t* str, long* ret);
+	//向指定窗口发送文本数据-输入法
+	void SendStringIme(long hwnd, const wchar_t* str, long* ret);
+	//运行可执行文件,可指定模式
+	void RunApp(const wchar_t* cmdline, long mode, long* ret);
+	//运行可执行文件,可指定显示模式
+	void WinExec(const wchar_t* cmdline, long cmdshow, long* ret);
+
+	//运行命令行并返回结果
+	void GetCmdStr(const wchar_t* cmd, long millseconds, std::wstring& retstr);
+
+	//--------------------Background -----------------------
+	//bind window and beign capture screen
+	void BindWindow(long hwnd, const wchar_t* display, const wchar_t* mouse, const wchar_t* keypad, long mode, long* ret);
+	//
+	void UnBindWindow(long* ret);
+	//--------------------mouse & keyboard------------------
+	//获取鼠标位置.
+	void GetCursorPos(long* x, long* y, long* ret);
+	//鼠标相对于上次的位置移动rx,ry.
+	void MoveR(long x, long y, long* ret);
+	//把鼠标移动到目的点(x,y)
+	void MoveTo(long x, long y, long* ret);
+	//把鼠标移动到目的范围内的任意一点
+	void MoveToEx(long x, long y, long w, long h, long* ret);
+	//按下鼠标左键
+	void LeftClick(long* ret);
+	//双击鼠标左键
+	void LeftDoubleClick(long* ret);
+	//按住鼠标左键
+	void LeftDown(long* ret);
+	//弹起鼠标左键
+	void LeftUp(long* ret);
+	//按下鼠标中键
+	void MiddleClick(long* ret);
+	//按住鼠标中键
+	void MiddleDown(long* ret);
+	//弹起鼠标中键
+	void MiddleUp(long* ret);
+	//按下鼠标右键
+	void RightClick(long* ret);
+	//按住鼠标右键
+	void RightDown(long* ret);
+	//弹起鼠标右键
+	void RightUp(long* ret);
+	//滚轮向下滚
+	void WheelDown(long* ret);
+	//滚轮向上滚
+	void WheelUp(long* ret);
+	//获取指定的按键状态.(前台信息,不是后台)
+	void GetKeyState(long vk_code, long* ret);
+	//按住指定的虚拟键码
+	void KeyDown(long vk_code, long* ret);
+	//按住指定的虚拟键码
+	void KeyDownChar(const wchar_t* vk_code, long* ret);
+	//弹起来虚拟键vk_code
+	void KeyUp(long vk_code, long* ret);
+	//弹起来虚拟键vk_code
+	void KeyUpChar(const wchar_t* vk_code, long* ret);
+	//等待指定的按键按下 (前台,不是后台)
+	void WaitKey(long vk_code, long time_out, long* ret);
+	//发送字符串
+	//long SendString(long HWND)
+	//弹起来虚拟键vk_code
+	void KeyPress(long vk_code, long* ret);
+	void KeyPressChar(const wchar_t* vk_code, long* ret);
+
+	//--------------------image and color-----------------------
+	//抓取指定区域(x1, y1, x2, y2)的图像, 保存为file
+	void Capture(long x1, long y1, long x2, long y2, const wchar_t* file_name, long* ret);
+	//比较指定坐标点(x,y)的颜色
+	void CmpColor(long x, long y, const wchar_t* color, double sim, long* ret);
+	//查找指定区域内的颜色
+	void FindColor(long x1, long y1, long x2, long y2, const wchar_t* color, double sim, long dir, long* x, long* y, long* ret);
+	//查找指定区域内的所有颜色
+	void FindColorEx(long x1, long y1, long x2, long y2, const wchar_t* color, double sim, long dir, std::wstring& retstr);
+	//根据指定的多点查找颜色坐标
+	void FindMultiColor(long x1, long y1, long x2, long y2, const wchar_t* first_color, const wchar_t* offset_color, double sim, long dir, long* x, long* y, long* ret);
+	//根据指定的多点查找所有颜色坐标
+	void FindMultiColorEx(long x1, long y1, long x2, long y2, const wchar_t* first_color, const wchar_t* offset_color, double sim, long dir, std::wstring& retstr);
+	//查找指定区域内的图片
+	void FindPic(long x1, long y1, long x2, long y2, const wchar_t* files, const wchar_t* delta_color, double sim, long dir, long* x, long* y, long* ret);
+	//查找多个图片
+	void FindPicEx(long x1, long y1, long x2, long y2, const wchar_t* files, const wchar_t* delta_color, double sim, long dir, std::wstring& retstr);
+	//
+	//这个函数可以查找多个图片, 并且返回所有找到的图像的坐标.此函数同FindPicEx.只是返回值不同.(file1,x,y|file2,x,y|...)
+	void FindPicExS(long x1, long y1, long x2, long y2, const wchar_t* files, const wchar_t* delta_color, double sim, long dir, std::wstring& retstr);
+	//查找指定区域内的颜色块,颜色格式"RRGGBB-DRDGDB",注意,和按键的颜色格式相反
+	void FindColorBlock(long x1, long y1, long x2, long y2, const wchar_t* color, double sim, long count, long height, long width, long* x, long* y, long* ret);
+	//查找指定区域内的所有颜色块, 颜色格式"RRGGBB-DRDGDB", 注意, 和按键的颜色格式相反
+	void FindColorBlockEx(long x1, long y1, long x2, long y2, const wchar_t* color, double sim, long count, long height, long width, std::wstring& retstr);
+	//获取(x,y)的颜色
+	void GetColor(long x, long y, std::wstring& ret);
+	//
+	//设置图像输入方式,默认窗口截图
+	void SetDisplayInput(const wchar_t* mode, long* ret);
+
+	void LoadPic(const wchar_t* file_name, long* ret);
+
+	void FreePic(const wchar_t* file_name, long* ret);
+	//从内存加载要查找的图片
+	void LoadMemPic(const wchar_t* file_name, void* data, long size, long* ret);
+	//
+	void GetScreenData(long x1, long y1, long x2, long y2, void** data, long* ret);
+	//
+	void GetScreenDataBmp(long x1, long y1, long x2, long y2, void** data, long* size, long* ret);
+	//
+	void GetScreenFrameInfo(long* frame_id, long* time);
+	//
+	void MatchPicName(const wchar_t* pic_name, std::wstring& retstr);
+	//----------------------ocr-------------------------
+	//设置字库文件
+	void SetDict(long idx, const wchar_t* file_name, long* ret);
+	//设置内存字库文件
+	void SetMemDict(long idx, const wchar_t* data, long size, long* ret);
+	//使用哪个字库文件进行识别
+	void UseDict(long idx, long* ret);
+	//识别屏幕范围(x1,y1,x2,y2)内符合color_format的字符串,并且相似度为sim,sim取值范围(0.1-1.0),
+	void Ocr(long x1, long y1, long x2, long y2, const wchar_t* color, double sim, std::wstring& ret_str);
+	//回识别到的字符串,以及每个字符的坐标.
+	void OcrEx(long x1, long y1, long x2, long y2, const wchar_t* color, double sim, std::wstring& ret_str);
+	//在屏幕范围(x1,y1,x2,y2)内,查找string(可以是任意个字符串的组合),并返回符合color_format的坐标位置
+	void FindStr(long x1, long y1, long x2, long y2, const wchar_t* strs, const wchar_t* color, double sim, long* retx, long* rety, long* ret);
+	//返回符合color_format的所有坐标位置
+	void FindStrEx(long x1, long y1, long x2, long y2, const wchar_t* strs, const wchar_t* color, double sim, std::wstring& retstr);
+	//识别屏幕范围(x1,y1,x2,y2)内的字符串,自动二值化,而无需指定颜色
+	void OcrAuto(long x1, long y1, long x2, long y2, double sim, std::wstring& ret_str);
+	//从文件中识别图片
+	void OcrFromFile(const wchar_t* file_name, const wchar_t* color_format, double sim, std::wstring& retstr);
+	//从文件中识别图片,无需指定颜色
+	void OcrAutoFromFile(const wchar_t* file_name, double sim, std::wstring& retstr);
+	//查找频幕中的直线
+	void FindLine(long x1, long y1, long x2, long y2, const wchar_t* color, double sim, std::wstring& retstr);
+
+	//向某进程写入数据
+	void WriteData(long hwnd, const wchar_t* address, const wchar_t* data, long size, long* ret);
+	//读取数据
+	void ReadData(long hwnd, const wchar_t* address, long size, std::wstring& retstr);
+};
+
+
+

+ 31 - 15
gm/gm/winapi/Injecter.cpp

@@ -37,45 +37,61 @@ BOOL Injecter::EnablePrivilege(BOOL enable)
 
 long Injecter::InjectDll(DWORD pid, LPCTSTR dllPath, long& error_code)
 {
-	auto jhandle = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
-	/**pid = processInfo.dwProcessId;
-	*process = processInfo.hProcess;*/
-	if (!jhandle) {
+	HANDLE hInjectProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
+	if (!hInjectProcess)
+	{
 		error_code = ::GetLastError();
 		return -1;
 	}
 	DWORD dllPathSize = ((DWORD)wcslen(dllPath) + 1) * sizeof(TCHAR);
 
 	// 申请内存用来存放DLL路径
-	void* remoteMemory = VirtualAllocEx(jhandle, NULL, dllPathSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
-	if (remoteMemory == NULL)
+	void* lpInjectData = VirtualAllocEx(hInjectProcess, NULL, dllPathSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+	if (lpInjectData == NULL)
 	{
-		//setlog(L"申请内存失败,错误代码:%u\n", GetLastError());
+		wprintf(L"申请内存失败,错误代码:%u\n", GetLastError());
 		error_code = ::GetLastError();
 		return -2;
 	}
 
 	// 写入DLL路径
-	if (!WriteProcessMemory(jhandle, remoteMemory, dllPath, dllPathSize, NULL))
+	if (!WriteProcessMemory(hInjectProcess, lpInjectData, dllPath, dllPathSize, NULL))
 	{
-		//setlog(L"写入内存失败,错误代码:%u\n", GetLastError());
+		wprintf(L"写入内存失败,错误代码:%u\n", GetLastError());
 		error_code = ::GetLastError();
+		// 释放内存,注意:MEM_RELEASE与MEM_DECOMMIT的区别;
+		VirtualFreeEx(hInjectProcess, lpInjectData, 0, MEM_RELEASE);
+		return -3;
+	}
+
+	HMODULE hk32 = GetModuleHandleW(L"kernel32.dll");
+	if (hk32 == NULL)
+	{
+		// 释放内存,注意:MEM_RELEASE与MEM_DECOMMIT的区别;
+		VirtualFreeEx(hInjectProcess, lpInjectData, 0, MEM_RELEASE);
 		return -3;
 	}
 
 	// 创建远线程调用LoadLibrary
-	auto lpfn = GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "LoadLibraryW");
-	if (!lpfn) {
+	LPVOID lpAddr = GetProcAddress(hk32, "LoadLibraryW");
+	if (!lpAddr) 
+	{
+		// 释放内存,注意:MEM_RELEASE与MEM_DECOMMIT的区别;
+		VirtualFreeEx(hInjectProcess, lpInjectData, 0, MEM_RELEASE);
 		error_code = ::GetLastError();
 		return -4;
 	}
-	HANDLE remoteThread = CreateRemoteThread(jhandle, NULL, 0, (LPTHREAD_START_ROUTINE)lpfn, remoteMemory, 0, NULL);
+
+	HANDLE remoteThread = CreateRemoteThread(hInjectProcess, NULL, 0, (LPTHREAD_START_ROUTINE)lpAddr, lpInjectData, 0, NULL);
 	if (remoteThread == NULL)
 	{
-		//setlog(L"创建远线程失败,错误代码:%u\n", GetLastError());
+		wprintf(L"创建远线程失败,错误代码:%ld\n", GetLastError());
 		error_code = ::GetLastError();
+		// 释放内存,注意:MEM_RELEASE与MEM_DECOMMIT的区别;
+		VirtualFreeEx(hInjectProcess, lpInjectData, 0, MEM_RELEASE);
 		return -5;
 	}
+
 	// 等待远线程结束
 	WaitForSingleObject(remoteThread, INFINITE);
 	// 取DLL在目标进程的句柄
@@ -87,8 +103,8 @@ long Injecter::InjectDll(DWORD pid, LPCTSTR dllPath, long& error_code)
 
 	// 释放
 	CloseHandle(remoteThread);
-	VirtualFreeEx(jhandle, remoteMemory, dllPathSize, MEM_DECOMMIT);
-	CloseHandle(jhandle);
+	VirtualFreeEx(hInjectProcess, lpInjectData, dllPathSize, MEM_DECOMMIT);
+	CloseHandle(hInjectProcess);
 	error_code = 0;
 	return 1;
 }

+ 6 - 1
gm/gm/winapi/Injecter.h

@@ -3,10 +3,15 @@
 
 class Injecter
 {
+	HANDLE m_hRemoteModule;
+	HANDLE m_hRemoteProcess;
 public:
 	Injecter();
 	~Injecter();
+	// 注入之前要提权;
 	static BOOL EnablePrivilege(BOOL enable);
-	// 
+	// 注入dll;
 	static long InjectDll(DWORD pid, LPCTSTR dllPath, long& error_code);
+	// 弹出注入的DLl;
+	static bool EjectDll();
 };

+ 236 - 0
gm/gm/注入dll.cpp

@@ -0,0 +1,236 @@
+// RemoteThread.cpp : 定义控制台应用程序的入口点。
+//
+
+#include "stdafx.h"
+
+
+// 提升进程特权,否则某些操作会失败
+BOOL EnablePrivilege(BOOL enable)
+{
+	// 得到令牌句柄
+	HANDLE hToken = NULL;
+	if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_READ, &hToken))
+		return FALSE;
+
+	// 得到特权值
+	LUID luid;
+	if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid))
+		return FALSE;
+
+	// 提升令牌句柄权限
+	TOKEN_PRIVILEGES tp = {};
+	tp.PrivilegeCount = 1;
+	tp.Privileges[0].Luid = luid;
+	tp.Privileges[0].Attributes = enable ? SE_PRIVILEGE_ENABLED : 0;
+	if (!AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL))
+		return FALSE;
+
+	// 关闭令牌句柄
+	CloseHandle(hToken);
+	
+	return TRUE;
+}
+
+// 注入DLL,返回模块句柄(64位程序只能返回低32位)
+HMODULE InjectDll(HANDLE process, LPCTSTR dllPath)
+{
+	DWORD dllPathSize = ((DWORD)_tcslen(dllPath) + 1) * sizeof(TCHAR);
+
+	// 申请内存用来存放DLL路径
+	void* remoteMemory = VirtualAllocEx(process, NULL, dllPathSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+	if (remoteMemory == NULL)
+	{
+		printf("申请内存失败,错误代码:%u\n", GetLastError());
+		return 0;
+	}
+
+	// 写入DLL路径
+	if (!WriteProcessMemory(process, remoteMemory, dllPath, dllPathSize, NULL))
+	{
+		printf("写入内存失败,错误代码:%u\n", GetLastError());
+		return 0;
+	}
+
+	// 创建远线程调用LoadLibrary
+	HANDLE remoteThread = CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)LoadLibrary, remoteMemory, 0, NULL);
+	if (remoteThread == NULL)
+	{
+		printf("创建远线程失败,错误代码:%u\n", GetLastError());
+		return NULL;
+	}
+	// 等待远线程结束
+	WaitForSingleObject(remoteThread, INFINITE);
+	// 取DLL在目标进程的句柄
+	DWORD remoteModule;
+	GetExitCodeThread(remoteThread, &remoteModule);
+
+	// 释放
+	CloseHandle(remoteThread);
+	VirtualFreeEx(process, remoteMemory, dllPathSize, MEM_DECOMMIT);
+
+	return (HMODULE)remoteModule;
+}
+
+// 程序运行时注入DLL,返回模块句柄(64位程序只能返回低32位)
+HMODULE InjectDll(LPTSTR commandLine, LPCTSTR dllPath, DWORD* pid, HANDLE* process)
+{
+	TCHAR* commandLineCopy = new TCHAR[32768]; // CreateProcess可能修改这个
+	_tcscpy_s(commandLineCopy, 32768, commandLine);
+	int cdSize = _tcsrchr(commandLine, _T('\\')) - commandLine + 1;
+	TCHAR* cd = new TCHAR[cdSize];
+	_tcsnccpy_s(cd, cdSize, commandLine, cdSize - 1);
+	// 创建进程并暂停
+	STARTUPINFO startInfo = {};
+	PROCESS_INFORMATION processInfo = {};
+	if (!CreateProcess(NULL, commandLineCopy, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, cd, &startInfo, &processInfo))
+	{
+		delete commandLineCopy;
+		delete cd;
+		return 0;
+	}
+	delete commandLineCopy;
+	delete cd;
+
+	*pid = processInfo.dwProcessId;
+	*process = processInfo.hProcess;
+
+	DWORD dllPathSize = ((DWORD)_tcslen(dllPath) + 1) * sizeof(TCHAR);
+
+	// 申请内存用来存放DLL路径
+	void* remoteMemory = VirtualAllocEx(processInfo.hProcess, NULL, dllPathSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+	if (remoteMemory == NULL)
+	{
+		printf("申请内存失败,错误代码:%u\n", GetLastError());
+		return 0;
+	}
+
+	// 写入DLL路径
+	if (!WriteProcessMemory(processInfo.hProcess, remoteMemory, dllPath, dllPathSize, NULL))
+	{
+		printf("写入内存失败,错误代码:%u\n", GetLastError());
+		return 0;
+	}
+
+	// 创建远线程调用LoadLibrary
+	HANDLE remoteThread = CreateRemoteThread(processInfo.hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)LoadLibrary, remoteMemory, 0, NULL);
+	if (remoteThread == NULL)
+	{
+		printf("创建远线程失败,错误代码:%u\n", GetLastError());
+		return NULL;
+	}
+	// 等待远线程结束
+	WaitForSingleObject(remoteThread, INFINITE);
+	// 取DLL在目标进程的句柄
+	DWORD remoteModule;
+	GetExitCodeThread(remoteThread, &remoteModule);
+
+	// 恢复线程
+	ResumeThread(processInfo.hThread);
+
+	// 释放
+	CloseHandle(remoteThread);
+	VirtualFreeEx(processInfo.hProcess, remoteMemory, dllPathSize, MEM_DECOMMIT);
+
+	return (HMODULE)remoteModule;
+}
+
+// 卸载DLL
+BOOL FreeRemoteDll(HANDLE process, HMODULE remoteModule)
+{
+	// 创建远线程调用FreeLibrary
+	HANDLE remoteThread = CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)FreeLibrary, (LPVOID)remoteModule, 0, NULL);
+	if (remoteThread == NULL)
+	{
+		printf("创建远线程失败,错误代码:%u\n", GetLastError());
+		return FALSE;
+	}
+	// 等待远线程结束
+	WaitForSingleObject(remoteThread, INFINITE);
+	// 取返回值
+	DWORD result;
+	GetExitCodeThread(remoteThread, &result);
+
+	// 释放
+	CloseHandle(remoteThread);
+	return result != 0;
+}
+
+#ifdef _WIN64
+#include <tlhelp32.h>
+HMODULE GetRemoteModuleHandle(DWORD pid, LPCTSTR moduleName)
+{
+	HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, pid);
+	MODULEENTRY32 moduleentry;
+	moduleentry.dwSize = sizeof(moduleentry);
+
+	BOOL hasNext = Module32First(snapshot, &moduleentry);
+	HMODULE handle = NULL;
+	do
+	{
+		if (_tcsicmp(moduleentry.szModule, moduleName) == 0)
+		{
+			handle = moduleentry.hModule;
+			break;
+		}
+		hasNext = Module32Next(snapshot, &moduleentry);
+	} while (hasNext);
+
+	CloseHandle(snapshot);
+	return handle;
+}
+#endif
+
+int _tmain(int argc, _TCHAR* argv[])
+{
+	// 提升权限
+	EnablePrivilege(TRUE);
+
+	// 打开进程
+	HWND hwnd = FindWindow(NULL, _T("任务管理器"));
+	DWORD pid;
+	GetWindowThreadProcessId(hwnd, &pid);
+	HANDLE process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
+	if (process == NULL)
+	{
+		printf("打开进程失败,错误代码:%u\n", GetLastError());
+		return 1;
+	}
+	
+	// 要将RemoteThreadDll.dll放在本程序当前目录下
+	TCHAR dllPath[MAX_PATH]; // 要用绝对路径
+	GetCurrentDirectory(_countof(dllPath), dllPath);
+	_tcscat_s(dllPath, _T("\\RemoteThreadDll.dll"));
+
+
+	// 注入DLL
+	HMODULE remoteModule = InjectDll(process, dllPath);
+	//HMODULE remoteModule = InjectDll(_T("C:\\Windows\\System32\\Taskmgr.exe"), dllPath, &pid, &process);
+	if (remoteModule == NULL)
+	{
+		CloseHandle(process);
+		return 2;
+	}
+#ifdef _WIN64
+	remoteModule = GetRemoteModuleHandle(pid, _T("RemoteThreadDll.dll"));
+	printf("模块句柄:0x%08X%08X\n", *((DWORD*)&remoteModule + 1), (DWORD)remoteModule);
+#else
+	printf("模块句柄:0x%08X\n", (DWORD)remoteModule);
+#endif
+
+	// 暂停
+	printf("按回车卸载DLL\n");
+	getchar();
+
+	// 卸载DLL
+	if (!FreeRemoteDll(process, remoteModule))
+	{
+		CloseHandle(process);
+		return 3;
+	}
+
+
+	// 关闭进程
+	CloseHandle(process);
+
+	return 0;
+}