VC编程之VC常用API+示例2
小标 2019-01-15 来源 : 阅读 1887 评论 0

摘要:本文主要向大家介绍了VC编程之VC常用API+示例2,通过具体的内容向大家展示,希望对大家学习VC编程有所帮助。

本文主要向大家介绍了VC编程之VC常用API+示例2,通过具体的内容向大家展示,希望对大家学习VC编程有所帮助。

VC编程之VC常用API+示例2

第二十一个CreateWindow创建一个窗口
//补习懂的人直接跳过
之前API函数的例子,都是针对DOS编程的,严格来说是在windows下的仿DOS(cmd)进行编程,编写控制台应用程序大家都知道,主函数是main,那针对windows编程的主函数也是main吗?不是的,windows下的主函数(入口函数)是WinMain。在定义main主函数的时候,可以给它带两个参数,也可以不带。而WinMain函数就不能这样了,它有固定的格式,它必须带四个参数。
现给出WinMain函数的固定格式:
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, instance LPSTR lpCmdLine,  int nCmdShow)
大家如果有兴趣可以通过其它渠道了解一下各参数的意思,现在我们只需要知道WinMain函数就是这样定义的,不理解也没关系。
知道了这个我们就来编一个WINDOWS程序吧!
因为我们是针对windows编程,所以要建一个Win32 Application工程,步骤是点击文件,然后选择新建,在弹出的对话框里选择工程,再选中Win32 Application 接着在右边的工程名称下填工程名称,名字随便取。之后点确定。接着又弹出了一个对话框,这里为了方便,我们选择“一个简单的  Win32 程序”,点完成。接着双击WinMain弹出代码编辑窗口,做完这个我们就可以打代码了。

简单的例子如下:
#include "stdafx.h"
int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
while(1)
Sleep(100);
 return 0;
}
怎么样够简单吧,是不是觉得奇怪,怎么没有窗口,因为窗口要自己创建,不像控制台程序,只要一运行便会有窗口。虽然没有窗口,但你创建了一个进程,打开任务管理器,可以找到你所创建的那个进程,其实也没什么奇怪的,像WINDOWS本身的一些系统服务,也是只有进程,没有窗口的像spoolsv.exe,svchost.exe。
那要如何创建一个窗口呢?要创建一个窗口,就必须要向系统提供窗口的信息,如你要创建的窗口名字叫什么,窗口图标是什么,窗口大小,窗口背景色等,不然,系统怎么给你创建窗口呢?所以为了方便,VC就定义了一个结构,专门用存储窗口信息。
现给出这个结构的定义。
  typedef struct _WNDCLASS { 
    UINT style; //描述类风格
    WNDPROC lpfnWndProc;  //窗口处理函数
    int cbClsExtra; //表示窗口类结构之后分配的额外的字节数。系统将该值初始化为0
    int cbWndExtra; //表示窗口实例之后分配的额外的字节数。系统将该值初始化为0
    HINSTANCE hInstance;// 应用程序实例句柄由WinMain函数传进来 
    HICON hIcon; //窗口图标句柄 
    HCURSOR hCursor; //窗口光标句柄
    HBRUSH hbrBackground; //画刷句柄
    LPCTSTR lpszMenuName; //窗口菜单名
    LPCTSTR lpszClassName; //窗口类名
    } WNDCLASS, *PWNDCLASS;
