coollang 发表于 2005-8-10 00:00:00

【专题文章】手机中的窗体

手机中的窗体

(我的例子中的函数都是以6688V55的地址为准,其他机型请大家参照查找响应函数,函数肯能有所差别)

一、浅谈手机中的窗体机制
在西门子的手机中使用了消息驱动的窗体机制,非常类似于windows中的机制。因为我对其运行机制并不是完全了解,所以在这里只说一下我的了解。
在西门子的手机中一个窗体的基本元素有标题,图标,滚动条,菜单项(菜单项图标,类似于List的Image),软键(按钮?)这些元素在具体的窗体中并不是全部出现的。我的理解是有一个基本的窗体,而其他的各种窗体只不过是这个窗体的实例化时的结果。而窗体的行为也类似于用windows的WindowsProc函数,响应具体的事件(类似的也有一个消息驱动的机制,很抱歉,我不能全部了解),比如大家经常看到这样的形式:
mov   [-r0], r9
mov   [-r0], r8
mov   r9, r13
mov   r8, r12
extp    r15, #1
mov   r12,
cmp   r12, #88h ; '?
jmpr    cc_Z, loc_D52318
cmp   r12, #90h ; '?
jmpr    cc_Z, loc_D52318
cmp   r12, #0F8h ; '?
jmpr    cc_Z, loc_D522F0
cmp   r12, #0F9h ; '?
jmpr    cc_Z, loc_D5230A
jmpr    cc_UC, loc_D52348

其实就是一个窗口函数的形式,而大家一般修改的按键响应我想只是OnKeyDown一样的函数。但是具体的消息定义我也不是很清楚。因为如此,我只总结一下我明白的东西,就当作是抛砖引玉,希望可以对大家有用!

二、一个基本的窗体
先说一个比较复杂的窗体,就是有标题,图标,滚动条,菜单的那种窗体,其实很多简单的窗体只是它的一个特列而已!主要是通过他来介绍一下常用的数据结构,为后面的理解作好准备。它涉及的主要函数有:

//创建窗体(需要注意的是int是16位整型,而所有指针都是32位的),需要注意的其他机型的
//函数可能和这个有所不同,但一般都有这两个结构参数。
int CreateMenu(int bBorder, int * ,int, wndFrame*, wndClass*, int*, int*, int*, int*)
//设置菜单项的信息,类似于windows的List控件的列表项自绘制函数,
//支持一个ImageList,而nImage则是序号,从0开始
int OnDrawMenuItem(int *, int *, int nImage)
//取得选中的菜单项的序号
int GetSelectMenuItem(struct MenuItem *)
//更新菜单项,这个函数会导致OnDrawMenuItem被调用,来更新菜单信息。
int UpdateMenuItem(struct MenuItem *)

//窗体的框架信息
struct wndFrame{
int unKnown_1;
int unKnown_2;
int ViewWidth;//窗体的视图区域宽度,比如菜单中可能只有中间一条是,类似于ClientRect
int ViewHeight; //窗体的视图区域高度
int *pImageID;//指向窗体图标序号的地址
int nTitleID;   //菜单标题的字串ID
int EndMask;    //通常7FFFh
}

typedef int (*MessgeFunction)(int *, int *); //回调函数指针

//窗口类信息
struct wndClass{
int * pUnknown_1;
MessgeFunction pOnkeyDown;                //按键响应函数
int * pUnknown_2;
int * pUnknown_3;
KeyCodeInfo * pKeyCodeInfo;                //窗体的软键信息       
KeyDefOrder * pKeyDefOrder;                //软键配置信息组
int nWndType;                                //窗体的类型信息
int nUnknown_4;
MessgeFunction OnMenuItemInit;         //菜单项初始化函数,注意是函数指针,请参考C语言相关内容。
MenuItem * pMenuItemList;                //菜单项结构列表       
MessgeFunction *pItemSelectFunList;         //菜单项被选中的函数
int nItemCount;                                //菜单项数量
}

