打印
[应用相关]

Win32 SDK菜鸟详细教程

[复制链接]
9234|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
gejigeji521|  楼主 | 2015-12-7 22:04 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
Win32 sdk学习感悟(1.1)------基础
    在学习win32 sdk编程之前,相信你已经会用c语言在dos下编程了。Api是windos封装的接口函数,我们要学会用它编程是一个漫长的过程,但是你直接去学习mfc,你会更加吃力。所以个人感觉在学mfc之前学习一下win32编程是为mfc打基础,这样以后学习mfc会相对容易的多。我写这**的目的只是想和大家一起进步,分享一下我对win32编程的理解,也是提高自己能力的一种方法吧。我尽我所能,希望能把我所知道的用最浅显直观的文字表达出来。所以有不当之处请原谅并希望你能指出。谢谢阅读。(同时说一句真心话,当你拿者一本书读不懂的时候,请你**下去。还不懂就反复看。或许你看的似懂非懂,那么过些天了,你再拿出来认真仔细的看。相信你在原来的基础上又有新的理解,那么你才会有所提高。)
                     一.。应用程序的运行机制
应用程序运行机制——不要被它给吓住了,我们在进行win32 sdk编程的时候,这是我们需要了解的一个重要问题,要不然怎么写出我们自己的应用程序了。显然应用程序运行机制就是告诉我们一个应用程序是怎样运行在系统里的。说得形象一些就是一个应用程序在系统里怎样“生存”。打个比方,我们人就是一个应用程序,我的生活的这个社会就是系统,我们要在这个社会里生存就要挣钱、工作、休息等。所以,你现在应该知道应用程序运行机制是个怎样的概念了吧。
上面说人和社会相当与应用程序和系统(这是个形象的比喻,便于你更好理解),我们要挣钱就要找到工作,有了工作我们就要有足够的时间去休息,这些都是有联系的,你会问:那应用程序和系统有什么联系呢? 好了,下面我们就来说说应用程序和系统的联系。
我们知道应用程序的运行是要在操作系统下才可以的(除非你写的程序是最底层的)。应用程序运行的时候,操作系统会自动为这个应用程序服务(当然有些需要我们自己写代码来实现,比如下面说的消息事件),这里所谓的服务是我们看不见的,也就是我们要了解的程序运行机制。比如我们的应用程序在点击鼠标左键会弹出一菜单,要实现这一过程那么我们写的应用程序必须向系统发送一个消息告诉它我们点了鼠标左键,然后再做什么事情等类似的一些事情(也就是事件)。在写程序时候我们只是用代码来完成这些事情,其他的工作都是系统自己干,所以我们不必很关心,只要把一些事情用代码表示出来就可以了。
好了,上面我只是让你对应用程序在系统里有个初步的了解,知道是怎么一会事,下面让我们来进一步了解一下。
你知道应用程序在系统里运行做的第一件事是什么吗?第二件事呢?第三 等等。一个应用程序出现在屏幕上,展现在我们眼前只是一瞬间,但是在我们win32 sdk下编写程序的时候。就不是一瞬间的事情了。那么要编写一个程序窗口有那些过程呢?或许你现在一定不知道,或许你看过其他的编程**,知道一点点但是又感觉这些知识点很乱,似懂非懂的感觉。不怕,往下看,我将会为你把思路理清晰。让你知道怎么回事
我们知道开发一个应用程序需要很多的代码。在这么多代码里有一个代码是最最重要的。那就是WinMain()函数。看上去它和c++在dos下编程里的Main()函数差不多,其实它们的作用是一样的。是一个应用程序的入口点。所以说它重要。(一个应用程序什么函数代码都可以不要,但是唯一这个函数一定要。)
      (解释什么是入口点:应用程序运行时系统会自动调用WinMain()这个函数,目的就是传递参数给这个函数。那么这个函数的功能是什么呢?说得简单易懂点就是一个告诉系统从这个函数开始读代码。上面不是说一个应用程序有许多代码吗?那么多代码系统怎么知道要从哪里读起走了?那么就是从WinMain()这个函数了。再打个比方,我们要上2楼,在1楼和2楼之间有许多道门,但是唯独一楼只有一道与外边相通的门。所以我们要上2楼,只有走这道门,所以这道门就叫2楼的入口点。所以WinMain()这个函数是应用程序的入口点。)
