Chinaunix首页 | 论坛 | 博客
  • 博客访问: 15317452
  • 博文数量: 2005
  • 博客积分: 11986
  • 博客等级: 上将
  • 技术积分: 22535
  • 用 户 组: 普通用户
  • 注册时间: 2007-05-17 13:56
文章分类

全部博文(2005)

文章存档

2014年(2)

2013年(2)

2012年(16)

2011年(66)

2010年(368)

2009年(743)

2008年(491)

2007年(317)

分类: 嵌入式

2009-07-09 10:05:22

  我们以minigui-1.6.10的industrialsample为例来讨论这个问题,问题的答案是在GetWndProc函数中发现的
static inline WNDPROC GetWndProc (HWND hWnd)
{
     return ((PMAINWIN)hWnd)->MainWindowProc;
     // 读取hWnd地址开始处以PMAINWIN为结构体的MainWindowProc偏移出的数据,
     // 而CONTROL控件类结构体的ControlProc和PMAINWIN为结构体的MainWindowProc偏移位置相同,因为
     // 这2个结构体的前面定义的所有数据完全一致(如果完全一致,完全可以将共有的内容抽象到一个独立结构体里边去,
     // 像minigui这种做法,很是缺乏代码结构性,完全在拼凑代码嘛,不敢苟同这种做法[luther.gliethttp])
}

1.首先注册class控件类"ctrl_rotate",该控件类的回调函数为RotateProc
#define CTRL_ROTATE "ctrl_rotate"
BOOL
RegisterRotate(void)
{
    WNDCLASS Class;

    Class.spClassName = CTRL_ROTATE; // 将要注册的控件类名称"ctrl_rotate"
    Class.dwStyle = WS_NONE;
    Class.dwExStyle = WS_EX_NONE;
    Class.hCursor = GetSystemCursor(IDC_ARROW);
    Class.iBkColor = COLOR_lightwhite;
    Class.WinProc = RotateProc; // 控件回调函数

    return RegisterWindowClass(&Class);
}
2.在RadarWinProc窗口创建时生成"ctrl_rotate"控件类的实例对象.
==>
case MSG_CREATE:
            radar_rotate.hwnd =
                CreateWindow(CTRL_ROTATE, "", WS_VISIBLE, IDC_RADAR_CTRL,
                             RADAR_X, RADAR_Y, RADAR_W, RADAR_H, hWnd,
                             (int)&radar_rotate); // 创建一个窗口,该窗口回调函数参数为&radar_rotate
细节就在CreateWindow(),展开它看看,
#define CreateWindow(class_name, caption, style, \
                id, x, y, w, h, parent, add_data) \
        CreateWindowEx(class_name, caption, style, 0, \
                        id, x, y, w, h, parent, add_data)

HWND GUIAPI CreateWindowEx (const char* spClassName, const char* spCaption,
                  DWORD dwStyle, DWORD dwExStyle, int id,
                  int x, int y, int w, int h,
                  HWND hParentWnd, DWORD dwAddData)
{
    ......
// MSG_GETCTRLCLASSINFO消息调用
// GetControlClassInfo (const char* szClassName)处理函数
// 获取RegisterWindowClass注册的类,以该类名命名的控件将全部使用该类定义的控件统一方法,即:Class.WinProc = RotateProc;
    cci = (PCTRLCLASSINFO)SendMessage (HWND_DESKTOP, // 以同步方式直接回调HWND_DESKTOP桌面窗口的回调函数处理消息[luther.gliethttp]
                MSG_GETCTRLCLASSINFO, 0, (LPARAM)spClassName); // 源码见后
    pNewCtrl->ControlProc = cci->ControlProc; // 就是Class.WinProc = RotateProc;
    pNewCtrl->pcci = cci; // 但是随后
    SendMessage (HWND_DESKTOP, MSG_NEWCTRLINSTANCE, (WPARAM)hParentWnd, (LPARAM)pNewCtrl); // 将该pNewCtrl添加到hParentWnd父窗口中.
    SendMessage ((HWND)pNewCtrl, MSG_NCCREATE, 0, (LPARAM)pNewCtrl);
    // 向pNewCtrl发送MSG_NCCREATE消息, 调用的pNewCtrl窗口回调函数MainWindowProc()就是控件的ControlProc
   
// 函数,我们这里就是RotateProc回调函数,传给该回调函数的参数为pNewCtrl,即该控件类的一个具体实例对象指针[luther.gliethttp].
    ......
}

