用户: 密码: 答案:   我要注册   忘记密码

加入收藏  设为首页

开发文档

CNJM首页

业界新闻

手机软件

终端应用

资源下载

EclipseME

CNJM论坛

                 

频道列表

J2ME开发 176篇
服务器端开发 33篇
JAVA语言 71篇
游戏与图形 101篇
WindowsMobile开发 6篇
Symbian开发 61篇
Brew开发 36篇
其它开发平台 6篇

热点文章

BREW™ SDK入门篇...  8244次
BREW开发相关技术论坛 7328次
BREW究竟是什么-B... 7270次
[原创]BREW高手之...  7213次
BREW & J2ME:在差...  7141次
BREW™ SDK入门篇...  6794次
深入Brew编程之一...  6759次
深入BREW消息处理机制 6312次
深入BREW模块加载机制 6184次
BREW SDK入门 6075次
联通博路的开发商F... 5793次
[原创] brew下的大... 5376次

文章搜索

搜 索
按 照
频 道
  
深入Brew编程之一——接口函数替换技术及其应用
编辑:choujs    审核:rocks    文章来源:CNJM论坛精华
关键词:无    发表日期:2005-05-04 12:30:08    浏览次数:6760次
本文版权归原作者,中国JAVA手机网收录本文的目的是让更多人阅读到此文章。转载请注明出处为中国JAVA手机网<www.cnjm.net>
来自:http://www.cnjm.net/tech/article750.html

[这个贴子最后由choujs在 2005/05/04 12:38pm 第 1 次编辑]

   今天我在这里要讲的我这几天工作的一个总结,希望对大家有帮助。不过我这个人有个毛病,在开宗明义之前总喜欢发点满腹牢骚。请大家满足一下我这个小小癖好。
   Brew实际上是一个再简单不过的系统了,只不过搭上手机开发这个比较新鲜的事物,所以有那么一点神秘感。各位新人们,我要告诉你们,开发Brew比开发Win32程序要简单的多,容易得多(当然,要想通过那个有点变态的UBT测试是另外一回事),完全无需心虚害怕。如果你对VC恶熟,程序写得很溜,那么恭喜你,你只需要最多一周的时间,就可以把Brew玩得很溜了。大家切忌有那种学了Brew就是捡了金矿的想法。
   好了,牢骚发完,进入正题。我们发帖子的,要讲的东西当然就不能讲那些Program Guide、API Refrence上能看到的东西,怎么也得是类似于深入XX编程这一层次的东西才对。我今天要讲的主题,是Brew接口函数替换技术和一个实际的例子:怎么为 IHtmlViewer 控件加上背景图片。我的方法可能不是唯一的方法,更不是最好的方法,但是应该有一些独特的地方。如果这个方法能给大家一点启示,作为抛砖引玉,让大家能更深入地挖掘Brew的玩法,然后贡献出来共同讨论,那就是最好不过的了。
   IHtmlViewer这个东西是一个好东西,但是也有很多让人出离愤怒的地方,包括不支持背景色和背景图片,令人郁闷不已。解决这个问题,我用到了两个关键技术:
(1) 接口函数替换技术
(2) 直接修改显示缓冲区技术
   接口函数替换类似于一种钩子方法(Hook),我通过这种方法用一个自定义的函数(IDISPLAYER_MyUpdateEx)替换IDisplay接口的IDISPLAY_UpdateEx函数。大家知道所有显示输出操作最后都需要调用IDISPLAY_UpdateEx函数刷新屏幕,IHtmlViewer也不例外。使用IDISPLAYER_MyUpdateEx替换IDISPLAY_UpdateEx函数后,IHtmlViewer在刷新屏幕的时候就会首先调用IDISPLAYER_MyUpdateEx,在这个函数中我修改显示缓冲区,添加背景图片,然后再调用真正的IDISPLAY_UpdateEx函数刷新屏幕,这样,IHtmlViewer控件就有背景图片了。
   首先看看怎么替换IDISPLAY_UpdateEx接口函数。打开AEEDisp.h,可以看到IDISPLAY_ UpdateEx的定义如下。
#define IDISPLAY_UpdateEx(p, bDefer)  AEEGETPVTBL(p,IDisplay)->Update((p), (bDefer))
再把AEEGETPVTBL宏定义展开,实际的定义应该是这样的:
#define IDISPLAY_UpdateEx(p, bDefer)  (*((IDisplayVtbl**)p))-> Update((p), (bDefer))
   从这里我们可以看到很多问题。我们知道,每一个应用都需要创建一个IDisplay接口的实例指针(假设是pIDisplay),那么这个指针指向怎么样一个数据结构呢?在AEEDisp.h中我们可以看到IDisplay的定义:
typedef struct _IDisplay IDisplay;
   可以看到,IDisplay实际上是一个伪数据类型,没有任何意义(所有的Ixxxxx数据类型定义都是如此),我们无从知道其具体数据结构定义。幸运的是,从接口函数的定义中我们可以知道两个事实:
(1) pIDisplay指针所指向的数据的前四个字节的值是一个指针
(2) 这个指针的类型为IDisplayVtbl(记为pIDisplay->pIDisplayVtbl)。
   IDisplayVtbl数据结构实际上是IDisplay接口的函数表(所有其它接口也都一样),在AEEDisp.h中定义。