好了,现在知道系统从哪里读代码了,接下来我们就可以放心的写更多的代码让系统自己去读了。(注意:这里我说的系统读代码其实是让你更直观的去理解这些知识,在大脑里产生这个过程。我们都知道,我们写的代码在编译器编译的时候都转换成了二进制码。这里只是做个解释,以免读者误会,可以不必在意)
                                 二.一个应用程序的窗口
我们做一件事要有先后主次之分,同样要让一程序运行也是的。我们先从创建一窗口说起,因为再好的应用程序都需要通过窗口直观的显示与用户交互,这样才能让用户更简洁方便的使用程序完成想要完成的事情。
    我们要修一座楼房,第一步就是要先设计这个楼房的结构,要画平面图。创建一个窗口也是如此,所以要设计一个窗口。
当我们设计好楼房的平面图后不能立即就修楼房,因为还要到相关政府部门去申请,请求批准。那么我们设计好一个窗口后也不能立即的就显示出这个窗口了,要向系统注册我们所设计的这个窗口,目的是告诉系统我们要开始创建一个应用程序窗口了。
在我们向系统注册了我们设计的窗口后,我们就可以正式的创建窗口。至此我们才能在屏幕上显示我们创建的这个窗口。
总的来说你现在已经很清晰的知道了在win32 sdk下我们用c语言是怎么样才能创建一个窗口的了。在给大家理清一下思路:
我们要创建一个窗口就需要下面这些步骤:
1.    设计一个窗口类
2.    注册这个窗口类
3.    显示并随时更新这个窗口
好了,现在你应该对win32 sdk编程有了一个更清晰的认识了。至少你应该知道一些在win32 sdk编程下的一些最最基本的知识。可以说你如果懂了我上面说的每一句话,那么你就有入门的感觉了。至于窗口如何发送消息等,还有程序入口函数、创建窗口所用的这些函数的具体用法,我会在后面陆续的说明。你也不要埋怨看了这么多文字连一个函数都没有讲到,感觉没学到什么。别急,静下心来体会一下上面这些文字,一定会给你带来收获的。编程这东西不能速成,也没有速成的办法,那是自己慢慢积累起来的东西,所以要多想、多练。其实上面所说的都是应该掌握的,因为那些就是一些理论知识,虽说我能力有限,但相信这对初学的你有所帮助,我的目的也就达到了。有了这些知识你学习win32 编程就很轻松,思路也很清晰,不会一头雾水。你要相信我也是过来人,我只是想竟我所能,把我当初学的、认识到的、怎样理解的呈现出来和大家一起分享。要是有不当之处还请读者指教,一起探讨。共同努力。

沙发
gejigeji521|  楼主 | 2015-12-7 22:05 | 只看该作者
今天在以前学习的基础上认真的理解了WinMain函数的运行机制和原理,并且有了一定的了解。当然在以后的学习中也要认真的思考和体会。
  下面是我自己80%写的完整程序。
  
#include <windows.h>
#include <stdio.h>
int WINAPI WinMain(
    HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nShowCmd
);
LRESULT CALLBACK WndProc(
        HWND hwnd,
  UINT uMsg,
  WPARAM wParam,
  LPARAM lParam
);
int WINAPI WinMain(
    HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nShowCmd
)
{
HWND hwnd;
WNDCLASS wnd;
wnd.cbClsExtra=0;
wnd.cbWndExtra=0;
wnd.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH);
wnd.hCursor=LoadCursor(hInstance,IDC_ARROW);
wnd.hIcon=LoadIcon(hInstance,IDI_APPLICATION);
wnd.hInstance=hInstance;
wnd.lpfnWndProc=WndProc;
wnd.lpszClassName="Win32";
wnd.lpszMenuName=NULL;
wnd.style=CS_HREDRAW | CS_VREDRAW;
RegisterClass(&wnd);
hwnd=CreateWindow("Win32","好好学习",WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,
  CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,hInstance,NULL);
