Archive for May, 2006

Falcon 4

 

Leave a comment

梅雨季降临

  周末好容易放晴两天,今天一大早就发现老天哭丧着脸,还不是挤几滴眼泪。等到了公司楼下,就已经抽泣起来了。空气闷闷的,家里的地板也隐隐有点返潮了。恐怖的是,厨房案台的角落居然长出了蘑菇,如果是木耳就好了……

  见鬼,手机给丢在家里洗手间了。

1 Comment

JNI ActiveX

  最近这些日子对JNI(Java Native Interface)作了一个简单的研究,起因是需要将几个第三方的Win32应用程序整合进我们用Java开发的软件框架里面。虽然这样Java的可移植性打了折扣,但是软件开发,客户的需求是第一位的。好在Java提供了JNI这么一个接口供开发者调用其他语言编写的代码,而大量的Win32应用程序也都能够以自动化服务器或者ActiveX控件的方式供其他程序调用,这样两者之间就能够建立一个桥梁。

  如果仅仅是为了针对某一个提供了COM接口的Win32应用程序与Java建立这么一个桥梁,事情就变得非常简单。只要获得Java窗口的Windows句柄,就可以利用这个句柄,在这个窗口上创建任何子窗口。将TypeLib导入到VC的工程中,可以获得ActiveX控件的C++包装类,然后直接调用类的方法就可以了。

  我遇到的问题跟这个又有点不一样,目标是提供一个通用的接口,能够根据CLSID创建任何一个已注册的ActiveX控件,并且根据名称直接访问控件的方法和属性。对于这个接口的使用者,可能的使用方式如下:

 AxWindow wnd = new AxWindow("CLSID");
 Object objProperty = wnd.getProperty("PROPERTY_NAME");
 wnd.putProperty("PROPERTY_NAME", objProperty);
 
 Object objParam1, objParam2;
 wnd.addParam(objParam1);
 wnd.addParam(objParam2);
 wnd.invokeMethod("METHOD_NAME");

  JNI方面的资料可以在J2SDK的文档中找到,生成C++头文件并且实现代码并编译得到DLL,在很多网站上都能找到简单的例子。但是MSDN上面对ActiveX控件的调用,大部分都是导入TypeLib得到C++包装类,可是如果仔细阅读代码,可以发现CComPtr类提供了这么几个成员函数:

 virtual HRESULT CComPtr<IDispatch>::GetIDsOfNames

 virtual HRESULT CComPtr<IDispatch>::Invoke;

 virtual HRESULT CComPtr<IDispatch>::GetPropertyByName

 virtual HRESULT CComPtr<IDispatch>::PutPropertyByName

 ……

  原来那些包装类最终也都是调用这些函数:即先调用GetIDofName,通过方法或者属性的名称得到接口ID,然后通过标志位来控制是调用方法还是对属性进行读写。典型的调用过程如下:

CComVariant varRet;

// 先得到控件的IUNKNOWN接口
IUnknown *pUnk = GetInterface();
if (pUnk != NULL)
{

  CComPtr<IDispatch> sp;

  pUnk->QueryInterface(IID_IDispatch, (void**)&sp);

  if (sp)

  {

    // 根据方法或者属性的名称得到DISPID

    DISPID dispid = 0;

    sp->GetIDsOfNames(IID_NULL, (LPOLESTR *)&lpszName, 1, 0, &dispid);

    // 预处理参数,参数均为VARIANT类型

    DISPPARAMS dispParams = {NULL, NULL, 1, 1};

    int nParams = m_ayParams.size();

    if (nParams > 0)

    {

      dispParams.cArgs = nParams;

      dispParams.rgvarg = new VARIANTARG[nParams];

      for (int n = 0; n < nParams; n++)

      {

        dispParams.rgvarg[n] = m_ayParams[n];

      }

    }

    // 调用方法或者访问属性 wFlag可以为以下值之一
    // DISPATCH_METHOD
    // DISPATCH_PROPERTYGET
    // DISPATCH_PROPERTYPUT
    // DISPATCH_PROPERTYPUTREF

    sp.p->Invoke(dispid, IID_NULL, 0, wFlag, &dispParams, &varRet, NULL, NULL);

    // 清理
    delete [] dispParams.rgvarg;
  }
}

m_ayParams.clear();

  还有需要解决的问题就是参数,首先是参数的个数和类型不确定,而且还需要首先将Java类型映射成C++类型或者反之。这个问题倒也不难,主要就是调用JNIEnv类的FindClass、GetMethodID、NewObject等函数,先获取类型,再得到该类型的构造函数id,最后通过构造函数在C++代码中创建一个对应的Java对象实例,或者是通过FindClass得到Java对象的类型,调用toString将对象的值统一转换成一个字符串,然后根据类型和值两个字符串创建一个C++对象。

  最后还有一个让我郁闷的事情就是,由于在代码中使用了ATL,因此需要在目标机器上也安装有ATL80.dll。按照老习惯,我先选择“静态链接到ATL”重新编译一次,奇怪的是结果文件的大小并没有发生变化,运行的时候仍然报错:“未找到ATL80.DLL……”。最后不得已,只有在另外一台安装Visual Studio 6.0的机器上面重新编译发布。希望有经验的朋友能够帮助我解决这个问题。

 

6 Comments

风筝

  这两年晒太阳的机会越来越少,据说比起读书的那会儿白了不少。可昨天在太阳底下放了一两个小时的风筝,今天就发现手臂裸露出来的皮肤发红发黑,真是“辛辛苦苦好几年,一下回到解放前”。

  要说也是因为这是第一次放风筝,有点兴奋也是难免的。小时候只知道一个人待在屋子里看各种杂书,风筝、陀螺、铁环、鞭炮烟花一干玩物一来是不感兴趣,二来也没有谁会给我做,燕子也差不多。昨天一下车就看见几个小贩一拥而上推销风筝,在燕子的提议下,一阵讨价还价后拿着风筝走进了森林公园。长假的最后一天,老天爷拼命放晴好弥补前几天阴雨留下的遗憾,所以阳光实在有点强烈,好在风还是很大的,刚走进公园就看见远处树梢上几个风筝在高高飘飞。

  不知道是应该感谢小贩的风筝做工好还是我无师自通,反正就是一次性放飞成功。一口气把五百米线都给放出去,看着身边几个新手手忙脚乱的就是飞不起来,虚荣心得到极大的满足,然后看着远处似乎还有更高的,不由得又悻悻抱怨小贩给的线太短。最有意思的是一群老外,玩得两个风筝都太偏门了。一个是当天唯一一个蜈蚣风筝,结果因为太长总是放不起来,从我身边走过的时候我不由脱口而出“So long”,结果大鼻子回头补了一句“Too long”,另外一个……根本就是降落伞嘛,倒是飞上去了,结果却是跟我的线缠在一起,好在解救及时,我自己倒没事,它老人家失去控制一头挂在树上……罪过罪过啊。

3 Comments

黄金长假

  人物篇

  花草篇

  风景篇

  燕子篇

3 Comments