滴水逆向初级-win32(四)

4.1.C语言中的宽字符

1、常用函数

char		wchar_ t		//多字节字符类型 宽字符类型
printf		wprintf			//打印到控制台函数
strlen		wcslen			//获取长度
strcpy		wcscpy			//字符串复制
strcat		wcscat			//字符串拼接
strcmp		wcscmp			//字符串比较
strstr		wcsstr			//字符串查找

2、打印宽字符

#include <locale.h>
setlocale(LC_ALL,")			//使用控制台默认的编码
wchar_ t swzStr[]= L“中国";
wprint(L"%s\n",x1);

3、字符串长度

char szStr] = "中国";
wchar_ t swzStr[] = L"中国";
strlen(szStr);		//取得多字节字符串中字符长度,不包含00
wcslen(swzStr); 	//取得多字 节字符串中字符长度,不包含00 00

4.2.Win32 API中的宽字符

1、什么是Win32 API?有哪些?在哪里?
主要是存放在C:\WINDOWS\system32下面所有的dll
几个重要的DLL:
<1> Kernel32.dl:最核心的功能模块,比如管理内存、进程和线程相关的函数等。
<2> User32 dIl:是Windows用 户界面相关应用程序接口,如创建窗口和发送消息等。

<3> GDI32.dll:全称是Graphical Device Interface(图形设备接口),包含用于画图和显示文本的函数。

2、关于Win32的数据类型:

int MessageBox(
    HWND hWnd,			// handle to owner window
    LPCTSTR IpText, 	// text in message box
    LPCTSTR lpCaption,  //message box title
    UINT uType			//message box style
);

3、常用数据类型:
汇编:

byte	BYTE	PBYTE
word	WORD	PWORD
dword	DWORD	PDWORD

C语言:

char			CHAR	PCHAR
unsigned char	UCHAR	PUCHAR
short			SHORT	PSHORT
unsigned short	USHORT	PUSHORT
int				INT		PINT
unsigned int	UINT	PUINT

C++

bool	BOOL

4、在Win32中使用字符串:

