关闭

开始写Win32 Application程序了

2823人阅读 评论(0) 收藏 举报

一、今天开始写Win32 Application 程序

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

这是主函数,是基于Win32 的应用程序的默认入口函数。

参数:hInstance       应用程序当前实例的句柄

      hPrevInstance :应用程序上一个实例的句柄,对于基于Win32的程序,该参数为空。

      如果需要检测是否有另外一个实例存在,调用CreatMutex函数创建一个独一无二的互斥命名,即使一个互斥命名已经存在,CreatMutex 也将会成功,但是GetLastError函数将会返回 ERROR_ALREADY_EXISTS,这就是说提示另外一个应用程序的实例已经存在,因为它先创建了一个互斥体。

         lpCmdLine :在命令行程序中,指向一个以空来结尾的字符串,不包含程序名。检索整个命令行,使用GetCommandLine函数。

         nCmdShow: :指定窗口如何显示,参数可以是下列值:

      

所代表的意义

SW_HIDE

隐藏该窗口激活另外一个窗口

SW_MINIMIZE

最小化指定得窗口,激活系统列表中得最上面的窗口

SW_RESTORE

激活并显示窗口。如果窗口最小化或者最大化,把窗口恢复到初始大小和初始位置。

SW_SHOW

以当前大小和位置激活窗口。

SW_SHOWMAXIMIZED

 

。。。。。。

 

返回值:

       如果函数成功,且当收到WM_PAINT消息时终止,它应该返回一个包含在消息的wParam参数中的exit值。如果函数在进入消息循环前终止,应该返回0

备注:要使用Windows的消息机制。


二、创建一个应用程序的步骤

首先设计一个窗口类,接着注册该窗口类,再创建该窗口,最后显示及更新。

1. 设计一个窗口类;

2. 注册窗口类;

3. 创建窗口;

4. 显示及更新窗口。

设计窗口类的过程即定义一个WNDCLASS 对象,给该对象的属性赋值。如下:

WNDCLASS 的相关信息:

这是一个结构体,包含了窗口类的属性,这些属性可以使用RegisterClass函数来注册。

该结构体已经被WNDCLASSEX函数所取代,注册函数也被RegisterClassEx函数取代。区别在于,在不使用和窗口类相关的小图标时,可以继续使用WNDCLASSRegisterClass

结构体定义如下:

typedef struct _WNDCLASS {

    UINT    style; // 指定类的风格类型。可以使用|连接几个风格。

    WNDPROC lpfnWndProc; //Windows 进程指针,必须使用CallWindowPro函数来调用window进程。

    int     cbClsExtra; // 指定该window类后面跟着的分配的额外的字节数

    int     cbWndExtra;// 指定window实例后面分配的额外的字节数。

    HANDLE  hInstance; //该类所在的window程序的实例句柄。

    HICON   hIcon;     //该类的图标,需为图标资源句柄,如果为空,应用程序在用户最小化窗口时须画一个图标。

    HCURSOR hCursor; // 光标

    HBRUSH  hbrBackground; // 背景句柄

    LPCTSTR lpszMenuName;  // 指向一个类的菜单的资源名的字符串的指针。

    LPCTSTR lpszClassName; // 指向一个字符串或者一个原子的指针。

} WNDCLASS;

 

RegisterClass 注册一个窗口类

    注册类函数注册一个窗口类,以便下一步在CreatWindow或者CreatWindowEx中使用,

    注册类函数现在已经被RegisterClassEx函数取代,如果不必使用小图标时可以继续使用该函数。

ATOM RegisterClass(
  CONST WNDCLASS *lpWndClass   // address of structure with class data
                   );

参数:lpWndClass : WNDCLASS结构的指针。在传过来之前必须填写合适的属性。

返回值:如果函数成功,返回值为一个原子值,它唯一的标志注册的类。如果失败,返回0,。可以调用GetLastError值看错误信息。

ATOM 其实就是一个Word ,有一个Atom表,它指向一个该表中一个字符串的引用。

 

 

CreateWindow

创建一个窗口,返回值为一个窗口句柄。

HWND CreateWindow(
  LPCTSTR lpClassName,  // pointer to registered class name
  LPCTSTR lpWindowName, // pointer to 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,          // handle to menu or child-window identifier
  HANDLE hInstance,     // handle to application instance
  LPVOID lpParam        // pointer to window-creation data
);

该函数创建一个overlapped 、弹出或子窗口。它指定窗口类,窗口的标题,风格,并且初始位置和大小(可选)。该函数也指定窗口的父窗口(如果有),和窗口的菜单。

hMenu:指向Menu的指针,或者指定一个子窗口标志的标志(根据window风格而定)

hInstance :和窗口相关的模块实例的句柄。

lpParam  :在WM_CREAT消息中传递的参数,通过CREATSTRUCT结构传给窗口的值的指针。

返回值:如果成功,返回一个新窗口的句柄。如果失败,返回NULL

备注:在返回之前,该函数发送一个WM_CREATE消息给window进程。

 

显示及刷新窗口 ShowWindow()
      ShowWindow(hwnd,SW_SHOWNORMAL);

UpdateWindow(hwnd);

 

 

三、传递消息

在显示窗口以后,要对该窗口内的消息进行分发和处理

首先定义消息的对象。

MSG

消息MSG为一个结构体,包含了来自一个进程的消息队列中的消息。

