Archive for the ‘Programming’ Category

FCKEditor的Packager
Saturday, July 7th, 2007

FCKEditor的js很大,它特意提供了一个packager来压缩。

FCKEditor的下载页提供了最新2.4.3版的下载,包括源代码及压缩过的代码。然而当我改动了JS想重新打包的时候问题来了,从同一下载页下载到的FCKEditor.Packager却不能使用,报错说找不到_packager.xml。搞笑的是那个下载的下面还提示2.4以前版本的Packager请到某某地下载。

最后浏览FCKEditor的Trac站点终于找到了想要的东西,下载地址

把它放在FCKEditor的目录下(和editor和_samples两个目录在同一层)运行即可。

Visual C++ 2005, ArcGIS Engine 9.2, ATL对话框程序
Friday, July 6th, 2007

首先向还在被迫学习或使用MFC、ATL之类代表原始社会生产力的工具的同志们道一声,你们辛苦了!

我郁闷了好长时间才把一个使用ArcGIS Engine的ATL程序弄起来。把详细过程分享出来,避免像我一样不熟悉ATL/COM的人走弯路。ArcGIS可以用C#或Java开发,但有时候你不能自己决定。

准备工作:

  1. Ctrl+Shift+N,New Project
  2. 选择Visual C++下的ATL,在右侧选择ATL Project,在Name栏填写project name,ATLDialog,OK
  3. 在随即出现的ATL Project Wizard里,选择“Application Settings”,Server Type选择Executable,点击Finish
  4. 项目已经生成。在Class View中,右击ATLDialog,Add=>Class
  5. 在Add Class对话框中,选择ATL Dialog,点击Add。接下来的ATL Dialog Wizard中,在Short name中填写TestDialog,点击Finish
  6. 向导已经为我们生成了一个ATL对话框的框架。

试一下吧。在文件ATLDialog.cpp中,找到_tWinMain函数,在前面添加代码:

CTestDialog dlg;
dlg.DoModal();

并且在前面要包含我们对话框的声明:#include “TestDialog.h”
按下F7,编译结束后对话框弹出了,按下OK,程序正常结束。

接下来,我们就可以在此基础上加上ArcGIS的控件了(给地图控件加一个点击事件处理)。

  1. Resource View中,ATLDialog->ATLDialog.rc->Dialog->IDD_TESTDIALOG,打开对话框编辑窗口
  2. 对话框稍微拉大点,右键->Insert ActiveX Control。在弹出的框中选择ESRI MapControl,同样方法加入ESRI LicenseControl
  3. 调整好MapControl的大小位置后,右键->Add Event Handler
  4. 弹出的向导中,选择CTestDialog类,Message Type选择OnMouseUp,点击Add and Edit
  5. 输入代码:

    IMapControl3Ptr ipMapControl;
    GetDlgControl(IDC_MAPCONTROL1, IID_IMapControl3, (void**) &ipMapControl);
    ipMapControl->AboutBox();

  6. 关键时刻来了。IMapControl3Ptr这些接口的定义在哪里呢?不要试图在ArcGIS的VC++ Help for VS2005中找到答案,它会让你郁闷几天的。
    在stdafx.h中找到#include <atlcom.h>这行,把它替换成下面的代码(根据你的ArcGIS安装位置更改):

    #define ISegment IMSSegment
    #include <atlcom.h>
    #include <atlwin.h>
    #undef ISegment

    #include “C:\Program Files\ArcGIS\include\CPPAPI\SDK_Windows.h”

  7. 按下F7,对话框又出现了,并且有淡蓝色背景的地图控件,在上面点右键,ESRI的授权声明就跳出来了。

ArcGIS的文档里,我没有发现有关于如何解决ISegment重复定义的介绍。而且文档中也没有提到SDK_Windows.h这个文件,只说那些控件的定义应该如何去导入,很繁琐,其实包含这个文件就可以了。

好了,有了这个基础,其它的翻翻文档和Sample应该就问题不大了,你可以试试加载一幅地图进来。

IE float元素的一个恶心Bug
Thursday, April 19th, 2007

这种问题不好Google,也许已经有许多人知道怎么解决了,不过我没有搜索到,为解决这问题,加起来花了应该有半天时间。我大致知道了一个重现的过程。

在一个比较窄的元素中,我想把几个词排成两列。用如下的代码(容器宽度是在外面的元素限制的):