好了,如果我们已经把窗口信息填好了,那我们要怎样把这个信息告诉系统呢,也就是把要创建窗口的信息传给系统。这里我们调用RegisterClass函数就能实现这个功能。注册完窗口,我们就要创建窗口,用CreateWindow函数就能实现,不要问为什么注册窗口后直接显示不就行了,还要搞什么创建窗口。这我也不知道,反正你只要记住这格式就行了,硬式规定的,你想创建一个窗口,就必须按这些步骤来。
好了,窗口创建了,我们就要调用ShowWindow函数显示窗口,然后用UpdateWindow函数刷新一下,确保窗口能立即显示。
以下详细实现代码:
#include "stdafx.h"
#include
int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
  WNDCLASS wndcls; //定义一个存储窗口信息WNDCLASS变量
  wndcls.cbClsExtra=0; //默认为0
  wndcls.cbWndExtra=0; //默认为0
  wndcls.hbrBackground=(HBRUSH)GetStockObject(GRAY_BRUSH); //背景画刷
  wndcls.hCursor=LoadCursor(NULL,IDC_CROSS); //十字光标
  wndcls.hIcon=LoadIcon(NULL,IDI_ERROR); //窗口图标
  wndcls.hInstance=hInstance;   //应用程序实例句柄由WinMain函数传进来 
  wndcls.lpfnWndProc=NULL; //窗口消息处理函数
  wndcls.lpszClassName="windowclass"; //窗口类名
  wndcls.lpszMenuName=NULL; //窗口菜单名,没有菜单,为NULL
  wndcls.style=CS_HREDRAW | CS_VREDRAW;//窗口类型,CS_HREDRAW和CS_VERDRAW 表明
  //当窗口水平方向垂直方向的宽度变化时重绘整个窗口
  RegisterClass(&wndcls); //把窗口信息提交给系统,注册窗口类
  HWND hwnd; //用以存储CreateWindow函数所创建的窗口句柄
   hwnd=CreateWindow("windowclass","first windows", 
  WS_OVERLAPPEDWINDOW,0,0,600,400,NULL,NULL,hInstance,NULL);//创建窗口
   ShowWindow(hwnd,SW_SHOWNORMAL);//窗口创建完了,显示它
   UpdateWindow(hwnd); //更新窗口,让窗口毫无延迟的显示
  return 0;
}
是不是出错了,内存不能读取,为什么了呢,因为你创建的窗口没有消息处理函数,windows系统当然不允许这样一个窗口存在,对按键,鼠标都没有反应,这样的窗口是没有实际意义的。  wndcls.lpfnWndProc=NULL; //窗口消息处理函数,就是前面这句,必须要填
窗口过程(消息)处理函数,那这个函数是怎样定义的呢,像WinMain一样,它也有固定的格式。
窗口过程处理函数的格式:LRESULT CALLBACK WinSunProc(HWND wnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
下面的这个是一个窗口创建的完整例子:
#include "stdafx.h"
#include
LRESULT CALLBACK WinSunProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
 if(uMsg==WM_LBUTTONDOWN) MessageBox(NULL,"kdjfkdf","Kjdfkdfj",MB_OK);//处理鼠标按下消息,弹出消息框
 return DefWindowProc(hwnd,uMsg,wParam,lParam); //未处理的消息通过DefWindowProc函数交给系统处理
}
int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
  WNDCLASS wndcls; //定义一个存储窗口信息WNDCLASS变量
  wndcls.cbClsExtra=0; //默认为0
  wndcls.cbWndExtra=0; //默认为0
  wndcls.hbrBackground=(HBRUSH)GetStockObject(GRAY_BRUSH); //背景画刷
  wndcls.hCursor=LoadCursor(NULL,IDC_ARROW); //光标
  wndcls.hIcon=LoadIcon(NULL,IDI_ERROR); //窗口图标
  wndcls.hInstance=hInstance;   //应用程序实例句柄由WinMain函数传进来 
  wndcls.lpfnWndProc=WinSunProc; //窗口消息处理函数
  wndcls.lpszClassName="windowclass"; //窗口类名
  wndcls.lpszMenuName=NULL; //窗口菜单名,没有菜单,为NULL
  wndcls.style=CS_HREDRAW | CS_VREDRAW;//窗口类型,CS_HREDRAW和CS_VERDRAW 表明
  //当窗口水平方向垂直方向的宽度变化时重绘整个窗口
  RegisterClass(&wndcls); //把窗口信息提交给系统,注册窗口类
  HWND hwnd; //用以存储CreateWindow函数所创建的窗口句柄
   hwnd=CreateWindow("windowclass","first windows", 
  WS_OVERLAPPEDWINDOW,0,0,600,400,NULL,NULL,hInstance,NULL);//创建窗口
   ShowWindow(hwnd,SW_SHOWNORMAL);//窗口创建完了,显示它
   UpdateWindow(hwnd); //更新窗口,让窗口毫无延迟的显示
   MSG msg;//消息结构类型
   while(GetMessage(&msg,NULL,0,0))//获取消息
   {
    //TranslateMessage(&msg); //此函数用于把键盘消息(WM_KEYDOWN,WM_KEYUP)转换成字符消息WM_CHAR
    DispatchMessage(&msg); //这个函数调用窗口过程处理函数,并把MSG里的信息处理后传给过程函数的四个参数
 }
  return 0;
}
WinSunProc函数的四个参数,分别对应着SendMessage函数四个参数,详情参见SendMessage函数参数解释。
MSG类型解释 :
结构定义:
typedef struct tagMSG 
       {
        HWND hwnd;//hwnd表示消息将要发送给的窗口句柄
       UINT message;//消息类型,如WM_WMCLOSE,WM_CHAR,WM_LBUTTONDOWN,参见消息表
       WPARAM wParam;//消息附带信息,取值的意思具体依据消息类型而定
       LPARAM lParam;//消息附带信息,取值的意思具体依据消息类型而定
       DWORD time;//消息的发送时间,不常用
       POINT pt;//消息发送时,鼠标所在的位置,不常用
       }MSG;