字符类型:
    CHAR szStr[]= “中国”;
    WCHAR swzStr[]= L“中国”; 
    TCHAR stzSr[] = TEXT(“中国");    //win32推荐的方式
字符串指针:
    PSTR pszStr=“中国";
    PWSTR pwszStr= L“中国";
    PTSTR ptszStr = TEXT(“中国");		//win32推荐的方式

5、第一个win32 api的使用

#include<stdio.h>
#include<stdlib.h>
#include<windows.h>

void main()
{	
	/*
	// ASSll编码
	int MessageBox(
		HWND hWnd,			//所有者窗口的句柄
		LPCTSTR IpText,		//消息框中的文本地址
		LPCTSTR IpCaption,	//消息框标题的地址
		UINT uType			//样式的消息框
	);
	*/
	
	/*
	//unicode编码
	CHAR szTitle[] = "Title";
	CHAR szContent[] = "hello world";
	MessageBoxA(0,szContent,szTitle,MB_OK);
	*/
	
	/*
	WCHAR swzTitle[] = L"Title";
	WCHAR swzContent[] = L"hello world";
	MessageBoxW(0,swzContent,swzTitle,MB_OK);
	*/
    
    //推荐的方式,编译器会自动选择编码方式
	TCHAR stzTitle[] = TEXT("Title");
	TCHAR stzContent[] = TEXT("hello world");
	MessageBox(0,stzContent,stzTitle,MB_OK);
    
	system("pause");
	return;
}

4.3.进程的创建过程

1、什么是进程?
进程提供程序所需的资源,如:数据、代码等等。

2、进程内存空间的地址划分

滴水逆向初级-win32(四)
3、进程的创建
<1>任何进程都是别的进程创建的: CreateProcess()
<2>进程的创建过程
1、映射EXE文件
2、创建内核对象EPROCESS
3、映射系统DLL(ntdll.dIl)
4、创建线程内核对象ETHREAD
5、系统启动线程
映射DLL(ntll.Ldrlnitialize Thunk)
线程开始执行

4.4.创建进程

进程的创建

进程的创建:
BOOL CreateProcess(
    LPCTSTR IpApplicationName,		// name of executable module
    LPTSTR lpCommandLine,			// command line string
    LPSECURITY_ ATTRIBUTES IpProcessAttributes, 	// SD
    LPSECURITY_ ATTRIBUTES IpThreadAttributes, 	// SD
    BOOL bInheritHandles,			//I handle inheritance option
    DWORD dwCreationFlags,			// creation flags
    LPVOID IpEnvironment,			// new environment block
    LPCTSTR IpCurrentDirectory,		// current directory name
    LPSTARTUPINFO IpStartupInfo,		// startup information
    LPPROCESS_ INFORMATION IpProcessInformation 		// process information
);

创建进程例子

#include<stdio.h>
#include<stdlib.h>
#include<windows.h>

BOOL CreateChildProcess(PTCHAR szChildProcessName,PTCHAR szCommandLine)
{
	STARTUPINFO si;
	PROCESS_INFORMATION pi;

	ZeroMemory(&pi,sizeof(pi));
	ZeroMemory(&si,sizeof(si));
	si.cb = sizeof(si);
	
    //创建子进程
	if(!CreateProcess(
		szChildProcessName,		//对象名称
		szCommandLine,			//命令行	
		NULL,					//不继承进程句柄
		NULL,					//不继承线程句柄
		FALSE,					//不继承句柄
		0,						//没有创建标志
		NULL,					//使用父进程环境差变量
		NULL,					//使用父进程目录作为当前目录。可以自己设置目录
		&si,					//STARTUPINFO 结构体详细信息
		&pi)					//PROCESS_INFOMATION结构体进程信息
		)
	{
		printf("CreateChildProcess Error:%d \n",GetLastError());
		return FALSE;
	}
	//释放句柄
	CloseHandle(pi.hProcess);
	CloseHandle(pi.hThread);
	return TRUE;
};

void main(int argc,char* argv[])
{	
	TCHAR szApplicationName[] = TEXT("C://Program Files//Tools//PE.exe");
	TCHAR szCommandLine[] = TEXT("1");
	CreateChildProcess(szApplicationName,szCommandLine);

	getchar();
	system("pause");
	return;
}

4.5.句柄表

1、什么是内核对象?
像进程、线程、文件、互斥体、事件等在内核都有一个对应的结构体,这些结构体由内核负责管理。我们管这样的对象叫做内核对象。

2、如何管理内核对象
滴水逆向初级-win32(四)
3、每个进程都有一个句柄表
滴水逆向初级-win32(四)
4、多进程共享一个内核对象
滴水逆向初级-win32(四)
5、句柄可以被继承
滴水逆向初级-win32(四)

4.6.进程相关API

1、ID与句柄
滴水逆向初级-win32(四)
2、以挂起的形势创建进程

<1>任何进程都是别的进程创建的: CreateProcess()
<2>进程的创建过程
1、映射EXE文件
2、创建内核对象EPROCESS
3、映射系统LLLntll.dI)
4、创建线程内核对象ETHREAD
5、如果是挂起的方式创建的
6、恢复以后再继续执行
映射DLL(ntllI.Ldrlnitialize^ Thunk)
线程开始执行

挂起的方式创建进程

#include<stdio.h>
#include<stdlib.h>
#include<windows.h>

BOOL CreateChildProcess(PTCHAR szChildProcessName,PTCHAR szCommandLine)
{
	STARTUPINFO si;
	PROCESS_INFORMATION pi;

	ZeroMemory(&pi,sizeof(pi));
	ZeroMemory(&si,sizeof(si));
	si.cb = sizeof(si);
	
	if(!CreateProcess(
		szChildProcessName,
		szCommandLine,
		NULL,
		NULL,
		FALSE,
		CREATE_SUSPENDED,    //以挂起的方式创建线程
		NULL,
		NULL,
		&si,
		&pi)
		)
	{
		printf("CreateChildProcess Error:%d \n",GetLastError());
		return FALSE;
	}

	//SuspendThread(pi.hThread);   //暂停进程
	//ResumeThread(pi.hThread);	   //恢复进程
	//打印进程ID和进程句柄
	printf("PID:%X - process:%x \n",pi.dwProcessId,pi.hProcess);
	
    //在恢复进程前,需要做的操作代码
	for(int i=0;i<5;i++)
	{
		Sleep(1000);
		printf("========\n");
	}
    //恢复进程
	ResumeThread(pi.hThread);
	//关闭进程和线程
	CloseHandle(pi.hProcess);
	CloseHandle(pi.hThread);
	return TRUE;
};

void main(int argc,char* argv[])
{	
	TCHAR szApplicationName[] = TEXT("C://Program Files//Tools//PE.exe");
	TCHAR szCommandLine[] = TEXT("1");
	CreateChildProcess(szApplicationName,szCommandLine);
	
	getchar();
	system("pause");
	return;
}

3、模块目录和工作目录

char strModule[256];
GetModuleFileName(NULL,strModule, 256); 	//模块目录
char strWork[1000];
int i=1000;
GetCurrentDirectory(1000,buf);				//工作目录

print("模块目录: %s\n工作目录: %s\n",strModule,strWork);

4、其它进程相关API

获取进程PID
GetCurrentProcessld
获取进程句柄
GetCurrentProcess
获取命令行
GetCommandL ine
获取启动信息
GetStartupInfo
遍历进程ID
EnumProcesses
快照
CreateToolhelp32Snapshot

4.7.创建线程

1、什么是线程?
<1>线程是附属在进程上的执行实体,是代码的执行流程。
<2>一个进程可以包含多个线程,但一个进程至少要包含一个线程。

2、创建线程

HANDLE CreateThread(
  LPSECURITY_ATTRIBUTES   lpThreadAttributes,
  SIZE_T                  dwStackSize,
  LPTHREAD_START_ROUTINE  lpStartAddress,
  LPVOID 				  lpParameter,
  DWORD                   dwCreationFlags,
  LPDWORD                 lpThreadId
);

实例

#include<stdio.h>
#include<stdlib.h>
#include<windows.h>

DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
    //强转传递的参数的类型
	int* p = (int*)lpParameter;

	for(int i=0;i<*p;i++)
	{
		Sleep(500);
		printf("+++++%d \n",i);
	}
	return 0;
}
//参数
int n = 10;

