16 六月, 2007

显示远程图形窗口 (Displaying remote X clients with Cygwin/X)

运行于Unix/Linux上的软件,越来越多地采用图形界面,特别是软件安装和应用管理。这得益于java,虽然java的图形界面非常丑陋,但确实极大地降低了开发的门槛。

那么,远程如何启用xwindow呢?下面介绍的就是一个基于cygwin上xwindow+openssh的方案。

Displaying remote X clients with Cygwin/X

Displaying remote X clients with Cygwin/X is nearly identical to displaying remote X clients with any other X Server. You may use the secure ssh method, or the unsecure telnet method (not recommended).


6 五月, 2007

VC: UrlDownloadToFile中的IBindStatusCallback和Custom HTTP headers

UrlDownloadToFile和UrlDownloadToCacheFile是URL Monikers Functions中的简单易用的2个函数。这两个函数在发送下载文件的请求的时候,会自动根据cache control来判别是否需要重新下载,如果需要,则会在HTTP头中自动添加If-Modified-Since和If-None-Match信息,以及对应于该Url的合法的cookie信息。

使用这两个函数下载文件,但是需要添加某项头信息,譬如Referer,或者修改某项头信息,譬如User-Agent,该如何实现呢?这就需要用到这两个函数的最后一个参数“LPBINDSTATUSCALLBACK lpfnCB”。以UrlDownloadToFile为例,它在Binding lpfnCB指向的回调接口的时候,会尝试QueryInterface(IID_IHttpNegotiate),如果这个接口存在,它会调用IHttpNegotiate::BeginningTransaction方法以获取additional Request Headers。所以你可以在IHttpNegotiate::BeginningTransaction方法内实现Custom headers的目的。

具体步骤:

参考:SAMPLE: PostMon.exe Demonstrates How to Use URL Moniker to POST Data

例程(Custom request header as "User-Agent: CB/1.0;Referer: http://www.utblog.com"):

 查看全文

2 五月, 2007

BHO: getflash.dll 引起IE其他控件工作不正常

getflash.dll是FlashGet安装的IE插件,你可以在FlashGet的安装目录下找到这个dll文件。如果启用这个名为“gFlash Class”的BHO插件,可能会造成其他IE控件非正常释放,从而致使IE内存访问异常甚至Crash。参考“防不胜防 Flashget不比速度比流氓”,“Internet Explorer crashes”。有意思的是,FlashGet的开发人员对如何解决此问题的回答是“run...>regsvr32 /u getflash.dll”,解除注册,一了白了。

如果你使用IE6,也可以在“加载项管理”内禁用getflash。

解除注册和在IE内禁用getflash都需要用户手工操作,如果不想这么做,那么可以在页面级(HTML),通过javascript将你的控件插入某一层内(div.innerHTML = "<object..."),并在HTML Body的onUnload事件内删除此层。这种方法可以避免因getflash不正确拦截内部消息造成的控件释放异常。


27 四月, 2007

WB, MFC: 如何改变Web Browser Control的UI

改动IE的Web Browser控件UI,包括自定义或者禁止右键菜单,禁止控件border的3D特性,如何处理鼠标双击事件等等。

通过实现IDocHostUIHandler接口实现。

在IDocHostUIHandler设置前的文档窗口属性(可以被GetHostInfo改变的那部分)不会变化。所以,如果是在DWebBrowserEvents2::DocumentComplete事件内通过ICustomDoc接口设置IDocHostUIHandler的,那么当前窗口的Border和Scroll等属性的设置需要等待下一次Navigation完毕才能生效。有效期一直维持到控件释放或者下一次显式设置。

trick: 在控件显示前,Navigate "about:blank"页面,同时设置IDocHostUIHandler

至于通过重载PreTranslateMessage的方法实现禁止右键菜单的方法(参考:IE的WebBrowser control是一个窗口类,disable right mouse click -context menu-, accelerator keys),限制太多,特别是当此控件被Hosting两次后,连PreTranslateMessage方法也会被屏蔽。

参考:WebBrowser Customization