大家试着把上面的例子运行一遍,然后关掉窗口,再运行一遍,是不是出错了,因为前一个程序虽然窗口关闭了,但进程还在运行,还记得那个循环语句吗?while(GetMessage(&msg,NULL,0,0))就是这个。只要条件成立,进程就会一直运行下去。如何让这个循环结束呢?用 PostQuitMessage(0); 这个语句就行了,参数0表示给自身窗口发送一个退出消息,当GetMessage函数接到PostQuitMessage函数发出的消息后,就会返回0值。
如在窗口过程函数中处理窗口关闭WM_CLOSE消息:if(uMsg==WM_CLOSE)PostQuitMessage(0); 这样只要一关闭窗口,它的进程也会结束。
接下来解释一下CreateWindow函数参数的意思,函数定义
HWND CreateWindow(LPCTSTR lpClassName,//窗口类名,应与WNDCLASS结构里的成员lpszClassName一致
LPCTSTR lpWindowName,,//窗口标题名
DWORD dwStyle,//窗口的风格,取值参见表Style
int x,
int y,//x,y表示所创建窗口左上角位置
int nWidth,
int nHeight,//nWidth,nHeight表示窗口的宽高
HWND hWndParent,//父窗口句柄,如果不是子窗口,这里取值为NULL
HMENU hMenu,//菜单句柄,没菜单的话,取NULL值
HANDLE hlnstance,//对应着WinMain函数的第一个参数
LPVOID lpParam);//NULL
表Style:(参考:百度)
WS_BORDER:创建一个单边框的窗口。   
WS_CAPTION:创建一个有标题框的窗口(包括WS_BODER风格)。
WS_CHILD:创建一个子窗口。这个风格不能与WS_POPUP风格合用。
WS_CHLDWINDOW:与WS_CHILD相同。
WS_CLIPCHILDREN:当在父窗口内绘图时,排除子窗口区域。在创建父窗口时使用这个风格。   
WS_CLlPBLINGS;排除子窗口之间的相对区域,也就是,当一个特定的窗口接收到WM_PAINT消息时,WS_CLIPSIBLINGS风格将所有层叠窗口排除在绘图之外,只重绘指定的子窗口。如果未指定WS_CLIPSIBLINGS风格,并且子窗口是层叠的,则在重绘子窗口的客户区时,就会重绘邻近的子窗口。
WS_DISABLED:创建一个初始状态为禁止的子窗口。一个禁止状态的窗口不能接受来自用户的输入信息.
WS_DLGFRAME:创建一个带对话框边框风格的窗口。这种风格的窗口不能带标题条。
WS_GROUP:指定一组控制的第一个控制。这个控制组由第一个控制和随后定义的控制组成,自第二个控制开始每个控制,具有WS_GROUP风格,每个组的第一个控制带有WS_TABSTOP风格,从而使用户可以在组间移动。用户随后可以使用光标在组内的控制间改变键盘焦点。   
WS_HSCROLL:创建一个有水平滚动条的窗口。   
WS_ICONIC:创建一个初始状态为最小化状态的窗口。
与WS_MINIMIZE风格相同。   
WS_MAXIMIZE:创建一个初始状态为最大化状态的窗口。   
WS_MAXIMIZEBOX:创建一个具有最大化按钮的窗口。该风格不能与WS_EX_CONTEXTHELP风格同时出现,同时必须指定WS_SYSMENU风格。   
WS_OVERLAPPED:产生一个层叠的窗口。一个层叠的窗口有一个标题条和一个边框。与WS_TILED风格相同。  WS_OVERLAPPEDWINDOW:创建一个具有WS_OVERLAPPED,WS_CAPTION,WS_SYSMENU WS_THICKFRAME,WS_MINIMIZEBOX,WS_MAXIMIZEBOX风格的层叠窗口,与WS_TILEDWINDOW风格相同。  WS_POPUP;创建一个弹出式窗口。该风格不能与WS_CHLD风格同时使用。   
WS_POPUWINDOW:创建一个具有WS_BORDER,WS_POPUP,WS_SYSMENU风格的窗口,WS_CAPTION和WS_POPUPWINDOW必须同时设定才能使窗口某单可见。   
WS_SIZEBOX:创建一个可调边框的窗口,与WS_THICKFRAME风格相同。   
WS_SYSMENU:创建一个在标题条上带有窗口菜单的窗口,必须同时设定WS_CAPTION风格。   
WS_TABSTOP:创建一个控制,这个控制在用户按下Tab键时可以获得键盘焦点。按下Tab键后使键盘焦点转移到下一具有WS_TABSTOP风格的控制。   
WS_THICKFRAME:创建一个具有可调边框的窗口,与WS_SIZEBOX风格相同。   
WS_TILED:产生一个层叠的窗口。一个层叠的窗口有一个标题和一个边框。
与WS_OVERLAPPED风格相同。   
WS_TILEDWINDOW:创建一个具有WS_OVERLAPPED,WS_CAPTION,WS_SYSMENU,WS_THICKFRAME,WS_MINIMIZEBOX,WS_MAXMIZEBOX风格的层叠窗口。与WS_OVERLAPPEDWINDOW风格相同。  
WS_VISIBLE创建一个初始状态为可见的窗口。   
WS_VSCROLL:创建一个有垂直滚动条的窗口。
 第二十二个GetMessage获取窗口消息