void main(int argc,char* argv[])
{	
	HANDLE hThread;  
    //1.返回的是线程句柄
    //2.第三个参数是要执行的线程函数
    //3.第四个参数是要执行的线程函数的参数,类型为LPVOID
	hThread = CreateThread(NULL,0,ThreadProc,(LPVOID)&n,0,NULL);
	CloseHandle(hThread);

	for(int i=0;i<100;i++)
	{
		Sleep(500);
		printf("------%d\n",i);
	}

	system("pause");
	return;
}

4.8.线程控制

1、如何让线程停下来

让自己停下来:
	Sleep()
让别人停下来:
	SuspendThread()
线程恢复:
	ResumeThread()

挂起和恢复线程

#include<stdio.h>
#include<stdlib.h>
#include<windows.h>

DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
	int* p = (int*)lpParameter;

	for(int i=0;i<*p;i++)
	{
		Sleep(500);
		printf("+++++%d \n",i);
	}
	return 0;
}

int n = 100;

void main(int argc,char* argv[])
{	
	HANDLE hThread;  
	hThread = CreateThread(NULL,0,ThreadProc,(LPVOID)&n,0,NULL);

	Sleep(5000);
	SuspendThread(hThread);    //挂起线程
	Sleep(5000);
	ResumeThread(hThread);	   //恢复线程
	
	getchar();
	CloseHandle(hThread);

	system("pause");
	return;
}

2、等待线程结束

<1> WaitForSingleObject();   

<2> WaitForMultipleObjects();

<3> GetExitCodeThread();

单个线程WaitForSingleObject()

  • 第一个参数是句柄,
  • 第二个参数是等待时间,INFINITE表示等待线程执行结束
#include<stdio.h>
#include<stdlib.h>
#include<windows.h>

DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
	int* p = (int*)lpParameter;

	for(int i=0;i<*p;i++)
	{
		Sleep(500);
		printf("+++++%d \n",i);
	}
	return 0;
}

int n = 20;

void main(int argc,char* argv[])
{	
	HANDLE hThread;  
	hThread = CreateThread(NULL,0,ThreadProc,(LPVOID)&n,0,NULL);

	WaitForSingleObject(hThread,INFINITE);  //等待线程结束,才会执行后面的代码
	printf("线程执行完毕\n");
	
	getchar();
	CloseHandle(hThread);

	system("pause");
	return;
}

多个线程WaitForMultipleObjects()

  • 第一个参数:线程个数
  • 第二个参数:线程句柄数组
  • 第三个参数:是否等待所有线程结束
  • 第四个参数:等待时间
#include<stdio.h>
#include<stdlib.h>
#include<windows.h>

DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
	int* p = (int*)lpParameter;

	for(int i=0;i<*p;i++)
	{
		Sleep(500);
		printf("+++++%d \n",i);
	}
	return 0;
}

int n = 20;

void main(int argc,char* argv[])
{	
	HANDLE arrThread[2];  
	arrThread[0] = CreateThread(NULL,0,ThreadProc,(LPVOID)&n,0,NULL);
	arrThread[1] = CreateThread(NULL,0,ThreadProc,(LPVOID)&n,0,NULL);

	WaitForMultipleObjects(2,arrThread,TRUE,INFINITE);
	printf("线程执行完毕\n");
	
	getchar();
	CloseHandle(arrThread[0]);
    CloseHandle(arrThread[1]);

	system("pause");
	return;
}

获取线程返回结果值GetExitCodeThread()

#include<stdio.h>
#include<stdlib.h>
#include<windows.h>

DWORD WINAPI ThreadProc1(LPVOID lpParameter)
{
	int* p = (int*)lpParameter;

	for(int i=0;i<*p;i++)
	{
		Sleep(500);
		printf("+++++%d \n",i);
	}
	return 0;   //返回结果
}

