Upgrade windows-rs, get the basics working
This commit is contained in:
76
Cargo.lock
generated
76
Cargo.lock
generated
@@ -60,60 +60,90 @@ checksum = "b5babd2d3fcd28bcf9712ef93e437684156f5c46173a9718829aa57aa4aa37a8"
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.37.0"
|
||||
version = "0.44.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57b543186b344cc61c85b5aab0d2e3adf4e0f99bc076eff9aa5927bcc0b8a647"
|
||||
checksum = "9e745dab35a0c4c77aa3ce42d595e13d2003d6902d6b08c9ef5fc326d08da12b"
|
||||
dependencies = [
|
||||
"windows-implement",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_msvc",
|
||||
"windows-interface",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-implement"
|
||||
version = "0.37.0"
|
||||
version = "0.44.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67a1062e555f7d9d66fd1130ed4f7c6ec41a47529ee0850cd0e926d95b26bb14"
|
||||
checksum = "6ce87ca8e3417b02dc2a8a22769306658670ec92d78f1bd420d6310a67c245c6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"windows-tokens",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-tokens"
|
||||
version = "0.37.0"
|
||||
name = "windows-interface"
|
||||
version = "0.44.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3263d25f1170419995b78ff10c06b949e8a986c35c208dc24333c64753a87169"
|
||||
checksum = "853f69a591ecd4f810d29f17e902d40e349fb05b0b11fff63b08b826bfe39c7f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.42.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.42.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.37.0"
|
||||
version = "0.42.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2623277cb2d1c216ba3b578c0f3cf9cdebeddb6e66b1b218bb33596ea7769c3a"
|
||||
checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.37.0"
|
||||
version = "0.42.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3925fd0b0b804730d44d4b6278c50f9699703ec49bcd628020f46f4ba07d9e1"
|
||||
checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.37.0"
|
||||
version = "0.42.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce907ac74fe331b524c1298683efbf598bb031bc84d5e274db2083696d07c57c"
|
||||
checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.37.0"
|
||||
version = "0.42.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2babfba0828f2e6b32457d5341427dcbb577ceef556273229959ac23a10af33d"
|
||||
checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.42.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.37.0"
|
||||
version = "0.42.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4dd6dc7df2d84cf7b33822ed5b86318fb1781948e9663bacd047fc9dd52259d"
|
||||
checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
|
||||
|
||||
@@ -10,9 +10,8 @@ widestring = "1.0.0"
|
||||
once_cell = "1.12.0"
|
||||
|
||||
[dependencies.windows]
|
||||
version = "0.37.0"
|
||||
version = "0.44.0"
|
||||
features = [
|
||||
"alloc",
|
||||
"implement",
|
||||
"Win32_Media_Audio",
|
||||
"Win32_UI_Shell_PropertiesSystem",
|
||||
|
||||
238
src/main.rs
238
src/main.rs
@@ -2,19 +2,24 @@ mod pid_to_exe;
|
||||
|
||||
use once_cell::sync::Lazy;
|
||||
use std::{
|
||||
collections::HashSet,
|
||||
error::Error,
|
||||
ffi::c_void,
|
||||
mem,
|
||||
ptr::{self, null_mut}, sync::{Arc, Mutex}
|
||||
ffi::{OsStr, OsString},
|
||||
path::Path,
|
||||
ptr::null_mut,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
use widestring::U16CStr;
|
||||
use windows::{
|
||||
core::{Interface, PCWSTR},
|
||||
Win32::{
|
||||
Foundation::{HINSTANCE, HWND},
|
||||
Media::Audio::{
|
||||
eRender, IAudioSessionManager2, IMMDeviceEnumerator, MMDeviceEnumerator,
|
||||
DEVICE_STATE_ACTIVE, IAudioSessionNotification, IAudioSessionControl, IAudioSessionNotification_Impl, IAudioSessionControl2, IMMNotificationClient, IMMNotificationClient_Impl,
|
||||
eRender, IAudioSessionControl, IAudioSessionControl2, IAudioSessionManager2,
|
||||
IAudioSessionNotification, IAudioSessionNotification_Impl, IMMDeviceEnumerator,
|
||||
IMMNotificationClient, IMMNotificationClient_Impl, ISimpleAudioVolume,
|
||||
MMDeviceEnumerator, DEVICE_STATE_ACTIVE,
|
||||
},
|
||||
System::Com::{CoCreateInstance, CoInitializeEx, CLSCTX_ALL, COINIT_MULTITHREADED},
|
||||
UI::{
|
||||
@@ -22,10 +27,10 @@ use windows::{
|
||||
WindowsAndMessaging::{
|
||||
DispatchMessageW, GetMessageW, GetWindowThreadProcessId, TranslateMessage,
|
||||
EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_MINIMIZEEND, MSG, WINEVENT_OUTOFCONTEXT,
|
||||
WINEVENT_SKIPOWNPROCESS,
|
||||
WINEVENT_SKIPOWNPROCESS, GetForegroundWindow,
|
||||
},
|
||||
},
|
||||
}, core::{Interface, PCWSTR},
|
||||
},
|
||||
};
|
||||
|
||||
use crate::pid_to_exe::pid_to_exe_path;
|
||||
@@ -33,7 +38,7 @@ use crate::pid_to_exe::pid_to_exe_path;
|
||||
unsafe extern "system" fn win_event_proc(
|
||||
_hook: HWINEVENTHOOK,
|
||||
event: u32,
|
||||
hwnd: HWND,
|
||||
_hwnd: HWND,
|
||||
_id_object: i32,
|
||||
_id_child: i32,
|
||||
_dw_event_thread: u32,
|
||||
@@ -41,8 +46,11 @@ unsafe extern "system" fn win_event_proc(
|
||||
) {
|
||||
if event == EVENT_SYSTEM_FOREGROUND || event == EVENT_SYSTEM_MINIMIZEEND {
|
||||
let mut pid: u32 = 0;
|
||||
GetWindowThreadProcessId(hwnd, &mut pid);
|
||||
println!("{:?}", pid_to_exe_path(pid));
|
||||
// Instead of using the hwnd passed to us in the wineventproc, call GetForegroundWindow again because Hollow Knight does something weird
|
||||
// and immediately fires again with the hwnd for explorer?
|
||||
GetWindowThreadProcessId(GetForegroundWindow(), Some(&mut pid));
|
||||
let path = pid_to_exe_path(pid).unwrap_or("".to_string());
|
||||
MUTER.lock().unwrap().notify_window_changed(&path);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,25 +92,34 @@ Okay, the main way this will function:
|
||||
- Register Session Notification on Session Manager
|
||||
- Get session enumerator from session manager
|
||||
- Detect sessions from applications we care about by getting session PID and mapping to process names using existing code
|
||||
|
||||
- This should really work based on PID and unmute only the open process's PID when focused? Though maybe not due to the weird nature of electron apps and shit?
|
||||
- Keep it the way it is for now I guess
|
||||
*/
|
||||
|
||||
#[windows::core::implement(IAudioSessionNotification)]
|
||||
struct SessionNotification {
|
||||
sessions: Arc<Mutex<Vec<IAudioSessionControl>>>
|
||||
}
|
||||
struct SessionNotification {}
|
||||
|
||||
impl IAudioSessionNotification_Impl for SessionNotification {
|
||||
fn OnSessionCreated(self: &SessionNotification,newsession: &core::option::Option<IAudioSessionControl>) -> windows::core::Result<()> {
|
||||
println!("Got OSC call");
|
||||
let ses = newsession.as_ref().unwrap().clone();
|
||||
let s2: IAudioSessionControl2 = ses.cast().unwrap();
|
||||
println!("Holy shit, new session created! {}", unsafe { pid_to_exe_path(s2.GetProcessId().unwrap()).unwrap() });
|
||||
self.sessions.lock().unwrap().push(ses);
|
||||
fn OnSessionCreated(
|
||||
self: &SessionNotification,
|
||||
newsession: &core::option::Option<IAudioSessionControl>,
|
||||
) -> windows::core::Result<()> {
|
||||
let ses: IAudioSessionControl2 = newsession.as_ref().unwrap().cast().unwrap();
|
||||
println!("New session created: {}", unsafe {
|
||||
ses.GetProcessId()
|
||||
.and_then(|x| Ok(pid_to_exe_path(x).unwrap().to_string()))
|
||||
.unwrap_or("UNKNOWN".to_string())
|
||||
});
|
||||
MUTER.lock()
|
||||
.unwrap()
|
||||
.add_session_if_interesting(ses)
|
||||
.unwrap();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for SessionNotification {
|
||||
|
||||
fn drop(&mut self) {
|
||||
println!("SN drop");
|
||||
}
|
||||
@@ -118,70 +135,141 @@ impl Drop for DeviceNotificationClient {
|
||||
}
|
||||
|
||||
impl IMMNotificationClient_Impl for DeviceNotificationClient {
|
||||
fn OnDeviceStateChanged(&self,_pwstrdeviceid: &windows::core::PCWSTR,_dwnewstate:u32) -> windows::core::Result<()> {
|
||||
fn OnDeviceStateChanged(
|
||||
&self,
|
||||
_pwstrdeviceid: &windows::core::PCWSTR,
|
||||
_dwnewstate: u32,
|
||||
) -> windows::core::Result<()> {
|
||||
println!("OnDeviceStateChanged");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn OnDeviceAdded(&self,_pwstrdeviceid: &windows::core::PCWSTR) -> windows::core::Result<()> {
|
||||
// EUGH!
|
||||
fn OnDeviceAdded(&self, pwstrdeviceid: &windows::core::PCWSTR) -> windows::core::Result<()> {
|
||||
println!("OnDeviceAdded");
|
||||
/*
|
||||
KING.lock().unwrap().add_device_by_id(pwstrdeviceid).map_err(|error| {
|
||||
println!("Error adding device: {:?}", error);
|
||||
}).unwrap_or(());
|
||||
*/
|
||||
MUTER.lock()
|
||||
.unwrap()
|
||||
.add_device_by_id(pwstrdeviceid)
|
||||
.map_err(|error| {
|
||||
println!("Error adding device: {:?}", error);
|
||||
})
|
||||
.unwrap_or(());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn OnDeviceRemoved(&self,_pwstrdeviceid: &windows::core::PCWSTR) -> windows::core::Result<()> {
|
||||
fn OnDeviceRemoved(&self, _pwstrdeviceid: &windows::core::PCWSTR) -> windows::core::Result<()> {
|
||||
println!("OnDeviceRemoved");
|
||||
// TODO: Remove device and all its sessions
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn OnDefaultDeviceChanged(&self,_flow:windows::Win32::Media::Audio::EDataFlow,_role:windows::Win32::Media::Audio::ERole,_pwstrdefaultdeviceid: &windows::core::PCWSTR) -> windows::core::Result<()> {
|
||||
fn OnDefaultDeviceChanged(
|
||||
&self,
|
||||
_flow: windows::Win32::Media::Audio::EDataFlow,
|
||||
_role: windows::Win32::Media::Audio::ERole,
|
||||
_pwstrdefaultdeviceid: &windows::core::PCWSTR,
|
||||
) -> windows::core::Result<()> {
|
||||
println!("OnDefaultDeviceChanged");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn OnPropertyValueChanged(&self,_pwstrdeviceid: &windows::core::PCWSTR,_key: &windows::Win32::UI::Shell::PropertiesSystem::PROPERTYKEY) -> windows::core::Result<()> {
|
||||
fn OnPropertyValueChanged(
|
||||
&self,
|
||||
_pwstrdeviceid: &windows::core::PCWSTR,
|
||||
_key: &windows::Win32::UI::Shell::PropertiesSystem::PROPERTYKEY,
|
||||
) -> windows::core::Result<()> {
|
||||
println!("OnPropertyValueChanged");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
struct SessionKing {
|
||||
sessions: Arc<Mutex<Vec<IAudioSessionControl>>>,
|
||||
device_enumerator : IMMDeviceEnumerator,
|
||||
dnc : IMMNotificationClient
|
||||
struct SessionMuter {
|
||||
sessions: Arc<Mutex<Vec<IAudioSessionControl2>>>,
|
||||
device_enumerator: IMMDeviceEnumerator,
|
||||
dnc: IMMNotificationClient,
|
||||
session_notification: IAudioSessionNotification,
|
||||
good_files: HashSet<String>,
|
||||
mute_flag: bool,
|
||||
session_managers: Vec<IAudioSessionManager2>
|
||||
}
|
||||
|
||||
impl SessionKing {
|
||||
fn new() -> SessionKing {
|
||||
SessionKing {
|
||||
sessions: Arc::new(Mutex::new(Vec::new())),
|
||||
device_enumerator: unsafe { CoCreateInstance(&MMDeviceEnumerator, None, CLSCTX_ALL).unwrap() },
|
||||
dnc: IMMNotificationClient::from(DeviceNotificationClient {})
|
||||
impl SessionMuter {
|
||||
fn new() -> SessionMuter {
|
||||
let s = Arc::new(Mutex::new(Vec::new()));
|
||||
SessionMuter {
|
||||
session_managers: Vec::new(),
|
||||
sessions: s.clone(),
|
||||
device_enumerator: unsafe {
|
||||
CoCreateInstance(&MMDeviceEnumerator, None, CLSCTX_ALL).unwrap()
|
||||
},
|
||||
dnc: IMMNotificationClient::from(DeviceNotificationClient {}),
|
||||
session_notification: IAudioSessionNotification::from(SessionNotification {}),
|
||||
good_files: HashSet::from(["hollow_knight.exe"].map(|s| s.to_string())),
|
||||
mute_flag: true,
|
||||
}
|
||||
}
|
||||
|
||||
fn add_session_if_interesting(
|
||||
self: &mut SessionMuter,
|
||||
session: IAudioSessionControl2,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
let file_name = self.session_to_filename(&session);
|
||||
if file_name.is_err() {
|
||||
return Ok(());
|
||||
}
|
||||
let fn_str = file_name
|
||||
.unwrap()
|
||||
.to_os_string()
|
||||
.to_string_lossy()
|
||||
.to_string();
|
||||
println!("Got session: {:?}", fn_str);
|
||||
if self.good_files.contains(&fn_str) {
|
||||
unsafe {
|
||||
let volume: ISimpleAudioVolume = session.cast()?;
|
||||
volume.SetMute(self.mute_flag, null_mut())?;
|
||||
}
|
||||
self.sessions.lock().unwrap().push(session);
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
fn boot_devices(self: &mut SessionKing) -> Result<String, Box<dyn Error>> {
|
||||
unsafe fn set_mute_all(self: &mut SessionMuter, mute: bool) {
|
||||
let sessions = self.sessions.lock().unwrap();
|
||||
let results = sessions
|
||||
.iter()
|
||||
.map(|session_control2| session_control2.cast::<ISimpleAudioVolume>())
|
||||
.map(|vol_result| vol_result.map(|volume| volume.SetMute(mute, null_mut())));
|
||||
for err in results.filter_map(|x| x.err()) {
|
||||
println!("Error muting a session: {:?}", err);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn notify_window_changed(self: &mut SessionMuter, path: &str) {
|
||||
let binding = Path::new(path).file_name().unwrap_or(OsStr::new(""));
|
||||
let file_name = binding.to_os_string().to_string_lossy().to_string();
|
||||
self.mute_flag = !self.good_files.contains(&file_name);
|
||||
self.set_mute_all(self.mute_flag);
|
||||
println!("Mute set to {} due to selection of {}", self.mute_flag, file_name);
|
||||
}
|
||||
|
||||
fn boot_devices(self: &mut SessionMuter) -> Result<String, Box<dyn Error>> {
|
||||
unsafe {
|
||||
(Interface::vtable(&self.device_enumerator).RegisterEndpointNotificationCallback)(Interface::as_raw(&self.device_enumerator), self.dnc.as_raw()).ok()?;
|
||||
let device_collection =
|
||||
self.device_enumerator.EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE)?;
|
||||
self.device_enumerator
|
||||
.RegisterEndpointNotificationCallback(&self.dnc)?;
|
||||
let device_collection = self
|
||||
.device_enumerator
|
||||
.EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE)?;
|
||||
let dc = 0..device_collection.GetCount()?;
|
||||
let devices = dc.map(|x| device_collection.Item(x));
|
||||
for x in devices {
|
||||
let mmdevice = x?;
|
||||
self.add_device(mmdevice)?;
|
||||
}
|
||||
println!("Boot done");
|
||||
return Ok("Done".to_string());
|
||||
}
|
||||
}
|
||||
|
||||
fn add_device_by_id(self: &mut SessionKing, id: &PCWSTR) -> Result<(), Box<dyn Error>> {
|
||||
fn add_device_by_id(self: &mut SessionMuter, id: &PCWSTR) -> Result<(), Box<dyn Error>> {
|
||||
unsafe {
|
||||
let device_enumerator: IMMDeviceEnumerator =
|
||||
CoCreateInstance(&MMDeviceEnumerator, None, CLSCTX_ALL)?;
|
||||
@@ -191,40 +279,54 @@ impl SessionKing {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn add_device(self: &mut SessionKing, mmdevice: windows::Win32::Media::Audio::IMMDevice) -> Result<(), Box<dyn Error>> {
|
||||
let mut sm_ptr: *mut c_void = null_mut();
|
||||
mmdevice.Activate(
|
||||
&<IAudioSessionManager2 as ::windows::core::Interface>::IID,
|
||||
CLSCTX_ALL,
|
||||
null_mut(),
|
||||
ptr::addr_of_mut!(sm_ptr),
|
||||
)?;
|
||||
let sm: IAudioSessionManager2 = mem::transmute(sm_ptr);
|
||||
fn session_to_filename(
|
||||
self: &mut SessionMuter,
|
||||
session: &IAudioSessionControl2,
|
||||
) -> Result<OsString, Box<dyn Error>> {
|
||||
unsafe {
|
||||
let pid = session.GetProcessId()?;
|
||||
let path = pid_to_exe_path(pid)?;
|
||||
let file_name = Path::new(&path)
|
||||
.file_name()
|
||||
.ok_or("Failed to extract filename from path")?;
|
||||
return Ok(file_name.to_os_string());
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn add_device(
|
||||
self: &mut SessionMuter,
|
||||
mmdevice: windows::Win32::Media::Audio::IMMDevice,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
let sm: IAudioSessionManager2 = mmdevice.Activate(CLSCTX_ALL, None)?;
|
||||
sm.RegisterSessionNotification(&self.session_notification)?;
|
||||
let sesenum = sm.GetSessionEnumerator()?;
|
||||
let sn_count = sesenum.GetCount()?;
|
||||
let mut cdses = (0..sn_count).map(|idx| sesenum.GetSession(idx)).collect::<Result<Vec<IAudioSessionControl>,_>>()?;
|
||||
self.sessions.lock().unwrap().append(&mut cdses);
|
||||
sm.RegisterSessionNotification(IAudioSessionNotification::from( SessionNotification {
|
||||
sessions: self.sessions.clone()
|
||||
}))?;
|
||||
let device_sessions = (0..sn_count)
|
||||
.map(|idx| sesenum.GetSession(idx))
|
||||
.map(|x| match x {
|
||||
Err(e) => Err(e),
|
||||
Ok(v) => v.cast(),
|
||||
})
|
||||
.collect::<Result<Vec<IAudioSessionControl2>, _>>()?;
|
||||
for session in device_sessions {
|
||||
self.add_session_if_interesting(session)?;
|
||||
}
|
||||
let str = U16CStr::from_ptr_str(mmdevice.GetId()?.0).to_string_lossy();
|
||||
println!("Device Added: {} {}", str, sn_count);
|
||||
self.session_managers.push(sm);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
unsafe impl Send for SessionKing {}
|
||||
unsafe impl Sync for SessionKing {}
|
||||
unsafe impl Send for SessionMuter {}
|
||||
unsafe impl Sync for SessionMuter {}
|
||||
|
||||
static KING : Lazy<Arc<Mutex<SessionKing>>> = Lazy::new(|| {
|
||||
Arc::new(Mutex::new(SessionKing::new()))
|
||||
});
|
||||
static MUTER: Lazy<Arc<Mutex<SessionMuter>>> = Lazy::new(|| Arc::new(Mutex::new(SessionMuter::new())));
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
CoInitializeEx(null_mut(), COINIT_MULTITHREADED).unwrap();
|
||||
CoInitializeEx(None, COINIT_MULTITHREADED).unwrap();
|
||||
}
|
||||
KING.lock().unwrap().boot_devices().unwrap();
|
||||
MUTER.lock().unwrap().boot_devices().unwrap();
|
||||
win_event_hook_loop();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user