笨笔老刘 さんのプロフィール笨笔老刘ブログリスト ツール ヘルプ

ブログ


3月30日

Bug of Mozilla or MSN Space?

在Linux下用Mozilla访问MSN spaces有一个问题。在“编辑网络日志项”时老是发现“发布项”这个按钮是disabled的。
可以通过在地址栏输入:
javascript:alert(document.forms[1].btn1.disabled=false)
来enable这个按钮。

后来发现如果标题的第一个字母用英文字母则没有问题,一看source code,有一行:
<input id="title" name="title" type="text" size=50 value="" class="text" onpropertychange='ValidateBlogEntryInput()' onkeyup='ValidateBlogEntryInput()' onpaste='ValidateBlogEntryInput()'>、

估计是"onkeyup"的问题。在Linux下用scim来输入中文可能不会在Mozilla中产生"onkeyup" event。

桌上足球

这些天也没有什么其他运动,常常跟同事打打桌上足球。本周以前还基本保持不败(仅指新同事之间,外国来的同事太厉害了,跟我们不是一个档次),这周被破了金身之后负多胜少。今天被负责黑板报的同事照了相,不知明天会不会登出来。
3月19日

紫禁城外走一圈

今天北京的天气特别好,我决心出去散散步。十四年前,我去过一次天安门和故宫,时间太长了,记忆已经不深刻了。所以把天安门选为了散步的目的地。

从广场跨过天安门,端门,就到了故宫的入口处的午门。我没有进去,而是开始绕着故宫走一圈。故宫被护城河环绕,又叫筒子河。河很浅,有人在钓鱼(墙上写了严禁钓鱼的),所以应该水质不会太差。故宫的东西两侧分别是北池子大街和北大街,这两条街两旁都是一些院子和胡同。不知这些院落是清朝就有还是后来建的,看上去很有传统建筑的风格。

很有意思的是在故宫后面的西侧,景山前街的南边,孤零零地立着一个牌坊。牌坊上两侧分别写着“乾元资始”和“大德日生”。一般的牌坊应该是在大门外,怎么在故宫的后面呢?我向牌坊的对面、景山前街的北边看去,果然有一个大院子,叫做“大高玄殿”,门口挂着游客止步的牌子。

回来一查才知道,“大高玄殿”是明清时皇家的道观,当年在这里还有两个牌坊,合称“三道门”,上世纪的中央军委就坐落在大高玄殿里。

看来我得去买本北京历史书,然后就可以常常周末去探古了。

中关村赶集

在一个阳光明媚的下午,我背着书包高高兴兴地去中关村的海龙大厦买数码相机。

中关村那一路上都是数码产品的店,路上的人那是相当的多(宋丹丹的语调)。原以为到海龙应该就像是去张杨路的太平洋一样,结果一进去我就蒙了,那人是相当相当的多。不断地有人过来说“大哥,要买数码相机不?”,“先生,我这里是Sony专卖,过来看看!”那个热情!这里的人口密度绝对不是上海的太平洋可以比的。我混到了二楼,到一个摊位去问了几句,那个推销员接下来就几乎是一直跟着我走,不断地说,非要我到他们12楼的展示厅去看看。那就去看看吧。

上去的电梯那个挤,等了两趟。幸亏电梯有超重系统,否则估计要挤得像北京的公交车和地铁一样了。12楼别有洞天。原以为这是一幢写字楼,上面应该都是公司办公的地方。公司倒都是公司,这里是各个销售公司的主要销售场所!很多销售人员会一对一地跟你谈价钱。就像在太平洋配电脑时的待遇一样。

其实这样的销售方式也可以理解,下面的门面太贵,人太挤,这样的方式能提供更好的购物环境。不过怎么就让我不由自主想起了上海的襄阳路呢。

好在12楼有很多家这样的店,我还是可以一个一个的讨价还价过来。最后买了一台canon。

难怪说中关村电子产品有名!
3月17日

在北京做只小白鼠

到北京一个星期了。

这一周的天气都非常好,每天都是晴天。刚下火车的那天还比较冷,这几天都很暖和。

