我使用的trac是1.5.1版的Trac月。
一个 Commit Error困扰我两天。
这个error的描述类似:
Error:Commit failed(details follow):
Error:MERGE request failed on '/svn/dir1/dir2/file'
Error:MERGE of '/svn/dir1/dir2/file' : 200 OK(https://tracserver)
经过长时间的实验, 发现基于windows的这个版本如果将apache作为service启动就会出现这种现象, 作为console启动没有问题。也许是因为某种权限或者用户路径的原因导致trac的post-commit没有完成。
也有一种说法是post-commit-hook的代码里有bug。
时间有限, 不再深究, 暂且console启动。
同病相怜者:
Vic Learn From World
Ariejan.net
Compiling ...
baryon.cpp
baryon.cpp(1) : warning C0000: all glory is fleeing
Welcome to BB Share Networking. ALL FREE download software.
Saturday, January 26
Wednesday, January 10
Error: L6265E
"
Error: L6265E: Non-RWPI Section libspace.o(.bss) cannot be assigned to PI Exec r
egion ER_ZI.
Error: L6248E: libspace.o(.text) in PI region 'ER_RO' cannot have address type r
elocation to __libspace_start in PI region 'ER_ZI'.
"
使用arm编译器编译brew程序可能会遇到这个错误,原因可能有两点
1:程序中使用了浮点数
2:如果使用C++开发brew程序, 可能是使用了原生的new,而没有重定义new,也就是说没有使用MALLOC(sizeof(struct))来初始化对象。
Error: L6265E: Non-RWPI Section libspace.o(.bss) cannot be assigned to PI Exec r
egion ER_ZI.
Error: L6248E: libspace.o(.text) in PI region 'ER_RO' cannot have address type r
elocation to __libspace_start in PI region 'ER_ZI'.
"
使用arm编译器编译brew程序可能会遇到这个错误,原因可能有两点
1:程序中使用了浮点数
2:如果使用C++开发brew程序, 可能是使用了原生的new,而没有重定义new,也就是说没有使用MALLOC(sizeof(struct))来初始化对象。
Friday, December 22
brew程序的入口点
一个brew程序的真正入口点在AEEModGen.c里面
#ifdef AEE_LOAD_DLL
__declspec(dllexport) int AEEMod_Load(IShell *pIShell, void *ph, IModule **ppMod)
#else
#if defined(BREW_MODULE) || defined(FLAT_BREW)
extern int module_main(IShell *pIShell, void *ph, IModule **ppMod);
int module_main(IShell *pIShell, void *ph, IModule **ppMod)
#else
int AEEMod_Load(IShell *pIShell, void *ph, IModule **ppMod)
#endif
#endif
{
// Invoke helper function to do the actual loading.
return AEEStaticMod_New(sizeof(AEEMod),pIShell,ph,ppMod,NULL,NULL);
}
可见模拟器通过DLL的公开函数AEEMod_Load进入初始化阶段
brew各个模块之间可以进行消息传递函数回调, 而每个模块都可以单独编译不需要连接lib, 是因为各个模块实际公开的都是函数指针, 类似于
#define ISHELL_SendEvent(p,cls,ec,wp,dw) GET_PVTBL(p,IShell)->SendEvent(p,0,cls,ec,wp, dw)
AEE环境给每一个module都传入IShell指针, 在程序里如果想调用其他模块, 需要首先通过ISHELL_CreateInstance创建一个新的实例。
ISHELL_CreateInstance没有代码可看, 可以猜测AEE通过给出classid, 到自己维护的classid表里找到需要dll(module), 调入内存, 执行公开函数AEEMod_Load做初始化
AEEMod_Load-> AEEStaticMod_New设置modFuncs->CreateInstance = AEEMod_CreateInstance
随后AEE调用这个指针,在AEEMod_CreateInstance里面完成调用AEEClsCreateInstance的任务, classid这时候作为参数传进来
在AEEModGen.h里面有AEEClsCreateInstance函数的声明, 这个函数的定义需要在自己的程序里面完成。
int AEEClsCreateInstance(AEECLSID ClsId, IShell *pIShell, IModule *pMod, void **ppobj);
如果一个module里面定义了多个class就需要判断classid的值,创建不同的实例。
在初始化代码里
if (NULL == (pme = (AEEApplet*)MALLOC(nSize + sizeof(IAppletVtbl))))
return FALSE; //分配空间,nSize代表CAPP的空间大小!!
appFuncs = (IAppletVtbl *)((byte *)pme + nSize);
这两句表明在applet的结构体后面就是IAppletVtbl
appFuncs->AddRef = AEEApplet_AddRef;
appFuncs->Release = AEEApplet_Release;
appFuncs->HandleEvent = AEEApplet_HandleEvent;
在AEEApplet_HandleEvent里面将IApplet指针转换成AEEApplet指针,然后调用AEEApplet的pAppHandleEvent
之所以可以这么转换是因为AEEApplet的第一个成员就是IApplet指针的地址。结构体的第一个成员的地址就是这个结构体的地址。
INIT_VTBL(pme, IApplet, *appFuncs);
这一句使的AEEApplet结构体的第一个成员指向applet结构体后面的IAppletVtbl
#ifdef AEE_LOAD_DLL
__declspec(dllexport) int AEEMod_Load(IShell *pIShell, void *ph, IModule **ppMod)
#else
#if defined(BREW_MODULE) || defined(FLAT_BREW)
extern int module_main(IShell *pIShell, void *ph, IModule **ppMod);
int module_main(IShell *pIShell, void *ph, IModule **ppMod)
#else
int AEEMod_Load(IShell *pIShell, void *ph, IModule **ppMod)
#endif
#endif
{
// Invoke helper function to do the actual loading.
return AEEStaticMod_New(sizeof(AEEMod),pIShell,ph,ppMod,NULL,NULL);
}
可见模拟器通过DLL的公开函数AEEMod_Load进入初始化阶段
brew各个模块之间可以进行消息传递函数回调, 而每个模块都可以单独编译不需要连接lib, 是因为各个模块实际公开的都是函数指针, 类似于
#define ISHELL_SendEvent(p,cls,ec,wp,dw) GET_PVTBL(p,IShell)->SendEvent(p,0,cls,ec,wp, dw)
AEE环境给每一个module都传入IShell指针, 在程序里如果想调用其他模块, 需要首先通过ISHELL_CreateInstance创建一个新的实例。
ISHELL_CreateInstance没有代码可看, 可以猜测AEE通过给出classid, 到自己维护的classid表里找到需要dll(module), 调入内存, 执行公开函数AEEMod_Load做初始化
AEEMod_Load-> AEEStaticMod_New设置modFuncs->CreateInstance = AEEMod_CreateInstance
随后AEE调用这个指针,在AEEMod_CreateInstance里面完成调用AEEClsCreateInstance的任务, classid这时候作为参数传进来
在AEEModGen.h里面有AEEClsCreateInstance函数的声明, 这个函数的定义需要在自己的程序里面完成。
int AEEClsCreateInstance(AEECLSID ClsId, IShell *pIShell, IModule *pMod, void **ppobj);
如果一个module里面定义了多个class就需要判断classid的值,创建不同的实例。
在初始化代码里
if (NULL == (pme = (AEEApplet*)MALLOC(nSize + sizeof(IAppletVtbl))))
return FALSE; //分配空间,nSize代表CAPP的空间大小!!
appFuncs = (IAppletVtbl *)((byte *)pme + nSize);
这两句表明在applet的结构体后面就是IAppletVtbl
appFuncs->AddRef = AEEApplet_AddRef;
appFuncs->Release = AEEApplet_Release;
appFuncs->HandleEvent = AEEApplet_HandleEvent;
在AEEApplet_HandleEvent里面将IApplet指针转换成AEEApplet指针,然后调用AEEApplet的pAppHandleEvent
之所以可以这么转换是因为AEEApplet的第一个成员就是IApplet指针的地址。结构体的第一个成员的地址就是这个结构体的地址。
INIT_VTBL(pme, IApplet, *appFuncs);
这一句使的AEEApplet结构体的第一个成员指向applet结构体后面的IAppletVtbl
Tuesday, December 5
突然想起若干年前某些华人的卑劣
1999年在日本,我第一次搬家。打登载在中文报纸上帮助搬家的人的电话, 电话里的声音听上去很朴实。搬家当天那个人开了一辆面包车来, 一开始并没有说什么。等你家当装在了他的车上, 开车途中, 露出了本像。先套话看你是不是黑户口, 然后用骂骂咧咧的语言, 讲他家开的是风俗店, 差点明说他就是黑社会。让我多交搬家费, 后来当着我一位女同事的面,讲黄色笑话。
2000年陪老婆去参加日语一级考试。校门口,韩国老生摆起桌子提供饮料为韩国学生鼓劲。零散的几个中国妇女往学生手里塞F:L-G的传单。
2000年陪老婆去参加日语一级考试。校门口,韩国老生摆起桌子提供饮料为韩国学生鼓劲。零散的几个中国妇女往学生手里塞F:L-G的传单。
Friday, December 1
Vista冲击
刚刚看了微软Vista中国发布现场实况。
http://wmv.it168.com/others/06.11.30/Windows.wmv
加上前一段时间ms放出的vista sdk+.net framework 3.0,
http://www.microsoft.com/downloads/details.aspx?FamilyId=C2B1E300-F358-4523-B479-F53D234CDCCF&displaylang=en
我认为vista将迅速普及。这里有两方面的原因
1,面向家庭用户, vista的交互界面对用户的吸引作用,加上硬件的需求很高, 使得intel和dell这样的硬件厂商非常热衷于推广它。推动用户更新电脑就意味着更高的收益。
2,面向企业用户,vista sdk和.net framework 3.0的捆绑对于企业软件提供商有很大吸引。特别是缺少积累的中小软件开发商,因为开发成本降低和用户体验大幅提高, 市场竞争将会更加激烈。
纯技术观点
在vista下运行你的软件, 这个blog显示了可能会存在的一些问题
http://blogs.itecn.net/blogs/winvista/archive/category/1095.aspx
给我印象深刻的是这篇文章
http://blogs.itecn.net/blogs/winvista/archive/2006/09/03/3604.aspx
如果你从一个程序员的角度暂时没有感到冲击,那没什么不正常。因为你还没有面向vista编程。注意vista改变了一些东西,加强了安全性。比如service将处于session 0, GUI将处于session 1, 再比如顶楼blog里提到的"虚拟重定向"。
如果你作为企业类软件的厂商暂时没感到冲击, 那说明你的嗅觉不够敏锐啊。
如果你做为普通用户没有感到冲击, 那说明你非常成熟, 一眼你就看出了新玩意的本质。可难道iPod之前就没有mp3 player吗?
http://wmv.it168.com/others/06.11.30/Windows.wmv
加上前一段时间ms放出的vista sdk+.net framework 3.0,
http://www.microsoft.com/downloads/details.aspx?FamilyId=C2B1E300-F358-4523-B479-F53D234CDCCF&displaylang=en
我认为vista将迅速普及。这里有两方面的原因
1,面向家庭用户, vista的交互界面对用户的吸引作用,加上硬件的需求很高, 使得intel和dell这样的硬件厂商非常热衷于推广它。推动用户更新电脑就意味着更高的收益。
2,面向企业用户,vista sdk和.net framework 3.0的捆绑对于企业软件提供商有很大吸引。特别是缺少积累的中小软件开发商,因为开发成本降低和用户体验大幅提高, 市场竞争将会更加激烈。
纯技术观点
在vista下运行你的软件, 这个blog显示了可能会存在的一些问题
http://blogs.itecn.net/blogs/winvista/archive/category/1095.aspx
给我印象深刻的是这篇文章
http://blogs.itecn.net/blogs/winvista/archive/2006/09/03/3604.aspx
如果你从一个程序员的角度暂时没有感到冲击,那没什么不正常。因为你还没有面向vista编程。注意vista改变了一些东西,加强了安全性。比如service将处于session 0, GUI将处于session 1, 再比如顶楼blog里提到的"虚拟重定向"。
如果你作为企业类软件的厂商暂时没感到冲击, 那说明你的嗅觉不够敏锐啊。
如果你做为普通用户没有感到冲击, 那说明你非常成熟, 一眼你就看出了新玩意的本质。可难道iPod之前就没有mp3 player吗?
Thursday, November 9
莫名其妙的糖尿病特效产品DNJ
父亲让我查一下一种叫做DNJ的糖尿病治疗产品。
在中文网站上可以找到叫做"地恩基(中国)国际医学研究院"的网站在宣传这种DNJ产品。看网站上的宣传就让人起疑。于是借助google和yahoo检索了一下, 也许是google和yahoo做的不好,并没有找到"日本糖尿病并发症研究所(JDCS)常务理事、早稻田大学名誉教授、DNJ日本国际医学研究院井上孝治博士"的任何信息, 也没有找到"日本神奈川大学桑叶研究中心"这么个机构。也没有野尻博士的什么信息。
只有DNJ这个关键词确实可以找到一些治疗糖尿病的健康食品的信息。比如这里的一些介绍。里面只是说DNJ是桑叶独有的成份,期待其成为控制血糖,减肥的健康食品素材。
一些信息显示是神奈川县卫生研究所对DNJ的抑制血糖效果作了研究。通过Google可以检索到他们的研究报告(1),(2)
我不是学医出身,只能简单看一下里面的结论。报告显示实验用白鼠在吃混有桑叶提取物的饲料40周以后,对空腹血糖的升高有明显的抑制作用。
也许这种叫做DNJ的桑叶提取物确实对糖尿病人有益, 但也不至于达到山西患者张阿姨30天逼近治愈的程度吧!
在中文网站上可以找到叫做"地恩基(中国)国际医学研究院"的网站在宣传这种DNJ产品。看网站上的宣传就让人起疑。于是借助google和yahoo检索了一下, 也许是google和yahoo做的不好,并没有找到"日本糖尿病并发症研究所(JDCS)常务理事、早稻田大学名誉教授、DNJ日本国际医学研究院井上孝治博士"的任何信息, 也没有找到"日本神奈川大学桑叶研究中心"这么个机构。也没有野尻博士的什么信息。
只有DNJ这个关键词确实可以找到一些治疗糖尿病的健康食品的信息。比如这里的一些介绍。里面只是说DNJ是桑叶独有的成份,期待其成为控制血糖,减肥的健康食品素材。
一些信息显示是神奈川县卫生研究所对DNJ的抑制血糖效果作了研究。通过Google可以检索到他们的研究报告(1),(2)
我不是学医出身,只能简单看一下里面的结论。报告显示实验用白鼠在吃混有桑叶提取物的饲料40周以后,对空腹血糖的升高有明显的抑制作用。
也许这种叫做DNJ的桑叶提取物确实对糖尿病人有益, 但也不至于达到山西患者张阿姨30天逼近治愈的程度吧!
Wednesday, May 24
改变微软拼音输入法的键盘布局
从windows2000以来,在日文环境下输入中文已经不成为问题了。特别是微软中国网站还提供最新的微软拼音输入法2003下载。安装到日文windows 2000/xp上就可以轻松输入中文了。
但是,在微软拼音输入法缺省使用的是英文键盘布局,通过日文键盘输入中文的时候经常出现找不到键的情况,要想快速的使用msn messenger聊天,特别是输入表情符号的时候,头脑中需要记住英文键盘布局,还要切换自如才行。
今天经过调查研究,知道了可以修改下面的注册表,来改变微软输入法的键盘布局。在日文键盘的环境下,将
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layouts\E00E0804
的Layout File的值改为kbdjpn.dll,再启动机器,应该可以成功地达到目的。
注册项Keyboard Layouts下的键值里面,以0804结尾的是简体中文,0404是繁体中文,更多国家代码参见:Configuring and Using International Features of Windows: Windows 2000 - List of Locale IDs and Language Groups
以上办法也总不灵验,极端大法是用系统目录system32下的kbdjpn.dll代替同目录下的kbdus.dll文件。以WindowsXP为例,首先将C:\WINDOWS\system32\kbdjpn.dll拷贝到C:\下,改名为kbdus.dll,然后考回C:\WINDOWS\system32目录,覆盖原来的kbdus.dll。重启机器。
以上办法在Windows XP日文版和Windows 2003英文版实验成功。
但是,在微软拼音输入法缺省使用的是英文键盘布局,通过日文键盘输入中文的时候经常出现找不到键的情况,要想快速的使用msn messenger聊天,特别是输入表情符号的时候,头脑中需要记住英文键盘布局,还要切换自如才行。
今天经过调查研究,知道了可以修改下面的注册表,来改变微软输入法的键盘布局。在日文键盘的环境下,将
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layouts\E00E0804
的Layout File的值改为kbdjpn.dll,再启动机器,应该可以成功地达到目的。
注册项Keyboard Layouts下的键值里面,以0804结尾的是简体中文,0404是繁体中文,更多国家代码参见:Configuring and Using International Features of Windows: Windows 2000 - List of Locale IDs and Language Groups
以上办法也总不灵验,极端大法是用系统目录system32下的kbdjpn.dll代替同目录下的kbdus.dll文件。以WindowsXP为例,首先将C:\WINDOWS\system32\kbdjpn.dll拷贝到C:\下,改名为kbdus.dll,然后考回C:\WINDOWS\system32目录,覆盖原来的kbdus.dll。重启机器。
以上办法在Windows XP日文版和Windows 2003英文版实验成功。
Tuesday, February 14
避免IE窗口的双重启动
很多项目中有避免IE窗口的双重启动的需求。
具体而言就是通过一个链接打开的窗口,因为可能已经输入了一部分资料而还没有提交给服务器,如果再此点击同样的连接,不能轻易轻易就将已经打开的窗口替换。另外也要避免未保存就直接关闭窗口的情况。窗口关闭的时候要同服务器交互,通知服务器。下面的几个要点可以避免发生问题。*只在IE6上做了测试
1,使用window.open方法打开新窗口。这个方法的第二个参数是target,如果target的名字一样,不同连接或者相同链接打开的页面会在同一个IE窗口中显示。
2,IE窗口中的页面迁移,更新,提交,窗口的关闭都会触发onbeforeunload这个事件。在这个事件中设置确认消息。如果回答OK,画面才会进行下一步的动作。
3,在关闭确认之后onunload事件会被触发,在这里通过ajax技术同服务器端进行交互。因为IE的bug,onunload事件有可能不会被触发。我们可以通过其他办法避免这个bug。
针对这项技术我可以提供一个sample和通过email的技术支持。 Need Support
具体而言就是通过一个链接打开的窗口,因为可能已经输入了一部分资料而还没有提交给服务器,如果再此点击同样的连接,不能轻易轻易就将已经打开的窗口替换。另外也要避免未保存就直接关闭窗口的情况。窗口关闭的时候要同服务器交互,通知服务器。下面的几个要点可以避免发生问题。*只在IE6上做了测试
1,使用window.open方法打开新窗口。这个方法的第二个参数是target,如果target的名字一样,不同连接或者相同链接打开的页面会在同一个IE窗口中显示。
2,IE窗口中的页面迁移,更新,提交,窗口的关闭都会触发onbeforeunload这个事件。在这个事件中设置确认消息。如果回答OK,画面才会进行下一步的动作。
3,在关闭确认之后onunload事件会被触发,在这里通过ajax技术同服务器端进行交互。因为IE的bug,onunload事件有可能不会被触发。我们可以通过其他办法避免这个bug。
针对这项技术我可以提供一个sample和通过email的技术支持。 Need Support
Sunday, January 15
Using WTL with Visual C++ 2005 Express Edition - The Code Project - WTL
虽然我的英语不好,但是在WTL Group Members的鼓励下,还是在CodeProject上发布了自己的第一篇文章。Using WTL with Visual C++ 2005 Express Edition - The Code Project - WTL 记住发布的日子2006年1月13日。
下周去无锡出差一周,我已经很久没有回国了,希望这次工作顺利。
如果希望作更有价值的人,那么还犹豫呢? 我应该回到我的祖国。
下周去无锡出差一周,我已经很久没有回国了,希望这次工作顺利。
如果希望作更有价值的人,那么还犹豫呢? 我应该回到我的祖国。
Monday, December 19
首页 - 历史我记录
这里应该避免成为转贴转载的集中地,没有自己经历过的事情不要记入为好。
1949年以来,中国飞速发展,这其中你是如何参与建设,开发的呢?
希望这里能多多记录每个人的经历,项目,产品的开发,失败与成功的故事,其中一定孕育了大量为中国人骄傲和自豪的事情和故事。必成为中国的ProjectX的素材集中地
Read more at www.recordhistory.org/m...
Tuesday, November 8
如何在VCExpress下安装WTL
1,从MSDN http://msdn.microsoft.com/vstudio/express/visualc/ 下载并安装VCExpress 2005
2,按照MSDN的指示安装PSDK, 并且修改VCExpress的相关文件 http://msdn.microsoft.com/vstudio/express/visualc/usingpsdk/default.aspx ,
3,在修改VCExpress的Visual C++目录时添加下面的目录
Include files: C:\Program Files\Microsoft Platform SDK\include\atl
4, 修改PSDK的atl目录下的atlwin.h和atlbase.h文件
修改atlwin.h的1725行的SetChainEntry函数,将第一个for循环里的int i;定义提前。
---------------------------------------------------------------
BOOL SetChainEntry(DWORD dwChainID, CMessageMap* pObject, DWORD dwMsgMapID = 0)
{
int i;
// first search for an existing entry
for(i = 0; i < m_aChainEntry.GetSize(); i++)
---------------------------------------------------------------
修改atlbase.h的287行的AllocStdCallThunk和FreeStdCallThunk函数,将元代码注释,用新的宏代替。
---------------------------------------------------------------
/* Comment it
PVOID __stdcall __AllocStdCallThunk(VOID);
VOID __stdcall __FreeStdCallThunk(PVOID);
#define AllocStdCallThunk() __AllocStdCallThunk()
#define FreeStdCallThunk(p) __FreeStdCallThunk(p)
#pragma comment(lib, "atlthunk.lib")
*/
#define AllocStdCallThunk() HeapAlloc(GetProcessHeap(),0,sizeof(_stdcallthunk))
#define FreeStdCallThunk(p) HeapFree(GetProcessHeap(), 0, p)
---------------------------------------------------------------
3,下载并安装WTL http://wtl.sf.net
4, 下载WTL for VCExpress Wizard, 拷贝到WTL的AppWiz目录下,并双击安装WTL Wizard到VCExpress
WTL for VCExpress Wizard
enjoy VCExpress&WTL
2,按照MSDN的指示安装PSDK, 并且修改VCExpress的相关文件 http://msdn.microsoft.com/vstudio/express/visualc/usingpsdk/default.aspx ,
3,在修改VCExpress的Visual C++目录时添加下面的目录
Include files: C:\Program Files\Microsoft Platform SDK\include\atl
4, 修改PSDK的atl目录下的atlwin.h和atlbase.h文件
修改atlwin.h的1725行的SetChainEntry函数,将第一个for循环里的int i;定义提前。
---------------------------------------------------------------
BOOL SetChainEntry(DWORD dwChainID, CMessageMap* pObject, DWORD dwMsgMapID = 0)
{
int i;
// first search for an existing entry
for(i = 0; i < m_aChainEntry.GetSize(); i++)
---------------------------------------------------------------
修改atlbase.h的287行的AllocStdCallThunk和FreeStdCallThunk函数,将元代码注释,用新的宏代替。
---------------------------------------------------------------
/* Comment it
PVOID __stdcall __AllocStdCallThunk(VOID);
VOID __stdcall __FreeStdCallThunk(PVOID);
#define AllocStdCallThunk() __AllocStdCallThunk()
#define FreeStdCallThunk(p) __FreeStdCallThunk(p)
#pragma comment(lib, "atlthunk.lib")
*/
#define AllocStdCallThunk() HeapAlloc(GetProcessHeap(),0,sizeof(_stdcallthunk))
#define FreeStdCallThunk(p) HeapFree(GetProcessHeap(), 0, p)
---------------------------------------------------------------
3,下载并安装WTL http://wtl.sf.net
4, 下载WTL for VCExpress Wizard, 拷贝到WTL的AppWiz目录下,并双击安装WTL Wizard到VCExpress
WTL for VCExpress Wizard
enjoy VCExpress&WTL
Monday, November 7
如何在ASP.NET的CustomErrorPage里捕捉UnhandledException
我们知道ASP.NET的web.config里面可以设置CustomErrorPage,就像下面这个样子。
<customErrors mode="On" defaultRedirect="errorpage.aspx" >
<error statusCode="404" redirect="error404.aspx"></error>
</customErrors>
可是你在其他的aspx程序里抛出一个异常,在errorpage.aspx里并不能被捕捉到
in WebForm1.aspx
private void Button1_Click(object sender, System.EventArgs e)
{
throw new Exception("A Error Raised");
}
in errorpage.aspx
private void Page_Load(object sender, System.EventArgs e)
{
Exception ex = Server.GetLastError(); //这里永远返回null
if( ex!=null )
{
Label1.Text+= ex.Message;
}
}
google到一个解决方案:Custom Error Pages in ASP.NET
正像作者mattwag所说在Application_Error 以后会开始一个新的Session,即使Server里曾经存在的LastError也失去了踪影。
WebForm1.aspx抛出的异常最终会被global.asax的Application_Error处理,在这里如果没有Server.ClearError();的话,那么就会跳到在Web.config里指定的CustomErrorPage,但是异常的细节并没有办法直接获得。
mattwag将异常信息保存在session里,然后使用Server.Transfer使得session不被刷新,来达到目的。
这让我想到另一个比较简单的方案就是使用Application来保存异常信息,如下:
in global.asax.cs
protected void Application_Error(Object sender, EventArgs e)
{
Exception ex = Server.GetLastError().InnerException;
Application["UnhandledException"]=ex;
}
in errorpage.aspx
private void Page_Load(object sender, System.EventArgs e)
{
Exception ex = (Exception)Application["UnhandledException"];
Application.Remove("UnhandledException");
if( ex!=null )
{
//Write your code here like
//Label1.Text+= ex.Message;
}
}
适当地配置web.config和书写errorpage.aspx可以达到你需要的效果。
比如使用在子目录下的错误处理页。
<customerrors mode="On" defaultredirect="~/Subfolder/CustomErrorPage.aspx">
</customerrors>
<customErrors mode="On" defaultRedirect="errorpage.aspx" >
<error statusCode="404" redirect="error404.aspx"></error>
</customErrors>
可是你在其他的aspx程序里抛出一个异常,在errorpage.aspx里并不能被捕捉到
in WebForm1.aspx
private void Button1_Click(object sender, System.EventArgs e)
{
throw new Exception("A Error Raised");
}
in errorpage.aspx
private void Page_Load(object sender, System.EventArgs e)
{
Exception ex = Server.GetLastError(); //这里永远返回null
if( ex!=null )
{
Label1.Text+= ex.Message;
}
}
google到一个解决方案:Custom Error Pages in ASP.NET
正像作者mattwag所说在Application_Error 以后会开始一个新的Session,即使Server里曾经存在的LastError也失去了踪影。
WebForm1.aspx抛出的异常最终会被global.asax的Application_Error处理,在这里如果没有Server.ClearError();的话,那么就会跳到在Web.config里指定的CustomErrorPage,但是异常的细节并没有办法直接获得。
mattwag将异常信息保存在session里,然后使用Server.Transfer使得session不被刷新,来达到目的。
这让我想到另一个比较简单的方案就是使用Application来保存异常信息,如下:
in global.asax.cs
protected void Application_Error(Object sender, EventArgs e)
{
Exception ex = Server.GetLastError().InnerException;
Application["UnhandledException"]=ex;
}
in errorpage.aspx
private void Page_Load(object sender, System.EventArgs e)
{
Exception ex = (Exception)Application["UnhandledException"];
Application.Remove("UnhandledException");
if( ex!=null )
{
//Write your code here like
//Label1.Text+= ex.Message;
}
}
适当地配置web.config和书写errorpage.aspx可以达到你需要的效果。
比如使用在子目录下的错误处理页。
<customerrors mode="On" defaultredirect="~/Subfolder/CustomErrorPage.aspx">
</customerrors>
Wednesday, December 15
未来基于boost::function的native event
我曾经发现的native event的bug在汇报给微软以后,今天收到了回音。
基本上在明年问世的VC2005里将有一个新的没有bug的基于boost::function的native eventn实现。
但那估计也激不起我多大兴趣了。因为我现在完全在期待Don Clugston完善他的FastDelegate,特别是Multi-cast delegates的实现。
基本上在明年问世的VC2005里将有一个新的没有bug的基于boost::function的native eventn实现。
但那估计也激不起我多大兴趣了。因为我现在完全在期待Don Clugston完善他的FastDelegate,特别是Multi-cast delegates的实现。
Tuesday, July 13
解决无法看MSDN的鬼问题
我遇到奇怪的MSDN内容无法显示问题已经若干个月了。在我安装最新的2004.7版本以后更是完全无法使用MSDN了。我的开发环境是Windows XP Profession SP2+VS.NET 2003。MSDN的所有页面都显示'This page cannot be displayed' ,在我以前安装的msdn版本里还能有个别页面可以显示文字。这回变的更加彻底了。而我在另外一台windows2000的机器上安装这套MSDN则完全没有问题。
我google以后还真找到了难兄难弟http://www.dotnet247.com/247reference/msgs/48/243646.aspx,
"The help wouldn't work at all, I keep getting 'This page cannot be displayed' and the error is 'Cannot find server or DNS Error Internet Explorer', so finally I re-installed MSDN for VS.NET 2003 and i still keep getting the same problem. Even clicking on 'Help on Help' was coming up with the same error"
经过无数次的重装MSDN,uninstall 各种软件都无效后,发现了问题所在。如果我以另外一个account登录windows,msdn的内容就可以正确了。而ms-help协议实际就是安装在自己机器里的http,也是通过IE来访问的。所以判断可能是cache有问题了。
我使用另外一个具有administrator权限的帐号登录,找到C:\Documents and Settings\\Local Settings\Temporary Internet Files\Content.IE5 删除。回到我的account里,MSDN就完全正确了。
具体原因也许是index.dat 莫名其妙地被lock上了。也许就是也许。
参照: http://chuacw.hn.org/chewy/archive/2004/03/25/392.aspx
我google以后还真找到了难兄难弟http://www.dotnet247.com/247reference/msgs/48/243646.aspx,
"The help wouldn't work at all, I keep getting 'This page cannot be displayed' and the error is 'Cannot find server or DNS Error Internet Explorer', so finally I re-installed MSDN for VS.NET 2003 and i still keep getting the same problem. Even clicking on 'Help on Help' was coming up with the same error"
经过无数次的重装MSDN,uninstall 各种软件都无效后,发现了问题所在。如果我以另外一个account登录windows,msdn的内容就可以正确了。而ms-help协议实际就是安装在自己机器里的http,也是通过IE来访问的。所以判断可能是cache有问题了。
我使用另外一个具有administrator权限的帐号登录,找到C:\Documents and Settings\
具体原因也许是index.dat 莫名其妙地被lock上了。也许就是也许。
参照: http://chuacw.hn.org/chewy/archive/2004/03/25/392.aspx
Wednesday, July 7
揭开native event的面纱
这是我的第3篇关与native event的随笔。第一篇对native event作了简介。第二篇报告一个BUG。这一篇我们看看native event是如何实现的,并且尝试解决我们遇到的BUG。
从VC7(Microsoft Visual C++ .NET (2002) )开始MSVC提供了native event这一机制,试图为C++引入一个实现delegate的办法。一共提供了4个扩展关键子:__event (定义一个event),__raise(触发一个event),__hook(将一个成员函数连到event上),__unhook(去掉指定的函数),和两个作用在类上的特性:event_source(一个事件源),event_receiver(一个事件接受者)。
为什么会提供这么多看上去很丑陋的关键子呢?这些关键子生成了什么样的代码呢?
可以使用下面的编译命令来编译我在第二篇随笔里的代码。
cl /Fx /Fas native_event.cpp
/Fx编译选项会生成一个native_event.mrg.cpp,这是MSVC编译器对特性作了展开以后生成的源代码。/Fas编译选项生成相应的汇编代码。
我们看看native_event.mrg.cpp就足够了解native event的实现方法了。
__event关键子被展开成为一个事件函数链表指针,一个虚构造体,一个模板构造体,3个模板函数,一个名为__RemoveAllEventHandlers的成员函数,一个与event名同名的inline函数。除此以外还有4个辅助结构体。 可见event机制是非常类似宏定义的实现方案。
__hook通过__AddEventHandler模板函数将函数指针追加到函数链表里。__unhook从链表中删除函数指针。
__raise本身没有什么用处。实际调用的事件函数的时候,会循环调用函数链表里的函数。函数链表的每个节点里都存储了对象实体指针(this)和成员函数指针。成员函数指针同void*指针的转换利用了__eventingGetAddr这个灵巧的辅助类。
虽然代码看上去有点乱,但并不是很长,应该很容易看懂。
我在第二篇随笔里提到的bug,发生在
int __isEqual(void* p, void* pfn)
{
return ((T*) p == this->p) && (__eventingGetAddr::__getMAddr(pfn) == (void ( T::*) ()) pmfn);
}
这个函数里。多继承的情况下对(void ( T::*) ()) 形式的指针做比较是比较微妙的,明明相等的指针确返回了false。查看汇编代码发现一共比较了8个byte,两个DWORD PTR,具体为什么这么做我还需要做一些分析。
看上去一个可行的代替方案是:
int __isEqual(void* p, void* pfn)
{
return ((T*) p == this->p) && pfn == __eventingGetAddr::__getVAddr((void (T::*) ()) pmfn));
}
将函数指针转换成void*,然后再做比较。从asm看到这产生了高效的代码。
这个BUG导致的后果就是:无法在ATL/WTL中使用native event。这使的这一机制几乎失去了意义。
警告:使用native event要小心。
建议:在MSVC改正BUG之前不要使用native event。
CodeProject里有一篇最近发表的文章提出一种FastDelegate方法,似乎是不错的single-target delegate 解决方案。boost的function和signals则是更加值得关注的。
Wednesday, July 07, 2004 2:49 PM
这是我的第3篇关与native event的随笔。第一篇对native event作了简介。第二篇报告一个BUG。这一篇我们看看native event是如何实现的,并且尝试解决我们遇到的BUG。
从VC7(Microsoft Visual C++ .NET (2002) )开始MSVC提供了native event这一机制,试图为C++引入一个实现delegate的办法。一共提供了4个扩展关键子:__event (定义一个event),__raise(触发一个event),__hook(将一个成员函数连到event上),__unhook(去掉指定的函数),和两个作用在类上的特性:event_source(一个事件源),event_receiver(一个事件接受者)。
为什么会提供这么多看上去很丑陋的关键子呢?这些关键子生成了什么样的代码呢?
可以使用下面的编译命令来编译我在第二篇随笔里的代码。
cl /Fx /Fas native_event.cpp
/Fx编译选项会生成一个native_event.mrg.cpp,这是MSVC编译器对特性作了展开以后生成的源代码。/Fas编译选项生成相应的汇编代码。
我们看看native_event.mrg.cpp就足够了解native event的实现方法了。
__event关键子被展开成为一个事件函数链表指针,一个虚构造体,一个模板构造体,3个模板函数,一个名为__RemoveAllEventHandlers的成员函数,一个与event名同名的inline函数。除此以外还有4个辅助结构体。 可见event机制是非常类似宏定义的实现方案。
__hook通过__AddEventHandler模板函数将函数指针追加到函数链表里。__unhook从链表中删除函数指针。
__raise本身没有什么用处。实际调用的事件函数的时候,会循环调用函数链表里的函数。函数链表的每个节点里都存储了对象实体指针(this)和成员函数指针。成员函数指针同void*指针的转换利用了__eventingGetAddr这个灵巧的辅助类。
虽然代码看上去有点乱,但并不是很长,应该很容易看懂。
我在第二篇随笔里提到的bug,发生在
int __isEqual(void* p, void* pfn)
{
return ((T*) p == this->p) && (__eventingGetAddr
}
这个函数里。多继承的情况下对(void ( T::*) ()) 形式的指针做比较是比较微妙的,明明相等的指针确返回了false。查看汇编代码发现一共比较了8个byte,两个DWORD PTR,具体为什么这么做我还需要做一些分析。
看上去一个可行的代替方案是:
int __isEqual(void* p, void* pfn)
{
return ((T*) p == this->p) && pfn == __eventingGetAddr
}
将函数指针转换成void*,然后再做比较。从asm看到这产生了高效的代码。
这个BUG导致的后果就是:无法在ATL/WTL中使用native event。这使的这一机制几乎失去了意义。
警告:使用native event要小心。
建议:在MSVC改正BUG之前不要使用native event。
CodeProject里有一篇最近发表的文章提出一种FastDelegate方法,似乎是不错的single-target delegate 解决方案。boost的function和signals则是更加值得关注的。
Wednesday, July 07, 2004 2:49 PM
BUG Report: Failed When a Native Event is Unhooked with with Multi-Heritance
SYMPTOMS
当在一个使用多继承类作为event_receiver的未托管应用程序中unhook (__unhook) 一个native events时, 将会失败。__unhook将返回1(表明没有成功地unhook。在应用程序结束以后native event机制造成了内存泄漏.
CAUSE
这个问题发生在事件的接受者(event_receiver)是多继承类的情况下。在unhook的时候event的注入代码无法正确比较成员函数指针。
WORKAROUND
这个问题可以使用下面的代码重现:
#include
class A
{
int a;
};
class B
{
int b;
};
[event_source(native)]
class CSource
{
public:
__event void MyEvent(int nValue);
};
[event_receiver(native)]
class CReceiver : public A, public B //多继承
{
public:
void MyHandler1(int nValue) {
printf("MyHandler1 was called with value %d.\n", nValue);
}
void MyHandler2(int nValue) {
printf("MyHandler2 was called with value %d.\n", nValue);
}
};
int main() {
CSource source;
CReceiver receiver;
__unhook(&CSource::MyEvent, &source, &CReceiver::MyHandler2, &receiver);
__hook(&CSource::MyEvent, &source, &CReceiver::MyHandler1, &receiver);
__raise source.MyEvent(1);
__unhook(&CSource::MyEvent, &source, &CReceiver::MyHandler1, &receiver);//失败
__hook(&CSource::MyEvent, &source, &CReceiver::MyHandler2, &receiver);
__raise source.MyEvent(2);
__unhook(&CSource::MyEvent, &source, &CReceiver::MyHandler2, &receiver);//失败
}
运行结果
MyHandler1 was called with value 1.
MyHandler2 was called with value 2.
MyHandler1 was called with value 2.
MyHandler2没有被正确unhook。
The information in this article applies to:
Microsoft Visual C++ .NET (2002)
Microsoft Visual C++ .NET (2003)
Visual C++ 2005 Express Edition Beta
Wednesday, July 07, 2004 11:10 AM
SYMPTOMS
当在一个使用多继承类作为event_receiver的未托管应用程序中unhook (__unhook) 一个native events时, 将会失败。__unhook将返回1(表明没有成功地unhook。在应用程序结束以后native event机制造成了内存泄漏.
CAUSE
这个问题发生在事件的接受者(event_receiver)是多继承类的情况下。在unhook的时候event的注入代码无法正确比较成员函数指针。
WORKAROUND
这个问题可以使用下面的代码重现:
#include
class A
{
int a;
};
class B
{
int b;
};
[event_source(native)]
class CSource
{
public:
__event void MyEvent(int nValue);
};
[event_receiver(native)]
class CReceiver : public A, public B //多继承
{
public:
void MyHandler1(int nValue) {
printf("MyHandler1 was called with value %d.\n", nValue);
}
void MyHandler2(int nValue) {
printf("MyHandler2 was called with value %d.\n", nValue);
}
};
int main() {
CSource source;
CReceiver receiver;
__unhook(&CSource::MyEvent, &source, &CReceiver::MyHandler2, &receiver);
__hook(&CSource::MyEvent, &source, &CReceiver::MyHandler1, &receiver);
__raise source.MyEvent(1);
__unhook(&CSource::MyEvent, &source, &CReceiver::MyHandler1, &receiver);//失败
__hook(&CSource::MyEvent, &source, &CReceiver::MyHandler2, &receiver);
__raise source.MyEvent(2);
__unhook(&CSource::MyEvent, &source, &CReceiver::MyHandler2, &receiver);//失败
}
运行结果
MyHandler1 was called with value 1.
MyHandler2 was called with value 2.
MyHandler1 was called with value 2.
MyHandler2没有被正确unhook。
The information in this article applies to:
Microsoft Visual C++ .NET (2002)
Microsoft Visual C++ .NET (2003)
Visual C++ 2005 Express Edition Beta
Wednesday, July 07, 2004 11:10 AM
Thursday, May 13
WTL终于成为了一个Open Source项目。
昨天,WTL的创造者Nenad Stefanovic将最新的WTL版本7.5.4133放到了SourceForge.net上。这是继Wix之后的第二个由微软贡献的开放源代码项目。
可以说MS走出这一步,真的很不容易。从2003年4月12日MS的Pranish Kumar发mail说WTL将会开放到2004年5月12日真的走出这一步,耗时13个月。
另外听说WindowsXP的盗版用户也可以安装即将推出的SP2,MS的Barry Goffe说:"It was a tough choice, but we finally decided that even if someone has pirated copy of Windows, it is more important to keep him safe than it is to be concerned about the revenue issue."
无论怎样,看上去MS变得更加灵活和开放,他们对社会的贡献度变得更大。
昨天,WTL的创造者Nenad Stefanovic将最新的WTL版本7.5.4133放到了SourceForge.net上。这是继Wix之后的第二个由微软贡献的开放源代码项目。
可以说MS走出这一步,真的很不容易。从2003年4月12日MS的Pranish Kumar发mail说WTL将会开放到2004年5月12日真的走出这一步,耗时13个月。
另外听说WindowsXP的盗版用户也可以安装即将推出的SP2,MS的Barry Goffe说:"It was a tough choice, but we finally decided that even if someone has pirated copy of Windows, it is more important to keep him safe than it is to be concerned about the revenue issue."
无论怎样,看上去MS变得更加灵活和开放,他们对社会的贡献度变得更大。
To: wtl@yahoogroups.com
From: "Nenad Stefanovic"
Date: Wed, 12 May 2004 15:57:08 -0700
Subject: [wtl] ANN: WTL moves to Open Source!
Hello everybody,
WTL is now available as an Open Source project on SourceForge.net. WTL
is now part of the Microsoft Shared Code initiative that enables the
community to contribute to the project.
You can find the project at http://sourceforge.net/projects/wtl.
Feel free to send your questions/comments/suggestions to me.
Cheers,
Nenad
Wednesday, April 14
.Framework上一个不明确的地方
在中文版.Framework SDK文档的里的"从对话框的父窗体检索信息"一节写的不清楚,MSDN联接在这里。
原文如下:
根据对话框的用途,可能希望访问该对话框的父窗体提供的信息。对话框的初始化可能需要此信息,或者此信息可能涉及有关父窗体的应用程序状态的特定详细资料。
使用该对话框的 Form.ParentForm 属性访问父窗体的公共成员。应当将由 ParentForm 属性返回的引用显式转换成适当的类型。 下列代码演示如何使用 ParentForm 属性访问父窗体上的属性(在此示例中为 Text 属性):
' Visual Basic
Public Sub GetParentText()
Dim x as String
x = CType(Me.ParentForm, Form1).Text
End Sub
// C#
public void GetParentText()
{
string x = ((Form1)this.ParentForm).Text
}
可是所谓的父窗体指的是什么呢?
这里的ParentForm属性只有在MDI环境下的子窗口才有效,可见父窗体指的是MDI风格的父窗口。(在MSDN里这之前的章节里根本没有提到过MDI字样)
如果你是通过一个普通的ShowDialog(me)显出出来的窗口,那么千万不要被MSDN误导,这时候的父窗口需要通过Owner属性取得。我想Owner更常用。
读MSDN很有用。我知道了Close()并不会真正关闭窗口,只是Hide()而已。Dispose()才是生死判官。呵呵。
在中文版.Framework SDK文档的里的"从对话框的父窗体检索信息"一节写的不清楚,MSDN联接在这里。
原文如下:
根据对话框的用途,可能希望访问该对话框的父窗体提供的信息。对话框的初始化可能需要此信息,或者此信息可能涉及有关父窗体的应用程序状态的特定详细资料。
使用该对话框的 Form.ParentForm 属性访问父窗体的公共成员。应当将由 ParentForm 属性返回的引用显式转换成适当的类型。 下列代码演示如何使用 ParentForm 属性访问父窗体上的属性(在此示例中为 Text 属性):
' Visual Basic
Public Sub GetParentText()
Dim x as String
x = CType(Me.ParentForm, Form1).Text
End Sub
// C#
public void GetParentText()
{
string x = ((Form1)this.ParentForm).Text
}
可是所谓的父窗体指的是什么呢?
这里的ParentForm属性只有在MDI环境下的子窗口才有效,可见父窗体指的是MDI风格的父窗口。(在MSDN里这之前的章节里根本没有提到过MDI字样)
如果你是通过一个普通的ShowDialog(me)显出出来的窗口,那么千万不要被MSDN误导,这时候的父窗口需要通过Owner属性取得。我想Owner更常用。
读MSDN很有用。我知道了Close()并不会真正关闭窗口,只是Hide()而已。Dispose()才是生死判官。呵呵。
Monday, April 12
奇怪的C#语法:缺省参数
C#不支持缺省参数。只能通过重栽来实现缺省参数的需求。VB.NET和C++都支持。可是特性(attribute)缺支持缺省参数。
另一方面,属性property的set里面有缺省参数value。
难道不自相矛盾吗???
C#不支持缺省参数。只能通过重栽来实现缺省参数的需求。VB.NET和C++都支持。可是特性(attribute)缺支持缺省参数。
另一方面,属性property的set里面有缺省参数value。
难道不自相矛盾吗???
1,使用System.IO.Path.GetFullPath(.)或者System.IO.Path.GetFullPath("c:")这样的命令,每次运行可能得到不同的结果。特别是是使用VS.NET开发时。而且Framework1.0和1.1的运行结果也可能不一致。比如:GetFullPath("c:")「注意不是C:\」,在VS.NET 2002下经常会得到C:\Program Files\Microsoft Visual Studio .NET\Common7\IDE这样的结果,但有时也会得到C:\。即使你将CurrentPath设成C:\也没有用。由于Path的IL内部使用经过优化或者是native的nGetFullPathHelper()函数取得FullPath,我无法分析具体的原因。MSDN上也没有给出足够的信息。
2,通过继承Control来定制自己的控件的时候,请注意属性初始化的位置。
方案(1) 变量声明既初始化
Private _path As String = System.IO.Directory.GetCurrentDirectory ''初始位置
Public Property Path() As String
Get
Return _path
End Get
Set(ByVal Value As String)
_path = System.IO.Path.GetFullPath(Value)
End Set
End Property
方案(2)在New里初始化
Private _path As String
Public Property Path() As String
Get
Return _path
End Get
Set(ByVal Value As String)
_path = System.IO.Path.GetFullPath(Value)
End Set
End Property
Public Sub New()
MyBase.New()
Me._path = System.IO.Directory.GetCurrentDirectory ''初始位置
End Sub
方案1,一般情况下不会出现问题。方案2,VS.NET的DesignMode会自动将你项目所在目录的写入Form的InitializeComponent()里。
如同,
.... ...
MyControl.Path = "C:\MyProject\TestControl"
.... ...
这样你的程序配布到其他机器上的时候,可能会出现目录不存在的错误。
以上代码为VB.NET。
2,通过继承Control来定制自己的控件的时候,请注意属性初始化的位置。
方案(1) 变量声明既初始化
Private _path As String = System.IO.Directory.GetCurrentDirectory ''初始位置
Public Property Path() As String
Get
Return _path
End Get
Set(ByVal Value As String)
_path = System.IO.Path.GetFullPath(Value)
End Set
End Property
方案(2)在New里初始化
Private _path As String
Public Property Path() As String
Get
Return _path
End Get
Set(ByVal Value As String)
_path = System.IO.Path.GetFullPath(Value)
End Set
End Property
Public Sub New()
MyBase.New()
Me._path = System.IO.Directory.GetCurrentDirectory ''初始位置
End Sub
方案1,一般情况下不会出现问题。方案2,VS.NET的DesignMode会自动将你项目所在目录的写入Form的InitializeComponent()里。
如同,
.... ...
MyControl.Path = "C:\MyProject\TestControl"
.... ...
这样你的程序配布到其他机器上的时候,可能会出现目录不存在的错误。
以上代码为VB.NET。
Subscribe to:
Posts (Atom)