<div style="width:250px">
<div style="border:1px solid #0066CC;padding:10px;font-size:14px;text-align:left;">
<div style="margin-left:10px;float:left;width:100px">Test</div>
<div style="margin-left:10px;float:left;width:100px">Test</div>
<div style="margin-left:10px;float:left;width:100px">Test</div>
<div style="margin-left:10px;float:left;width:100px">Test</div>
<div style="margin-left:10px;float:left;width:100px">Test</div>
<div style="margin-left:10px;float:left;width:100px">Test</div>
<div style="margin-left:10px;float:left;width:100px">Test</div>
<div style="margin-left:10px;float:left;width:100px">Test</div>
<div style="clear:both"></div>
</div>
</div>

但效果是这样:

Test
Test
Test
Test
Test
Test
Test
Test

显然我想边框把这几个条目全部包起来(而且行间距也不应该那么大!)。最初的时候这几个词是相等字数即等宽的,于是我把”Test”的float属性去掉,加上display:inline。这时,宽度就无效了,但因为字符串等长,我就给它加了固定的margin,可以实现两列了,而且IE的border也把它们都包起来了。

不过最近需求变了,这几个词的长度不等了,用display:inline再加margin的办法不行了。该面对的问题还是要面对,尽管IE很垃圾,用它的人还是太多。仔细看上面代码显示的效果,IE似乎是认为那个框里只有三行(在我的应用里,它是认为只有一行),显然是处理float的高度有问题。知道这点后,我就在那些float元素的前面加了一个空的div,NND,这就没事了。

代码:


<div style="width:250px">
<div style="border:1px solid #0066CC;padding:10px;font-size:14px;text-align:left;">
<div></div>
<div style="margin-left:10px;float:left;width:100px">Test</div>
<div style="margin-left:10px;float:left;width:100px">Test</div>
<div style="margin-left:10px;float:left;width:100px">Test</div>
<div style="margin-left:10px;float:left;width:100px">Test</div>
<div style="margin-left:10px;float:left;width:100px">Test</div>
<div style="margin-left:10px;float:left;width:100px">Test</div>
<div style="margin-left:10px;float:left;width:100px">Test</div>
<div style="margin-left:10px;float:left;width:100px">Test</div>
<div style="clear:both"></div>
</div>
</div>

效果:

Test
Test
Test
Test
Test
Test
Test
Test

request.getParameter返回null
Sunday, April 8th, 2007

用GET方法传递过去的参数,在某些情况下用request.getParameter只能取得null,而apache确实得到了完整的URL,且Debug时URL也是完整的,就是取不出来。

参数是一大段文字,其中可能有中文,我在客户端是用Javascript编码过的,为了避免URL过长,截断过,在以前的PHP里用得很好,就是偶尔会把一个中文字的编码给切断,造成末尾乱码,但影响不大。这次出了这个问题,我一直怀疑是不是Tomcat不能接受这么长的URL,或者是struts/JSP. 结果找到最后,发现就是编码不完整的问题。

在request.getParameter这个调用里,会对percent encode过的参数值进行解码,但解码时遇到不正确的码就会返回null. 这不正确的码就是我截断的。

以前编码是把所有的文字编码,组成URL后截断长度到6000。于是改了一下编码的策略,每100个字符作为一个块编码一次,直到字符串结束或剩下的空间不能容纳一个块为止。目前看来,这是一个好办法。

奇怪的错误
Tuesday, April 3rd, 2007

刚才调试一个日记页面时,突然看见tomcat打出的异常,整页的stacktrace,吓了一跳。仔细看,跟这个页面一点关系都没有。

后来老大过来看,原来是他刚才把一个出错页面信息保存下来记到日记里了。。。

愚人节还有一件趣事,有时间再记。

精彩评论
Saturday, March 31st, 2007

Quoted from IEBlog:

http://blogs.msdn.com/ie/archive/2006/11/30/ie6-and-ie7-running-on-a-single-machine.aspx#1186820

This “solution” shows the utter lack of talent at Microsoft. An application shouldn’t be so ingrained into an operating system that an entire virtual environment is needed to use different versions. I used to believe it was a pain testing web applications for quirks in IE6, Mozilla, Opera, Safari, etc, but now, thanks to the dolts at MS, I have to run a virtual environment in addition to my normal rounds of testing, and I guess I can forget about supporting IE6 users after April 1st. Because the Software Engineers at Microsoft are clearly lacking in their ability to produce a well written operating system, I’ve provided a diagram below to prevent mistakes like this from happening again, courtesy of my undergraduate OS class:

The right way to write an operating system:

[hardware]

[kernel]

[applications]

Notice how the applications sit entirely on their own level. Ingenuous!

The wrong way to write an operating system:

[hardware]

[kernel+GUI+Browser+Mr.Clippy+...]

[3rd party applications]

Notice how the applications, like Internet Explorer, are integrated with the OS. While this may be good for protecting monopolies, it’s bad for every one of your users. So please avoid it in the future!

- One unhappy customer

http://blogs.msdn.com/ie/archive/2006/11/30/ie6-and-ie7-running-on-a-single-machine.aspx#1186839

Damn, i see so many “well” trained people here. You call yourselves developers ? You are coding machines, have you ever developed something real in your life? Something that works on every noticeable browser at least on the market ? MS did a good think for themselves to keep you locked in in IE, but you see how many problems it created? I lay my hat down for IE, at the beginning of its age, it was a tool FOR developers, a tool that because of ignorance to the new wave of web features or because of too much bugfixes suddenly transformed itself in tool against developers, and i actually mean AGAINST(<-- font-weight:bold;font-size:8em;) developers, or at least good ones, that are preocupied to run their software for all of their clients. You people at MS, at least the ones that are developing IE, should make a partnership or quit doing browsers, give support to Mozilla or Opera to create a damn standards friendly browser. And create something like Apollo from Adobe for your own platform taste. IE is now a mess, progress has been made with IE7 but it is far from being or at least trying to be as standards friendly as FF or Opera or Safari. You could even start concentrating on doing good, quality software as a plugin for FF (like .net integration). Active-X is a mess. No serious company still sees it as a common choice over java(if you want low level stuff, not possible with flash). You have lost the plugin war, and the browser war is still won by you, but only by inertia. I repeat it again, i bet you have great programmers there, but because you are a company "for the money", they will always have pressure on them from above and never finish a good quality product, they will always have to switch focus on something else than browsers.Dont tell me that your browser team, in 7 years has developed only and only IE7. The so crazy "developers, developers" is something like a Jabba roar when i kill my mind hacking IE to make my client or my boss happy. And this thing of not being possible to run two versions of IE on the same machine is quite a blow. IE is only damn renderer, and i bet the part that breaks is the one that made windows so integrable with it. You've got sued for this, and you also got sued for the Eolas issue.And even your own plugin architecture got broken.We have to rely on crazy JS hacks to insert a MediaPlayer plugin, not making our content possilbe to multiple devices, or having to overwork to avoid this. Problems that the Opensource Mozilla Gecko engine will never have. I finish my rant here, but probably Adobe's Apolo will be the wave of the future with Internet Applications, or might that be ExpresionSuite with .net ? Or the browser will maintain forever its might.

http://blogs.msdn.com/ie/archive/2006/11/30/ie6-and-ie7-running-on-a-single-machine.aspx#1187334

Its funny I was just thinking about how messed up Windows had done things and how simple the logic would be. If it where me developing an OS (Which I realize is a lot of work) that I wouldnt want anyone being able to mess around with the core of the OS itself and that to create a folder like the windows folder that is not writable to period and have another folder for all 3rd party applications including there own so that the end user would have full control but not have to worry about any program / user from removing files that make the os work. you could have a layer overtop of the core os that could be modified to look like it was modified but not actually changing it so if you didnt want it you could remove it. Another method of working with IE 6 and IE 7 that no one has mentioned is to have access to another pc and using vnc or something of the like, thats what I do for all my web dev. For app dev I use vmware cause I dont want to blow up my os lol (again because its so unstable) I think developers should just say to hell with older browser versions and force an update lol :) if all websites wouldnt work with IE6 people would have to upgrade. Yes I realize there are cases where you cant upgrade but still (thats no excuse)

IE,无比垃圾
Saturday, March 31st, 2007

对于开发者来说,使自己的界面在IE下显示正常,需要花费数倍于在Firefox中下的功夫。

人们可以为Firefox开发出Firebug这样强大的东西,而IE的开发者们自己也仅仅只能做出一个跟Firebug比起来基本上没用的toolbar.

时无英雄,竟使竖子称雄!希望IE早日安息。

GBK(GB2312)向UTF-8的编码转换
Thursday, February 8th, 2007

最近做一个IE插件,要从网页中取得文字,编码到一个URL中去。在前一篇文章“中文URL编码”中,粗略地介绍了URL编码的规则,以及中文URL编码的过程,但在如何将GBK或者GB2312编码的汉字转换到UTF-8编码仍然是一个问题。编码是一个很复杂的问题,我也了解甚少,这里只是写写我的经验,欢迎补充和指正。

在PHP、.NET中,编码的转换都比较容易。ATL中有一些宏是用来做编码转换的,我没试过,而且我更愿意用后面所讲的方法。

在COM编程中,字符串多存储在BSTR结构中。网上许多文章都说这个数据结构中存储的就是Unicode,我就试了好多次从Unicode转UTF-8,未遂。在Debug的时候,含有中文字符串的BSTR能够正常显示,说明它的编码应该是GBK.

如何从GBK转换到UTF-8呢?libiconv应该可以做到,然而我使用它的Windows port后,可以编译、注册COM组件,就是工具栏出不来了,于是放弃。上网搜索,得到一个被广泛转载的CChineseCode类。然而它仅仅针对汉字(每个汉字在UTF-8编码中占3个字节),如果字符串中有英文,就有麻烦了,因为英文在UTF-8编码中只有一个字节。另外有的字符会占用更多的字节。所以这个类并不适用。

正确的方法是用Win32 API的MultiByteToWideCharWideCharToMultiByte两个函数,Wide character指的就是Unicode. GBK和UTF-8之间的转换,需要用Unicode作为桥梁(在这种方法里)。比如我们要转换这样一个字符串”编码 - Google 搜索”。

从GBK向Unicode转换

该字符串在BSTR类型的变量in中存储,首先将其转换为普通的字符串:

char *lpszText = _com_util::ConvertBSTRToString(in);

此时,如果用strlen函数取得lpszText的长度,则为18,4个汉字,每个占两个字节,另外有10个英文字符。所以说GBK/GB2312是MultiByte而不是WideChar. 并且有lpszText[0] == 0xb1 && lpszText[1] == 0xe0,在微软Windows Codepage 936这一页上查到果然是“编”字,更坚定了我们认为它是GBK的信心。

转换到Unicode所用的函数是MultiByteToWideChar,第一个参数是MultiByte的Code page,如果确定是GBK,就可以使用936. 我考虑它应该是与系统有关的(比如日语系统上应该是932),所以使用CP_ACP,系统所用的Codepage.

先通过将cchWideChar参数设置为0,取得转换后需要的空间大小,然后分配空间,再做实际的转换(转换时cbMultiByte为-1表示要转换的字符串以0结尾)。代码如下:

int wLen = MultiByteToWideChar(CP_ACP, 0, lpszText, -1, NULL, 0);
LPWSTR wStr = (LPWSTR)CoTaskMemAlloc(wLen * sizeof(WCHAR));
MultiByteToWideChar(CP_ACP, 0, lpszText, -1, wStr, wLen);

wLen是15,注意是指宽字符的个数,很贴心,14个字符,加上末尾的结束符。分配空间的时候也要注意,不是15个字节,而应该分配30个字节。这些在MSDN中都有说明,仔细看cchWideChar参数的介绍。最后一行代码执行后,wStr中就是这些汉字的Unicode了,查看一下,wStr[0] == 0×7f16,刚才在微软Windows Codepage 936查找时,“编”字的下面标明7f16,就是它的Unicode编码,说明一切正常。

从Unicode向UTF-8转换

转换到Unicode后,就可以使用WideCharToMultiByte函数将其转换到UTF-8编码,这次的code page要用CP_UTF8. 和前面的转换一样,先计算所需要的空间大小并分配,再做实际转换。

int aLen = WideCharToMultiByte(CP_UTF8, 0, wStr, -1, NULL, 0, NULL, NULL);
char* converted = (char*)CoTaskMemAlloc(aLen);
WideCharToMultiByte(CP_UTF8, 0, wStr, -1, converted, aLen, NULL, NULL);

aLen为23,因为4个汉字,每个占3个字节,加上10个英文字符(每个占1字节),再加末尾的’\0′,正好是23. 现在converted里就是字符串”编码 - Google 搜索”的UTF-8编码。converted[0] == 0xe7 && converted[1] == 0xbc,正是“编”字的UTF-8编码。

好了,现在终于得到了中英文混合字符串的UTF-8字节序列,可以进行URL编码(percent encoding)了。

如果你也看了CChineseCode类的代码,就会奇怪既然作者知道用WideCharToMultiByte做GB2312到Unicode的转换,为什么在UnicodeToUTF_8函数中要舍近求远呢?