WGI的WEdit.c文件源代码


/**
 *
 * 文 件 名:WEdit.c
 *
 * 描    述:
 *
 * 创 建 者:赵平智   <[email protected]>
 *
 * 创建日期:20091116
 *
 * 备    注:
 *
 *
 * * 维护历史 *
 *
 *   <日期>                <修改者>
 *   <修改内容...>
 *
 **/

#include "WEdit.h"
#include "../WDialog/WDialog.h"
#include "../WScrollBar/WScrollBar.h"


#define    MOVE_CARET_TO_PREVCHARACTER        0x00000001
#define    MOVE_CARET_TO_NEXTCHARACTER        0x00000002
#define    MOVE_CARET_TO_PREVROW              0x00000004
#define    MOVE_CARET_TO_NEXTROW              0x00000008
#define    MOVE_CARET_TO_ROWBEGINNING         0x00000010
#define    MOVE_CARET_TO_ROWEND               0x00000020
#define    SET_CARETPOS_BY_POINT              0x00000040
#define    DELETE_CHARACTER                   0x00000080


VOID  TOG_WEdit(OBJECT* pObj);

static void  Prepaint(OBJECT* This, HBITMAP hBitmap);
static void  Paint(OBJECT* This, HBITMAP hBitmap, const VR* pCaller);

static  void  CalculateText(OBJECT* This, const VR* pCaller);
static  void  MakeCaretVisible(OBJECT* This);
static  void  MakeCaretInvisible(OBJECT* This);
static  void  SetCaretPosByPoint(OBJECT* This, POINT pt);
static  void  SetCaretPosBYnCaretChar(OBJECT* This, const UI32 flag);
static  void  MoveCaretToPrevCharacter(OBJECT* This);
static  void  MoveCaretToNextCharacter(OBJECT* This);
static  void  MoveCaretToPrevRow(OBJECT* This);
static  void  MoveCaretToNextRow(OBJECT* This);
static  void  MoveCaretToRowBeginning(OBJECT* This);
static  void  MoveCaretToRowEnd(OBJECT* This);
static  void  Delete(OBJECT* This, int iFirst, int iLast, const VR* pCaller);
static  void  WriteText(OBJECT* This, const VR* pCaller);


/*=====================+ OICC label +====================*/

/*<oicc>*/
/*<ibn> WControl </ibn>*/
/*<crt>*/
FRESULT  CRT_WEdit(OBJID* pOID, BYTKTY IQCty, BYTKTY OQCty, SI32 NumCR, OBJECT** ppObj, BYTE* pExotic)
{
 extern  VOID  InitAIBofND(OBJECT* pND, MLDSN* pMsn, NUMIB nib);
 extern  VOID  InitABNofND(OBJECT* pND, MLDSN* pMsn, NUMBN nbn);
 extern  VOID  TOG_WControl(OBJECT* pObj);
 extern  VOID  TOG_WGrinterface(OBJECT* pObj);
 extern  VOID  TOG_OIOIC(OBJECT* pObj);


 UI32   ux_ND = 4;  /* ND数量。*/
 UI32   ux_BN = 6;  /* 各ND的BN数量之和。*/
 UI32   ux_IB = 3;  /* 各ND的IBN数量之和。*/
 UI32   ux_CS = NumCR * 10;  /* 各ND的最少CS数量之和。*/
 UI32   ux_EM = sizeof(EM_WEDIT) + sizeof(EM_WEDIT) + sizeof(EM_WGRINTERFACE)
   + sizeof(EM_OIOIC);  /* 各ND的EM尺寸之和。*/

 UI32  sum = ux_ND * sizeof(OBJECT)  /* for AND. */
   + ux_BN * sizeof(OBJECT*)  /* for "ppo_ABN". */
   + ux_IB * sizeof(OBJECT*)  /* for "ppo_AIB". */
   + ux_CS * sizeof(VR) + ux_EM;  /* for "pvr_ACS" and "pEM". */


 BYTE*  pIC = NULL;

 if(NULL == pExotic)
 {
  *ppObj = NULL;
  pIC = (BYTE*)calloc(sum, 1);
 }else
 {
  pIC = pExotic;
 }


 if( pIC != NULL )
 {
  OBJECT*  pND;
  MLDSN    ArrMsn[3];
  BYTE*    p = pIC + sizeof(OBJECT) * ux_ND;


  /***  确定AND各元素  ***/

  /** WEdit **/
  pND = (OBJECT*)pIC;
  TOG_WEdit(pND);
  pND->MSN = MSN_WEDIT;
  pND->OID = (*pOID)++;
  pND->po_AND = (OBJECT*)pIC;
  pND->NND = ux_ND;

  /** WControl **/
  TOG_WControl(++pND);
  pND->MSN = MSN_WCONTROL;
  pND->OID = (*pOID)++;
  pND->po_AND = (OBJECT*)pIC;
  pND->NND = ux_ND;

  /** WGrinterface **/
  TOG_WGrinterface(++pND);
  pND->MSN = MSN_WGRINTERFACE;
  pND->OID = (*pOID)++;
  pND->po_AND = (OBJECT*)pIC;
  pND->NND = ux_ND;

  /** OIOIC **/
  TOG_OIOIC(++pND);
  pND->MSN = MSN_OIOIC;
  pND->OID = (*pOID)++;
  pND->po_AND = (OBJECT*)pIC;
  pND->NND = ux_ND;


  /***  初始化各ND  ***/

  /** WEdit **/
  pND = (OBJECT*)pIC;

  /* - AIB - */
  pND->ppo_AIB = (OBJECT**)p;
  ArrMsn[0] = MSN_WCONTROL;
  InitAIBofND(pND, ArrMsn, 1);
  p += sizeof(OBJECT*) * 1;

  /* - ABN - */
  pND->ppo_ABN = (OBJECT**)p;
  ArrMsn[0] = MSN_WCONTROL;
  ArrMsn[1] = MSN_WGRINTERFACE;
  ArrMsn[2] = MSN_OIOIC;
  InitABNofND(pND, ArrMsn, 3);
  p += sizeof(OBJECT*) * 3;

  /* - ACS - */
  pND->pvr_ACS = (VR*)p;
  pND->NCS = NumCR * 1;
  p += sizeof(VR) * pND->NCS;

  /* - EM - */
  pND->pEM = (EM*)p;
  p += sizeof(EM_WEDIT);

  /** WControl **/
  ++pND;

  /* - AIB - */
  pND->ppo_AIB = (OBJECT**)p;
  ArrMsn[0] = MSN_WGRINTERFACE;
  InitAIBofND(pND, ArrMsn, 1);
  p += sizeof(OBJECT*) * 1;

  /* - ABN - */
  pND->ppo_ABN = (OBJECT**)p;
  ArrMsn[0] = MSN_WGRINTERFACE;
  ArrMsn[1] = MSN_OIOIC;
  InitABNofND(pND, ArrMsn, 2);
  p += sizeof(OBJECT*) * 2;

  /* - ACS - */
  pND->pvr_ACS = (VR*)p;
  pND->NCS = NumCR * 2;
  p += sizeof(VR) * pND->NCS;

  /* - EM - */
  pND->pEM = (EM*)p;
  p += sizeof(EM_WEDIT);

  /** WGrinterface **/
  ++pND;

  /* - AIB - */
  pND->ppo_AIB = (OBJECT**)p;
  ArrMsn[0] = MSN_OIOIC;
  InitAIBofND(pND, ArrMsn, 1);
  p += sizeof(OBJECT*) * 1;

  /* - ABN - */
  pND->ppo_ABN = (OBJECT**)p;
  ArrMsn[0] = MSN_OIOIC;
  InitABNofND(pND, ArrMsn, 1);
  p += sizeof(OBJECT*) * 1;

  /* - ACS - */
  pND->pvr_ACS = (VR*)p;
  pND->NCS = NumCR * 3;
  p += sizeof(VR) * pND->NCS;

  /* - EM - */
  pND->pEM = (EM*)p;
  p += sizeof(EM_WGRINTERFACE);

  /** OIOIC **/
  ++pND;

  /* - ACS - */
  pND->pvr_ACS = (VR*)p;
  pND->NCS = NumCR * 4;
  p += sizeof(VR) * pND->NCS;

  /* - EM - */
  pND->pEM = (EM*)p;
  if( IQCty > 0 )
  {
   /* - IQ - */
   ((EM_OIOIC*)(pND->pEM))->IQ.Dtrm = (BYTE*)calloc(IQCty, 1);
   if( NULL == ((EM_OIOIC*)(pND->pEM))->IQ.Dtrm)
   {
    /* 分配IQ的容量失败!*/
    if(NULL == pExotic)
     free(pIC);
    return FR_N;
   }
   ((EM_OIOIC*)(pND->pEM))->IQ.Front = ((EM_OIOIC*)(pND->pEM))->IQ.Rear = ((EM_OIOIC*)(pND->pEM))->IQ.Dtrm - 1;
   ((EM_OIOIC*)(pND->pEM))->IQ.Cty = IQCty;
   ((EM_OIOIC*)(pND->pEM))->IQ.Qty = ((EM_OIOIC*)(pND->pEM))->IQ.Lost = 0;
  }

  if( OQCty > 0 )
   {
   /* - OQ - */
   ((EM_OIOIC*)(pND->pEM))->OQ.Dtrm = (BYTE*)calloc(OQCty, 1);
   if(NULL == ((EM_OIOIC*)(pND->pEM))->OQ.Dtrm)
   {
    /* 分配OQ的容量失败!*/
    if( ((EM_OIOIC*)(pND->pEM))->IQ.Dtrm != NULL )
     free(((EM_OIOIC*)(pND->pEM))->IQ.Dtrm);
    if(NULL == pExotic)
     free(pIC);
    return FR_N;
   }
   ((EM_OIOIC*)(pND->pEM))->OQ.Front = ((EM_OIOIC*)(pND->pEM))->OQ.Rear = ((EM_OIOIC*)(pND->pEM))->OQ.Dtrm - 1;
   ((EM_OIOIC*)(pND->pEM))->OQ.Cty = OQCty;
   ((EM_OIOIC*)(pND->pEM))->OQ.Qty = ((EM_OIOIC*)(pND->pEM))->OQ.Lost = 0;
  }
  p += sizeof(EM_OIOIC);
 }else
 {
  return FR_N;
 }


 if(NULL == pExotic)
  *ppObj = (OBJECT*)pIC;


 return FR_P;
}
/*</crt>*/
/*</oicc>*/

