You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多线程操作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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 07:50:28