Feeling

    三人行,必有我师焉

   ::  :: 新随笔 :: 联系 ::  :: 管理 ::
  52 随笔 :: 0 文章 :: 172 评论 :: 0 Trackbacks

2008年12月5日 #

做不下去了,Vista快把我逼疯了,啥都不支持,随意取消n多API,开发人员能做的事情太有限了,Vista你到底想干什么?

看一看MSDN,全是抱怨Vista的。管理员给出的答案就是按照兼容XP的方式运行,这算哪门子解决方案呀。

Have you tried running your application elevated? (Right Click->Run As Administrator) If this doesn't work try applying an XP SP2 Compatibility shim from the Compatibility Tab in the properties dialog. (Right Click->Properties | Compatibility).

Let me know if this works.

Thanks!


怒呀!!!!!!!

从Win3.1 到 Vista,没有哪个版本比Vista更失败的,无论是从用户角度,还是从开发角度。微软是不是想倒闭不做了?
posted @ 2008-12-05 18:16 三人行,必有我师焉 阅读(1421) | 评论 (4)编辑 收藏

2008年10月23日 #

沉寂了一段时间,现在继续SWT Win32 Extension的开发,说实话,最近的进展挺失败的。Black Glossy效果我发现在某些机器上的显示效果非常的卡,我自己的机器却没有任何问题。另外就是我最近在XP下实现了Window Mixer API,用来管理系统声音。Win98,2000,XP都没有问题,结果Vista让我郁闷了,Vista居然取消了Mixer,我哭呀。以下是微软员工给出的答案:

That's because the mixer APIs are virtualized on Windows Vista - you don't get to see the real audio hardware by default, only a virtualized version.  We did this because the vast majority of applications that used the mixer APIs were using them to control their own volume, which is quite rude (it says "I own the box, no other sounds on the system matter").

 You have two choices.  The first is to run your application in XP compatibility mode, in which case you'll be able to access the real audio hardware (please note: you'll see exactly what the hardware provides, which may lead to surprising results).

 The other choice is to use the new Vista audio engine APIs.  either the IAudioEndpointVolume API which allows you access to the master volume for each of the audio endpoints on the machine.  If you really need to access the actual audio controls the IDeviceTopology interface will allow you direct access to the various controls on the audio hardware.

没脾气了,只能专门为Vista实现一套简单的API了。
posted @ 2008-10-23 18:25 三人行,必有我师焉 阅读(1507) | 评论 (4)编辑 收藏

2008年9月4日 #

最近做了一个可视化编辑器相关的项目,采用了GMF。现在项目即将进入尾声,以后可能不再接触这个东西,so在还没有忘掉之前,将经验记录下来以供大家参考。 当然做这个项目之前,我对GMF,EMF一无所知,只是对GEF有所了解,所以可能会有些囫囵吞枣的感觉,但是相信我的理解还是会对各位有所帮助。

GMF其实是一个整合了GEF,EMF的自动化生成代码的项目。使用GMF,可以快速的生成一个包含可视化编辑器的项目,这一点网上有文章介绍:15分钟学会GMF。15分钟是夸张了一点,不过15天完成一个可视化项目,对一个熟练的GMF程序员来说,却绝对不是什么难事。但是既然使用了GMF框架,你就不得不面对以下几个问题:

一、既然是框架,自然要遵守框架的规则,GMF是模式驱动设计的,也就是说必须建好模型,才能进行下一步的开发工作。但是国内很多项目,需求总是不断更新,这种情况下,不要轻易使用GMF。
二、使用GMF框架,自然不具备GEF的灵活性,很多地方都被限制住了,不适合做灵活性非常大的图形设计。
三、不得不忍受GMF里大量的bug。

我比较过GMF1.0,2.0,2.1三个版本,其中1.0完全不能容忍,2.0比较傻,2.1还过得去,所以GMF还是值得大家期待的,毕竟是越做越好。


一个比较简单的GMF流程编辑器

个人感觉GMF非常适合做流程编辑器,主要是图形要求简单,并且适合GMF自动布局,兼之对模型要求不高。