/*=====================+ Interface +=====================*/

/**
*
* 名称:WEdit_Open
*/
static IRESULT  WEdit_Open(OBJECT* This, const VR* pCaller)
{
 EM_WEDIT*    pem;

 OBS_OBJECT_OPEN_;

 /* 在下面完成接口自己的任务。*/

 if(1 == This->RefCnt)
 {
  pem = (EM_WEDIT*)This->pEM;
  pem->pWGrinterface = GetBN(This, MSN_WGRINTERFACE);
  pem->pWControl = GetBN(This, MSN_WCONTROL);
 }

 return IR_P;
}

/**
*
* 名称:WEdit_Input
*/
static IRESULT  WEdit_Input(OBJECT* This, BYTE* IStrm, BYTKTY Qty, const VR* pCaller)
{

 /* ... */


 /* 在上面完成接口自己的任务。*/

 SBO_OBJECT_INPUT;
}

/**
*
* 名称:WEdit_Output
*/
static IRESULT  WEdit_Output(OBJECT* This, BYTE* OStrm, BYTKTY Cty, BYTKTY* pQty, const VR* pCaller)
{

 /* ... */


 /* 在上面完成接口自己的任务。*/

 SBO_OBJECT_OUTPUT;
}

/**
*
* 名称:WEdit_IOput
*/
static IRESULT  WEdit_IOput(OBJECT* This, BYTE* IStrm, BYTKTY Qty, BYTE* OStrm, BYTKTY Cty, BYTKTY* pQty, const VR* pCaller)
{

 /* ... */


 /* 在上面完成接口自己的任务。*/

 SBO_OBJECT_IOPUT;
}

/**
*
* 名称:WEdit_Interact0
*/
static IRESULT  WEdit_Interact0(OBJECT* This, ACTION Act, const VR* pCaller)
{
 VR      caller;
 EM_WEDIT*           pem = (EM_WEDIT*)This->pEM;
 EM_WGRINTERFACE* pem_wgr = (EM_WGRINTERFACE*)pem->pWGrinterface->pEM;
 EM_WPANEL*          pem_parwpa;
 HFONT               hOldFont;
 HDC                 hdc;
 TEXTMETRIC          tm;

 caller.cr = pCaller->cr;
 caller.mr = This->OID;

 switch(Act)
 {
 case CMD_PREPARE:
  if(pem->cpty > 0)
  {
   pem->pAPWC = (POINT*)calloc(pem->cpty, sizeof(POINT));
   if(NULL == pem->pAPWC)
    return IR_N;
  }
  pem_parwpa = (EM_WPANEL*)GetEMofBN(pem_wgr->pParentWnd, MSN_WPANEL);
  hdc = GetDC(pem_parwpa->hWnd);
  
  if(pem->font)
   hOldFont = SelectObject(hdc, pem->font);

  // Get the metrics of the current font. 
  GetTextMetrics(hdc, &tm);

  if(pem->font)
   SelectObject(hdc, hOldFont);

  ReleaseDC(pem_parwpa->hWnd, hdc);
  pem->CharHeight = tm.tmHeight;
  CalculateText(This, &caller);
  return IR_P;
 case CMD_WGI_PREPAINT:
  Prepaint(This, NULL);
  return  IR_P;
 case  CMD_WGI_PAINT0:
  Paint(This, NULL, &caller);
  return  IR_P;
 case CLR_WGI_TEXT:
  VO_Interact0(pem->pWGrinterface, CLR_WGI_TEXT, &caller);
  Paint(This, NULL, &caller);
  return IR_P;
 default:
  break;
 }


 /* 在上面完成接口自己的任务。*/

 SBO_OBJECT_INTERACT0;
}

/**
*
* 名称:WEdit_Interact1
*/
static IRESULT  WEdit_Interact1(OBJECT* This, ACTION Act, BYTE* OStrm, BYTKTY Cty, BYTKTY* pQty, const VR* pCaller)
{

 /* ... */


 /* 在上面完成接口自己的任务。*/

 SBO_OBJECT_INTERACT1;
}

