kst*_*tis 2 python winapi pywin32 win32com python-multithreading
所以,我有以下代码片段,它试图通过 win32api 启动 Microsoft Powerpoint:
import threading
import win32com.client
import sys
class myDemo(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
try:
myObject = win32com.client.Dispatch("Powerpoint.Application")
print "OK"
except:
print "Failed to start Powerpoint!"
sys.exit(1)
print "Now attempting to shutdown..."
try:
myObject.quit()
except:
print "Error"
if __name__ == "__main__":
test = myDemo()
test.start()
Run Code Online (Sandbox Code Playgroud)
问题是它失败了,我不知道为什么。但是,如果我将最后一行更改为test.run()它将成功启动。那么,为什么这会失败test.start()?
为什么会发生这种情况,考虑到我需要 Powerpoint 在单独的线程上异步运行,我应该如何解决它?
提前致谢。
编辑:显然我的问题与此有关:http : //python.6.x6.nabble.com/Dispatch-error-CoInitialize-has-not-been- called-td1951088.html
然而,除了提出的正确解决方案之外,似乎没有人回答为什么 COM 会以这种方式行事。
由于 COM 和线程的复杂性以及它们的工作方式,恐怕您的问题可能无法用一两句话来概括。但对于初学者来说,这里有一些很好的信息,说明 COM 在线程下的行为方式:
http://msdn.microsoft.com/en-us/library/ms809971.aspx
Run Code Online (Sandbox Code Playgroud)
此外,您应该考虑查看Python Programming on Win32一书。它包含有用的信息,可以更深入地了解 COM 线程。(尽管它已经很老了,但它仍然很有用。)
最后,如果从您提供的参考中不清楚,无论何时您的程序使用线程和 COM,您都必须在代码中指明您将在线程中使用 COM:
import pythoncom
import win32com.client
### ... inside the thread function ...
x = win32com.client.Dispatch("someCOMobject")
win32com.CoInitialize()
# com calls here
win32com.CoUninitialize()
Run Code Online (Sandbox Code Playgroud)
这种类型的调用使用所谓的单单元线程。它发生在线程代码本身实例化 COM 对象时。
如果您发现自己在线程代码之外实例化单个 COM 对象(并在线程代码中使用实例化对象,例如在线程之间传递对 COM 对象的访问权限),则这种类型的 COM 线程称为多线程单元线程:
import sys
sys.coinit_flags = 0
import pythoncom
import win32com.client
# ... outside the thread function ...
x = win32com.client.Dispatch("someCOMobject")
# ... inside the thread function ...
pythoncom.CoInitialize(pythoncom.COINIT_MULTITHREADED)
# com calls here for x
pythoncom.CoUninitialize()
Run Code Online (Sandbox Code Playgroud)
希望这可以帮助。