<<深入浅出MFC>>笔记1——Win32基本程序观念

来源:互联网 发布:php soap header 验证 编辑:程序博客网 时间:2024/06/05 16:52
1.Windows SDK程序开发流程

主要分为程序代码和UI资源两部分。
 
2.以消息未基础,以事件驱动

    程序不断的等待外围的输入,判断在处理。操作系统通过捕捉外围输入,以消息的形式进入程序中,程序通过获取的不同消息进行不同的处理。USER模块掌管外围的驱动程序。
    程序通过一个循环来获取消息。
MSG msg;
while (GetMessage(&msg, NULL, NULL, NULL)) {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}
其中MSG是一个结构体如下:
typedef struct tagMSG
{
    HWND hwnd;
    UINT message; // WM_xxx ,例如WM_MOUSEMOVE ,WM_SIZE...
    WPARAM wParam;
    LPARAM lParam;
    DWORD time;
    POINT pt;
} MSG;
    获取消息后必须将获取的消息进行处理,这个过程就需要一个窗口处理函数函数,形式如下:
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
    case WM_CREATE:
        //....
        break;
    case WM_CLOSE:
        //....
        break;
    case WM_DESTROY:
        //....
        break;
    //...
    default:
        return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}
整个过程如下图:
 
 
3.Windows程序
  • 程序入口点
main  是一般C程序的进入点:
    int main(int argc, char *argv[]);
{
    ...
}
WinMain  则是Windows程序的进入点:
    int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    LPSTR lpCmdLine, int nCmdShow)
{
    ...
}
// 在Win32 中CALLBACK被定义为__stdcall,是一种函数调用习惯,关系到
// 参数压入到堆栈的次序,以及处理堆栈的责任归属。其它的函数调用习惯还有
// _pascal  和_cdecl
  • 消息循环
        初始化后程序进入消息循环:
        
while (GetMessage(&msg,...)) {
    TranslateMessage(&msg); //  转换键盘消息
    DispatchMessage(&msg); //  分派消息
}
    其中TranslateMessage是为了将键盘消息转化,DispatchMessage将消息传给窗口函数去处理,当消息发生之时,OS已根据当时状态,为他表明了所属窗口。而窗口窗口类又已经标明了窗口函数(也就是wc. lpfnWndProc所指定的函数),所以DispatchMessage可以将消息发送给窗口处理。
  • 窗口函数
         消息循环中的DispatchMessage通过USER,模块将消息送到窗口函数,窗口函数通过Switch/case来判断消息种类,由于窗口函数是右系统所调用,所以这就是一种回调函数,用于Windows系统调用,还不会由我们调用。
        整个流程是消息经过输入,再经由消息循环的抓取,再传输给窗口进而给窗口函数,
LRESULT CALLBACK WndProc(HWND hWnd,
    UINT message,
    WPARAM wParam,
    LPARAM lParam)
        所有消息都要经过处理,所以Switch/case中的default必须调用DefWindwosProc,这个是windows内部预设的消息处理函数。
  • 消息映射(Message Map)的雏形
         首先,定义一个MSGMAP_ENTRY   结构和一个di m   宏:
struct MSGMAP_ENTRY {
    UINT nMessage;
    LONG (*pfn)(HWND, UINT, WPARAM, LPARAM);
};
#define dim(x) (sizeof(x) / sizeof(x[0]))
        其中pfn是一个函数指针,用出指针处理nMessgae消息,接下来定义两个数组_messageEntries[]和_commandEntries[],将消息和处理方法关联起来:
// 消息与处理方法之对照
struct MSGMAP_ENTRY _messageEntries[] =
{
    WM_CREATE, OnCreate,
    WM_PAINT, OnPaint,
    WM_SIZE, OnSize,
    WM_COMMAND, OnCommand,
    WM_SETFOCUS, OnSetFocus,
    WM_CLOSE, OnClose,
    WM_DESTROY, OnDestroy,
} ;
//  Command-ID 与处理方法对照
struct MSGMAP_ENTRY _commandEntries =
{
    IDM_ABOUT,      OnAbout,
    IDM_FILEOPEN,   OnFileOpen,
    IDM_SAVEAS,     OnSaveAs,
} ;  
        窗口函数的设计如下:
