舜's profilela vie n'est pas PhotosBlogListsMore Tools Help
    August 29

    奇怪的梦之“任务管理器”

    昨晚的梦很神奇,整个过程如下:

    事件A,我在某处干某事。

    事件B,我在用某东西拍摄事件A中的我。

    事件C,起来喝水,并接着躺下继续睡。

    事件D,不明原因的无法入睡,于是,按了Ctrl+Shift+Esc打开任务管理器。发现里面显示进程A占用CPU 20%,10多个进程B,每个占用5%的CPU。"喔。。。原来刚才的梦还没完啊,删之"。继续做梦。

    事件E,"我刚才干了什么?""我不是在做梦吧?""怎么还有任务管理器?"。。。"我醒了没?"

    事件F,睁眼发现同宿舍的正要出门,感觉很饿,于是下楼吃饭。

    事件G,写下这篇。

    PS:想起好像有首歌叫"睁一只眼闭一只眼"

    August 28

    Ctypes: Unleash the power of Python

    如果你认为Python仅仅是一个脚本语言,那么在你看完本文后或许会有新的感慨:Woooo~,It's cool

    Ctypes module是提供Python直接调用C库函数的接口模块,有了它你可以像写C一样写Python,或者像写Python一样来写C。它提供了跟C兼容的数据类型,使得你可以直接调用dlls或者共享库导出的函数。下面大概介绍一下使用方法。

    1. 首先当然是 from ctypes import *
    2. 获取链接库:

      >>> print windll.kernel32 # doctest: +WINDOWS
      <WinDLL 'kernel32', handle ... at ...>

      >>> cdll.LoadLibrary("libc.so.6") # doctest: +LINUX
      <CDLL 'libc.so.6', handle ... at ...>

    3. 获得库函数:

      >>> libc.printf
      <_FuncPtr object at 0x...>
      >>> print windll.kernel32.GetModuleHandleA # doctest: +WINDOWS
      <_FuncPtr object at 0x...>

         

      注意:Windows下跟字符串相关的函数分ANSI和UNICODE版本:FuncNameA和FuncNameW。调用哪个需要你自己决定。

    4. 数据类型:

      >>> c_int()
      c_long(0)
      >>> c_char_p("Hello, World")
      c_char_p('Hello, World')
      >>> c_ushort(-3)
      c_ushort(65533)

         

      注意:内容将被更改的字符串指针应该用create_string_buffer来获得,如下:

      >>> p = create_string_buffer(3) # 3个字节长度,预置0x00
      >>> print sizeof(p), repr(p.raw)
      3 '\x00\x00\x00'
      >>> p = create_string_buffer("Hello") #用Hello来初始化
      >>> print sizeof(p), repr(p.raw) #内部表示
      6 'Hello\x00'
      >>> print repr(p.value) #值
      'Hello'
      >>> p = create_string_buffer("Hello", 10) # 同时指定初值和长度

      >>> print sizeof(p), repr(p.raw)
      10 'Hello\x00\x00\x00\x00\x00'
      >>> p.value = "Hi"
      >>> print sizeof(p), repr(p.raw)
      10 'Hi\x00lo\x00\x00\x00\x00\x00' # 获得新值,包含最后的0x00结尾

         

    5. 函数调用:

      >>> printf = cdll.msvcrt.printf
      >>> printf("Hello, %s\n", "World!")
      Hello, World!
      14
      >>> printf("Hello, %S", u"World!")
      Hello, World!
      13
      >>> printf("%d bottles of beer\n", 42)
      42 bottles of beer
      19

      >>>

         

      下面用一个具体例子来介绍:

      我的目标是(没有蛀牙!:)直接调用WIN32 API函数来移动桌面的某些窗口,此处涉及到传递callback 函数作为函数实参的例子。

    6. 首先定义callback函数类型:

      ENUMCHILDPROC = WINFUNCTYPE(c_int, c_int, c_int) # 表示一个 int FuncProc(int, int) 的C类型函数

    7. 定义要用到的一些常用结构:

      class RECT(Structure):

      _fields_ = [('left', c_long),

      ('top', c_long),

      ('right', c_long),

      ('bottom', c_long)]

      def __str__(self):

      return str((self.left, self.top, self.right, self.bottom))

         

      class POINT(Structure):

      _fields_ = [('x', c_long),

      ('y', c_long)]

      def __str__(self):

      return str((self.x, self.y))

    8. 定义实际执行的Callback函数

      def EnumChildProc(lhwnd, lParam):

      """return True, 继续枚举下一个窗口

      return False, 不再继续"""

      global wndlist

      pt = POINT()

      windll.user32.GetCursorPos(byref(pt))

         

      winclassname = create_string_buffer(255)

      windll.user32.GetClassNameA(lhWnd, winclassname,255)

      wintitlename = create_string_buffer(255)

      windll.user32.GetWindowTextA(lhWnd, wintitlename, 255)

      rect = RECT()

      windll.user32.GetWindowRect(lhWnd, byref(rect))

         

      if wndlist.has_key(winclassname.value):

      wndlist[winclassname.value].append((wintitlename.value, str(rect)))

      else:

      wndlist[winclassname.value] = [(wintitlename.value, str(rect))]

         

      if len(winclassname.value)==0 or len(wintitlename.value)==0:

      return True # 跳过那些"非实体"window

         

      # 根据class name决定是否要移动

      if winclassname.value=='TkTopLevel' and wintitlename.value.find('.py')!=-1:

      windll.user32.MoveWindow(hwnd, pt.x, pt.y, rect.right-rect.left, rect.bottom-rect.top, True)

      print '%s moved to under cursor. (%s)'%(wintitlename.value,winclassname.value)

      return True

    9. 最后,开始启动找窗口:

      wndlist = {}

      enumchildprc = ENUMCHILDPROC(EnumChildProc) # 保持一个对callback的引用,防止被回收

      tophwnd = windll.user32.GetDesktopWindow()

      windll.user32.EnumChildWindows(tophwnd, enumchildprc, c_int(-1))

         

      更多文档参见:

    • The tutorial and the reference as one single HTML page each.
    • Single HTML pages from the official Python 2.5 documentation.

         

      源文档 <http://starship.python.net/crew/theller/ctypes/>

         

      提示:ctypes在Windows, Mac OS X, Linux, Solaris, FreeBSD, OpenBSD下均可以使用,而且Python 2.5已经有ctypes默认安装。