wdext 0.1.0

A DbgEng wrapper framework
// SPDX-FileCopyrightText: 2026 takubokudori
// SPDX-License-Identifier: MIT OR Apache-2.0
//! IDebugAdvanced
use crate::{dbgeng::*, object::traits::context::Context};
use bitflags::bitflags;
use std::mem::MaybeUninit;

bitflags! {
    #[derive(Debug, Copy, Clone,Eq, PartialEq)]
    pub struct DebugFindSourceFlags: u32 {
        const Default = DEBUG_FIND_SOURCE_DEFAULT;
        const FullPath = DEBUG_FIND_SOURCE_FULL_PATH;
        const BestMatch = DEBUG_FIND_SOURCE_BEST_MATCH;
        const NoSrcsrv = DEBUG_FIND_SOURCE_NO_SRCSRV;
        const TokenLookup = DEBUG_FIND_SOURCE_TOKEN_LOOKUP;
        const WithChecksum = DEBUG_FIND_SOURCE_WITH_CHECKSUM;
        const WithChecksumStrict = DEBUG_FIND_SOURCE_WITH_CHECKSUM_STRICT;
    }
}

enum_flags! {
    pub enum DebugSrcFileSymbolOptions: u32 {
        Token = DEBUG_SRCFILE_SYMBOL_TOKEN,
        TokenSourceCommandWide = DEBUG_SRCFILE_SYMBOL_TOKEN_SOURCE_COMMAND_WIDE,
        ChecksumInfo = DEBUG_SRCFILE_SYMBOL_CHECKSUMINFO,
    }
}

pub enum DebugSrcFileSymbolData {
    Token(Vec<u8>),
    TokenSourceCommandWide(WString),
}

impl_debug_interface!(
    DebugAdvanced,
    DebugAdvancedRef,
    IDebugAdvanced4,
    IDebugAdvanced
);

// IDebugAdvanced
impl DebugAdvanced {
    /// # Safety
    pub unsafe fn get_thread_context<C: Context>(&self) -> WinResult<C> {
        unsafe {
            let mut context = MaybeUninit::<C>::zeroed();
            self.0.GetThreadContext(
                context.as_mut_ptr() as *mut _,
                size_of::<C>() as u32,
            )?;
            Ok(context.assume_init())
        }
    }

    /// # Safety
    pub unsafe fn set_thread_context<C: Context>(
        &self,
        context: &C,
    ) -> WinResult<()> {
        unsafe {
            self.0.SetThreadContext(
                context as *const _ as *const _,
                size_of::<C>() as u32,
            )
        }
    }
}

// IDebugAdvanced2
impl DebugAdvanced {
    // Request

    unsafe fn _request(&self, request: u32) -> WinResult<bool> {
        unsafe {
            hr!(vcall!(
                self,
                Request,
                request,
                std::ptr::null(),
                0,
                std::ptr::null_mut(),
                0,
                std::ptr::null_mut()
            ))
        }
    }

    unsafe fn _request_i<T: Sized>(
        &self,
        request: u32,
        in_buffer: &T,
    ) -> WinResult<()> {
        unsafe {
            vcall!(
                self,
                Request,
                request,
                in_buffer as *const T as *const c_void,
                size_of::<T>() as u32,
                std::ptr::null_mut(),
                0,
                std::ptr::null_mut()
            )
            .ok()
        }
    }

    unsafe fn _request_o<T: Sized>(&self, request: u32) -> WinResult<T> {
        let mut out_size = 0;
        let mut ret = MaybeUninit::<T>::uninit();
        let obj_size = size_of::<T>() as u32;
        unsafe {
            vcall!(
                self,
                Request,
                request,
                std::ptr::null(),
                0,
                ret.as_mut_ptr() as *mut c_void,
                obj_size,
                &mut out_size,
            )
            .ok()?;
            assert_eq!(obj_size, out_size);
            Ok(ret.assume_init())
        }
    }

    pub fn _request_source_path_has_source_server(&self) -> WinResult<bool> {
        unsafe { self._request(DEBUG_REQUEST_SOURCE_PATH_HAS_SOURCE_SERVER) }
    }

    // _request_target_exception_context

    // _request_target_exception_thread

    // _request_target_exception_record

    pub fn _request_get_additional_create_options(
        &self,
    ) -> WinResult<DebugCreateProcessOptions> {
        unsafe { self._request_o(DEBUG_REQUEST_GET_ADDITIONAL_CREATE_OPTIONS) }
    }

    pub fn _request_set_additional_create_options(
        &self,
        options: &DebugCreateProcessOptions,
    ) -> WinResult<()> {
        unsafe {
            self._request_i(
                DEBUG_REQUEST_SET_ADDITIONAL_CREATE_OPTIONS,
                options,
            )
        }
    }

    // _request_get_win32_major_minor_versions

    // _request_read_user_minidump_stream

    pub fn _request_target_can_detach(&self) -> WinResult<bool> {
        unsafe { self._request(DEBUG_REQUEST_TARGET_CAN_DETACH) }
    }

    // _request_set_local_implicit_command_line

    pub fn _request_get_captured_event_code_offset(
        &self,
    ) -> WinResult<DebuggeeOffset> {
        unsafe { self._request_o(DEBUG_REQUEST_GET_CAPTURED_EVENT_CODE_OFFSET) }
    }

    pub fn _request_read_captured_event_code_stream(
        &self,
    ) -> WinResult<Vec<u8>> {
        let mut out_size = 0;
        let mut ret: Vec<u8> = Vec::with_capacity(64);
        unsafe {
            vcall!(
                self,
                Request,
                DEBUG_REQUEST_READ_CAPTURED_EVENT_CODE_STREAM,
                std::ptr::null(),
                0,
                ret.as_mut_ptr() as *mut c_void,
                64,
                &mut out_size,
            )
            .ok()?;
            assert!(
                out_size <= 64,
                "DbgEng returned an output size larger than the supplied \
                 buffer"
            );
            ret.set_len(out_size as usize);
            Ok(ret)
        }
    }

    // _request_ext_typed_data_ansi

    /// Returns `true` if non-invasive user-mode attach, `false` if not. `E_FAIL` otherwise.
    pub fn _request_live_user_non_invasive(&self) -> WinResult<bool> {
        unsafe { self._request(DEBUG_LIVE_USER_NON_INVASIVE) }
    }

    pub fn _request_resume_thread(&self, tid: ThreadId) -> WinResult<()> {
        unsafe { self._request_i(DEBUG_REQUEST_RESUME_THREAD, &tid) }
    }

    // GetSourceFileInformation

    // FindSourceFileAndToken

    // GetSymbolInformation

    // GetSystemObjectInformation
}

// IDebugAdvanced3
impl DebugAdvanced {
    // GetSourceFileInformationWide

    // FindSourceFileAndTokenWide

    // GetSymbolInformationWide
}

// IDebugAdvanced4
impl DebugAdvanced {
    // GetSymbolInformationWideEx
}