在学习GMF之前,有必要研究一下GEF和EMF,其中GEF是必须要有所了解的,而对EMF要求不算太高,能建一个ecore模型,了解emf的commandstack就够了(其实我本人不太喜欢EMF,我更喜欢用自己的模型框架)。

GMF的学习周期大概2周左右,上手到熟练大概需要1个月的时间(我自己的学习周期),当然这期间会碰到各种各样的技术问题,针对不同的case,碰到的问题也会不一样,而我这个系列的文章,主要就是把我所遇到的问题陈列出来,并提供一个解决之道。

附GMF相关资料:
八进制:GMF常见问题
GMF Newsgroup Q and A
posted @ 2008-09-04 14:52 三人行,必有我师焉 阅读(1356) | 评论 (3)编辑 收藏

2008年7月4日 #

在Birt Designer中,Binding 是无处不在的,如何正确的是用Birt的Binding呢?首先我们需要知道Birt的Binding Type。

Birt的Binding type随着Birt的版本的升级而越来越丰富,早期的Birt版本只有2种类型:为自己创建一个Data Column Binding,和使用Container的Data Binding,随着CrossTab的出现,进而出现了Cube,ReportItem Reference Binding的概念。

普通的Binding,一般是通过属性编辑器的BindingPage来创建,可以set一个Data set,然后自动创建一个Binding列表。Crosstab和Chart两种类型的Report Item 可以不依赖于Data set,而采用Cube来作为Bingding源。而ReportItem Reference 的概念更是简便了Binding的生成,我们可以让一个ReportItem 直接引用另外一个ReportItem的Binding,而非仅仅是Container的Binding,当然既然是引用,那么你是无法编辑这些Binding的,而且被引用的ReportItem必须包含一个名字,有些ReportItem比如Table本身是可以不设名字的,但在这个地方你就要加上了。

再来说说Binding的设置,我们可以通过Binding Dialog和Binding Page来设置,这两种设置是不同的,如果在Binding Dialog上添加一个Binding,那么这个Binding是添加到这个Report Item的BindingHolder身上,如果在 Binding Page上设置,则Bindnig会添加到自身,让自己成为BindingHolder。
posted @ 2008-07-04 11:47 三人行,必有我师焉 阅读(1678) | 评论 (1)编辑 收藏

2008年6月20日 #

通过打开Birt透视图,然后Reset至缺省的Layout,我们能够看到基本的一些View和一个主要的报表可视化编辑器。

先来说一下View,Birt主要的View包含7块:

左上角包含3个视图,Palette,Data Explorer和Resource Explorer,Palette里放置了报表常用的可视化组件,直接将这些组件拖到报表设计器的时候,这些组件并没有作特殊的初始化处理,而从Data Explorer里向设计器拖入一个Dataset会自动生成一个Table,拖入一个Cube会生成一个Crosstab,拖入一个Dataset Column会生成一个DataItem。Data Explorer主要是用来管理和显示数据源。Resource Explorer 老版本里是Library Explorer,新版本则变更为了Resource Explorer,用来特别显示Library,CSS文件,其他文件则不进行特殊处理。

左下角有2个视图,包含Navigator视图和Online视图,Navigator视图是用来建立Birt项目用的,如果是Birt Rcp版本,我们则看不到这个视图,这是IDE版本专有的一个视图,在Rcp版本里没有Project这个概念,直接以文件的形式进行管理。Outline是Birt里较为重要的视图,所有的报表部件都会在这个View里显示并会随着报表的变化实时刷新。

右下角包含了Property Editor 和 Problems两个视图, Property Editor 用来编辑每个可视化报表元素的属性,一般比较常用的属性都会在前几个Tab页里,但是有些属性前几个Tab页里都没有,这时候需要选择Advanced这个Tab页,它里面包含了这个元素所有可用的属性,如果连这儿也没有,那么说明该元素不存在你想要的属性。Problems视图则用来显示报表收集到的一些问题,如果报表校验的时候发生错误,会在此处显示出来。

