WGI的WMenu.c文件源代码


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

#include "WMenu.h"
#include "../../../se/wgi.h"
#include "../WButton/WButton.h"

 

static const TCHAR gs_szWindowClass[] = TEXT("WMenu");

VOID  TOG_WMenu(OBJECT* pObj);
static ATOM  MyRegisterClass(HINSTANCE hInstance);
static LRESULT CALLBACK WMenuProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
static int  CalculateWidthOfText(HDC  hdc, TCHAR*  text, BYTKTY  len);
static  float  RollAndCalculateScale2End(OBJECT* This, SI32 delta, int flag, const VR* pCaller);


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

/*<oicc>*/
/*<ibn> WDialog </ibn>*/
/*<crt>*/
FRESULT  CRT_WMenu(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_WDialog(OBJECT* pObj);
 extern  VOID  TOG_WPanel(OBJECT* pObj);
 extern  VOID  TOG_WGrinterface(OBJECT* pObj);
 extern  VOID  TOG_OIOIC(OBJECT* pObj);


 UI32   ux_ND = 5;  /* ND数量。*/
 UI32   ux_BN = 10;  /* 各ND的BN数量之和。*/
 UI32   ux_IB = 4;  /* 各ND的IBN数量之和。*/
 UI32   ux_CS = NumCR * 15;  /* 各ND的最少CS数量之和。*/
 UI32   ux_EM = sizeof(EM_WMENU) + sizeof(EM_WDIALOG) + sizeof(EM_WPANEL)
   + 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[4];
  BYTE*    p = pIC + sizeof(OBJECT) * ux_ND;


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

  /** WMenu **/
  pND = (OBJECT*)pIC;
  TOG_WMenu(pND);
  pND->MSN = MSN_WMENU;
  pND->OID = (*pOID)++;
  pND->po_AND = (OBJECT*)pIC;
  pND->NND = ux_ND;

  /** WDialog **/
  TOG_WDialog(++pND);
  pND->MSN = MSN_WDIALOG;
  pND->OID = (*pOID)++;
  pND->po_AND = (OBJECT*)pIC;
  pND->NND = ux_ND;

  /** WPanel **/
  TOG_WPanel(++pND);
  pND->MSN = MSN_WPANEL;
  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  ***/

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

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

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

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

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

  /** WDialog **/
  ++pND;

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

  /* - ABN - */
  pND->ppo_ABN = (OBJECT**)p;
  ArrMsn[0] = MSN_WPANEL;
  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 * 2;
  p += sizeof(VR) * pND->NCS;

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

  /** WPanel **/
  ++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 * 3;
  p += sizeof(VR) * pND->NCS;

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

  /** 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 * 4;
  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 * 5;
  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 +=====================*/

/**
*
* 名称:WMenu_Open
*/
static IRESULT  WMenu_Open(OBJECT* This, const VR* pCaller)
{
 EM_WMENU*  pem = (EM_WMENU*)This->pEM;

 OBS_OBJECT_OPEN_;

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


 if(1 == This->RefCnt)
 {
  pem->pWGrinterface = GetBN(This, MSN_WGRINTERFACE);
  pem->pWPanel = GetBN(This, MSN_WPANEL);
  pem->pWDialog = GetBN(This, MSN_WDIALOG);
  pem->pWndProc = WMenuProc;
 }


 return IR_P;
}

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

 /* ... */


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

 SBO_OBJECT_INPUT;
}

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

 /* ... */


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

 SBO_OBJECT_OUTPUT;
}

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

 /* ... */


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

 SBO_OBJECT_IOPUT;
}