//软键的虚键值信息
struct KeyCodeInfo{
KeyCodeDef * pKeyCodeDef;        //软键定义列表       
int nDefCount;                        //软键配置信息组的数量(有待商榷)
}

//软键的虚键值定义
struct KeyCodeDef
{
int nShortPressCode;                //短按软键的键值
int nLongPressCode;                //长按软键的键值
int nStringID;                        //软键显示的字串ID
}

//软键配置信息组
struct KeyDefOrder{
int nLeftKeyDefOrder;                //左软键的配置信息,是在软键定义列表中的序号
int nRightKeyDefOrder;                //右软键的配置信息,是在软键定义列表中的序号
}

//菜单项信息
struct MenuItem{       
int * nImageList;                //菜单的Image列表,以0结束       
int nNormalStringID;                //通常模式下的菜单字串ID
int nBigFontStrID;                //大字符模式下的菜单字串ID
int nUnkown_1                       
int * KeyDefOrder;                //菜单项被选择时软键的信息,比如选择框和帮助信息会在软键上有不同显示和虚键值。
int nType;                        //类型信息,细节未知
int nFlag;                        //标志,比如隐藏菜单就通过这个标志,系统由一个函数,用这个值作为参数来返回TRUE和FALSE信息。
}

具体的信息可以看Patch实例,用户配置菜单。因为程序过长,就不列出,有兴趣的可以看以前的帖子。
在那个程序中,主要实现的是函数有OnMenuItemInit,如下:

//菜单项初始化函数,R14是菜单项序号,开始于0
OnMenuItemInit proc far
      mov   r2, #0         
      cmp   r14, #0
      jmpr    cc_Z, loc_EE       
      mov   r2, r14
      callr   IsFlagTrue        ;判断对应的标志位(一个Bit)是否为1
      and   r2, r1
      jmpr    cc_Z, loc_EC
      mov   r2, #1               
      jmpr    cc_UC, loc_EE

loc_EC:                     
      mov   r2, #2

loc_EE:                     
                              
      mov   [-r0], r2        ;设置ImageOrder
      calls   seg(SetMenu),sof(SetMenu) ;设置MenuItem
      add   r0, #2
      rets
OnMenuItemInit endp

//标志判断函数
IsFlagTrue proc near                     
                              
      mov   r1, #1
      sub   r2, #1
      shl   r1, r2
      extp    #42h, #1
      mov   r2, 3EFCh
      ret
IsFlagTrue   endp

//菜单响应函数
OnSelect proc far; start main of patch
      mov   [-r0], r12   
      mov   [-r0], r13
      calls   seg(GetSelectMenu),sof(GetSelectMenu)   //判断被选中的菜单项Order
      mov   r2, r4
      callr   loc_F8
      xor   r2, r1
      extp    #0Eh, #1               
      mov   3A42h, r2                                 //更新数据,有意义的Action       
      mov   r13,
      mov   r12,
      jmps    seg(UpdateMenu),sof(UpdateMenu)         //更新菜单项信息,这里主要是图片
OnSelect endp

三、其他的窗体函数
前面我做过猜测,就是所有的窗体都是一个基本的函数创建出来,在我在解读FireWare的过程中,发现这样的函数是确实存在的,我就以6688为例说一下这些函数的关系。
A、)
以下的窗体虽然各有不同,但是他们都是由一个函数0xF3:E9FACreateWnd(struct WndStruct*)创造的,再细分一下,又分成两类,有边框(一个矩形的框,如选项对话框等)和无边框的,分别由如下函数创建。
CreateWnd_FullScreen(struct WndStruct*) 0xF3:EA82
CreateWnd_Pop(struct WndStruct*) 0xF3:EA8A      
这两个函数都是调用CreateWnd的。而在第二节中说到的CreateMenu最终也是要调用CreateWnd_FullScreen的。
下面我们看一下6688中存在的窗体类型。

1、基本的菜单式窗体。就是第一节中所说所说的类型,他拥有几乎所有的界面元素。代表:基本的菜单大都是这一类。通过第一个参数bBorder可以决定最后调用CreateWnd_FullScreen还是CreateWnd_Pop,如果bBorder是1,那么则创建一个有边框的弹出式窗体。