/**
*
* 名称:WEdit_Interact2
*/
static IRESULT  WEdit_Interact2(OBJECT* This, ACTION  Act, BYTE* IStrm, BYTKTY Qty, const VR* pCaller)
{
 VR      caller;
 EM_WEDIT*           pem = (EM_WEDIT*)This->pEM;
 EM_WEDIT*         pem_wct = (EM_WEDIT*)pem->pWControl->pEM;
 EM_WGRINTERFACE* pem_wgr = (EM_WGRINTERFACE*)pem->pWGrinterface->pEM;
 EM_WGRINTERFACE*    pem_parwgr;
 EM_WPANEL*          pem_parwpa;
 EM_WDIALOG*         pem_parwdl;
 EM_WGRINTERFACE* pem_sbwgr;
 HFONT               hOldFont;
 INIT_WEDIT*         piwed;
 HDC                 hdc;
 TEXTMETRIC          tm;


 caller.cr = pCaller->cr;
 caller.mr = This->OID;

 switch(Act)
 {
 case CMD_INITIALIZE:
  assert(sizeof(INIT_WEDIT) == Qty);
  piwed = (INIT_WEDIT*)IStrm;
  pem->style = piwed->style;
  pem->nSpcRow = piwed->nSpcRow;
  pem->nSpcClm = piwed->nSpcClm;
  pem->text = piwed->text;
  pem->cpty = piwed->cpty;
  pem->clen = piwed->clen;
  pem->format = piwed->format;
  pem->font = piwed->font;
  pem->crsel = piwed->crsel;
  pem->crnor = piwed->crnor;
  pem->crbgsel = piwed->crbgsel;

  pem->hBmpLRIntArea = piwed->hBmpLRIntArea;
  pem->nHSBHeight = piwed->nHSBHeight;
  pem->nVSBWidth = piwed->nVSBWidth;
  pem->GetBitmapsForHScrollBar = piwed->GetBitmapsForHScrollBar;
  pem->GetBitmapsForVScrollBar = piwed->GetBitmapsForVScrollBar;
  return IR_P;
 case SET_WGI_WINDOWPOS:
  VO_Interact2(pem->pWGrinterface, SET_WGI_WINDOWPOS, IStrm, sizeof(WINPOSINFO), &caller);
  Paint(This, NULL, &caller);
  return IR_P;
 case SET_WGI_TIRECT:
  assert(Qty >= sizeof(RECT));
  pem_wgr->ti.rect = *(RECT*)IStrm;
  Paint(This, NULL, &caller);
  return IR_P;
 case SET_WGI_TEXT:
  assert(Qty < (BYTKTY)pem_wgr->ti.cpty);
  wcscpy(pem_wgr->ti.text, (TCHAR*)IStrm);
  pem_wgr->ti.clen = Qty;
  Paint(This, NULL, &caller);
  return IR_P;
 case MSG_WGI_FOCUSOVERMOVE:
  assert(sizeof(POINT) == Qty);
  if(pem->pHScrBar != NULL)
  {
   pem_parwdl = (EM_WDIALOG*)GetEMofBN(pem_wgr->pParentWnd, MSN_WDIALOG);
   pem_sbwgr = (EM_WGRINTERFACE*)GetEMofBN(pem->pHScrBar, MSN_WGRINTERFACE);
   if(PtInRect(&pem_sbwgr->rect, *(POINT*)IStrm))
   {
    pem_parwdl->ctrls.icwf = pem_sbwgr->no;
    VO_Interact2(pem->pHScrBar, MSG_WGI_FOCUSOVERMOVE, IStrm, sizeof(POINT), &caller);
    return IR_P;
   }
  }

  if(pem->pVScrBar != NULL)
  {
   pem_parwdl = (EM_WDIALOG*)GetEMofBN(pem_wgr->pParentWnd, MSN_WDIALOG);
   pem_sbwgr = (EM_WGRINTERFACE*)GetEMofBN(pem->pVScrBar, MSN_WGRINTERFACE);
   if(PtInRect(&pem_sbwgr->rect, *(POINT*)IStrm))
   {
    pem_parwdl->ctrls.icwf = pem_sbwgr->no;
    VO_Interact2(pem->pVScrBar, MSG_WGI_FOCUSOVERMOVE, IStrm, sizeof(POINT), &caller);
    return IR_P;
   }
  }

  return IR_P;
 case MSG_WGI_FOCUSBT1DOWN:
  assert(sizeof(POINT) == Qty);
  if(!pem->bFocus)
  {
   pem_parwgr = (EM_WGRINTERFACE*)GetEMofBN(pem_wgr->pParentWnd, MSN_WGRINTERFACE);
   pem_parwpa = (EM_WPANEL*)GetEMofBN(pem_wgr->pParentWnd, MSN_WPANEL);
   CreateCaret(pem_parwpa->hWnd, NULL, pem->CaretWidth, pem->CharHeight);
   pem->bFocus = TRUE;
  }
  SetCaretPosByPoint(This, *(POINT*)IStrm);

  return IR_P;
 case MSG_WGI_FOCUSLOSE:
  assert(sizeof(POINT) == Qty);
  if(!PtInRect(&pem_wgr->rect,  *(POINT*)IStrm))
  {
   DestroyCaret();
   pem->bFocus = FALSE;
   pem->bCaretVisible = FALSE;
  }
  return IR_P;
 case MSG_WGI_KEYDOWN:
  assert(sizeof(int) <= Qty);
  pem_parwgr = (EM_WGRINTERFACE*)GetEMofBN(pem_wgr->pParentWnd, MSN_WGRINTERFACE);
  pem_parwpa = (EM_WPANEL*)GetEMofBN(pem_wgr->pParentWnd, MSN_WPANEL);
  switch (*(int*)IStrm)
  {
  case VK_RIGHT:  // right arrow
   MoveCaretToNextCharacter(This);
   break;
  case VK_LEFT:  // left arrow
   MoveCaretToPrevCharacter(This);
   break;
  case VK_HOME:
   MoveCaretToRowBeginning(This);
   return IR_P;
  case VK_END:
   MoveCaretToRowEnd(This);
   return IR_P;
  case VK_UP:
   MoveCaretToPrevRow(This);
   break;
  case VK_DOWN:
   MoveCaretToNextRow(This);
   break;
  case VK_DELETE:
   if(pem->nCaretChar == pem->clen)
   {
    ShowCaret(pem_parwpa->hWnd);
    return IR_N;
   }
   Delete(This, pem->nCaretChar, pem->nCaretChar, &caller);
   break;
  default:
   return IR_P;
  }
  return IR_P;
 case MSG_WGI_CHAR:
  assert(sizeof(TCHAR) <= Qty);
  pem_parwpa = (EM_WPANEL*)GetEMofBN(pem_wgr->pParentWnd, MSN_WPANEL);
  switch (*(TCHAR*)IStrm)
  {
  case 0x08:  // backspace
   if(0 == pem->nCaretChar)
   {
    ShowCaret(pem_parwpa->hWnd);
    return IR_N;
   }
   Delete(This, pem->nCaretChar-1, pem->nCaretChar-1, &caller);
   break;
  default:    // displayable character
   if(pem->clen == pem->cpty)
   {
    ShowCaret(pem_parwpa->hWnd);
    return IR_N;
   }

   memmove(pem->text + pem->nCaretChar + 1, pem->text + pem->nCaretChar, (pem->clen - pem->nCaretChar) * sizeof(TCHAR));
   if(0x0D == *(TCHAR*)IStrm) // "Enter" key ?
   {
    if(pem->style & ES_SINGLELINE)
     return IR_P;
    pem->text[pem->nCaretChar] = 0x0A;
   }else
   {
    pem->text[pem->nCaretChar] = *(TCHAR*)IStrm;
   }
   pem->clen++;
   CalculateText(This, &caller);
   MoveCaretToNextCharacter(This);
   Paint(This, NULL, &caller);
   break;
  }
  return IR_P;
 case SET_WGI_FONT:
  assert(sizeof(HFONT) == Qty);
  pem->font = *(HFONT*)IStrm;

  pem_parwpa = (EM_WPANEL*)GetEMofBN(pem_wgr->pParentWnd, MSN_WPANEL);
  hdc = GetDC(pem_parwpa->hWnd);
  
  if(pem->font)
   hOldFont = SelectObject(hdc, pem->font);
  
  // Get the metrics of the current font. 
  GetTextMetrics(hdc, &tm);
  
  if(pem->font)
   SelectObject(hdc, hOldFont);
  
  ReleaseDC(pem_parwpa->hWnd, hdc); 
  pem->CharHeight = tm.tmHeight;
  WriteText(This, &caller);
  return IR_P;
 default:
  break;
 }


 /* 在上面完成接口自己的任务。*/

 SBO_OBJECT_INTERACT2;
}

/**
*
* 名称:WEdit_Interact3
*/
static IRESULT  WEdit_Interact3(OBJECT* This, ACTION Act, BYTE* IStrm, BYTKTY Qty, BYTE* OStrm, BYTKTY Cty, BYTKTY* pQty, const VR* pCaller)
{
 EM_WEDIT*           pem = (EM_WEDIT*)This->pEM;
 EM_WGRINTERFACE* pem_wgr = (EM_WGRINTERFACE*)pem->pWGrinterface->pEM;
 SI32                delta;
 VR                  caller;
 float               fSCtoEnd;
 long                n;
 
 caller.cr = pCaller->cr;
 caller.mr = This->OID;

 switch(Act)
 {
 case CMD_WGI_HFROLL3:
 case CMD_WGI_HBROLL3:
  assert(sizeof(SI32) == Qty);
  assert(sizeof(float) == Cty);

  delta = *(SI32*)IStrm;
  
  if(CMD_WGI_HFROLL3 == Act)
  {
   n = pem_wgr->rcfi.right - pem_wgr->rcfi.left;
   pem->xDelta -= delta;
   if(n - pem->xDelta > pem->CttWidth)
    pem->xDelta = n - pem->CttWidth;
   fSCtoEnd = (float) (pem->CttWidth + pem->xDelta - n) / pem->CttWidth;
  }else
  {
   n = pem_wgr->rcfi.right - pem_wgr->rcfi.left;
   pem->xDelta += delta;
   if(pem->xDelta > 0)
    pem->xDelta = 0;
   fSCtoEnd = (float) (-pem->xDelta) / pem->CttWidth;
  }
  
  Paint(This, NULL, &caller);

  *(float*)OStrm = fSCtoEnd;
  *pQty = sizeof(float);
  return IR_P;
 case CMD_WGI_VFROLL3:
 case CMD_WGI_VBROLL3:
  assert(sizeof(SI32) == Qty);
  assert(sizeof(float) == Cty);

  delta = *(SI32*)IStrm;
  
  if(CMD_WGI_VFROLL3 == Act)
  {
   n = pem_wgr->rcfi.bottom - pem_wgr->rcfi.top;
   pem->yDelta -= delta;
   if(n - pem->yDelta > pem->CttHeight)
    pem->yDelta = n - pem->CttHeight;
   fSCtoEnd = (float) (pem->CttHeight + pem->yDelta - n) / pem->CttHeight;
  }else
  {
   n = pem_wgr->rcfi.bottom - pem_wgr->rcfi.bottom;
   pem->yDelta += delta;
   if(pem->yDelta > 0)
    pem->yDelta = 0;
   fSCtoEnd = (float) (-pem->yDelta) / pem->CttHeight;
  }
  
  Paint(This, NULL, &caller);

  *(float*)OStrm = fSCtoEnd;
  *pQty = sizeof(float);

  return IR_P;
 default:
  break;
 }

 /* 在上面完成接口自己的任务。*/

 SBO_OBJECT_INTERACT3;
}

