CreateToolhelp32Snapshot
<TlHelp32.h>这个头文件,有CreateToolhelp32Snapshot这个api
这个api的第一个参数是个宏,有的可以查看的是所有进程,有的是查看该进程的所有模块。
HANDLE WINAPI CreateToolhelp32Snapshot( DWORD dwFlags, DWORD th32ProcessID );
第二个是Pid,如果填0就是所有的。
但注意 只是一瞬间的快照。
TH32CS_SNAPHEAPLIST |
Includes the heap list of the specified process in the snapshot. |
TH32CS_SNAPMODULE |
Includes the module list of the specified process in the snapshot. |
TH32CS_SNAPPROCESS |
Includes the process list in the snapshot. |
TH32CS_SNAPTHREAD |
Includes the thread list in the snapshot. |
然后这个api返回的是一个句柄。
HANDLE类型的,句柄类似指针,只有有句柄程序才能对这个进行操作。
PROCESSENTRY32等一众结构体
这个是配套着刚才CreateToolhelp32Snapshot来使用的。
还有Process32First和Process32Next,这个句柄指向一个链表。
上述两个api第一个参数就是哪个HANDLE,第二个参数就是结构体指针。
所以判断没了,那肯定就是什么时候这个结构体是null就没了。
这个结构体储存这找到的程序的一切。
typedef struct tagPROCESSENTRY32 {
DWORD dwSize;
DWORD cntUsage;
DWORD th32ProcessID;
ULONG_PTR th32DefaultHeapID;
DWORD th32ModuleID;
DWORD cntThreads;
DWORD th32ParentProcessID;
LONG pcPriClassBase;
DWORD dwFlags;
TCHAR szExeFile[MAX_PATH];
} PROCESSENTRY32;
typedef PROCESSENTRY32 *PPROCESSENTRY32;
类似这个api,还有THREADENTRY32...只不过是线程了。
继续类推,因为CreateToolhelp32Snapshot还有看模块的功能
所以还有MODULEENTRY32...
还有...其实,因为哪个宏还有TH32CS_SNAPHEAPLIST...所以还有对应的堆栈结构体?(回头都试试)
Process32First/Process32Next等一众api
把第一个哪个句柄放进去,对应的结构体放进去,这里之所以说是对应,因为还有Thread32First...等一众api
CloseHandle
这个是用来关闭句柄的,句柄用了不关闭,可能会造成内存泄露。
ExitProcess
用来关闭自己进程的,但是关闭的时候想好,有的东西被这个关闭可能不会被析构,毕竟
FindWindow和FindWindowEx
这两个是用来找找窗口的,连子窗口也可以找到
FindWindowEx是比FindWindow多了两个参数。
FindWindow第一个参数是窗口类的名字,第二个是窗口的名字。
FindWindowEx多出来的前俩个是两个HWND类型的,是用来判断查找范围的。
第一个参数是从哪个主窗口来查找,第二个则是从哪个子窗口开始查找。如果是0,都遍历一遍。
TermniateProcess
第一个就是进程句柄hProcess,第二个是退出码。
这个只要有进程句柄就可以关闭别的程序,0就是关闭自己.
OpenProcess
OpenProcess 函数用来打开一个已存在的进程对象,并返回进程的句柄
要注意他和CreateProcess的区别,这个是打开一个已经存在的进程,返回进程句柄。
而CreateProcess则是直接打开。
这个是返回进程句柄的,而CreateProcess则是返回个BOOL 下面在更详细地介绍CreateProcess
有了进程句柄,就可以干别的了。
OpenCreateProcess有三个参数
HANDLE OpenProcess( DWORD dwDesiredAccess, // access flag BOOL bInheritHandle, // handle inheritance option DWORD dwProcessId // process identifier);
第一个是一个宏了
可以用来确定打开进程的一些特权,比如PROCESS_ALL_ACCESSS,这个是最常用的
第二个是不是继承原来父窗口的句柄 TRUE或者FALSE 第三个就是PID,进程ID,是唯一标识程序的东西。注意他和进程句柄,各种句柄的区别!
OpenProcess
这个是用来打开进程的,
而且需要STARTUPINFO和PROCESS_INFOMATION这两个结构体
如果想要立刻显示打开的进程,需要改一些东西,比如si.wShowWindow=true...
BOOL CreateProcess(
LPCTSTR lpApplicationName, // name of executable module
LPTSTR lpCommandLine, // command line string
LPSECURITY_ATTRIBUTES lpProcessAttributes, // SD
LPSECURITY_ATTRIBUTES lpThreadAttributes, // SD
BOOL bInheritHandles, // handle inheritance option
DWORD dwCreationFlags, // creation flags
LPVOID lpEnvironment, // new environment block
LPCTSTR lpCurrentDirectory, // current directory name
LPSTARTUPINFO lpStartupInfo, // startup information
LPPROCESS_INFORMATION lpProcessInformation // process information );
注意最后两个参数! 最后一个PROCESS_INFOMATION存储着PID..进程ID。。句柄什么的
聪明如我,肯定还有OpenThread....
PROCESS_INFOMATION是一个输出的结构体,所以放进去是空的,出来就是满的了。
ReadProcessMemory与WirteProcessMemory
ReadProcessMemory非常好用,是进行读取内容必备的API,
他有这么多参数,
第一个就是进程句柄,第二个是读取的基质(从哪儿开始读),第三个是读到哪
第四个是读多少,如果想遍历整个进程,由4kb物理页+进程的低2GB空间即可
4096byte为一个物理页,存进去。
比较的时候就用for循环比较,而且是一个字节一个字节的比对目标数。
pdw = (DWORD*)&arBytes[i];比如这样pdw就是一个指向DWORD的变量了,假如DWORD是待查找数据的类型。
然后在进行比较就行。然后找到就是dwBaseAddress+i就是地址了。因为是一个字节一个字节地比较。
与之相比下,WriteProcessMemory使用起来就简单的多。
WirteProcessMemory函数原型
第一个还是进程句柄,然后第二个是要写的地址,第三个是从哪里写入,第四个是写多少
LPVOID就是个void*而已,终归是个类型,你甚至可以用DWORD和int来代表地址,最后强转就行!
CreateThread
这是一个创建线程的API,多个线程可以提高程序所占用的时间片,可以使计算机运行计算该程序的时间变长。
线程同步是一大问题
以后应该会学习。但是感觉也应该不要太用
线程要注意有个线程ID和线程处理函数
还有个WiatForSingleObject和WaitForMutipObject...的使用
InterLockIncerment
这个是原子锁,保护临界资源只能被一个线程访问而且必须访问完才能结束
ProcessProc
与其他窗口处理函数一样,线程处理函数也是有固定的格式的。
DWORD CALLBACK ProcessProc(LPVOID lParam);这个就是线程处理函数
WndProc和WinMain
WinMain在win32的地位就相当于是main函数console中的地位。
类似int main的固定格式
WinMain作为回调函数也有其格式
他的格式是
Int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE,LPSTR lpcmdline,int){
...
}
他是windows窗口第一个执行的程序。
而WndProc也是一个回调函数,是窗口过程。
他也遵循着固定的格式供操作系统调用。
他的格式是
LRESULT CALLBACK WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam){
Case-switch的一个巨大结构体
return DefWindowProc(...);//用来返回默认的窗口处理过程
}
要记住,每个窗口(广义的窗口)都对应着一个窗口处理函数。无论是对话框,子窗口,控件,都有。
有的系统已经封装好的类,同样也有,你知道了这些信息,发送,同样是合理的。
所有比如有的时候SendMessage给子窗口,让按钮,edit实现一些功能是正常的。
各种消息
WM_QUIT WM_CLOSE...我觉得查询msdn是好的,但是也要稍微记一下常见消息的内容.
WNDCLASS和RegisterClass
WNDCLASS是win32非常核心的一个结构体,也叫做窗口类,只有有了窗口类,并且注册了,即以及让操作系统仍到内核,才可以进行CreateWindow一系列操作。
WNDCLASS里面有着很多东西,比如决定着窗口处理函数。
设置完WNDCLASS所有的成员之后,再进行RegisterClass即可
CreateWindow和ShowWindow以及UpdateWindow
这三个是相辅相成的,CreateWindow后,进行ShowWindow(SW_SHOW)和UpdateWindow()来使窗口进入消息循环。
消息循环
核心是三个api+MSG结构体
MSG结构体用来存储消息的详细信息
Hwnd、LWparam message消息类型
代码实现就是while(GetMessage(&msg,NULL,0,0)){
//GetMessage后面三个参数是限制范围的,一般全填0即可。
然后TranslateMessage(&msg);//转译键盘消息的
DispatchMesaage(&msg);//分发 来调用回调函数
}
SetTimer
这是一个定时器消息
有四个参数
SetTimer(hWnd, IDT_TIMER, 100, NULL);
第一个参数就是给那个窗口设置这个定时器,第二个是ID,第三个是毫秒时间 第四个是如果想给这个玩意弄个定时器处理函数的话你就弄.
定时器发的消息是WM_TIMER。Wparam是定时器的ID
Win32的控件
一定要深刻理解,窗口就是控件->控件也是窗口->更是子窗口->每个窗口都有对应的窗口处理函数->系统封装好的也有.
Win32也可以实现可视化编程,但是需要基于Dialog对话框来实现。
如果不这样的话,那么只能进行创建了。用CreateWindow进行创建
窗口类填写系统已经搞好的类,还要填上对应的窗口类的风格以及对应窗口类(比如按钮 文本框的ID
这些所有的子窗口,或者说是控件。被进行操作的话会产生WM_COMMAND消息
低16就是哪个控件 高16位就是具体是进行了哪个操作.
被进行操作对每个类型的控件各不相同,对于按钮,可能就是下压,对于文本框,有可能是改变里面的内容。总之各不相同.
上面说到 win32也可以可视化编程,但是要是再对话框上添加。
而且可视化编程拖拽上去的控件也具备了更强的封装,比如原来CreateWindow创建的复选框,你点击他也不会选中,但是拖拽上去的就会。
虽然拖拽上去的控件有了更完善的封装,但是没办法直接获取控件的句柄了。
所以用GetDlgItem可以获取 还有SetDlgItemText....利用ID就可以进行操作了
同样的,消息还是那些,但是处理要放在对话框的窗口过程进行处理了。
如你所想,对话框的窗口处理函数也是回调函数,因此他要遵循一定的规则,但是基本和WndProc一样。
DialogBox和EndDialog
DialogBox就是进行打开模式对话框的一个API
第一个是实例句柄,第二个是ID(在Vs里面的),第三个是父窗口句柄,第四个是对话框处理函数。
这是一个阻塞函数,而非模式对话框就不是一个阻塞函数了.
对话框的窗口处理函数
和WndProc一样 但是返回类型不一样 WndProc返回是LRESULT 而这个返回的是BOOL
返回值决定是不是由默认的处理函数进行处理.一般返回假.
WM_INITDIALOG
对话框的初始化并不是WM_CREATE,而是这个玩意
HBITMAP、HICON
既然有句柄,说明已经扔到内存里面去供程序去使用了。所以位图什么的,也变成句柄,供程序去加载使用。
加载位图的的函数
HBITMAP hBitMap=LoadBitmap(hInstance,(LPCTSTR)用VS加载进来的ID);
注意,加载位图只可以是Static进行加载
如果是手动拖拽的文本框,那么它默认的属性是不能加载图片的。
所以要用GetWindowLong和SetWindowLong来进行操作。
GetWindowLong和SetWindowLong
这两个东西非常有用,第一参数是窗口句柄,第二个是宏。
第二个宏填不同的东西可以实现很多不同的功能。常见的就是给窗口加新风格
GetWindowLong 函数检索有关指定窗口的信息。 该函数还将指定偏移量处的 32 位(长)值检索到额外的窗口内存中。
LONG GetWindowLong( HWND hWnd, // 窗口句柄
int nIndex // 填特定的参数以获取改句柄的不同信息;
下面是第二个参数可以填的一些特定值
常用的就是GWL_STYLE,他会返回改窗体的风格,对于不知道风格来加风格非常有用。
例子:比如我想给一个static窗口类添加一个可以显示图片的风格,却又不想改变他原有的风格,这就十分必要需要GetWindowLong这个函数了
LONG nStyle = GetWindowLong(hWndBMP, GWL_STYLE);
GetWindowLong SetWindowLong很重要
GetWindowLOng 就是获取原有的窗口风格
然后不改变原有风格的条件下还能加载
SetWindowLong(hWndBMP, GWL_STYLE,nStyle|SS_BITMAP);
当然,这里用到了SetWindowLong,要和GetWindowLOng对应起来使用.
STM_SETIMAGE
这个是利用SendMessage专门发给static的消息,让他来加载图片的
Wparam写IMAGE_BITMAP就是加载位图,lParam填句柄!
SetWindowPos
SetWindowPos函数改变一个子窗口,弹出式窗口或顶层窗口的尺寸,位置和Z序。子窗口,弹出式窗口,及顶层窗口根据它们在屏幕上出现的顺序排序、顶层窗口设置的级别最高,并且被设置为Z序的第一个窗口。
常用的就是用它改置顶窗口
第一个参数就是hwnd,第二个参数可以填写以下宏
- HWND_BOTTOM:值为1,将窗口置于Z序的底部。如果参数hWnd标识了一个顶层窗口,则窗口失去*位置,并且被置在其他窗口的底部。
- HWND_NOTOPMOST:值为-2,将窗口置于所有非顶层窗口之上(即在所有顶层窗口之后)。如果窗口已经是非顶层窗口则该标志不起作用。
- HWND_TOP:值为0,将窗口置于Z序的顶部。
- HWND_TOPMOST:值为-1,将窗口置于所有非顶层窗口之上。即使窗口未被激活窗口也将保持*位置。
中间四个就是各种位置,边界。
最后一个是窗口的属性,比如不能移动。
SendDlgItemMessage一众API
SendMessage和GetDlgItem的结合,不必用中间量HWND来过度了
类似的还有
IsDlgButtonChecked(hDlg,ID)==GetDlgItem+SendMessage(hbutton,BM_GETCHECK,0,0),这个是用来检测是不是按钮被点击了,BST_CHECKED这是一个返回值,说明被点击了
BM_开头的一众消息
是ButtonMessage的缩写,是专门给按钮用的,
比如检测是不是被点击了,发送过去让其被点击
常见的BM_GETMESSAGE BM_SETMESSAGE 等等
LB_开头的一众消息
是专门类List列表框用的,
比如LB_ADDSTRING lParam是zero 而wParam就是加的字符串
简单MFC
所谓MFC,就是微软把一系列东西进行了一系列封装。
比如hInstance封装成了CWinApp这个类,我们使用的话要继承
再比如我们HWND他给封装成了CFrameWnd或者CWnd这个类
我们使用同样要继承。
但是,MFC省去了冗余的代码,而且利用面向对象的思想,以及消息映射机制
让我们不必使用代码量非常之大的switch-case结构了
并且,MFC还封装了按钮,编辑框,让他们变成类。
加上相应成员和成员函数,大大减少了代码量。
正常创建一个窗口非常的简单
首先,先继承WinApp那个类,
然后,覆写虚函数InitInstance
然后类似地,把CWinApp(hInstance)和CFrameWnd(HWND)关联起来
如何关联呢?
在覆写InitInstance函数的时候m_pmainWnd=new CHelloWnd();即可
然后m_pMainWnd->show.....一系列操作
这个时候调过了WNDCLASS 和注册窗口类
然后写以下CMyFrameWnd类的构造函数.
在这个构造函数里面要干什么呢?当然是创建窗口了!
直接用Create这个函数创建就行了,是MFC这个类里面的,第一个是类名,我们不填的话最后兜兜转转下MFC会自己给我们申请一个.
消息映射机制
MFC六大机制之一
可以减少大量的switch-case这种代码
一般是在继承的CFrameWnd哪个类里面先声明消息映射
DECLARE_MESSAGE_MAP()
然后BEGIN_MESSAGE_MAP()
这个是个带参宏,第一个参数是子类,第二个是父类.
中间填各种映射的消息
比如ON_WM_PAINT啦这种正常的消息
然后记得在添加了详细映射机制的程序
如果是命令消息,那就ON_COMMAND
最后END_MESSAGE_MAP()
先讲下Windows消息的分类。Windows消息分为系统消息和用户自定义消息。Windows系统消息有三种:
1.标准Windows消息。除WM_COMMAND外以WM_开头的消息是标准消息。例如,WM_CREATE、WM_CLOSE。
2.命令消息。消息名为WM_COMMAND,消息中附带了标识符ID来区分是来自哪个菜单、工具栏按钮或加速键的消息。
3.通知消息。通知消息一般由列表框等子窗口发送给父窗口,消息名也是WM_COMMAND,其中附带了控件通知码来区分控件。
CWnd的派生类都可以接收到标准Windows消息、通知消息和命令消息。命令消息还可以由文档类等接收。
最后,每个消息所对应的消息映射各不相同,需要查询msdn,比较在win32中,WM_消息l和wparam里面所代表的东西也不同啦.
MFC还有一个更方便的功能就是它基本上把所有的的HWND控件什么的都变成了自己的类。
这样利用面向对象的思想十分方便。
CreateToolhelp32Snapshot(TH32CS_SNAPMODULE)
这是用来进行模块快照的,进程并不是独立运行的,需要一大堆模块进行支持。
这个可以用来获取模块,和获取的进程快照是一模一样的!
静态库Lib
静态库Lib没有入口函数,所以直接在里面写函数就行
注意C和Cpp的导入静态库的区别!
Cpp支持重名函数,所以导出的时候名字可就不是那样了!
引入动态和静态链接库
#pragma comment(lib,”xxx.lib”)
这是引入静态链接库。
动态库的话,需要先进行加载。比较是外部的东西
一个进程想使用任何外部的东西肯定先要进行加载进程序,才可以使用。
HMODULE hDll=LoadLibrary(“xx.dll”);
然后直接GetProcAddress(hModule,“function name”);就直接可以获得
FARPROC类型的东西 其实就是个函数指针
也是函数的地址!