Windowsのファイルシステムリダイレクタにハマった話

Windows 7で日本語による音声合成がしたくて、WSHを使って WScript.CreateObject("Speech.SpVoice"); とやってそれを使うスクリプトを作った。

これをコマンドプロンプトから単体で起動すると問題なく動くが、Pythonからsubprocess.callで実行すると「オブジェクトを作成できませんでした。」というエラーになる。

コマンドプロンプトから起動したcscript.exeは64bitで、Pythonは32bitで、32bitプログラムから起動した場合SysWOW64下の32bit版のcscript.exeが起動し、32bit版は"Speech.SpVoice"をロードできないことが原因。出力メッセージ上32bit版と64bit版には差がないのでわかりにくい。

この挙動はWindowsファイルシステムリダイレクタによるもので、フルパスで64bit版を指定しても32bit版が起動する。

32 ビット アプリケーションで %windir%\System32 ディレクトリにアクセスしようとすると、アクセスが %windir%\SysWOW64 という新しいディレクトリにリダイレクトされます。

32 ビット アプリケーションでは、%windir%\System32 ディレクトリの代わりに %windir%\Sysnative ディレクトリを指定すると、ネイティブのシステム ディレクトリにアクセスできます。Sysnative は、ファイル システムでアクセスをリダイレクトしないことを示すために使用する特殊なエイリアスとして、WOW64 で認識されます。このメカニズムは柔軟で使いやすいので、ファイル システムのリダイレクトを回避する際の推奨メカニズムです。

ファイル システム リダイレクタ (Windows)

なので以下のように書くのが正解

subprocess.check_call([r"c:\windows\sysnative\cscript.exe", "yomiage.wsf", arg])