wdext 0.1.0

A DbgEng wrapper framework
// SPDX-FileCopyrightText: 2026 takubokudori
// SPDX-License-Identifier: MIT OR Apache-2.0
//! IDebugSystemObjects
use crate::dbgeng::{client::ProcessServer, *};
use windows_core::{PSTR, PWSTR};
use windy::{ACPString, WString};

impl_debug_interface!(
    DebugSystemObjects,
    DebugSystemObjectsRef,
    IDebugSystemObjects4,
    IDebugSystemObjects
);

impl DebugSystemObjects {
    pub fn get_event_thread(&self) -> WinResult<EngineThreadId> {
        unsafe { Ok(self.0.GetEventThread()?.into()) }
    }

    pub fn get_event_process(&self) -> WinResult<EngineProcessId> {
        unsafe { Ok(self.0.GetEventProcess()?.into()) }
    }

    pub fn get_current_thread_id(&self) -> WinResult<EngineThreadId> {
        unsafe { Ok(self.0.GetCurrentThreadId()?.into()) }
    }

    pub fn set_current_thread_id(
        &self,
        id: impl Into<EngineThreadId>,
    ) -> WinResult<()> {
        unsafe { self.0.SetCurrentThreadId(id.into().0) }
    }

    pub fn get_current_process_id(&self) -> WinResult<EngineProcessId> {
        unsafe { Ok(self.0.GetCurrentProcessId()?.into()) }
    }

    pub fn set_current_process_id(
        &self,
        id: impl Into<EngineProcessId>,
    ) -> WinResult<()> {
        unsafe { self.0.SetCurrentProcessId(id.into().0) }
    }

    pub fn get_number_threads(&self) -> WinResult<u32> {
        unsafe { self.0.GetNumberThreads() }
    }

    /// Returns `(Total, LargestProcess)`.
    pub fn get_total_number_threads(&self) -> WinResult<(u32, u32)> {
        let mut total = 0;
        let mut largest_process = 0;
        unsafe {
            self.0
                .GetTotalNumberThreads(&mut total, &mut largest_process)?;
            Ok((total, largest_process))
        }
    }

    pub fn get_thread_ids_by_index(
        &self,
        start: u32,
        count: u32,
    ) -> WinResult<Vec<(EngineThreadId, ThreadId)>> {
        let mut ids = Vec::with_capacity(count as usize);
        let mut sys_ids = Vec::with_capacity(count as usize);
        unsafe {
            self.0.GetThreadIdsByIndex(
                start,
                count,
                Some(ids.as_mut_ptr()),
                Some(sys_ids.as_mut_ptr()),
            )?;
            ids.set_len(count as usize);
            sys_ids.set_len(count as usize);
            Ok(ids
                .into_iter()
                .zip(sys_ids)
                .map(|(id, sys_id)| {
                    (EngineThreadId::from(id), ThreadId::from(sys_id))
                })
                .collect())
        }
    }

    pub fn get_thread_id_by_processor(
        &self,
        processor: u32,
    ) -> WinResult<EngineThreadId> {
        unsafe { Ok(self.0.GetThreadIdByProcessor(processor)?.into()) }
    }

    pub fn get_current_thread_data_offset(&self) -> WinResult<DebuggeeOffset> {
        unsafe { self.0.GetCurrentThreadDataOffset() }
    }

    pub fn get_thread_id_by_data_offset(
        &self,
        offset: DebuggeeOffset,
    ) -> WinResult<EngineThreadId> {
        unsafe { Ok(self.0.GetThreadIdByDataOffset(offset)?.into()) }
    }

    pub fn get_current_thread_teb(&self) -> WinResult<DebuggeeOffset> {
        unsafe { self.0.GetCurrentThreadTeb() }
    }

    pub fn get_thread_id_by_teb(
        &self,
        offset: DebuggeeOffset,
    ) -> WinResult<EngineThreadId> {
        unsafe { Ok(self.0.GetThreadIdByTeb(offset)?.into()) }
    }

    pub fn get_current_thread_system_id(&self) -> WinResult<ThreadId> {
        unsafe { Ok(self.0.GetCurrentThreadSystemId()?.into()) }
    }