/**
*
* 名称:WEdit_Close
*/
static IRESULT  WEdit_Close(OBJECT* This, const VR* pCaller)
{
 EM_WEDIT*  pem = (EM_WEDIT*)This->pEM;
 EM_WGRINTERFACE*  pem_wgr = (EM_WGRINTERFACE*)pem->pWGrinterface->pEM;

 OBS_OBJECT_CLOSE_;

 /* 在下面完成接口自己的任务。*/

 if(0 == This->RefCnt)
 {
  if(pem->pAPWC)
   free(pem->pAPWC);
  return IR_P_RCZERO;
 }

 return IR_P;
}

/*========================+ TOG +========================*/

/**
*
* 名称:TOG_WEdit
*/
VOID  TOG_WEdit(OBJECT* pObj)
{
 pObj->Open = WEdit_Open;
 pObj->Input = WEdit_Input;
 pObj->Output = WEdit_Output;
 pObj->IOput = WEdit_IOput;
 pObj->Interact0 = WEdit_Interact0;
 pObj->Interact1 = WEdit_Interact1;
 pObj->Interact2 = WEdit_Interact2;
 pObj->Interact3 = WEdit_Interact3;
 pObj->Close = WEdit_Close;
}

/*=======================+ IRF(s) +======================*/
/* ... */

/*====================+ Function(s) +====================*/


/**
*
* NAME: CreateHScrollBar
* DESC: Create horizontal scroll bar.
*/
static  BOOL  CreateHScrollBar(OBJECT* This, int length, SI32 scrlen, const VR* pCaller)
{
 EM_WEDIT*            pem = (EM_WEDIT*)This->pEM;
 EM_WGRINTERFACE*  pem_wgr = (EM_WGRINTERFACE*)pem->pWGrinterface->pEM;
 EM_WGRINTERFACE*     pem_parwgr;
 EM_WDIALOG*          pem_parwdl;
 INIT_WGRINTERFACE    iwgr;
 INIT_WSCROLLBAR      iwsb;
 SCROLLBARBITMAPS     sbbmps;
 CONTROL**            ppACtrl;
 OBJECT*              pObject;
    int                  x, y;

 assert(NULL == pem->pHScrBar);

 if(pem->nHSBHeight > pem_wgr->rcfi.bottom - pem_wgr->rcfi.top)
  pem->nHSBHeight = pem_wgr->rcfi.bottom - pem_wgr->rcfi.top;

 pem_parwgr = (EM_WGRINTERFACE*)GetEMofBN(pem_wgr->pParentWnd, MSN_WGRINTERFACE);
 pem_parwdl = (EM_WDIALOG*)GetEMofBN(pem_wgr->pParentWnd, MSN_WDIALOG);

 memset(&iwgr, 0, sizeof(INIT_WGRINTERFACE));
 memset(&iwsb, 0, sizeof(INIT_WSCROLLBAR));

 CreateObject(MSN_WSCROLLBAR, 0, 0, 1, &pem->pHScrBar);
 VO_Open(pem->pHScrBar, pCaller);

 x = pem_wgr->rect.left + pem_wgr->rcfi.left;
 y = pem_wgr->rect.top + pem_wgr->rcfi.bottom - pem->nHSBHeight;

 pem->GetBitmapsForHScrollBar(pem_wgr->pParentWnd, &sbbmps);
 iwsb.pOwner = This;
 iwsb.scrlen = scrlen;
 iwsb.hBmpBase = sbbmps.hBmpBase;
 iwsb.hBmpBRBNormal = sbbmps.hBmpBRBNormal;
 iwsb.hBmpBRBOver = sbbmps.hBmpBRBOver;
 iwsb.hBmpBRBDown = sbbmps.hBmpBRBDown;
 iwsb.hBmpFRBNormal = sbbmps.hBmpFRBNormal;
 iwsb.hBmpFRBOver = sbbmps.hBmpFRBOver;
 iwsb.hBmpFRBDown = sbbmps.hBmpFRBDown;
 iwsb.hBmpRBNormal = sbbmps.hBmpRBNormal;
 iwsb.hBmpRBOver = sbbmps.hBmpRBOver;
 iwsb.hBmpRBDown = sbbmps.hBmpRBDown;
 
 iwgr.hInstance = pem_wgr->hInstance;
 iwgr.pParentWnd = pem_wgr->pParentWnd;
 iwgr.no = pem_wgr->no - 2;
 iwgr.rect.left = x;
 iwgr.rect.right = x + length;
 iwgr.rect.top = y;
 iwgr.rect.bottom = y + pem->nHSBHeight;
 iwgr.rcfi.left = 1;
 iwgr.rcfi.top = 1;
 iwgr.rcfi.right = length - 1;
 iwgr.rcfi.bottom = pem->nHSBHeight - 1;

 ppACtrl = &pem_parwdl->ctrls.pACtrl;
 (*ppACtrl)[pem_wgr->no-2].pCtrl = pem->pHScrBar;
 (*ppACtrl)[pem_wgr->no-2].rect.left = pem_parwgr->rcfi.left + iwgr.rect.left;
 (*ppACtrl)[pem_wgr->no-2].rect.top = pem_parwgr->rcfi.top + iwgr.rect.top;
 (*ppACtrl)[pem_wgr->no-2].rect.right = pem_parwgr->rcfi.left + iwgr.rect.right;
 (*ppACtrl)[pem_wgr->no-2].rect.bottom = pem_parwgr->rcfi.top + iwgr.rect.bottom; 

 pObject = GetBN(pem->pHScrBar, MSN_WGRINTERFACE);
 VO_Interact2(pObject, CMD_INITIALIZE, (BYTE*)&iwgr, sizeof(INIT_WGRINTERFACE), pCaller);
 VO_Interact2(pem->pHScrBar, CMD_INITIALIZE, (BYTE*)&iwsb, sizeof(INIT_WSCROLLBAR), pCaller);
 VO_Interact0(pem->pHScrBar, CMD_PREPARE, pCaller);

 pem_wgr->rcfi.bottom -= pem->nHSBHeight;

 return  TRUE;
}

/**
*
* NAME: CreateVScrollBar
* DESC: Create vertical scroll bar.
*/
static  BOOL  CreateVScrollBar(OBJECT* This, int length, SI32 scrlen, const VR* pCaller)
{
 EM_WEDIT*            pem = (EM_WEDIT*)This->pEM;
 EM_WGRINTERFACE*  pem_wgr = (EM_WGRINTERFACE*)pem->pWGrinterface->pEM;
 EM_WGRINTERFACE*     pem_parwgr;
 EM_WDIALOG*          pem_parwdl;
 INIT_WGRINTERFACE    iwgr;
 INIT_WSCROLLBAR      iwsb;
 SCROLLBARBITMAPS     sbbmps;
 CONTROL**            ppACtrl;
 OBJECT*              pObject;
    int                  x, y;

 assert(NULL == pem->pVScrBar);

 if(pem->nVSBWidth > pem_wgr->rcfi.right - pem_wgr->rcfi.left)
  pem->nVSBWidth = pem_wgr->rcfi.right - pem_wgr->rcfi.left;

 pem_parwgr = (EM_WGRINTERFACE*)GetEMofBN(pem_wgr->pParentWnd, MSN_WGRINTERFACE);
 pem_parwdl = (EM_WDIALOG*)GetEMofBN(pem_wgr->pParentWnd, MSN_WDIALOG);

 memset(&iwgr, 0, sizeof(INIT_WGRINTERFACE));
 memset(&iwsb, 0, sizeof(INIT_WSCROLLBAR));

 CreateObject(MSN_WSCROLLBAR, 0, 0, 1, &pem->pVScrBar);
 VO_Open(pem->pVScrBar, pCaller);

 x = pem_wgr->rect.left + pem_wgr->rcfi.right - pem->nVSBWidth;
 y = pem_wgr->rect.top + pem_wgr->rcfi.top;

 pem->GetBitmapsForVScrollBar(pem_wgr->pParentWnd, &sbbmps);
 iwsb.pOwner = This;
 iwsb.scrlen = scrlen;
 iwsb.hBmpBase = sbbmps.hBmpBase;
 iwsb.hBmpBRBNormal = sbbmps.hBmpBRBNormal;
 iwsb.hBmpBRBOver = sbbmps.hBmpBRBOver;
 iwsb.hBmpBRBDown = sbbmps.hBmpBRBDown;
 iwsb.hBmpFRBNormal = sbbmps.hBmpFRBNormal;
 iwsb.hBmpFRBOver = sbbmps.hBmpFRBOver;
 iwsb.hBmpFRBDown = sbbmps.hBmpFRBDown;
 iwsb.hBmpRBNormal = sbbmps.hBmpRBNormal;
 iwsb.hBmpRBOver = sbbmps.hBmpRBOver;
 iwsb.hBmpRBDown = sbbmps.hBmpRBDown;
 
 iwgr.hInstance = pem_wgr->hInstance;
 iwgr.pParentWnd = pem_wgr->pParentWnd;
 iwgr.no = pem_wgr->no - 1;
 iwgr.rect.left = x;
 iwgr.rect.right = x + pem->nVSBWidth;
 iwgr.rect.top = y;
 iwgr.rect.bottom = y + length;
 iwgr.rcfi.left = 1;
 iwgr.rcfi.top = 1;
 iwgr.rcfi.right = pem->nVSBWidth - 1;
 iwgr.rcfi.bottom = length - 1;

 ppACtrl = &pem_parwdl->ctrls.pACtrl;
 (*ppACtrl)[pem_wgr->no-1].pCtrl = pem->pVScrBar;
 (*ppACtrl)[pem_wgr->no-1].rect.left = pem_parwgr->rcfi.left + iwgr.rect.left;
 (*ppACtrl)[pem_wgr->no-1].rect.top = pem_parwgr->rcfi.top + iwgr.rect.top;
 (*ppACtrl)[pem_wgr->no-1].rect.right = pem_parwgr->rcfi.left + iwgr.rect.right;
 (*ppACtrl)[pem_wgr->no-1].rect.bottom = pem_parwgr->rcfi.top + iwgr.rect.bottom; 

 pObject = GetBN(pem->pVScrBar, MSN_WGRINTERFACE);
 VO_Interact2(pObject, CMD_INITIALIZE, (BYTE*)&iwgr, sizeof(INIT_WGRINTERFACE), pCaller);
 VO_Interact2(pem->pVScrBar, CMD_INITIALIZE, (BYTE*)&iwsb, sizeof(INIT_WSCROLLBAR), pCaller);
 VO_Interact0(pem->pVScrBar, CMD_PREPARE, pCaller);

 pem_wgr->rcfi.right -= pem->nVSBWidth;

 return  TRUE;
}