typedef struct tagMSG {     // msg 
    HWND   hwnd;     // 接收消息的串口句柄
    UINT   message;  //消息的number 
    WPARAM wParam;   // 指定消息的额外信息,精确的意思取决于message成员
    LPARAM lParam;   // 也是指定消息的额外信息,同上。
    DWORD  time;     // 消息发出的时间。
    POINT  pt;       // 指针位置,以屏幕为坐标系,
} MSG; 

GetMessage()

得到消息

该函数从调用线程消息队列中读取消息,并把它放在指定的结构体中。它能够同时读取和指定窗口相关的消息,和通过PostThreadMessage函数传递的线程消息。该函数读取位于指定范围内的消息。它不会得到属于其他进程的消息。

BOOL GetMessage(
  LPMSG lpMsg,         // address of structure with message
  HWND hWnd,           // handle of window
  UINT wMsgFilterMin,  // first message
  UINT wMsgFilterMax   // last message
);

lpMsg :从进程消息对列中获取消息,放在该指针指向的一个MSG结构体。

hWnd :窗口句柄,消息即是从该窗口中获取。其中NULL值有特殊意义,表示:函数从属于该进程的所有窗口中和通过调用PostThreadMessage传递给的进程中获取消息。

wMsgFilterMin : 最小的消息,整数

wMsgFilterMax:最大的消息,整数

返回值:如果函数得到一个非WM_PAINT 消息,返回值非0

        如果是WM_PAINT ,返回0

        如果出错,返回-1

TranslateMessage

翻译消息

BOOL TranslateMessage(
  CONST MSG *lpMsg   // address of structure with message
);

该函数把虚键值翻译成字符消息。字符消息被发送给调用进程的消息队列,当进程下一次调用GetMessage或者PeekMessage函数时被读出。

唯一的一个参数lpMsg 为一个MSG指针,

返回值: 如果消息被翻译(即字符消息被传给进程消息队列)返回非0;或者如果消息是       WM_KEYDOWN,WM_KEYUP,WM_SYSKEYDOWN,

WM_SYSKEYUP时,不管翻译情况,都返回非0;如果没有翻译,返回0

DispatchMessage

分发消息

该函数把消息分发给窗口进程。典型的用于通过GetMessage函数获得的消息。

LONG DispatchMessage(
  CONST MSG *lpmsg   // pointer to structure with message
);

参数 lpmsg :指向MSG 结构的指针。

返回值:为窗口进程返回的值。经常被忽略。

备注:MSG结构必须包含合法的消息值。如果lpmsg 参数指向一个WM_TIMER消息,并且WM_TIMERlParam参数不为NULLlParam 指向一个调用的函数而非window 进程。

 

三、编写窗口处理函数WindowProc

WindowProc 函数是一个应用程序定义的函数,它处理发给窗口的消息。WNDPROC类型定义了一个调用返回函数的指针。WindowProc为应用程序定义函数名的占位符。

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

hwnd  窗口句柄

uMsg  指定消息

wParam  指定消息的额外信息。内容取决于uMsg 参数的值。

lParam

返回值  :返回值是消息处理的结果,取决于所发送的消息。

 

 

在处理消息的过程中,一定要在switch()的最后写上一个default 情况,(这也是所有switch()中应该注意的)。另外要有WM_DESTROY 消息,

     case WM_DESTROY:

       PostQuitMessage(0);

       break;

      default:

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


 

 

这次在显示菜单的时候有些问题,

在设计窗口类时,很多地方用的是直接赋值,

wndclass.lpszMenuName = IDR_MENU1;

但是有的时候出问题,所以需要用下面的方式

      wndcls.lpszMenuName=MAKEINTRESOURCE(IDR_MENU1);

MAKEINTRESOURCE():这是一个宏,参数为一个整型,把该整型对应的资源和一个32位应用程序的资源对应。

菜单命令消息属于WM_COMMAND里面的。即,处理菜单命令,需要在

Case WM_COMMAND : 中处理,判断是哪个菜单被点击,用lparam 参数,

         case WM_COMMAND:

                {

                       switch(wParam)

                       {

                       case IDM_EXIT:

                              if(IDYES== MessageBox(hwnd,"Really close","guanbi",MB_YESNO))

                              {

                                     DestroyWindow(hwnd);

                              }

                       }

                }

                break;

所有的菜单命令处理都在这里面。

下面是在写该程序过程中出现的问题:

1。在关闭程序后,还不能彻底关闭该进程。

报的错误如下:

LINK : fatal error LNK1168: cannot open Debug/WinMain.exe for writing
Error executing link.exe.

这是因为在消息循环时的疏忽所致,代码可能如下:

 while(GetMessage(&msg,hwnd,0,0))
 {
  TranslateMessage(&msg);
  DispatchMessage(&msg);
 }
注意:GetMessage 的第二个参数说明如下

HWND hWnd, // 检索消息的窗口,如果为NULL,则是指所有的窗口。因此,如果没有设置成NULL,则关闭程序后仍旧检索该窗口的消息,所以县城仍然存在。此问题的解决办法即是把该参数设置为NULL。


0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:588324次
    • 积分:7203
    • 等级:
    • 排名:第3094名
    • 原创:146篇
    • 转载:78篇
    • 译文:3篇
    • 评论:112条
    文章分类
    最新评论