DWORD WINAPI ThreadProc2(LPVOID lpParameter)
{
	int* p = (int*)lpParameter;

	for(int i=0;i<*p;i++)
	{
		Sleep(500);
		printf("+++++%d \n",i);
	}
	return 1;   //返回结果
}

int n = 20;

void main(int argc,char* argv[])
{	
	HANDLE arrThread[2];  
	DWORD dwResult1;
	DWORD dwResult2;
	arrThread[0] = CreateThread(NULL,0,ThreadProc1,(LPVOID)&n,0,NULL);
	arrThread[1] = CreateThread(NULL,0,ThreadProc2,(LPVOID)&n,0,NULL);

	WaitForMultipleObjects(2,arrThread,TRUE,INFINITE);
    //获取线程返回结果值
	GetExitCodeThread(arrThread[0],&dwResult1);
	GetExitCodeThread(arrThread[1],&dwResult2);

	printf("%d %d\n",dwResult1,dwResult2);   //0  1
	printf("线程执行完毕\n");
	
	getchar();
	CloseHandle(arrThread[0]);
	CloseHandle(arrThread[1]);

	system("pause");
	return;
}

3、获取和设置线程上下文

//获取
BOOL GetThreadContext(
	HANDLE hThread, 		// handle to thread with context
	LPCONTEXT IpContext 	// context structure
);

//设置
BOOL SetThreadContext(
	HANDLE hThread,	     	// handle to thread
	CONST CONTEXT *lpContext    //context structure
);

获取上下文

#include<stdio.h>
#include<stdlib.h>
#include<windows.h>

DWORD WINAPI ThreadProc1(LPVOID lpParameter)
{
	int* p = (int*)lpParameter;

	for(int i=0;i<*p;i++)
	{
		Sleep(500);
		printf("+++++%d \n",i);
	}
	return 0;   //返回结果
}

DWORD WINAPI ThreadProc2(LPVOID lpParameter)
{
	int* p = (int*)lpParameter;

	for(int i=0;i<*p;i++)
	{
		Sleep(500);
		printf("+++++%d \n",i);
	}
	return 1;   //返回结果
}

int n = 20;

void main(int argc,char* argv[])
{	
	HANDLE arrThread[2];  
	DWORD dwResult1;
	DWORD dwResult2;

	arrThread[0] = CreateThread(NULL,0,ThreadProc1,(LPVOID)&n,0,NULL);
	arrThread[1] = CreateThread(NULL,0,ThreadProc2,(LPVOID)&n,0,NULL);

	SuspendThread(arrThread[0]);
	CONTEXT context;
	context.ContextFlags = CONTEXT_INTEGER;
	GetThreadContext(arrThread[0],&context);     //获取上下文
	printf("%x %x\n",context.Eax,context.Ecx);
	ResumeThread(arrThread[0]);
	
	getchar();
	CloseHandle(arrThread[0]);
	CloseHandle(arrThread[1]);

	system("pause");
	return;
}

4.9.临界区

1、线程安全问题

每个线程都有自己的栈,而局部变量是存储在栈中的,这就意味着每个线程都有一份自己的“局部变量",如果线程仅仅使用“局部变量”那么就不存在线程安全问题。那如果多个线程共用-一个全局变量呢?

2、解决思路
滴水逆向初级-win32(四)
3、临界区实现之线程锁

<1>创建全局变量
CRITICAL SECTION cs;
<2>初始化全局变量
InitializeCriticalSection(&cs);
<3>实现临界区
EnterCriticalSection(&cs);
使用临界资源
LeaveCriticalSection(&cs);

#include<stdio.h>
#include<stdlib.h>
#include<windows.h>

int g_dwTickets = 10;
CRITICAL_SECTION cs;   //创建全局变量

DWORD WINAPI MyFirstThreadProc(LPVOID lpParameter)
{
	EnterCriticalSection(&cs);     //实现临界区
	while(g_dwTickets>0)
	{
		EnterCriticalSection(&cs);
		printf("还有:%d张票\n",g_dwTickets);
		g_dwTickets--;
		printf("卖出一张,还有:%d张票\n",g_dwTickets);
		LeaveCriticalSection(&cs);    //使用临街资源
	}
	return 0;   
}

void main(int argc,char* argv[])
{	
	HANDLE arrThread[2];  
	DWORD dwResult1;
	DWORD dwResult2;

	InitializeCriticalSection(&cs);   //初始化全局变量

	arrThread[0] = CreateThread(NULL,0,MyFirstThreadProc,NULL,0,NULL);
	arrThread[1] = CreateThread(NULL,0,MyFirstThreadProc,NULL,0,NULL);

	WaitForMultipleObjects(2,arrThread,TRUE,INFINITE);
	GetExitCodeThread(arrThread[0],&dwResult1);
	GetExitCodeThread(arrThread[0],&dwResult2);

	getchar();
	CloseHandle(arrThread[0]);
	CloseHandle(arrThread[1]);

	system("pause");
	return;
}