/**
*
* NAME: DestroyScrollBar
*/
static  BOOL  DestroyScrollBar(OBJECT* This, const VR* pCaller)
{
 EM_WEDIT*            pem = (EM_WEDIT*)This->pEM;
 EM_WGRINTERFACE*  pem_wgr = (EM_WGRINTERFACE*)pem->pWGrinterface->pEM;
 EM_WDIALOG*          pem_parwdl;
 CONTROL**            ppACtrl;
 
 assert(pem->pHScrBar != NULL || pem->pVScrBar != NULL);
 
 pem_parwdl = (EM_WDIALOG*)GetEMofBN(pem_wgr->pParentWnd, MSN_WDIALOG);

 ppACtrl = &pem_parwdl->ctrls.pACtrl;

 if(pem->pHScrBar != NULL)
 {
  VO_Close(pem->pHScrBar, pCaller);
  DestroyObject(pem->pHScrBar);
  (*ppACtrl)[pem_wgr->no-2].pCtrl = NULL;

  pem_wgr->rcfi.bottom += pem->nHSBHeight;
 }
 
 if(pem->pVScrBar != NULL)
 {
  VO_Close(pem->pVScrBar, pCaller);
  DestroyObject(pem->pVScrBar);
  (*ppACtrl)[pem_wgr->no-1].pCtrl = NULL;

  pem_wgr->rcfi.right += pem->nVSBWidth;
 }

 pem_parwdl->ctrls.iccf = -1;
 pem_parwdl->ctrls.ichf = pem_wgr->no;
 pem_parwdl->ctrls.icwf = pem_wgr->no;

 return  TRUE;
}

/**
*
* 名称:CalculateText
*/
static  void  CalculateText(OBJECT* This, const VR* pCaller)
{
 EM_WEDIT*           pem = (EM_WEDIT*)This->pEM;
 EM_WGRINTERFACE* pem_wgr = (EM_WGRINTERFACE*)pem->pWGrinterface->pEM;
 EM_WPANEL*          pem_parwpa = (EM_WPANEL*)GetEMofBN(pem_wgr->pParentWnd, MSN_WPANEL);
 HFONT               hOldFont;
 HDC                 hdc;
 SIZE                size;
 BOOL                bCVSB, bCHSB;
 long                rcfiLeft, rcfiRight, rcfiTop, rcfiBottom;
 SI32                cttw;
 long                i, n, m;


 if(!(pem->style & ES_HSCROLLBAR) && (pem->pHScrBar != NULL))
  DestroyScrollBar(This, pCaller);
 else if(!(pem->style & ES_VSCROLLBAR) && (pem->pVScrBar != NULL))
  DestroyScrollBar(This, pCaller);


 hdc = GetDC(pem_parwpa->hWnd);
 
 if(pem->font)
  hOldFont = SelectObject(hdc, pem->font);

 bCVSB = bCHSB = FALSE;
 rcfiLeft = pem_wgr->rcfi.left;
 rcfiRight = (pem->pVScrBar != NULL) ? pem_wgr->rcfi.right + pem->nVSBWidth : pem_wgr->rcfi.right;
 rcfiTop = pem_wgr->rcfi.top;
 rcfiBottom = (pem->pHScrBar != NULL) ? pem_wgr->rcfi.bottom + pem->nHSBHeight : pem_wgr->rcfi.bottom;
 
 pem->NumRow = 1;
 n = m = 0;
 pem->CttWidth = cttw = 0;
 for(i=0; i<pem->clen; i++)
 {
  if(pem->style & ES_SINGLELINE)
  {
   GetTextExtentPoint32(hdc, pem->text+i, 1, &size);
   pem->pAPWC[i].x = n;
   pem->pAPWC[i].y = 0;
   pem->CttWidth = n + size.cx; 
   n += size.cx + pem->nSpcClm;
  }else
  {
   if(0x0A == pem->text[i])
   {
    pem->pAPWC[i].x = n;
    pem->pAPWC[i].y = m;
    n = 0;
    m += pem->CharHeight + pem->nSpcRow;
    pem->NumRow++;
    if(cttw > pem->CttWidth)
     pem->CttWidth = cttw;
    cttw = 0;
   }else
   {
    GetTextExtentPoint32(hdc, pem->text+i, 1, &size);
    if(!(pem->style & ES_UNAUTOLINEFEED))
    {
     if(rcfiLeft + n + size.cx > rcfiRight)
     {
      n = 0;
      m += pem->CharHeight + pem->nSpcRow;
      pem->NumRow++;
      cttw = 0;
     }
    }
    pem->pAPWC[i].x = n;
    pem->pAPWC[i].y = m;
    cttw = n + size.cx; 
    if(cttw > pem->CttWidth)
     pem->CttWidth = cttw;
    n += size.cx + pem->nSpcClm;
   }
  }
 }
 
 pem->CttHeight = pem->NumRow * (pem->CharHeight + pem->nSpcRow) - pem->nSpcRow;
 
 if(pem->font)
  SelectObject(hdc, hOldFont);
 ReleaseDC(pem_parwpa->hWnd, hdc);


 if(pem->pHScrBar != NULL)
 {
  if(pem->pVScrBar != NULL)
  {
   if(pem->CttWidth <= rcfiRight - rcfiLeft - pem->nVSBWidth
    || pem->CttHeight <= rcfiBottom - rcfiTop - pem->nHSBHeight)
    DestroyScrollBar(This, pCaller);
  }else
  {
   if(pem->CttWidth <= rcfiRight - rcfiLeft)
    DestroyScrollBar(This, pCaller);
  }
 }else if(pem->pVScrBar != NULL)
 {
  if(pem->CttHeight <= rcfiBottom - rcfiTop)
   DestroyScrollBar(This, pCaller);
 }
 
 if((pem->style & ES_HSCROLLBAR) && (NULL == pem->pHScrBar))
 {
  n = (pem->pVScrBar != NULL) ? pem->nVSBWidth : 0;
  if(pem->CttWidth > rcfiRight - rcfiLeft - n)
   bCHSB = TRUE;
 }
 
 if((pem->style & ES_VSCROLLBAR) && (NULL == pem->pVScrBar))
 {
  n = (pem->pHScrBar != NULL) ? pem->nHSBHeight : 0;
  if(pem->CttHeight > rcfiBottom - rcfiTop - n)
   bCVSB = TRUE;
 }
 
 if(TRUE == bCHSB)
 {
  if(pem->pVScrBar != NULL)
  {
   DestroyScrollBar(This, pCaller);
   CreateVScrollBar(This, pem_wgr->rcfi.bottom - pem_wgr->rcfi.top - pem->nHSBHeight, pem->CttHeight, pCaller);
   n = pem_wgr->rcfi.right - pem_wgr->rcfi.left;
  }else if(TRUE == bCVSB)
  {
   n = pem_wgr->rcfi.right - pem_wgr->rcfi.left - pem->nVSBWidth;
  }else
  {
   n =  pem_wgr->rcfi.right - pem_wgr->rcfi.left;
  }

  CreateHScrollBar(This, n, pem->CttWidth, pCaller);
 }else if(pem->pHScrBar != NULL && pem->lastCttWidth != pem->CttWidth)
 {
  VO_Interact2(pem->pHScrBar, MSG_WGI_SCRLENCHANGED, (BYTE*)&pem->CttWidth, sizeof(UI32), pCaller);
 }
 
 if(TRUE == bCVSB)
 {
  if(pem->pHScrBar != NULL)
  {
   DestroyScrollBar(This, pCaller);
   CreateHScrollBar(This, pem_wgr->rcfi.right - pem_wgr->rcfi.left - pem->nVSBWidth, pem->CttWidth, pCaller);
  }

  CreateVScrollBar(This, pem_wgr->rcfi.bottom - pem_wgr->rcfi.top, pem->CttHeight, pCaller);
 }else if(pem->pVScrBar != NULL && pem->lastCttHeight != pem->CttHeight)
 {
  VO_Interact2(pem->pVScrBar, MSG_WGI_SCRLENCHANGED, (BYTE*)&pem->CttHeight, sizeof(UI32), pCaller);
 }

 pem->lastCttWidth = pem->CttWidth;
 pem->lastCttHeight = pem->CttHeight;

 return;
}