以上的那些视图属于缺省视图,但还有几个视图也比较有用,一个是Error log视图,一个是Example视图。Error log视图主要是开发用的,当你使用Birt进行二次开发的时候,难免会碰到一些bug,当你感觉有问题的时候,不妨打开error log视图,只要Birt捕捉到了异常,一般都会显示在这个视图里。而Example视图里提供了各种各样的视图,可以Open 和 Save, Open的时候会自动帮你在workspace里建立一个项目,以便你浏览该项目文件。Save则是把这个Example保存到本地某个目录。

说完视图,再来看看Birt可视化的报表设计器,这个设计器包含了五个部分:Layout,Master Page,Script,XML Source,Preview。

Layout为设计器的主要部分,只要通过可视化的拖拽,一个报表就会被自动生成出来,当然要想灵活运用报表设计器,就必须对各个组件的属性了如指掌,Birt提供了丰富灵活的属性供用户选择。MasterPage主要用来设置页眉页脚,以及打印显示之类的功能。Script页面,当你在Layout页面里选中一个元素之后,切换到Script页面,就可以对这个元素进行脚本编码,主要用来监听各种事件,使用Javascript,在采用Web显示里,这些脚本会生效。XML Source则是将这张报表背后的XML source显示出来,用户如果觉得自己对Birt很熟,可以直接在这儿手工修改代码。Preview则是预览Birt报表,Birt会启动Tomcat显示Web运行效果。

基本上Birt还是比较强大的,基本的功能一应俱全。可能你会发现缺少一些更高级花哨的功能,比如flash之类的,其实怎么说呢,不是Birt没有,而是开源版的没有,这个功能在Birt商业版里,可以在 http://www.actuatechina.com/download.php 下载专业版试用。如同IBM,这是这类公司特有的策略,免费上面做收费。喜欢的话,可以试一下专业版,呵呵,可惜网上找不到破解版。

posted @ 2008-06-20 11:48 三人行,必有我师焉 阅读(2639) | 评论 (1)编辑 收藏

2008年6月17日 #

Eclipse3.4马上就要Release了,相信Eclipse的fans都已经开始翘首以待,望穿秋水了。不过现在的RC版本用得很不爽呀,性能非常差,Eclipse的惯例就是最后一个月的工作基本上就是对性能做优化,以达到最佳使用效果。

随着Plugin的增多,Eclipse采用了特殊的策略,增加了一个子目录dropins,用来放用户新增加的plugin,而原有的plugins目录,则基本用于系统基本功能,2者的区别就是,前者可以任意添加删除,后者则基本上是一个ReadOnly的状态,添加了就不能再作修改了,Eclipse会将每一个添加的plugin记录下来,以后启动就不再检查这些plugin了。

不过对于我来说,我一直都习惯于使用plugins目录,下了一个插件直接解压,就直接覆盖安装到plugins目录了,而且有一些plugin不支持dropins目录,必须在plugins目录下才能正常工作。不过一旦插件安装失败,想再reset就比较麻烦了。Eclipse不会自动恢复到初始安装状态,经过测试,找到了一个解决方案,用原始的eclipse的文件替代2个目录:configuration和p2目录。plugins文件位置记录在configuration\org.eclipse.equinox.simpleconfigurator\bundles.info里,p2目录里则记录了更多的初始化信息。要想Reset Eclipse3.4,这两个目录必须被恢复到初始化状态,然后就可以正常使用了。

posted @ 2008-06-17 22:30 三人行,必有我师焉 阅读(5753) | 评论 (5)编辑 收藏

2008年6月12日 #

最近的项目需要使用报表,因为是RCP应用,所以选择了Birt,用了一下,感觉还可以,就是网上资料少了点,不过以前也研究过一些Eclipse相关技术,这些都不重要了,找了SDK版本Debug,啥研究不出来?

BIRT是一个Eclipse-based开放源代码报表系统。它主要是用在基于Java与J2EE的Web应用程序上。BIRT主要由两部分组成:一个是基于Eclipse的报表设计和一个可以加到你应用服务的运行期组件。BIRT同时也提供一个图形报表制作引擎。

官方主页:http://www.eclipse.org/birt
官方BBS支持:http://www.actuatechina.com/forum2.html