2、无标题和图标的窗体。这类窗体没有标题和图标,没有菜单,一般是一张图片。代表:游戏的开始画面,6688和x618的图形菜单也是基于这类窗体。如下是猜数字的主函数:
0xD1:AD08 ; ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
0xD1:AD08 loc_D1AD08:                           ; CODE XREF: 0xD1:AD76J
0xD1:AD08               mov   [-r0], r9
0xD1:AD0A               mov   [-r0], r8
0xD1:AD0C               mov   r12, #898Ch   0xD3898C MMIMalloc
0xD1:AD10               mov   r13, #0D3h ;
0xD1:AD14               mov   r14, #89C8h   0xD389C8 MMIFree
0xD1:AD18               mov   r15, #0D3h ;
0xD1:AD1C               calls   0E2h, InitScreen
0xD1:AD20               mov   r8, r4
0xD1:AD22               mov   r9, r5
0xD1:AD24               mov   r12, r8
0xD1:AD26               mov   r13, r9
0xD1:AD28               mov   r14, #2CB6h   ; 0xD1:ACB6 窗口的相关结构
0xD1:AD2C               mov   r15, #346h
0xD1:AD30               calls   0E2h, sub_E2367F   //填充窗口结构
......
//略去和创建窗口无关的部分
......
0xD1:AD68               mov   r12, r8
0xD1:AD6A               mov   r13, r9
0xD1:AD6C               calls   0F3h, CreateWnd_FullScreen //在这里直接调用的创建noBorder的窗口函数
0xD1:AD70               mov   r8,
0xD1:AD72               mov   r9,
0xD1:AD74               rets
0xD1:AD76 ; ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
//窗口结构的相关信息
0xD1:AC9E               dw 2Fh                //软键定义Order_0,键码为2F
0xD1:ACA0               dw 2Fh
0xD1:ACA2               dw 38Ch               //文字为"Options"
0xD1:ACA4               dw 5                  //软键定义Order_1,键码为5
0xD1:ACA6               dw 5
0xD1:ACA8               dw 303h               //文字为"Start"
0xD1:ACAA               dw 2C9Eh            //KeyCodeInfo, 有1套配置
0xD1:ACAC               dw 346h
0xD1:ACAE               dw 1
0xD1:ACB0               dw 0                  //配置信息,左软键用Order为0的配置
0xD1:ACB2               dw 1                  //右软键用Order为1的配置
0xD1:ACB4               dw 107h               //图标ID
0xD1:ACB6               dw 0                  ; field_0
0xD1:ACB6               dw 0                  ; field_2
0xD1:ACB6               dw 0ACDCh             ; OnCommandOff
0xD1:ACB6               dw 0D1h               ; OnCommandPage
0xD1:ACB6               dw 0                  ; field_8
0xD1:ACB6               dw 0                  ; field_A
0xD1:ACB6               dw 0E636h             ; field_C
0xD1:ACB6               dw 0F3h               ; field_E
0xD1:ACB6               dw 2CB0h            ; SKeyItem_Offset
0xD1:ACB6               dw 346h               ; SKeyItem_Page
0xD1:ACB6               dw 2CAAh            ; SKeyListOffset
0xD1:ACB6               dw 346h               ; SKeyList_Page
0xD1:ACB6               dw 0                  ; field_18
0xD1:ACB6               dw 0                  ; field_1A
0xD1:ACB6               dw 65h                ; Weigth
0xD1:ACB6               dw 41h                ; Heigth
0xD1:ACB6               dw 2CB4h            ; IconOffset
0xD1:ACB6               dw 346h               ; IconPage
0xD1:ACB6               dw 0                  ; field_24

