Python 2.6 の _winreg.ExpandEnvironmentStrings を ctypes で
Python 2.6 より _winreg モジュールに追加された ExpandEnvironmentStrings 関数。REG_EXPAND_SZ 型のレジストリ値のように % で囲まれた環境変数を展開するというもの。ソースコードを見ると PC/_winreg.c の 1159 行目からの PyExpandEnvironmentStrings 関数で実装されていた。 ExpandEnvironmentStringsW 関数を2度呼んでいる。ひとまず lpDst を NULL ポインタ、 nSize を 0 で呼び出しておいて得られる文字列長を事前確認、その長さ分のメモリ確保、再度実行という流れ。なるほどこうやって使うのか、と。コード読むのはホント、ためになる。
そして、意味も無く作ってみた。このくらいならば ctypes でも実装できそうな気がして。いや、 Python 2.3 以上で使えるのでまったくの無駄でもないか…。C コンパイラに頼らずともさくっと API アクセスできてしまう ctypes 。なんという Python 界ひきこもり用モジュール。いけない、 C, C++ もたまにはかかないと。
# coding: utf-8 from ctypes import windll, POINTER, WINFUNCTYPE from ctypes import c_wchar_p, create_unicode_buffer from ctypes.wintypes import DWORD __all__ = ['ExpandEnvironmentStrings'] LPCTSTR = LPTSTR = c_wchar_p _ExpandEnvironmentStringsW = WINFUNCTYPE(DWORD, LPCTSTR, LPTSTR, DWORD)( ('ExpandEnvironmentStringsW', windll.kernel32), ((1, 'lpSrc'), (1, 'lpDst'), (1, 'nSize'))) def _errcheck(result, func, args): if not result: raise WindowsError('ExpandEnvironmentStrings') return args _ExpandEnvironmentStringsW.errcheck = _errcheck def ExpandEnvironmentStrings(unicode): size = _ExpandEnvironmentStringsW(lpSrc=unicode, lpDst=None, nSize=0) dst = create_unicode_buffer(size) _ExpandEnvironmentStringsW(lpSrc=unicode, lpDst=dst, nSize=size) return dst.value def _test(): o = ExpandEnvironmentStrings(u'%Path%') print repr(o) if __name__ == '__main__': _test()
追記、そして、わざわざ ctypes を使わなくても正規表現と os.getenv の組み合わせで何とでもなってしまいそうだということに気づいたのは1日後のことでした。