ShowWindow(hwnd,SW_SHOWNORMAL);
UpdateWindow(hwnd);
MSG msg;
while(GetMessage(&msg,NULL,0,0))
{
  TranslateMessage(&msg);
  DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WndProc(
        HWND hwnd,
  UINT uMsg,
  WPARAM wParam,
  LPARAM lParam
)
{
switch(uMsg)
{
case WM_LBUTTONDOWN:
  MessageBox(hwnd,"hello world","Test",MB_YESNO);
  HDC hdc;
  hdc=GetDC(hwnd);
  TextOut(hdc,0,100,"好好学习",strlen("好好学习"));
  ReleaseDC(hwnd,hdc);
  break;
case WM_PAINT:
  PAINTSTRUCT pst;
  HDC hDC;
  hDC=BeginPaint(hwnd,&pst);
  TextOut(hDC,0,50,"Come on",strlen("Come on"));
  EndPaint(hwnd,&pst);
  break;
case WM_CHAR:
  char szchar[20];
  sprintf(szchar,"the value is %d",wParam);
  MessageBox(hwnd,szchar,"ShowInfo",MB_OK);
  break;
case WM_CLOSE:
  if(IDYES==MessageBox(hwnd,"您确定退出程序?","退出程序",MB_YESNO))
  {
   DestroyWindow(hwnd);
  }
  break;
case WM_DESTROY:
  PostQuitMessage(0);
  break;
default:
  return DefWindowProc(hwnd,uMsg,wParam,lParam);
}
return 0;
}
  其中用到了很多的Win32 API函数,如GetStockObject(),GetDC(),BeginPaint(),
TranslateMessage(),DestroyWindow(),DefWindowProc(),PostQuitMessage()。另外,还有一些系统消息。如:WM_PAINT,WM_CHAR,WM_CLOSE等。这对刚开始学习Windows编程的学习者,希望能够有所帮助。

使用特权

评论回复
板凳
gejigeji521|  楼主 | 2015-12-7 22:05 | 只看该作者
第一篇 预备知识 白云小飞 1 说在前面 由于VC6及MFC的特点,我们许多人从标准C++学习到VC6MFC应用程序的编程学习的过度会有一个很大的夸跃,从而感到非常的吃力。 究其原因之一:MFC类库设计虽然精巧,但我们在使用MFC设计程序时,会发现MFC到处是API函数的影子。MFC并没有象Delphi的VCL类库,VB的控件库一样封装得让人几乎完全不用知道还有Win32API函数及其操作原理,所以要想利用VC6的MFC编程,我认为就一定要先学习如何直接用Win32API函数来编程。对API编程中的一些关键的概念和原理要有一定认识,这样才会有一个比较平滑的过渡。以上就是我写这个系列的初衷。 2 我假设你已有的知识: 这里我假设你已经掌握了如下的知识,如果你在如下方面知识有点不太清楚,那要去补一补罗,否则你看到相关的内容时会有麻烦的。 下面说是我对你知识的假设: 2.1 Windows系统的文件、文件夹、路径的概念 2.2 C语言的基本知识(基本以等级考试二级C语言为准,还要有所扩充) 2.2.1 指针的概念。 2.2.2 函数指针概念。 2.2.3 各种自定义类型(最重要的是struct类型)的概念。 2.2.4 要知道函数的各种参数传递形式(值、地址、引用传递)。 2.2.5 typedef及其应用。 2.2.6 #include及其应用。 2.2.7 十进制、二进制、十六进制。 2.2.8 按位与、或、非运算的实质。 2.2.9 宏定义概念、使用及意义。 (每个人总是学完了C或C++语法后才会开始用VC6进行Windows编程学习的。但是你的基础又是如何呢?这是一个关键。因此我对你的C知识做了具体的假设。) 2.3 会安装VC6.0并安装到一台机上 2.4 VC6编译界面的各组成部分及基本操作(至少会用VC6写控制台程序)。 2.5 VC6调试中至少要会设置断点哦。 (呵呵!我的要求不过份吧!) 3 还必须预备的知识: 以上知识是你看本系列的前提,不过我还要给你预备一下我们再这个阶段学习中会遇到的新东西。 3.1 你将会接触到的Win32API函数库: 以前的DOS下或Windows的控制台程序下,你要在显示器上输出文字,要用printf(),或cout的函数对象来完。但如果你要显示一个图形或图象或为你的程序设计一个图形化的操作界面等等的,那可就惨了,一切都要你自已完成。复杂得很了!(唉!谁叫DOS是字符界面的操作系统呢!) 现在好了,在Windows下编程你可就轻松得多了。因为Windows操作系统都为我们准备好了,它提供给我们多达数千个函数(啊!我要昏倒了。这么多的函数要学。),我们通过这些函数来操作Windows系统提供给我们的各种功能。比如我要在桌面上创建并显示一个窗口。就只要调用几个相关的被称为API的函数,让Windows来帮助我们完成这些事。我们是通过这些函数与Windows系统交互的,所以这些函数被称作Win32应用程序接口函数,简称Win32API函数。 请不用害怕哟!其实,这么多的函数我们不必都马上一一学过,只要掌握了不多的具有代表性的函数的使用方法,并知道大体API函数都提供了哪些功能就可以了。以后要用时再去查。 Window拥有现成的各种各样的系统功能,供我们的程序调用。那么又是通过什么方式来调用这些系统功能呢?原来,Window还现成提供一个接口,好让我们的程序来使用这些系统功能,这个结口就是Win32API函数了(注:API是应用程序接口的英文缩写)。Win32API函数是我们的应用程序与Windows系统交互的唯一途径。 我并不打算这时就介绍任何一个具体的API函数。你现在只要知道你又要接触一个函数库了——被称为Win32API的函数库,如同你以前所学的C/C++函数库。 哈哈,这真是太好了,我们不用再象DOS一样,自已来完成程序界面的绘制了。我们现在又增加一个全新的函数库,只要调用几个相关API函数,剩下的一切由Windows来完成就可以啦!(当然还有很多其它功能。) 3.2 “新”的数据类型: 学完C、C++之后,我们就可以开始进入VC6的Windows编程学习了。但是在接下来的学习中我们会发现在Windows编程中有许多“新”的数据类型。看下面: BOOL、BYTE、INT、UINT、WORD、DWORD、FLOAT、CHAR、LPSTR、HINSTANCE、HWND、HMENU、HICON等等。 你看这些大写的数据类型,你以前有见过吗?还有很多哦!我们以后的学习过程中还会见到的。(呵呵!你可要有思想准备了!) 这真是让我们初学者迷惑呀!难道VC6中对C/C++的基本数据类型又有重大的扩充了吗? 其实不用害怕,只是用新瓶装旧酒而已了。在VC6的windef.h头文件中已有这些定义: typedef int BOOL; typedef unsigned char BYTE; typedef int INT; typedef unsigned int UINT; typedef unsigned short WORD; typedef unsigned long DWORD; typedef float FLOAT; 在winnt.h中有 typedef long LONG; typedef char CHAR; typedef CHAR *LPSTR, *PSTR; 你看其中(粗体字)CHAR只不过是char 的别名而已,也就是说它们是等价的。只要你包含了相关的头文件,然后你就可以这样申明一个变量: INT i; //等同于int i; CHAR a; //等同于char a; LPSTR pa; //等同于char *pa; 明白了吗? 我想你一定会问:为什么要这样转义呢?我们直接用int 、unsighed int、char等等不就行了吗?我一句两句也说不清,你只要知道,微软这样做一定是要道理的。 哦!还有这些HINSTANCE、HWND、HMENU、HICON我没说呢!今后你还会见到许多这样以H为开头的数据类型,下面就让我在下一节的“句柄”概念中说给你听。 3.3 “句柄”概念 由windows系统创建出来的或加载的对象(如应用程序进程、线程、窗口、菜单、图标、光标等等的对象),windows系统都会分配给它们一个唯一的标识值,作为这些对象的标志,称之为句柄。我们程序中对这些对象的操作其实就是对其句柄的操作。请记住,句柄就是这些对象的“代号”了。 在编程序中,我们需要用相应的句柄变量来保存这些句柄值,那么用什么类型的句柄变量呢? 就是我们前面提到过的HINSTANCE、HWND。 像其它变量一样(如:int a;)申明句柄变量,如下: HINSTANCE hst; //hst变量可以保存某个应用程序实例(即一个进程)的句柄。 HWND hwFirst; //hwFrist变量可以保存某个窗体句柄。 HMENU hMenu; //hMenu变量可以保存某个菜单句柄。 HICON hIcon; //hIcon变量可以保存某个图标句柄。 具体的使用让我以后再慢慢与你道来啦。 那么这些类型的实质又是什么? 目前,它们都只是一个int类型(小语:我听说微软也许以后会改变它的类型)。不过不管怎样,你现在只要把HINSTANCE、HWND、HMENU、HICON当做是一个独立的数据类型就可以了。 3.4 消息标识 Windows系统是一个基于消息的系统。这样的机制导致我们的程序与以往DOS下的程序流程会有很大的不同。(这可是很考我们的智慧喽!) 从软件使用者角度看一个Win32窗口程序运行的过程: 1) 我们运行一个应用程序,程序创建并显示一个我们想要的程序窗口。 2) 当我们对窗口进行操作时(如单击、双击、右击、按下键盘、最大化、最小化、关闭窗口等等),程序会完成特定的操作,如:单击最大化、最小化按钮时,窗口会最大化、最小化操作;对窗口中菜单项的选取时,会完成该菜单的相应功能。 从程序员的角度看一个Win32窗口程序运行的过程: 1) 我们运行一个应用程序,程序中我们通过Win32API函数创建并显示一个我们想要的程序窗口。(由我们的程序来调用函数实现) 2) 当我们对窗口进行操作时(如单击、双击、右击、按下键盘、最大化、最小化、关闭窗口等等),窗口会自动产生一系列相应的消息(这是由操作系统实现的)。 3) 具体地讲:当我们改变窗口大小时,会产生WM_SIZE消息;单击关闭按钮关闭窗口时,会产生WM_CLOSE消息;选取某一菜单项时,会产生WM_COMMAND消息;按下键盘时,会产生WM_CHAR、WM_KEYDOWN、WM_KEYUP消息;单击鼠标左键时,会产生WM_LBUTTONUP、WM_LBUTTONDOWN消息等等。啊,很多很多,我也不必全部罗列出来了。(我说过了,这些都是由操作系统实现的) 4) windows系统会将这些消息排入我们窗口所在线程的消息队列中(你会明白线程是什么吗?)(也由Window操作系统实现),这样我们的程序才有机会获取并处理这些产生的消息。 5) 我们的程序可以通过Window操作系统提供的API函数来获取这些消息及相关的信息。然后通过我们学过的条件判断语句来判断是什么消息及其相关的操作信息并可编写相应的程序代码,从而实现对窗口操作的不同反应。(由我们的程序来实现) 看上述的过程描述,你可能要有点的抽象思维能力了。你现在只要有对程序流程有如上的大体认知就可以了。慢慢地我会将上述流程变成确实的程序代码噢! (等等,还是有个问题:这些WM_CLOSE、WM_COMMAND、WM_CHAR、WM_KEYDOWN、WM_KEYUP、WM_LBUTTONUP、WM_LBUTTONDOWN等等的以WM_开头的消息到底又是什么东西呢?) 看VC6的头文件winuser.h中的片段: …… #define WM_CLOSE 0x0010 …… #define WM_LBUTTONDOWN 0x0201 #define WM_LBUTTONUP 0x0202 #define WM_LBUTTONDBLCLK 0x0203 #define WM_RBUTTONDOWN 0x0204 …… #define WM_KEYDOWN 0x0100 #define WM_KEYUP 0x0101 #define WM_CHAR 0x0102 …… #define WM_INITDIALOG 0x0110 #define WM_COMMAND 0x0111 #define WM_SYSCOMMAND 0x0112 …… 哦!这些WM_开头的所谓的消息只不过是一系列16进制整型数值的符号常量而已。每一个不同的整型数值代表着一个窗口某一操作的标识,因此我们将这些数值或者说以WM_开头的符号常量称之为消息了。 也就说,我们在窗口中作各种不同的操作,Windows系统会产生各种相应的数值。我们就是通过条件语句比较这些数值来判断我们在窗口中所做的操作的。 3.5 资源标识 (你看我没完没了地介绍一个个概念,觉得烦不烦?不用你说,我自已也有点烦了。唉!不过这些似乎是必要的,所以我不得不**下去。不过,还好,剩下的不多了。) 那么VC6中资源是什么一种概念呢? 我们的程序中可能要用到各种图标(*.ico文件)、各种形状的鼠标(*.cur文件)、各种图像(*.bmp/*.gif等等)、各种声音(*.wav等)、各种菜单……,这些就是我们这里所说的资源了。 每一个要用到资源,我们都要给它分配一个编号或名称,作为这个资源的标识。之后我们的程序只是通过这个编号或名称来访问这些资源了。所以这些编号或名称我们称之为资源标识。好了,现在你也只要有了一个大体的映象就可以了,具体的形式和应用让我慢慢再与你说了。 (各位可以提出你的疑问,白云小飞一定会尽力回复的。) 啊!终于结束冗长的概念解说了,看到这里,请先回顾一下我们前面讲的东西。然后嘛——我们可以开工啦!。

使用特权

评论回复
地板
ddc21ic| | 2015-12-7 22:59 | 只看该作者
多谢分享!
建议楼主做成个文档,pdf也可以,这样阅读起来会方便些。
像楼上那样,读起来很费劲的。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

180

主题

2268

帖子

8

粉丝