/**
*
* 名称:WMenu_Interact0
*/
static IRESULT  WMenu_Interact0(OBJECT* This, ACTION Act, const VR* pCaller)
{
 VR      caller;
 EM_WMENU*           pem = (EM_WMENU*)This->pEM;
 EM_WGRINTERFACE* pem_wgr = (EM_WGRINTERFACE*)pem->pWGrinterface->pEM;
 EM_WPANEL*          pem_wpa = (EM_WPANEL*)pem->pWPanel->pEM;
 EM_WDIALOG*         pem_wdl = (EM_WDIALOG*)pem->pWDialog->pEM;
 CONTROL**           ppACtrl = &pem_wdl->ctrls.pACtrl;
 CONTROL*            pACtrl;
 OBJECT*             poWGrinterface;
 EM_WPANEL*          pem_parwpa;
 INIT_WGRINTERFACE   iwgr;
 INIT_WBUTTON        iwbt;
 INIT_WSCROLLBAR     iwsb;
 SCROLLBARBITMAPS    sbbmps;
 WINPOSINFO          wpi;
 MENUITEM*           pmit;
 HDC                 hdc;
 HFONT               hOldFont;
 SIZE                size;
 BITMAP              bm;
 SI32                delta;
 SI32                maxWidth, maxHeight;
 SI32                nHeightItem ;
 SI32                nWidthMenu;
 SI32                nHeightMenu;
 int                 i, n;


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

 switch(Act)
 {
 case CMD_PREPARE:
  if(0 == MyRegisterClass(pem_wgr->hInstance))
   return IR_N;
  return IR_P;
 case CMD_WGI_POP: 
  pem_parwpa = (EM_WPANEL*)GetEMofBN(pem_wgr->pParentWnd, MSN_WPANEL);
  pem_wpa->hWnd = CreateWindowEx(0, gs_szWindowClass, NULL, WS_POPUP | WS_VISIBLE,
   pem_wgr->rect.left, pem_wgr->rect.top, 0, 0, pem_parwpa->hWnd, NULL, pem_wgr->hInstance, NULL);

  SetWindowLong(pem_wpa->hWnd, GWL_USERDATA, (LONG)This);
  hdc = GetDC(pem_wpa->hWnd);
  if(pem_wgr->ti.font)
   hOldFont = SelectObject(hdc, pem_wgr->ti.font);

  n = maxWidth = maxHeight = 0;
  pmit = pem->pfirstmit;
  do
  { 
   GetTextExtentPoint32(hdc, pmit->text, wcslen(pmit->text), &size);
   if(size.cx > maxWidth)
    maxWidth = size.cx;
   if(size.cy > maxHeight)
    maxHeight = size.cy;
   n++;
   pmit = pmit->next;
  }while(pmit != NULL);
 
  if(pem_wgr->ti.font)
   SelectObject(hdc, hOldFont);

  nHeightItem = (pem->style & MS_ITEMHEIGHTBMP) ? 0 : maxHeight;
  nWidthMenu = (pem->style & MS_ITEMWIDTHSPS) ? pem_wgr->rect.right - pem_wgr->rect.left : maxWidth;
  nHeightMenu = (pem->style & MS_ITEMHEIGHTBMP) ? 0 : n * nHeightItem;

  *ppACtrl = (CONTROL*)calloc(n, sizeof(CONTROL));
  if(NULL == *ppACtrl)
   return IR_N;
  // initialize Dialog
  pem_wdl->ctrls.num = n;

  memset(&iwgr, 0, sizeof(INIT_WGRINTERFACE));
  memset(&iwbt, 0, sizeof(INIT_WBUTTON));
  
  iwgr.hInstance = pem_wgr->hInstance;
  iwgr.pParentWnd = This;
  iwgr.ti.font = pem_wgr->ti.font;
  iwgr.ti.color = pem_wgr->ti.color;
  iwbt.crTextNormal = pem->crMITNormal;
  iwbt.crTextOver = pem->crMITOver;
  iwbt.crTextDown = pem->crMITDown;
  iwbt.crTextDisable = pem->crMITDisable;

  i = 0;
  pmit = pem->pfirstmit;
  do
  {
   CreateObject(MSN_WBUTTON, 0, 0, 1, &(*ppACtrl)[i].pCtrl);
   VO_Open((*ppACtrl)[i].pCtrl, &caller);

   pem->GetBitmapsForItem(pem_wgr->pParentWnd, pmit);

   iwbt.hBmpOver = pmit->hBmpOver;
   iwbt.hBmpNormal = pmit->hBmpNormal;
   iwbt.hBmpDown = pmit->hBmpDown;
   iwbt.hBmpDisable = pmit->hBmpDisable;
   iwgr.hBmpCurrent = iwbt.hBmpNormal;

   (*ppACtrl)[i].rect.left = 0;
   (*ppACtrl)[i].rect.right = (*ppACtrl)[i].rect.left + nWidthMenu;
   if(pem->style & MS_ITEMHEIGHTBMP)
   {
    GetObject(iwgr.hBmpCurrent, sizeof(bm), &bm);
    (*ppACtrl)[i].rect.top += nHeightMenu;
    (*ppACtrl)[i].rect.bottom = (*ppACtrl)[i].rect.top + bm.bmHeight;
    nHeightMenu += bm.bmHeight;
   }else
   {
    (*ppACtrl)[i].rect.top = i * nHeightItem;
    (*ppACtrl)[i].rect.bottom = (*ppACtrl)[i].rect.top + nHeightItem;
   }
   
   iwgr.rect.left = (*ppACtrl)[i].rect.left;
   iwgr.rect.top = (*ppACtrl)[i].rect.top;
   iwgr.rect.right = (*ppACtrl)[i].rect.right;
   iwgr.rect.bottom = (*ppACtrl)[i].rect.bottom;

   iwgr.ti.text = pmit->text;
   iwgr.ti.cpty = sizeof(pmit->text) / sizeof(TCHAR);
   iwgr.ti.clen = wcslen(pmit->text);
   iwgr.ti.format = TF_LEFT;
   iwgr.ti.rect.left = iwgr.ti.rect.top = 0;
   iwgr.ti.rect.right = nWidthMenu;
   iwgr.ti.rect.bottom = nHeightItem;

   poWGrinterface = GetBN((*ppACtrl)[i].pCtrl, MSN_WGRINTERFACE);
   VO_Interact2(poWGrinterface, CMD_INITIALIZE, (BYTE*)&iwgr, sizeof(INIT_WGRINTERFACE), &caller);
   VO_Interact2((*ppACtrl)[i].pCtrl, CMD_INITIALIZE, (BYTE*)&iwbt, sizeof(INIT_WBUTTON), &caller);

   i++;
   pmit = pmit->next;
  }while(pmit != NULL);

  if(!(pem->style & MS_AUTOHEIGHT))
  {
   if(nHeightMenu > pem_wgr->rect.bottom - pem_wgr->rect.top)
   {
    if(pem->style & MS_VSCROLLBAR)
    {
     n = i+1;
     pACtrl = (CONTROL*)calloc(n, sizeof(CONTROL));
     if(NULL == pACtrl)
      return IR_N;
  
     memcpy(pACtrl, pem_wdl->ctrls.pACtrl, sizeof(CONTROL) * pem_wdl->ctrls.num);
     free(pem_wdl->ctrls.pACtrl);
     pem_wdl->ctrls.pACtrl = pACtrl;
     pem_wdl->ctrls.num = n;

     pem->GetBitmapsForVScrollBar(pem_wgr->pParentWnd, &sbbmps);
     GetObject(sbbmps.hBmpBRBNormal, sizeof(bm), &bm);

     for(i = 0; i < n-1; i++)
     {
      (*ppACtrl)[i].rect.right -= bm.bmWidth + 2;
      wpi.x = (*ppACtrl)[i].rect.left;
      wpi.y = (*ppACtrl)[i].rect.top;
      wpi.cx = (*ppACtrl)[i].rect.right - (*ppACtrl)[i].rect.left;
      wpi.cy = (*ppACtrl)[i].rect.bottom - (*ppACtrl)[i].rect.top;
      poWGrinterface = GetBN((*ppACtrl)[i].pCtrl, MSN_WGRINTERFACE);
      VO_Interact2(poWGrinterface, SET_WGI_WINDOWPOS, (BYTE*)&wpi, sizeof(WINPOSINFO), &caller);
     }
     
     memset(&iwsb, 0, sizeof(INIT_WSCROLLBAR));

     iwsb.pOwner = This;
     iwsb.scrlen = nHeightMenu;
     nHeightMenu = pem_wgr->rect.bottom - pem_wgr->rect.top;

     // create Scroll Bar
     CreateObject(MSN_WSCROLLBAR, 0, 0, 1, &(*ppACtrl)[i].pCtrl);
     VO_Open((*ppACtrl)[i].pCtrl, &caller);
     
     (*ppACtrl)[i].rect.right = pem_wgr->rect.right - pem_wgr->rect.left;
     (*ppACtrl)[i].rect.bottom = pem_wgr->rect.bottom - pem_wgr->rect.top;
     (*ppACtrl)[i].rect.left = (*ppACtrl)[i].rect.right - bm.bmWidth - 2;
     (*ppACtrl)[i].rect.top = 0;
     iwgr.rect.left = (*ppACtrl)[i].rect.left;
     iwgr.rect.top = (*ppACtrl)[i].rect.top;
     iwgr.rect.right = (*ppACtrl)[i].rect.right;
     iwgr.rect.bottom = (*ppACtrl)[i].rect.bottom;
     iwgr.rcfi.left = 1;
     iwgr.rcfi.top = 1;
     iwgr.rcfi.right = iwgr.rect.right - iwgr.rect.left - iwgr.rcfi.left;
     iwgr.rcfi.bottom = iwgr.rect.bottom - iwgr.rect.top - iwgr.rcfi.top;
     memset(&iwgr.ti, 0, sizeof(TEXTINFO));
     poWGrinterface = GetBN((*ppACtrl)[i].pCtrl, MSN_WGRINTERFACE);
     VO_Interact2(poWGrinterface, CMD_INITIALIZE, (BYTE*)&iwgr, sizeof(INIT_WGRINTERFACE), &caller);
     
     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;
     
     VO_Interact2((*ppACtrl)[i].pCtrl, CMD_INITIALIZE, (BYTE*)&iwsb, sizeof(INIT_WSCROLLBAR), &caller);
     VO_Interact0((*ppACtrl)[i].pCtrl, CMD_PREPARE, &caller);

     pem->nScrCtrl = 1;
    }
   }
  }

  ReleaseDC(pem_wpa->hWnd, hdc);

  if(MS_UPDOWN & pem->style && MS_UPPOP & pem->style)
   pem_wgr->rect.top -= nHeightMenu;
  pem_wgr->rect.right = pem_wgr->rect.left + nWidthMenu;
  pem_wgr->rect.bottom = pem_wgr->rect.top + nHeightMenu;
  SendMessage(pem_wpa->hWnd, WM_INITDIALOG, 0, 0);
  // ShowWindow(pem_wpa->hWnd, SW_SHOW);
  SetWindowPos(pem_wpa->hWnd, HWND_TOP, pem_wgr->rect.left, pem_wgr->rect.top,
   nWidthMenu, nHeightMenu, SWP_SHOWWINDOW);

  return IR_P;
 case CMD_WGI_VFROLLTOEND:
 case CMD_WGI_VBROLLTOEND:
  n = pem_wdl->ctrls.num-pem->nScrCtrl;
  if(CMD_WGI_VFROLLTOEND == Act)
  {
   delta = pem_wgr->rect.bottom - pem_wgr->rect.top - (*ppACtrl)[n-1].rect.bottom;
   if(0 == delta)
    return IR_P;
  }else
  {
   delta = -(*ppACtrl)[0].rect.top;
   if(0 == delta)
    return IR_P;
  }

  for(i=0; i<n; i++)
  {
   (*ppACtrl)[i].rect.top += delta;
   (*ppACtrl)[i].rect.bottom += delta;
   wpi.x = (*ppACtrl)[i].rect.left;
   wpi.y = (*ppACtrl)[i].rect.top;
   wpi.cx = (*ppACtrl)[i].rect.right - (*ppACtrl)[i].rect.left;
   wpi.cy = (*ppACtrl)[i].rect.bottom - (*ppACtrl)[i].rect.top;
   VO_Interact2((*ppACtrl)[i].pCtrl, SET_WGI_WINDOWPOS, (BYTE*)&wpi, sizeof(WINPOSINFO), &caller);
  }
  return IR_P;
 case CMD_WGI_HFROLLTOEND:
 case CMD_WGI_HBROLLTOEND:
  return IR_P;
 default:
  break;
 }


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

 SBO_OBJECT_INTERACT0;
}