4.10.互斥体

1、内核级临街资源怎么办
滴水逆向初级-win32(四)
2、互斥体的使用
滴水逆向初级-win32(四)
互斥体例子

#include<stdio.h>
#include<stdlib.h>
#include<windows.h>

void main(int argc,char* argv[])
{	
    //创建一个互斥体
	HANDLE g_hMutex = CreateMutex(NULL,FALSE,"test");  //第三个参数:随便起一个名字
	//获取令牌
	WaitForSingleObject(g_hMutex,INFINITE);

	for(int i=0;i<10;i++)
	{
		Sleep(1000);
		printf("%d\n",i);
	}
	//释放令牌
	ReleaseMutex(g_hMutex);

	getchar();

	system("pause");
	return;
}

3、互斥体与线程锁的区别
1、线程锁只能用于单个进程间的线程控制
2、互斥体可以设定等待超时,但线程锁不能
3、线程意外终结时,Mutex可以避免无限等待
4、Mutex效率没有线程锁高

4、通过互斥体防止程序多开

#include<stdio.h>
#include<stdlib.h>
#include<windows.h>

int main(int argc,char* argv[])
{	
	HANDLE hMutex = CreateMutex(NULL,FALSE,"防止多开");
    //1.第一次打开程序的时候GetLastError()返回值为:0
    //2.第二次打开程序的时候GetLastError()返回为:ERROR_ALREADY_EXISTS
    //3.其它情况则是程序出错
	DWORD dwRet = GetLastError();
	if(hMutex)
	{
		if(ERROR_ALREADY_EXISTS == dwRet)    //如果是第二次打开程序,直接关闭进程
		{
			CloseHandle(hMutex);
			return 0;
		}
	}
	else
	{
		printf("创建失败,程序退出\n");
		CloseHandle(hMutex);
		return 0;
	}

	while(1)
	{
		Sleep(1000);
		printf("程序执行中.....\n");
	}
		
	getchar();
	system("pause");
	return 0;
}

4.11.事件

1、通知事件

HANDLE CreateEvent(
  LPSECURITY_ATTRIBUTES lpEventAttributes, // SD
  BOOL bManualReset,                       // reset type
  BOOL bInitialState,                      // initial state
  LPCTSTR lpName                           // object name
);

实例

#include<stdio.h>
#include<stdlib.h>
#include<windows.h>

HANDLE g_hEvent

DWORD WINAPI ThreadProc_1(LPVOID lpParameter)
{
	TCHAR szBuffer[10] = {0};
	//等待通知
	WaitForSingleObject(g_hEvent,INFINITE);

	printf("ThreadProc_1执行了\n");
	getchar();
	return 0;
}

DWORD WINAPI ThreadProc_2(LPVOID lpParameter)
{
	TCHAR szBuffer[10] = {0};
	//等待通知
	WaitForSingleObject(g_hEvent,INFINITE);

	printf("ThreadProc_2执行了\n");
	getchar();
	return 0;
}

int main(int argc,char* argv[])
{	
    //创建事件
    //参数:1.默认安全属性;2.TRUE通知。FALSE互斥
    //参数:3.初始没信号;4.如果想其它进程用,进起个名字
	g_hEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
	HANDLE hThread[2];
    //创建两个线程
	hThread[0] = CreateThread(NULL,0,ThreadProc_1,NULL,0,NULL);
	hThread[0] = CreateThread(NULL,0,ThreadProc_2,NULL,0,NULL);
	//设置事件为通知	
	SetEvent(g_hEvent); 
	WaitForMultipleObjects(2,hThread,TRUE,INFINITE);
	CloseHandle(hThread[0]);
	CloseHandle(hThread[1]);
	CloseHandle(g_hEvent);
		
	getchar();

	system("pause");
	return 0;
}

2、线程同步
<1>线程互斥:线程互斥是指对于共享的进程系统资源,在各单个线程访问时的排它性。当有若干个线程都要使用某一共享资源时, 任何时刻最多只允许一个线程去使用,其它要使用该资源的线程必须等待,直到占用资源者释放该资源。
<2>线程同步:线程同步是指线程之间所具有的一种制约关系,一个线程的执行依赖另一个线程的消息,当它没有得到另一个线程的消息时应等待,直到消息到达时才被唤醒。

同步=互斥+有序执行

3、同步的前提是互斥

滴水逆向初级-win32(四)
滴水逆向初级-win32(四)
4、生产者和消费者

#include<stdio.h>
#include<stdlib.h>
#include<windows.h>

HANDLE g_hSet,g_hClear;
int g_Max = 10;
int g_Numberr = 0;