在火车上碰到一个心理医生,聊到中国人是否快乐的问题。她说对中国人来说,现在这个世界变化得太快,危机感太强,所以总的心态是焦虑。
举了一个心理学实验的例子:
一群小白鼠关在笼子里,笼子是圆形的,周围贴了一些图案。一开始笼子会慢慢地转动,小白鼠们可以很好的生活,就像笼子没有转一样。后来笼子越转越快,这个时候小白鼠们的举动就不一样了。有的小白鼠会像往常一样生活,只是不时的会抬头看一会转动的笼子;有的小白鼠会躲到笼子的角落里低着头不敢看;而极端的一些小白鼠会跟着笼子的转动沿着笼子一直跑。

我是哪只小白鼠呢?

我喜欢我的两个24吋显示器,我也渐渐开始喜欢我的Linux桌面了。
3月8日

妇女节快乐

今天是一年一度的妇女/女孩节。祝女同胞们节日快乐。摘抄一段妇女节的由来:

“1903 年3月8日,美国芝加哥市的女工为了反对资产阶级压迫、剥削、和歧视,争取自由平等,举行了大罢工和示威游行。这一斗争得到了美国广大劳动妇女的支持和热烈响应。1910年,一些国家的先进妇女在丹麦首都哥本哈根举行第二次国际社会主义者妇女代表大会。大会根据主持会议的德国社会主义革命家蔡特金的建议,为了加强世界劳动妇女的团结和支持妇女争取自由平等的斗争,规定每年的3月8日为国际妇女节。联合国从1975年开始庆祝国际妇女节,从此"三八 "节就成为全世界劳动妇女为争取和平、争取妇女儿童的权利、争取妇女解放而斗争的伟大节日。

我国第一次纪念"三八"国际劳动妇女节始于1924年。当时,我国劳动妇女在中国共产党的领导下,于广州举行了"三八"国际劳动妇女节的纪念活动。

中华人民共和国成立之后,中央人民政府政务院于1949年12月通令全国,定3月8日为妇女节。”


妇女节的意义在于纪念和继续妇女的解放运动,这一方面要靠全社会,更重要的靠妇女自己能更好地认识自己,更自信地发挥自己的长处。今天看到一篇不错的文章,与大家共享:我对女性做工程师的一点看法
3月6日

比较Eclipse与Mozilla中的COM/XPCOM Java Wrapper技术

 

背景

Microsoft 的COM是在Microsoft平台上广泛使用的一项技术,它是建立可重用的构件 (component)的基础。Mozilla的 XPCOM是由Mozilla.org实现,它类似COM,跨平台,是Mozilla用来建造如Mozilla FirefoxMozilla Thundermail等应用程序的基础。
 
COM和XPCOM都是基于virtual table技术,是一种二进制的规范(在Windows平台上,XPCOM与COM做到了二进制兼容。所以Windows平台上的XPCOM控件同时也是 COM控件)。COM和XPCOM的规范本身都没有限制实现的语言,但由于C++的virtual table与COM/XPCOM的virtual table在二进制上兼容,所以C++成了COM/XPCOM世界中的首选语言。
 
Java是受控语言,对其我们无法控制其在物理内存中的各种数据结构的位置,更谈不上控制virtual table的结构了。所以要支持Java与COM/XPCOM的交互,需要有C++写的native code来帮助。这里想比较一下两个支持Java/COM/XPCOM互操作的典型例子:Eclipse的SWT中对COM的支持,和Mozilla 的XULRunner中的JavaXPCOM
 

基本COM/XPCOM支持

在Java中调用COM/XPCOM

Eclipse SWT

在Eclipse SWT中,每个需要被调用的COM接口会有一个对应的Java class。所有这些Java class组成与COM interface同样的继承结构,它们都继承自org.eclipse.swt.internal.ole.win32.IUnknown这个class,对应COM中的IUnknown。IUnknown中会纪录一个field:address,对应COM对象的指针。
 
