多线程操作CATIA出现跨线程封送接口调用错误求助
解决CATIA Python脚本跨线程COM接口封送错误
错误原因
COM对象具有线程亲和性:通过win32com.client获取的CATIA文档对象(如ActiveDocument)属于创建它的线程,无法直接在其他线程中进行比较或访问,否则会触发跨线程封送接口错误。你直接在两个不同线程中存储和比较COM对象document_new与document_old,就会导致这个问题。
解决方案
避免跨线程传递/操作COM对象,改用线程安全的文档唯一标识(如文件完整路径)来存储和对比:
- 用字符串类型存储文档的
FullName(完整路径),替代直接存储COM对象 - 在对比时,获取当前文档的路径字符串,与之前存储的字符串比较
- 使用类的实例变量替代全局变量,提升代码封装性
- 每个线程中调用
pythoncom.CoInitialize()后,要确保调用pythoncom.CoUninitialize()释放资源
修改后的代码示例
import os import win32com.client import numpy as np import pandas as pd import openpyxl import threading from tkinter import * from tkinter import ttk from tkinter import messagebox import pythoncom import psutil class STD_Check_compare(): def __init__(self): #Form self.root = Tk() self.root.geometry("700x200") self.root.title("STD Check") self.mainframe = ttk.Frame(self.root, padding="3 3 12 12") self.mainframe.grid(column=0, row=0, sticky=(N, W, E, S)) self.root.columnconfigure(0, weight=1) self.root.rowconfigure(0, weight=1) # 用实例变量存储文档路径,替代全局变量 self.document_new_path = None #========================================================================================================== def STD_Check(self): self.STD_Check_button["state"] = "disable" try: pythoncom.CoInitialize() Cat = win32com.client.Dispatch('catia.application') Cat.Visible = True Cat.DisplayFileAlerts = True # 存储文档完整路径,而非COM对象 active_doc = Cat.ActiveDocument self.document_new_path = active_doc.FullName self.progressbar_STDCheck.start() #Do something self.progressbar_STDCheck.stop() messagebox.showinfo("", "STD Check done for parameters. Excel created and stored in defined folder") finally: # 释放COM资源 pythoncom.CoUninitialize() self.STD_Check_button["state"] = "normal" def STD_Compare(self): self.STD_Compare_button["state"] = "disable" try: pythoncom.CoInitialize() Cat = win32com.client.Dispatch('catia.application') Cat.Visible = True Cat.DisplayFileAlerts = True active_doc = Cat.ActiveDocument document_old_path = active_doc.FullName # 对比文档路径字符串,而非COM对象 if self.document_new_path and document_old_path == self.document_new_path: messagebox.showinfo("", "You have selected same STD file. Select old STD to compare") self.STD_Compare_button["state"] = "normal" return self.progressbar_STDCompare.start() #do something self.progressbar_STDCompare.stop() messagebox.showinfo("", "STD Comparison done in DMU") finally: pythoncom.CoUninitialize() self.STD_Compare_button["state"] = "normal" def Thread_STD_Check(self): threading.Thread(target=self.STD_Check, daemon=True).start() def Thread_STD_Compare(self): threading.Thread(target=self.STD_Compare, daemon=True).start() #---------------Buttons, labels and Progress bars in Frame-------------------------- def display(self): self.Label_path = ttk.Label(self.mainframe, text="Enter path to store Excel files").grid(column=1, row=3, sticky=W) self.storepath = StringVar() self.path_entry = ttk.Entry(self.mainframe, width=50, textvariable = self.storepath) self.path_entry.grid(column=1, row=4, sticky=W) self.Label1 = ttk.Label(self.mainframe, text="Press submit button for STD Check").grid(column=1, row=7, sticky=W) self.STD_Check_button = ttk.Button(self.mainframe, text="Submit", command=self.Thread_STD_Check) self.STD_Check_button.grid(column=2, row=7, sticky=W) self.Label2 = ttk.Label(self.mainframe, text="Press submit button to compare STD").grid(column=1, row=10, sticky=W) self.STD_Compare_button = ttk.Button(self.mainframe, text="Submit", command=self.Thread_STD_Compare) self.STD_Compare_button.grid(column=2, row=10, sticky=W) self.progressbar_STDCheck = ttk.Progressbar(self.mainframe, style='text.Horizontal.TProgressbar', mode='indeterminate', length=150) self.progressbar_STDCheck.grid(column = 3, row = 7) self.progressbar_STDCompare = ttk.Progressbar(self.mainframe, style='text.Horizontal.TProgressbar', mode='indeterminate', length=150) self.progressbar_STDCompare.grid(column = 3, row = 10) self.root.mainloop() start = STD_Check_compare() start.display()
关键修改点
- 将全局变量
document_new替换为类实例变量self.document_new_path,存储文档的完整路径字符串 - 在
STD_Check中获取ActiveDocument.FullName而非直接存储COM对象 - 在
STD_Compare中对比两个文档的路径字符串,避免直接操作跨线程的COM对象 - 每个线程的COM操作放在
try...finally块中,确保调用pythoncom.CoUninitialize()释放资源
内容的提问来源于stack exchange,提问作者Ashish
相关产品推荐
相关产品推荐