DWORD WINAPI ThreadProduct(LPVOID pM)
{
	for (int i=0;i<g_Max;i++)
	{
		WaitForSingleObject(g_hSet,INFINITE);
		g_Numberr = 1;
		DWORD id = GetCurrentThreadId();
		printf("生产者%d将数据%d防入缓冲区\n",id,g_Numberr);
		SetEvent(g_hClear);
	}
	return 0;
}

DWORD WINAPI ThreadConsumer(LPVOID pM)
{
	for (int i=0;i<g_Max;i++)
	{
		WaitForSingleObject(g_hClear,INFINITE);
		g_Numberr = 0;
		DWORD id = GetCurrentThreadId();
		printf("消费者%d将数据%d防入缓冲区\n",id,g_Numberr);
		SetEvent(g_hSet);
	}
	return 0;
}

int main(int argc,char* argv[])
{	
	HANDLE hThread[2];
	g_hSet = CreateEvent(NULL,FALSE,TRUE,NULL);      //生产者。第三个参数TRUE,默认有信号
	g_hClear = CreateEvent(NULL,FALSE,FALSE,NULL);	//消费者者。第三个参数FALSE,默认无信号
	
	hThread[0] = ::CreateThread(NULL,0,ThreadProduct,NULL,0,NULL);
	hThread[1] = ::CreateThread(NULL,0,ThreadConsumer,NULL,0,NULL);

	WaitForMultipleObjects(2,hThread,TRUE,INFINITE);
	CloseHandle(hThread[0]);
	CloseHandle(hThread[1]);
	CloseHandle(g_hSet);
	CloseHandle(g_hClear);
		
	system("pause");
	return 0;
}

4.12.窗口的本质

1、窗口的本质
滴水逆向初级-win32(四)
2、GDI图形设备接口(Graphics Device Interface)**
<1>设备对象(HWND)
<2> DC(设备上下文,Device Contexts)
<3>图形对象
滴水逆向初级-win32(四)

4.13.消息队列

1、什么是消息?
当我们点击鼠标的时候,或者当我们按下键盘的时候,操作系统都要把这些动作记录下来,存储到一个结构体中,这个结构体就是消息。
2、消息队列:每个线程只有一个消息队列
滴水逆向初级-win32(四)
3、窗口与线程
滴水逆向初级-win32(四)

4.14.第一个Windows程序

1、创建win32应用程序
滴水逆向初级-win32(四)
滴水逆向初级-win32(四)
2、WinMain函数

int WINAPI WinMain(
  HINSTANCE hInstance,      // handle to current instance
  HINSTANCE hPrevInstance,  // handle to previous instance
  LPSTR lpCmdLine,          // command line
  int nCmdShow              // show state
);

3、调试信息的输出

char szOutBuff[0x80];
sprintf(szOutBuff,"Error: %d",GetLastError());
OutputDebugString(szOutBuff)

4、打印当前程序的入口地址

// derek.cpp : Defines the entry point for the application.
//

#include "stdafx.h"

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
	char szOutBuff[0x80];
	DWORD dwAddr = (DWORD)hInstance;
	sprintf(szOutBuff,"address: %x\n",dwAddr);
	OutputDebugString(szOutBuff);      //address:400000
    
	return 0;
}

5、创建一个window窗口程序过程
滴水逆向初级-win32(四)
6、用到的API函数

typedef struct _WNDCLASS { 
    UINT       style; 
    WNDPROC    lpfnWndProc; 
    int        cbClsExtra; 
    int        cbWndExtra; 
    HINSTANCE  hInstance; 
    HICON      hIcon; 
    HCURSOR    hCursor; 
    HBRUSH     hbrBackground; 
    LPCTSTR    lpszMenuName; 
    LPCTSTR    lpszClassName; 
} WNDCLASS, *PWNDCLASS; 

LRESULT CALLBACK WindowProc(
  HWND hwnd,      // handle to window
  UINT uMsg,      // message identifier
  WPARAM wParam,  // first message parameter
  LPARAM lParam   // second message parameter
);

HWND CreateWindow(
  LPCTSTR lpClassName,  // registered class name
  LPCTSTR lpWindowName, // window name
  DWORD dwStyle,        // window style
  int x,                // horizontal position of window
  int y,                // vertical position of window
  int nWidth,           // window width
  int nHeight,          // window height
  HWND hWndParent,      // handle to parent or owner window
  HMENU hMenu,          // menu handle or child identifier
  HINSTANCE hInstance,  // handle to application instance
  LPVOID lpParam        // window-creation data
);