/**
*
* 名称:MakeCaretVisible
*/
static  void  MakeCaretVisible(OBJECT* This)
{
 EM_WEDIT*           pem = (EM_WEDIT*)This->pEM;
 EM_WGRINTERFACE* pem_wgr = (EM_WGRINTERFACE*)pem->pWGrinterface->pEM;
 EM_WPANEL*          pem_parwpa = (EM_WPANEL*)GetEMofBN(pem_wgr->pParentWnd, MSN_WPANEL);
 
 if(pem->bCaretVisible)
  return;

 ShowCaret(pem_parwpa->hWnd);
 pem->bCaretVisible = TRUE;

 return;
}


/**
*
* 名称:MakeCaretInvisible
*/
static  void  MakeCaretInvisible(OBJECT* This)
{
 EM_WEDIT*           pem = (EM_WEDIT*)This->pEM;
 EM_WGRINTERFACE* pem_wgr = (EM_WGRINTERFACE*)pem->pWGrinterface->pEM;
 EM_WPANEL*          pem_parwpa = (EM_WPANEL*)GetEMofBN(pem_wgr->pParentWnd, MSN_WPANEL);
 
 if(!pem->bCaretVisible)
  return;

 HideCaret(pem_parwpa->hWnd);
 pem->bCaretVisible = FALSE;

 return;
}

/**
*
* 名称:SetCaretPosByPoint
*/
static  void  SetCaretPosByPoint(OBJECT* This, POINT pt)
{
 EM_WEDIT*           pem = (EM_WEDIT*)This->pEM;
 EM_WGRINTERFACE* pem_wgr = (EM_WGRINTERFACE*)pem->pWGrinterface->pEM;
 EM_WGRINTERFACE*    pem_parwgr = (EM_WGRINTERFACE*)GetEMofBN(pem_wgr->pParentWnd, MSN_WGRINTERFACE);
 EM_WPANEL*          pem_parwpa = (EM_WPANEL*)GetEMofBN(pem_wgr->pParentWnd, MSN_WPANEL);
 SIZE                oldSize, newSize;
 HFONT               hOldFont;
 HDC                 hdc;
 RECT                rc;
 int                 i;
 
 if(pem->clen > 0)
 {   
  hdc = GetDC(pem_parwpa->hWnd);
  
  if(pem->font)
   hOldFont = SelectObject(hdc, pem->font);
  
  pt.x -= pem_wgr->rect.left + pem_wgr->rcfi.left;
  pt.y -= pem_wgr->rect.top + pem_wgr->rcfi.top;
  
  i=0;
  pem->nCaretRow = 0;
  while(1)
  {
   if(pem->text[i] != 0x0A)
   {
    GetTextExtentPoint32(hdc, pem->text+i, 1, &newSize);
    
    if(0 == i)
    {
     pem->nCaretRow = 1;
     pem->nCaretClm = 1;

     rc.left = rc.top = 0;
     rc.right = newSize.cx / 2;
     rc.bottom = newSize.cy + pem->nSpcRow / 2;
    }else
    {
     if(pem->pAPWC[i].y > pem->pAPWC[i-1].y)
     {
      pem->nCaretRow++;
      pem->nCaretClm = 1;

      rc.left = rc.right;
      rc.right = pem_wgr->rcfi.right-pem_wgr->rcfi.left;
      if(PtInRect(&rc, pt))
       break;
      
      rc.left = 0;
      rc.right = newSize.cx / 2;
      rc.top = rc.bottom;
      rc.bottom += pem->nSpcRow + newSize.cy;
     }else
     {
      pem->nCaretClm++;

      rc.left = rc.right;
      rc.right += pem->nSpcClm + (oldSize.cx + newSize.cx) / 2;
     }
    }
    
    if(PtInRect(&rc, pt))
     break;

    oldSize = newSize;
   }else
   {
    pem->nCaretRow++;
    pem->nCaretClm = 0;
   }
   
   if(++i == pem->clen)
    break; 
  }
  
  pem->nCaretChar = i;
  
  if(pem->font)
   SelectObject(hdc, hOldFont);
  
  ReleaseDC(pem_parwpa->hWnd, hdc);
 }else
 {
  pem->nCaretChar = 0;
  pem->nCaretRow = 1;
  pem->nCaretClm = 0;
 }

 SetCaretPosBYnCaretChar(This, SET_CARETPOS_BY_POINT);
}

/**
*
* 名称:SetCaretPosBYnCaretChar
*/
static  void  SetCaretPosBYnCaretChar(OBJECT* This, const UI32 flag)
{
 EM_WEDIT*           pem = (EM_WEDIT*)This->pEM;
 EM_WGRINTERFACE* pem_wgr = (EM_WGRINTERFACE*)pem->pWGrinterface->pEM;
 EM_WGRINTERFACE*    pem_parwgr = (EM_WGRINTERFACE*)GetEMofBN(pem_wgr->pParentWnd, MSN_WGRINTERFACE);
 EM_WPANEL*          pem_parwpa = (EM_WPANEL*)GetEMofBN(pem_wgr->pParentWnd, MSN_WPANEL);
 HFONT               hOldFont;
 HDC                 hdc;
 SIZE                size;
 int                 i, x, y;

 if(pem->nCaretChar > 0)
 {
  i = pem->nCaretChar-1;
  do{
   if(pem->nCaretChar < pem->clen)
   {
    if((pem->pAPWC[pem->nCaretChar].y > pem->pAPWC[i].y) && (pem->text[pem->nCaretChar] != 0x0A))
    {
     if(!(flag & MOVE_CARET_TO_ROWEND)
      && !(flag & MOVE_CARET_TO_PREVROW)
      && !(flag & MOVE_CARET_TO_NEXTROW)
      || (flag & MOVE_CARET_TO_PREVROW && 0 == pem->nCaretClm)
      || (flag & MOVE_CARET_TO_NEXTROW && 0 == pem->nCaretClm))
     {
      pem->CaretX = 0;
      pem->CaretY = pem->pAPWC[pem->nCaretChar].y;
      break;
     }
    }
   }
   
   if(0x0A == pem->text[i])
   {
    pem->CaretX = 0;
    pem->CaretY = pem->pAPWC[i].y + pem->CharHeight + pem->nSpcRow;
   }else
   {
    pem->CaretX = pem->pAPWC[i].x;
    hdc = GetDC(pem_parwpa->hWnd);
    if(pem->font)
     hOldFont = SelectObject(hdc, pem->font);
    
    GetTextExtentPoint32(hdc, pem->text+i, 1, &size);
    
    if(pem->font)
     SelectObject(hdc, hOldFont);
    ReleaseDC(pem_parwpa->hWnd, hdc);
    
    pem->CaretX += size.cx;
    pem->CaretY = pem->pAPWC[i].y;
   }
   break;
  }while(1);
 }else if(0 == pem->clen)
 {
  pem->CaretX = 0;
  pem->CaretY = 0;
 }else
 {
  pem->CaretX = pem->pAPWC[0].x;
  pem->CaretY = pem->pAPWC[0].y;
 }

 x = pem->CaretX + pem_parwgr->rcfi.left + pem_wgr->rect.left + pem_wgr->rcfi.left;
 y = pem->CaretY + pem_parwgr->rcfi.top + pem_wgr->rect.top + pem_wgr->rcfi.top;

 SetCaretPos(x, y);

 if(pem->CaretX >= 0 && pem->CaretX <= pem_wgr->rcfi.right && pem->CaretY >= 0 && pem->CaretY <= pem_wgr->rcfi.bottom)
  MakeCaretVisible(This);

 return;
}