/**
*
* 名称:WMenu_Interact1
*/
static IRESULT  WMenu_Interact1(OBJECT* This, ACTION Act, BYTE* OStrm, BYTKTY Cty, BYTKTY* pQty, const VR* pCaller)
{
 VR     caller;
 EM_WMENU*            pem = (EM_WMENU*)This->pEM;
 EM_WGRINTERFACE*  pem_wgr = (EM_WGRINTERFACE*)pem->pWGrinterface->pEM;
 SI32                 delta;
 int                  flag;

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

 switch(Act)
 {
 case CMD_WGI_HFPAGE:
 case CMD_WGI_HBPAGE:
  return IR_P;
 case CMD_WGI_VFPAGE:
 case CMD_WGI_VBPAGE:
  delta = pem_wgr->rect.bottom - pem_wgr->rect.top;
  flag = CMD_WGI_VFPAGE == Act ? 0 : 1;
  *(float*)OStrm = RollAndCalculateScale2End(This, delta, flag, &caller);
  *pQty = sizeof(float);
  return IR_P;
 default:
  break;
 }


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

 SBO_OBJECT_INTERACT1;
}

/**
*
* 名称:WMenu_Interact2
*/
static IRESULT  WMenu_Interact2(OBJECT* This, ACTION  Act, BYTE* IStrm, BYTKTY Qty, const VR* pCaller)
{
 VR     caller;
 EM_WMENU*           pem = (EM_WMENU*)This->pEM;
 EM_WGRINTERFACE* pem_wgr = (EM_WGRINTERFACE*)pem->pWGrinterface->pEM;
 EM_WDIALOG*         pem_wdl = (EM_WDIALOG*)pem->pWDialog->pEM;
 CONTROL**           ppACtrl = &pem_wdl->ctrls.pACtrl;
 INIT_WMENU*         piwmu;
 SI32                delta;
 WINPOSINFO          wpi;
 int                 i, n, m;

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

 switch(Act)
 {
 case CMD_INITIALIZE:
  assert(sizeof(INIT_WMENU) == Qty);
  piwmu = (INIT_WMENU*)IStrm;
  pem->pfirstmit = piwmu->pfirstmit;
  pem->style = piwmu->style;
  pem->curitem = -1;
  pem->crMITNormal = piwmu->crMITNormal;
  pem->crMITOver = piwmu->crMITOver;
  pem->crMITDown = piwmu->crMITDown;
  pem->crMITDisable = piwmu->crMITDisable;
  pem->GetBitmapsForItem = piwmu->GetBitmapsForItem;
  pem->GetBitmapsForVScrollBar = piwmu->GetBitmapsForVScrollBar;
  return IR_P;
 case CMD_WGI_VFROLL2:
 case CMD_WGI_VBROLL2:
  assert(sizeof(SI32) == Qty);
  delta = *(SI32*)IStrm;

  n = pem_wdl->ctrls.num - pem->nScrCtrl;

  if(CMD_WGI_VFROLL2 == Act)
  {
   m = pem_wgr->rect.bottom - pem_wgr->rect.top;
   if((*ppACtrl)[n-1].rect.bottom == m)
    return IR_P;
   m = (*ppACtrl)[n-1].rect.bottom - m;
   if(delta > m)
    delta = m;
   delta = - delta;
  }else
  {
   m = (*ppACtrl)[0].rect.top;
   if(0 == m)
    return IR_P;
   if(delta > -m)
    delta = -m;
  }

  for(i=0; i<n; i++)
  {
   (*ppACtrl)[i].rect.top += delta;
   (*ppACtrl)[i].rect.bottom += delta;
   wpi.x = (*ppACtrl)[i].rect.left;
   wpi.y = (*ppACtrl)[i].rect.top;
   wpi.cx = (*ppACtrl)[i].rect.right - (*ppACtrl)[i].rect.left;
   wpi.cy = (*ppACtrl)[i].rect.bottom - (*ppACtrl)[i].rect.top;
   VO_Interact2((*ppACtrl)[i].pCtrl, SET_WGI_WINDOWPOS, (BYTE*)&wpi, sizeof(WINPOSINFO), &caller);
  }

  return IR_P;
 case CMD_WGI_HFROLL2:
 case CMD_WGI_HBROLL2:
  assert(sizeof(SI32) == Qty);
  return IR_P;
 default:
  break;
 }


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

 SBO_OBJECT_INTERACT2;
}

