|
|
用户名:天蝎星座 笔名:Lionel 地区: 中国-上海 行业:其他 |
| 日 | 一 | 二 | 三 | 四 | 五 | 六 |
本blog记录了我情感的各个片断,写的都是些婆婆妈妈的伤心事,反映了我感性的一面。如果你更喜欢讨论技术,请访问EROSiON的THE OTHER SiDE,那是我理性的一面。“情感”与“理性”二字则刻画了一个活生生的人。
读书计划三
(作者置顶)
还是自己建网站的好
2009年刚刚转战blogger不久,blogspot就被和谐了,郁闷。
无奈之下,自己租了服务器空间,自己申请了域名,欢迎大家访问:http://dbgcool.com
转战blogger
Recession? Depression? 区别在哪里?
最近学英语,大家议论最多的话题就是recession,可是recession究竟是什么呢?在我查阅了一些英文文档后,突然来了翻译的雅致,所以索性把整片文档翻译一下,以方便大家理解。
Recession? Depression? 区别在哪里?
这里有一个古老的关于经济学家的笑话:当你的邻居失业了,就是recession;当你下岗了,就是depression。
Recession和depression之间的区别不太好被理解,原因很简单:根本就没有一个全球公认的关于这两个词的定义。如果你问100个不同的经济学家,这两个单词的区别是什么,那么你很可能得到100个不同的答案。我将会尝试总结这两个词的含义,而这个含义会被大多数经济学家所认可。
Recession: 报纸上的定义
报纸上关于recession的定义是GDP连续2个季度以上下跌。
但是这个定义在经济学家中并不是很流行,原因有两点。第一,这个定义没有考虑到其它因素的变化。例如失业率和消费者的信心。第二,使用季度作为时间点,无法精确的计算recession到底是哪天开始的,哪天结束的。很可能recession仅仅发生10个月或者更短,但却无法被检测出来。
Recession:BCDC的定义
美国经济研究局(National Bureau of Economic Research)下属的The Business Cycle Dating Committe提供了一个更好的确认是否已经发生recession的方法。那就是,统计商业活动的数量,例如:非失业人口数、工业成产、实际收入、批发零售等。当这种活动达到顶峰,并且直到滑落到最低点,这段时期就叫做recession。当这种商业活动再次爬升,就叫做发展阶段。在这种定义之下,平均来说一次recession要持续一年左右的时间。
Depression
在30年代depression之前,所有的经济下滑都被叫做depression。Recession一词就是在depression这段时期被造出来的,用以区别像30年代这样的depression。Recession用来描述1910-1913这样的小幅度经济下滑。这样的话,depression就可以被定义为持续时间更长、经济下滑幅度更大的recession。
那么我们具体如何区分recession和depression呢?一个比较好的办法就是查看GNP。Depression是指实际GDP下滑超过10%,而recession则是指下滑小于这个幅度。
在这个尺度的计算下,最近一次美国depression是发生在1937年5月到1938年6月,实际GDP下滑了18.2个百分点。同样,在这个尺度的计算下,30年代的美国depression就可以被分为两个阶段,一个阶段是1929年8月到1933年3月,这一阶段depression难以置信的严重,实际GDP下滑了几乎33个百分点。紧接着经历了一个短期的恢复阶段,然后1937-1938年又开始了一段比较严重的depression阶段。美国在战后从未经历过这么严重的depression。
60年来,最严重的recession则是发生在1973年11月到1975年3月,实际GDP降低了4.9个百分点。
在这种定义下,芬兰和印度尼西亚也经历过类似的depression。
现在,你应该已经可以不用借助之前的那个无聊经济学家的笑话,也可以区分recession和depression了吧?
原文链接:http://economics.about.com/cs/businesscycles/a/depressions.htm
美丽的西塘
西塘是我去过的第一个江南水乡。去之前,我在西塘、乌镇二者中选择了好久,最后终于决定去西塘。西塘是一个千年古镇,商业气息不如乌镇那么浓。据说西塘的夜色很美,所以我决定周四就去,晚上在西塘过夜,周五返回。周末去的话,人比较多,房价也贵,很不划算。
西塘地方不大,基本上半天就能走完。但是,真的非常建议在那里过夜。如果只是白天走走马观花的溜达一遍,无法体验水乡的那种感觉,那种意境。周四去的时候,人非常少。西塘一边是吃,另外一边基本都是住。住宿的地方我看了好几家,最后决定在河边客栈上下凉台那家过夜。房子窗户非常大,整个一面墙都是窗户,可以打开,而且还有美人靠,这是西塘很有特色的地方。因为这个房子位置太好了,所以即使周四,最后也只砍到120块钱。老板说,周五的话,这个房子就要租200,周末300。屋子里有空调电视,可以洗热水澡。其它的客栈也走了几家,要么窗户太小了,要么没有真正临水。
西塘的小酒吧非常有情调,装饰古典而又有现代气息。我去的那家名字忘了,是一个年轻mm开的,门口躺着一条白色的大狗,非常老实憨厚。我去了二楼,窗户正对西塘的那条河,楼上有好多书可以看。我点了一杯生姜水,边喝边从窗户向外望去。
西塘吃的我觉得都一般,粉蒸肉比较肥油腻;桂花酒酿苏杭都有;豆腐花就是东北的豆腐脑,但是量小了很多;螺丝也不大新鲜,但是分量还是可以的。点了一条鱼,结果都被饭店的猫吃了...哎,去西塘被猫欺负了,死缠着我不放,结果我一不忍心,就把鱼分给它吃了。糖醋排骨醋放的太多了,很酸,排骨肉又少,都是骨头。
西塘一行最令我难忘的就是太阳下山的时候,打开窗户,坐在窗边,躺在美人靠上,欣赏河对面的景色。看着来来往往,形形色色的人。有好多搞艺术的学生来这边画画呢。


通过代码实现EXE文件图标的替换
最近,好多人问我如何通过写个小程序,动态替换可执行文件的图标。这个问题看起来虽小,但却涉及到很多问题。网上也只能找到一些零零散散的资料,却没有详细的指导性文档。所以我决定把这个问题写下来,以方便大家查阅。
EXE文件图标的替换有很多方法,例如用一个EXE文件的图标替换另外一个EXE文件的图标;用一个ICO文件内的图标替换EXE文件的图标。这两种情况替换的方法不太相同,下面会详细讨论。
EXE文件图标的替换更一般的情形,是PE(Portable Executable)文件图标的替换。只不过Windows操作系统只会显示EXE文件的图标罢了。但DLL、OCX等PE文件也都可以包含图标资源。下面我们从ICO文件格式说起,一步步讲解替换EXE文件图标的方法和原理。
一、.ico文件中图标的保存格式
对于一个扩展名是.ico的文件,大部分人会认为一个ICO文件里面只能包含一个图标。但事实上,一个ICO文件里面可以包含很多图标。而且,目前大部分ICO文件里面都包含有不同尺寸、不同色深的好几个图标。我们以MSN安装包里的msnmsn.ico为例,这个图标文件就包含了9个不同尺寸、不同色深的图标,如图所示:

图表 1 msnms.ico
这样做的目的,是为了保证不同的操作系统、不同的桌面色深,图标显示均可达到最佳效果。操作系统会选择并显示一个最合适的图标。Windows XP支持32位色的图标,Windows 2000最多只支持256色的图标。所以,如果我们开发的软件若要同时支持Windows XP和2000,那么为了达到视觉上的最佳效果,每一个ICO文件应至少包含两个图标,一个是32位色的,一个是256色的。
ICO文件头部结构定义如下:
typedef struct
{
WORD idReserved; // Reserved (must be 0)
WORD idType; // Resource Type (1 for icons)
WORD idCount; // How many images?
ICONDIRENTRY idEntries[1]; // An entry for each image (idCount of 'em)
} ICONDIR, *LPICONDIR;
idCount表示该ICO文件包含图标的数量,所以理论上,一个ICO文件最多可以包含65535个图标。接下来,是该文件所包含的每一个图标的描述。
typedef struct
{
BYTE bWidth; // Width, in pixels, of the image
BYTE bHeight; // Height, in pixels, of the image
BYTE bColorCount; // Number of colors in image (0 if >=8bpp)
BYTE bReserved; // Reserved ( must be 0)
WORD wPlanes; // Color Planes
WORD wBitCount; // Bits per pixel
DWORD dwBytesInRes; // How many bytes in this resource?
DWORD dwImageOffset; // Where in the file is this image?
} ICONDIRENTRY, *LPICONDIRENTRY;
ICONDIRENTRY中记录了每一个图标的尺寸、色深、图标资源占用的字节数。dwImageOffset是一个文件偏移地址,指向图标资源数据起始位置。至于每一个图标资源内部的具体格式,与本文关系不大,这里就不再详细介绍了。
二、PE文件中的图标保存格式
PE文件中的图标保存格式与.ico文件中图标的保存格式略有不同。PE文件中,把ICONDIR和图标资源作为两种资源类型分别保存,前者是RT_GROUP_ICON类型,后者是RT_ICON类型。为了与.ico文件中图标的保存格式做以区分,我们把PE文件中的图标保存格式重新定义如下:
// #pragmas are used here to insure that the structure's
// packing in memory matches the packing of the EXE or DLL.
#pragma pack( push )
#pragma pack( 2 )
typedef struct
{
WORD idReserved; // Reserved (must be 0)
WORD idType; // Resource type (1 for icons)
WORD idCount; // How many images?
GRPICONDIRENTRY idEntries[1]; // The entries for each image
} GRPICONDIR, *LPGRPICONDIR;
typedef struct
{
BYTE bWidth; // Width, in pixels, of the image
BYTE bHeight; // Height, in pixels, of the image
BYTE bColorCount; // Number of colors in image (0 if >=8bpp)
BYTE bReserved; // Reserved
WORD wPlanes; // Color Planes
WORD wBitCount; // Bits per pixel
DWORD dwBytesInRes; // how many bytes in this resource?
WORD nID; // the ID
} GRPICONDIRENTRY, *LPGRPICONDIRENTRY;
#pragma pack( pop )
这里有一个区别,就是在.ico文件中,ICONDIRENTRY结构最后一个成员dwImageOffset表示的是图标资源文件偏移地址。而PE文件中,GRPICONDIRENTRY结构最后一个成员nID表示的是图标的索引ID。
三、Windows API
Windows操作系统为我们提供了几个API函数,用来更新PE文件中资源的函数有:BeginUpdateResource, UpdateResource, EndUpdateResource。用来枚举PE文件中资源的函数有:EnumResourceTypes,EnumResourceNames,EnumResourceLanguages。具体的使用方法可以参见MSDN。
下面我们通过具体的例子,来验证上面的方案是否可行。
四、用一个EXE中的图标替换另外一个EXE文件的图标
在这个例子中,我们用Windows XP自带的记事本的图标替换计算器的图标。

图表 2 记事本图标

图表 3 计算器图标
下面代码演示了如何替换32x32 32bits的图标:
HMODULE hModule = ::LoadLibrary("notepad.exe");
HRSRC hResInfo = ::FindResource(hModule, MAKEINTRESOURCE(8), RT_ICON);
HGLOBAL hGlobal = ::LoadResource(hModule, hResInfo);
DWORD dwSize = ::SizeofResource(hModule, hResInfo);
void* pData = ::LockResource(hGlobal);
HANDLE hUpdate = ::BeginUpdateResource("calc.exe", FALSE);
VERIFY(::UpdateResource(hUpdate, RT_ICON, MAKEINTRESOURCE(7),
MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
pData, dwSize));
VERIFY(::EndUpdateResource(hUpdate, FALSE));
VERIFY(::FreeLibrary(hModule));
大家肯定有个疑问,上面代码中MAKEINTRESOURCE(8)和MAKEINTRESOURCE(7)是怎么来的呢?其实索引8和7分别是notepad.exe和calc.exe中,32x32 32bits图标的索引。我们可以通过加载RT_GROUP_ICON资源,然后遍历GRPICONDIRENTRY中每一个图标的大小、色深,找到这个图标的索引。为了简便,这里直接写死的索引号,省略了这一动态查找的过程。
还有一个疑问应该就是MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT)了。PE文件中,每一个资源都至少对应一种语言。因为我的操作系统是英文的,所以记事本和计算器中的图标资源语言也是英文的。对于简体中文Windows XP操作系统所自带的记事本和计算器,这个值应该是MAKELANGID(LANG_CHINESE, SUBLANG_SYS_DEFAULT)。
那么我们怎么才能知道一个PE文件中,图标资源的语言是什么呢?我们可以通过资源枚举API,枚举所有图标、语言。可以参考上面提到过的那几个API函数,并查阅MSDN获取这些函数的帮助文档。
我们用记事本32x32 32bits图标替换计算器同样尺寸、色深的图标后,效果如下,在Titles显示方式下,图标大小是48x48的,图标没有被改变:

图表 4 48x48图标
在Icons显示方式下,图标大小是32x32的,图标被我们改变了:

图表 5 32x32图标
五、用一个ICO文件中的图标替换另外一个EXE文件的图标
用ICO文件中的图标替换EXE文件图标稍微有点麻烦,我们必须借助数据结构ICONDIR和ICONDIRENTRY来完成。我们使用msnms.ico中的32x32 32bits图标替换计算器中同样大小色深的图标:
DWORD dwSize = sizeof(ICONDIRENTRY);
HANDLE hFile = ::CreateFile("msnms.ico", GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
::SetFilePointer(hFile, sizeof(ICONDIR) + dwSize * 6, NULL, FILE_BEGIN);
DWORD dwRead = 0;
ICONDIRENTRY Entry;
VERIFY(::ReadFile(hFile, &Entry, dwSize, &dwRead, NULL));
::SetFilePointer(hFile, Entry.dwImageOffset, NULL, FILE_BEGIN);
void* pData = new char[Entry.dwImageOffset];
VERIFY(::ReadFile(hFile, pData, Entry.dwBytesInRes, &dwRead, NULL));
HANDLE hUpdate = ::BeginUpdateResource("calc.exe", FALSE);
VERIFY(::UpdateResource(hUpdate, RT_ICON, MAKEINTRESOURCE(7),
MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
pData, Entry.dwBytesInRes));
VERIFY(::EndUpdateResource(hUpdate, FALSE));
delete[] pData;
pData = NULL;
VERIFY(::CloseHandle(hFile));
上面代码中,sizeof(ICONDIR) + dwSize * 6的意思是定位到第8个图标结构体ICONDIRENTRY的位置,这个图标是32x32 32bits的。我们可以通过遍历每一个ICONDIRENTRY来判断,到底哪个图标是这个尺寸的。这里我们为了简便,把这部分代码省略了。
定位到第8个图标结构体ICONDIRENTRY的位置后,Entry.dwImageOffset的值就是第8个图标资源的文件偏移地址,Entry.dwBytesInRes的值是第8个图标图标资源的大小。然后我们将文件指针定位到Entry.dwImageOffset,并读取Entry.dwBytesInRes大小的数据到指针pData指向的内存当中。
最后,是替换文件图标资源的代码,这部分代码跟上一个例子是相同的。