问题描述
我有一个想要在 Windows (10+) 上运行的 python 3 应用程序。但是,当我在 MacBook Pro 上的 Windows-10 Pro Parallels VM 上打开应用程序窗口的情况下运行 onfocus 事件自动化时,应用程序崩溃并显示以下错误:
Unhandled Exception: System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
at Accessibility.IAccessible.get_accFocus()
at MS.Internal.AutomationProxies.Accessible.GetFocus()
at MS.Internal.AutomationProxies.MsaaNativeProvider.System.Windows.Automation.Provider.IRawElementProviderFragmentRoot.GetFocus()
at MS.Internal.Automation.FocusTracker.GetFocusedElementFromWinEvent(IntPtr hwnd,Int32 idObject,Int32 idChild)
at MS.Internal.Automation.FocusTracker.HandleFocusChange(IntPtr hwnd,Accessible acc,Int32 idChild,UInt32 eventTime)
at MS.Internal.Automation.FocusTracker.WinEventProc(Int32 eventId,IntPtr hwnd,UInt32 eventTime)
at MS.Internal.Automation.WinEventWrap.WinEventReentrancyFilter(Int32 winEventHook,Int32 eventId,Int32 eventThread,UInt32 eventTime)
它不会立即崩溃,但会很快崩溃。下面是一个最小的可重现示例(您需要先安装 dot-net 和 python)。要复制错误,请通过命令提示符运行代码,当我的应用程序窗口打开时,单击无用按钮,然后单击窗口内的背景以更改焦点,然后单击该按钮,然后继续单击窗口中的内容。也许单击其他应用程序,然后在窗口中单击返回。在所有点击后不久,它就会使程序崩溃。
这在我的戴尔上似乎根本没有发生。只是 MacBook Pro。它似乎在戴尔上运行正常。
将 UIAutomation onfocus 绑定线程作为守护程序运行(或不运行)没有区别。
我非常乐意让它只杀死一个有问题的 onfocus 事件,然后处理下一个 onfocus 事件,而不会导致应用程序本身崩溃。甚至杀死所有 onfocus 功能,以便我需要重新启动代码中的 onfocus 监控,只要应用程序本身不会崩溃。但我不知道如何捕捉 onfocus 错误:它们不是来自我的代码。
当然,理想情况下,根本不会抛出任何错误,但如果我至少能在抛出错误时处理它们,那对我来说将是朝着正确方向迈出的一大步。
这是 MRE。我很想知道它是否发生在你身上!欢迎提出任何修复建议!
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import threading
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
import clr
clr.AddReference('../UIAutomationClient')
clr.AddReference('../UIAutomationClientsideProviders')
clr.AddReference('../UIAutomationProvider')
clr.AddReference('../UIAutomationTypes')
from System.Windows.Automation import *
class MyApp:
qtApp = None
myWindow = None
frameMainMenu = None
frameMainMenuLayout = None
contentRunContainer = None
def __init__(self):
self.runApp()
def onFocusChange(self,element,args):
print('onFocusChange() RUNNING')
pass
def launchWindowsEventMonitoring(self):
#TODO: This randomly crashes the app on Windows.
try:
print("----------------------------------")
print("launchWindowsEventMonitoring() 00")
focusHandler = AutomationFocusChangedEventHandler(self.onFocusChange)
Automation.AddAutomationFocusChangedEventHandler(focusHandler)
print("launchWindowsEventMonitoring() 01")
except Exception as e:
print("useful.launchWindowsEventMonitoring() ERROR: " + str(e))
def runApp(self):
try:
print('runApp() 00')
t = threading.Thread(target=self.launchWindowsEventMonitoring)
#t.setDaemon(True)
t.start()
self.setupGUI()
print('runApp() 01')
except Exception as e:
print("self.runApp() ERROR: " + str(e))
def setupMainMenuScreen(self):
try:
print("setupMainMenuScreen() 00")
self.frameMainMenu = QFrame()
self.frameMainMenuLayout = QVBoxLayout()
self.frameMainMenu.setLayout(self.frameMainMenuLayout)
menuWidget = QWidget()
menuWidget.setObjectName('menuWidget')
menuScroller = QScrollArea()
menuScroller.horizontalScrollbarPolicy = Qt.ScrollBarAlwaysOff
menuScroller.verticalScrollbarPolicy = Qt.ScrollBarAlwaysOn
menuScroller.setObjectName('menuScroller')
self.menuLayout = QVBoxLayout(menuWidget)
btnMyButton = QPushButton('A great button')
self.menuLayout.addWidget(btnMyButton)
menuScroller.setWidget(menuWidget)
self.frameMainMenuLayout.addWidget(menuScroller)
self.contentRunContainer.addWidget(self.frameMainMenu)
print("setupMainMenuScreen() 01")
except Exception as e:
print("self.setupMainMenuScreen() ERROR: " + str(e))
def setupGUI(self):
try:
print("setupGUI() 00")
self.qtApp = QApplication([])
self.qtApp.setQuitOnLastWindowClosed(False)
self.myWindow = theWindow()
self.theWindowWidget = QWidget()
self.theWindowWidget.setObjectName('body')
self.myWindow.setCentralWidget(self.theWindowWidget)
mainLayout = QVBoxLayout()
self.theWindowWidget.setLayout(mainLayout)
self.runWrapper = QFrame()
self.runWrapperLayout = QVBoxLayout()
self.runWrapper.setLayout(self.runWrapperLayout)
sharedRunWrapper = QVBoxLayout()
self.contentRunContainer = QVBoxLayout()
sharedRunWrapper.addLayout(self.contentRunContainer)
self.runWrapperLayout.addLayout(sharedRunWrapper)
mainLayout.addWidget(self.runWrapper)
self.setupMainMenuScreen()
self.myWindow.show()
print("setupGUI() 01")
self.qtApp.exec()
except Exception as e:
print("self.setupGUI() ERROR: " + str(e))
class theWindow(QMainWindow):
def __init__(self):
try:
super().__init__()
self.setWindowTitle("My Application")
except Exception as e:
print("theWindow.init() ERROR: " + str(e))
if __name__ == "__main__":
MyApp = MyApp()
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)