首页 > 代码库 > windll对象
windll对象
回过头来,再看一下windll和oledll的区别,这两者之间最大的区别是oledll调用的函数都是固定返回HRESULT类型的值,而windll是不固定的类型的。在Python 3.3版本之前,都是返回命名为OSError类型错误,在这之后就返回命名为WindowsError类型错误。通一大段的讨论,我们彻底地了解cdll、windll和oledll之间的区别,为了更加清楚地记住它们,总结如下表所示:
表2-1:
对象名称 | 参数入栈顺序 | 清栈方式 | 返回值类型 |
cdll | 从右向左 | 调用者 | 不固定 |
windll | 从右向左 | 被调用者 | 不固定 |
oledll | 从右向左 | 被调用者 | WindowsError |
windll对象
调用WIN32的API函数,主要是通过windll对象来实现。那windll是何许人也?由于Python是开源的项目,我们很方便就定位到它的源码库里,查看它的实现方式,这样对于了解windll背后的秘密带来了极大的方便,如果是商业的项目就比较艰难了。在Milang或者Python的安装目录下,如下:
E:\Milang\python\Lib\ctypes
就可以找到ctypes库,这个库是通过包来发布的,因此在此目录下看到__init__.py文件,这个文件就是ctypes库导入时最初运行的文件,那么cdll、windll和oledll对象就是在这里创建的。与这里讨论相关的代码如下:
...
cdll = LibraryLoader(CDLL)
pydll = LibraryLoader(PyDLL)
if _os.name in ("nt", "ce"):
pythonapi = PyDLL("python dll", None, _sys.dllhandle)
elif _sys.platform == "cygwin":
pythonapi = PyDLL("libpython%d.%d.dll" % _sys.version_info[:2])
else:
pythonapi = PyDLL(None)
if _os.name in ("nt", "ce"):
windll = LibraryLoader(WinDLL)
oledll = LibraryLoader(OleDLL)
...
通过这段代码可以看到,windll是LibraryLoader类的实例,它是一个WinDLL类型的对象。LibraryLoader的主要功能就是实现动态库连接库的搜索、加载和重载运算符,让在Python里使用动态连接库更加方便。到这里就可以来看这句代码的具体意思了:
MessageBox = windll.user32.MessageBoxW
windll就是前面创建的动态连接库加载对象,user32是Windows提供的WIN32的API接口的动态连接库的名称(user32.dll),MessageBoxW是WIN32提供的弹出一个提示框的函数名称。在这行代码里,有意思的是并没有采用传送参数的方式来访问不同的动态连接库,而通过属性的方式(点号运行)来选择不同的动态连接库。在这里.user32就是表示访问动态连接user32.dll。像下面这行代码:
windll.kernel32.GetModuleHandleW(None)
就是表示访问动态连接库kernel32.dll,因此访问动态连接库gdi32.dll,就是变成这样:
windll.gdi32
通过点号运算就可以方便地加载不同的动态连接库,这是由于LibraryLoader类在后面进行点号运算符进行重载的结果。这样使用起来更方便和更清晰,比传送参数打更少的代码。在Windows里主要提供下面三个动态连接来对Windows的功能调用,如下:
kernel32.dll是Windows9x/Me中非常重要的32位动态链接库文件,属于内核级文件。它控制着系统的内存管理、数据的输入输出操作和中断处理,当Windows启动时,kernel32.dll就驻留在内存中特定的写保护区域,使别的程序无法占用这个内存区域。
user32.dll是Windows用户界面相关应用程序接口,用于包括Windows处理,基本用户界面等特性,如创建窗口和发送消息。
gdi32.dll是Windows GDI图形用户界面相关程序,包含的函数用来绘制图像和显示文字。
在这里有一点,你也许注意到了,当想调用MessageBox函数时,其实是写的名称是MessageBoxW,在后面多了一个W,这个W是什么用的呢?其实在WIN32的API里,提供了两套的API接口,一套是支持是UNICODE的API接口,一套是支持ANSI的API接口。说白了就是为了解决双字节和单字节的文字的显示问题。因此,要想使用ANSI单字的API接口,要使用MessageBoxA的名称。在我们编写C和C++程序时,只需要使用MessageBox就可以了,其实这是由于API在接口的头文件进行宏定义。在Python里没有必要进行这种魔幻的操作,让人更加明了,明白。