编辑框

编辑框在DELPHI里类名为"TEDIT",在StdCtrls里进行了子类化:CreateSubClass(Params, 'EDIT'),请参数StdCtrls单元里的TCustomEdit.CreateParams方法.
Delphi子类化过程:
procedure TWinControl.CreateSubClass(var Params: TCreateParams;
  ControlClassName: PChar);
const
  CS_OFF = CS_OWNDC or CS_CLASSDC or CS_PARENTDC or CS_GLOBALCLASS;
  CS_ON = CS_VREDRAW or CS_HREDRAW;
var
  SaveInstance: THandle;
begin
  if ControlClassName <> nil then
    with Params do
    begin
      SaveInstance := WindowClass.hInstance;
      if not GetClassInfo(HInstance, ControlClassName, WindowClass) and  //当前模块句柄,可能是dll或pkg
        not GetClassInfo(0, ControlClassName, WindowClass) and           //系统保留类(by the system )
        not GetClassInfo(MainInstance, ControlClassName, WindowClass) then  //应用程序模块句柄
        GetClassInfo(WindowClass.hInstance, ControlClassName, WindowClass);
      WindowClass.hInstance := SaveInstance;
      WindowClass.style := WindowClass.style and not CS_OFF or CS_ON;
    end;
end;

子类化函数,主要是要理解:
BOOL GetClassInfo(
  HINSTANCE hInstance,    // handle to application instance
  LPCTSTR lpClassName,    // class name
  LPWNDCLASS lpWndClass   // class data
);
它是将应用程序内部的类的信息提取到lpWndClass中.在CreateSubClass里有用三个句柄取得类信息,0表示系统里.三个判断条件无非就是要取得WindowClass.hInstance,而后再取得真正的类信息,可见delphi真是用心良苦啊.另外他只是将类信息保存到CreateParams里去.
这里特别要注意,delphi所有的winControl类的都含有:
  CS_OFF = CS_OWNDC or CS_CLASSDC or CS_PARENTDC or CS_GLOBALCLASS;
  CS_ON = CS_VREDRAW or CS_HREDRAW;  resize时候进行重画.

再看下windows内部的edit的WndClass定义:
/*********************************************************************
 * edit class descriptor
 */
