最早时候就曾经哪里看到过说所有控件都是窗口(window),更有甚者说都是对象,这个就不扯了。自己做好的控件是做成Lib还是Dll那是后话,MFC我是不熟悉了,Win32还是看了几天的。大致把制作的整个流程简要的记录一下。

自己做的控件最主要的功能就是接受你发给他的命令,也就是要给外部调用的接口。控件有自己的消息处理函数比如

LRESULT CALLBACK PETextViewWndProc(HWND hWnd,UINT Message,WPARAM wParam,LPARAM lParam)
{
    PETextView 
*View = (PETextView*)GetWindowLong(hWnd,0);

    
switch(Message)
    
{
    
case WM_NCCREATE:
        
if((View = new PETextView(hWnd)) == 0)
            
return false;

        SetWindowLong(hWnd,
0,(LONG)View);
        
return true;

    
case WM_NCDESTROY:
        
if(View)delete View;
        
return 0;

    
case WM_PAINT:
        
return View->OnPaint();

    
case WM_SIZE:
        
return View->OnSize(wParam, LOWORD(lParam), HIWORD(lParam));

    
case PEM_OPENFILE:
        
return View->OpenFile((TCHAR*)lParam);

    
case PEM_CLEAR:
        
return View->ClearFile();
    
default:
        
break;
    }


    
return DefWindowProc(hWnd,Message,wParam,lParam);
}


这里有两类消息,一类是系统定义的以WM开头,一类是自己定义的,当然随便你自己定义啦。对应的消息看到是调用相应的函数完成的,这也就是说控件的行为就可以另外编写逻辑部分,然后提供接口给这里调用即可。

之所以说控件就是窗口是因为他有自己的窗口类,以及初始化函数,同时也有创建的函数。窗口类的定义和注册也做成提供给外部的接口,在外部必要的时候调用。而控制控件是通过发送消息来实现的,为了更加好看,可以定义一个宏,比如

#define PE_OpenFile(hWnd, Path)        SendMessage((hWnd), PEM_OPENFILE, 0, (LPARAM)(Path))

那么创建窗口和控件唯一不同的地方就是,内部的创建和销毁消息是WM_NCCREATEWM_NCDESTROY,先不管这两个消息。我们看到WM_NCCREATE之前有个GetWindowLong,其内有个SetWindowLong。这两个是关键的,这样就设置了这个控件的属性,使其关联起来,第二个参数msdn上是没有说明设置为0是什么意思的,其实这两个函数的第二个参数设置0表示读取的意思,第一个是读取该控件的属性,然后第二个函数在增加第三个参数的属性的同时读取赋予给这个控件。

 

一切都OK了!那么控件创建可在外部的WM_CREATE之时调用,当然也可以在使用其功能前调用即可。

 

一切提供给外部的调用都Port在一个头文件中,这样使用的时候包含这个头文件就好了。

接下来解释那两个消息,这两个消息是因为我们创建了子窗口,也就是我们自己的控件。

这两个消息与WM_CREATE,WM_DESTROY之间的顺序关系是这样的,只看销毁吧。

hwnd = parent, uMsg = WM_DESTROY
hwnd = child, uMsg = WM_DESTROY
hwnd = child, uMsg = WM_NCDESTROY
hwnd = parent, uMsg = WM_NCDESTROY

WM_DESTROY是通知子窗口销毁,然后子窗口通过接受WM_NCDESTROY进行销毁,并发送给父窗口,进行销毁。

 

细节部分介绍的差不多,总体思路就是和创建窗口差不多,但是要搞个头文件,把一些个常量和功能的函数另外一个窗口类的初始化和创建的接口搞进去。