    pub fn get_thread_id_by_system_id(
        &self,
        sys_id: impl Into<ThreadId>,
    ) -> WinResult<EngineThreadId> {
        unsafe {
            Ok(self.0.GetThreadIdBySystemId(sys_id.into().into())?.into())
        }
    }

    pub fn get_current_thread_handle(&self) -> WinResult<ThreadHandle> {
        unsafe { Ok(ThreadHandle::new(self.0.GetCurrentThreadHandle()?)) }
    }

    pub fn get_thread_id_by_handle(
        &self,
        handle: &ThreadHandle,
    ) -> WinResult<EngineThreadId> {
        unsafe {
            Ok(self.0.GetThreadIdByHandle(handle.as_raw_handle())?.into())
        }
    }

    pub fn get_number_processes(&self) -> WinResult<u32> {
        unsafe { self.0.GetNumberProcesses() }
    }

    pub fn get_process_ids_by_index(
        &self,
        start: u32,
        count: u32,
    ) -> WinResult<Vec<(EngineProcessId, ProcessId)>> {
        let mut ids = Vec::with_capacity(count as usize);
        let mut sys_ids = Vec::with_capacity(count as usize);
        unsafe {
            self.0.GetProcessIdsByIndex(
                start,
                count,
                Some(ids.as_mut_ptr()),
                Some(sys_ids.as_mut_ptr()),
            )?;
            ids.set_len(count as usize);
            sys_ids.set_len(count as usize);
            Ok(ids
                .into_iter()
                .zip(sys_ids)
                .map(|(id, sys_id)| {
                    (EngineProcessId::from(id), ProcessId::from(sys_id))
                })
                .collect())
        }
    }

    pub fn get_current_process_data_offset(&self) -> WinResult<DebuggeeOffset> {
        unsafe { self.0.GetCurrentProcessDataOffset() }
    }

    pub fn get_process_id_by_data_offset(
        &self,
        offset: DebuggeeOffset,
    ) -> WinResult<EngineProcessId> {
        unsafe { Ok(self.0.GetProcessIdByDataOffset(offset)?.into()) }
    }

    pub fn get_current_process_peb(&self) -> WinResult<DebuggeeOffset> {
        unsafe { self.0.GetCurrentProcessPeb() }
    }

    pub fn get_process_id_by_peb(
        &self,
        offset: DebuggeeOffset,
    ) -> WinResult<EngineProcessId> {
        unsafe { Ok(self.0.GetProcessIdByPeb(offset)?.into()) }
    }

    pub fn get_current_process_system_id(&self) -> WinResult<ProcessId> {
        unsafe { Ok(self.0.GetCurrentProcessSystemId()?.into()) }
    }

    pub fn get_process_id_by_system_id(
        &self,
        sys_id: impl Into<ProcessId>,
    ) -> WinResult<EngineProcessId> {
        unsafe {
            Ok(self.0.GetProcessIdBySystemId(sys_id.into().into())?.into())
        }
    }

    pub fn get_current_process_handle(&self) -> WinResult<ProcessHandle> {
        unsafe { Ok(ProcessHandle::new(self.0.GetCurrentProcessHandle()?)) }
    }

    pub fn get_process_id_by_handle(
        &self,
        handle: &ProcessHandle,
    ) -> WinResult<EngineProcessId> {
        unsafe {
            Ok(self.0.GetProcessIdByHandle(handle.as_raw_handle())?.into())
        }
    }

    pub fn get_current_process_executable_name(&self) -> WinResult<ACPString> {
        unsafe {
            astring_with_capacity(128, |v, s| {
                vcall!(
                    self,
                    GetCurrentProcessExecutableName,
                    PSTR(v.as_mut_ptr() as *mut _),
                    v.len().try_into().unwrap(),
                    s,
                )
            })
        }
    }
}

// IDebugSystemObjects2
impl DebugSystemObjects {
    pub fn get_current_process_up_time(&self) -> WinResult<u32> {
        unsafe { self.0.GetCurrentProcessUpTime() }
    }

    pub fn get_implicit_thread_data_offset(&self) -> WinResult<DebuggeeOffset> {
        unsafe { self.0.GetImplicitThreadDataOffset() }
    }

