このブログの更新は Twitterアカウント @m_hiyama で通知されます。
Follow @m_hiyama

メールでのご連絡は hiyama{at}chimaira{dot}org まで。

はじめてのメールはスパムと判定されることがあります。最初は、信頼されているドメインから差し障りのない文面を送っていただけると、スパムと判定されにくいと思います。

参照用 記事

Pythonから呼ぶWin32 APIがうまく動かない件

pyreadline-1.7.1に入れ替えたら、それまで動いていたWin32を呼ぶクリアスクリーンが動かなくなってしまった、という現象がありまして、その理由がわかりませんでした。にわか仕込みでデバッガ(pdb)を使ったりしましたがヤッパリわからない。

結局、次のエラーメッセージのとおりだったんですね。


File "./lib/win32cls.py", line 67, in clear_screen
coord, byref(dwDummy))
ArgumentError: argument 4: : wrong type

File "./lib/win32cls.py", line 67 は次のようなコード。

    FillConsoleOutputAttribute (hConOut, csbi.wAttributes, 
                                csbi.dwSize.X * csbi.dwSize.Y, 
                                coord, byref(dwDummy))

FillConsoleOutputAttribute関数の第4引数(argument 4)は、coordですが、このcoordが実際に wrong type だったようです。X,Y座標を含むデータであるcoordの初期化は次のとおり。

  coord = COORD() # 初期値 coord.X = 0, coord.Y = 0

COORDは、もともとはC言語の構造体ですが、それをPythonクラスとして定義しています。

class COORD(Structure):
  """struct in wincon.h."""
  _fields_ = [
    ("X", SHORT),
    ("Y", SHORT)]

このCOORD型データがWin32 API関数にうまく渡らないようです。それに気付いたのは、pyreadlineのconsole.pyのなかにfixcoordという関数を見つけたからです。必要な部分だけを抜き書きすると:

# pyreadline-1.7.1/pyreadline/console/cosole.py
#
#       Copyright (C) 2003-2006 Gary Bishop.
#       Copyright (C) 2006  Jorgen Stenarson. <jorgen.stenarson@bostream.nu>
#
#  Distributed under the terms of the BSD License.


def fixcoord(x, y):
    u'''Return a long with x and y packed inside.'''
    
    # this is a hack! ctypes won't pass structures but COORD is 
    # just like a long, so this works.
    return c_int(y << 16 | x)

座標を作るときは、例えば COORD(2, 3) の代わりに fixcoord(2, 3) とします。そうするとエラーはなくなります。

しかし不思議なのは、以前pyreadline-1.5と併用していたときはfixcoordなしで動いていたことです。pyreadline-1.5がWindows APIをフックするようなことは考えにくいし、pyreadline-1.5自体も逐一fixcoordしています。ウーン謎だ。