AEEINTERFACE(IDisplay)
JAVA手机网[www.cnjm.net]
{
  INHERIT_IBase(IDisplay);
  …
  void (*Update)(IDisplay * po, boolean bDefer);
  …
JAVA手机网[www.cnjm.net]
}
把宏定义展开就是这样:
typedef struct IDisplayVtbl IDisplayVtbl;
struct IDisplayVtbl
{
  uint32  (*AddRef) (IDisplay*);
  uint32  (*Release) (IDisplay*);
  …
  void (*Update)(IDisplay * po, boolean bDefer);
  …
}
JAVA手机网[www.cnjm.net]
   其它函数我们就不关心了,跟这篇文章有关的就是这个 Update 函数指针。很显然,我们只要把这个指针替换为IDISPLAY_MyUpdateEx就可以了。但是且慢,这里还有一个问题。pIDisplay->pIDisplayVtbl这个指针指向的地址位于代码段,是不能修改的。因此我们还需要做一些处理。方法是重新构造一个函数表,用于替换原来的函数表。
   函数替换的代码如下。
IDisplay* pIDisplay = ((AEEApplet*) GETAPPINSTANCE() )->m_pIDisplay;
IDisplayVtbl* pIDisplayVtbl = (IDisplayVtbl*)MALLOC(sizeof(IDisplayVtbl*));
MEMCPY(pIDisplayVtbl, *(( IDisplayVtbl**) pIDisplay), sizeof(IDisplayVtbl));
//在这里保存原来的Update函数指针
SaveOldUpdate(pIDisplayVtbl->Update);
//替换
pIDisplayVtbl->Update = IDISPLAY_MyUpdateEx;
*(( IDisplayVtbl**) pIDisplay) = pIDisplayVtbl;
   这样IDISPLAY_UpdateEx就替换成自己定义的函数了。下面看一下IDISPLAY_ MyUpdateEx这个函数怎么实现。直接修改显示缓冲区的方法在过去已经有人讨论过,在这里就不详细说明了,直接给出IDISPLAY_ MyUpdateEx函数的参考实现。在参考实现中没有做任何错误处理,请注意。
void IDISPLAY_MyUpdateEx(IDisplay * po, boolean bDefer)
{
   IBitmap* pScrBitmap;
   IDIB* pScrDIB;
   IBitmap* pBgBitmap;
   IDID* pBgDIB;
   IImage* pBgImage;
   // 获取显示器位图
   IDISPLAY_GetDeviceBitmap(po, &pScrBitmap);
   // 获取显示缓冲区
   IBITMAP_QueryInterface(pScrBitmap, AEECLSID_DIB, (void**)& pScrDIB);
   // 创建背景位图
JAVA手机网[www.cnjm.net]
   IBITMAP_CreateCompatibleBitmap(pScrBitmap, &pBgBitmap,pDIB->cx,pDIB->cy);
   // 获取背景位图的缓冲区
   IBITMAP_QueryInterface(pBgBitmap, AEECLSID_DIB, (void**)&pBgDIB);
   // 载入背景图片
   pBgImage = ISHELL_LoadImage(
JAVA手机网[www.cnjm.net]
                          ((AEEApplet*)GETAPPINSTANCE() )->m_pIShell,
JAVA手机网[www.cnjm.net]
     “bg.png”
      );
   // 替换IDisplay接口的目标位图
   IDISPLAY_SetDestination(po, pBgBitmap);
   IBITMAP_Release(pScrBitmap); // 引用计数减1
   // 贴背景图
   IIMAGE_Draw(pBgImage);
   // 还原IDisplay接口的目标位图
JAVA手机网[www.cnjm.net]
   IDISPLAY_SetDestination(po, pScrBitmap);
   IBITMAP_Release(pBgBitmap); // 引用计数减1
   IIMAGE_Release(pBgImage);
   // 这时,pScrDIB里面是原来IHtmlViewer载入的页面的位图数据,pBgDIB里是背景图片
   // 的位图数据,我们pScrDIB里白色的点用pBgDIB对应的点来替换。这里假设设备的颜色
   // 深度为16bit
   {
       uint16* pixel = (uint16*)pScrDIB->pBmp;
       uint16* bgpixel = (uint16*)pBgDIB->pBmp;
       int pcount = pScrDIB->cx * pScrDIB->cy;
       for(; pcount; --pcount) {
           if(*pixel == 0xffff) *pixel = *bgpixel;
 ++pixel;
 ++bgpixel;
       }
   }
   // 调用真正的屏幕刷新函数
   (GetOldUpdate())(po, bDefer);
   // 释放资源
   IDIB_Release(pBgDIB);
   IBITMAP_Release(pBgBitmap);
}
   好了,到此这篇文章也该结束了。最好我想狗尾续貂一下。上面讲的我想应该是一种较具普篇性的,应该不只限于为IHtmlViewer控件添加背景图(包括背景色),通过举一反三,还可以用于其它目的。希望大家可以共同探讨一下。
JAVA手机网[www.cnjm.net]

来自:http://www.cnjm.net/tech/article750.html

相关文章
   暂无相关文章
最新评论   [查看全部评论(10条)]
tiger3927 在 2006-09-06 16:27:24 发表的评论:
试验了,不好使,htmlviewer变化的时候不会调用displayupdate的,空欢喜了。 
joe8019 在 2005-08-16 20:52:48 发表的评论:
楼主,这个方法是不是不行呢,我试了,不行,有没有人使用过,楼主能不能给详细的代码呢? 
joe8019 在 2005-08-16 15:37:58 发表的评论:
是怎么用的呀,兄弟能说说不,我想在菜单中用背景图 
lql3 在 2005-08-02 09:17:19 发表的评论:
thanks
 
rainwell 在 2005-08-01 16:27:02 发表的评论:
谢了 
migliang 在 2005-06-06 09:58:21 发表的评论:
多谢!又学到了一招 
网站简介  |  关于版权  |  广告服务  |  网站地图  |  联系我们
Copyright © www.CNJM.net, All rights reserved
中国JAVA手机网 版权所有
ICP备案:京ICP备041452