|
发表于 2019-3-22 18:14:37
|
显示全部楼层
只下了D2D1Game1.rar,看了一下,动态库不是那么整地。动态库首先就是个库。它不是自动执行你的任务。是要你控制调用它函数。所以东西放到初始函数InitInstance()里是不合适地。那是MFC初始的地方,不是你初始的方法。没有函数库模块已加载就开始自动搞事地。这是其一。第二动态库内的函数,类和属主交互要输入输出,这好像都没懂。于是导致问题就绵绵无绝期。事情原来不是D2D1问题,而是方法问题。这个问题就不好整。我讲我的,你看听不听的进。这到处都是陷阱。最怕误人子弟。而且现在自以为是的,要用麻袋装。
动态链接库的编写一般要搞两个项目。1是动态库,2是调用程序。调用程序调用动态库指明模块有两个方法1.是传统的.def文件法,在里面编辑 2.是declspec法,它不仅能导出函数名,还能用作导出类class。
动态库的编写,你用的是MFC DLL,其实不管用什么,一条原则,不要用它的,那里面都应建自己的,它建的都不要理它。
调用程序的编写没下,我用控制台写,都能用。看1个都明白你想要干什么。去黑别人窗口。但是这不是一个简单的事。幸好遇上我,头脑发热,就开始整。一夜繁花看尽,凭想象弄了一个。有性情就自己套用吧,瞎猫有时也能逮住老鼠。不过人的精力有限,不是什么都会,廉颇老矣。
下面谈谈看你程序,重建解释参考:
一、建空MFC动态库,其中头文件内容:
// DemoMFCLibrary.h : DemoMFCLibrary DLL 的主头文件
//
#pragma once
#ifndef __AFXWIN_H__
#error "在包含此文件之前包含“stdafx.h”以生成 PCH 文件"
#endif
#include "resource.h" // 主符号
/************************************************/
//这部分是添加头文件和测试用的std
#include <d2d1.h>
#include <cmath>
#include <Tlhelp32.h>
#include <dwrite.h>
#include <mmsystem.h>
#pragma comment( lib,"Dwmapi.lib" )
#pragma comment(lib,"d2d1.lib")
#pragma comment(lib,"Dwrite.lib")
#pragma comment( lib,"winmm.lib" )
#include <wincodec.h>
#pragma comment(lib,"windowscodecs.lib")
#include <iostream>
using namespace std;
#define XDEBUG 1
/************************************************/
// CDemoMFCLibraryApp
// 有关此类实现的信息,请参阅 DemoMFCLibrary.cpp
//
class CDemoMFCLibraryApp : public CWinApp
{
public:
CDemoMFCLibraryApp();
// 重写
public:
virtual BOOL InitInstance();
DECLARE_MESSAGE_MAP()
};
/************************************************/
//这部分是第一种控制导入/导出
#ifdef IN_MFC_DLL
#define DLL_EXPORT __declspec(dllexport)
#else
#define DLL_EXPORT __declspec(dllimport)
#endif
/*************************************************/
//第2种.def中符号导出地,如同函数。
void ShowText(float fx, float fy, wstring s,int color);
void ShowBitmap(float fx, float fy);
反斜杠注释包围地是我添加的,其中XDEBUG 为0 不显示跟踪数据。1为显示。class CDemoMFCLibraryApp : public CWinApp
都是系统自动生成地,不管它。要注意的就是IN_MFC_DLL这个符号定义为导入导出做准备。在库.cpp函数中定义并放在包含文件前。
在调用程序中不要。当然也可以#undefine IN_MFC_DLL,不过没试,哪有那么多闲精神。
ShowText,ShowBitmap是两个调用程序要调用的函数,主要在这里声明,就是要在.def文件里要添加的符号。
我这里.def 文件为DemoMFCLibrary.def .里面内容如下,分号是注释行,是系统自动生成地,不要不分皂白地又添加进去,复制到这里是提醒从那里添加。
; 此处可以是显式导出
ShowText @1
ShowBitmap @2
2.库.cpp文件。
主要添加类和这个类的唯一实例CD2D1 d2d1app,作用就是把所有自己函数,数据放在一起。
因为有内存指针数据,还能在析构时自动释放。
/**********************************************************/
/*这部分是用户在动态库的动作,都放在一起,唯一的一个实例d2d1*/
/**********************************************************/
class CD2D1 {
ID2D1Factory *pFactory = NULL;
ID2D1HwndRenderTarget *pRenderTarget = NULL;
ID2D1SolidColorBrush *pRedBrush = NULL;
ID2D1SolidColorBrush *pYellowBrush = NULL;
HWND gamehwnd = (HWND)0x0;
HWND hWnd = NULL;
//
IDWriteFactory* pDWriteFactory = NULL;
ID2D1BitmapRenderTarget*pBitmapRenderTarget = NULL;
public:
CD2D1() {};
~CD2D1();
HRESULT Init(HWND hWnd);
HRESULT LoadD2d1Bitmap(wstring FileBitmapName);
void DWriteDrawText(float fx,float fy,wstring str, int color);
void D2d1DrawBitmap(float fx,float fy);
void renderText(float fx,float fy,wstring str, int color);
void renderBitmap(float fx, float fy);
};
CD2D1 d2d1app;
/*********************************************************/
成员具体做什么在后面讲。成员方法的描述较多,就不在这粘贴了。看代码吧,没人下,还是很孤独地。
就是人们常说地:自古XX很寂寞。人在高处不胜寒。
其次添加 4个任务需要的公共函数。注意是4个,两个是.def输出,两个是extern "C" DLL_EXPORT
这样输出的。这样输出的不需要在.def文件中描述。一样两个,再看不会就该打板子。
/********************************************************************************************/
/*动态库输出的公共函数 ,一样两个. */
/*输出有两种方式: */
/*1、用 __declspec(dllexport),__declspec(dllimport)交替直接输出,注意定义DLL_EXPORT自动转换 */
/*2、在动态库.def文件中定义 */
/********************************************************************************************/
//按第1种方式输出,动态库.h文件中不需要函数声明,调用程序需声明
extern "C" DLL_EXPORT void Initialize(HWND hWnd)
{
d2d1app.Init(hWnd);
if(XDEBUG) wcout << "d2d1 is ready!" << endl;
}
extern "C" DLL_EXPORT HRESULT LoadD2d1Image(wstring s) {
HRESULT hr=d2d1app.LoadD2d1Bitmap(s);
if (XDEBUG) wcout << "LoadD2d1Bitmap "<<s.c_str()<<" status=" <<hex<<hr<< endl;
return hr;
}
//按第2种方式输出.h文件需要有声明
void ShowText(float fx, float fy, wstring s,int color)
{
if (XDEBUG) wcout << "d2d1 draw str !" <<s.c_str()<< endl;
d2d1app.renderText(fx,fy, s,color);
}
void ShowBitmap(float fx, float fy)
{
if (XDEBUG) wcout << "d2d1 draw bitmap !" << endl;
d2d1app.renderBitmap(fx, fy);
}
直此就库就完毕了。
二、调用程序
编写动态库,一般就要写调用程序,并且放在一起。不会分开写。所以就没下你的,库的内容只那么多,主程序也不会多。猜。
我人太懒了,主观意识强,真懒的看。控制台不很长,都粘贴在这
#include "stdafx.h"
#include <iostream>
#include <unordered_map>
#include "resource.h"
using namespace std;
#include <afxwin.h>
#include"..\DemoMFCLibrary\DemoMFCLibrary.h"
#pragma comment(lib,"DemoMFCLibrary.lib")
extern "C" DLL_EXPORT void Initialize(HWND hWnd);
extern "C" DLL_EXPORT HRESULT LoadD2d1Image(wstring s);
#define XDEBUG 1
namespace xx_demo {
//本地测试部分
void Show();
//找进程的一类放在一起
namespace lookup
{
wstring defaultExestr = L"notepad.exe";
HWND search_for_one_window(wstring s);
struct ProcessWindowData
{
HWND hWnd;
unsigned long lProcessId;
};
BOOL CALLBACK EnumWindowCallback(HWND hWnd, LPARAM lParam);
HWND GetMainWindowHwnd(unsigned long lProcessId);
}
};
using namespace xx_demo;
using namespace xx_demo::lookup;
int main()
{
HWND hWnd = search_for_one_window(defaultExestr);
if (!hWnd)
{
cout << "没有找到指定程序的窗口,使用控制台窗口!" << endl;
hWnd = GetConsoleWindow();
}
//调用初始化
Initialize(hWnd);
unordered_map<string,wstring> img;
img["bird"] = L"bird.jpg";
img["female"] = L"female.jpg";
BOOL bSwapBitmap = FALSE;
Show();
//控制按键速度300ms以外
DWORD lastTick, thisTick;
DWORD checkLastTick,checkThisTick;
lastTick = GetTickCount();
checkLastTick = GetTickCount();
while (!GetAsyncKeyState(VK_ESCAPE)) {
SHORT key;
key = GetAsyncKeyState(VK_F1);
if (key&0x8000) {
thisTick = GetTickCount();
if(thisTick-lastTick>300){
Show();
lastTick = thisTick;
}
}
key = GetAsyncKeyState(VK_F2);
if (key & 0x8000) {
thisTick = GetTickCount();
if (thisTick - lastTick>1000) {
bSwapBitmap = !bSwapBitmap;
if (bSwapBitmap) LoadD2d1Image(img["bird"]);
else LoadD2d1Image(img["female"]);
lastTick = thisTick;
}
}
//15秒检查窗口是否关闭
checkThisTick = GetTickCount();
if (checkThisTick - checkLastTick > 15000)
{
checkLastTick = GetTickCount();
if (GetConsoleWindow() != hWnd) {
HWND hWndNew = search_for_one_window(defaultExestr);
if(!hWndNew)
{
cout << "所黑窗口已退出,再见!" << endl;
SleepEx(5, TRUE);
break;
}
}
}
}
return 0;
}
void xx_demo::Show() {
//在该窗口涂鸦
ShowBitmap(10, 10);
ShowText(0, 0, L"Hello! ",0);
ShowText(0, 50, L"I come here MFC-D2D1. ",1);
cout << "按1次F2切换位图,再按F1刷新" << endl;
cout << "按F1再黑一遍" << endl;
cout << "按ESC退出" << endl;
}
BOOL CALLBACK xx_demo::lookup::EnumWindowCallback(HWND hWnd, LPARAM lParam)
{
ProcessWindowData& wndData = *(ProcessWindowData*)lParam;
unsigned long lProcessId = 0;
GetWindowThreadProcessId(hWnd, &lProcessId);
TCHAR szClassName[MAX_PATH];
TCHAR szWindowName[MAX_PATH];
GetClassName(hWnd, szClassName, MAX_PATH);//获取窗口类名
//获取窗口名,好像不能取得正确结果
//GetWindowText(hWnd, szTitle, MAX_PATH);
SendMessage(hWnd, WM_GETTEXT, MAX_PATH, (LPARAM)szWindowName);
if ((wndData.lProcessId != lProcessId) || (GetWindow(hWnd, GW_OWNER) != (HWND)0) || !IsWindowVisible(hWnd))
{
if (XDEBUG) {
wcout << "hWnd=0x" << hex << hWnd << " id=" << dec << lProcessId << " ClassName=";
wcout << (TCHAR*)szClassName /*<< " WindowTitleName=" << (TCHAR*)szWindowName*/ << endl;
}
return 1;
}
wndData.hWnd = hWnd;
if (XDEBUG) {
wcout << "找到 hWnd=0x" << hex << hWnd << " id=" << dec << lProcessId << " ClassName=";
wcout << (TCHAR*)szClassName/* << " WindowTitleName=" << (TCHAR*)szWindowName */ << endl;
}
return 0;
}
HWND xx_demo::lookup::GetMainWindowHwnd(unsigned long lProcessId)
{
ProcessWindowData wndData;
wndData.hWnd = 0;
wndData.lProcessId = lProcessId;
EnumWindows(EnumWindowCallback, (LPARAM)&wndData);
return wndData.hWnd;
}
HWND xx_demo::lookup::search_for_one_window(wstring s)
{
//查找进程ID
PROCESSENTRY32 pe;
pe.dwSize = sizeof(PROCESSENTRY32);
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (!Process32First(hSnapshot, &pe)) return NULL;
do {
if (XDEBUG) wcout << (TCHAR*)pe.szExeFile << endl;
if (!Process32Next(hSnapshot, &pe)) return NULL;
} while (StrCmp(pe.szExeFile, defaultExestr.c_str()));
DWORD id = pe.th32ProcessID;
if (XDEBUG) cout << "id=" << dec << id << endl;
//查找窗口
return GetMainWindowHwnd(id);
}
域名xx_demo用来把闲散变量,函数整合到一起,域名xx_demo::lookup把找窗口的整在一起。
#include"..\DemoMFCLibrary\DemoMFCLibrary.h"
#pragma comment(lib,"DemoMFCLibrary.lib")
extern "C" DLL_EXPORT void Initialize(HWND hWnd);
extern "C" DLL_EXPORT HRESULT LoadD2d1Image(wstring s);
是动态库应用包含和两个非.def文件输出的库函数。它和那两个showXX是有点区别地。
三、任务说明
任务就是程序要做什么,程序第一在进程中找exe文件,找到后根据id找窗口。找到窗口,就黑它。
怎么黑,就是输出东西。先文字,再图片,变脸。
注意找窗口,取窗口文本好像不对,但是Spy++又找的到,这技巧还是从网上扒吧,我只列出窗口,类名和ID。
找到窗口,用什么写,用D2D1。怎么写,又成问题。一个句柄就会折腾那么久,遇到问题还会更多。
为杜绝这个问题。我把D2D1写文本DWrite写位图都给你做了,或多或少有些帮助。再应该没有问题了。有点怕,特别
是一长串代码后还是没解决,是绝望。画蛇添足。
四、运行
下载的代码是12版本,我是14版本,如果用先前版本打开不能编译,应该选项目右键属性->常规中平台工具集,把版本降下来就可以了。
打开解包所在目录中的ConMFCDemo.sln即可,一个解决方案下有两项目,1个是调用程序,1个是库,库不能单独运行。
运行流程:
1 打开记事本。不输内容就可以。主要黑它,学会了以后再黑别人。练习嘛。
2 查找窗口,没找到就黑自己本窗,不过点一下就刷新了。找到init执行库里面实例初始化,建相关联的D2D1环境,对象,位图渲染环境 等.
3 输出位图到窗口
4 输出文本到窗口
5 等待ESC按键退出,其中15秒检查该窗口是否关闭,本窗口忽略
每按F1就再画一次。点击记事本,就会消失,按一下就能再看到
按F2重新载入位图。要按F1才会显示,它只是后台更新完。不主动显示。
五、演示图
启动后图
按F2后再按F1图
Spy的窗口标题
六、代码
工程全代码,含源代码和执行代码。如果不能编译,内有已编译好的执行码。
编译环境window10 + vs2015
MFCDLLDemo.rar
(418.19 KB, 下载次数: 1)
|
|