参照CreateWindow函数例子,以后的例子可能是在控制台下,也可能是Win32 Application,大家以后根据主函数判断该建什么工程。
第二十三个RegisterClass注册窗口类,参照CreateWindow
第二十四个UpdateWindow参照CreateWindow
第二十五个DispatchMessage参照CreateWindow
第二十六个LoadCursorFromFile从磁盘加载一个光标文件,函数返回该光标句柄
假设e盘下有一个名为a.cur的光标文件。
HCURSOR cursor//定义一个光标句柄,用于存放LoadCursorFromFile函数返回的光标句柄
cursor=LoadCursorFromFile("e:\\a.cur");
获得了光标句柄有什么用呢?看一下窗口类WNDCLASS里的hCursor成员,这个成员也是一个光标句柄,明白了吧!
第二十七个CreateSolidBrush创建一个画刷,函数返回画刷句柄
HBRUSH hbr=CreateSolidBrush(RGB(12,172,59));//三个数字分别表明RGB的颜色值,RGB根据三种颜色值返回一个COLORREF类型的值
第二十八个LoadImage装载位图、图标、光标函数
函数定义:HANDLE LoadImage(HINSTANCE hinst,LPCTSTR lpszName,UINT uType,int cxDesired,int CyDesired,UINT fuLoad)
这里我们只要这个函数的几个简单功能:从磁盘加载位图,从磁盘加载图标,从磁盘加载光标。所以第一个参数hinst我们不用管它,直接填NULL就行,第二个参数lpszName是图片文件所在路径名,第三个参数uType指明要加载的是什么类型的图片,
是位图(填IMAGE_BITMAP),还是光标(填IMAGE_CURSOR),还是图标(填IMAGE_ICON)。第四个cxDesired和第五个参数CyDesired,指定要加载的图片的宽高(可以放大光标,或者缩小),如果加载的是位图的话,则两个参数必须为0,第六个参数fuLoad表示以何种方式加载文件,这里我们是从磁盘加载文件,所以填LR_LOADFROMFILE;
好了,假设e盘下有一个c.cur和i.ico文件。例子:设置窗口图标和光标,还有背景色
#include "stdafx.h"//这个头文件是编译器自动生成的,不是空工程,都会有,
//如果是直接建C++源文件,包含这个头文件,会出错
#include  
#include  
LRESULT CALLBACK WinSunProc( 
  HWND hwnd,      // handle to window 
  UINT uMsg,       // message identifier 
  WPARAM wParam,  // first message parameter 
  LPARAM lParam   // second message parameter 
); //窗口过程函数声明
int WINAPI WinMain( 
  HINSTANCE hInstance,      // handle to current instance 
  HINSTANCE hPrevInstance,    // handle to previous instance 
  LPSTR lpCmdLine,           // command line 
  int nCmdShow                // show state 


  //设计一个窗口类 
  WNDCLASS wndcls; 
  wndcls.cbClsExtra=0; 
  wndcls.cbWndExtra=0; 
  wndcls.hbrBackground=CreateSolidBrush(RGB(12,172,59));//画刷
  wndcls.hCursor=(HCURSOR)LoadImage(NULL,"e:\\c.cur",IMAGE_CURSOR,24,24,LR_LOADFROMFILE);//加载光标
  wndcls.hIcon=(HICON)LoadImage(NULL,"e:\\i.ico",IMAGE_ICON,48,48,LR_LOADFROMFILE);//加载图标
  wndcls.hInstance=hInstance;   //应用程序实例句柄由WinMain函数传进来 
  wndcls.lpfnWndProc=WinSunProc; //定义窗口处理函数
  wndcls.lpszClassName="windowclass"; 
  wndcls.lpszMenuName=NULL; 
  wndcls.style=CS_HREDRAW | CS_VREDRAW; 
  RegisterClass(&wndcls); 
  
  //创建窗口,定义一个变量用来保存成功创建窗口后返回的句柄 
  HWND hwnd; 
  hwnd=CreateWindow("windowclass","first window", 
WS_OVERLAPPEDWINDOW,0,0,600,400,NULL,NULL,hInstance,NULL);
 //显示及刷新窗口 
  ShowWindow(hwnd,SW_SHOWNORMAL); 
  UpdateWindow(hwnd);
  //定义消息结构体,开始消息循环 
  MSG msg; 
  while(GetMessage(&msg,NULL,0,0)) 
  { 
    TranslateMessage(&msg); 
    DispatchMessage(&msg); 
  } 
  return msg.wParam; 

 
//编写窗口过程函数 
LRESULT CALLBACK WinSunProc( 
  HWND hwnd,      // handle to window 
  UINT uMsg,      // message identifier 
  WPARAM wParam,  // first message parameter 
  LPARAM lParam   // second message parameter 


  switch(uMsg) 
  { 
  case WM_CHAR: //字符消息
    char szChar[20]; 
    sprintf(szChar,"char code is %c",wParam); 
    MessageBox(hwnd,szChar,"char",0); 
    break; 
   case WM_LBUTTONDOWN: //鼠标左键按下消息
    MessageBox(hwnd,"mouse clicked","message",0); 
    break; 
  case WM_CLOSE: 
    if(IDYES==MessageBox(hwnd,"是否真的结束?","message",MB_YESNO))
    { 
      DestroyWindow(hwnd); //销毁窗口,并发送WM_DESTROY消息给自身窗口
    } 
    break; 
  case WM_DESTROY:
    PostQuitMessage(0); 
    break; 
  default: 
    return DefWindowProc(hwnd,uMsg,wParam,lParam); 
  } 
  return 0; 
}
第二十九个GetDC根据窗口句柄获取设备上下文(DC)返回DC句柄
得到了一个窗口的设备上下文,就可以进行画图操作了,像画圆,画正方形,显示图片等函数都是要设备上下文(DC)句柄做参数的。
HDC dc//定义一个DC句柄
HWND wnd=FindWindow(NULL,"无标题.txt - 记事本");//获取窗口句柄
dc=GetDC(wnd)//获取这个窗口的设备上下文
第三十个Rectnagle在窗口中画一个矩形
以"无标题.txt - 记事本"窗口为例,在这个窗口简单的画一个矩形
#include
void main()
{
 HDC dc;
 HWND wnd=FindWindow(NULL,"无标题.txt - 记事本");
 dc=GetDC(wnd);//获取窗口设备上下文(DC)
 while(1)//用循环语句重复画,是为了确保不会被窗口刷新给刷掉
 {
 Rectangle(dc,50,50,200,200);//画一个矩形
 Sleep(200);
 }
}
第三十个CreateToolhelp32Snapshot给当前进程拍一个照
HANDLE hProcessSnap=::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
//记住这种格式就行了,返回的句柄,存储有进程信息,可以用Process32Firs函数找出来。
第三十一个Process32First根据CreateToolhelp32Snapshot函数返回的句柄获取进程信息
结合Process32Next函数使用,有点像文件寻找函数。
看完整例子:显示系统进程名,以及进程ID号
#include
#include//声明快照函数的头文件
#include
int main()
{
 PROCESSENTRY32 pe32;//进程的信息将会存储在这个结构里
 //在使用这个结构之前,先设置它的大小
 pe32.dwSize=sizeof(pe32);
 //给系统内的所有进程拍一个快照
 HANDLE hProcessSnap=::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
 BOOL bMore=::Process32First(hProcessSnap,&pe32);//第一次查找
 while(bMore)
 {
  printf("进程名称:%s\n",pe32.szExeFile);//szExeFile是进程名
  printf("进程ID号:%u\n\n",pe32.th32ProcessID);//th32ProcessID是进程ID号
  bMore=::Process32Next(hProcessSnap,&pe32);//寻找下个进程,函数返回0,则没有进程可寻
 }
 return 0;
}
第三十二个OpenProcess根据进程ID号获得进程句柄,句柄通过函数返回
函数定义:HANDLEOpenProcess( DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId);
第一个参数不要管它,填PROCESS_ALL_ACCESS,第二个参数也一样,填FALSE,那最后一个参数就是进程ID号。
第三十三个TerminateProcess结束一个进程(需进程句柄做参数)
该函数只有两个参数,第一个是进程句柄,第二个填0就行了。
现在给个例子:假设当前有一个进程名为abc.exe的进程正在运行,编一个程序结束它。
#include
#include//声明快照函数的头文件
int main(int argc,char *argv[])


 PROCESSENTRY32 pe32;
 //在使用这个结构之前,先设置它的大小
 pe32.dwSize=sizeof(pe32);
 //给系统内的所有进程拍一个快照
 HANDLE hProcessSnap=::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
 //遍历进程快照,轮流显示每个进程的信息
 BOOL bMore=::Process32First(hProcessSnap,&pe32);
 while(bMore)
 {
      if(strcmp("abc.exe",pe32.szExeFile)==0)//如果找到进程名为abc.exe
   {
    HANDLE hProcess=OpenProcess(PROCESS_ALL_ACCESS,FALSE,pe32.th32ProcessID);//获取句柄
     ::TerminateProcess(hProcess,0);//结束它
   }
  bMore=::Process32Next(hProcessSnap,&pe32);//寻找下一个
 }
 return 0;
}
上面的这个例子,只能结束普通权限进程,如果为系统进程的话,则没有用,结束不了。在后面的提升权限函数,会有例子说明如何结束系统进程。
第三十四个CreatePen创建一个画笔(返回画笔句柄)
函数定义:BOOL CreatePen(int nPenStyle, int nWidth, COLORREF crColor);
第一个参数,表示是什么类型的线,取值有以下:
 如创建一个画笔:HPEN pen=CreatePen(PS_SOLID,3,RGB(255,78,99));