HWND CreateWindow(
  LPCTSTR lpClassName,  // registered class name
  LPCTSTR lpWindowName, // window name
  DWORD dwStyle,        // window style
  int x,                // horizontal position of window
  int y,                // vertical position of window
  int nWidth,           // window width
  int nHeight,          // window height
  HWND hWndParent,      // handle to parent or owner window
  HMENU hMenu,          // menu handle or child identifier
  HINSTANCE hInstance,  // handle to application instance
  LPVOID lpParam        // window-creation data
);

BOOL GetMessage(
  LPMSG lpMsg,         // message information
  HWND hWnd,           // handle to window
  UINT wMsgFilterMin,  // first message
  UINT wMsgFilterMax   // last message
);

7、实例

// derek.cpp : Defines the entry point for the application.
//

#include "stdafx.h"

LRESULT CALLBACK WindowProc(
  HWND hwnd,      // handle to window
  UINT uMsg,      // message identifier
  WPARAM wParam,  // first message parameter
  LPARAM lParam   // second message parameter
);

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
    //1.定义窗口的样子
	char szOutBuff[0x80];
	TCHAR className[] = TEXT("My first window");
	WNDCLASS wndclass = {0};
    //wndclass:主要是下面4个参数
	wndclass.hbrBackground = (HBRUSH)COLOR_BACKGROUND;  
	wndclass.lpfnWndProc = WindowProc;
	wndclass.lpszClassName = className;
	wndclass.hInstance = hInstance;
    
	RegisterClass(&wndclass);   //注册窗口
	
    //2.创建窗口
	HWND hwnd = CreateWindow(
		className,
		TEXT("我的第一个窗口"),
		WS_OVERLAPPEDWINDOW,
		10,
		10,
		600,
		300,
		NULL,
		NULL,
		hInstance,
		NULL	
		);
	//如果窗口没有创建成功,打印错误信息
	if(hwnd == NULL)
	{
		sprintf(szOutBuff,"Error: %d\n",GetLastError());
		OutputDebugString(szOutBuff);  
		return 0;
	}
	//显示窗口
	ShowWindow(hwnd,SW_SHOW);
	
    //3.消息处理
	MSG msg;
	BOOL bRet;
	while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
	{ 
		if (bRet == -1)
		{
			sprintf(szOutBuff,"Error: %d\n",GetLastError());
			OutputDebugString(szOutBuff);
		}
		else
		{
			//TranslateMessage(&msg);    //转换消息
			DispatchMessage(&msg);       //分发消息
		}
    };

	return 0;
};

LRESULT CALLBACK WindowProc(
  HWND hwnd,      // handle to window
  UINT uMsg,      // message identifier
  WPARAM wParam,  // first message parameter
  LPARAM lParam   // second message parameter
)
{
	return DefWindowProc(hwnd,uMsg,wParam,lParam);    //必须提供消息的处理方式,这里按默认方式
}

4.15.消息类型

1、消息产生与处理流程
滴水逆向初级-win32(四)
2、消息类型

// derek.cpp : Defines the entry point for the application.
//

#include "stdafx.h"

LRESULT CALLBACK WindowProc(
  HWND hwnd,      // handle to window
  UINT uMsg,      // message identifier
  WPARAM wParam,  // first message parameter
  LPARAM lParam   // second message parameter
);

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
	char szOutBuff[0x80];
	TCHAR className[] = TEXT("My first window");
	WNDCLASS wndclass = {0};
	wndclass.hbrBackground = (HBRUSH)COLOR_BACKGROUND;
	wndclass.lpfnWndProc = WindowProc;
	wndclass.lpszClassName = className;
	wndclass.hInstance = hInstance;
	RegisterClass(&wndclass);
	
	HWND hwnd = CreateWindow(
		className,
		TEXT("我的第一个窗口"),
		WS_OVERLAPPEDWINDOW,
		10,
		10,
		600,
		300,
		NULL,
		NULL,
		hInstance,
		NULL	
		);
	
	if(hwnd == NULL)
	{
		sprintf(szOutBuff,"Error: %d\n",GetLastError());
		OutputDebugString(szOutBuff);  
		return 0;
	}

	ShowWindow(hwnd,SW_SHOW);

	MSG msg;
	BOOL bRet;
	while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
	{ 
		if (bRet == -1)
		{
			sprintf(szOutBuff,"Error: %d\n",GetLastError());
			OutputDebugString(szOutBuff);
		}
		else
		{
			TranslateMessage(&msg);    //把键盘虚拟键码自动转换成对应字符
			DispatchMessage(&msg); 
		}
    };

	return 0;
};

LRESULT CALLBACK WindowProc(
  HWND hwnd,      // handle to window
  UINT uMsg,      // message identifier
  WPARAM wParam,  // first message parameter
  LPARAM lParam   // second message parameter
)
{
	//WM_CREATE
	switch(uMsg)
	{
	case WM_DESTROY:    //窗口销毁message
		{
			PostQuitMessage(0);   
			return 0;
		}
	case WM_CHAR:      //键盘按键消息
		{
			char szOutBuff[0x80];
			sprintf(szOutBuff,"消息:%c\n",wParam);   //获取按了键盘哪个键
			OutputDebugString(szOutBuff);
			return 0;
		}

	}

	return DefWindowProc(hwnd,uMsg,wParam,lParam);
}