DesktopWinProc
==>
case MSG_GETCTRLCLASSINFO:
            return (int)GetControlClassInfo ((const char*)lParam); // 获取RegisterRotate注册的"ctrl_rotate"控件类信息
case MSG_NEWCTRLINSTANCE:
            dskOnNewCtrlInstance ((PCONTROL)wParam, (PCONTROL)lParam); // 源码见后
            break;

// 将一个calloc内存空间的新控件登记到pParent父窗口中[lutehr.gliethttp]
static void dskOnNewCtrlInstance (PCONTROL pParent, PCONTROL pNewCtrl)
{
    PCONTROL pFirstCtrl, pLastCtrl;
 
    pFirstCtrl = pParent->children; // 取出child链表头

    pNewCtrl->next = NULL;
    
    if (!pFirstCtrl) {
        // parent还没有一个child,那么pNewCtrl成为第一个
        pParent->children = pNewCtrl;
        pNewCtrl->prev = NULL;
    }
    else {
        pLastCtrl = pFirstCtrl;
        
        while (pLastCtrl->next) // 找到结尾,之所以需要将pNewCtrl添加到结尾,涉及到GUI图形的Z序知识,
// 位于一个平面desktop上的多个windows窗体,是有上下层次感的,位于最上层的窗体可以覆盖剪切所有位于它下层的
// 窗体,根据添加顺序先后,该windows窗体内部多个控件也就有了控件们的Z序,后添加的控件永远可以覆盖先前添加的
// 控件[luther.gliethttp]
            pLastCtrl = pLastCtrl->next;
            
        pLastCtrl->next = pNewCtrl; // 将pNewCtrl置于Z序最上层[luther.gliethttp]
        pNewCtrl->prev = pLastCtrl;
    }

    init_invrgn ((PMAINWIN)pNewCtrl); // 初始化该控件窗口剪切计算单元

    if (pNewCtrl->dwExStyle & WS_EX_CTRLASMAINWIN) {
        // The control can be displayed out of the main window which contains the control.
        PZORDERNODE pNode = pNewCtrl->pZOrderNode;

        // Init Global Clip Region info.
        init_gcrinfo ((PMAINWIN)pNewCtrl);

        // Add to Z-Order list.
        pNode->hWnd = (HWND)pNewCtrl;
        add_new_window ((PMAINWIN)pNewCtrl, pNode);

        // Update others' GCRInfo.
        if (pNewCtrl->dwStyle & WS_VISIBLE ) {
            dskUpdateGCRInfoOnShowNewMainWin ((PMAINWIN)pNewCtrl);
        }
    }
        
    pNewCtrl->pcci->nUseCount ++;
    // 该pcci引用计数加1,只有当该控件类引用计数nUseCount为0时,UnregisterWindowClass才会真正释放掉
    // 由RegisterWindowClass登记到ccitable[]全局控件类管理变量中的控件类空间free(cci);
}


int GUIAPI SendMessage (HWND hWnd, int iMsg, WPARAM wParam, LPARAM lParam)
{
    WNDPROC WndProc;

    MG_CHECK_RET (MG_IS_WINDOW(hWnd), -1);

#ifndef _LITE_VERSION

//该发起者因为调用SendMessage,发现向其他thread[比如Desktop线程发送消息]而被阻塞),将停留在SendSyncMessage函数sem_wait (SyncMsg.sem_handle)中,等待其他线程处理完自己发过去的消息之后,发送sem_post(pSyncMsg->sem_handle);唤醒信号.[luther.gliethttp]

    if (!BE_THIS_THREAD(hWnd))
        return SendSyncMessage (hWnd, iMsg, wParam, lParam);
#endif /* !_LITE_VERSION */
    
    if ( !(WndProc = GetWndProc(hWnd)) ) // 和ucgui不同的是,hWnd就是指针,所以省去了检索指针的操作,
    // 但这也体现了minigui中1并不见得是1,让维护的人概念模糊,文字上说不清,我看像是混世型的[luther.gliethttp].
    // 读取hWnd地址开始处以PMAINWIN为结构体的MainWindowProc偏移出的数据,
    // 而CONTROL控件类结构体的ControlProc和PMAINWIN为结构体的MainWindowProc偏移位置相同,因为
    // 这2个结构体的前面定义的所有数据完全一致(如果完全一致,完全可以将共有的内容抽象到一个独立结构体里边去,
    // 像minigui这种做法,很是缺乏代码结构性,完全在拼凑代码嘛,不敢苟同这种做法,trick[luther.gliethttp])
        return ERR_INV_HWND;

    return (*WndProc)(hWnd, iMsg, wParam, lParam);

}

阅读(2394) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~