Pythonでctypesを使ってUNLHA32.dllを扱う

  • October 12, 2008 00:38

PythonでLhaを扱いたかったのだけど、ググッてもモジュールもなければ、ブログのエントリーもないので調査しました。

どうやらctypesを使うといいらしい。

ctypesも初めて使うのでいろいろ迷いましたが、割と簡単に使うことができるようです。

以下ソース

#! coding=sjis
from ctypes import windll, wintypes, Structure, c_char, byref
TEST_ARC = r'c:\temp\hogearchive1.lzh'

# INDIVIDUALINFO型の構造体を扱うためにStructureを継承したクラスを作る。_fields ではなく _fields_ なので注意
class INDIVIDUALINFO(Structure):
    _fields_ = [
            ('dwOriginalSize', wintypes.DWORD),
            ('dwCompressedSize', wintypes.DWORD),
            ('dwCRC', wintypes.DWORD),
            ('uFlag', wintypes.UINT),
            ('uOSType', wintypes.UINT),
            ('wRatio', wintypes.WORD),
            ('wDate', wintypes.WORD),
            ('wType', wintypes.WORD),
            ('szFileName', c_char * 513), #配列は * を使う
            ('dummy1', c_char * 3),
            ('szAttribute', c_char * 8),
            ('szMode', c_char * 8)
    ]
individualinfo = INDIVIDUALINFO()

#UNLHA.dllを扱うにはwindll.LoadLibraryを使う
openlha = windll.LoadLibrary('UNLHA32.dll')

#UnlhaOpenArchiveの引数を渡して、指定の書庫ファイルに対応したハンドルを受け取る
# 引数
#        _hwnd           UNLHA32.DLL を呼び出すアプリのウィンドウのハンドル。
#        _szFileName     書庫ファイル名。
#        _dwMode         UnlhaFindFirst() 等の処理のモード。
#

hdl = openlha.UnlhaOpenArchive(None, TEST_ARC, None)
if hdl:
    #OpenArchive系の関数はハンドルとINDIVIDUALINFO型の構造体のポインタを引数にとることが多いので最初に作ったINDIVIDUALINFOクラスのインスタンスをbyref関数でくるんで渡す。
    if openlha.UnlhaFindFirst(hdl, '*.*', byref(individualinfo)) == 0:
        while True:
            print individualinfo.szFileName
            if openlha.UnlhaFindNext(hdl, byref(individualinfo)) != 0:
                break

#close
openlha.UnlhaCloseArchive(hdl)

ちなみにINDIVIDUALINFO型の構造体は以下のようなもの

typedef struct {
       DWORD                   dwOriginalSize;         /* ファイルのサイズ */
       DWORD                   dwCompressedSize;       /* 圧縮後のサイズ */
       DWORD                   dwCRC;                          /* 格納ファイルのチェックサム */
       UINT                    uFlag;                          /* 処理結果 */
                                                                               /* Status flag */
       UINT                    uOSType;                        /* 書庫作成に使われた OS */
       WORD                    wRatio;                         /* 圧縮率 */
       WORD                    wDate;                          /* 格納ファイルの日付(DOS 形式) */
       WORD                    wTime;                          /* 格納ファイルの時刻(〃) */
       char                    szFileName[FNAME_MAX32 + 1];    /* 格納ファイル名 */
       char                    dummy1[3];
       char                    szAttribute[8];         /* 格納ファイルの属性(書庫固有) */
       char                    szMode[8];                      /* 格納ファイルの格納モード(〃) */
} NDIVIDUALINFOA, *LPINDIVIDUALINFOA;

実行結果は以下の通り

C:\temp>python unlha.py
/temp/hoge1/
/temp/hoge1/difflib.py
/temp/hoge1/difflib.pyc
/temp/hoge1/dircache.py
/temp/hoge1/dis.py
/temp/hoge1/dis.pyc
/temp/hoge1/doctest.py
/temp/hoge1/doctest.pyc
/temp/hoge1/DocXMLRPCServer.py

他の関数も同じようにして使うことが出来そうです。

ctypesはなかなかいいのではないでしょうか?

Pythonはzipを簡単に使えるので自分だけで使う分にはLhaは扱う必要ないです。