4.16.子窗口控件

<1> WINDOWS提供了几个预定义的窗口类以方便我们的使用,我们一-般就它们叫做子窗口控件,简称控件。
<2>控件会自己处理消息,并在自己状态发生改变时通知父窗口。
<3>预定义的控件有:
按钮、复选框、编辑框、静态字符串标签和滚动条等

实例

// derek.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#define IDC_EDIT_1 0X100        //子窗口身份标识
#define IDC_BUTTON_1 0X101
#define IDC_BUTTON_2 0X102

HINSTANCE g_hInstance;         //定义全局的g_hInstance,子窗口可以获取到父窗口的hInstance

LRESULT CALLBACK WindowProc(
  HWND hwnd,      // handle to window
  UINT uMsg,      // message identifier
  WPARAM wParam,  // first message parameter
  LPARAM lParam   // second message parameter
);

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
	char szOutBuff[0x80];
	g_hInstance = hInstance;   //把父窗口的hInstance赋值给全局的g_hInstance,
	TCHAR className[] = TEXT("My first window");
	WNDCLASS wndclass = {0};
	wndclass.hbrBackground = (HBRUSH)COLOR_BACKGROUND;
	wndclass.lpfnWndProc = WindowProc;
	wndclass.lpszClassName = className;
	wndclass.hInstance = hInstance;
	RegisterClass(&wndclass);
	
	HWND hwnd = CreateWindow(
		className,
		TEXT("我的第一个窗口"),
		WS_OVERLAPPEDWINDOW,
		10,
		10,
		600,
		300,
		NULL,
		NULL,
		hInstance,
		NULL	
		);
	
	if(hwnd == NULL)
	{
		sprintf(szOutBuff,"Error: %d\n",GetLastError());
		OutputDebugString(szOutBuff);  
		return 0;
	}

	ShowWindow(hwnd,SW_SHOW);

	MSG msg;
	BOOL bRet;
	while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
	{ 
		if (bRet == -1)
		{
			sprintf(szOutBuff,"Error: %d\n",GetLastError());
			OutputDebugString(szOutBuff);
		}
		else
		{
			TranslateMessage(&msg); 
			DispatchMessage(&msg); 
		}
    };

	return 0;
};

LRESULT CALLBACK WindowProc(
  HWND hwnd,      // handle to window
  UINT uMsg,      // message identifier
  WPARAM wParam,  // first message parameter
  LPARAM lParam   // second message parameter
)
{
	char szOutBuff[0x80];
	//sprintf(szOutBuff,"消息: %x\n",uMsg);   //查看消息类型
	//OutputDebugString(szOutBuff); 
	//WM_CREATE
	switch(uMsg)
	{
	case WM_DESTROY:
		{
			PostQuitMessage(0);
			break;
		}

	case WM_COMMAND:
		{
			switch(LOWORD(wParam))          //低16位
			{
			case IDC_BUTTON_1:
				{
					SetDlgItemText(hwnd,IDC_EDIT_1,TEXT("测试"));
					break;
				}

			case IDC_BUTTON_2:
				{
					GetDlgItemText(hwnd,IDC_EDIT_1,szOutBuff,100);
					MessageBox(hwnd,szOutBuff,szOutBuff,MB_OK);
					break;
				}
			}

			break;
		}

	case WM_CREATE:
		{
			CreateWindow(
				"EDIT",
				"",
				WS_CHILD|WS_VISIBLE|WS_VSCROLL|ES_MULTILINE,    //子窗口通用style和特殊style
				0,
				0,
				500,
				300,
				hwnd,                    //父窗口
				(HMENU)IDC_EDIT_1,       //子窗口身份标识
				g_hInstance,
				NULL	
				);
			CreateWindow(
				"BUTTON",
				"设置",
				WS_CHILD|WS_VISIBLE,
				520,
				180,
				60,
				30,
				hwnd,
				(HMENU)IDC_BUTTON_1,
				g_hInstance,
				NULL	
				);
			CreateWindow(
				"BUTTON",
				"获取",
				WS_CHILD|WS_VISIBLE,
				520,
				220,
				60,
				30,
				hwnd,
				(HMENU)IDC_BUTTON_2,
				g_hInstance,
				NULL	
				);
			break;
		}
	}
	return DefWindowProc(hwnd,uMsg,wParam,lParam);
};
上一篇:c# win32 api获取顶部的窗口


下一篇:win32 API编程之常用控件