/**
*
* 名称:WMenu_Interact3
*/
static IRESULT  WMenu_Interact3(OBJECT* This, ACTION Act, BYTE* IStrm, BYTKTY Qty, BYTE* OStrm, BYTKTY Cty, BYTKTY* pQty, const VR* pCaller)
{
 VR     caller;
 int    flag;

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

 switch(Act)
 {
 case CMD_WGI_VFROLL3:
 case CMD_WGI_VBROLL3:
 assert(sizeof(SI32) == Qty);
  assert(sizeof(float) == Cty);
  flag = CMD_WGI_VFROLL3 == Act ? 0 : 1;
  *(float*)OStrm = RollAndCalculateScale2End(This, *(SI32*)IStrm, flag, &caller);
  *pQty = sizeof(float);
  return IR_P;
 case CMD_WGI_HFROLL3:
 case CMD_WGI_HBROLL3:
  assert(sizeof(SI32) == Qty);
  return IR_P;
 default:
  break;
 }


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

 SBO_OBJECT_INTERACT3;
}

/**
*
* 名称:WMenu_Close
*/
static IRESULT  WMenu_Close(OBJECT* This, const VR* pCaller)
{
 VR      caller;
 EM_WMENU*         pem = (EM_WMENU*)This->pEM;
 EM_WPANEL*        pem_wpa = (EM_WPANEL*)pem->pWPanel->pEM;

 OBS_OBJECT_CLOSE_;

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

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

 if(0 == This->RefCnt)
 {
  SendMessage(pem_wpa->hWnd, WM_CLOSE, 0, 0);
  if(pem->pSubMenu)
  {
   VO_Close(pem->pSubMenu, &caller);
   DestroyObject(pem->pSubMenu);
  }
  return IR_P_RCZERO;
 }

 return IR_P;
}

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

