minigui代码分析

来源:互联网 发布:华为ife矩阵 编辑:程序博客网 时间:2024/05/17 15:20
一、minigui运行模式

1.线程模式:MiniGui-Threads 

定义:_MGRM_THREADS 
行在MiniGui-Threads上的程序可以在不同的线程中建立多个窗口,但所有的窗口在一个进程或地址空间中运行,传统意义上的嵌入式操作系统。

2.进程模式:MiniGui-Processes 

定义:_MGRM_Processes或者定义_LITE_VERSION 

MiniGui-Processes上每个程序是单独的进程,每个进程也可以建立多个窗口,并且实现了多进程窗口系统。适用于具有完整UNIX特性的嵌入式式系统。

3.独立应用模式:MiniGui-Standalone

定义:_MGRM_STANDALONE 或者定义_LITE_VERSION和_STAND_ALONE 

通过独立任务的方式运行,既不需要多进程支持也不需要多线程支持。

二、数据结构

1.CreateMainWindow函数参数:PMAINWINCREATE  pCreateInfo

结构体MAINWINCREATE 定义了被创建的窗口的位置、标题、类型等基本参数。实际上包含了创建窗口的UI风格和窗口处理函数两方面的内容。

PMAINWINCREATE为指向该结构体的指针。

typedef struct _MAINWINCREATE{    DWORD dwStyle;                                      //窗口风格    DWORD dwExStyle;                                    //窗口的附加风格    const char* spCaption;                              //窗口的标题    HMENU hMenu;                                        //附加在窗口上的菜单句柄    HCURSOR hCursor;                                    //在窗口中所使用的鼠标光标句柄    HICON hIcon;                                        //程序的图标句柄    HWND  hHosting;                                     //窗口消息队列的托管窗口    int (*MainWindowProc)(HWND, int, WPARAM, LPARAM);   //该窗口的消息处理函数指针,回调函数    int lx, ty, rx, by;                                 //窗口相对屏幕的绝对坐标,以象素点表示    int iBkColor;                                       //窗口背景颜色    DWORD dwAddData;                                    //附带给窗口的一个32 位值    DWORD dwReserved;                                   //预留,没有用到}MAINWINCREATE;typedef MAINWINCREATE* PMAINWINCREATE;

2.MAINWIN结构体:主窗口的详细信息由该结构体给出
typedef struct _MAINWIN{    /* These fields are similiar with CONTROL struct. */    unsigned char DataType;     // 数据类型,表示是否是一个窗口(主窗口或者控件窗口),对于该结构和CONTROL结构,都必须是TYPE_HWND</span>    unsigned char WinType;      // 判断是否是主窗口,对于该结构,必须是TYPE_MAINWIN</span>    unsigned short Flags;       // special runtime flags, such EraseBkGnd flags    int left, top;      // the position and size of main window.    int right, bottom;    int cl, ct;         // the position and size of client area.    int cr, cb;    DWORD dwStyle;      // the styles of main window.    DWORD dwExStyle;    // the extended styles of main window.        int iBkColor;       // the background color.    HMENU hMenu;        // handle of menu.    HACCEL hAccel;      // handle of accelerator table.    HCURSOR hCursor;    // handle of cursor.    HICON hIcon;        // handle of icon.    HMENU hSysMenu;     // handle of system menu.    PLOGFONT pLogFont;  // pointer to logical font.    char* spCaption;    // the caption of main window.    int   id;           // the identifier of main window.    LFSCROLLBARINFO vscroll; // the vertical scroll bar information.    LFSCROLLBARINFO hscroll; // the horizital scroll bar information.    /** the window renderer */    WINDOW_ELEMENT_RENDERER* we_rdr;    HDC   privCDC;      // the private client DC.    INVRGN InvRgn;      // 这个主窗口的无效区域,在处理MSG_PAINT消息时很重要    PGCRINFO pGCRInfo;  // pointer to global clip region info struct.    // the Z order node.    int idx_znode;    PCARETINFO pCaretInfo; // pointer to system caret info struct.    DWORD dwAddData;    // the additional data.    DWORD dwAddData2;   // the second addtional data.    int (*MainWindowProc)(HWND, int, WPARAM, LPARAM); // the address of main window procedure.    struct _MAINWIN* pMainWin; // the main window that contains this window. for main window, always be itself.    HWND hParent;       // the parent of this window.   for main window, always be HWND_DESKTOP.        /* Child windows.*/    HWND hFirstChild;    // the handle of first child window.    HWND hActiveChild;  // the currently active child window.    HWND hOldUnderPointer;  // the old child window under pointer.    HWND hPrimitive;    // the premitive child of mouse event.    NOTIFPROC NotifProc;    // the notification callback procedure.    /* window element data. */    struct _wnd_element_data* wed;        /* Main Window hosting. The following members are only implemented for main window.*/    struct _MAINWIN* pHosting; // the hosting main window.    struct _MAINWIN* pFirstHosted; // the first hosted main window.    struct _MAINWIN* pNextHosted;  // the next hosted main window.    PMSGQUEUE pMessages;  // the message queue.    GCRINFO GCRInfo; // the global clip region info struct. put here to avoid invoking malloc function.#ifdef _MGRM_THREADS    pthread_t th;        // the thread which creates this main window.#endif//the controls as mainHWND hFirstChildAsMainWin;    HDC   secondaryDC;                // the secondary window dc.    ON_UPDATE_SECONDARYDC update_secdc; // the callback of secondary window dc    RECT  update_rc;} MAINWIN;
3.MSGQUEUE消息队列

struct _MSGQUEUE{    DWORD dwState;              // message queue states#ifdef _MGRM_THREADS    pthread_mutex_t lock;       // lock    sem_t wait;                 // the semaphore for wait message    sem_t sync_msg;             // the semaphore for sync message#endif    PQMSG  pFirstNotifyMsg;     // head of the notify message queue    PQMSG  pLastNotifyMsg;      // tail of the notify message queue#ifdef _MGRM_THREADS    PSYNCMSG pFirstSyncMsg;     // head of the sync message queue    PSYNCMSG pLastSyncMsg;      // tail of the sync message queue#else    IDLEHANDLER OnIdle;         // Idle handler#endif#ifdef _MGRM_THREADS    PMAINWIN pRootMainWin;      // The root main window of this message queue.#endif    MSG* msg;                   /* post message buffer */    int len;                    /* buffer len */    int readpos, writepos;      /* positions for reading and writing */    int FirstTimerSlot;         /* the first timer slot to be checked */    DWORD TimerMask;            /* timer slots mask */    int loop_depth;             /* message loop depth, for dialog boxes. */};

三、CreateMainWindow函数流程

1.init_desktop_win 

<pre name="code" class="objc">static void init_desktop_win (void){    static MAINWIN sg_desktop_win;    PMAINWIN pDesktopWin;    LICENSE_SET_MESSAGE_OFFSET();    pDesktopWin = &sg_desktop_win; //作为默认的Desktop    pDesktopWin->pMessages         = __mg_dsk_msg_queue;  // 自己的消息队列,其他窗口发送的SendMessage将消息压入该队列[luther.gliethttp]    pDesktopWin->MainWindowProc    = DesktopWinProc;      // 桌面默认回调处理函数    pDesktopWin->DataType          = TYPE_HWND;    pDesktopWin->WinType           = TYPE_ROOTWIN;#ifdef _MGRM_THREADS    pDesktopWin->th                = __mg_desktop;#endif    pDesktopWin->pLogFont          = GetSystemFont (SYSLOGFONT_WCHAR_DEF);    pDesktopWin->spCaption         = "THE DESKTOP WINDOW";    pDesktopWin->pGCRInfo          = &sg_ScrGCRInfo;    pDesktopWin->idx_znode         = 0;    pDesktopWin->pMainWin          = pDesktopWin;    pDesktopWin->we_rdr            = __mg_def_renderer;    __mg_hwnd_desktop = (HWND)pDesktopWin;  // 登记到desktop的全局量中    __mg_dsk_win  = pDesktopWin;}
2.main函数 
#define main_entry main#define MiniGUIMain \MiniGUIAppMain (int args, const char* argv[]); \int main_entry (int args, const char* argv[]) \{ \    int iRet = 0; \    if (InitGUI (args, argv) != 0) { \        return 1; \    } \    iRet = MiniGUIAppMain (args, argv); \    TerminateGUI (iRet); \    return iRet; \} \int MiniGUIAppMain

3.CreateMainWindow函数流程

HWND GUIAPI CreateMainWindowEx (PMAINWINCREATE pCreateInfo,         const char* werdr_name, const WINDOW_ELEMENT_ATTR* we_attrs,        const char* window_name, const char* layer_name){    // 指针    PMAINWIN pWin;    if (pCreateInfo == NULL) {        return HWND_INVALID;    }    if (!(pWin = calloc(1, sizeof(MAINWIN)))) { //分配结构体内存        return HWND_INVALID;    }#ifdef _MGRM_THREADS //这是重要部分,用于找到消息队列    if (pCreateInfo->hHosting == HWND_DESKTOP || pCreateInfo->hHosting == 0) {        /*如果托管窗口为桌面窗口或者没有托管窗口,为新建的主窗口创建线程信息和消息队列,获取本线程关联的消息队列结构体。         *若获取失败说明该窗口是最顶层的主窗口,目前还有对应的消息队列,则为其创建一个消息队列结构体*/        if ((pWin->pMessages = GetMsgQueueThisThread ()) == NULL) { //试图获取本线程关联的消息队列结构体            if (!(pWin->pMessages = mg_InitMsgQueueThisThread ()) ) { //试图去创建一个消息队列结构体                free (pWin);                return HWND_INVALID;            }            pWin->pMessages->pRootMainWin = pWin;//如果创建消息队列结构体成功,则设置当前窗口为根窗口        }        else {            /* Already have a top level main window, in case of user have set                a wrong hosting window */            pWin->pHosting = pWin->pMessages->pRootMainWin;//设置托管口        }    }    else {        pWin->pMessages = GetMsgQueueThisThread (); //直接获取,这种情况下,是可以肯定消息队列已经存在        if (pWin->pMessages != kernel_GetMsgQueue (pCreateInfo->hHosting) || //该函数的调用者必须和hosting的消息队列所在线程一致。这很重要                pWin->pMessages == NULL) {            free (pWin);            return HWND_INVALID;        }    }    if (pWin->pHosting == NULL) //如果当前窗口的托管主窗口为空,利用传递的函数参数获得托管主窗口信息        pWin->pHosting = gui_GetMainWindowPtrOfControl (pCreateInfo->hHosting);    /* leave the pHosting is NULL for the first window of this thread. */#else    pWin->pHosting = gui_GetMainWindowPtrOfControl (pCreateInfo->hHosting); //运行模式为非MiniGui-Threads,获得托管窗口的句柄    if (pWin->pHosting == NULL)        pWin->pHosting = __mg_dsk_win; //托管窗口句柄为空,设置托管窗口为默认桌面窗口    pWin->pMessages = __mg_dsk_msg_queue; //将消息队列设置为默认桌面消息队列#endif    pWin->pMainWin      = pWin; //以下部分在初始化结构体成员,可以忽略    pWin->hParent       = 0;    //当前窗口的父窗口不存在    pWin->pFirstHosted  = NULL; //第一个托管主窗口    pWin->pNextHosted   = NULL; //下一个托管主窗口    pWin->DataType      = TYPE_HWND;      //数据类型    pWin->WinType       = TYPE_MAINWIN;   //窗口类型#ifdef _MGRM_THREADS    pWin->th            = pthread_self(); //创建主窗口的线程#endif    pWin->hFirstChild   = 0;    //第一个子窗口的句柄为0,即不存在    pWin->hActiveChild  = 0;    //当前活动的子窗口的句柄为0,即不存在    pWin->hOldUnderPointer = 0; //旧的子窗口    pWin->hPrimitive    = 0;    pWin->NotifProc     = NULL;    pWin->dwStyle       = pCreateInfo->dwStyle;    pWin->dwExStyle     = pCreateInfo->dwExStyle;#ifdef _MGHAVE_MENU    pWin->hMenu         = pCreateInfo->hMenu;#else    pWin->hMenu         = 0;#endif    pWin->hCursor       = pCreateInfo->hCursor;    pWin->hIcon         = pCreateInfo->hIcon;#ifdef _MGHAVE_MENU    if ((pWin->dwStyle & WS_CAPTION) && (pWin->dwStyle & WS_SYSMENU)) //如果当前窗口包含标题且包含系统菜单,则创建系统菜单        pWin->hSysMenu= CreateSystemMenu ((HWND)pWin, pWin->dwStyle);    else#endif        pWin->hSysMenu = 0; //否则系统菜单项为0    pWin->spCaption    = FixStrAlloc (strlen (pCreateInfo->spCaption));//分配空间存放标题    if (pCreateInfo->spCaption [0]) //如果函数参数结构体的标题字符串的第一个字符非空        strcpy (pWin->spCaption, pCreateInfo->spCaption); //复制标题到结构体的标题项    pWin->MainWindowProc = pCreateInfo->MainWindowProc; //消息处理函数    pWin->iBkColor    = pCreateInfo->iBkColor;    pWin->pCaretInfo = NULL; //指向系统插入字符信息结构体    pWin->dwAddData   = pCreateInfo->dwAddData;    pWin->dwAddData2  = 0;    pWin->secondaryDC = 0;    /* Scroll bar */ //下面是初始化滚动条相关的内容    if (pWin->dwStyle & WS_VSCROLL) { //垂直方向的滚动条        pWin->vscroll.minPos = 0;        pWin->vscroll.maxPos = 100;        pWin->vscroll.curPos = 0;        pWin->vscroll.pageStep = 101;        pWin->vscroll.barStart = 0;        pWin->vscroll.barLen = 10;        pWin->vscroll.status = SBS_NORMAL;    }    else        pWin->vscroll.status = SBS_HIDE | SBS_DISABLED;    if (pWin->dwStyle & WS_HSCROLL) { //水平方向的滚动条        pWin->hscroll.minPos = 0;        pWin->hscroll.maxPos = 100;        pWin->hscroll.curPos = 0;        pWin->hscroll.pageStep = 101;        pWin->hscroll.barStart = 0;        pWin->hscroll.barLen = 10;        pWin->hscroll.status = SBS_NORMAL;    }    else        pWin->hscroll.status = SBS_HIDE | SBS_DISABLED;    /** perfer to use parent renderer */ //初始化渲染器相关的内容,这时可以忽略这一部分    if (pWin->dwExStyle & WS_EX_USEPARENTRDR) {        if (((PMAINWIN)pCreateInfo->hHosting)->we_rdr) {            pWin->we_rdr = ((PMAINWIN)pCreateInfo->hHosting)->we_rdr;            ++pWin->we_rdr->refcount;        }        else {            return HWND_INVALID;        }    }    else {        /** set window renderer */        set_window_renderer (pWin, werdr_name);    }    /** set window element data */    while (we_attrs && we_attrs->we_attr_id != -1) {        // append_window_element_data (pWin,         //       we_attrs->we_attr_id, we_attrs->we_attr);        DWORD _old;        set_window_element_data ((HWND)pWin,                 we_attrs->we_attr_id, we_attrs->we_attr, &_old);        ++we_attrs;    }    /** prefer to parent font */    if (pWin->dwExStyle & WS_EX_USEPARENTFONT)        pWin->pLogFont = __mg_dsk_win->pLogFont;    else {        pWin->pLogFont = GetSystemFont (SYSLOGFONT_WCHAR_DEF);    }    if (SendMessage ((HWND)pWin, MSG_NCCREATE, 0, (LPARAM)pCreateInfo)) // MSG_NCCREATE表示窗口已经创建但是还没有向系统注册        goto err;    /** reset menu size */    ResetMenuSize ((HWND)pWin);#ifdef __TARGET_FMSOFT__    pCreateInfo->lx += __mg_mainwin_offset_x;    pCreateInfo->rx += __mg_mainwin_offset_x;    pCreateInfo->ty += __mg_mainwin_offset_y;    pCreateInfo->by += __mg_mainwin_offset_y;#endif    SendMessage ((HWND)pWin, MSG_SIZECHANGING, //开始发生一些消息,让窗口进行一些工作            (WPARAM)&pCreateInfo->lx, (LPARAM)&pWin->left);    SendMessage ((HWND)pWin, MSG_CHANGESIZE, (WPARAM)&pWin->left, 0);    pWin->pGCRInfo = &pWin->GCRInfo;    if (SendMessage (HWND_DESKTOP, MSG_ADDNEWMAINWIN, (WPARAM) pWin, 0) < 0)//这个很重要:把主窗口发送给Desktop窗口托管,进行管理。        goto err;    /*      * We should add the new main window in system and then     * SendMessage MSG_CREATE for application to create     * child windows.     */    if (SendMessage ((HWND)pWin, MSG_CREATE, 0, (LPARAM)pCreateInfo)) { //发送一个MSG_CREATE消息,告知应用程序窗口已经创建成功        SendMessage(HWND_DESKTOP, MSG_REMOVEMAINWIN, (WPARAM)pWin, 0);        goto err;    }<pre name="code" class="objc">
#ifndef _MGRM_PROCESSES    screensaver_create();#endif    return (HWND)pWin;err:#ifdef _MGRM_THREADS    if (pWin->pMessages && pWin->pHosting == NULL) {        mg_FreeMsgQueueThisThread ();    }#endif    if (pWin->secondaryDC) DeleteSecondaryDC ((HWND)pWin);    free (pWin);    return HWND_INVALID;}

1)判断传入的参数pCreateInfo是否为空

        Case NULL:若参数为空,返回HWND_INVALID  

        Case NOT NULL:若参数不为空,继续执行2 
2)为PMAINWIN类型的pWin分配内存空间,并判断pWin是否为空 

        Case NULL:分配空间失败,返回HWND_INVALID 

        Case NOT NULL:分配空间成功,继续执行3 
3)是否定义_MGRM_THREADS:

        3.a定义了_MGRM_THREADS,代表minigui的运行模式为MiniGui-Threads

        设置pWin的成员pWin->pMessages和pWin->pHosting 

        3.b没有定义_MGRM_THREADS,代表minigui的运行模式为非MiniGui-Threads  

        设置pWin的成员pWin->pMessages和pWin->pHosting 
4)设置pWin的成员。

5)初始化渲染器相关的内容。