PS_SOLID  画笔画出的是实线   PS_DASH 画笔画出的是虚线(nWidth必须是1) PS_DOT 画笔画出的是点线(nWidth必须是1)
PS_DASHDOT 画笔画出的是点划线(nWidth必须是1) PS_DASHDOTDOT 画笔画出的是点-点-划线(nWidth必须是1)
第二个参数是画笔的宽度,第三个参数是画笔的颜色,COLORREF类型可以RGB来获得如RGB(233,128,88);分别是红绿蓝。
第三十五个CreateSolidBrush创建一个画刷
只有一个COLORREF类型的参数
HBRUSH brush=CreateSolidBrush(RGB(22,182,111));
第三十六个SelectObject把GDI对象选入相应的DC中
像画笔(句柄HPEN),画刷(HBURSH),位图(HBITMAP)等都是GID对象。因为画图函数,如画圆,画矩形,画直线,它们所画出图形,默认属性都是不变的,如线的宽度。那么想要改变画出来时线的宽度,比如我想画出来的图形它的线条宽度为5(像素),那么就要创建一个宽度为5的画笔,然后再通过SelectObject函数,给这个画笔选入,就可以了.
接下举个例子:SelectObject应用

#include "stdafx.h"
#include
LRESULT CALLBACK WinSunProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
 static HPEN pen=CreatePen(PS_SOLID,3,RGB(255,78,99));//创建画笔
 static HBRUSH brush=CreateSolidBrush(RGB(22,182,111));//创建画刷
 if(uMsg==WM_PAINT)//窗口需要重画的时候
 {
    HDC hDC; 
    PAINTSTRUCT ps; 
    hDC=BeginPaint(hwnd,&ps);    //BeginPaint只能在响应WM_PAINT,不能用GetDC获取设备上下文
 SelectObject(hDC,pen);//选入画笔
 SelectObject(hDC,brush);//选入画刷
 Rectangle(hDC,100,100,200,200);
    EndPaint(hwnd,&ps); 
}
else if(uMsg==WM_CLOSE)//用户关闭了窗口
 DestroyWindow(hwnd);//销毁窗口,并发送WM_DESTROY消息
