使用pythoncom在Python进程之间封送COM对象 [英] Marshaling COM objects between Python processes using pythoncom

查看:200
本文介绍了使用pythoncom在Python进程之间封送COM对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望有人能够帮助我从Python向Excel进行复杂的跨进程调用。

I'm hoping someone can help me with being able to make a marshaled cross-process call into Excel from Python.

我有一个通过Python启动的Excel会话我知道当需要从单独的Python进程访问它时,它将启动并运行。使用pythoncom模块中的 CoMarshalInterfaceInStream() CoGetInterfaceAndReleaseStream()进行封送处理,我已经可以按需工作我需要重复访问该流(在我的情况下只能设置一次),并且 CoGetInterfaceAndReleaseStream()允许仅一次访问该接口。

I have an Excel session initiated via Python that I know will be up and running when it needs to be accessed from a separate Python process. I have got everything working as desired using marshaling with CoMarshalInterfaceInStream() and CoGetInterfaceAndReleaseStream() calls from the pythoncom module, but I need repeat access to the stream (which I can only set up once in my case), and CoGetInterfaceAndReleaseStream() allows once-only access to the interface.

我相信我想实现的目标可以使用 CreateStreamOnHGlobal() CoMarshalInterface() CoUnmarshalInterface(),但由于我没有传递正确的参数,因此几乎无法使它正常工作。

I believe that what I would like to achieve can be done with CreateStreamOnHGlobal(), CoMarshalInterface() and CoUnmarshalInterface() but am unable to get it working, almost certainly because I am not passing in the correct parameters.

我没有详细描述我的主要情况,而是建立了一个简单的示例程序,如下所示-显然,这是在相同的过程中进行的,但一次仅一步!以下代码段可以正常工作:

Rather than describe in detail my main scenario, I have set up a simple example program as follows - obviously this takes place in the same process but one step at a time! The following snippet works fine:

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"

但是,当我尝试以下操作时:

However, when I try the following:

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)

调用 pythoncom.CoMarshalInterface()时出现此错误(我想这与第三个参数有关)

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

有人知道我如何使这个简单的示例正常工作吗?

Does anyone know how I can get this simple example working?

预先感谢

推荐答案

经过一番焦虑,我设法解决了我所面临的问题,以及后来遇到的问题。我还将描述。

After much angst, I have managed to resolve the issue I was facing, and indeed subsequent ones which I will also describe.

首先,我猜对了我的最初问题是调用pythoncom.CoMarshalInterface()的第三个参数是正确的。实际上,我应该一直引用excelApp变量的 oleobj 属性:

First, I was correct in guessing that my initial problem was with the 3rd parameter in the call to pythoncom.CoMarshalInterface(). In fact, I should have been making a reference to the oleobj property of my excelApp variable:

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

但是,这次我在调用pythoncom.CoUnmarshalInterface()时遇到了另一条错误消息:

However, I then faced a different error message, this time in the call to pythoncom.CoUnmarshalInterface():

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

事实证明,这是由于流指针需要在使用之前通过Seek()方法进行重置的原因:

It turned out that this was due to the fact that the stream pointer needs to be reset prior to use, with the Seek() method:

myStream.Seek(0,0) 

最后,尽管大多数方面都可以正常工作,但我发现尽管在在代码末尾之前,如果将Excel对象编组并明确将所有变量设置为None,那么我将面临僵尸Excel进程。尽管事实是pythoncom._GetInterfaceCount()返回0。

Finally, although most aspects were working correctly, I found that despite using Quit() on the marshalled Excel object and explicitly setting all variables to None prior to the end of the code, I was left with a zombie Excel process. This was despite the fact that pythoncom._GetInterfaceCount() was returning 0.

事实证明,我必须显式清空通过调用CoReleaseMarshalData()创建的流)(首先必须重新设置流指针)。因此,整个示例代码段如下所示:

It turns out that I had to explicitly empty the stream I had created with a call to CoReleaseMarshalData() (having first reset the stream pointer again). So, the example code snippet in its entirety looks like this:

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()

我希望这可以帮助其他人克服我所遇到的障碍!

I hope that this helps someone else out there to overcome the obstacles I faced!

这篇关于使用pythoncom在Python进程之间封送COM对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