use crate::dbgeng::{callbacks::*, *};
use windows::core::Interface;
use windows_core::{PCSTR, PCWSTR, PSTR, PWSTR};
use windy::{ACPStr, ACPString, WStr, WString};
use windy_macros::{acpstr, wstr};
impl_debug_interface!(DebugClient, DebugClientRef, IDebugClient7, IDebugClient);
enum_flags! {
pub enum DebugAttachKernelFlags: u32 {
KernelConnection = DEBUG_ATTACH_KERNEL_CONNECTION,
ExdiDriver = DEBUG_ATTACH_EXDI_DRIVER,
}
}
bitflags::bitflags! {
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct DebugAttachProcessFlags: u32 {
const Default = DEBUG_ATTACH_DEFAULT;
const Noninvasive = DEBUG_ATTACH_NONINVASIVE;
const Existing = DEBUG_ATTACH_EXISTING;
const NoninvasiveNoSuspend = DEBUG_ATTACH_NONINVASIVE_NO_SUSPEND;
const InvasiveNoInitialBreak = DEBUG_ATTACH_INVASIVE_NO_INITIAL_BREAK;
const InvasiveResumeProcess = DEBUG_ATTACH_INVASIVE_RESUME_PROCESS;
}
}
bitflags::bitflags! {
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct DebugConnectSessionFlags: u32 {
const NoVersion = DEBUG_CONNECT_SESSION_NO_VERSION;
const NoAnnounce = DEBUG_CONNECT_SESSION_NO_ANNOUNCE;
}
}
pub const DEBUG_CREATE_PROCESS_NO_DEBUG_HEAP: u32 = 0x400;
pub const DEBUG_CREATE_PROCESS_THROUGH_RTL: u32 = 0x10000;
pub const DEBUG_PROCESS: u32 = 0x1;
pub const DEBUG_ONLY_THIS_PROCESS: u32 = 0x2;
bitflags::bitflags! {
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct DebugCreateProcessCreateFlags: u32 {
const NoDebugHeap = DEBUG_CREATE_PROCESS_NO_DEBUG_HEAP;
const ThroughRtl = DEBUG_CREATE_PROCESS_THROUGH_RTL;
const DebugProcess = DEBUG_PROCESS;
const OnlyThisProcess = DEBUG_ONLY_THIS_PROCESS;
}
}
bitflags::bitflags! {
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct DebugCreateProcessEngCreateFlags: u32 {
const InheritHandles = DEBUG_ECREATE_PROCESS_INHERIT_HANDLES;
const UseVerifierFlags = DEBUG_ECREATE_PROCESS_USE_VERIFIER_FLAGS;
const UseImplicitCommandLine = DEBUG_ECREATE_PROCESS_USE_IMPLICIT_COMMAND_LINE;
}
}
enum_flags! {
pub enum DebugEndFlags: u32 {
Passive = DEBUG_END_PASSIVE,
ActiveTerminate = DEBUG_END_ACTIVE_TERMINATE,
ActiveDetach = DEBUG_END_ACTIVE_DETACH,
Reentrant = DEBUG_END_REENTRANT,
EndDisconnect = DEBUG_END_DISCONNECT,
}
}
bitflags::bitflags! {
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct DebugServersFlags: u32 {
const Debugger = DEBUG_SERVERS_DEBUGGER;
const Process = DEBUG_SERVERS_PROCESS;
}
}
enum_flags! {
pub enum DebugClassFlags: u32 {
Uninitialized = DEBUG_CLASS_UNINITIALIZED,
Kernel = DEBUG_CLASS_KERNEL,
UserWindows = DEBUG_CLASS_USER_WINDOWS,
ImageFile = DEBUG_CLASS_IMAGE_FILE,
}
}
enum_flags! {
pub enum DebugDumpFlags: u32 {
Small = DEBUG_DUMP_SMALL,
Default = DEBUG_DUMP_DEFAULT,
Full = DEBUG_DUMP_FULL,
ImageFile = DEBUG_DUMP_IMAGE_FILE,
TraceLog = DEBUG_DUMP_TRACE_LOG,
WindowsCe = DEBUG_DUMP_WINDOWS_CE,
Active = DEBUG_DUMP_ACTIVE,
}
}
enum_flags! {
pub enum DebugDumpFileType: u32 {
Base = DEBUG_DUMP_FILE_BASE,
PageFileDump = DEBUG_DUMP_FILE_PAGE_FILE_DUMP,
}
}
bitflags::bitflags! {
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct DebugFormatFlags: u32 {
const WriteCab = DEBUG_FORMAT_WRITE_CAB;
const WriteCabSecondaryFiles = DEBUG_FORMAT_CAB_SECONDARY_FILES;
const NoOverwrite = DEBUG_FORMAT_NO_OVERWRITE;
const UserSmallFullMemory = DEBUG_FORMAT_USER_SMALL_FULL_MEMORY;
const UserSmallHandleData = DEBUG_FORMAT_USER_SMALL_HANDLE_DATA;
const UserSmallUnloadedModules = DEBUG_FORMAT_USER_SMALL_UNLOADED_MODULES;
const UserSmallIndirectMemory = DEBUG_FORMAT_USER_SMALL_INDIRECT_MEMORY;
const UserSmallDataSegments = DEBUG_FORMAT_USER_SMALL_DATA_SEGMENTS;
const UserSmallFilterMemory = DEBUG_FORMAT_USER_SMALL_FILTER_MEMORY;
const UserSmallFilterPaths = DEBUG_FORMAT_USER_SMALL_FILTER_PATHS;
const UserSmallProcessThreadData = DEBUG_FORMAT_USER_SMALL_PROCESS_THREAD_DATA;
const UserSmallPrivateReadWriteMemory = DEBUG_FORMAT_USER_SMALL_PRIVATE_READ_WRITE_MEMORY;
const UserSmallNoOptionalData = DEBUG_FORMAT_USER_SMALL_NO_OPTIONAL_DATA;
const UserSmallFullMemoryInfo = DEBUG_FORMAT_USER_SMALL_FULL_MEMORY_INFO;
const UserSmallThreadInfo = DEBUG_FORMAT_USER_SMALL_THREAD_INFO;
const UserSmallCodeSegments = DEBUG_FORMAT_USER_SMALL_CODE_SEGMENTS;
}
}
#[repr(transparent)]
#[derive(Debug, Clone)]
pub struct DebugCreateProcessOptions(pub DEBUG_CREATE_PROCESS_OPTIONS);
impl DebugCreateProcessOptions {
pub fn new(
create_flags: DebugCreateProcessCreateFlags,
eng_create_flags: DebugCreateProcessEngCreateFlags,
verifier_flags: u32,
) -> Self {
Self(DEBUG_CREATE_PROCESS_OPTIONS {
CreateFlags: create_flags.bits(),
EngCreateFlags: eng_create_flags.bits(),
VerifierFlags: verifier_flags,
Reserved: 0,
})
}
pub fn create_flags(&self) -> DebugCreateProcessCreateFlags {
DebugCreateProcessCreateFlags::from_bits_retain(self.0.CreateFlags)
}
pub fn eng_create_flags(&self) -> DebugCreateProcessEngCreateFlags {
DebugCreateProcessEngCreateFlags::from_bits_retain(
self.0.EngCreateFlags,
)
}
pub fn verifier_flags(&self) -> u32 { self.0.VerifierFlags }
pub fn reserved(&self) -> u32 { self.0.Reserved }
}
impl From<DEBUG_CREATE_PROCESS_OPTIONS> for DebugCreateProcessOptions {
fn from(value: DEBUG_CREATE_PROCESS_OPTIONS) -> Self { Self(value) }
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
pub enum ProcessServer {
Local,
Server(u64),
}
impl From<ProcessServer> for u64 {
fn from(value: ProcessServer) -> Self {
match value {
ProcessServer::Local => 0,
ProcessServer::Server(x) => x,
}
}
}
impl From<u64> for ProcessServer {
fn from(value: u64) -> Self {
match value {
0 => ProcessServer::Local,
x => ProcessServer::Server(x),
}
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum KernelConnectionOptions {
Resync,
CycleSpeed,
}
impl KernelConnectionOptions {
pub fn get_str(&self) -> &str {
match self {
KernelConnectionOptions::Resync => "resync",
KernelConnectionOptions::CycleSpeed => "cycle_speed",
}
}
pub(crate) fn get_astr(&self) -> &ACPStr {
match self {
KernelConnectionOptions::Resync => acpstr!("resync"),
KernelConnectionOptions::CycleSpeed => acpstr!("cycle_speed"),
}
}
pub(crate) fn get_wstr(&self) -> &WStr {
match self {
KernelConnectionOptions::Resync => wstr!("resync"),
KernelConnectionOptions::CycleSpeed => wstr!("cycle_speed"),
}
}
}
impl DebugClient {
pub fn attach_kernel(
&self,
flags: DebugAttachKernelFlags,
connect_options: impl AsRef<ACPStr>,
) -> WinResult<()> {
unsafe { self.0.AttachKernel(flags as u32, pca!(connect_options)) }
}
pub fn get_kernel_connection_options(&self) -> WinResult<ACPString> {
unsafe {
astring_with_capacity(32, |v, s| {
vcall!(
self,
GetKernelConnectionOptions,
pa!(v),
v.len().try_into().unwrap(),
s
)
})
}
}
pub fn set_kernel_connection_options(
&self,
options: KernelConnectionOptions,
) -> WinResult<()> {
unsafe {
self.0.SetKernelConnectionOptions(PCSTR(
options.get_astr().as_u8_ptr(),
))
}
}
pub fn start_process_server(
&self,
flags: DebugClassFlags,
options: impl AsRef<ACPStr>,
) -> WinResult<()> {
unsafe { self.0.StartProcessServer(flags as u32, pca!(options), None) }
}
pub fn connect_process_server(
&self,
remote_options: impl AsRef<ACPStr>,
) -> WinResult<ProcessServer> {
unsafe { Ok(self.0.ConnectProcessServer(pca!(remote_options))?.into()) }
}
pub fn disconnect_process_server(
&self,
server: ProcessServer,
) -> WinResult<()> {
unsafe { self.0.DisconnectProcessServer(server.into()) }
}
pub fn attach_process(
&self,
server: ProcessServer,
process_id: impl Into<ProcessId>,
attach_flags: DebugAttachProcessFlags,
) -> WinResult<()> {
unsafe {
self.0.AttachProcess(
server.into(),
process_id.into().0,
attach_flags.bits(),
)
}
}
pub fn create_process(
&self,
server: ProcessServer,
command_line: impl AsRef<ACPStr>,
create_flags: DebugCreateProcessCreateFlags,
) -> WinResult<()> {
let mut command_line =
command_line.as_ref().as_bytes_with_nul().to_vec();
unsafe {
self.0.CreateProcessA(
server.into(),
PSTR(command_line.as_mut_ptr()),
create_flags.bits(),
)
}
}
pub fn create_process_and_attach(
&self,
server: ProcessServer,
command_line: impl AsRef<ACPStr>,
create_flags: DebugCreateProcessCreateFlags,
process_id: Option<u32>,
attach_flags: DebugAttachProcessFlags,
) -> WinResult<()> {
let mut command_line =
command_line.as_ref().as_bytes_with_nul().to_vec();
unsafe {
self.0.CreateProcessAndAttach(
server.into(),
PSTR(command_line.as_mut_ptr()),
create_flags.bits(),
process_id.unwrap_or(0),
attach_flags.bits(),
)
}
}
pub fn get_process_options(&self) -> WinResult<DebugProcessFlags> {
unsafe {
Ok(DebugProcessFlags::from_bits_retain(
self.0.GetProcessOptions()?,
))
}
}
pub fn add_process_options(
&self,
options: DebugProcessFlags,
) -> WinResult<()> {
unsafe { self.0.AddProcessOptions(options.bits()) }
}
pub fn remove_process_options(
&self,
options: DebugProcessFlags,
) -> WinResult<()> {
unsafe { self.0.RemoveProcessOptions(options.bits()) }
}
pub fn set_process_options(
&self,
options: DebugProcessFlags,
) -> WinResult<()> {
unsafe { self.0.SetProcessOptions(options.bits()) }
}
pub fn open_dump_file(
&self,
dump_file: impl AsRef<ACPStr>,
) -> WinResult<()> {
unsafe { self.0.OpenDumpFile(pca!(dump_file)) }
}
pub fn write_dump_file(
&self,
dump_file: impl AsRef<ACPStr>,
qualifier: DebugDumpFlags,
) -> WinResult<()> {
unsafe { self.0.WriteDumpFile(pca!(dump_file), qualifier as u32) }
}
pub fn connect_session(
&self,
flags: DebugConnectSessionFlags,
history_limit: u32,
) -> WinResult<()> {
unsafe { self.0.ConnectSession(flags.bits(), history_limit) }
}
pub fn start_server(&self, options: impl AsRef<ACPStr>) -> WinResult<()> {
unsafe { self.0.StartServer(pca!(options)) }
}
pub fn output_servers(
&self,
output_control: DebugOutctlFlags,
machine: impl AsRef<ACPStr>,
flags: DebugServersFlags,
) -> WinResult<()> {
unsafe {
self.0.OutputServers(
output_control.bits(),
pca!(machine),
flags.bits(),
)
}
}
pub fn terminate_processes(&self) -> WinResult<()> {
unsafe { self.0.TerminateProcesses() }
}
pub fn detach_processes(&self) -> WinResult<()> {
unsafe { self.0.DetachProcesses() }
}
pub fn end_session(&self, flags: DebugEndFlags) -> WinResult<()> {
unsafe { self.0.EndSession(flags as u32) }
}
pub fn get_exit_code(&self) -> WinResult<(u32, bool)> {
let mut code = 0;
unsafe {
let b = hr!(vcall!(self, GetExitCode, &mut code))?;
Ok((code, b))
}
}
pub fn dispatch_callbacks(&self, timeout: u32) -> WinResult<bool> {
unsafe { hr!(vcall!(self, DispatchCallbacks, timeout)) }
}
pub fn exit_dispatch(&self, client: &DebugClient) -> WinResult<()> {
unsafe {
self.0.ExitDispatch(IDebugClient::from_raw_borrowed(
&client.0.as_raw(),
))
}
}
pub fn create_client(&self) -> WinResult<Self> {
unsafe { Self::from_interface(&self.0.CreateClient()?) }
}
pub fn get_input_callbacks(
&self,
) -> WinResult<Option<DebugInputCallbacks>> {
unsafe {
match self.0.GetInputCallbacks() {
Ok(x) => Ok(Some(x.into())),
Err(x) if x.code() == S_OK => Ok(None),
Err(x) => Err(x),
}
}
}
pub fn set_input_callbacks(
&self,
callbacks: Option<DebugInputCallbacksAdapter>,
) -> WinResult<()> {
unsafe { self.0.SetInputCallbacks(callbacks.map(Into::into).as_ref()) }
}
pub(crate) unsafe fn _set_input_callbacks_raw(
&self,
callbacks: Option<IDebugInputCallbacks>,
) -> WinResult<()> {
unsafe { self.0.SetInputCallbacks(callbacks.as_ref()) }
}
pub(crate) fn _get_output_callbacks_raw(
&self,
) -> WinResult<Option<IDebugOutputCallbacks>> {
unsafe {
match self.0.GetOutputCallbacks() {
Ok(x) => Ok(Some(x)),
Err(x) if x.code() == S_OK => Ok(None),
Err(x) => Err(x),
}
}
}
pub fn get_output_callbacks(
&self,
) -> WinResult<Option<DebugOutputCallbacks>> {
self._get_output_callbacks_raw()?
.map(|callbacks| DebugOutputCallbacks::from_interface(&callbacks))
.transpose()
}
pub fn set_output_callbacks(
&self,
callbacks: Option<DebugOutputCallbacksAdapter>,
) -> WinResult<()> {
unsafe {
self.0
.SetOutputCallbacks(callbacks.map(Into::into).as_ref())
}
}
pub(crate) unsafe fn _set_output_callbacks_raw(
&self,
callbacks: Option<IDebugOutputCallbacks>,
) -> WinResult<()> {
unsafe { self.0.SetOutputCallbacks(callbacks.as_ref()) }
}
pub fn get_output_mask(&self) -> WinResult<DebugOutputFlags> {
unsafe {
Ok(DebugOutputFlags::from_bits_retain(self.0.GetOutputMask()?))
}
}
pub fn set_output_mask(&self, mask: DebugOutputFlags) -> WinResult<()> {
unsafe { self.0.SetOutputMask(mask.bits()) }
}
pub fn get_other_output_mask(
&self,
client: &DebugClient,
) -> WinResult<DebugOutputFlags> {
unsafe {
Ok(DebugOutputFlags::from_bits_retain(
self.0.GetOtherOutputMask(IDebugClient::from_raw_borrowed(
&client.0.as_raw(),
))?,
))
}
}
pub fn set_other_output_mask(
&self,
client: &DebugClient,
mask: DebugOutputFlags,
) -> WinResult<()> {
unsafe {
self.0.SetOtherOutputMask(
IDebugClient::from_raw_borrowed(&client.0.as_raw()),
mask.bits(),
)
}
}
pub fn get_output_width(&self) -> WinResult<u32> {
unsafe { self.0.GetOutputWidth() }
}
pub fn set_output_width(&self, width: u32) -> WinResult<()> {
unsafe { self.0.SetOutputWidth(width) }
}
pub fn get_output_line_prefix(&self) -> WinResult<ACPString> {
unsafe {
astring_with_capacity(32, |v, s| {
vcall!(
self,
GetOutputLinePrefix,
pa!(v),
v.len().try_into().unwrap(),
s
)
})
}
}
pub fn set_output_line_prefix(
&self,
prefix: impl AsRef<ACPStr>,
) -> WinResult<()> {
unsafe { self.0.SetOutputLinePrefix(pca!(prefix)) }
}
pub fn get_identity(&self) -> WinResult<ACPString> {
unsafe {
astring_with_capacity(32, |v, s| {
vcall!(
self,
GetIdentity,
pa!(v),
v.len().try_into().unwrap(),
s
)
})
}
}
pub fn output_identity(
&self,
output_control: DebugOutctlFlags,
flags: u32,
format: impl AsRef<ACPStr>,
) -> WinResult<()> {
unsafe {
self.0
.OutputIdentity(output_control.bits(), flags, pca!(format))
}
}
pub fn get_event_callbacks(
&self,
) -> WinResult<Option<DebugEventCallbacks>> {
unsafe {
match self.0.GetEventCallbacks() {
Ok(x) => Ok(Some(x.into())),
Err(x) if x.code() == S_OK => Ok(None),
Err(x) => Err(x),
}
}
}
pub fn set_event_callbacks(
&self,
callbacks: Option<DebugEventCallbacksAdapter>,
) -> WinResult<()> {
unsafe { self.0.SetEventCallbacks(callbacks.map(Into::into).as_ref()) }
}
pub(crate) unsafe fn _set_event_callbacks_raw(
&self,
callbacks: Option<IDebugEventCallbacks>,
) -> WinResult<()> {
unsafe { self.0.SetEventCallbacks(callbacks.as_ref()) }
}
pub fn flush_callbacks(&self) -> WinResult<()> {
unsafe { self.0.FlushCallbacks() }
}
}
impl DebugClient {
pub fn add_dump_information_file(
&self,
info_file: impl AsRef<ACPStr>,
r#type: DebugDumpFileType,
) -> WinResult<()> {
unsafe {
self.0
.AddDumpInformationFile(pca!(info_file), r#type as u32)
}
}
pub fn end_process_server(&self, server: ProcessServer) -> WinResult<()> {
unsafe { self.0.EndProcessServer(server.into()) }
}
pub fn wait_for_process_server_end(&self, timeout: u32) -> WinResult<bool> {
unsafe { hr!(vcall!(self, WaitForProcessServerEnd, timeout)) }
}
pub fn is_kernel_debugger_enabled(&self) -> WinResult<bool> {
unsafe { hr!(vcall!(self, IsKernelDebuggerEnabled)) }
}
pub fn terminate_current_process(&self) -> WinResult<()> {
unsafe { self.0.TerminateCurrentProcess() }
}
pub fn detach_current_process(&self) -> WinResult<()> {
unsafe { self.0.DetachCurrentProcess() }
}
pub fn abandon_current_process(&self) -> WinResult<()> {
unsafe { self.0.AbandonCurrentProcess() }
}
}
impl DebugClient {
pub fn create_process_wide(
&self,
server: ProcessServer,
command_line: impl AsRef<WStr>,
create_flags: DebugCreateProcessCreateFlags,
) -> WinResult<()> {
let mut command_line =
command_line.as_ref().as_bytes_with_nul().to_vec();
unsafe {
self.0.CreateProcessWide(
server.into(),
PWSTR(command_line.as_mut_ptr()),
create_flags.bits(),
)
}
}
pub fn create_process_and_attach_wide(
&self,
server: ProcessServer,
command_line: impl AsRef<WStr>,
create_flags: DebugCreateProcessCreateFlags,
process_id: Option<u32>,
attach_flags: DebugAttachProcessFlags,
) -> WinResult<()> {
let mut command_line =
command_line.as_ref().as_bytes_with_nul().to_vec();
unsafe {
self.0.CreateProcessAndAttachWide(
server.into(),
PWSTR(command_line.as_mut_ptr()),
create_flags.bits(),
process_id.unwrap_or(0),
attach_flags.bits(),
)
}
}
}
impl DebugClient {
pub fn open_dump_file_wide<'a>(
&self,
file_name: impl Into<Option<&'a WStr>>,
file_handle: Option<u64>,
) -> WinResult<()> {
let file_name = file_name.into();
let file_name = file_name
.map_or(PCWSTR(std::ptr::null()), |name| PCWSTR(name.as_ptr()));
unsafe {
self.0
.OpenDumpFileWide(file_name, file_handle.unwrap_or_default())
}
}
pub fn write_dump_file_wide<'a>(
&self,
file_name: impl Into<Option<&'a WStr>>,
file_handle: Option<u64>,
qualifier: DebugDumpFlags,
format_flags: DebugFormatFlags,
comment: impl AsRef<WStr>,
) -> WinResult<()> {
let file_name = file_name.into();
let file_name = file_name
.map_or(PCWSTR(std::ptr::null()), |name| PCWSTR(name.as_ptr()));
unsafe {
self.0.WriteDumpFileWide(
file_name,
file_handle.unwrap_or_default(),
qualifier as u32,
format_flags.bits(),
pcw!(comment),
)
}
}
pub fn add_dump_information_file_wide(
&self,
info_file: impl AsRef<WStr>,
file_handle: u64,
r#type: DebugDumpFileType,
) -> WinResult<()> {
unsafe {
self.0.AddDumpInformationFileWide(
pcw!(info_file),
file_handle,
r#type as u32,
)
}
}
pub fn get_number_dump_files(&self) -> WinResult<u32> {
unsafe { self.0.GetNumberDumpFiles() }
}
}
impl DebugClient {
pub fn attach_kernel_wide(
&self,
flags: DebugAttachKernelFlags,
connect_options: impl AsRef<WStr>,
) -> WinResult<()> {
unsafe { self.0.AttachKernelWide(flags as u32, pcw!(connect_options)) }
}
pub fn get_kernel_connection_options_wide(&self) -> WinResult<WString> {
unsafe {
wstring_with_capacity(32, |v, s| {
vcall!(
self,
GetKernelConnectionOptionsWide,
pw!(v),
v.len().try_into().unwrap(),
s
)
})
}
}
pub fn set_kernel_connection_options_wide(
&self,
options: KernelConnectionOptions,
) -> WinResult<()> {
unsafe {
self.0.SetKernelConnectionOptionsWide(PCWSTR(
options.get_wstr().as_ptr(),
))
}
}
pub fn start_process_server_wide(
&self,
flags: DebugClassFlags,
options: impl AsRef<WStr>,
) -> WinResult<()> {
unsafe {
self.0
.StartProcessServerWide(flags as u32, pcw!(options), None)
}
}
pub fn connect_process_server_wide(
&self,
remote_options: impl AsRef<WStr>,
) -> WinResult<ProcessServer> {
unsafe {
Ok(self
.0
.ConnectProcessServerWide(pcw!(remote_options))?
.into())
}
}
pub fn start_server_wide(
&self,
options: impl AsRef<WStr>,
) -> WinResult<()> {
unsafe { self.0.StartServerWide(pcw!(options)) }
}
pub fn output_servers_wide(
&self,
output_control: DebugOutctlFlags,
machine: impl AsRef<WStr>,
flags: DebugServersFlags,
) -> WinResult<()> {
unsafe {
self.0.OutputServersWide(
output_control.bits(),
pcw!(machine),
flags.bits(),
)
}
}
pub fn get_output_callbacks_wide(
&self,
) -> WinResult<Option<DebugOutputCallbacksWide>> {
unsafe {
match self.0.GetOutputCallbacksWide() {
Ok(x) => Ok(Some(x.into())),
Err(x) if x.code() == S_OK => Ok(None),
Err(x) => Err(x),
}
}
}
pub fn set_output_callbacks_wide(
&self,
callbacks: Option<DebugOutputCallbacksWideAdapter>,
) -> WinResult<()> {
unsafe {
self.0
.SetOutputCallbacksWide(callbacks.map(Into::into).as_ref())
}
}
pub(crate) unsafe fn _set_output_callbacks_wide(
&self,
callbacks: Option<IDebugOutputCallbacksWide>,
) -> WinResult<()> {
unsafe { self.0.SetOutputCallbacksWide(callbacks.as_ref()) }
}
pub fn get_output_line_prefix_wide(&self) -> WinResult<WString> {
unsafe {
wstring_with_capacity(32, |v, s| {
vcall!(
self,
GetOutputLinePrefixWide,
pw!(v),
v.len().try_into().unwrap(),
s
)
})
}
}
pub fn set_output_line_prefix_wide(
&self,
prefix: impl AsRef<WStr>,
) -> WinResult<()> {
unsafe { self.0.SetOutputLinePrefixWide(pcw!(prefix)) }
}
pub fn get_identity_wide(&self) -> WinResult<WString> {
unsafe {
wstring_with_capacity(32, |v, s| {
vcall!(
self,
GetIdentityWide,
pw!(v),
v.len().try_into().unwrap(),
s
)
})
}
}
pub fn output_identity_wide(
&self,
output_control: DebugOutctlFlags,
flags: u32,
format: impl AsRef<WStr>,
) -> WinResult<()> {
unsafe {
self.0.OutputIdentityWide(
output_control.bits(),
flags,
pcw!(format),
)
}
}
pub fn get_event_callbacks_wide(
&self,
) -> WinResult<Option<DebugEventCallbacksWide>> {
unsafe {
match self.0.GetEventCallbacksWide() {
Ok(x) => Ok(Some(x.into())),
Err(x) if x.code() == S_OK => Ok(None),
Err(x) => Err(x),
}
}
}
pub fn set_event_callbacks_wide(
&self,
callbacks: Option<DebugEventCallbacksWideAdapter>,
) -> WinResult<()> {
unsafe {
self.0
.SetEventCallbacksWide(callbacks.map(Into::into).as_ref())
}
}
pub(crate) unsafe fn _set_event_callbacks_wide(
&self,
callbacks: Option<IDebugEventCallbacksWide>,
) -> WinResult<()> {
unsafe { self.0.SetEventCallbacksWide(callbacks.as_ref()) }
}
#[allow(clippy::too_many_arguments)]
pub fn create_process_and_attach2_wide<'a>(
&self,
server: ProcessServer,
command_line: impl AsRef<WStr>,
options: &DebugCreateProcessOptions,
initial_directory: impl Into<Option<&'a WStr>>,
environment: Option<&[u16]>,
process_id: Option<u32>,
attach_flags: DebugAttachProcessFlags,
) -> WinResult<()> {
let initial_directory = initial_directory.into();
if options
.create_flags()
.contains(DebugCreateProcessCreateFlags::ThroughRtl)
&& environment.is_some()
{
return Err(E_INVALIDARG.into());
}
let initial_directory = initial_directory
.map_or(PCWSTR(std::ptr::null()), |directory| {
PCWSTR(directory.as_ptr())
});
let environment = match environment {
None => PCWSTR(std::ptr::null()),
Some(environment)
if environment.len() >= 2
&& environment[environment.len() - 2..] == [0, 0] =>
{
PCWSTR(environment.as_ptr())
}
Some(_) => return Err(E_INVALIDARG.into()),
};
let mut command_line =
command_line.as_ref().as_bytes_with_nul().to_vec();
unsafe {
self.0.CreateProcessAndAttach2Wide(
server.into(),
PWSTR(command_line.as_mut_ptr()),
std::ptr::from_ref(&options.0).cast(),
size_of::<DEBUG_CREATE_PROCESS_OPTIONS>() as u32,
initial_directory,
environment,
process_id.unwrap_or_default(),
attach_flags.bits(),
)
}
}
pub fn get_number_input_callbacks(&self) -> WinResult<u32> {
unsafe { self.0.GetNumberInputCallbacks() }
}
pub fn get_number_output_callbacks(&self) -> WinResult<u32> {
unsafe { self.0.GetNumberOutputCallbacks() }
}
pub fn get_number_event_callbacks(
&self,
event_flags: DebugEventFlags,
) -> WinResult<u32> {
unsafe { self.0.GetNumberEventCallbacks(event_flags.bits()) }
}
pub fn get_quit_lock_string(&self) -> WinResult<ACPString> {
unsafe {
astring_with_capacity(32, |v, s| {
vcall!(
self,
GetQuitLockString,
pa!(v),
v.len().try_into().unwrap(),
s
)
})
}
}
pub fn set_quit_lock_string(
&self,
string: impl AsRef<ACPStr>,
) -> WinResult<()> {
unsafe { self.0.SetQuitLockString(pca!(string)) }
}
pub fn get_quit_lock_string_wide(&self) -> WinResult<WString> {
unsafe {
wstring_with_capacity(32, |v, s| {
vcall!(
self,
GetQuitLockStringWide,
pw!(v),
v.len().try_into().unwrap(),
s
)
})
}
}
pub fn set_quit_lock_string_wide(
&self,
string: impl AsRef<WStr>,
) -> WinResult<()> {
unsafe { self.0.SetQuitLockStringWide(pcw!(string)) }
}
}
impl DebugClient {
}
impl DebugClient {
#[doc(hidden)]
pub unsafe fn set_client_context(
&self,
context: *mut c_void,
context_size: u32,
) -> WinResult<()> {
unsafe { self.0.SetClientContext(context, context_size) }
}
}
impl DebugClient {
}
impl DebugClient {
}