Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add macros for creating null-terminated string literals to `windows-s…
…ys` (#2043)
- Loading branch information
Showing
11 changed files
with
177 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
/// A literal UTF-8 string with a trailing null terminator. | ||
#[macro_export] | ||
macro_rules! s { | ||
($s:literal) => { | ||
::core::concat!($s, '\0').as_ptr() | ||
}; | ||
} | ||
|
||
/// A literal UTF-16 wide string with a trailing null terminator. | ||
#[macro_export] | ||
macro_rules! w { | ||
($s:literal) => {{ | ||
const INPUT: &[u8] = $s.as_bytes(); | ||
const OUTPUT_LEN: usize = $crate::core::utf16_len(INPUT) + 1; | ||
const OUTPUT: &[u16; OUTPUT_LEN] = { | ||
let mut buffer = [0; OUTPUT_LEN]; | ||
let mut input_pos = 0; | ||
let mut output_pos = 0; | ||
while let Some((mut code_point, new_pos)) = $crate::core::decode_utf8_char(INPUT, input_pos) { | ||
input_pos = new_pos; | ||
if code_point <= 0xffff { | ||
buffer[output_pos] = code_point as u16; | ||
output_pos += 1; | ||
} else { | ||
code_point -= 0x10000; | ||
buffer[output_pos] = 0xd800 + (code_point >> 10) as u16; | ||
output_pos += 1; | ||
buffer[output_pos] = 0xdc00 + (code_point & 0x3ff) as u16; | ||
output_pos += 1; | ||
} | ||
} | ||
&{ buffer } | ||
}; | ||
OUTPUT.as_ptr() | ||
}}; | ||
} | ||
|
||
// Ensures that the macros are exported from the `windows::core` module. | ||
pub use s; | ||
pub use w; | ||
|
||
#[doc(hidden)] | ||
pub const fn decode_utf8_char(bytes: &[u8], mut pos: usize) -> Option<(u32, usize)> { | ||
if bytes.len() == pos { | ||
return None; | ||
} | ||
let ch = bytes[pos] as u32; | ||
pos += 1; | ||
if ch <= 0x7f { | ||
return Some((ch, pos)); | ||
} | ||
if (ch & 0xe0) == 0xc0 { | ||
if bytes.len() - pos < 1 { | ||
return None; | ||
} | ||
let ch2 = bytes[pos] as u32; | ||
pos += 1; | ||
if (ch2 & 0xc0) != 0x80 { | ||
return None; | ||
} | ||
let result: u32 = ((ch & 0x1f) << 6) | (ch2 & 0x3f); | ||
if result <= 0x7f { | ||
return None; | ||
} | ||
return Some((result, pos)); | ||
} | ||
if (ch & 0xf0) == 0xe0 { | ||
if bytes.len() - pos < 2 { | ||
return None; | ||
} | ||
let ch2 = bytes[pos] as u32; | ||
pos += 1; | ||
let ch3 = bytes[pos] as u32; | ||
pos += 1; | ||
if (ch2 & 0xc0) != 0x80 || (ch3 & 0xc0) != 0x80 { | ||
return None; | ||
} | ||
let result = ((ch & 0x0f) << 12) | ((ch2 & 0x3f) << 6) | (ch3 & 0x3f); | ||
if result <= 0x7ff || (0xd800 <= result && result <= 0xdfff) { | ||
return None; | ||
} | ||
return Some((result, pos)); | ||
} | ||
if (ch & 0xf8) == 0xf0 { | ||
if bytes.len() - pos < 3 { | ||
return None; | ||
} | ||
let ch2 = bytes[pos] as u32; | ||
pos += 1; | ||
let ch3 = bytes[pos] as u32; | ||
pos += 1; | ||
let ch4 = bytes[pos] as u32; | ||
pos += 1; | ||
if (ch2 & 0xc0) != 0x80 || (ch3 & 0xc0) != 0x80 || (ch4 & 0xc0) != 0x80 { | ||
return None; | ||
} | ||
let result = ((ch & 0x07) << 18) | ((ch2 & 0x3f) << 12) | ((ch3 & 0x3f) << 6) | (ch4 & 0x3f); | ||
if result <= 0xffff || 0x10ffff < result { | ||
return None; | ||
} | ||
return Some((result, pos)); | ||
} | ||
None | ||
} | ||
|
||
#[doc(hidden)] | ||
pub const fn utf16_len(bytes: &[u8]) -> usize { | ||
let mut pos = 0; | ||
let mut len = 0; | ||
while let Some((code_point, new_pos)) = decode_utf8_char(bytes, pos) { | ||
pos = new_pos; | ||
len += if code_point <= 0xffff { 1 } else { 2 }; | ||
} | ||
len | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,8 @@ | ||
mod literals; | ||
|
||
#[doc(hidden)] | ||
pub use literals::*; | ||
|
||
#[repr(C)] | ||
pub struct GUID { | ||
pub data1: u32, | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
[package] | ||
name = "sample_message_box_sys" | ||
version = "0.0.0" | ||
edition = "2018" | ||
|
||
[dependencies.windows-sys] | ||
path = "../../libs/sys" | ||
features = [ | ||
"Win32_Foundation", | ||
"Win32_UI_WindowsAndMessaging", | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
use windows_sys::{core::*, Win32::UI::WindowsAndMessaging::*}; | ||
|
||
fn main() { | ||
unsafe { | ||
MessageBoxA(0, s!("Ansi"), s!("World"), MB_OK); | ||
MessageBoxW(0, w!("Wide"), w!("World"), MB_OK); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
use windows_sys::{core::*, Win32::System::Registry::*, Win32::System::Threading::*, Win32::UI::WindowsAndMessaging::*}; | ||
|
||
/// Tests a few APIs that have reserved parameters to ensure they can be called with `None`. | ||
#[test] | ||
fn test() { | ||
unsafe { | ||
assert_eq!(InSendMessageEx(std::ptr::null_mut()), ISMEX_NOSEND); | ||
assert!(CreateThreadpool(std::ptr::null_mut()) != 0); | ||
assert_eq!(TrackPopupMenu(0, TPM_LEFTBUTTON, 1, 2, 0, 0, std::ptr::null()), 0); | ||
|
||
let mut key = 0; | ||
RegOpenKeyExA(HKEY_CLASSES_ROOT, s!(r".txt"), 0, KEY_QUERY_VALUE, &mut key); | ||
let mut len = 0; | ||
RegQueryValueExA(key, s!("Content Type"), std::ptr::null_mut(), std::ptr::null_mut(), std::ptr::null_mut(), &mut len); | ||
let mut buffer = vec![0u8; (len) as usize]; | ||
RegQueryValueExA(key, s!("Content Type"), std::ptr::null_mut(), std::ptr::null_mut(), buffer.as_mut_ptr() as _, &mut len); | ||
assert_eq!(String::from_utf8_lossy(&buffer), "text/plain\0"); | ||
} | ||
} |
File renamed without changes.