首页 > 代码库 > windll对象

windll对象

回过头来,再看一下windlloledll的区别,这两者之间最大的区别是oledll调用的函数都是固定返回HRESULT类型的值,而windll是不固定的类型的。在Python 3.3版本之前,都是返回命名为OSError类型错误,在这之后就返回命名为WindowsError类型错误。通一大段的讨论,我们彻底地了解cdllwindlloledll之间的区别,为了更加清楚地记住它们,总结如下表所示:

2-1

对象名称

参数入栈顺序

清栈方式

返回值类型

cdll

从右向左

调用者

不固定

windll

从右向左

被调用者

不固定

oledll

从右向左

被调用者

WindowsError

 

windll对象

调用WIN32API函数,主要是通过windll对象来实现。那windll是何许人也?由于Python是开源的项目,我们很方便就定位到它的源码库里,查看它的实现方式,这样对于了解windll背后的秘密带来了极大的方便,如果是商业的项目就比较艰难了。在Milang或者Python的安装目录下,如下:

E:\Milang\python\Lib\ctypes

就可以找到ctypes库,这个库是通过包来发布的,因此在此目录下看到__init__.py文件,这个文件就是ctypes库导入时最初运行的文件,那么cdllwindlloledll对象就是在这里创建的。与这里讨论相关的代码如下:

...

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)

...

通过这段代码可以看到,windllLibraryLoader类的实例,它是一个WinDLL类型的对象。LibraryLoader的主要功能就是实现动态库连接库的搜索、加载和重载运算符,让在Python里使用动态连接库更加方便。到这里就可以来看这句代码的具体意思了:

MessageBox = windll.user32.MessageBoxW

windll就是前面创建的动态连接库加载对象,user32Windows提供的WIN32API接口的动态连接库的名称(user32.dll),MessageBoxWWIN32提供的弹出一个提示框的函数名称。在这行代码里,有意思的是并没有采用传送参数的方式来访问不同的动态连接库,而通过属性的方式(点号运行)来选择不同的动态连接库。在这里.user32就是表示访问动态连接user32.dll。像下面这行代码:

windll.kernel32.GetModuleHandleW(None)

就是表示访问动态连接库kernel32.dll,因此访问动态连接库gdi32.dll,就是变成这样:

windll.gdi32

通过点号运算就可以方便地加载不同的动态连接库,这是由于LibraryLoader类在后面进行点号运算符进行重载的结果。这样使用起来更方便和更清晰,比传送参数打更少的代码。在Windows里主要提供下面三个动态连接来对Windows的功能调用,如下:

kernel32.dllWindows9x/Me中非常重要的32位动态链接库文件,属于内核级文件。它控制着系统的内存管理、数据的输入输出操作和中断处理,当Windows启动时,kernel32.dll就驻留在内存中特定的写保护区域,使别的程序无法占用这个内存区域。

user32.dllWindows用户界面相关应用程序接口,用于包括Windows处理,基本用户界面等特性,如创建窗口和发送消息。

gdi32.dllWindows GDI图形用户界面相关程序,包含的函数用来绘制图像和显示文字。

在这里有一点,你也许注意到了,当想调用MessageBox函数时,其实是写的名称是MessageBoxW,在后面多了一个W,这个W是什么用的呢?其实在WIN32API里,提供了两套的API接口,一套是支持是UNICODEAPI接口,一套是支持ANSIAPI接口。说白了就是为了解决双字节和单字节的文字的显示问题。因此,要想使用ANSI单字的API接口,要使用MessageBoxA的名称。在我们编写CC++程序时,只需要使用MessageBox就可以了,其实这是由于API在接口的头文件进行宏定义。在Python里没有必要进行这种魔幻的操作,让人更加明了,明白。