基本上来说Birt功能还是很强大的,支持时下比较流行的WebService,Ajax技术,既可用于Web,也可以用于桌面,更新也算稳定,基本上遵循Eclipse的开发步骤,一个一个大版本,同时支持脚本调用,debug开发等等。唯一不足的就是中国的国情支持得还不够完善,毕竟中国比较特殊,我以前给公司做党务报表,要按照纸质报表画,一分一毫都不能变差,那个变态呀,在电脑上画报表还是拿尺子量。

刚刚开始用,慢慢研究,看了下Birt自带的Example,的确是很强大,做得也很漂亮,自己试着创建一个报表也很简单,希望能够比较快的上手吧。

在网上找了一些资源:
http://blogger.org.cn/blog/more.asp?name=sixsun&id=13933 BIRT 中文指南
http://www.springside.org.cn/docs/reference/Birt.htm BIRT报表
http://www-128.ibm.com/developerworks/cn/opensource/os-ecl-birt/ Birt的IBM DW的中文教程
http://download.eclipse.org/birt/downloads/demos/FirstReport/MyFirstReport.html Birt Flash Demo.
posted @ 2008-06-12 12:02 三人行,必有我师焉 阅读(3458) | 评论 (8)编辑 收藏

2008年5月18日 #

  最近很多人问我SWT Extension 项目上的那个不需要的JREExample是如何做出来的。我以前也会执着于这个问题,毕竟如果不依赖于JRE的话,就不需要为用户准备一个容量极大的安装包,但是这种做法看似有利,实则有利有弊。

就我所知,目前把Java程序编译成本机可执行程序的方法有两种,一种是GCJ,免费的,一种是Excelsior JET,商业的。我已经很久没有碰过GCJ了,因为当初用起来实在是非常麻烦,现在的版本如何,我不太清楚。我自己使用的是Excelsior JET,版本为3.7。有一点要注意的的是,Excelsior JET的后续版本好像已经不支持这个功能了,3.7是我所知的最后一个版本,能支持当前所有的Win32平台和早期的Linux(当前比较流行的Ubuntu不支持,因为内核版本过高,不过企业版Redhat没有问题)。不过我是很久以前从0day当下来的,由于0day仓储只保留一年,故现在已经找不到了,我自己的机器上也没有安装包了(有一次大意之下,把整个Download目录全给删掉了,事后悔之晚矣)。

Excelsior JET无非就是用自己的Runtime来代替JRE,只是比JRE更加灵活,根据Java程序具体的依赖来生成对应的Runtime。其实这个Runtime也挺大的,通常10M左右,不过比起JRE,那要小很多了。SWT Extension上的那个例子只有6M,是因为我用ASPack把所有的DLL文件全部压缩过了,体积小了一半。

就我的感觉,Excelsior JETGCJ更加灵活,也更好用,毕竟是商业版的东西,它的网站上曾经有例子将Eclipse 3.0编译成本机程序,不过我当初照着例子试了一遍,没有成功。Excelsior JET的编译过程极为耗时,我上大学的时候,当时机器只有128M内存,编译了一天JRE也没有完成,后来找同学借了根256的内存,这才得以完成。

JAVA代码编译成本机程序的弊端也是有的,那意味着你将无法在线升级,GCJ也许可以,但是Excelsior JET是绝对不行的,这是因为它最后一步要对所有DLL进行链接,如果更换了DLL文件,它会检测出来并报错。

各位看官如果哪位有兴趣,可以自行在网上查找Excelsior JET3.7或其他版本。由于安装包我自己也没有,故无法提供下载,见谅。

posted @ 2008-05-18 15:38 三人行,必有我师焉 阅读(3505) | 评论 (7)编辑 收藏

2008年5月11日 #

在SWT Extension中,引入了Function这个类。基本上所有的Win32 JNI库都有这个类,用来直接操纵Win32 的部分API。有了这个Class,我们不用编写JNI,就可以实现某些简单的,甚至是较复杂的Win32 API。这里我们就以EnumWindows这个API举例,看看怎么Java来执行这个Win32 API。
    private static final String FUNTION_ENUMWINDOWS = "EnumWindows";
    