对每一个COM interface中的方法,在其对应的Java class中会有一个同名的方法,接收Java参数,大部分情况下,这个Java方法会直接调用一个native方法: org.eclipse.swt.internal.ole.win32.COM#VtblCall(...)。因为不同COM interface的不同的方法可能有不同的个数和类型的参数,所以在org.eclipse.swt.internal.ole.win32.COM中提供一组VtblCall(...)的实现,每一个接受不同个数和类型的参数。每个VtblCall方法的实现基本是一样的,因为在这个方法中的参数包括了底层COM对象的地址,以及方法在virtual table中的序号,所以这个方法只需把Java的参数组marshall成C++参数,然后用virtual table来调用即可。

public class IUnknown
{
    int address;
public IUnknown(int address) {
    this.address = address;
}
public int AddRef() {
    return COM.VtblCall(1, address);
}
public int getAddress() {
    return address;
}
public int QueryInterface(GUID riid, int ppvObject[]) {
    return COM.VtblCall(0, address, riid, ppvObject);
}
public int Release() {
    return COM.VtblCall(2, address);
}
}


JavaXPCOM

JavaXPCOM基于一套与Eclipse SWT不同的思路。在JavaXPCOM中,每一个XPCOM interface有一个对应的Java interface,注意这里是Java interface,而不是Java class。那么,在JavaXPCOM中怎么生成一个XPCOM对象的Java wrapper呢?在JavaXPCOM中,巧妙地使用了reflection。对每一个XPCOM对象,会生成一个Proxy 来作为Java wrapper,这个Proxy对象实现XPCOM对象所实现的interface。然后这个Proxy把Java interface中的方法调用再delegate到一个JavaXPCOM提供的XPCOMJavaProxy(实现InvocationHandler)上。

这里有几个问题:1。系统根据一个XPCOM对象的指针,怎么知道这个XPCOM对象实现了什么XPCOM接口?再怎么根据这个XPCOM接口找到对应的 Java interface来生成Proxy?2。XPCOMJavaProxy怎么把一个Java调用再映射到底层的XPCOM调用上?