/**
*
* 名称:MoveCaretToPrevCharacter
*/
static  void  MoveCaretToPrevCharacter(OBJECT* This)
{
 EM_WEDIT*           pem = (EM_WEDIT*)This->pEM;
 int                 i, j;
 
 if(0 == pem->nCaretChar)
  return;

 i = pem->nCaretChar - 1;
 if(i >= 0)
 {
  do{
   if(pem->pAPWC[i].y < pem->CaretY)
   {
    pem->nCaretRow--;

    for(j = i; j >= 0 ; j--)
    {
     if(pem->pAPWC[j].y < pem->pAPWC[i].y)
      break;
    }

    pem->nCaretClm = j >= 0 ? i-j : i;
   }else
   {
    pem->nCaretClm--;
   }
   break;
  }while(0);
 }else
 {
  pem->nCaretRow = 1;
  pem->nCaretClm = 0;
 }

 pem->nCaretChar--;

 SetCaretPosBYnCaretChar(This, MOVE_CARET_TO_PREVCHARACTER);

 return;
}

/**
*
* 名称:MoveCaretToNextCharacter
*/
static  void  MoveCaretToNextCharacter(OBJECT* This)
{
 EM_WEDIT*           pem = (EM_WEDIT*)This->pEM;

 if(pem->nCaretChar == pem->clen)
  return;

 if(pem->pAPWC[pem->nCaretChar].y > pem->CaretY || 0x0A == pem->text[pem->nCaretChar])
 {
  pem->nCaretRow++;
  pem->nCaretClm = pem->text[pem->nCaretChar] != 0x0A ? 1 : 0;
 }else if((pem->nCaretChar+1 < pem->clen)
  && (pem->pAPWC[pem->nCaretChar+1].y > pem->CaretY && pem->text[pem->nCaretChar+1] != 0x0A))
 {
   pem->nCaretRow++;
   pem->nCaretClm = 0;
 }else
 {
  pem->nCaretClm++;
 }

 pem->nCaretChar++;

 SetCaretPosBYnCaretChar(This, MOVE_CARET_TO_NEXTCHARACTER);

 return;
}

/**
*
* 名称:MoveCaretToPrevRow
*/
static  void  MoveCaretToPrevRow(OBJECT* This)
{
 EM_WEDIT*           pem = (EM_WEDIT*)This->pEM;
 int                 i, j, n, m, y;
 
 if(1 == pem->nCaretRow)
  return;

 y = pem->CaretY;
 j = 0;
 for(i = pem->nCaretChar-1; i >= 0; i--)
 {
  if(pem->pAPWC[i].y < y)
  {
   if(2 == ++j)
    break;

   y = pem->pAPWC[i].y;
  }
 }
 
 i++;
 n = i + pem->nCaretClm;
 m = 0;
 for(j=i; j < n ; j++)
 {
  if(0x0A == pem->text[j])
  {
   m++;
   continue;
  }

  if(pem->pAPWC[j].y > y)
   break;
 }

 j -= m;
 if(0x0A == pem->text[i])
 {
  if(j > i)
   pem->nCaretClm = j - i - 1;
  else
   pem->nCaretClm = j - i;
 }else
 {
  pem->nCaretClm = j - i;
 }
 pem->nCaretChar = i + pem->nCaretClm;
 pem->nCaretRow--;

 SetCaretPosBYnCaretChar(This, MOVE_CARET_TO_PREVROW);

 return;
}

/**
*
* 名称:MoveCaretToNextRow
*/
static  void  MoveCaretToNextRow(OBJECT* This)
{
 EM_WEDIT*           pem = (EM_WEDIT*)This->pEM;
 int                 i, j, n, y;
 
 if(pem->nCaretRow == pem->NumRow)
  return;

 y = pem->CaretY;
 for(i = pem->nCaretChar-1; i < pem->clen; i++)
 {
  if(pem->pAPWC[i].y > y)
  {
   y = pem->pAPWC[i].y;
   break;
  }
 }
 
 n = 0;
 for(j=i; j < pem->clen ; j++)
 {
  if(0x0A == pem->text[j])
  {
   n++;
   continue;
  }

  if(pem->pAPWC[j].y > y)
   break;
 }

 j -= n;
 if(j-i < pem->nCaretClm)
  pem->nCaretClm = j-i;
 pem->nCaretChar = i + pem->nCaretClm;
 pem->nCaretRow++;

 SetCaretPosBYnCaretChar(This, MOVE_CARET_TO_NEXTROW);

 return;
}

/**
*
* 名称:MoveCaretToRowBeginning
*/
static  void  MoveCaretToRowBeginning(OBJECT* This)
{
 EM_WEDIT*           pem = (EM_WEDIT*)This->pEM;
 EM_WGRINTERFACE* pem_wgr = (EM_WGRINTERFACE*)pem->pWGrinterface->pEM;
 EM_WGRINTERFACE*    pem_parwgr = (EM_WGRINTERFACE*)GetEMofBN(pem_wgr->pParentWnd, MSN_WGRINTERFACE);
 int                 i;

 pem->nCaretClm = 0;
 pem->CaretX = 0;

 if(pem->nCaretChar > 0)
 {
  for(i = pem->nCaretChar-1; i < pem->clen; i--)
  {
   if(pem->pAPWC[i].y < pem->CaretY)
    break;
  }
  pem->nCaretChar = i+1;
 }

 SetCaretPosBYnCaretChar(This, MOVE_CARET_TO_ROWBEGINNING);

 return;
}

/**
*
* 名称:MoveCaretToRowEnd
*/
static  void  MoveCaretToRowEnd(OBJECT* This)
{
 EM_WEDIT*           pem = (EM_WEDIT*)This->pEM;
 //EM_WGRINTERFACE* pem_wgr = (EM_WGRINTERFACE*)pem->pWGrinterface->pEM;
 //EM_WGRINTERFACE*    pem_parwgr = (EM_WGRINTERFACE*)GetEMofBN(pem_wgr->pParentWnd, MSN_WGRINTERFACE);
 //EM_WPANEL*          pem_parwpa = (EM_WPANEL*)GetEMofBN(pem_wgr->pParentWnd, MSN_WPANEL);
 int                 i, n;
 
 if(pem->nCaretChar == pem->clen)
  return;
 
 for(i = pem->nCaretChar; i < pem->clen; i++)
 {
  if(pem->pAPWC[i].y > pem->CaretY || 0x0A == pem->text[i])
   break;
 }
 
 n = pem->nCaretChar;
 pem->nCaretChar = i;
 pem->nCaretClm += pem->nCaretChar - n;
 SetCaretPosBYnCaretChar(This, MOVE_CARET_TO_ROWEND);
 return;
}


/**
*
* 名称:Delete
*/
static  void  Delete(OBJECT* This, int iFirst, int iLast, const VR* pCaller)
{
 EM_WEDIT*           pem = (EM_WEDIT*)This->pEM;
 int                 i, y;
 
 pem->clen -= iLast-iFirst+1;
 memmove(pem->text+iFirst, pem->text+iLast+1, pem->clen * sizeof(TCHAR));
 CalculateText(This, pCaller);

 if(pem->clen > 0)
 {
  pem->nCaretRow = 1;
  pem->nCaretClm = 0;
  pem->nCaretChar = iFirst;
  y = pem->pAPWC[0].y;
  for(i=0; i < iFirst; i++)
  {
   if(0x0A == pem->text[i])
   {
    pem->nCaretRow++;
    pem->nCaretClm = 0;
    if(i < iFirst-1)
     y = pem->pAPWC[i+1].y;
    continue;
   }

   if(pem->pAPWC[i].y > y)
   {
    pem->nCaretRow++;
    pem->nCaretClm = 0;
    y = pem->pAPWC[i].y;
    continue;
   }

   pem->nCaretClm++;
  }
 }else
 {
  pem->nCaretRow = 1;
  pem->nCaretClm = 0;
  pem->nCaretChar = 0;
 }

 SetCaretPosBYnCaretChar(This, DELETE_CHARACTER);
 Paint(This, NULL, pCaller);

 return;
}

/**
*
* 名称:WriteText
*/
static  void  WriteText(OBJECT* This, const VR* pCaller)
{
 CalculateText(This, pCaller);
 Paint(This, NULL, pCaller);
 return;
}