private static final String USER32_LIB = "user32";
    
private static List windowsList = new ArrayList();
    
    
public static int[] enumWindows()
    {
        windowsList.clear();
        Callback callback 
= new Callback(Windows.class"enumWindowsProc"2);
        
int address = callback.getAddress();
        
if (address != 0)
        {
            
try
            {
                Function function 
= new Function(USER32_LIB, FUNTION_ENUMWINDOWS);
                function.invoke_I(address, 
0);
                function.close();
            } 
catch (Exception e)
            {
                SWT.error(SWT.ERROR_INVALID_ARGUMENT);
            }
            callback.dispose();
        }
        
int[] handles = new int[windowsList.size()];
        
for (int i = 0; i < windowsList.size(); i++)
            handles[i] 
= ((LONG) windowsList.get(i)).value;
        
return handles;
    }

    
private static int enumWindowsProc(int hwnd, int lParam)
    {
        windowsList.add(
new LONG(hwnd));
        
return 1;
    }
EnumWindows是用来遍历Windows窗口的API,它需要传入一个返回boolean值的callback的地址作为参数。实际上在C里面,一个boolean值无非就是是否非0,如果为0,则为false,不为0,则为true。我们只需要new 一个function实例,传入这个API所在的Lib和API名字,然后执行invoke方法就OK了,在Function里面,可以最多执行含有4个简单类型参数的API。

让我们再来看看FindWindowEx这个API,它需要传入2个int变量和2个字符串指针,根据SWT的设计,我们是可以将Java的字符串转换为指针的,因此通过Function我们也可以实现这个API:
    private static final String FUNTION_FINDWINDOWEX = Extension.IsUnicode ? "FindWindowExW"
            : 
"FindWindowExA";
    
private static final String USER32_LIB = "user32";
    
    
public static int findWindowEx(int parent, int hwndChildAfter, String className,
            String windowName)
    {
        
int result = 0;
        
int lpClassName = 0;
        
int lpWindowName = 0;
        
int hHeap = Extension.GetProcessHeap();

        
if (className != null)
        {
            TCHAR buffer 
= new TCHAR(0, className, true);
            
int byteCount = buffer.length() * TCHAR.sizeof;
            lpClassName 
= Extension.HeapAlloc(hHeap, Extension.HEAP_ZERO_MEMORY, byteCount);
            Extension.MoveMemory(lpClassName, buffer, byteCount);
        }
        
if (windowName != null)
        {
            TCHAR buffer 
= new TCHAR(0, windowName, true);
            
int byteCount = buffer.length() * TCHAR.sizeof;
            lpWindowName 
= Extension.HeapAlloc(hHeap, Extension.HEAP_ZERO_MEMORY, byteCount);
            Extension.MoveMemory(lpWindowName, buffer, byteCount);
        }

        
try
        {
            Function function 
= new Function(USER32_LIB, FUNTION_FINDWINDOWEX);
            result 
= function.invoke_I(parent, hwndChildAfter, lpClassName, lpWindowName);
            function.close();
        } 
catch (Exception e)
        {
            SWT.error(SWT.ERROR_INVALID_ARGUMENT);
        }
        
if (lpClassName != 0) Extension.HeapFree(hHeap, 0, lpClassName);
        
if (lpWindowName != 0) Extension.HeapFree(hHeap, 0, lpWindowName);
        
return result;
    }
其实像这种简单参数类型的API,Win32 里还有很多,我们完全不必为其专门编写JNI,只需使用熟悉的Java即可。虽然不是调用全部的API,但大部分常用的API都是没有问题的,关键是如何灵活运用。现在的大型商业RCP应用中,其实多多少少都参和了JNI,用于提升对用户的友好性和软件的执行性能,毕竟Java天生就是客户端开发的矮子。对于JNI,我们既不能一味排斥,也不能滥用,要把握一个平衡点,使之成为Java客户端开发的利器。
posted @ 2008-05-11 19:31 三人行,必有我师焉 阅读(2876) | 评论 (5)编辑 收藏

2008年5月4日 #