//----------------------------------------------------------------------
//窗口函数
//----------------------------------------------------------------------
LRESULT CALLBACK WndProc(HWND  hWnd,     UINT  message,
                            WPARAM wParam, LPARAM lParam)
{
    int i;
    for(i=0; i < dim(_messageEntries); i++) {  // 消息对照表
        if (message ==  _messageEntries[i].nMessage)
            return((*_messageEntries[i].pfn)(hWnd,  message, wParam,  lParam));
    }
    return(DefWindowProc(hWnd, message, wParam, lParam));
}
//----------------------------------------------------------------------
// OnCommand --  专门处理WM_COMMAND
//----------------------------------------------------------------------
LONG OnCommand(HWND hWnd, UINT message,
                WPARAM  wParam, LPARAM lParam)
{
    int i;
    for(i=0; i < dim(_commandEntries); i++) {  // 命令对照表
        if (LOWORD(wParam) ==  _commandEntries[i].nMessage)
            return((*_commandEntries[i].pfn)(hWnd, message, wParam, lParam));
    }
    return(DefWindowProc(hWnd, message, wParam, lParam));
}
//----------------------------------------------------------------------
LONG OnCreate(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam)
{
    ...
}
//----------------------------------------------------------------------
LONG OnAbout(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam)
{
    ...
}
//----------------------------------------------------------------------
       这样一来WndProc和OnComand就不用改变了,每有新要处理的消息,只要添加到_messageEntries[]和_commandEntries[]两个数组中就行了。
  • 对话框的运作
       对话框有两种:
  1. 模态对话框:当子对话框运行的时候父窗口不能使用
  2. 无模对话框:子对话框和父窗口共同运行
      一张图说明问题:


4.Windows程序生命周期

  1. 在初始化过程中调用CreateWindow创建窗口,同时CreateWindow发送WM_CREATE消息,用于初始化动作。
  2. 在程序运行过程中不断的使用GetMessage获取存储的消息,如果获取的消息是WM_QUIT,GetMessage就返回0同时While循环就结束,从而就结束运行。
  3. DispatchMessage通过USER模块将消息发送到窗口函数。
  4. 不断重复2和3。
  5. 当点击关闭按钮时,窗口发送WM_CLOSE消息,这个消息一般是DefWindwosProc进行处理。
  6. 当DefWindwosProc收到WM_CLOSE后嗲偶哦那个DestoryWindow把窗口清理,DestoryWindow本身会发送WM_DESTORY消息。
  7. 窗口函数对WM_DESTORY消息进行处理,通过调用PostQuitMessage处理。
  8. 通过PostQuitMessage发送WM_QUIT消息,让GetMessage获取消息让2处理。

5.空闲时间处理

      当消息队列中没有消息的时候,就存在空闲时间,获取这个时间可以通过如下代码:
while (TRUE) {
    if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE) {
        if (msg.message ==  WM_QUIT)
            break;
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    else {
        OnIdle ();
    }
}
PeekMessage   返回   TRUE   的条件是有消息,如果没有消息返回   FALSE   
GetMessage   返回   TRUE   的条件是有消息且该消息不为WM_QUIT返回 ,  FALSE  的条件是有消息且该消息  为   WM_QUIT 
       相同点:

            PeekMessage函数与GetMessage函数都用于查看应用程序消息队列,有消息时将队列中的消息派发出去。

       不同点:
            无论应用程序消息队列是否有消息,PeekMessage函数都立即返回,程序得以继续执行后面的语句(无消息则执行其它指令,有消息时一般要将消息派发出去,再执行其它指令)。GetMessage函数只有在消息对立中有消息时返回,队列中无消息就会一直等,直至下一个消息出现时才返回。在等的这段时间,应用程序不能执行任何指令。


6.进程与线程

        进程:执行中的程序。
        线程:在一个程序内部也可以实现多个任务并发执行,其中每个任务称为线程,线程是比进程更小的执行单位,它是在一个进程中独立的控制流,即程序内部的控制流。
  •  内核对象
          内核对象是系统的一种资源,内核对象一经创建,任何应用程序都可以使用。系统通过一个使用计数来管理内核对象,常用的内核对象如下:
内核对象产生方法eventCreateEventmutexCreateMutexsemaphoreCreateSemaphorefileCreateFilefile-mappingCreateFileMappingprocessCreateProcessthreadCreateThread
         内核对象产生方式不同,但是都会获得一个handle句柄作为识别,每被使用一次,使用计数加1,其结束的时候都是调用CloseHandle。其中process对象是一个数据结构,系统通过它来管理进程。
  • 进程的生命周期
          执行一个程序,就会产生一个进程,最直接的就是通过windows的shell执行一个App.exe应用程序,当双击就可运行.流程如下:

  • 创建子进程
           通过CreateProcess创建进程:
BOOL WINAPI
CreateProcessW(
    __in_opt    LPCWSTR lpApplicationName,
    __inout_opt LPWSTR lpCommandLine,
    __in_opt    LPSECURITY_ATTRIBUTES lpProcessAttributes,
    __in_opt    LPSECURITY_ATTRIBUTES lpThreadAttributes,
    __in        BOOL bInheritHandles,
    __in        DWORD dwCreationFlags,
    __in_opt    LPVOID lpEnvironment,
    __in_opt    LPCWSTR lpCurrentDirectory,
    __in        LPSTARTUPINFOW lpStartupInfo,
    __out       LPPROCESS_INFORMATION lpProcessInformation
    );



<待续>

原创粉丝点击