这里面的主要结构如下
struct wndClass_2{
int * pUnknown_1;
MessgeFunction pOnkeyDown;        //按键响应函数
int * pUnknown_2;
MessgeFunction pUnknown_3;//未知的函数,一般是直接返回,即ret;
KeyCodeInfo * pKeyCodeInfo;        //窗体的软键信息       
KeyDefOrder * pKeyDefOrder;        //软键配置信息组
int unKnown_4;
int unKnown_5;
int ViewWidth;            //窗体的视图区域宽度
int ViewHeight;             //窗体的视图区域高度
int *pImageID;            //指向窗体图标序号的地址
int unKnown_6;               //菜单标题的字串ID
}

此外,说一下这里面的按键响应函数
0xD1:ACDC ; ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
0xD1:ACDC               mov   [-r0], r8
0xD1:ACDE               mov   r8, #0FFFFh       //按键响应函数的返回值,意义下面解释
0xD1:ACE2               extp    r15, #1
0xD1:ACE4               mov   r12,
0xD1:ACE8               cmp   r12, #2Fh ; '/'   //左软键
0xD1:ACEC               jmpr    cc_Z, loc_D1ACF4
0xD1:ACEE               cmp   r12, #5         //右软键
0xD1:ACF0               jmpr    cc_Z, loc_D1ACFA
0xD1:ACF2               jmpr    cc_UC, loc_D1AD00
0xD1:ACF4 ; ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
0xD1:ACF4 loc_D1ACF4:                           ; CODE XREF: 0xD1:ACECj
0xD1:ACF4               calls   0D1h, sub_D18BAA
0xD1:ACF8               jmpr    cc_UC, loc_D1AD02
0xD1:ACFA ; ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
0xD1:ACFA loc_D1ACFA:                           ; CODE XREF: 0xD1:ACF0j
0xD1:ACFA               calls   0D1h, sub_D1AC32
0xD1:ACFE               jmpr    cc_UC, loc_D1AD02
0xD1:AD00 ; ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
0xD1:AD00 loc_D1AD00:                           ; CODE XREF: 0xD1:ACF2j
0xD1:AD00               mov   r8, #0
0xD1:AD02 loc_D1AD02:                           ; CODE XREF: 0xD1:ACF8j
0xD1:AD02                                       ; 0xD1:ACFEj
0xD1:AD02               mov   r4, r8
0xD1:AD04               mov   r8,
0xD1:AD06               rets
0xD1:AD08 ; ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆

这里面需要注意是按键响应函数的返回值,如果按键已经被处理,那么需要返回-1(0FFFFh),则消息系统会认为你已经处理,否则会转到系统的默认窗口函数去处理。

3、消息框的窗体,类似于windows的MessageBox,可以显示文本信息,并制定图标,和键盘控制,如一般的确认对话框。如下是写短消息时选项中按清除文本后的处理:
//次函数最终根据bBorder调用CreateWnd_FullScreen还是CreateWnd_Pop。
0xE6:017E MessageBox(int bBorder, int * Prama, int , struct wndClass_3 * pwndClass)

0xD5:63AE ; ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
0xD5:63AE DeleteText:                           ; CODE XREF: 0xD5:62B6j
0xD5:63AE               mov   r12, r8
0xD5:63B0               mov   r13, r9
0xD5:63B2               calls   0E5h, sub_E5F0FC
0xD5:63B6               mov   r8, r4
0xD5:63B8               mov   r9, r5
0xD5:63BA               mov   r6, #3A04h    ; 0xD4:FA04
0xD5:63BE               mov   r7, #353h
0xD5:63C2               mov   [-r0], r7
0xD5:63C4               mov   [-r0], r6
0xD5:63C6               mov   r12, #1
0xD5:63C8               mov   r13, r8
0xD5:63CA               mov   r14, r9
0xD5:63CC               calls   0E6h, MessageBox
0xD5:63D0               add   r0, #4
0xD5:63D2               jmpa    cc_UC, loc_D5646E
0xD5:63D6 ; ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆

0xD4:FA04               dw 0
0xD4:FA06               dw 0
0xD4:FA08               dw 6152h
0xD4:FA0A               dw 0D5h
0xD4:FA0C               dw 0
0xD4:FA0E               dw 0
0xD4:FA10               dw 0E636h
0xD4:FA12               dw 0F3h
0xD4:FA14               dw 39B6h
0xD4:FA16               dw 399h
0xD4:FA18               dw 399Ch
0xD4:FA1A               dw 399h
0xD4:FA1C               dw 1
0xD4:FA1E               dw 0
0xD4:FA20               dw 4E6h               ; 删除文本?Delete Text?
0xD4:FA22               dw 39F2h
0xD4:FA24               dw 399h
0xD4:FA26               dw 0
0xD4:FA28               dw 3
0xD4:FA2A               dw 2
0xD4:FA2C               dw 0
0xD4:FA2E               dw 0
0xD4:FA30               dw 0
0xD4:FA30 ; ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆

这里面的主要结构如下
struct wndClass_2{
int * pUnknown_1;
MessgeFunction pOnkeyDown;        //按键响应函数
int * pUnknown_2;
MessgeFunction pUnknown_3;//未知的函数,一般是直接返回,即ret;
KeyCodeInfo * pKeyCodeInfo;        //窗体的软键信息       
KeyDefOrder * pKeyDefOrder;        //软键配置信息组
int unKnown_4;
int unKnown_5;
int nStringID               //显示的消息的StringID
int *pImageID;            //指向窗体图标序号的地址
int unKnown_6;
int unKnown_7;
int unKnown_8;
int unKnown_9;
int unKnown_A;
int unKnown_B;
}


4、简单消息框的窗体。只是简单的显示一条消息,有三类(i,v,无图标)。其中参数r12来决定由没有边框。本质上,以上的几个函数都是下面复杂窗体的一个特例,为了使用方便,特独立列出!主要有以下三个函数:
0xE6:04A8 MessageBox_v(int bBorder, int nStringID)//消息框图标为i
0xE6:0508 MessageBox_i(int bBorder, int nStringID)//消息框图标为v
0xE6:0538 MessageBox_NoIcon(int bBorder, int nStringID) //无图标
这三个函数比较简单,主要是根据bBorder来决定两个不同的结构,然后调用CreateWnd_FullScreen或CreateWnd_Pop。


               
B、)

                                                       待续。。。。。。。。。。。
[此贴子已经被作者于2004-3-28 21:03:29编辑过]

coollang 发表于 2005-8-10 00:01:00

待续。。。。
最近一直很忙,每天只是匆忙来看一下,很是过意不去。
这个关于窗体的,一直想写了(好像是在进阶的计划里面的),赶在这个周末,把它写完!
大家如果有兴趣和问题,不妨一起讨论,把Unknown变成specific!

RainMoon 发表于 2005-8-10 00:02:00

必然签到 :)   窗体一直只有个模糊的理解,这样能比较详细的了解一下了。

llhn 发表于 2005-8-10 00:03:00

我也来签到!回去慢慢学习。

ZiHwA 发表于 2005-8-10 00:04:00

怎能不支持呢?
宝贵的经验可以造福不少SPGCer啊!

KoncaCN 发表于 2005-8-10 00:05:00

支持呀!

lishenglyx 发表于 2005-8-10 00:06:00

终于出来了,太好了。
支持!感谢!

MrJewes 发表于 2005-8-10 00:07:00

签到!

落单的虫子 发表于 2005-8-10 00:08:00

学习中……

sOLO 发表于 2005-8-10 00:09:00

报道~~

xhjjxm 发表于 2005-8-10 00:10:00

收之.                                       

nj528 发表于 2005-8-10 00:11:00

能不能以6688应用程序为例子//标志判断函数
IsFlagTrue proc near                     
                              
      mov   r1, #1
      sub   r2, #1
      shl   r1, r2
      extp    #42h, #1
      mov   r2, 3EFCh ------------------------#42:3FFC   怎么找到一个地址使用呢,与别的菜单能不能使用相同的地址
      ret
IsFlagTrue   endp

买醉生 发表于 2007-4-2 09:20:52

虽然不懂,开始狼大的帖子,怎么能不顶呢
页: [1]
查看完整版本: 【专题文章】手机中的窗体