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、进程内存空间的地址划分
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、如何管理内核对象
3、每个进程都有一个句柄表
4、多进程共享一个内核对象
5、句柄可以被继承
4.6.进程相关API
1、ID与句柄
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、解决思路
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、内核级临街资源怎么办
2、互斥体的使用
互斥体例子
#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、同步的前提是互斥
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、窗口的本质
2、GDI图形设备接口(Graphics Device Interface)**
<1>设备对象(HWND)
<2> DC(设备上下文,Device Contexts)
<3>图形对象
4.13.消息队列
1、什么是消息?
当我们点击鼠标的时候,或者当我们按下键盘的时候,操作系统都要把这些动作记录下来,存储到一个结构体中,这个结构体就是消息。
2、消息队列:每个线程只有一个消息队列
3、窗口与线程
4.14.第一个Windows程序
1、创建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窗口程序过程
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、消息产生与处理流程
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);
};