4

Python から Excel へのマーシャリングされたクロスプロセス呼び出しを行うことができるように、誰かが私を助けてくれることを願っています。

別の Python プロセスからアクセスする必要があるときに、Python を介して開始された Excel セッションが起動して実行されることがわかっています。マーシャリングとpythoncomモジュールからの呼び出しを使用して、すべてがCoMarshalInterfaceInStream()必要CoGetInterfaceAndReleaseStream()に応じて機能していますが、ストリームへの繰り返しアクセスが必要であり(私の場合は1回しか設定できません)、CoGetInterfaceAndReleaseStream()インターフェースへの1回だけのアクセスを許可します。

私が達成したいことは で実行できると信じていますがCreateStreamOnHGlobal()、正しいパラメーターを渡していないため、ほぼ確実に機能させることができません。CoMarshalInterface()CoUnmarshalInterface()

私の主なシナリオを詳細に説明するのではなく、簡単なサンプル プログラムを次のように設定しました。明らかに、これは同じプロセスで行われますが、一度に 1 ステップずつ行われます。次のスニペットは正常に機能します。

import win32com.client
import pythoncom

excelApp = win32com.client.DispatchEx("Excel.Application")

marshalledExcelApp = pythoncom.CoMarshalInterThreadInterfaceInStream(pythoncom.IID_IDispatch, excelApp)

xlApp = win32com.client.Dispatch(
                                pythoncom.CoGetInterfaceAndReleaseStream(marshalledExcelApp, pythoncom.IID_IDispatch))

xlWb = xlApp.Workbooks.Add()
xlWs = xlWb.Worksheets.Add()
xlWs.Range("A1").Value = "AAA"

ただし、次のことを試すと:

import win32com.client
import pythoncom

excelApp = win32com.client.DispatchEx("Excel.Application")

myStream = pythoncom.CreateStreamOnHGlobal()                                   
pythoncom.CoMarshalInterface(myStream,
                             pythoncom.IID_IDispatch,
                             excelApp,
                             pythoncom.MSHCTX_LOCAL,
                             pythoncom.MSHLFLAGS_TABLESTRONG)   

myUnmarshaledInterface = pythoncom.CoUnmarshalInterface(myStream, pythoncom.IID_IDispatch)

への呼び出しを行うときに、このエラーが発生します(これは3番目のパラメーターに関連していると思います)pythoncom.CoMarshalInterface()

"ValueError: argument is not a COM object (got type=instance)"

この簡単な例を機能させる方法を知っている人はいますか?

前もって感謝します

4

1 に答える 1

10

多くの不安の末、私は直面していた問題を解決することができました。実際、その後の問題についても説明します。

まず、最初の問題は pythoncom.CoMarshalInterface() への呼び出しの 3 番目のパラメーターにあると推測して正解でした。実際、excelApp 変数のoleobjプロパティを参照する必要がありました。

pythoncom.CoMarshalInterface(myStream, 
                             pythoncom.IID_IDispatch, 
                             excelApp._oleobj_, 
                             pythoncom.MSHCTX_LOCAL, 
                             pythoncom.MSHLFLAGS_TABLESTRONG)

ただし、今度は pythoncom.CoUnmarshalInterface() の呼び出しで、別のエラー メッセージに直面しました。

com_error: (-2147287010, 'A disk error occurred during a read operation.', None, None)

これは、使用前に Seek() メソッドを使用してストリーム ポインターをリセットする必要があるためであることが判明しました。

myStream.Seek(0,0) 

最後に、ほとんどの部分は正しく機能していましたが、マーシャリングされた Excel オブジェクトで Quit() を使用し、コードの終了前にすべての変数を明示的に None に設定したにもかかわらず、ゾンビの Excel プロセスが残っていることがわかりました。これは、pythoncom._GetInterfaceCount() が 0 を返しているにもかかわらずでした。

CoReleaseMarshalData() を呼び出して、作成したストリームを明示的に空にする必要があることがわかりました (最初にストリーム ポインターを再度リセットしました)。したがって、サンプル コード スニペット全体は次のようになります。

import win32com.client
import pythoncom

pythoncom.CoInitialize()

excelApp = win32com.client.DispatchEx("Excel.Application")

myStream = pythoncom.CreateStreamOnHGlobal()    
pythoncom.CoMarshalInterface(myStream, 
                             pythoncom.IID_IDispatch, 
                             excelApp._oleobj_, 
                             pythoncom.MSHCTX_LOCAL, 
                             pythoncom.MSHLFLAGS_TABLESTRONG)    

excelApp = None

myStream.Seek(0,0)
myUnmarshaledInterface = pythoncom.CoUnmarshalInterface(myStream, pythoncom.IID_IDispatch)    
unmarshalledExcelApp = win32com.client.Dispatch(myUnmarshaledInterface)

# Do some stuff in Excel in order to prove that marshalling has worked. 
unmarshalledExcelApp.Visible = True
xlWbs = unmarshalledExcelApp.Workbooks
xlWb = xlWbs.Add()
xlWss = xlWb.Worksheets
xlWs = xlWss.Add()
xlRange = xlWs.Range("A1")
xlRange.Value = "AAA"
unmarshalledExcelApp.Quit()    

# Clear the stream now that we have finished
myStream.Seek(0,0)
pythoncom.CoReleaseMarshalData(myStream)

xlRange = None
xlWs = None
xlWss = None
xlWb = None
xlWbs = None
myUnmarshaledInterface = None
unmarshalledExcelApp = None
myStream = None

pythoncom.CoUninitialize()

これが、私が直面した障害を克服するために他の誰かに役立つことを願っています!

于 2014-04-11T13:28:23.000 に答える