/**
*
* 名称:TOG_WMenu
*/
VOID  TOG_WMenu(OBJECT* pObj)
{
 pObj->Open = WMenu_Open;
 pObj->Input = WMenu_Input;
 pObj->Output = WMenu_Output;
 pObj->IOput = WMenu_IOput;
 pObj->Interact0 = WMenu_Interact0;
 pObj->Interact1 = WMenu_Interact1;
 pObj->Interact2 = WMenu_Interact2;
 pObj->Interact3 = WMenu_Interact3;
 pObj->Close = WMenu_Close;
}

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

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


/**
*
* 名称:RegisterClass
* 描述:
*/
static ATOM  MyRegisterClass(HINSTANCE hInstance)
{
 WNDCLASS wc;

 wc.style   = CS_HREDRAW | CS_VREDRAW;
 wc.lpfnWndProc     = (WNDPROC)WMenuProc;
 wc.cbClsExtra  = 0;
 wc.cbWndExtra  = 0;
 wc.hInstance  = hInstance;
 wc.hIcon   = NULL;
 wc.hCursor      = NULL;
 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
 wc.lpszMenuName     = NULL;
 wc.lpszClassName = gs_szWindowClass;

 return RegisterClass(&wc);
}


/**
*
* 名称:WMenuProc
* 描述:Mesage handler for WMenu.
*/
static LRESULT CALLBACK WMenuProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
 VR                caller;
 OBJECT*           This;
 EM_WMENU*         pem ;
 EM_WPANEL*        pem_wpa;
 EM_WGRINTERFACE*  pem_wgr;
 EM_WDIALOG*       pem_wdl;
 CONTROL**         ppACtrl;
 MENUINFO          mif;
 PAINTSTRUCT       ps;

 caller.mr = OID_MAIN;

 memset(&mif, 0, sizeof(MENUINFO));

 switch (message)
 {
 case WM_INITDIALOG:
  This = (OBJECT*)GetWindowLong(hWnd, GWL_USERDATA);
  pem = (EM_WMENU*)This->pEM;
  pem_wdl = (EM_WDIALOG*)pem->pWDialog->pEM;
  ppACtrl = &pem_wdl->ctrls.pACtrl;
  caller.cr = This->OID;
  VO_Interact0(pem->pWDialog, LOD_WGI_SKIN0, &caller);
  break;
 case WM_PAINT: 
  if(NULL == (This = (OBJECT*)GetWindowLong(hWnd, GWL_USERDATA)))
   break;
  pem = (EM_WMENU*)This->pEM;
  pem_wdl = (EM_WDIALOG*)pem->pWDialog->pEM;
  BeginPaint(hWnd, &ps);
  pem_wdl->pWndProc(hWnd, message, wParam, lParam);
  EndPaint(hWnd, &ps);
  return TRUE;
 case WM_MOUSEMOVE:
 case WM_LBUTTONDOWN:
 case WM_LBUTTONUP:
  This = (OBJECT*)GetWindowLong(hWnd, GWL_USERDATA);
  pem = (EM_WMENU*)This->pEM;
  pem_wgr = (EM_WGRINTERFACE*)pem->pWGrinterface->pEM;
     pem_wpa = (EM_WPANEL*)pem->pWPanel->pEM;
     pem_wdl = (EM_WDIALOG*)pem->pWDialog->pEM;
  caller.cr = This->OID;
  ppACtrl = &pem_wdl->ctrls.pACtrl;
  pem_wdl->pWndProc(hWnd, message, wParam, lParam);
  if(WM_MOUSEMOVE == message)
  {
   if(pem_wdl->ctrls.icwf > -1 && pem_wdl->ctrls.icwf < pem_wdl->ctrls.num - pem->nScrCtrl)
   {
    if(pem_wdl->ctrls.icwf != pem->curitem)
    {
     if(pem->pSubMenu)
     {
      VO_Close(pem->pSubMenu, &caller);
      DestroyObject(pem->pSubMenu);
     }

     if(NULL != (pem->pfirstmit + pem_wdl->ctrls.icwf)->nextlv)
     {
      mif.pfirstmit = (pem->pfirstmit + pem_wdl->ctrls.icwf)->nextlv;
      mif.style = 0;
      mif.style |= MS_AUTOWIDTH | MS_AUTOHEIGHT;
      mif.bSitu = FALSE;
      mif.hBmpBkgd = pem_wgr->hBmpCurrent;
      mif.hFont = pem_wgr->ti.font;
      mif.crMITNormal = pem->crMITNormal;
      mif.crMITOver = pem->crMITOver;
      mif.crMITDown = pem->crMITDown;
      mif.crMITDisable = pem->crMITDisable;
      mif.GetBitmapsForItem = pem->GetBitmapsForItem;
      pem->pSubMenu = PopMenu((*ppACtrl)[pem_wdl->ctrls.icwf].pCtrl, pem_wgr->pParentWnd, &mif, &caller);
     }
     pem->curitem = pem_wdl->ctrls.icwf;
    }
   }
  }else if(WM_LBUTTONUP == message)
  {
   if(pem_wdl->ctrls.icwf > -1 && pem_wdl->ctrls.icwf < pem_wdl->ctrls.num - pem->nScrCtrl && pem_wdl->ctrls.ichf < pem_wdl->ctrls.num - pem->nScrCtrl)
    VO_Interact2(pem_wgr->pParentWnd, MSG_WGI_ONMENUITEM, (BYTE*)&(pem->pfirstmit+pem_wdl->ctrls.icwf)->id, sizeof(int), &caller);
  }
  break;
 case WM_ERASEBKGND:
  return TRUE; // 消除移动窗口闪烁。
 case WM_CLOSE:
  DestroyWindow(hWnd);
  return TRUE;
 default:
  if(NULL == (This = (OBJECT*)GetWindowLong(hWnd, GWL_USERDATA)))
   break;
  pem = (EM_WMENU*)This->pEM;
  pem_wdl = (EM_WDIALOG*)pem->pWDialog->pEM;
  return pem_wdl->pWndProc(hWnd, message, wParam, lParam);
 }

 return TRUE;
}