JavaXPCOM是这样实现的:
  1. 对每一个XPCOM对象的指针,知道其实现的interface的IID。
  2. 使用nsIInterfaceInfoManager来reflect 这个IID,得到这个interface的meta data(nsIInterfaceInfo
  3. 将这个XPCOM对象的指针及nsIInterfaceInfo组合在一起,放在一个JavaXPCOMInterface的数据结构里。
  4. 用这个JavaXPCOMInterface结构的指针来构建XPCOMJavaProxy(java wrapper)。构建XPCOMJavaProxy对象时(XPCOMJavaProxy#createProxy(Class aInterface, long aXPCOMInterface))有两个参数,第一个为这个proxy实现的Java interface。这个Java interface的名字由"org.mozilla.xpcom" + (XPCOM interface name)得来。
  5. 当XPCOMJavaProxy上的方法被调用时,native code会得到方法名、参数数组以及JavaXPCOMInterface的指针。从JavaXPCOMInterface可以得到 nsIInterfaceInfo,通过nsIInterface里所包含的meta data,可以得到这个方法在virtual table中的位置。同时meta data还会包含信息说明每个参数的数据类型,根据这个信息,可以把每个参数marshall成一个nsXPTCVariant结构。
  6. 通过xptcall,就可以完成对virtual table中的方法的调用。
  7. 对方法调用的结果,可以再根据meta data来unmarshall成Java对象。如果某个out参数或return参数是一个XPCOM对象,在meta data中会描述这个参数的interface的IID,那么又可以象第一步一样来对其生成Java wrapper(XPCOMJavaProxy)(nsJavaXPCOMBindingUtils.cpp#GetNewOrUsedJavaObject)。
当然,实际的实现更复杂,比如说有一个global table来记录Java wrapper与native的JavaXPCOMInterface之间的关系以避免不必要的多次为同一XPCOM对象建立Java wrapper等。

在Java中实现COM/XPCOM组件(component)

前面讨论了怎么从Java中调用COM/XPCOM中的组件,接下来讨论怎么用Java语言来实现COM/XPCOM组件。

Eclipse SWT

 这里我尝试用一个图来说明Eclipse SWT中的实现。
  1. SWT会在内存中构建一个native function table(see COMObject#Callbacks)。这个table的横坐标为virtual table中的index,纵坐标为参数的个数。
  2. 这个table中的每个function的实现会调用COMObject这个类中的对应的静态方法:callbackn(int[] callbackArgs),这里的callbackn表示的是callback0,callback1...。在SWT中, org.eclipse.swt.internal.Callback这个类实现了一套通用的从native code回调Java的机制。COMObject使用了这套机制。
  3. 在传给callbackn(int[] callbackArgs)的参数中,第一个是virtual table的地址,根据这个地址,系统可以根据一个全局的hashtable找到对应的COMObject实例。然后调用 COMObject#methodn(int[] args)方法。这里methodn不是静态方法。
  4. 缺省的methodn的实现会返回COM.E_NOTIMPL。用户程序可以override,来实现自己的逻辑。
  5. 再回过头来看怎么在Java中实现一个COM组件:实例化一个COMObject,并override对应的methodn方法。作为参数传给COMObject的constructor每个methodn会需要几个参数。COMObject的初始化函数会在内存中构建virtual table,并让每个virtual table entry指向对应的在native function table中的位置(这里需要使用每个method需要几个参数这个信息)
下面是一个例子,简单地在Java中实现了一个IUnknown
iUnknown = new COMObject(new int[]{2, 0, 0}){ /* 2,0,0 is the arg count for queryInterface/addRef/release */
    int refCount = 0;
    public int method0(int[] args) {return QueryInterface(args[0], args[1]);}
    public int method1(int[] args) {return AddRef();}
    public int method2(int[] args) {return Release();}
    public int AddRef() { return ++refCount;}
    public int Release() {
        refCount--;
        if (refCount == 0) {COMObject.this.dispose();}
        return refCount;
    }
    protected int QueryInterface(int riid, int ppvObject) {
        if (riid == 0 || ppvObject == 0)
            return COM.E_NOINTERFACE;
        GUID guid = new GUID();
        COM.MoveMemory(guid, riid, GUID.sizeof);

        if (COM.IsEqualGUID(guid, COM.IIDIUnknown)) {
            COM.MoveMemory(ppvObject, new int[] {iUnknown.getAddress()}, 4);
            AddRef();
            return COM.S_OK;
        }
        COM.MoveMemory(ppvObject, new int[] {0}, 4);
        return COM.E_NOINTERFACE;
    }
};


实现了多个COM interface的Java对象要稍微复杂一点。一般是在一个Java对象中管理多个COMObject,这几个COMObject的AddRef/Release/QueryInterface这几个函数的实现统一实现。

JavaXPCOM

 JavaXPCOM中的支持还是依赖了type information,这是有了这个依赖,JavaXPCOM中实现XPCOM组件要容易得多。在JavaXPCOM中,只需要这个Java对象实现了所需要实现的XPCOM interface所对应的Java interface即可。
  1. 当一个Java object作为参数传给某个XPCOM方法时,native code会通过这个方法的meta data,知道这个参数应该是一个XPCOM对象。
  2. native code会检查这个Java object是不是一个Java wrapper,如果是,那么可以直接从这个Java wrapper知道它所wrap的XPCOM对象。
  3. 接下来会检查是不是已经给这个Java object生成过stub,如果没有则生成一个nsJavaXPTCStub。nsJavaXPTCStub 会根据meta data生成virtual table,而且当virtual table中的方法被调用时,会根据meta data知道被调用方法的名字,再根据这个名字到Java object中通过reflect找到对应的Java方法并调用它。
另外JavaXPCOM的实现中还实现了reference management,这样在Java code中不再需要去实现如AddRef/Release,系统已经都管理好了。

总结

在这里我们比较了Eclipse SWT和JavaXPCOM中对基本COM/XPCOM的支持的基本原理。这里没有讨论更高级一些的应用,比如说scripting(automation)。

Eclipse SWT

优点:
  1. 结构简单。因为支持基于virtual table,所以支持几乎最底层的COM规范。高效。
  2. 可以用工具来自动生成新的COM interface的Java wrapper。因为每个Java wrapper class的结构基本一样。
缺点:
  1. 不支持Java的garbage collection。Developer必须记得调用IUnknown#Release()方法,否则如果COM对象的Java wrapper被gc了,有可能造成内存泄露。
  2. 只支持有限种COM#VtblCall(...)方法。如果有一个新的COM interface中的某方法,需要更多的参数,而系统提供的COM#VtblCall(...)方法中没有与之匹配的,则需要另外再提供native code。
  3. 用Java实现XPCOM组件复杂。

JavaXPCOM

优点:
  1. 每个XPCOM interface对应到Java中还是interface。
  2. 支持Java的garbase collection。在XPCOMJavaProxy中,重载了finalize()方法,所以Java programmer不需要再去调用Release。
  3. 增加新的XPCOM interface容易。只需在org.mozilla.xpcom这个package中增加相应的Java interface即可。
  4. Java interface可以通过工具自动生成。
  5. 用Java实现XPCOM组件非常简单。
缺点:
  1. 由于实现依赖nsIInterfaceInfoManager,也就依赖typelib。这样一来,方法调用不能象Eclipse SWT中一样直接转换为virtual table调用,效率要明显低一些。另外,只能支持那些支持typelib的interface。
  2. 虽然增加新的XPCOM interface容易,但这个interface必须放在org.mozilla.xpcom这个package中,不适合第三方扩充。
3月3日

赞一个

上午去把我过期的护照重新申领一下。当年我在浦西第一次去办护照时到处排队,花了大半天的时间。所以今天我早早起来,早早出门,希望能省点时间。
 
现在上海出入境管理中心搬到了浦东,位于迎春路民生路路口,属于浦东的政府办公区,一幢非常气派的建筑。门口就放好了指示牌,告诉办理什么东西到什么地方。一楼左边就是护照办理。首先照相,非常方便,交好30元,四个点同时在照,根本不需排队,三分钟就照好,剪好,拿好照片了。进门再复印资料,需要复印身份证,户口本,以及我过期的护照,一元钱一张,贵是贵了点,不过还合理,而且态度很好,不需排队。接下来填表。大厅里有一大片地方摆好了桌子笔供填表,所以可以舒舒服服坐下来慢慢填。最后办理的窗口有很大一排,可能因为比较早而且又不是周末,所以人不多,大部分窗口都空着,于是找了个mm窗口,mm很认真,态度也很好,几分钟就办完了,十个工作日就可以来取。前前后后不到二十分钟就都搞定了!
 
忍不住要赞一个。虽然政府机关大楼总是占着最好的地段,盖得最为豪华令我不满,但如果干什么事情都像上海政府一样有效率,那我还是接受并心甘情愿继续交我的个人所得税的。
3月2日

声明

我不是周笔畅的fan,名字里带个“笔”字纯属偶然。

赋闲在家

这两天赋闲在家,每天睡到自然醒,晒晒太阳,上上网,跟上海的朋友们吃吃饭,明天起要开始清理东西了。
 
人说在家万事好,可一回家呆着就觉得这网络实在令人受不了。本来想既然要去Google,当然应该开一个Google的Blog,可blogspot被封了,上不去,连google.com也是时断时续。最令人气愤的是sourceforge.net也不能访问。
 
昨天中国队1:2输给了伊拉克。无话可说。
3月1日

长不大的我

好象我一直长不大,三十好几的人了,还是一个理想主义者。一直梦想着什么地方有一个工程师的天堂。于是再次离职,背井离乡远上北京,去尝试那传说中的Google。
当年刚毕业的时候,在一家startup呆了很长时间。那段日子是愉快的,上面有在工业届资深的CEO可以直接指导,下面有一群同样年轻的人一同奋斗。可惜公司没有获得成功。
接着去了一家跨国的大公司,时间飞逝,一晃又是几年。这段日子也是愉快的。大公司的人更多,结交了更多的朋友。可似乎自己在技术的路线上没有什么长进。
于今,我要去尝试第三份工作。我的朋友们,祝福我吧。
我回上海要请我吃饭啊!