当用 Python ctypes 模块调用动态链接库,如何传入一个结构体指针

最近用 dv2xvid 这个东东很多,上两周几乎每天都用它跑一个晚上压缩2个小时的视频。于是又萌发了把它改进得更通用的念头。

目前 dv2xvid 有一个很严重的问题,就是只支持 xvid-1.1.0-beta2 的压缩。而事实上目前大家用的最多的是应该都是正式版本,比如 1.0.3 或者 1.1.0 之类。如果想能支持更多版本的 xvid codec,就必须能在压缩之前判断 xvid 的版本。

恶心的是安装的 xvid 的目标文件没有 Windows Dll 的版本属性,查了半天,调用 xvidcore.dll 里面的一个函数可以获得 xvidcore.dll 的版本号

  1. #include "xvid.h"
  2.  
  3. {
  4.   xvid_gbl_info_t info;
  5.   HINSTANCE m_hdll;
  6.  
  7.   memset(&info, 0, sizeof(info));
  8.   info.version = XVID_VERSION;
  9.   m_hdll = LoadLibrary(XVID_DLL_NAME);
  10.   if (m_hdll != NULL) {
  11.     ((int (__cdecl *)(void *, int, void *, void*))
  12. GetProcAddress(m_hdll, "xvid_global"))(0, XVID_GBL_INFO, &info, NULL);
  13.    
  14.    printf("xvidcore.dll version %d.%d.%d (\"%s\")",
  15.                 XVID_VERSION_MAJOR(info.actual_version),
  16.                 XVID_VERSION_MINOR(info.actual_version),
  17.                 XVID_VERSION_PATCH(info.actual_version),
  18.                 info.build);
  19.  
  20.     FreeLibrary(m_hdll);
  21.   } else {
  22.     printf("xvidcore.dll not found!");
  23.   }
  24. }

如果在 python 里面做到这个事情,可以通过 ctypes 模块来完成。但查遍 ctypes 有关的中文文档,都没有关于怎样在函数中传入结构体指针的说明,只能自己 google 之,后来发现应该这么来做:

  1. from ctypes import *
  2.  
  3. ### 定义结构体
  4. class xvid_gbl_info_t(Structure):
  5.     _fields_ = [("version", c_int),
  6.                 ("actual_version", c_int),
  7.                 ("build", c_char_p),
  8.                 ("cpu_flags", c_uint),
  9.                 ("num_threads", c_int)]
  10.  
  11. XVID_GBL_INFO = 1
  12.  
  13. dll = cdll.load("c:\\windows\\system32\\xvidcore.dll")
  14. xvid_global = dll.xvid_global
  15.  
  16. ### 构造 pinfo 结构体, 然后赋值
  17. pinfo = xvid_gbl_info_t()
  18. pinfo.version = ((((1)&0xff)<<16) | (((0)&0xff)<<8) | ((0)&0xff))
  19.  
  20. x = c_voidp(0)
  21. y = c_voidp(0)
  22. ### 用 byref 传入指针
  23. if xvid_global(x, c_int(XVID_GBL_INFO), byref(pinfo), y) == 0:
  24.     major_version = (pinfo.actual_version>>16)&0xff
  25.     minor_version = (pinfo.actual_version>>8)&0xff
  26.     patch_version = (pinfo.actual_version>>0)&0xff
  27.     print major_version, minor_version, patch_version
  28.     print pinfo.build
  29.     print pinfo.cpu_flags
  30.     print pinfo.num_threads
  31. else:
  32.     print "ERROR"

另:最近一周: qyt 完成了 blog 搬家, www.dup2.org 已经通过 ICP 备案. Logo 和 favicon 也正在热情实施中...(不得不承认我弟比我有美术天赋)

Topic: 技术

评论

Get a DLL's Version Number

Introduction

What is the version number of a DLL? This is the "File Version" you get if you open up a DLL's properties and go to the Version tab. The code here only gets the version shown at the top of that tab (on Win2K, anyway). You can use the slightly more messy language-dependent code in the demos which come with pywin32 to find the strings in the box beneath it.

from win32api import GetFileVersionInfo, LOWORD, HIWORD

def get_version_number (filename):
info = GetFileVersionInfo (filename, "\\")
ms = info['FileVersionMS']
ls = info['FileVersionLS']

return HIWORD (ms), LOWORD (ms), HIWORD (ls), LOWORD (ls)

if __name__ == '__main__':
import os
filename = os.environ["COMSPEC"]

print ".".join ([str (i) for i in get_version_number (filename)])

谢谢你提供的方法。

不过对 xvid 的 dll 可能不适用,因为在右键属性菜单里面,是看不到它的版本号的。

怎么被你搞的这么复杂

本来很简单的东西,看你的例子都看晕了。

写的太差了