    pub fn set_implicit_thread_data_offset(
        &self,
        offset: DebuggeeOffset,
    ) -> WinResult<()> {
        unsafe { self.0.SetImplicitThreadDataOffset(offset) }
    }

    pub fn get_implicit_process_data_offset(
        &self,
    ) -> WinResult<DebuggeeOffset> {
        unsafe { self.0.GetImplicitProcessDataOffset() }
    }

    pub fn set_implicit_process_data_offset(
        &self,
        offset: DebuggeeOffset,
    ) -> WinResult<()> {
        unsafe { self.0.SetImplicitProcessDataOffset(offset) }
    }
}

// IDebugSystemObjects3
impl DebugSystemObjects {
    pub fn get_event_system(&self) -> WinResult<EngineSystemId> {
        unsafe { Ok(self.0.GetEventSystem()?.into()) }
    }

    pub fn get_current_system_id(&self) -> WinResult<EngineSystemId> {
        unsafe { Ok(self.0.GetCurrentSystemId()?.into()) }
    }

    pub fn set_current_system_id(
        &self,
        id: impl Into<EngineSystemId>,
    ) -> WinResult<()> {
        unsafe { self.0.SetCurrentSystemId(id.into().0) }
    }

    pub fn get_number_systems(&self) -> WinResult<u32> {
        unsafe { self.0.GetNumberSystems() }
    }

    pub fn get_system_ids_by_index(
        &self,
        start: u32,
        count: u32,
    ) -> WinResult<Vec<EngineSystemId>> {
        let mut ids = Vec::with_capacity(count as usize);
        unsafe {
            vcall!(self, GetSystemIdsByIndex, start, count, ids.as_mut_ptr())
                .ok()?;
            ids.set_len(count as usize);
        }
        Ok(ids.into_iter().map(EngineSystemId::from).collect())
    }

    /// Returns `(TotalThreads, TotalProcesses, LargestProcessThreads, LargestSystemThreads, LargestSystemProcesses)`.
    pub fn get_total_number_threads_and_processes(
        &self,
    ) -> WinResult<(u32, u32, u32, u32, u32)> {
        let mut total_threads = 0;
        let mut total_processes = 0;
        let mut largest_process_threads = 0;
        let mut largest_system_threads = 0;
        let mut largest_system_processes = 0;
        unsafe {
            self.0.GetTotalNumberThreadsAndProcesses(
                &mut total_threads,
                &mut total_processes,
                &mut largest_process_threads,
                &mut largest_system_threads,
                &mut largest_system_processes,
            )?;
            Ok((
                total_threads,
                total_processes,
                largest_process_threads,
                largest_system_threads,
                largest_system_processes,
            ))
        }
    }

    pub fn get_current_system_server(&self) -> WinResult<ProcessServer> {
        unsafe { Ok(self.0.GetCurrentSystemServer()?.into()) }
    }

    pub fn get_system_by_server(
        &self,
        server: ProcessServer,
    ) -> WinResult<EngineSystemId> {
        unsafe { Ok(self.0.GetSystemByServer(server.into())?.into()) }
    }

    pub fn get_current_system_server_name(&self) -> WinResult<ACPString> {
        unsafe {
            astring_with_capacity(128, |v, s| {
                vcall!(
                    self,
                    GetCurrentSystemServerName,
                    PSTR(v.as_mut_ptr() as *mut _),
                    v.len().try_into().unwrap(),
                    s,
                )
            })
        }
    }
}

// IDebugSystemObjects4
impl DebugSystemObjects {
    pub fn get_current_process_executable_name_wide(
        &self,
    ) -> WinResult<WString> {
        unsafe {
            wstring_with_capacity(128, |v, s| {
                vcall!(
                    self,
                    GetCurrentProcessExecutableNameWide,
                    PWSTR(v.as_mut_ptr() as *mut _),
                    v.len().try_into().unwrap(),
                    s,
                )
            })
        }
    }

    pub fn get_current_system_server_name_wide(&self) -> WinResult<WString> {
        unsafe {
            wstring_with_capacity(128, |v, s| {
                vcall!(
                    self,
                    GetCurrentSystemServerNameWide,
                    PWSTR(v.as_mut_ptr() as *mut _),
                    v.len().try_into().unwrap(),
                    s,
                )
            })
        }
    }
}