I have a python script that I use to balance sound and (this is the more interesting part) change values in registries. To be able able to change those values, my script requests UAC elevation when it needs to. Here is my problem: in one function, the call to another function (used for elevating) goes normally and nothing crashes, while in another function, which calls the elevation function the exact same way as the former function, keeps crashing my program. I have discovered that the problem is in the elevation function itself, but only when being called from the function that causes it to crash. Here is my code:
from ctypes import cast, POINTER
from comtypes import CLSCTX_ALL
from pycaw.pycaw import AudioUtilities, IAudioEndpointVolume
import time
import sys, winreg, pyuac
from PyQt5.QtWidgets import QDialog, QApplication
from balancer_ui import *
adminError = False
class Window(QDialog):
def devicesetup(self):
devices = AudioUtilities.GetSpeakers()
interface = devices.Activate(IAudioEndpointVolume._iid_, CLSCTX_ALL, None)
volume = cast(interface, POINTER(IAudioEndpointVolume))
return devices, interface, volume
def setKeyValue(self, value):
global adminError
try:
if not pyuac.isUserAdmin():
adminError = False
pyuac.runAsAdmin()
sys.exit(0)
except Exception as e:
adminError = True
self.ui.wlErrorPopup("Cannot run as Admin: ", e)
try:
keySet = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"SYSTEM\CurrentControlSet\Control\Bluetooth\Audio\AVRCP\CT", 0, winreg.KEY_SET_VALUE)
winreg.SetValueEx(keySet, 'DisableAbsoluteVolume', 0, winreg.REG_DWORD, value)
winreg.CloseKey(keySet)
except Exception as e:
self.ui.wlErrorPopup("Error writing registry: ", e)
return adminError
def __init__(self):
super().__init__()
self.ui = Ui_Dialog()
self.ui.setupUi(self)
self.ui.balance.valueChanged.connect(self.main)
self.ui.volume.valueChanged.connect(self.main)
self.ui.wireless.released.connect(self.wltoggle)
def wlstatus():
global adminError
adminError = False
try:
keyRead = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"SYSTEM\CurrentControlSet\Control\Bluetooth\Audio\AVRCP\CT", 0, winreg.KEY_QUERY_VALUE)
keyReadValue = winreg.QueryValueEx(keyRead, 'DisableAbsoluteVolume')
errorRead = False
winreg.CloseKey(keyRead)
except Exception as e:
errorRead = True
keyReadValue = False
if not pyuac.isUserAdmin():
self.ui.wlErrorPopup("There has been an error reading the registry. Wireless audio balancing will not work. The program will automatically try to fix the error. If it fails, edit the registry manually. The error is: ", e)
try:
adminError = self.setKeyValue(0)
except Exception as e:
print(e)
self.ui.wlErrorPopup("Something else went wrong: ", e)
print(e)
return errorRead, keyReadValue, adminError
for i in range (2):
errorRead, keyReadValue, adminError = wlstatus()
if adminError:
break
if errorRead:
self.ui.wireless.setEnabled(False)
elif keyReadValue[0] == 1:
self.ui.wireless.setChecked(True)
devices, interface, volume = self.devicesetup()
mastervolume = round(volume.GetMasterVolumeLevelScalar()*100)
if mastervolume == 0:
self.ui.volumeval.setText("0")
self.ui.volume.setValue(mastervolume)
self.show()
def wltoggle(self):
try:
if self.ui.wireless.isChecked():
value = 98
else:
value = 6
self.setKeyValue(value)
keyReadValue = self.wlstatus()
if keyReadValue[0] != value:
self.ui.wlErrorPopup("Something else went wrong ", e)
except Exception as e:
print(e)
self.ui.wlErrorPopup("Something else went wrong: ", e)
def main(self):
devices, interface, volume = self.devicesetup()
target = self.ui.balance.value()
mastervolume = self.ui.volume.value()/100
volume.SetMasterVolumeLevelScalar(mastervolume, None)
self.ui.balanceval.setText(str(target-5))
if target != 5:
targetL = (mastervolume/10)*(10-target)
targetR = (mastervolume/10)*(target)
else:
targetL = mastervolume
targetR = mastervolume
volume.SetChannelVolumeLevelScalar(0, targetL, None)
volume.SetChannelVolumeLevelScalar(1, targetR, None)
if __name__=="__main__":
app = QApplication(sys.argv)
w = Window()
w.show()
sys.exit(app.exec())
So let me explain: SetKeyValue is the function that requests UAC elevation and changes the registry value. WLstatus is the function that causes no problems when calling the SetKeyValue from within itself. WLtoggle is the function which causes pyuac functions inside the SetKeyValue function to crash the whole scipt. I get zero output in the console 99% of the time. The console restarts, and thats it. I also tried using ShellExecuteEx instead of pyuac with the same results.
I once got this in my console, no idea if it is related to the issue but ill just leave it here in case it is:
Exception ignored in: <function compointer_base.del at 0x0000023A081B7380> Traceback (most recent call last): File "C:\Users\MJouv\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\LocalCache\local-packages\Python311\site-packages\comtypes_init.py", line 956, in del self.Release() File "C:\Users\MJouv\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\LocalCache\local-packages\Python311\site-packages\comtypes_init_.py", line 1211, in Release return self.__com_Release() ^^^^^^^^^^^^^^^^^^^^ OSError: exception: access violation reading 0xFFFFFFFFFFFFFFFF
Edit: I also sometimes get this error:
Exception ignored in: <function compointer_base.del at 0x000001BBD2CB3420> Traceback (most recent call last): File "C:\Users\MJouv\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\LocalCache\local-packages\Python311\site-packages\comtypes_init.py", line 956, in del self.Release() File "C:\Users\MJouv\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\LocalCache\local-packages\Python311\site-packages\comtypes_init_.py", line 1211, in Release return self.__com_Release() ^^^^^^^^^^^^^^^^^^^^ ValueError: COM method call without VTable