/**
*
* 名称:Prepaint
* 描述:hBitmap - the bitmap to paint on the control. If NULL, paints the hBmpCurrent.
*/
static void  Prepaint(OBJECT* This, HBITMAP hBitmap)
{
 EM_WEDIT*           pem = (EM_WEDIT*)This->pEM;
 EM_WGRINTERFACE*    pem_wgr = (EM_WGRINTERFACE*)pem->pWGrinterface->pEM;
 EM_WGRINTERFACE*    pem_parwgr = (EM_WGRINTERFACE*)GetEMofBN(pem_wgr->pParentWnd, MSN_WGRINTERFACE);
 EM_WPANEL*          pem_parwpa = (EM_WPANEL*)GetEMofBN(pem_wgr->pParentWnd, MSN_WPANEL);
// EM_WDIALOG*         pem_parwdl = (EM_WDIALOG*)GetEMofBN(pem_wgr->pParentWnd, MSN_WDIALOG);
 EM_WGRINTERFACE*    pem_sbwgr;
 HBITMAP             hNewBmp, hOldBmp1, hOldBmp2, hOldBmp3;
 HDC                 hdc, memdc1, memdc2, memdc3;
 HFONT               hOldFont;
 COLORREF            crOldColor;
 RECT                rc;
 BITMAP              bm;
 long                i, n, m, w, h, x, y;

 x = pem_parwgr->rcfi.left + pem_wgr->rect.left;
 y = pem_parwgr->rcfi.top + pem_wgr->rect.top;
 w = pem_wgr->rect.right - pem_wgr->rect.left;
 h = pem_wgr->rect.bottom - pem_wgr->rect.top;

 hdc = GetDC(pem_parwpa->hWnd);
 memdc1 = CreateCompatibleDC(hdc);
 memdc2 = CreateCompatibleDC(hdc);

 hOldBmp1 = SelectObject(memdc1, pem_parwgr->hBmpCurrent);

 if(!hBitmap)
  hBitmap = pem_wgr->hBmpCurrent;
 hOldBmp2 = SelectObject(memdc2, hBitmap);
 
 GetObject(hBitmap, sizeof(bm), &bm);
 //BitBlt(memdc1, x, y, w, h, memdc2, 0, 0, SRCCOPY);
 StretchBlt(memdc1, x, y, w, h, memdc2, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);

 SetBkMode(memdc1, TRANSPARENT);

 if(pem_wgr->ti.clen > 0)
 {
  if(pem_wgr->ti.font)
   hOldFont = SelectObject(memdc1, pem_wgr->ti.font);
  crOldColor = SetTextColor(memdc1, pem_wgr->ti.color);
  
  rc = pem_wgr->ti.rect;
  n = pem_parwgr->rcfi.left + pem_wgr->rect.left + pem_wgr->rcfi.left;
  m = pem_parwgr->rcfi.top + pem_wgr->rect.top + pem_wgr->rcfi.top;
  rc.left += n;
  rc.top += m;
  rc.right += n;
  rc.bottom += m;
  DrawText(memdc1, pem_wgr->ti.text, pem_wgr->ti.clen, &rc, pem_wgr->ti.format);
  
  if(pem_wgr->ti.font)
   SelectObject(memdc1, hOldFont);
  SetTextColor(memdc1, crOldColor);
 }

 if(pem->clen > 0)
 {
  memdc3 = CreateCompatibleDC(hdc);
  w = pem_wgr->rcfi.right - pem_wgr->rcfi.left;
  h = pem_wgr->rcfi.bottom - pem_wgr->rcfi.top;
  hNewBmp = CreateCompatibleBitmap(hdc, w, h);
  hOldBmp3 = SelectObject(memdc3, hNewBmp);
  BitBlt(memdc3, 0, 0, w, h, memdc2, pem_wgr->rcfi.left, pem_wgr->rcfi.top, SRCCOPY);

  if(pem->font)
   hOldFont = SelectObject(memdc3, pem->font);
  crOldColor = SetTextColor(memdc3, pem->crnor);
  SetBkMode(memdc3, TRANSPARENT);

  for(i=0; i<pem->clen; i++)
  {
   if(0x0A == pem->text[i])
    continue;
   TextOut(memdc3, pem->pAPWC[i].x + pem->xDelta, pem->pAPWC[i].y + pem->yDelta, pem->text+i, 1);
  }

  if(pem->font)
   SelectObject(memdc3, hOldFont);
  SetTextColor(memdc3, crOldColor);

  x = pem_parwgr->rcfi.left + pem_wgr->rect.left + pem_wgr->rcfi.left;
  y = pem_parwgr->rcfi.top + pem_wgr->rect.top + pem_wgr->rcfi.top;
  BitBlt(memdc1, x, y, w, h, memdc3, 0, 0, SRCCOPY);

  SelectObject(memdc3, hOldBmp3);
  DeleteDC(memdc3);
  DeleteObject(hNewBmp);
 }

 if(pem->pHScrBar != NULL)
 {
  pem_sbwgr = (EM_WGRINTERFACE*)GetEMofBN(pem->pHScrBar, MSN_WGRINTERFACE);
  SelectObject(memdc2, pem_sbwgr->hBmpCurrent);
  x = pem_parwgr->rcfi.left + pem_wgr->rect.left + pem_wgr->rcfi.left;
  y = pem_parwgr->rcfi.top + pem_wgr->rect.top + pem_wgr->rcfi.bottom;
  w = pem_sbwgr->rect.right - pem_sbwgr->rect.left;
  h = pem->nHSBHeight;
  StretchBlt(memdc1, x, y, w, h, memdc2, 0, 0, w, h, SRCCOPY);
  if(pem->pVScrBar != NULL)
  {
   GetObject(pem->hBmpLRIntArea, sizeof(bm), &bm);
   SelectObject(memdc2, pem->hBmpLRIntArea);
   StretchBlt(memdc1, x+w, y, pem->nVSBWidth, pem->nHSBHeight, memdc2, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
  }
 }

 if(pem->pVScrBar != NULL)
 {
  pem_sbwgr = (EM_WGRINTERFACE*)GetEMofBN(pem->pVScrBar, MSN_WGRINTERFACE);
  SelectObject(memdc2, pem_sbwgr->hBmpCurrent);
  x = pem_parwgr->rcfi.left + pem_wgr->rect.left + pem_wgr->rcfi.right;
  y = pem_parwgr->rcfi.top + pem_wgr->rect.top + pem_wgr->rcfi.top;
  w = pem->nVSBWidth;
  h = pem_sbwgr->rect.bottom - pem_sbwgr->rect.top;
  StretchBlt(memdc1, x, y, w, h, memdc2, 0, 0, w, h, SRCCOPY);
 }
 
 SelectObject(memdc1, hOldBmp1);
 DeleteDC(memdc1);
 SelectObject(memdc2, hOldBmp2);
 DeleteDC(memdc2);
 ReleaseDC(pem_parwpa->hWnd, hdc);

 return;
}


/**
*
* 名称:Paint
* 描述:hBitmap - the bitmap to paint on the control. If NULL, paints the hBmpCurrent.
*/
static void  Paint(OBJECT* This, HBITMAP hBitmap, const VR* pCaller)
{
 EM_WEDIT*        pem = (EM_WEDIT*)This->pEM;
 EM_WGRINTERFACE*    pem_wgr = (EM_WGRINTERFACE*)pem->pWGrinterface->pEM;
 EM_WGRINTERFACE*    pem_parwgr = (EM_WGRINTERFACE*)GetEMofBN(pem_wgr->pParentWnd, MSN_WGRINTERFACE);
 EM_WPANEL*          pem_parwpa = (EM_WPANEL*)GetEMofBN(pem_wgr->pParentWnd, MSN_WPANEL);
// EM_WDIALOG*         pem_parwdl = (EM_WDIALOG*)GetEMofBN(pem_wgr->pParentWnd, MSN_WDIALOG);
 HDC                 hdc, memdc;
 HBITMAP             hOldBmp;
 int                 w, h, x, y;

 if(pem->bCaretVisible)
  HideCaret(pem_parwpa->hWnd);

 Prepaint(This, hBitmap);

 x = pem_parwgr->rcfi.left + pem_wgr->rect.left;
 y = pem_parwgr->rcfi.top + pem_wgr->rect.top;
 w = pem_wgr->rect.right - pem_wgr->rect.left;
 h = pem_wgr->rect.bottom - pem_wgr->rect.top;

 hdc = GetDC(pem_parwpa->hWnd);
 memdc = CreateCompatibleDC(hdc);
 hOldBmp = SelectObject(memdc, pem_parwgr->hBmpCurrent);
 BitBlt(hdc, x, y, w, h, memdc, x, y, SRCCOPY);
 ReleaseDC(pem_parwpa->hWnd, hdc);

 SelectObject(memdc, hOldBmp);
 DeleteDC(memdc);

 if(pem->bCaretVisible)
  ShowCaret(pem_parwpa->hWnd);

 return;
}