OleInitialize 运行失败的问题

本文记述了作者在调试DIALOG使用DoModal时遇到的问题及解决过程。问题源于使用了多线程的CoInitializeEx,导致OleInitialize失败。通过仔细检查引入的DLL和LIB文件,在一个LIB的构造函数中找到了原因,并通过调整初始化顺序解决了问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天在改了几千行代码后终于可以调试一下了,发现一个奇怪的问题,我的DIALOG在DoModal的时候不成功,用2003试,不行,2008试也不行,新建工程只加控件,没问题,没办法了,满头问号的只好跟代码了,我在DoModal里一路下来,跟到AfxOleInit中的OleInitialize,发现OleInitialize不成功,MSDN了一下,说我用了多线程的 CoInitializeEx,最开始怀疑是写的控件里,搜遍只找到 CoInitialize,又在程序里找,未果。只好把加进来的DLL,LIB都打开,终于在一个LIB的构造函数中发现因为要用XML写的 CoInitializeEx,不能放在构造函数里了,加了个调用。多改了几十行代码,经过5分钟的重新编译,按下F5,可算见着可爱的DIALOG出现了。时间啊,为了找这么个问题用了3个小时。。。。。。。

 

我有一个获取窗口控件填入条码的程序,在我写完controller.py后程序运行会报错,我把代码文件张贴在下面你帮我分析一下QWindowsContext: OleInitialize() failed: "COM error 0x80010106: 執行緒模式設定後就不能再變更它。" qt.qpa.window: SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) failed: COM error 0x5: 存取被拒。 Qt's default DPI awareness context is DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2. If you know what you are doing you can overwrite this default using qt.conf (https://doc.qt.io/qt-6/highdpi.html#configuring-windows) Failed to initialize COM library (執行緒模式設定後就不能再變更它。) main.py from PySide6.QtWidgets import QApplication from auto_fill_window import Auto_Fill_Barcode import sys import ctypes def main(): app = QApplication(sys.argv) #QApplication 管理GUI应用程序生命周期 window = Auto_Fill_Barcode() #创建窗口 window.show() #使窗口可见 sys.exit(app.exec()) #启动QT事件循环,监听用户与界面的交互 if __name__=="__main__": main() ui.py from PySide6 import QtWidgets from getBarcode_ui import Ui_Form from logger import Logger from PySide6.QtWidgets import QFileDialog from config_load import config_load #从.py中导入要先from from controller import Controller,Worker class Auto_Fill_Barcode(QtWidgets.QMainWindow,Ui_Form): def __init__(self): super().__init__() self.setupUi(self) self.log_text = self.plainTextEdit self.config = None self.controller = None self.flag = 'idle' self.logger = Logger(text_edit=self.log_text) self.update_from_ui("等待加载配置文件","black") self.update_ui_state('idle') #事件绑定 self.pushButton.clicked.connect(self.load_config_file) self.pushButton_2.clicked.connect(self.start_stop) def update_from_ui(self,str,color): self.label_13.setText(f"{str}") self.label_13.setStyleSheet(f"color: {color};") def ini_controller(self): self.controller = Controller(self.config) self.controller.log_send.connect(self.log_send) self.controller.finished.connect(self.handle_finished) def handle_finished(self): self.logger.info("正在停止程序,线程资源已释放...") self.update_from_ui("等待启动","black") self.update_ui_state('idle') self.flag = 'idle' def log_send(self,log): self.logger.info(log) def start_stop(self): if not self.config: self.logger.info("请先加载配置文件") return if self.flag=='idle': self.controller.start() self.logger.info("程序启动...") self.update_from_ui("运行中","green") self.update_ui_state('running') self.flag = 'running' else: self.controller.stop() self.logger.info("正在停止程序...") def update_ui_state(self,state:str): self.pushButton_2.setText('启动' if state != 'running' else '停止') def load_config_file(self): file_path,_ = QFileDialog.getOpenFileName(self, "选择配置文件", "", "配置文件 (*.ini)") if not file_path: return try: self.config = config_load(file_path) self.lineEdit.setText(file_path) self.label_2.setText(f"{self.config['TimeSettings']['WAIT_MEDIUM']}") self.label_6.setText(f"{self.config['TimeSettings']['WAIT_LONG']}") self.label_12.setText(f"{self.config['TimeSettings']['BARCODE_ALERT_COUNT']}") self.logger.info("配置文件加载成功") self.update_from_ui("等待启动","black") #初始化controller self.ini_controller() except Exception as e: self.logger.error(f"加载配置失败:{e}") def closeEvent(self,event): '''关闭窗口时停止任务''' if self.controller is not None and self.controller.is_running(): self.controller.stop() event.accept() controller.py from PySide6.QtCore import QObject,QThread,Signal import time import json import random import psutil from pywinauto import Application from pywinauto.findwindows import ElementNotFoundError, find_elements from pywinauto.timings import TimeoutError, wait_until from pywinauto.base_wrapper import ElementNotEnabled class Worker(QObject): #使用Object为了使用信号槽机制 finished = Signal() #任务完成 log_send = Signal(str) #转发日志 def __init__(self,config): super().__init__() self._running = True self.config = config self.alert_count = 0 self.TARGET_WINDOW_TITLE = "请扫描或输入条码" self.WAIT_PERFORMANCE = int(self.config['TimeSettings']['WAIT_PERFORMANCE']) self.WAIT_MEDIUM = int(self.config['TimeSettings']['WAIT_MEDIUM']) self.WAIT_LONG = int(self.config['TimeSettings']['WAIT_LONG']) self.BARCODE_ALERT_COUNT = int(self.config['TimeSettings']['BARCODE_ALERT_COUNT']) def run(self): #填条码任务 while self._running: try: # 性能检查 cpu_percent = psutil.cpu_percent(interval=0.1) mem_percent = psutil.virtual_memory().percent if cpu_percent > 80 or mem_percent > 70: QThread.sleep(self.WAIT_PERFORMANCE) continue # 查找窗口 windows = find_elements(visible_only=True) found_window = None for win in windows: if win.name == self.TARGET_WINDOW_TITLE: found_window = win break if not found_window: QThread.sleep(self.WAIT_LONG) continue handle = found_window.handle # 连接窗口 app = Application(backend="uia").connect(handle=handle) dialog = app.window(handle=handle) # 使用标签定位两个输入框 edit1, edit2 = self.find_edit_boxes_by_labels(self,dialog) if not edit1 or not edit2: self.log_send.emit("无法定位输入框,跳过本次循环") self.alert_count = 0 QThread.sleep(self.WAIT_LONG) continue # 查找确定按钮 confirm_btn = dialog.child_window(title="确定", control_type="Button") # 第一次检查输入框是否为空 val1 = edit1.get_value().strip() val2 = edit2.get_value().strip() if val1 or val2: self.log_send.emit("检测到条码已录入,跳过填充") self.alert_count =0 QThread.sleep(self.WAIT_LONG) continue self.log_send.emit("检测到条码框为空,等待2秒后再次确认") QThread.sleep(self.WAIT_MEDIUM) # 再次检查窗口是否存在 if not self.is_window_valid(handle): self.log_send.emit("窗口已关闭,跳过填充") self.alert_count = 0 continue # 再次检查输入框是否为空 val1 = edit1.get_value().strip() val2 = edit2.get_value().strip() if val1 or val2: self.log_send.emit("检测到条码已录入,跳过填充") self.alert_count = 0 continue # 开始填充 barcode1 = self.generate_simulated_barcode() barcode2 = self.generate_simulated_barcode() edit1.set_text(barcode1) edit2.set_text(barcode2) # 等待按钮可用 for _ in range(5): if confirm_btn.is_enabled(): break QThread.msleep(500) confirm_btn.click() self.log_send.emit(f"已自动填充条码: {barcode1}, {barcode2}") self.alert_count = self.alert_count+1 if(self.alert_count>=5): self._running = False QThread.msleep(500) # 给窗口关闭一点时间 except (ElementNotFoundError, TimeoutError) as e: self.log_send.emit(f"查找控件失败: {str(e)}") QThread.sleep(self.WAIT_LONG) except ElementNotEnabled as e: self.log_send.emit(f"控件不可操作: {str(e)}") QThread.sleep(self.WAIT_PERFORMANCE) except Exception as e: self.log_send.emit(f"发生异常: {str(e)}", exc_info=True) QThread.sleep(self.WAIT_LONG) self.finished.emit() def is_window_valid(self,handle): try: app = Application(backend="uia").connect(handle=handle) window = app.window(handle=handle) window.exists() return True except: return False def find_edit_boxes_by_labels(self,dialog): """ 根据 '子板1' 和 '子板2' 的 Static 标签查找对应的 Edit 控件 """ try: # 查找两个 Static 标签 label1 = dialog.child_window(title="子板1", control_type="Text") label2 = dialog.child_window(title="子板2", control_type="Text") if not label1 or not label2: self.log_send.emit("找不到标签控件,跳过填充") return None, None # 获取下一个兄弟控件(即 Edit 输入框) edit1 = label1.parent().children(control_type="Edit")[0] edit2 = label2.parent().children(control_type="Edit")[1] return edit1, edit2 except Exception as e: self.log_send.emit(f"通过标签查找输入框失败: {str(e)}") return None, None def stop(self): self._running = False def generate_simulated_barcode(self): prefix = "AUTO_" timestamp = int(time.time()) % 100000 random_part = random.randint(1000, 9999) return f"{prefix}{timestamp}{random_part}" class Controller(QObject): finished = Signal() log_send = Signal(str) def __init__(self,config): super().__init__() self.config = config self.thread = None self.worker = None def start(self): self.thread = QThread() self.worker = Worker(self.config) self.worker.moveToThread(self.thread) #绑定信号 self.worker.log_send.connect(self.log_send) self.worker.finished.connect(self.thread.quit) #线程结束时清理 self.thread.finished.connect(self.finished) self.thread.finished.connect(self.worker.deleteLater) self.thread.finished.connect(self.thread.deleteLater) #启动线程 self.thread.started.connect(self.worker.run) self.thread.start() def stop(self): if self.worker: self.worker.stop() if self.thread and self.thread.isRunning(): self.thread.quit() self.thread.wait(500) #线程是否正在运行 def is_running(self): return self.thread is not None and self.thread.isRunning()
最新发布
08-03
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值