一个简单的例子:Disabling TCppWebBrowser's context menu or "right-click" menu. - by Borland Developer Support Staff


26 四月, 2007

Firefox吃内存,IE的webbrowser控件bug


23 四月, 2007

DIP: 反转片效果

做自动的反转片效果比较难,因为使用固定的参数只能适合少数照片。我使用的方法是:

  1. 自动色阶调整,提高原图质量
  2. Unsharp mask做轻度锐化(.5,.5,2)
  3. 适当调整亮度(-3)和对比度(+10)
  4. 大幅提高色彩饱和度(+30)

效果示意,原图:

Original,贵州都匀摆忙乡石板寨

应用反转效果后:

反转片效果


23 四月, 2007

DIP: 负片冲印(反转负冲)效果

参考pchome上的负片冲印效果PS方法,依次在VC++6.0内实现。

步骤:

  1. 红色通道“颜色加深”,绿色通道“反相,正片叠底,不透明度30%”,蓝色通道“反相,正片叠底,不透明度50%”
  2. 分别对三个通道进行色阶调整
  3. 合并通道,调整亮度和对比度
  4. 调整色彩明亮度和饱和度

效果示例,原图:

Original,贵州都匀摆忙乡石板寨

应用反转负冲效果后:

负片冲印效果

参考:

反转负冲效果(进修版本)

Photoshop图层混合模式计算公式大全

HSL and RGB conversion


20 四月, 2007

VC6: 半透明窗口

win2000以后,有新方法SetLayeredWindowAttributes,可以实现此目的。使用SetLayeredWindowAttributes,会影响到整个窗口,包括标题栏以及窗口内的所有控件。这是真正意义上的“半透明窗口”。

如果只是想实现“半透明窗口背景”效果的对话框,可以在首次绘制窗口之前保存被窗口覆盖的那部分的屏幕位图(从显示设备环境CDC对象COPY),然后采用AlphaBlend方法生成半透明效果,再绘制到窗口上。

AlphaBlend API需要msimg32.dll,这个动态库不支持win95/NT。如果想要支持95/NT,可以自己写一个AlphaBlend,毕竟,半透明位图的AC_SRC_OVER 算法相当简单。


20 四月, 2007

ActiveX: 如何获取IE浏览器的客户区屏幕坐标

  1. 首先要获取顶层浏览器窗口的接口,参考:"Retrieve the Top-Level IWebBrowser2 Interface from an ActiveX Control"
  2. 注意,IWebBrowser2的ClientToWindow方法,传入参数并非某点坐标,而是客户区的Size。返回的结果是在给定客户区Size的前提下,整个Browser的大小,包含标题栏,工具条,菜单,状态栏等,也包含整个客户区四周的Margin。所以无法通过这个方法取得客户端的left-top坐标
  3. 取得IHTMLDocument2接口:IWebBrowser2::get_document
  4. IHTMLWindow2接口:IHTMLDocument2::get_parentWindow
  5. 取得IHTMLWindow3接口:IHTMLWindow2::QueryInterface(IID_IHTMLWindow3)。注:window对象的所有方法,是通过IHTMLWindow2IHTMLWindow3IHTMLWindow4IHTMLWindow5这4个接口共同实现的。
  6. 通过IHTMLWindow3接口,取得window.screenLeft和window.screenTop的值。这两个值就是浏览器客户区left-top点相对于屏幕的坐标
  7. 通过IHTMLDocument2::get_body,获取document.body对象的offsetLeft, offsetTop, offsetWidth, offsetHeight值
  8. 现在,我们终于可以得到浏览器客户区的屏幕坐标了


31 三月, 2007

IE的WebBrowser control是一个窗口类,disable right mouse click (context menu), accelerator keys

VC++ 6.0

使用WebBrowser控件,它是IE核心控件,文档Load以后,右键点击会出现我们使用IE时一样的context menu。how to disable it?

一个通常的办法,是通过javascript脚本覆盖document.oncontextmenu属性,但是这要求你具有修改网页的权限,而且,IE安全设置必须允许运行javascript。

解决办法:

WebBrowser control是CWnd的继承类,所以,可以重载PreTranslateMessage过程来禁止右键菜单(甚至加上自己的context menu),也可以禁止accelerator keys功能。


29 三月, 2007

为帮助保护您的安全,Internet Explorer 已经限制此文件显示可能访问您计算机的活动内容

XP SP2对使用IE浏览的安全做了大幅提升,“本地计算机区域锁定”就是其一。这是防止恶意网页试图通过提升区域至更少浏览限制的“本地计算机区域”来运行有害代码。

“为帮助保护您的安全,Internet Explorer 已经限制此文件显示可能访问您计算机的活动内容”这样的提示,对于普通用户基本没有影响。但是对于开发者,因为测试本地html文件的需要,此类提示必然频繁出现,极其影响效率。

解决方法:

  1. Internet选项-->高级-->安全-->允许活动内容在我的计算机上的文件中运行,或者
  2. 在网页头添加"Web 标记",或者直接修改注册表。参考下面的链接

Internet Explorer 本地计算机区域锁定

Internet Explorer 区域提升限制


28 三月, 2007

php: 如何去除URL中的SESSION ID

php.ini有一个参数session.use_trans_sid,用来控制在客户端禁止cookie的时候是否自动重写url从而达到支持session的目的。URL重写的规则是由另外一个参数"url_rewriter.tags"设定的,缺省值为"a=href,area=href,frame=src,input=src,form=fakeentry,fieldset="。

问题来了,当用户打开第一个php页面,后台的php模块接到请求,创建了一个新的session(session_start),但是它在这个时候却无法得知客户端是否支持cookie。如果,系统的session.use_trans_sid是打开(1)的,那么php会重写所有url,将类似"PHPSESSID=93d5b29abebbd31a8cc53e2ac691abcf"字样的session id信息以参数形式记录在url中。

解决办法:

没有完美的解决方案,既然不希望php擅自修改url,那么只有放弃基于url的session实现机制,也就是放弃那些不支持cookie的用户。

设置session.use_trans_sid=0,或者设置url_rewriter.tags=""都可以达到去除url中恼人的PHPSESSID。url_rewriter.tags,可以使用ini_set动态设置,但是session.use_trans_sid不可以动态修改,这似乎和php的版本有关。如果Apache支持,那么修改.htaccess文件,也是可以的


1 三月, 2007

atoi, cookie, strcmp等


5 十一月, 2006

thread safety,就必须保证所有的函数线程安全

用到libxml2的nanohttp模块,虽说libxml2自从2.4.7版本开始就号称已经做到thread safety了,但是,至少这个附加的nanohttp模块在多线程环境中是不安全的。

即便你用--with-threads和--with-thread-alloc选项编译libxml2,也只能保证libxml2库在Parser和内存分配这部分线程安全。nanohttp的不安全不是因为libxml2自己内存管理冲突。

事实上,当多个线程同时调用nanohttp模块的时候,主机地址解析就会发生冲突。用tcpdump查看多线程调用nanohttp fetch的网络包,就发现,经常地,应当向B主机发送的请求却被发送到A主机。

原因是这个模块中调用了非线程安全的函数gethostbyname。处理B主机请求的线程调用gethostbyname(B),它生成的hostent数据覆盖了这之前负责处理A请求的线程的gethostbyname(A)的数据。结果,B主机请求就被发送到了A,张冠李戴了。

要想实现thread safety,就必须使用gethostbyname的线程安全版gethostbyname_r

同理,象localtime、gmtime之类的函数,与gethostbyuname类似,返回结果的内存分配不是由调用者控制的,都不是thread-safe的。应该用他们各自的reenter版,分别是localtime_r,gmtime_r。

这里找到一份Thread-Safe and Thread-Unsafe Procedure List


20 七月, 2006

UTM, The Universal Transverse Mercator System

近来研究google map,不得已要接触这些Projection System。

好文:http://www.uwgb.edu/dutchs/FieldMethods/UTMSystem.htm

mLL = mLE * cos(radian of lat);

