feat: replace DSSound slot 0 (destructor) with Rust
Browse filesReleases all COM objects in correct order: 8 channel desc buffers
(Stop + Release), 500 channel slot buffers (Release), primary buffer
(Stop + Release), IDirectSound (Release). Sets secondary vtable at end.
Update Ghidra names for all converted DSSound vtable methods.
22/24 DSSound vtable slots now Rust. Only slots 3 (play_sound) and
4 (play_sound_pooled) remain.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
crates/openwa-core/src/audio/dssound.rs
CHANGED
|
@@ -396,6 +396,60 @@ pub unsafe extern "thiscall" fn set_channel_volume(
|
|
| 396 |
1
|
| 397 |
}
|
| 398 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 399 |
/// Slot 14: sub_destructor β sets secondary vtable (0x66AF58), optionally frees.
|
| 400 |
/// This is a base-class destructor called by the primary destructor (slot 0).
|
| 401 |
pub unsafe extern "thiscall" fn sub_destructor(
|
|
|
|
| 396 |
1
|
| 397 |
}
|
| 398 |
|
| 399 |
+
/// Slot 0: destructor β releases all COM objects and frees memory.
|
| 400 |
+
pub unsafe extern "thiscall" fn destructor(
|
| 401 |
+
this: *mut DSSound, flags: u8,
|
| 402 |
+
) -> *mut DSSound {
|
| 403 |
+
let snd = &mut *this;
|
| 404 |
+
|
| 405 |
+
// Reset vtable to primary (destructor chain pattern).
|
| 406 |
+
use crate::address::va;
|
| 407 |
+
use crate::rebase::rb;
|
| 408 |
+
snd.vtable = rb(va::DS_SOUND_VTABLE) as *const DSSoundVtable;
|
| 409 |
+
|
| 410 |
+
// Release all 8 channel descriptor buffers (Stop + Release).
|
| 411 |
+
for desc in &mut snd.channel_descs {
|
| 412 |
+
if let Some(buf) = desc.take_buffer() {
|
| 413 |
+
let _ = buf.Stop();
|
| 414 |
+
// Release on drop
|
| 415 |
+
}
|
| 416 |
+
}
|
| 417 |
+
|
| 418 |
+
// Release all 500 channel slot buffers.
|
| 419 |
+
for slot in &mut snd.channel_slots {
|
| 420 |
+
if *slot != 0 {
|
| 421 |
+
let buf: IDirectSoundBuffer = core::mem::transmute_copy(slot);
|
| 422 |
+
// Release on drop (no Stop needed β these are template buffers)
|
| 423 |
+
drop(buf);
|
| 424 |
+
*slot = 0;
|
| 425 |
+
}
|
| 426 |
+
}
|
| 427 |
+
|
| 428 |
+
// Release primary buffer (Stop + Release).
|
| 429 |
+
if snd.primary_buffer != 0 {
|
| 430 |
+
let buf: IDirectSoundBuffer = core::mem::transmute_copy(&snd.primary_buffer);
|
| 431 |
+
let _ = buf.Stop();
|
| 432 |
+
drop(buf);
|
| 433 |
+
snd.primary_buffer = 0;
|
| 434 |
+
}
|
| 435 |
+
|
| 436 |
+
// Release IDirectSound.
|
| 437 |
+
if snd.direct_sound != 0 {
|
| 438 |
+
use windows::Win32::Media::Audio::DirectSound::IDirectSound;
|
| 439 |
+
let ds: IDirectSound = core::mem::transmute_copy(&snd.direct_sound);
|
| 440 |
+
drop(ds);
|
| 441 |
+
snd.direct_sound = 0;
|
| 442 |
+
}
|
| 443 |
+
|
| 444 |
+
// Set secondary vtable (base class destructor pattern).
|
| 445 |
+
snd.vtable = rb(0x0066_AF58) as *const DSSoundVtable;
|
| 446 |
+
|
| 447 |
+
if flags & 1 != 0 {
|
| 448 |
+
crate::wa_alloc::wa_free(this as *mut u8);
|
| 449 |
+
}
|
| 450 |
+
this
|
| 451 |
+
}
|
| 452 |
+
|
| 453 |
/// Slot 14: sub_destructor β sets secondary vtable (0x66AF58), optionally frees.
|
| 454 |
/// This is a base-class destructor called by the primary destructor (slot 0).
|
| 455 |
pub unsafe extern "thiscall" fn sub_destructor(
|
crates/openwa-core/src/audio/mod.rs
CHANGED
|
@@ -8,6 +8,7 @@ pub mod streaming;
|
|
| 8 |
pub use active_sound::{ActiveSoundEntry, ActiveSoundTable};
|
| 9 |
pub use dssound::{DSSound, DSSoundVtable, ChannelDescriptor};
|
| 10 |
pub use dssound::{
|
|
|
|
| 11 |
update_channels, release_finished,
|
| 12 |
is_slot_loaded, is_channel_finished, stop_channel,
|
| 13 |
set_volume_params, set_master_volume, set_channel_volume, set_pan,
|
|
|
|
| 8 |
pub use active_sound::{ActiveSoundEntry, ActiveSoundTable};
|
| 9 |
pub use dssound::{DSSound, DSSoundVtable, ChannelDescriptor};
|
| 10 |
pub use dssound::{
|
| 11 |
+
destructor as dssound_destructor,
|
| 12 |
update_channels, release_finished,
|
| 13 |
is_slot_loaded, is_channel_finished, stop_channel,
|
| 14 |
set_volume_params, set_master_volume, set_channel_volume, set_pan,
|
crates/openwa-wormkit/src/replacements/sound.rs
CHANGED
|
@@ -170,6 +170,7 @@ unsafe fn patch_dssound_vtable() -> Result<(), String> {
|
|
| 170 |
use openwa_core::audio::{
|
| 171 |
update_channels, release_finished,
|
| 172 |
is_slot_loaded, is_channel_finished, stop_channel,
|
|
|
|
| 173 |
set_volume_params, set_master_volume, set_channel_volume, set_pan,
|
| 174 |
dssound_sub_destructor,
|
| 175 |
load_wav, dssound_noop, dssound_returns_0, dssound_returns_1,
|
|
@@ -181,6 +182,9 @@ unsafe fn patch_dssound_vtable() -> Result<(), String> {
|
|
| 181 |
// Slot 12: load_wav β WAV file β DirectSound secondary buffer (hound + windows crate)
|
| 182 |
*vt.add(12) = load_wav as *const () as u32;
|
| 183 |
|
|
|
|
|
|
|
|
|
|
| 184 |
// Slot 1: update_channels β release finished buffers each frame
|
| 185 |
*vt.add(1) = update_channels as *const () as u32;
|
| 186 |
|
|
@@ -223,6 +227,6 @@ unsafe fn patch_dssound_vtable() -> Result<(), String> {
|
|
| 223 |
// Trivial returns-1 (slot 23)
|
| 224 |
*vt.add(23) = dssound_returns_1 as *const () as u32;
|
| 225 |
|
| 226 |
-
let _ = log_line("[Sound] DSSound vtable: patched
|
| 227 |
}).map_err(|e| e.to_string())
|
| 228 |
}
|
|
|
|
| 170 |
use openwa_core::audio::{
|
| 171 |
update_channels, release_finished,
|
| 172 |
is_slot_loaded, is_channel_finished, stop_channel,
|
| 173 |
+
dssound_destructor,
|
| 174 |
set_volume_params, set_master_volume, set_channel_volume, set_pan,
|
| 175 |
dssound_sub_destructor,
|
| 176 |
load_wav, dssound_noop, dssound_returns_0, dssound_returns_1,
|
|
|
|
| 182 |
// Slot 12: load_wav β WAV file β DirectSound secondary buffer (hound + windows crate)
|
| 183 |
*vt.add(12) = load_wav as *const () as u32;
|
| 184 |
|
| 185 |
+
// Slot 0: destructor β releases all COM objects
|
| 186 |
+
*vt.add(0) = dssound_destructor as *const () as u32;
|
| 187 |
+
|
| 188 |
// Slot 1: update_channels β release finished buffers each frame
|
| 189 |
*vt.add(1) = update_channels as *const () as u32;
|
| 190 |
|
|
|
|
| 227 |
// Trivial returns-1 (slot 23)
|
| 228 |
*vt.add(23) = dssound_returns_1 as *const () as u32;
|
| 229 |
|
| 230 |
+
let _ = log_line("[Sound] DSSound vtable: patched 22/24 slots with Rust");
|
| 231 |
}).map_err(|e| e.to_string())
|
| 232 |
}
|