else if(uMsg==WM_DESTROY)//如果窗口被销毁
 PostQuitMessage(0);//让进程退出
 return DefWindowProc(hwnd,uMsg,wParam,lParam); //未处理的消息通过DefWindowProc函数交给系统处理
}
int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
  WNDCLASS wndcls; //定义一个存储窗口信息WNDCLASS变量
  wndcls.cbClsExtra=0; //默认为0
  wndcls.cbWndExtra=0; //默认为0
  wndcls.hbrBackground=(HBRUSH)GetStockObject(GRAY_BRUSH); //背景画刷
  wndcls.hCursor=LoadCursor(NULL,IDC_ARROW); //光标
  wndcls.hIcon=LoadIcon(NULL,IDI_ERROR); //窗口图标
  wndcls.hInstance=hInstance;   //应用程序实例句柄由WinMain函数传进来 
  wndcls.lpfnWndProc=WinSunProc; //窗口消息处理函数
  wndcls.lpszClassName="windowclass"; //窗口类名
  wndcls.lpszMenuName=NULL; //窗口菜单名,没有菜单,为NULL
  wndcls.style=CS_HREDRAW | CS_VREDRAW;//窗口类型,CS_HREDRAW和CS_VERDRAW 表明
  //当窗口水平方向垂直方向的宽度变化时重绘整个窗口
  RegisterClass(&wndcls); //把窗口信息提交给系统,注册窗口类
  HWND hwnd; //用以存储CreateWindow函数所创建的窗口句柄
   hwnd=CreateWindow("windowclass","first windows", 
  WS_OVERLAPPEDWINDOW,0,0,600,400,NULL,NULL,hInstance,NULL);//创建窗口
   ShowWindow(hwnd,SW_SHOWNORMAL);//窗口创建完了,显示它
   UpdateWindow(hwnd); //更新窗口,让窗口毫无延迟的显示
   MSG msg;//消息结构类型
   while(GetMessage(&msg,NULL,0,0))//获取消息
   {
    //TranslateMessage(&msg); //此函数用于把键盘消息(WM_KEYDOWN,WM_KEYUP)转换成字符消息WM_CHAR
    DispatchMessage(&msg); //这个函数调用窗口过程处理函数,并把MSG里的信息处理后传给过程函数的四个参数
 }
  return 0;
}
第三十七个 ReadProcessMemory根据进程句柄读取相应的一段内存(读其它进程里的内存)
函数定义:BOOL ReadProcessMemory(HANDLE hProcess,PVOID pvAddressRemote,PVOID pvBufferLocal,DWORD dwSize,
PDWORD pdwNumBytesRead);总共四个参数
第一个参数hProcess是远程进程句柄,被读取者 。第二个pvAddressRemote是远程进程中内存地址。 从具体何处读取
pvBufferLocal是本地进程中内存地址. 函数将读取的内容写入此处 ,dwSize是要读取的字节数。要读取多少 
pdwNumBytesRead是实际读取的内容(函数执行后,实际读了多少字节,将存储在该变量里)
远程进程的内存地址是什么意思呢,比如我现在定义一个变量a,int a;就是了,大家知道int型是占四个字节的,也就是说如果a变量所占的内存起始地址是0x1234,那么变量a就占用0x1234,0x1235,0x1236,0x1237这四个字节,这四个字节的内容决定了a变量的值。
好了知道了这个,我们就来举个例子,读取另一个进程里一个变量的值:需设计两个程序,一个用于读(Read)一个用于被读(BeRead);
那么要如何获得另一个进程中一个变量的地址呢?这里我们用一个简单的方法,让另一个进程自己去获取,然后输出地址值。
被读的程序代码如下:假设该进程名为:BeRead.exe
#include
int main()
{
 int a=10;//要读取的变量。
  printf("%x\n",&a);//输出这个变量的起始地址,假设输出为12ff7c
  while(1)
  {
   Sleep(1000);
  }
 return 0;
}
必须先让这个程序运行,然后根据输出的地址值,才能在下面的程序填入地址值。
读取的程序代码如下:
#include
#include
#include
int main()
{
//先要获取进程句柄,如何获取,参照TerminateProcess函数,结束一个进程
 HANDLE ReProcess;
 PROCESSENTRY32 pe32;
 pe32.dwSize=sizeof(pe32);
 HANDLE hProcessSnap=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
 BOOL bMore=::Process32First(hProcessSnap,&pe32);
 while(bMore)
 {
  if(strcmp(pe32.szExeFile,"BeRead.exe")==0)//如果是BeRead.exe
  {
   ReProcess=::OpenProcess(PROCESS_ALL_ACCESS,FALSE,pe32.th32ProcessID);//获取该进程句柄
   break;
  }
  bMore=Process32Next(hProcessSnap,&pe32);
 }
 int *ReAddress=(int *)0x12ff7c;//要读取的内存的地址值
 int  *p=new int;
    unsigned long size;
 ReadProcessMemory(ReProcess,ReAddress,p,4,&size);//读取BeRead进程的内存
 printf("%d\n",*p);//输出读取来的值
 return 0;
}
第三十八个WriteProcessMemory根据进程句柄写入相应的一段内存(写入其它进程里的内存)
这个函数里的参数跟ReadProcessMemory函数参数意思一样,只不过一个是写,一个是读。
下面直接举个例子,形式跟读内存函数的例子一样。
被写的程序代码如下:假设该进程名为:BeWrite.exe
#include
int main()
{
 int a=10;
  printf("%x\n",&a);//假设输出为12ff7c
  while(1)
  { 
   printf("%d\n",a);//每隔一秒输出,查看值有没有改变
   Sleep(1000);
  }
 return 0;
}
写入的代码如下:
#include
#include
#include
int main()
{
 HANDLE ReProcess;
 PROCESSENTRY32 pe32;
 pe32.dwSize=sizeof(pe32);
 HANDLE hProcessSnap=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
 BOOL bMore=::Process32First(hProcessSnap,&pe32);
 while(bMore)
 {
  if(strcmp(pe32.szExeFile,"BeWrite.exe")==0)
  {
   ReProcess=::OpenProcess(PROCESS_ALL_ACCESS,FALSE,pe32.th32ProcessID);
   break;
  }
  bMore=Process32Next(hProcessSnap,&pe32);
 }
 int *ReAddress=(int *)0x12ff7c;
 int  *p=new int;
 *p=300;
    unsigned long size;
 WriteProcessMemory(ReProcess,ReAddress,p,4,&size);
 return 0;
}
第三十九个CreateThread创建一个线程(多线程)
线程是什么意思呢,代码是由线程来执行的,一个程序默认只有一个线程(主线程),打个比方,线程就好比一个人,而不同功能的代码或函数就好是一件件不同的事情,如洗碗,洗衣服,擦地。一个人要把这几种事情做完,可以有好几种方案,第一种就是,洗完碗,就去洗衣服,衣服洗完了,再去擦地。第二种就是:洗一分钟碗,再去洗一分钟衣服,再去擦一分钟,然后又去洗一分钟衣服.......直到做完。好了,现在你可以再创造一个人帮你做事,创造这个人后,你就叫他洗衣服,而你就洗碗,这样两件事就可以同时被做了。而这里的创造一个人指的就是CreateThread函数。
函数定义:HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,DWORD dwStackSize,LPTHREAD_START_ROUTINE lpStartAddress,LPVOID lpParameter,DWORD dwCreationFlags,LPDWORD lpThreadId);
该函数有六个参数,第一个参数不用管它,填NULL,第二个参数dwStackSize用于新线程的初始堆栈大小,默认为0,第三个lpStartAddress填函数名(指标),但这个函数必须是这种固定格式的DWORD _stdcall ThreadProc(LPVOID lpParameter),新的线程将会执行这个函数里面的代码,直到函数结束,线程死亡。第四个lpParameter是一自定义参数,用户可以通过这个参数,传递需要的类型,这个参数与线程函数的参数相对应。第五个dwCreationFlags填0表示立即执行,如果是CREATE_SUSPENDED表示挂起,直到用ResumeThread函数唤醒。第六个lpThreadId填NULL就行了。
现举个例子,两个线程同时每隔一秒输出一个数字,也就是一秒会有两数字输出。
#include
#include
DWORD _stdcall ThreadProc(LPVOID lpParameter)//线程执行函数
{
 int si=100;
 while(si>0)
 {
  printf("子线程输出数字:%d\n",si--);
  Sleep(1000);
 }
 return 0;
}
int main()
{
 int mi=0;
 CreateThread(NULL,0,ThreadProc,NULL,0,NULL);//创建一个线程,去执行ThreadProc函数
 while(mi<100)
 {
  printf("主线程输出数字:%d\n",mi++);
  Sleep(1000);
 }
 return 0;
}
第四十个GetCurrentProcessId获得当前进程ID
 DWORD currentPID;
 currentPID=::GetCurrentProcessId();//返回进程ID号
 cout<<currentPID<<endl;    

以上就介绍了VC/MFC的学习,希望对VC/MFC有兴趣的朋友有所帮助。了解更多内容,请关注职坐标编程语言VC/MFC频道!

本文由 @小标 发布于职坐标。未经许可,禁止转载。
喜欢 | 1 不喜欢 | 0
看完这篇文章有何感觉?已经有1人表态,100%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式AI+学习就业服务平台 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved