Archive for the ‘Windows’ Category

为什么在转换到LPARAM之前会进行一个多余的转换

星期日, 20 6 月, 2010

如果你阅读以前的代码,将会经常发现有类型转换看上去是多余的:

SendMessage(hwndListBox, LB_ADDSTRING, 0, (LPARAM)(LPSTR)”str”);

为什么“str”要首先被转换到LPSTR?这个字符串已经是个LPSTR!

这是在16位Windows中遗留下来的问题。我们还记得在16位Windows中声明指针时,默认情况下是生成一个近指针。因此,“str”是一个指向字符串的近指针。如果代码被写成下面这样:

SendMessage(hwndListBox, LB_ADDSTRING, 0, (LPARAM)”str”);

那么这个近指针将被转换为一个长整数值。由于近指针是16位的值,因此程序将通过零扩展把指针扩展为32位长整数。

然而,在窗口消息中,所有的指针都必须是远指针,因为接收消息的窗口过程可能与发送消息的代码是在两个不同的模块中。近指针需要和默认选择符组合在一起再使用,而在每个模块中的默认选择符是不同的。如果只是传递一个近指针给另一个模块,那么将会导致这个指针和接收模块的默认选择符放在一起使用,而这个默认选择符与发送模块的默认选择符是不同的。

不过在Win32中,你无需去担心这个问题了,你是不是应该感到很高兴?

巨指针百度百科

远指针百度百科

HINSTANCE HMODULE

星期日, 20 6 月, 2010

这两者现在表示的是同样的意思,但在以前它们的含义是非常不同的。这个区别主要是来自于16位Windows。

在过去,模块(module)表示一个已被加载到内存的磁盘文件,并且模块句柄指向的是一个描述文件信息的数据结构,这个数据结构所包含的信息是:这些文件来自什么地方,以及被加载到内存的什么位置。而实例(instance)表示的则是一组变量。

我们可以使用一个很形象的比喻:模块就像一个C++类,它描述了如何构造一个对象,以及实现一些方法,并且描述了由这个类创建出来的对象的行为。而实例就像是一个用这个类创建出来的C++对象,它描述的是某个特定对象的状态,而状态也就相当于这个对象中成员的值。

在16位Windows中,所有的程序都是在同一个地址空间中运行的,即时有五个程序使用同一个DLL,这个DLL也只会被加载到内存中一次,并且DLL的数据段也只有一个副本(在C++/C#术语中,DLL就好像是一个单件(singleton)类)。

这是正确的,DLL应该是属于系统范围的,而不是属于进程范围的。对于每个使用DLL的程序,DLL不会单独创建一个独立的数据副本。不过,如果在DLL中需要知道每个程序的一些信息,你必须自己来记录这些信息。

我们用实例句柄来表示一个程序,而不是模块句柄,因为在打开的两个记事本程序中有着相同的模块句柄(因为在每个实例中运行的是相同的代码)。这样,把这两个记事本程序区分开来的东西就是在每个实例中都包含了自己的变量。

这就是为什么在WinExec函数和ShellExecute函数中返回的是HINSTANCE:这是从16位Windows中沿用过来的方式,其中HINSTANCE正式用来标识程序的方法。

在Win32中程序是运行在独立的地址空间中,因此程序的实例句柄无法跨越进程边界。因此设计者们只需要使用唯一一个信息:模块的基地址。在Win32中HINSTANCE和HMODULE都用来表示模块的基地址。

WPARAM LPARAM

星期日, 20 6 月, 2010

Windows早期是16位的。在每个消息中可以携带两个参数,分别是WPARAM和LPARAM。其中,第一个参数是16位的值(word),因此在这个参数的名字中使用了W,而第二个参数是32位的值(long),因此在这个参数的名字中使用了L。通常,W参数是用来传递句柄和整数之类的东西,而L参数则是用来传递指针。

当Windows过渡到32位时,WPARAM参数也随之变成了32位的值。因此虽然W表示word的意思,但现在已经不再是一个word了(而在64位Windows中,这两个参数都将是64位的值)。

WDK DDK

星期一, 7 6 月, 2010

WDK Windows Driver Kit

DDK Device Development Kit

编写驱动源码时,应采用.c文件编写。否则编译时会报错,找不到驱动入口函数DriverEntry(因为C++编译时会更改函数名)。如果采用.cpp文件编写,可使用extern “C”关键字解决上述问题。

驱动开发环境的配置

对Windows程序设计规范的建议

星期五, 12 2 月, 2010

变量名:通常采用所谓的“匈牙利命名法”,变量名由“类型缩写(小写)”+“变量描述(单词首字母大写)”构成,如字符串类型的变量可以命名为szFileName,DWORD类型的数据可以命名为dwFileSize,指针类型可以命名为lpBuffer,句柄类型的变量可以命名为hLogFile等。

函数名:各单词的首字母大写,如EnumerateFilesInDrectory、ShowFileSize等。

类型名:全大写,各单词以下划线分隔,如WIN32_FILE_ATTRIBUTE_DATA、DWORD、HANDLE等。

常量:同类型名的命名方式。

宏:多与类型名命名方式相同,有的也与函数名命名方式相同。

大括号与代码段:一般大括号独立占一行,大括号内的代码段缩进。如果代码段仅一行(如if-else后的语句),也建议使用大括号。

在调用或定义函数时,如果函数太长,可以分行写,将每个参数写一行。一般多于3个参数的函数需要分行写,以美观和方便阅读为原则。