

64bit Python から 32bit Python をコントロールしたいと思っています。  
単純に 64bit Python でコントロールできればいいのですが、コントロールしたい機器が 32bit しかサポートしておらず、またコントローラが
64bit版しかないという状態です。

**イメージ:**  
自動化ソフトウェア -- 64bit Python -- 32bit Python --> コントロールしたい機器

自動化したい機器は win32com でコントロール可能ですが 32bit のみのサポートです。32bit Python
からコントロールしたい機器は制御できています。

問題は、64bit Python から 32bit Python を実行 (subprocess) しているのですが、その際 32bit Python が
win32com を import するタイミングで 64bit Python の dll を参照してしまい、エラーとなっています。

**64bit からの実行**

[code]

    import subprocess
    
    py_path = r"C:\path\to\32bit\Python\python.exe"
    cmd = r"C:\users\py\command.py"
    proc = subprocess.Popen(
                [py_path, cmd],
                shell=True,
                stdin=subprocess.PIPE,
                stdout=open('out.txt', 'w'),
                stderr=open('err.txt', 'w'), 
                encoding='utf-8'
    )
    
[/code]

command.py

[code]

    import win32com.client
    ...
    
[/code]

上記を実行すると、command.py の import の時点で以下のエラーが表示され動作しません。

[code]

    Traceback (most recent call last):
      File "C:\\users\\py\\command.py", line 1, in <module>
        import win32com.client
      File "C:\Path\to\64bit\Python\lib\site-packages\win32com\__init__.py", line 5, in <module>
        import win32api, sys, os
    ImportError: DLL load failed while importing win32api: %1 is not a valid Win32 application.
    
[/code]

実際、command.py の方で sys.path を確認すると以下の通り 64bit 版を参照しに行っています。

[code]

    ['C:\\users\\py',
     'C:\\Path\\to\\32bit\\Python\\python38.zip',
     'C:\\Path\\to\\64bit\\Python\\DLLs',
     'C:\\Path\\to\\64bit\\Python\\lib',
     'C:\\Users\\user\\AppData\\Local\\Programs\\Python',
     'C:\\Path\\to\\64bit\\Python',
     'C:\\Path\\to\\64bit\\Python\\lib\\site-packages',
     'C:\\Path\\to\\64bit\\Python\\lib\\site-packages\\win32',
     'C:\\Path\\to\\64bit\\Python\\lib\\site-packages\\win32\\lib',
     'C:\\Path\\to\\64bit\\Python\\lib\\site-packages\\Pythonwin']
    
[/code]

そこで、command.py の方で sys.path.append() などを使い 32bit
版を優先的に見るようにしてみましたが、エラーに変化はありませんでした。  
また、command.py で sys.path を空 ([]) にして、32bit 版のパスだけを入れてみましたが今度は win32com
が見つからないとなってしまいました。

どうすればよいでしょうか?


CC BY-SA 4.0
2021-09-27T08:20:13.000
82716
2021-09-29T10:09:06.960
2021-09-27T11:30:24.280
3060
48380
question
python windows
python 64bit から 32bit をコントロールしたい (dll が 64bit 版を参照してしまう)


自己解決しましたので、自分なりの解決方法を書いておきます。

64bit Python を動かすアプリケーションでは、アプリケーション内で自動でいくつかの PATH が追加されるような動作が入っていたようで、それらの
PATH を消した上で subprocess の引数 env に 32bit 用の環境変数を作って渡すことで動作することが出来ました。

[code]

    import os
    new_env = os.environ.copy()
    
    delete_name = ['xxx', 'yyy'] # xxx, yyy はアプリケーションの名前
    add_path_list = [r'C:\path\to\32bit\python']
    new_env_dict = {
        'PYTHONHOME' : r'C"\path\to\32bit\python']
    }
    
    path_list = []
    for newpath in new_env ['PATH'].split(';'):
        flag = 0
        for target in delete_name:
            if target in newpath:
                flag = 1
    
            if flag == 0:
                path_list.append(mypath)
    
    for newpath in add_path_list:
        path_list.append(newpath)
    
    path_list = filter(lambda a: a != '', path_list)
    path_str = ";".join(path_list)
    new_env ['PATH'] = path_str
    
    for key, value in new_env_dict.items():
         new_env[key] = value
    
    
[/code]

として作成した new_env を subprocess の引数 env で渡します。

[code]

    import subprocess
    
    py_path = r"C:\path\to\32bit\Python\python.exe"
    cmd = r"C:\users\py\command.py"
    proc = subprocess.Popen(
                [py_path, cmd],
                shell=True,
                stdin=subprocess.PIPE,
                stdout=open('out.txt', 'w'),
                stderr=open('err.txt', 'w'), 
                encoding='utf-8',
                env=new_env,
    )
    
[/code]

以上で、64bit Python から 32bit Python を動作し、32bit dll を使った動作が出来ました。

なお上記環境変数設定で、実際にはアプリケーションで使用する Python のパスだけを  
削除すれば動作自体は可能でした。

ありがとうございました。


CC BY-SA 4.0
2021-09-29T10:09:06.960
82755
2021-09-29T10:09:06.960
48380
82716
answer