我正在使用自动热键编写脚本来切换麦克风的“监听此设备”:
有两个步骤可以完成此操作,首先我需要找出正在修改的注册表项,我可以使用 RegShot 来完成此操作。
密钥存在于:
Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio\Capture\{My-Microphone's-UUID}\Properties
密钥称为
{24dbb0fc-9311-4b3d-9cf0-18ff155639d4},1
(不仅仅是我的笔记本电脑,而是所有计算机)。
切换“监听此设备”时的值会发生如下变化:(0 变为 f)
xxxxxxxxxxxxxxxx0000xxxx
xxxxxxxxxxxxxxxxffffxxxx
第二步是我的问题所在,当我检查 GUI 时,我看到“监听此设备”复选框已被勾选,但我实际上无法从麦克风中听到任何声音,当我取消勾选它然后点击“应用”并重新-勾选它并单击“应用”,我听到我的麦克风声音。这意味着我在这里需要某种 DllCall 或 PostMessage,但这就是我非常不足的地方:
我不知道如何让Windows了解此设置已更改,我需要找出当我单击“应用”时发送了哪些消息或调用了哪些dll。
所以我用谷歌搜索了Windows消息列表,然后我逐字地发布了页面上存在的每一个十六进制,如下所示:
PostMessage, 0x0000,,,,A
...
PostMessage, 0xcccd,,,,A
当然没用,这是在黑暗中开枪。
在声音 GUI 上使用 Autohotkey 的 WindowSpy 和 从本文中我发现
shell32.dll
可能与此有关,因此使用 nirsoft 的 DLL 导出查看器复制了 shell32
中存在的所有函数,并使用以下命令调用了所有函数像这样的自动热键:
DllCall("shell32\Control_RunDLL")
...
但这也行不通。
起初我认为,这是一个编程问题,可以用 Autohotkey 及其工具来回答,所以我在 SO 上问了这个问题,但我要求将其移至 RE,因为下面的评论给了我更多见解。
请教我如何正确地进行逆向工程。
感谢RE上的这个答案,我能够想出一个正确的代码示例来设置是否启用/禁用监听,以及应该在哪个设备上监听 - 包括“默认播放设备”设置.
它是使用 pycaw 和 comtypes 在 python 中实现的,但我认为使用具有 coreaudio 库的其他语言也可以轻松完成。
from typing import Optional
from comtypes import GUID
from comtypes.automation import VT_BOOL, VT_LPWSTR, VT_EMPTY
from comtypes.persist import STGM_READWRITE
from pycaw.api.mmdeviceapi import PROPERTYKEY
from pycaw.api.mmdeviceapi.depend import PROPVARIANT
from pycaw.utils import AudioUtilities
#Hardcoded values
LISTEN_SETTING_GUID = "{24DBB0FC-9311-4B3D-9CF0-18FF155639D4}"
CHECKBOX_PID = 1
LISTENING_DEVICE_PID = 0
#Values you can change:
microphone_name = 'Microphone (USB-MIC)'
listening_device_name = 'Speakers (5- GSA 70 Main Audio)' #Set to 'None' to use the default playback device
enable_listening = False
def main():
store = get_device_store(microphone_name)
if store is None:
print("failed to open property store")
exit(1)
set_listening_checkbox(store, enable_listening)
set_listening_device(store, listening_device_name)
#Write to the checkbox property
def set_listening_checkbox(property_store, value:bool):
checkbox_pk = PROPERTYKEY()
checkbox_pk.fmtid = GUID(LISTEN_SETTING_GUID)
checkbox_pk.pid = CHECKBOX_PID
new_value = PROPVARIANT(VT_BOOL)
new_value.union.boolVal = value
property_store.SetValue(checkbox_pk, new_value)
#Write to the device property
def set_listening_device(property_store, output_device_name:Optional[str]):
if output_device_name is not None:
listening_device_guid = get_GUID_from_name(output_device_name)
else:
listening_device_guid = None
device_pk = PROPERTYKEY()
device_pk.fmtid = GUID(LISTEN_SETTING_GUID)
device_pk.pid = LISTENING_DEVICE_PID
if listening_device_guid is not None:
new_value = PROPVARIANT(VT_LPWSTR)
new_value.union.pwszVal = listening_device_guid
else:
new_value = PROPVARIANT(VT_EMPTY)
property_store.SetValue(device_pk, new_value)
#Gets the device store from the device name
def get_device_store(device_name:str):
device_guid = get_GUID_from_name(device_name)
enumerator = AudioUtilities.GetDeviceEnumerator()
dev = enumerator.GetDevice(device_guid)
store = dev.OpenPropertyStore(STGM_READWRITE)
return store
#This is just a helper method to turn a device name into a GUID.
def get_GUID_from_name(device_name:str) -> str:
input_devices = get_list_of_active_coreaudio_devices("input")
for device in input_devices:
if device.FriendlyName == device_name:
return device.id
output_devices = get_list_of_active_coreaudio_devices("output")
for device in output_devices:
if device.FriendlyName == device_name:
return device.id
raise ValueError("Device not found!")
#Helper method to get all (active) devices
def get_list_of_active_coreaudio_devices(device_type:str) -> list:
import comtypes
from pycaw.pycaw import AudioUtilities, IMMDeviceEnumerator, EDataFlow, DEVICE_STATE
from pycaw.constants import CLSID_MMDeviceEnumerator
if device_type != "output" and device_type != "input":
raise ValueError("Invalid audio device type.")
if device_type == "output":
EDataFlowValue = EDataFlow.eRender.value
else:
EDataFlowValue = EDataFlow.eCapture.value
# Code to enumerate devices adapted from https://github.com/AndreMiras/pycaw/issues/50#issuecomment-981069603
devices = list()
device_enumerator = comtypes.CoCreateInstance(
CLSID_MMDeviceEnumerator,
IMMDeviceEnumerator,
comtypes.CLSCTX_INPROC_SERVER)
if device_enumerator is None:
raise ValueError("Couldn't find any devices.")
collection = device_enumerator.EnumAudioEndpoints(EDataFlowValue, DEVICE_STATE.ACTIVE.value)
if collection is None:
raise ValueError("Couldn't find any devices.")
count = collection.GetCount()
for i in range(count):
dev = collection.Item(i)
if dev is not None:
if not ": None" in str(AudioUtilities.CreateDevice(dev)):
devices.append(AudioUtilities.CreateDevice(dev))
return devices
if __name__ == "__main__":
main()