/**
*
* NAME: CalculateWidthOfText
*/
static  int  CalculateWidthOfText(HDC hdc, TCHAR* text, BYTKTY len)
{
 BYTKTY      i;
 int         n;
 int         width = 0;
 
 for(i = 0; i < len; i++)
 {
  GetCharWidth32(hdc, (UINT)text[i], (UINT)text[i], &n);
  width += n;
 }

 return  width;
}


/**
*
* NAME: RollAndCalculateScale2End
* PARA: -- flag --
*       0 - vertically forward, 1 - vertically backward
*       2 - horizontally forward, 3 - horizontally backward
*/
static  float  RollAndCalculateScale2End(OBJECT* This, SI32 delta, int flag, const VR* pCaller)
{
 EM_WMENU*           pem = (EM_WMENU*)This->pEM;
 EM_WGRINTERFACE* pem_wgr = (EM_WGRINTERFACE*)pem->pWGrinterface->pEM;
 EM_WDIALOG*         pem_wdl = (EM_WDIALOG*)pem->pWDialog->pEM;
 CONTROL**           ppACtrl = &pem_wdl->ctrls.pACtrl;
 WINPOSINFO          wpi;
 float               fSCtoEnd;
 int                 i, n, m;
 
 n = pem_wdl->ctrls.num - pem->nScrCtrl;
 
 do
 {
  if(0 == flag)
  {
   m = pem_wgr->rect.bottom - pem_wgr->rect.top;
   if((*ppACtrl)[n-1].rect.bottom == m)
   {
    fSCtoEnd = 0.0;
    break;
   }
   
   m = (*ppACtrl)[n-1].rect.bottom - m;
   if(delta > m)
    delta = m;
   delta = - delta;
  }else if(1 == flag)
  {
   m = (*ppACtrl)[0].rect.top;
   if(0 == m)
   {
    fSCtoEnd = 0.0;
    break;
   }
   
   if(delta > -m)
    delta = -m;
  }else
  {
   assert(0);
  }
  
  for(i=0; i<n; i++)
  {
   (*ppACtrl)[i].rect.top += delta;
   (*ppACtrl)[i].rect.bottom += delta;
   wpi.x = (*ppACtrl)[i].rect.left;
   wpi.y = (*ppACtrl)[i].rect.top;
   wpi.cx = (*ppACtrl)[i].rect.right - (*ppACtrl)[i].rect.left;
   wpi.cy = (*ppACtrl)[i].rect.bottom - (*ppACtrl)[i].rect.top;
   VO_Interact2((*ppACtrl)[i].pCtrl, SET_WGI_WINDOWPOS, (BYTE*)&wpi, sizeof(WINPOSINFO), pCaller);
  }
  
  if(0 == flag)
  {
   m = pem_wgr->rect.bottom - pem_wgr->rect.top;
   fSCtoEnd = (float) ((*ppACtrl)[n-1].rect.bottom - m) / ((*ppACtrl)[n-1].rect.bottom - (*ppACtrl)[0].rect.top);
   break;
  }else if(1 == flag)
  {
   m = -(*ppACtrl)[0].rect.top;
   fSCtoEnd = (float) m / ((*ppACtrl)[n-1].rect.bottom - (*ppACtrl)[0].rect.top);
   break;
  }else
  {
   assert(0);
  }
 }while(0);
 
 return  fSCtoEnd;
}