美国军方(还有整个NATO)使用的表示方法,MGRS中间几位也是用的这种。以上海市(121.4666667E, 31.2333333N)为例,它的UTM数据是:Northing: 3456474, Easting: 353968, Zone: 51R;而不同精度的NATO表示如下:
UQ55(10公里)
UQ5356(1公里)
UQ539564(100米)
UQ53965647(10米)
UQ5396956474(1米)
转换的方法,查看上文中的“100-kilometer Digraphs”,“Determining Grid Coordinates”,“Appendix: The Digraph Lettering System”三个小节。

zoom pixelsPerLonDegree
==== ==================
0 93206.75555555556
1 46603.37777777778
2 23301.68888888889
3 11650.844444444445
4 5825.422222222222
5 2912.711111111111
6 1456.3555555555556
7 728.1777777777778
8 364.0888888888889
9 182.04444444444445
10 91.02222222222223
11 45.51111111111111
12 22.755555555555556
13 11.377777777777778
14 5.688888888888889
15 2.8444444444444446
16 1.4222222222222223
17 0.7111111111111111

来源:http://groups.google.com/group/Google-Maps-API/browse_thread/thread/6ff83431273c6adb/14042b7b07243ab6?q=scale+zoom&lnk=gst&rnum=1#14042b7b07243ab6

放大到最大(zoom=0),在赤道上,Google Map上的一个pixel对应实际距离1.2米左右(111,000/93206.75555555556~=1.2,赤道上,每经度间距离约111公里)

如果你想让自己的地图和Google Map配套使用,那么以上的数据就非常有用。


3 七月, 2006

wxPython: Boa vs. PythonCard

Boa Constructor

PythonCard

Boa,Python IDE和wxPython GUI开发平台,是一个类似于Delphi的相当优秀的RAD工具。开源,当前版本0.4.4alpha,发布时间是2005/07/11。虽然这个项目的开发进度似乎已经停滞,但是这个版本的Boa还是完全适用小型的GUI应用的开发。作为一个IDE,它具备大多数应该有的功能,也包括code completion, code tips等附加功能。支持自行修改添加Plug-in(如customModuleInfo),支持Custom component等。

不过作为内测alpha版,使用Boa,在开发过程中,一定会碰到很多Bug,想办法绕过去吧。还有,用Sizer实现半可视化的Layout调整,不太方便;以 全路径而不是相对路径调用外部图片等资源,如果不手工修改自动生成代码,则会在实际运行环境中产生异常。

PythonCard, 使用下来,不如Boa方便。不算是统一的集成开发环境(你需要分别调用layout Editor, code Editor);没有采用代码生成方法,而是以特定的资源文件来描述GUI(.rsrc.py),并通过PythonCard.model来解析这个资源 文件。所以严格来说,PythonCard不应该算是一个好的开发平台,更应当被看做是一个封装wxPython的框架(Frame)

参考:PythonCard and Boa Constructor not ready yet


2 七月, 2006

wxPython: wxApp::OnExceptionInMainLoop无效,如何接管异常处理?

wxApp::OnExceptionInMainLoop
“This function is called if an unhandled exception occurs inside the main application event loop. ”

重载了此方法,但是无效,无论什么异常,发生时,这个方法根本不会被执行。没有看过wxPython源码,猜测要么这是一个bug,要么帮助文件中的描述有问题,wxApp::MainLoop()会处理绝大部分Exceptions,所以几乎不存在“unhandled exception”。

如何接管wx App的异常处理?

写一个新的接收三参数( type, value, traceback)的过程,然后覆盖sys.excepthook

例如,在wxApp中将所有的异常都以Message Dialog形式报告给用户:

import sys, trackback

class MyApp(wx.App):
...
#new excepthook method
def _OnExceptionInMainLoop(self, type, value, traceback1):
topwin = self.GetTopWindow()
tblist = traceback.format_list(traceback.extract_tb(traceback1))
dlg = wx.MessageDialog(topwin, '%s : %srn%s'%(type, value, 'rn'.join(tblist)), 'Exception', wx.OK | wx.ICON_ERROR)
try:
dlg.ShowModal()
finally:
dlg.Destroy()
#call default exception handler here
sys.__excepthook__(type, value, traceback1)

