windows SDK编程简单总结

夏侯兴学
2023-12-01

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类型的东西 其实就是个函数指针

也是函数的地址!

 类似资料: