2009年1月30日星期五

IE7中ClearType自动关闭的问题

我的系统是Windows XP,装上了微软雅黑并打开ClearType。前些日子更新了IE7之后,很快我就发现,有很多页面(如百度空间)上的雅黑中文显示不正常,发虚,很模糊,而英文却又全是锯齿,总之没法看。

拜了Google大神,都说是IE7默认打开了ClearType导致中文发虚,可我这里的问题明明是ClearType被关了才会这样。小白太多,把Google都淹了,于是只好靠自己。在百度空间上随便找一个页面保存下来,一点一点找,总算是确定了问题所在:“FILTER: none”和“ZOOM: 1”。

有了关键字才好Google。IEBlog上有一篇《Notes on the interaction of ClearType with DXTransforms in IE7》,说是启用了filter就会强制关闭ClearType。IE 透明度失效和 zoom:1 有關?还提及,会出问题的还并不仅仅是ZOOM。

问题找到了,但在IE7内部似乎没办法解决。不过还是有一个曲线救国的法子,那就是用GDI++。GDI++是一个日本人开发的字体渲染工具,借助他可以把Linux下的FreeType2搬到Windows里边用。既然渲染引擎都被换掉,ClearType关不关也就无所谓了。

GDI++日文WIKI上找到并下载gdi0850.zipgdi0869.7z,解到同一个目录,然后用这样的命令启动IE:"gdi++.exe" "C:\Program Files\Internet Explorer\iexplore.exe"

下图中左边的窗口是ClearType被强制关闭的效果,右边是使用GDI++后的效果:

GDI++早已停止开发,但因为其是开源软件,所以有很多修改版,有点乱。有兴趣的话就去拜Google大神吧,这东西会很是需要一番折腾。

用了一段时间IE7,感觉也没有找到值得升级的理由。IE7不比IE6快,增加的功能我也不需要,问题还比IE6多。至于说标准,时至今日IE6还有20%以上市场占有率,有人敢无视?未来会有IE6被淘汰的一天,但显然不是现在。

2009年1月29日星期四

WSH中XMLHttp的怪异表现

参考如下JScript代码:

var xmlhttp = new ActiveXObject("MSXML2.XMLHTTP");
xmlhttp.onreadystatechange = function () {
 WScript.Echo(xmlhttp.readyState);
}
xmlhttp.open("GET", "http://otnth.blogspot.com/", true);
xmlhttp.send();

保存为js文件并用cscript或wscript执行,上述程序输出两次1后退出。如果把open挪到onreadystatechange前面,则只输出一次1后退出。

网上有很多人遇到移步方式下onreadystatechange只执行一次的问题,解决办法是把onreadystatechange写在open前面。但这里的问题似乎没有那么简单,感觉像是Windows Scripting Host脚本宿主未等待onreadystatechange变化就直接退出了,于是我写了如下代码求证:

var xmlhttp = new ActiveXObject("MSXML2.XMLHTTP");
xmlhttp.open("GET", "http://otnth.blogspot.com/", true);
xmlhttp.send();
while (true) {
 var n = xmlhttp.readyState;
 WScript.Echo(n);
 WScript.Sleep(100);
 if (n == 4) break;
}

这次输出了N个1后,直接跳到4。所以,WSH是单线程的?

解决问题的办法也有,即使用WScript.Shell新开一个进程运行所需代码,并通过命令行传递参数:

if (WScript.Arguments.length>0) {
 var xmlhttp = new ActiveXObject("MSXML2.XMLHTTP");
 xmlhttp.open("GET", WScript.Arguments.item(0), false);
 xmlhttp.send();
 WScript.Echo(xmlhttp.status + ' : ' + xmlhttp.statusText);
} else {
 var wsh = new ActiveXObject("WScript.Shell");
 var s = 'http://otnth.blogspot.com/';
 wsh.run('wscript ' + WScript.scriptfullname + ' "' + s + '"');
}

能用,不过看起来很不舒服。另外需要注意的是,命令行参数有长度限制,还要留意引号的问题。

好吧,就这样了。

2009年1月20日星期二

从解码Base64的宏想起

从找到那天起,一直都很爱EmEditor。轻巧快速,完善的正则表达式和多内码支持。除了编辑超大文件时的表现不如UEdit32外,我几乎找不到别的缺点。而且在没有丢失已有优点的前提下,EmEditor也有在一点点变得更好更强大,是个用起来很窝心的编辑器。

好了,工商时间结束。话说最近一次升级到EmEditor v8后发现,以前的Base64解码插件不能用了。正好现在的EmEditor借助Windows Scripting Host(WSH)提供了宏功能,于是想自己写个解码宏试试感觉。

这个宏需要做的有两件事:一、将Base64字符串解码;二、如需要,进行内码转换。

WSH的标准配备Javascript和VBScript都没有直接提供解决这两件事的函数或对象,也没有所谓标准库一说,要用JS或VBS的话就必须找现成的纯实现或自己写。当然,如果喜欢Perl、PHP、Python、Ruby等等等,WSH其实也能够支持。

这两种法子都不好。Base64肯定有成熟的纯实现,内码转换却是个很复杂的问题,UTF-8至GBK或许OK,Big5至GBK呢?但如果用Ruby一类的语言,写出来的宏就只有自己用了,普通人哪会去装个Ruby解释器?

其实,所谓的“完美”解决办法是有的,而且看起来很简洁,很清晰:

#title = "Base64Decode"
#tooltip = "Decode Selected Base64 String."

function Base64DecodeText(Base64Str, sCharset){
 var xml_dom = new ActiveXObject("MSXML2.DOMDocument");
 var tmpNode = xml_dom.createElement("tmpNode");
 tmpNode.dataType = "bin.base64";
 tmpNode.text = Base64Str;

 var ado_stream = new ActiveXObject("ADODB.Stream");
 // Default gb2312
 ado_stream.Charset = (typeof(sCharset) == "undefined") ? "gb2312" : sCharset;
 ado_stream.Type = 1; // 1=adTypeBinary 2=adTypeText
 ado_stream.Open();
 ado_stream.Write(tmpNode.nodeTypedValue);
 ado_stream.Position = 0;
 ado_stream.Type = 2; // 1=adTypeBinary 2=adTypeText
 var str = ado_stream.ReadText(-1); // -1=adReadAll
 ado_stream.Close();

 return str;
}

if (!document.selection.IsEmpty) {
 var s = document.selection.Text;
 //s = Base64DecodeText(s); // gb2312
 s = Base64DecodeText(s, "UTF-8");
 OutputBar.Clear();
 OutputBar.writeln(s);
 OutputBar.Visible = true;
 OutputBar.SetFocus();
} else {
 alert('Select First!');
}

这一小段东西至少说明了一个问题:那些所谓《YY天精通XX语言》的书,纯属胡扯。