application = MyApp(0)
#assigne new exception handler to sys.excepthook attribution
sys.excepthook = application._OnExceptionInMainLoop
application.MainLoop()

因为sys和trackback是通用模块,这个方法也适用于非wxPython应用

参考: http://docs.python.org/lib/module-sys.html


24 六月, 2006

python: locale - setlocale

错误:"locale.Error : unsupported locale setting"

locale.setlocale,最终调用本地OS上的setlocale的c/c++库。

如果本地OS不支持locale,或者本地OS的locale格式不同于locale模块的帮助文档中的描述,调用setlocale都会引发以上异常

以winxp简体中文,python 2.4为例,locale.setlocale(0,'')会返回locale字符串"Chinese_People's Republic of China.936",而不是locale.getdefaultlocale返回的"zh_CN.cp936",更多设置,需参考VC++的setlocale方法。而在中文Linux上,同样的方法,会返回标准的"xx_XX.xxx"格式字符串,譬如"zh_CN.GB18030",参考POSIX的setlocale man页。

严格说,这不算是bug。不过,为了提高Python程序的可移植性,保证这门语言的平台无关特性,最好能在将来的版本中解决这个问题


8 六月, 2006

python: 元组(tuple)的标准定义

元组(tuple),作为python序列数据类型的一种,标准定义如下:

A tuple consists of a number of values separated by commas

某些文章(譬如《A Byte of Python》,《Dive Into Python》)的定义却是:(与列表(list)类似的)在圆括号中用逗号分割的数据类型。

其实,圆括号"()"只在tuple输出的时候使用,而不是元组数据定义所必须的。

temp = 1,2,3,4 等同于temp = (1,2,3,4)

这就可以理解对于一个字典数据dictA,我们为什么能够使用for key, val in dictA.items()这样的语句,因为它和for (key, val) in dictA.items()是一样的

只有在声明空元组的时候,圆括号才是必须的

emptyTuple=()

其它:

一个元素的元组:

temp = 1, 等同于 temp = (1,)


8 六月, 2006

pyton: The __del__ method is not a reliable cleanup mechanism

Python初学者的经典教程《A Byte of Python》,在讲述“Class and Object Variables”的时候,有一个Person Class的例子,其中包括__init__和__del__实现。

比较C++,__init__类似于constructor,而__del__类似于destructor。实际上,Python的实现机制和C++有很大区别,特别是对于__del__。

作者也在此文末尾,特地提醒到:“ The __del__ method is run when the object is no longer in use and there is no guarantee when that method will be run. If you want to explicitly do this, you just have to use the del statement which we have used in previous examples.”

意思是说,如果想保证__del__顺利执行,需要显式调用del函数。否则的话,python会在垃圾收集的时候释放这些对象占用的内存,那时候,很难保证全局域中的Class声明本身是否还可用。很有可能你会在程序退出的时候,发生类似异常“exceptions.AttributeError:"'NoneType' object has no attribute...”。"NoneType"就是因为类声明已经先于对象被释放了(be set to None)

所以说,“The __del__ method is not a reliable cleanup mechanism”。你可以通过添加另外的方法实现这部分功能,如果一定要使用__del__的话,请务必显式(explicit)调用del来释放对象。


1 六月, 2006

IP首部拆解——中国协议分析网

see http://www.cnpaf.net/class/TCPANDIP/0532918532739185.html

摘要:

IP首部结构

typedef struct _iphdr //定义IP首部
{
  unsigned char h_verlen; //4位首部长度,4位IP版本号
  unsigned char tos; //8位服务类型TOS
  unsigned short total_len; //16位总长度(字节)
  unsigned short ident; //16位标识
  unsigned short frag_and_flags; //3位标志位+13位片偏移
  unsigned char ttl; //8位生存时间 TTL
  unsigned char proto; //8位协议 (TCP, UDP 或其他)
  unsigned short checksum; //16位IP首部校验和
  unsigned int sourceIP; //32位源IP地址
  unsigned int destIP; //32位目的IP地址
}IP_HEADER;


26 五月, 2006

sprintf的字符缓存越界

int sprintf(char *str, const char *format, ...);

要保证目标字符串缓存str的大小足够大。否则,会引起不可知错误。什么叫“不可知”,就是不可预测,就是让你很头晕,让你很后悔为啥要做一个程序员。

正在写的一个后台的服务进程,在收到SIGTERM(SIGKILL)信号的时候,结束所有的线程,释放所有的资源,并正常终止。然而昨天下午,这个服务突然不能被kill掉了。花了几个小时的debug,才发现原来错误就起源于一小段测试例程中的这个小小的不起眼的sprintf函数。缓冲区稍微小了那么几个字符,溢出覆盖了线程的数据区。而那些傻不拉唧的threads哪里知道它们的一亩三分地已经被人践踏,依旧照着这些莫名其妙的数据执行着莫名其妙的指令。结果是,我莫名其妙地浪费了很多时间。

建议:

参考:sprintf man(3) page


26 四月, 2006

Socket编程中发送接收缓冲大小设置

对于TCP,因为是可靠连接,所以,一个包被抛弃(发送方或者接受方),底层协议会要求再发送一次,或者阻塞在应用层。

而如果使用UDP,那么必须由应用层自己作逻辑判断,保证数据的完整性。否则阻塞时,包会被简单地丢弃。

Linxu 2.4中,

应用层,使用setsockopt(sock, SOL_SOCKET, SO_RCVBUF/SO_SNDBUF, &bufsize, (socklen_t)len)来设置send/receive buffer的最大值,此值不能超过sysctl中设置的最大对应值。所以,如果想增加缓冲大小,必须先修改系统配置,可以使用sysctl命令(reboot不保留),或者修改/etc/sysctl.conf(sysctl -p或者reboot后有效)

缓冲区增大,无疑会加重系统开销,要根据实际需求进行调节,不是大了就好。

对于UDP,写缓冲区和TCP不一样,UDP其实没有所谓的写缓冲区,SO_SNDBUF只是设置了当前发送包的最大尺寸


21 四月, 2006

GNU C/C++中,sizeof (struct xys) 与struct成员size之和不一致

X86Linux Redhat 8.0gcc/g++ v3.2

struct xyzstruct{

char a;

double b;

} xyz;

32位的编译器下,因为性能的考虑,对于struct(也包含union等其它数据结构)的大小和每个成员变量的位置都根据寄存器/内存访问值的边界要求做了align。这就使得sizeof(xyz) = 16 而不是实际成员所占空间之和 sizeof(char) + sizeof(double) = 9


一般来说,这不成问题,不过,对于那些空间紧张,或者有特殊要求的应用,就需要考虑struct的紧凑实现了。

譬如,将服务器端传入的固定格式的数据包直接映射到一个结构上去,便于访问:

union {

char bytes[9];

struct xyzstruct data;

} uvw;

如果这里的struct/union是紧凑实现的,那么我们可以通过uvw.data来直接访问bytes中的数据,不用再另外编写代码了。

解决办法:

1. gcc的编译选项“-fpack-struct

可以去除struct结构中额外的hole,缺点是,影响应用中所有的struct,包括从其它库中引入的struct结构

2. __attribute__ ((packed)) 声明

struct {char a; double b;} xyz __attribute__ ((packed));

不过这种简单格式的声明只对C有效,在C++中,你必须对struct中的每个成员(size>1)进行这样的声明:

struct {

char a;

double b __attribute__ ((packed));

int c __attribute__ ((packed));

} xyz;

3. 预编译选项 #pragma pack(n)

这里的n是通知编译器对此“pragma”行后出现的所有数据结构(包括stuct/union)采用n字节方式对齐(align)。如果n=1,那么表示全紧凑,struct中不会出现任何占位的hole。如果n是空,表示回复到编译器缺省的设置(一般=8

#pragma pack(1)

//此段内所有数据结构全紧凑

#pragma pack()