网上有一篇关于JNI中文问题的文章,写得很详细,http://www.vckbase.com/document/viewdoc/?id=1611

我在这里主要是想说说我碰到的一些问题,并且希望能从各位老大身上获得答案。

因为一直从事Java编程,基本上没有涉及过C++的开发,最近因为开源项目SWT Extension,不得已需要用JNI来实现一些系统Native功能。但是总是需要一些Java字符串对应C++的字符串的问题。一边情况下我都是使用SWT的TCHAR来解决问题,少部分情况需要传递Java String到JNI。然而少部分的这些Case总是在某些问题下出现乱码或者异常。我一直使用的是网上比较流行的中文编码解决方案:
char* jstringToNative( JNIEnv  *env, jstring jstr )
{
  
int length = env->GetStringLength(jstr );
  
const jchar* jcstr = env->GetStringChars(jstr, 0 );
  
char* rtn = (char*)malloc( length*2+1 );
  
int size = 0;
  size 
= WideCharToMultiByte( CP_ACP, 0, (LPCWSTR)jcstr, length, rtn,(length*2+1), NULL, NULL );
  
if( size <= 0 )return NULL;
  env
->ReleaseStringChars(jstr, jcstr );
  rtn[size] 
= 0;
  
return rtn;
}

jstring nativeTojstring( JNIEnv
* env, char* str )
{
  jstring rtn 
= 0;
  
int slen = strlen(str);
  unsigned 
short * buffer = 0;
  
if( slen == 0 )
    rtn 
= env->NewStringUTF( str ); 
  
else
  {
    
int length = MultiByteToWideChar( CP_ACP, 0, (LPCSTR)str, slen, NULL, 0 );
    buffer 
= (unsigned short *)malloc( length*2 + 1 );
    
if( MultiByteToWideChar( CP_ACP, 0, (LPCSTR)str, slen, (LPWSTR)buffer, length ) >0 )
      rtn 
= env->NewString(  (jchar*)buffer, length );
  }
  
if( buffer )
  free( buffer );
  
return rtn;
}

一般情况下,这两个函数能够很好的工作。但是在读写注册表时,如果一个key的名字或者value的名字中包含了中文,jstringToNative的解决方案是不正确的,我在网上查了一下其它的关于Java访问注册表的开源项目,发现虽然它们都对字符串进行了处理,但依然存在着中文问题。我进行了数次尝试,但都没有成功。最后到了已经绝望的时候,用开头我提到的那篇文章中里说的最不可能用到的方法将问题成功地解决了:
char* jstringToNative( JNIEnv  *env, jstring jstr )
{
  
const char* pstr = env->GetStringUTFChars(jstr, false);
  
int nLen = MultiByteToWideChar( CP_UTF8, 0, pstr, -1, NULL, NULL );
  LPWSTR lpwsz 
= new WCHAR[nLen];    
  MultiByteToWideChar( CP_UTF8, 
0, pstr, -1, lpwsz, nLen );
  
int nLen1 = WideCharToMultiByte( CP_ACP, 0, lpwsz, nLen, NULL, NULL, NULL, NULL );    
  LPSTR lpsz 
= new CHAR[nLen1];
  
int size = 0;
  size 
= WideCharToMultiByte( CP_ACP, 0, lpwsz, nLen, lpsz, nLen1, NULL, NULL );
  
if( size <= 0 ){
      delete [] lpwsz;
      
return NULL;
  }
  env
->ReleaseStringUTFChars(jstr, pstr );
  delete [] lpwsz;
  
return lpsz;
}
问题虽然解决了,但是我却不求甚解,为什么直接通过env拿到unicode字串,然后转成多字节串不行,但是通过env拿到utf-8字串,然后转成unicode字串,再将这个unicode字串转成多字节串就能工作?

如果大家有兴趣的话,不妨试试,用JNI调用RegOpenKeyEx这个API,就能验证我说的这个Case。哪位老大对JNI比较在行的话,可以在评论中告诉我,不甚感激。
posted @ 2008-05-04 13:17 三人行,必有我师焉 阅读(2520) | 评论 (2)编辑 收藏

仅列出标题  下一页