Skip to content

Commit

Permalink
Add Natvis definitions for types defined in the core module of the …
Browse files Browse the repository at this point in the history
…`windows` crate (#2023)
  • Loading branch information
ridwanabdillahi authored Sep 21, 2022
1 parent e018d41 commit 29e5510
Show file tree
Hide file tree
Showing 11 changed files with 492 additions and 4 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -195,4 +195,5 @@ jobs:
cargo clippy -p tool_msvc &&
cargo clippy -p tool_sys &&
cargo clippy -p tool_windows &&
cargo clippy -p tool_yml
cargo clippy -p tool_yml &&
cargo clippy -p test_debugger_visualizer
4 changes: 4 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,10 @@ jobs:
cargo test --target ${{ matrix.target }} -p tool_windows &&
cargo test --target ${{ matrix.target }} -p tool_yml
- name: Test debugger_visualizer feature
run: cargo test --target ${{ matrix.target }} -p test_debugger_visualizer -- --test-threads=1
if: matrix.version == 'nightly' && endsWith(matrix.target, '-msvc')

- name: Check import libs
shell: pwsh
run: |
Expand Down
5 changes: 5 additions & 0 deletions crates/libs/windows/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -724,3 +724,8 @@ Win32_UI_WindowsAndMessaging = ["Win32_UI"]
Win32_UI_Wpf = ["Win32_UI"]
Win32_UI_Xaml = ["Win32_UI"]
Win32_UI_Xaml_Diagnostics = ["Win32_UI_Xaml"]

# UNSTABLE FEATURES (requires Rust nightly)
# Enable to use the #[debugger_visualizer] attribute.
debugger_visualizer = []

1 change: 1 addition & 0 deletions crates/libs/windows/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Learn more about Rust for Windows here: <https://github.com/microsoft/windows-rs

#![doc(html_no_source)]
#![allow(non_snake_case, non_upper_case_globals, non_camel_case_types, clashing_extern_declarations, unused_variables, dead_code, clippy::all)]
#![cfg_attr(feature = "debugger_visualizer", feature(debugger_visualizer), debugger_visualizer(natvis_file = "../windows.natvis"))]

extern crate self as windows;
mod Windows;
Expand Down
82 changes: 82 additions & 0 deletions crates/libs/windows/windows.natvis
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="windows::core::array::Array&lt;*&gt;">
<DisplayString>{{ len={len} }}</DisplayString>

<Expand>
<Item Name="[len]">len</Item>
<ArrayItems>
<Size>len</Size>
<ValuePointer>data</ValuePointer>
</ArrayItems>
</Expand>
</Type>

<Type Name="windows::core::error::Error">
<Expand>
<ExpandedItem>code</ExpandedItem>
<Item Name="[info]">info</Item>
</Expand>
</Type>

<Type Name="windows::core::hresult::HRESULT">
<DisplayString>{(HRESULT)__0}</DisplayString>
</Type>

<Type Name="windows::core::ref_count::RefCount">
<DisplayString>{__0}</DisplayString>
</Type>

<Type Name="windows::core::strings::hstring::HSTRING">
<DisplayString Condition="__0 == nullptr">""</DisplayString>
<DisplayString>{((char16_t*)__0->data),[__0->len]su}</DisplayString>

<Expand>
<Item Name="[len]">__0 == nullptr ? (unsigned int)0 : __0->len</Item>
<Item Name="[ref_count]" Condition="__0 != nullptr">__0->count</Item>
<Item Name="[flags]" Condition="__0 != nullptr">__0->flags</Item>
<Synthetic Name="[chars]" Condition="__0 != nullptr">
<Expand>
<ArrayItems>
<Size>__0->len</Size>
<ValuePointer>(char16_t*)__0->data</ValuePointer>
</ArrayItems>
</Expand>
</Synthetic>
</Expand>
</Type>

<Type Name="windows::core::strings::pstr::PSTR">
<AlternativeType Name="windows::core::strings::pcstr::PCSTR" />
<Intrinsic Name="len" Expression="strlen(((char*)__0))" />
<DisplayString>{(char*)__0,[len()]s8}</DisplayString>
<Expand>
<Item Name="[len]">len()</Item>
<Synthetic Name="[chars]">
<Expand>
<ArrayItems>
<Size>len()</Size>
<ValuePointer>(char*)__0</ValuePointer>
</ArrayItems>
</Expand>
</Synthetic>
</Expand>
</Type>

<Type Name="windows::core::strings::pwstr::PWSTR">
<AlternativeType Name="windows::core::strings::pcwstr::PCWSTR" />
<Intrinsic Name="len" Expression="wcslen(((WCHAR*)__0))" />
<DisplayString>{(char16_t*)__0,[len()]su}</DisplayString>

<Expand>
<Item Name="[len]">len()</Item>
<Synthetic Name="[chars]">
<Expand>
<ArrayItems>
<Size>len()</Size>
<ValuePointer>(char16_t*)__0</ValuePointer>
</ArrayItems>
</Expand>
</Synthetic>
</Expand>
</Type>
</AutoVisualizer>
18 changes: 18 additions & 0 deletions crates/tests/debugger_visualizer/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[package]
name = "test_debugger_visualizer"
version = "0.0.0"
authors = ["Microsoft"]
edition = "2018"

[dependencies.windows]
path = "../../libs/windows"
features = [
"debugger_visualizer",
"implement",
"Win32_System_Com",
"Win32_Foundation",
]

[dev-dependencies]
debugger_test = "0.1.0"
debugger_test_parser = "0.1.0"
1 change: 1 addition & 0 deletions crates/tests/debugger_visualizer/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

241 changes: 241 additions & 0 deletions crates/tests/debugger_visualizer/tests/test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
use debugger_test::*;
use windows::core::*;
use windows::Win32::Foundation::*;
use windows::Win32::System::Com::*;

#[inline(never)]
fn __break() {}

#[implement(IErrorInfo)]
struct Test;

impl IErrorInfo_Impl for Test {
fn GetGUID(&self) -> Result<GUID> {
Err(Error::new(E_OUTOFMEMORY, "Out of memory message".into()))
}
fn GetSource(&self) -> Result<BSTR> {
Err(Error::new(E_INVALIDARG, "Invalid argument message".into()))
}
fn GetDescription(&self) -> Result<BSTR> {
Ok(BSTR::new())
}
fn GetHelpFile(&self) -> Result<BSTR> {
Ok(BSTR::new())
}
fn GetHelpContext(&self) -> Result<u32> {
Ok(1)
}
}

#[debugger_test(
debugger = "cdb",
commands = "
.nvlist
dx array
dx -r2 pstr
dx -r2 pcstr
dx -r2 pwstr
dx -r2 pcwstr
dx empty
dx -r2 hstring
dx out_of_memory_error
dx invalid_argument_error
",
expected_statements = r#"
array : { len=0xd } [Type: windows::core::array::Array<u8>]
[<Raw View>] [Type: windows::core::array::Array<u8>]
[len] : 0xd
[0] : 0x48 [Type: unsigned char]
[1] : 0x65 [Type: unsigned char]
[2] : 0x6c [Type: unsigned char]
[3] : 0x6c [Type: unsigned char]
[4] : 0x6f [Type: unsigned char]
[5] : 0x20 [Type: unsigned char]
[6] : 0x57 [Type: unsigned char]
[7] : 0x6f [Type: unsigned char]
[8] : 0x72 [Type: unsigned char]
[9] : 0x6c [Type: unsigned char]
[10] : 0x64 [Type: unsigned char]
[11] : 0x21 [Type: unsigned char]
[12] : 0x0 [Type: unsigned char]
pstr : "This is a PSTR" [Type: windows::core::strings::pstr::PSTR]
[<Raw View>] [Type: windows::core::strings::pstr::PSTR]
[len] : 0xe
[chars]
[0] : 84 'T' [Type: char]
[1] : 104 'h' [Type: char]
[2] : 105 'i' [Type: char]
[3] : 115 's' [Type: char]
[4] : 32 ' ' [Type: char]
[5] : 105 'i' [Type: char]
[6] : 115 's' [Type: char]
[7] : 32 ' ' [Type: char]
[8] : 97 'a' [Type: char]
[9] : 32 ' ' [Type: char]
[10] : 80 'P' [Type: char]
[11] : 83 'S' [Type: char]
[12] : 84 'T' [Type: char]
[13] : 82 'R' [Type: char]
pcstr : "This is a PCSTR" [Type: windows::core::strings::pcstr::PCSTR]
[<Raw View>] [Type: windows::core::strings::pcstr::PCSTR]
[len] : 0xf
[chars]
[0] : 84 'T' [Type: char]
[1] : 104 'h' [Type: char]
[2] : 105 'i' [Type: char]
[3] : 115 's' [Type: char]
[4] : 32 ' ' [Type: char]
[5] : 105 'i' [Type: char]
[6] : 115 's' [Type: char]
[7] : 32 ' ' [Type: char]
[8] : 97 'a' [Type: char]
[9] : 32 ' ' [Type: char]
[10] : 80 'P' [Type: char]
[11] : 67 'C' [Type: char]
[12] : 83 'S' [Type: char]
[13] : 84 'T' [Type: char]
[14] : 82 'R' [Type: char]
pwstr : "This is a PWSTR" [Type: windows::core::strings::pwstr::PWSTR]
[<Raw View>] [Type: windows::core::strings::pwstr::PWSTR]
[len] : 0xf
[chars]
[0] : 0x54 'T' [Type: char16_t]
[1] : 0x68 'h' [Type: char16_t]
[2] : 0x69 'i' [Type: char16_t]
[3] : 0x73 's' [Type: char16_t]
[4] : 0x20 ' ' [Type: char16_t]
[5] : 0x69 'i' [Type: char16_t]
[6] : 0x73 's' [Type: char16_t]
[7] : 0x20 ' ' [Type: char16_t]
[8] : 0x61 'a' [Type: char16_t]
[9] : 0x20 ' ' [Type: char16_t]
[10] : 0x50 'P' [Type: char16_t]
[11] : 0x57 'W' [Type: char16_t]
[12] : 0x53 'S' [Type: char16_t]
[13] : 0x54 'T' [Type: char16_t]
[14] : 0x52 'R' [Type: char16_t]
pcwstr : "This is a PCWSTR" [Type: windows::core::strings::pcwstr::PCWSTR]
[<Raw View>] [Type: windows::core::strings::pcwstr::PCWSTR]
[len] : 0x10
[chars]
[0] : 0x54 'T' [Type: char16_t]
[1] : 0x68 'h' [Type: char16_t]
[2] : 0x69 'i' [Type: char16_t]
[3] : 0x73 's' [Type: char16_t]
[4] : 0x20 ' ' [Type: char16_t]
[5] : 0x69 'i' [Type: char16_t]
[6] : 0x73 's' [Type: char16_t]
[7] : 0x20 ' ' [Type: char16_t]
[8] : 0x61 'a' [Type: char16_t]
[9] : 0x20 ' ' [Type: char16_t]
[10] : 0x50 'P' [Type: char16_t]
[11] : 0x43 'C' [Type: char16_t]
[12] : 0x57 'W' [Type: char16_t]
[13] : 0x53 'S' [Type: char16_t]
[14] : 0x54 'T' [Type: char16_t]
[15] : 0x52 'R' [Type: char16_t]
empty : "" [Type: windows::core::strings::hstring::HSTRING]
[<Raw View>] [Type: windows::core::strings::hstring::HSTRING]
[len] : 0x0 [Type: unsigned int]
hstring : "This is an HSTRING" [Type: windows::core::strings::hstring::HSTRING]
[<Raw View>] [Type: windows::core::strings::hstring::HSTRING]
[len] : 0x12 [Type: unsigned int]
[ref_count] : 1 [Type: windows::core::ref_count::RefCount]
[flags] : 0x0 [Type: unsigned int]
[chars]
[0] : 0x54 'T' [Type: char16_t]
[1] : 0x68 'h' [Type: char16_t]
[2] : 0x69 'i' [Type: char16_t]
[3] : 0x73 's' [Type: char16_t]
[4] : 0x20 ' ' [Type: char16_t]
[5] : 0x69 'i' [Type: char16_t]
[6] : 0x73 's' [Type: char16_t]
[7] : 0x20 ' ' [Type: char16_t]
[8] : 0x61 'a' [Type: char16_t]
[9] : 0x6e 'n' [Type: char16_t]
[10] : 0x20 ' ' [Type: char16_t]
[11] : 0x48 'H' [Type: char16_t]
[12] : 0x53 'S' [Type: char16_t]
[13] : 0x54 'T' [Type: char16_t]
[14] : 0x52 'R' [Type: char16_t]
[15] : 0x49 'I' [Type: char16_t]
[16] : 0x4e 'N' [Type: char16_t]
[17] : 0x47 'G' [Type: char16_t]
out_of_memory_error : 0x8007000e (Not enough memory resources are available to complete this operation.) [Type: windows::core::error::Error]
[<Raw View>] [Type: windows::core::error::Error]
[info] : Some [Type: enum2$<core::option::Option<windows::core::bindings::IRestrictedErrorInfo> >]
invalid_argument_error : 0x80070057 (The parameter is incorrect.) [Type: windows::core::error::Error]
[<Raw View>] [Type: windows::core::error::Error]
[info] : Some [Type: enum2$<core::option::Option<windows::core::bindings::IRestrictedErrorInfo> >]
"#
)]
fn test_debugger_visualizer() {
let string = "Hello World!\0".to_string();
let mut array = Array::<u8>::with_len(string.len());
for (i, ch) in string.as_bytes().iter().enumerate() {
array[i] = ch.clone();
}

// Test debugger visualizations for PSTR
let mut pstr_string = "This is a PSTR\0".to_string();
let pstr = PSTR::from_raw(pstr_string.as_mut_ptr());
unsafe {
assert_eq!(&pstr_string.as_bytes()[..(pstr_string.len() - 1)], pstr.as_bytes());
}

// Test debugger visualizations for PCSTR
let pcstr_string = "This is a PCSTR\0".to_string();
let pcstr = PCSTR::from_raw(pcstr_string.as_ptr());
unsafe {
assert_eq!(&pcstr_string.as_bytes()[..(pcstr_string.len() - 1)], pcstr.as_bytes());
}

// Test debugger visualizations for PWSTR
let mut pwstr_string: Vec<u16> = vec![84, 104, 105, 115, 32, 105, 115, 32, 97, 32, 80, 87, 83, 84, 82, 0];
let pwstr = PWSTR::from_raw(pwstr_string.as_mut_ptr());
unsafe {
assert_eq!(&pwstr_string.as_slice()[..(pwstr_string.len() - 1)], pwstr.as_wide());
}

// Test debugger visualizations for PCWSTR
let pcwstr_string: Vec<u16> = vec![84, 104, 105, 115, 32, 105, 115, 32, 97, 32, 80, 67, 87, 83, 84, 82, 0];
let pcwstr = PCWSTR::from_raw(pcwstr_string.as_ptr());
unsafe {
assert_eq!(&pcwstr_string.as_slice()[..(pcwstr_string.len() - 1)], pcwstr.as_wide());
}

// Test debugger visualizations for HSTRING
let empty = HSTRING::new();
assert!(empty.is_empty());

let hstring = HSTRING::from("This is an HSTRING");
assert!(!hstring.is_empty());
assert!(hstring.len() == 18);

let test: IErrorInfo = Test.into();

unsafe {
// Test debugger visualizations for Error
let result = test.GetGUID();
let out_of_memory_error = result.unwrap_err();
assert_eq!(out_of_memory_error.code(), E_OUTOFMEMORY);
assert_eq!(out_of_memory_error.message(), "Out of memory message");

let result = test.GetSource();
let invalid_argument_error = result.unwrap_err();
assert_eq!(invalid_argument_error.code(), E_INVALIDARG);
assert_eq!(invalid_argument_error.message(), "Invalid argument message");
__break();
}
}
11 changes: 11 additions & 0 deletions crates/tools/windows/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,17 @@ interface = ["windows-interface"]
}
}

file.write_all(
r#"
# UNSTABLE FEATURES (requires Rust nightly)
# Enable to use the #[debugger_visualizer] attribute.
debugger_visualizer = []
"#
.as_bytes(),
)
.unwrap();

std::fs::copy("license-mit", "crates/libs/windows/license-mit").unwrap();
std::fs::copy("license-apache-2.0", "crates/libs/windows/license-apache-2.0").unwrap();
}
Expand Down
Loading

0 comments on commit 29e5510

Please sign in to comment.