6)SendMessage ((HWND)pWin,MSG_NCCREATE, 0, (LPARAM)pCreateInfo)

        表示该窗口已经创建但是还没有向系统进行注册,当收到这种类型的消息时可以对自己创建的对象进行初始化,但不能创建子窗口,也不能进行绘图。如果函数返回值为非零值,创建的窗口将被销毁。

7)SendMessage ((HWND)pWin, MSG_SIZECHANGING,(WPARAM)&pCreateInfo->lx, (LPARAM)&pWin->left);

        指示了将要被更改的窗口的大小,当窗口大小将要发生改变时,该消息会发送给窗口。如果你想要控制窗口改变后的实际位置和大小(窗口改变可能是MoveWindow或者其他函数引起的),你需要使用MSG_SIZECHANGING作为SendMessage函数的第二个参数,并且通过第二个参数返回位置和大小信息。

9)SendMessage ((HWND)pWin,MSG_CHANGESIZE, (WPARAM)&pWin->left, 0);

        确定改变后的窗口大小。

9)SendMessage (HWND_DESKTOP,MSG_ADDNEWMAINWIN, (WPARAM) pWin, 0);

        把主窗口发送给Desktop窗口托管,进行管理,并绘制窗口。

10)SendMessage ((HWND)pWin,MSG_CREATE, 0, (LPARAM)pCreateInfo);

        发送一个MSG_CREATE消息,告知应用程序窗口已经创建成功。


0 0
原创粉丝点击