static const WCHAR editW[] = {'E','d','i','t',0};
const struct builtin_class_descr EDIT_builtin_class =
{
    editW,                /* name */  //还记得昨天菜单窗口的类名32678吗?
    CS_DBLCLKS | CS_PARENTDC,   /* style */
    EditWndProcA,         /* procA */
    EditWndProcW,         /* procW */
    sizeof(EDITSTATE *),  /* extra */             //注意:窗口扩展数据,不是类扩展数据.那么类扩展数据在那儿定义呢?可以看到Edit扩展结构是EDITSTATE *
    IDC_IBEAM,            /* cursor */
    0                     /* brush */
};
这里主要是看  EditWndProcA, EditWndProcW两过程,一个是ASCII的,一个是UNICODE的,他俩都是简单调用:
static LRESULT EditWndProc_common( HWND hwnd, UINT msg,
                                   WPARAM wParam, LPARAM lParam, BOOL unicode )
{
    EDITSTATE *es = (EDITSTATE *)GetWindowLongPtrW( hwnd, 0 );//GetWindowLong64位扩展版
    LRESULT result = 0;
       
    if (!es && msg != WM_NCCREATE)
        return DefWindowProcT(hwnd, msg, wParam, lParam, unicode);

    if (es && (msg != WM_DESTROY)) EDIT_LockBuffer(es);

    switch (msg) {
    case EM_GETSEL:        //选中位置
        result = EDIT_EM_GetSel(es, (PUINT)wParam, (PUINT)lParam);
        break;

    case EM_SETSEL:        //设置插入符位置
        EDIT_EM_SetSel(es, wParam, lParam, FALSE);
        EDIT_EM_ScrollCaret(es);
        result = 1;
        break;

    case EM_GETRECT:        //取得可画RECT
        if (lParam)
            CopyRect((LPRECT)lParam, &es->format_rect);
        break;

    case EM_SETRECT:        //设置可画RECT,只对ES_MULTILINE有效
        if ((es->style & ES_MULTILINE) && lParam) {
            EDIT_SetRectNP(es, (LPRECT)lParam);
            EDIT_UpdateText(es, NULL, TRUE);
        }
        break;

    case EM_SETRECTNP:     //同上,只是不刷新TEXT         
        if ((es->style & ES_MULTILINE) && lParam)
            EDIT_SetRectNP(es, (LPRECT)lParam);
        break;

    case EM_SCROLL:        //滚动
        result = EDIT_EM_Scroll(es, (INT)wParam);
                break;

    case EM_LINESCROLL:       //行滚动
        result = (LRESULT)EDIT_EM_LineScroll(es, (INT)wParam, (INT)lParam);
        break;

    case EM_SCROLLCARET:      //滚动插入符  
        EDIT_EM_ScrollCaret(es);
        result = 1;
        break;

    case EM_GETMODIFY:        //是否已经修改过
        result = ((es->flags & EF_MODIFIED) != 0);
        break;

    case EM_SETMODIFY:         //设置修改过
        if (wParam)
            es->flags |= EF_MODIFIED;
        else
                        es->flags &= ~(EF_MODIFIED | EF_UPDATE);  /* reset pending updates */
        break;

    case EM_GETLINECOUNT:         //行数
        result = (es->style & ES_MULTILINE) ? es->line_count : 1; //直接返回es->line_count,多行时候,其实WM_PAINT还有考虑滚动
        break;

    case EM_LINEINDEX:            //当前行的偏移
        result = (LRESULT)EDIT_EM_LineIndex(es, (INT)wParam);
        break;

    case EM_SETHANDLE:             // 重新分配本地堆数据  
        EDIT_EM_SetHandle(es, (HLOCAL)wParam);
        break;

    case EM_GETHANDLE:              //取得本地堆缓存指针
        result = (LRESULT)EDIT_EM_GetHandle(es);
        break;

    case EM_GETTHUMB:              //滚动
        result = EDIT_EM_GetThumb(es);
        break;

    /* these messages missing from specs */
    case WM_USER+15:
    case 0x00bf:
    case WM_USER+16:
    case 0x00c0:
    case WM_USER+19:
    case 0x00c3:
    case WM_USER+26:
    case 0x00ca:
        FIXME("undocumented message 0x%x, please report\n", msg);
        result = DefWindowProcW(hwnd, msg, wParam, lParam);
        break;

    case EM_LINELENGTH:             //一行的长度      
        result = (LRESULT)EDIT_EM_LineLength(es, (INT)wParam);
        break;

    case EM_REPLACESEL:            //替换选中内容    
    {
        LPWSTR textW;

        if(unicode)
            textW = (LPWSTR)lParam;
        else
        {
            LPSTR textA = (LPSTR)lParam;
            INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
            if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
            MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
        }

        EDIT_EM_ReplaceSel(es, (BOOL)wParam, textW, TRUE, TRUE);
        result = 1;

        if(!unicode)
            HeapFree(GetProcessHeap(), 0, textW);
        break;
    }

    case EM_GETLINE:                           //当前行
        result = (LRESULT)EDIT_EM_GetLine(es, (INT)wParam, (LPWSTR)lParam, unicode);
        break;

    case EM_SETLIMITTEXT:                       //限制字符个数
        EDIT_EM_SetLimitText(es, wParam);
        break;

    case EM_CANUNDO:                            //恢复取消
        result = (LRESULT)EDIT_EM_CanUndo(es);
        break;

    case EM_UNDO:
    case WM_UNDO:                                  //取消
        result = (LRESULT)EDIT_EM_Undo(es);
        break;

    case EM_FMTLINES:                              //可视区域行数    
        result = (LRESULT)EDIT_EM_FmtLines(es, (BOOL)wParam);
        break;

    case EM_LINEFROMCHAR:                          //可视区域字符数
        result = (LRESULT)EDIT_EM_LineFromChar(es, (INT)wParam);
        break;

    case EM_SETTABSTOPS:                           //可停留
        result = (LRESULT)EDIT_EM_SetTabStops(es, (INT)wParam, (LPINT)lParam);
        break;

    case EM_SETPASSWORDCHAR:                       //设置格式化字符
    {
        WCHAR charW = 0;

        if(unicode)
            charW = (WCHAR)wParam;
        else
        {
            CHAR charA = wParam;
            MultiByteToWideChar(CP_ACP, 0, &charA, 1, &charW, 1);
        }

        EDIT_EM_SetPasswordChar(es, charW);
        break;
    }

    case EM_EMPTYUNDOBUFFER:                           //清空取消缓冲
        EDIT_EM_EmptyUndoBuffer(es);
        break;

    case EM_GETFIRSTVISIBLELINE:                       //TOPROW
        result = (es->style & ES_MULTILINE) ? es->y_offset : es->x_offset;
        break;

    case EM_SETREADONLY:                                //只读
        if (wParam) {
                    SetWindowLongPtrW( hwnd, GWL_STYLE,
                                       GetWindowLongPtrW( hwnd, GWL_STYLE ) | ES_READONLY );
                    es->style |= ES_READONLY;
        } else {
                    SetWindowLongPtrW( hwnd, GWL_STYLE,
                                       GetWindowLongPtrW( hwnd, GWL_STYLE ) & ~ES_READONLY );
                    es->style &= ~ES_READONLY;
        }
                result = 1;
         break;

    case EM_SETWORDBREAKPROC:                             //折行
        EDIT_EM_SetWordBreakProc(es, (void *)lParam);
        break;

    case EM_GETWORDBREAKPROC:                              //取得是否折行
        result = (LRESULT)es->word_break_proc;
        break;

    case EM_GETPASSWORDCHAR:                               //格式化字符
    {
        if(unicode)
            result = es->password_char;
        else
        {
            WCHAR charW = es->password_char;
            CHAR charA = 0;
            WideCharToMultiByte(CP_ACP, 0, &charW, 1, &charA, 1, NULL, NULL);
            result = charA;
        }
        break;
    }

    /* The following EM_xxx are new to win95 and don't exist for 16 bit */

    case EM_SETMARGINS:                    //只能设置左右的偏移,其实是设置format_rect                        
        EDIT_EM_SetMargins(es, (INT)wParam, LOWORD(lParam), HIWORD(lParam), TRUE);
        break;

    case EM_GETMARGINS:
        result = MAKELONG(es->left_margin, es->right_margin);
        break;

    case EM_GETLIMITTEXT:                        //取得限制字符长度
        result = es->buffer_limit;
        break;

    case EM_POSFROMCHAR:                        //取得某一位置的字符内容
        if ((INT)wParam >= get_text_length(es)) result = -1;
        else result = EDIT_EM_PosFromChar(es, (INT)wParam, FALSE);
        break;

    case EM_CHARFROMPOS:                       //某一行字符的第一个位置  
        result = EDIT_EM_CharFromPos(es, (short)LOWORD(lParam), (short)HIWORD(lParam));
        break;

        /* End of the EM_ messages which were in numerical order; what order
         * are these in?  vaguely alphabetical?
         */

    case WM_NCCREATE:                          //非客户区初始
        result = EDIT_WM_NCCreate(hwnd, (LPCREATESTRUCTW)lParam, unicode);
        break;

    case WM_DESTROY:                           //释放
        result = EDIT_WM_Destroy(es);
        es = NULL;
        break;

    case WM_GETDLGCODE:                       //设置键盘接受字符    
        result = DLGC_HASSETSEL | DLGC_WANTCHARS | DLGC_WANTARROWS;
        
        if (es->style & ES_MULTILINE)
           result |= DLGC_WANTALLKEYS;

        if (lParam && (((LPMSG)lParam)->message == WM_KEYDOWN))
        {
           int vk = (int)((LPMSG)lParam)->wParam;

                   if (es->hwndListBox)
                   {
                       if (vk == VK_RETURN || vk == VK_ESCAPE)
                           if (SendMessageW(GetParent(hwnd), CB_GETDROPPEDSTATE, 0, 0))
                               result |= DLGC_WANTMESSAGE;
                   }
                   else
                   {
                       switch (vk)
                       {
                           case VK_ESCAPE:
                               SendMessageW(GetParent(hwnd), WM_CLOSE, 0, 0);
                               break;
                           default:
                               break;
                       }
                   }
                }
        break;

        case WM_IME_CHAR:                             //输入法字符
            if (!unicode)
            {
                WCHAR charW;
                CHAR  strng[2];

                strng[0] = wParam >> 8;
                strng[1] = wParam & 0xff;
                if (strng[0]) MultiByteToWideChar(CP_ACP, 0, strng, 2, &charW, 1);
                else MultiByteToWideChar(CP_ACP, 0, &strng[1], 1, &charW, 1);
        result = EDIT_WM_Char(es, charW);
        break;
            }
            /* fall through */
    case WM_CHAR:                              //处理字符消息     
    {
        WCHAR charW;

        if(unicode)
            charW = wParam;
        else
        {
            CHAR charA = wParam;
            MultiByteToWideChar(CP_ACP, 0, &charA, 1, &charW, 1);
        }

                if (es->hwndListBox)
                {
                    if (charW == VK_RETURN || charW == VK_ESCAPE)
                    {
                        if (SendMessageW(GetParent(hwnd), CB_GETDROPPEDSTATE, 0, 0))
                            SendMessageW(GetParent(hwnd), WM_KEYDOWN, charW, 0);
                        break;
                    }
                }
        result = EDIT_WM_Char(es, charW);
        break;
    }

        case WM_UNICHAR:                          //中文字符消息     
                if (unicode)
                {
                    if (wParam == UNICODE_NOCHAR) return TRUE;
                    if (wParam <= 0x000fffff)
                    {
                        if(wParam > 0xffff) /* convert to surrogates */
                        {
                            wParam -= 0x10000;
                            EDIT_WM_Char(es, (wParam >> 10) + 0xd800);
                            EDIT_WM_Char(es, (wParam & 0x03ff) + 0xdc00);
                        }
                        else EDIT_WM_Char(es, wParam);
                    }
                    return 0;
                }
                break;

    case WM_CLEAR:                               //清楚TEXT
        EDIT_WM_Clear(es);
        break;

    case WM_COMMAND:                             //通知命令消息
        EDIT_WM_Command(es, HIWORD(wParam), LOWORD(wParam), (HWND)lParam);
        break;

        case WM_CONTEXTMENU:                         //右键菜单消息
        EDIT_WM_ContextMenu(es, (short)LOWORD(lParam), (short)HIWORD(lParam));
        break;

    case WM_COPY:                             //拷贝
        EDIT_WM_Copy(es);
        break;

    case WM_CREATE:                      //初始化
        if(unicode)
            result = EDIT_WM_Create(es, ((LPCREATESTRUCTW)lParam)->lpszName);
        else
        {
            LPCSTR nameA = ((LPCREATESTRUCTA)lParam)->lpszName;
            LPWSTR nameW = NULL;
            if(nameA)
            {
            INT countW = MultiByteToWideChar(CP_ACP, 0, nameA, -1, NULL, 0);
            if((nameW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
                MultiByteToWideChar(CP_ACP, 0, nameA, -1, nameW, countW);
            }
            result = EDIT_WM_Create(es, nameW);
                    HeapFree(GetProcessHeap(), 0, nameW);
        }
        break;

    case WM_CUT:                         //剪贴
        EDIT_WM_Cut(es);
        break;

    case WM_ENABLE:                         //设置ENABLED
                es->bEnableState = (BOOL) wParam;
        EDIT_UpdateText(es, NULL, TRUE);
        break;

    case WM_ERASEBKGND:                     //擦除背景
        /* we do the proper erase in EDIT_WM_Paint */
        result = 1;
        break;

    case WM_GETFONT:                        //字体,默认为系统字体
        result = (LRESULT)es->font;
        break;

    case WM_GETTEXT:            //这个就不说了
        result = (LRESULT)EDIT_WM_GetText(es, (INT)wParam, (LPWSTR)lParam, unicode);
        break;

    case WM_GETTEXTLENGTH:         //这个就不说了
                if (unicode) result = get_text_length(es);
                else result = WideCharToMultiByte( CP_ACP, 0, es->text, get_text_length(es),
                                                   NULL, 0, NULL, NULL );
        break;

    case WM_HSCROLL:             //这个就不说了
        result = EDIT_WM_HScroll(es, LOWORD(wParam), (short)HIWORD(wParam));
        break;

    case WM_KEYDOWN:              //这个就不说了
        result = EDIT_WM_KeyDown(es, (INT)wParam);
        break;

    case WM_KILLFOCUS:           //这个就不说了
        result = EDIT_WM_KillFocus(es);
        break;

    case WM_LBUTTONDBLCLK:          //这个就不说了
        result = EDIT_WM_LButtonDblClk(es);
        break;

    case WM_LBUTTONDOWN:            //以下都就不说了
        result = EDIT_WM_LButtonDown(es, wParam, (short)LOWORD(lParam), (short)HIWORD(lParam));
        break;

    case WM_LBUTTONUP:           
        result = EDIT_WM_LButtonUp(es);
        break;

    case WM_MBUTTONDOWN:
          result = EDIT_WM_MButtonDown(es);
        break;

    case WM_MOUSEMOVE:
        result = EDIT_WM_MouseMove(es, (short)LOWORD(lParam), (short)HIWORD(lParam));
        break;

    case WM_PRINTCLIENT:
    case WM_PAINT:
            EDIT_WM_Paint(es, (HDC)wParam);
        break;

    case WM_PASTE:                  
        EDIT_WM_Paste(es);
        break;

    case WM_SETFOCUS:
        EDIT_WM_SetFocus(es);
        break;

    case WM_SETFONT:
        EDIT_WM_SetFont(es, (HFONT)wParam, LOWORD(lParam) != 0);
        break;

    case WM_SETREDRAW:               
        /* FIXME: actually set an internal flag and behave accordingly */
        break;

    case WM_SETTEXT:
        EDIT_WM_SetText(es, (LPCWSTR)lParam, unicode);
        result = TRUE;
        break;

    case WM_SIZE:
        EDIT_WM_Size(es, (UINT)wParam, LOWORD(lParam), HIWORD(lParam));
        break;

        case WM_STYLECHANGED:          //Style切换
                result = EDIT_WM_StyleChanged(es, wParam, (const STYLESTRUCT *)lParam);
                break;

        case WM_STYLECHANGING:
                result = 0; /* See EDIT_WM_StyleChanged */
                break;

    case WM_SYSKEYDOWN:
        result = EDIT_WM_SysKeyDown(es, (INT)wParam, (DWORD)lParam);
        break;

    case WM_TIMER:
        EDIT_WM_Timer(es);
        break;

    case WM_VSCROLL:
        result = EDIT_WM_VScroll(es, LOWORD(wParam), (short)HIWORD(wParam));
        break;

        case WM_MOUSEWHEEL:
                {
                    int gcWheelDelta = 0;
                    UINT pulScrollLines = 3;
                    SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0);

                    if (wParam & (MK_SHIFT | MK_CONTROL)) {
                        result = DefWindowProcW(hwnd, msg, wParam, lParam);
                        break;
                    }
                    gcWheelDelta -= GET_WHEEL_DELTA_WPARAM(wParam);
                    if (abs(gcWheelDelta) >= WHEEL_DELTA && pulScrollLines)
                    {
                        int cLineScroll= (int) min((UINT) es->line_count, pulScrollLines);
                        cLineScroll *= (gcWheelDelta / WHEEL_DELTA);
            result = EDIT_EM_LineScroll(es, 0, cLineScroll);
                    }
                }
                break;

            
    /* IME messages to make the edit control IME aware */           
    case WM_IME_SETCONTEXT:
        break;

    case WM_IME_STARTCOMPOSITION:
        es->composition_start = es->selection_end;
        es->composition_len = 0;
        break;

    case WM_IME_COMPOSITION:
                EDIT_ImeComposition(hwnd, lParam, es);
        break;

    case WM_IME_ENDCOMPOSITION:
                if (es->composition_len > 0)
                {
                        static const WCHAR empty_stringW[] = {0};
                        EDIT_EM_ReplaceSel(es, TRUE, empty_stringW, TRUE, TRUE);
                        es->selection_end = es->selection_start;
                        es->composition_len= 0;
                }
        break;

    case WM_IME_COMPOSITIONFULL:
        break;

    case WM_IME_SELECT:
        break;

    case WM_IME_CONTROL:
        break;
                
    default:
        result = DefWindowProcT(hwnd, msg, wParam, lParam, unicode);
        break;
    }
    
    if (es) EDIT_UnlockBuffer(es, FALSE);

        TRACE("hwnd=%p msg=%x (%s) -- 0x%08lx\n", hwnd, msg, SPY_GetMsgName(msg, hwnd), result);

    return result;
}

以下一一解析:
LONG
WINAPI
GetWindowLongW(HWND hWnd, int nIndex)        //这是一个可以改变窗体属性的函数,非常常用
{
    PWINDOW Wnd; //定义一窗口对象

    Wnd = ValidateHwnd(hWnd);       //验证窗口句柄是否合格
    if (Wnd == NULL)
        return 0;

    if (nIndex >= 0)
    {
        if ((DWORD)nIndex + sizeof(LONG) > Wnd->ExtraDataSize)  //这时取得是窗口扩展数据,并非类扩展数据
        {
            SetLastError(ERROR_INVALID_PARAMETER);
            return 0;
        }

        return *((LONG *)((PCHAR)(Wnd + 1) + nIndex)); //注意这里的计算,Wnd + 1其实就是将指针移到窗口对象之后,然后加上nIndex偏移
    }
    else
    {
        switch (nIndex)
        {
            case GWL_EXSTYLE:                //扩展风格
                return Wnd->ExStyle;
            case GWL_STYLE:
                return Wnd->Style;           //普通风格
            case GWL_HINSTANCE:              //窗口模块句柄
                return (LONG)Wnd->Instance;
            case GWL_ID:
                return Wnd->IDMenu;          //   
            case GWL_USERDATA:               //
                return Wnd->UserData;

            case GWL_HWNDPARENT:                     //父窗口
            {
                HWND parent = GetAncestor( hWnd, GA_PARENT );
                if (parent == GetDesktopWindow()) parent = GetWindow( hWnd, GW_OWNER );
                return (LONG)parent;
            }
            case GWL_WNDPROC:                         //回调函数
                /* Call win32k for this as a callproc handle may need
                   to be created */
                return NtUserGetWindowLong(hWnd, nIndex, FALSE);

            default:
                SetLastError(ERROR_INVALID_PARAMETER);
                return 0;
        }
    }
}

typedef struct _WINDOW
{
    USER_OBJHDR hdr; /* FIXME: Move out of the structure once new handle manager is implemented */

    /* NOTE: This structure is located in the desktop heap and will
             eventually replace WINDOW_OBJECT. Right now WINDOW_OBJECT
             keeps a reference to this structure until all the information
             is moved to this structure */
    struct _PROCESSINFO *pi; /* FIXME: Move to object header some day */     //三个进程指针,系统进程信息,W32进程信息,桌面进程信息
    struct _W32THREADINFO *ti;
    struct _DESKTOP *pdesktop;
    RECT WindowRect;
    RECT ClientRect;

    WNDPROC WndProc;   //回调函数 
    union
    {
        /* Pointer to a call procedure handle */
        PCALLPROC CallProc;                                       
        /* Extra Wnd proc (windows of system classes) */
        WNDPROC WndProcExtra;                           
    };

    struct _WINDOW *Parent;     //父窗口
    struct _WINDOW *Owner;      //子窗口

    /* Size of the extra data associated with the window. */
    ULONG ExtraDataSize;        //窗口扩展数据,紧跟窗口对象,并初始化为零
    /* Style. */
    DWORD Style;
    /* Extended style. */
    DWORD ExStyle;
    /* Handle of the module that created the window. */
    HINSTANCE Instance;                                 //创建窗口的模块句柄,是创建者!
    /* Window menu handle or window id */
    UINT IDMenu;                                         //菜单或者窗口的ID值
    LONG UserData;                                       //用户数据  
    /* Pointer to the window class. */
    PWINDOWCLASS Class;                                  //窗口类
    /* Window name. */
    UNICODE_STRING WindowName;                           //窗口名字
    /* Context help id */
    DWORD ContextHelpId;                                 //HELP ID  

    HWND hWndLastActive;                                 //最后一次活动窗口
    /* Property list head.*/
    LIST_ENTRY PropListHead;              //属性链表
    ULONG PropListItems;

    struct
    {
        RECT NormalRect;                                 //  
        POINT IconPos;
        POINT MaxPos;
    } InternalPos;

    UINT Unicode : 1;                                      //一些标志位,是否是UINICODE
    /* Indicates whether the window is derived from a system class */
    UINT IsSystem : 1;                                     //是否从系统类继承下来的 
    UINT InternalPosInitialized : 1;                       //初始的位置
    UINT HideFocus : 1;                                    //隐藏焦点
    UINT HideAccel : 1;                                    //不接受快捷键
} WINDOW, *PWINDOW;

所以EDITSTATE *es = (EDITSTATE *)GetWindowLongPtrW( hwnd, 0 )首先是取得EDIT扩展数据.其设计也很简单,其结构如下:
typedef struct
{
    BOOL is_unicode;        /* how the control was created */
    LPWSTR text;            /* the actual contents of the control */              //文本内容,重要性不用说了
        UINT text_length;               /* cached length of text buffer (in WCHARs) - use get_text_length() to retrieve */
    UINT buffer_size;        /* the size of the buffer in characters */
    UINT buffer_limit;        /* the maximum size to which the buffer may grow in characters */
    HFONT font;            /* NULL means standard system font */
    INT x_offset;            /* scroll offset    for multi lines this is in pixels  //X轴偏移
                                for single lines it's in characters */
    INT line_height;        /* height of a screen line in pixels */
    INT char_width;            /* average character width in pixels */
    DWORD style;            /* sane version of wnd->dwStyle */
    WORD flags;            /* flags that are not in es->style or wnd->flags (EF_XXX) */
    INT undo_insert_count;        /* number of characters inserted in sequence */
    UINT undo_position;        /* character index of the insertion and deletion */
    LPWSTR undo_text;        /* deleted text */
    UINT undo_buffer_size;        /* size of the deleted text buffer */
    INT selection_start;        /* == selection_end if no selection */
    INT selection_end;        /* == current caret position */
    WCHAR password_char;        /* == 0 if no password char, and for multi line controls */
    INT left_margin;        /* in pixels */
    INT right_margin;        /* in pixels */         
    RECT format_rect;                                   //相当重要,它决定了从那个地方开始画一行内容
    INT text_width;            /* width of the widest line in pixels for multi line controls
                       and just line width for single line controls    */
    INT region_posx;        /* Position of cursor relative to region: */
    INT region_posy;        /* -1: to left, 0: within, 1: to right */

    void *word_break_proc;        /* 32-bit word break proc: ANSI or Unicode */
    INT line_count;            /* number of lines */
    INT y_offset;            /* scroll offset in number of lines */  
    BOOL bCaptureState;         /* flag indicating whether mouse was captured */
    BOOL bEnableState;        /* flag keeping the enable state */
    HWND hwndSelf;            /* the our window handle */         句柄
    HWND hwndParent;        /* Handle of parent for sending EN_* messages.  父窗口句柄
                           Even if parent will change, EN_* messages
                       should be sent to the first parent. */
    HWND hwndListBox;        /* handle of ComboBox's listbox or NULL */
    /*
     *    only for multi line controls
     */
    INT lock_count;            /* amount of re-entries in the EditWndProc */
    INT tabs_count;
    LPINT tabs;
    LINEDEF *first_line_def;    /* linked list of (soft) linebreaks */
    HLOCAL hloc32W;            /* our unicode local memory block */

    HLOCAL hloc32A;            /* alias for ANSI control receiving EM_GETHANDLE
                          or EM_SETHANDLE */
    /*
     * IME Data
     */
    UINT composition_len;   /* length of composition, 0 == no composition */
    int composition_start;  /* the character position for the composition */
} EDITSTATE;


是在WM_CREATE进行初始化的:

    case WM_CREATE:
        if(unicode)
            result = EDIT_WM_Create(es, ((LPCREATESTRUCTW)lParam)->lpszName)

再看wm_paint:
    case WM_PRINTCLIENT:
    case WM_PAINT:
            EDIT_WM_Paint(es, (HDC)wParam);
        break;

如下:
static void EDIT_WM_Paint(EDITSTATE *es, HDC hdc)
{
    PAINTSTRUCT ps;
    INT i;
    HDC dc;
    HFONT old_font = 0;
    RECT rc;
    RECT rcClient;
    RECT rcLine;
    RECT rcRgn;
    HBRUSH brush;
    HBRUSH old_brush;
    INT bw, bh;
    BOOL rev = es->bEnableState &&
                ((es->flags & EF_FOCUSED) ||
                    (es->style & ES_NOHIDESEL));
        dc = hdc ? hdc : BeginPaint(es->hwndSelf, &ps);

    GetClientRect(es->hwndSelf, &rcClient);

    /* get the background brush */
    brush = EDIT_NotifyCtlColor(es, dc);      //向父窗口发送取得背景颜色消息:WM_CTLCOLORSTATIC或WM_CTLCOLOREDIT

    /* paint the border and the background */
    IntersectClipRect(dc, rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);//设置描述符的RECT
    
    if(es->style & WS_BORDER) {
        bw = GetSystemMetrics(SM_CXBORDER);
        bh = GetSystemMetrics(SM_CYBORDER);
        rc = rcClient;
        if(es->style & ES_MULTILINE) {
            if(es->style & WS_HSCROLL) rc.bottom+=bh;  
            if(es->style & WS_VSCROLL) rc.right+=bw;      //根据BORDER修改RECT大小
        }                                                    
        
        /* Draw the frame. Same code as in nonclient.c */
        old_brush = SelectObject(dc, GetSysColorBrush(COLOR_WINDOWFRAME));      //设置边框颜色
        PatBlt(dc, rc.left, rc.top, rc.right - rc.left, bh, PATCOPY);           //以下是画四条边框
        PatBlt(dc, rc.left, rc.top, bw, rc.bottom - rc.top, PATCOPY);
        PatBlt(dc, rc.left, rc.bottom - 1, rc.right - rc.left, -bw, PATCOPY);
        PatBlt(dc, rc.right - 1, rc.top, -bw, rc.bottom - rc.top, PATCOPY);
        SelectObject(dc, old_brush);
        
        /* Keep the border clean */
        IntersectClipRect(dc, rc.left+bw, rc.top+bh,                               //再次将RECT恢复
            max(rc.right-bw, rc.left+bw), max(rc.bottom-bh, rc.top+bh));
    }
    
    GetClipBox(dc, &rc);
    FillRect(dc, &rc, brush);

    IntersectClipRect(dc, es->format_rect.left,       //设置可画的RECT
                es->format_rect.top,
                es->format_rect.right,
                es->format_rect.bottom);
    if (es->style & ES_MULTILINE) {
        rc = rcClient;
        IntersectClipRect(dc, rc.left, rc.top, rc.right, rc.bottom);     
    }
    if (es->font)
        old_font = SelectObject(dc, es->font);

    if (!es->bEnableState)
        SetTextColor(dc, GetSysColor(COLOR_GRAYTEXT));
    GetClipBox(dc, &rcRgn);
    if (es->style & ES_MULTILINE) {                              
        INT vlc = get_vertical_line_count(es);
        for (i = es->y_offset ; i <= min(es->y_offset + vlc, es->y_offset + es->line_count - 1) ; i++) {  //多行,在DELPHI里是TMEMO
            EDIT_GetLineRect(es, i, 0, -1, &rcLine);
            if (IntersectRect(&rc, &rcRgn, &rcLine))
                EDIT_PaintLine(es, dc, i, rev);                   //画每一行内容
        }
    } else {                                                                  
        EDIT_GetLineRect(es, 0, 0, -1, &rcLine);                                       //单行,DELPHI的EDIT
        if (IntersectRect(&rc, &rcRgn, &rcLine))
            EDIT_PaintLine(es, dc, 0, rev);
    }
    if (es->font)                             //恢复原有属性
        SelectObject(dc, old_font);

        if (!hdc)
            EndPaint(es->hwndSelf, &ps);
}

//设置插入符
static void EDIT_WM_SetFocus(EDITSTATE *es)
{
    es->flags |= EF_FOCUSED;

        if (!(es->style & ES_NOHIDESEL))
            EDIT_InvalidateText(es, es->selection_start, es->selection_end);

        /* single line edit updates itself */如果是单行格式,就刷新下TEXT
        if (!(es->style & ES_MULTILINE))
        {
            HDC hdc = GetDC(es->hwndSelf);
            EDIT_WM_Paint(es, hdc);
            ReleaseDC(es->hwndSelf, hdc);
        }

    CreateCaret(es->hwndSelf, 0, 1, es->line_height);         //插入符本身也是一种用户对象
    EDIT_SetCaretPos(es, es->selection_end,
             es->flags & EF_AFTER_WRAP);
    ShowCaret(es->hwndSelf);       //直接调用系统服务NtUserShowCaret,系统负责控制插入符的显示
    EDIT_NOTIFY_PARENT(es, EN_SETFOCUS);
}

//删除插入符
static LRESULT EDIT_WM_KillFocus(EDITSTATE *es)
{
    es->flags &= ~EF_FOCUSED;
    DestroyCaret();
    if(!(es->style & ES_NOHIDESEL))
        EDIT_InvalidateText(es, es->selection_start, es->selection_end);
    EDIT_NOTIFY_PARENT(es, EN_KILLFOCUS);
    return 0;
}


从Edit的WM_Paint处理例程来看,那么有这样的一个问题,就是单行的EDIT并不能设置Format_Rect,那么现在要求设置单行EDIT上下左右都居中,怎么办?
利用以上知识,我们知道,解决以上问题,只有设置Format_Rect一种方法(当然有些特殊的方法,基本上很麻烦,不算!),那就是在ES_MUTLILINE风格下可以设置,但是EDIT偏偏就是NOT ES_MUTLILINE风格.经过思考终于想到一个方案,如下:

重载Edit的CreateParams并设置其为ES_MUTLILINE风格
procedure TEdit.CreateParams(var Params: TCreateParams);
begin
  inherited ;
  Params.Style := Params.Style or ES_CENTER or ES_MULTILINE;
end;

//设置Format_Rect
procedure TForm1.FormCreate(Sender: TObject);
var
  EditStyle: DWord;
  EditRect: TRect;
begin
  EditStyle := Windows.GetWindowLong(Edit1.Handle,GWL_STYLE);
  if (EditStyle and ES_MULTILINE > 0) then
  begin
    //Get Edit FormatRect
    Windows.SetRect(EditRect,0,0,0,0);
    SendMessage(Edit1.Handle,EM_GETRECT,0,DWord(@EditRect));

    //Set Edit FormatRect
    OffsetRect(EditRect,10,10);
    SendMessage(Edit1.Handle,EM_SETRECT,0,DWord(@EditRect));
  end;
end;

//重载Edit的WM_CHAR消息,以使VK_RETURN不再处理换行作用,也就是相当于屏蔽了ES_MUTLILINE风格
procedure TEdit.WMChar(var Message: TWMChar);
begin
  if Message.CharCode = VK_Return then
  begin
    //todo        
  end
  else
    inherited;
end;

----------Henry 20100705


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值