我正在尝试使应用程序状态在 Rust 中工作。
\n我从windows-rs 示例行 357获取了 Rust 应用程序状态部分,并对其进行了一些修改以适用于我的代码。唯一的问题是,它没有按预期工作......
\n正如您从下面代码中的注释中看到的,我的问题是,在使用上述两个函数后,我的指针 ( state) 丢失了前两位数字。
每次我运行这个时,前两位数字总是丢失。
\n我该如何解决这个问题?
\nextern "system" fn wndproc(window: HWND, message: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT {\n unsafe {\n match message as u32 {\n WM_NCCREATE => {\n // ORIGINAL address given to CreateWindowExW: 0xb678ddf730\n let cs = lparam as *const CREATESTRUCTW;\n let state = (*cs).lpCreateParams as *mut State;\n \n println!("{:?}", state); // OUTPUT: 0xb678ddf730 (correct)\n\n // After using the two functions:\n SetWindowLongW(window, GWLP_USERDATA, state as i32);\n\n let state = GetWindowLongW(window, GWLP_USERDATA) as *mut State;\n\n println!("{:?}", state); // OUTPUT: 0x78ddf730 (missing first 2 digits "b6")\n 1\n }\n ...\nRun Code Online (Sandbox Code Playgroud)\n完整代码:
\n#![allow(dead_code)]\n//#![allow(unused_)]\n#![allow(unused_variables)]\n\nuse windows_sys::{\n Win32::Foundation::*,\n Win32::Graphics::Gdi::ValidateRect,\n Win32::System::LibraryLoader::GetModuleHandleW,\n Win32::UI::WindowsAndMessaging::*,\n};\n\nfn u16_str(string: &str) -> Vec<u16> {\n let mut result: Vec<u16> = string.encode_utf16().collect();\n result.push(0);\n result\n}\n\n#[derive(Debug)]\nstruct State {\n name: String,\n}\n\nfn main() {\n unsafe {\n let instance = GetModuleHandleW(std::ptr::null());\n\n let wc = WNDCLASSEXW {\n cbSize: std::mem::size_of::<WNDCLASSEXW>() as u32,\n hCursor: LoadCursorW(0, IDC_ARROW),\n hInstance: instance,\n lpszClassName: u16_str("asd").as_ptr(),\n style: CS_HREDRAW | CS_VREDRAW,\n lpfnWndProc: Some(wndproc),\n cbClsExtra: 0,\n cbWndExtra: 0,\n hIcon: 0,\n hbrBackground: 0,\n lpszMenuName: std::ptr::null(),\n hIconSm: 0,\n };\n\n RegisterClassExW(&wc);\n\n let mut state = State {\n name: String::from("name"),\n };\n\n println!("{:?}", &mut state as *mut _);\n\n CreateWindowExW(\n 0,\n u16_str("asd").as_ptr(),\n u16_str("Ablak 1 \xc3\xa1\xc3\xa9\xc5\x91\xc3\xbc\xc5\xb1\xc3\xb6").as_ptr(),\n WS_OVERLAPPEDWINDOW | WS_VISIBLE,\n CW_USEDEFAULT,\n CW_USEDEFAULT,\n CW_USEDEFAULT,\n CW_USEDEFAULT,\n 0, 0, instance, &mut state as *mut _ as _,\n );\n\n let mut message = std::mem::zeroed();\n\n while GetMessageW(&mut message, 0, 0, 0) != 0 {\n DispatchMessageW(&message);\n }\n }\n}\n\nextern "system" fn wndproc(window: HWND, message: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT {\n unsafe {\n match message as u32 {\n WM_NCCREATE => {\n let cs = lparam as *const CREATESTRUCTW;\n let state = (*cs).lpCreateParams as *mut State;\n\n println!("{:?}", state);\n\n SetWindowLongW(window, GWLP_USERDATA, state as i32);\n\n let state = GetWindowLongW(window, GWLP_USERDATA) as *mut State;\n\n println!("{:?}", state);\n 1\n }\n WM_PAINT => {\n //let state = GetWindowLongPtrW(window, GWLP_USERDATA) as *mut State;\n //println!("{:?}", state);\n //println!("{}", GetLastError());\n println!("paint");\n ValidateRect(window, std::ptr::null());\n 0\n }\n WM_DESTROY => {\n println!("WM_DESTROY");\n PostQuitMessage(0);\n 0\n }\n _ => DefWindowProcW(window, message, wparam, lparam),\n }\n }\n}\n\nRun Code Online (Sandbox Code Playgroud)\n货物.toml:
\n...\n\n[dependencies.windows-sys]\nversion = "0.36.1"\nfeatures = [\n "Win32_Foundation",\n "Win32_System_LibraryLoader",\n "Win32_Graphics_Gdi",\n "Win32_Graphics_Direct2D",\n "Win32_UI_WindowsAndMessaging",\n]\nRun Code Online (Sandbox Code Playgroud)\n
和APIGetWindowLongW调用SetWindowLongW只能存储 32 位值。32 位是 32 位体系结构的指针大小。由于您的目标是 64 位架构,因此您必须遵循文档中的建议:
如果您要检索指针或句柄,则此函数已被
GetWindowLongPtrW函数取代。(指针和句柄在 32 位 Windows 上为 32 位,在 64 位 Windows 上为 64 位。)要编写与 32 位和 64 位版本的 Windows 兼容的代码,请使用GetWindowLongPtrW.
和
该函数已被
SetWindowLongPtr函数取代。要编写与 32 位和 64 位版本的 Windows 兼容的代码,请使用该SetWindowLongPtr函数。
你必须更换
SetWindowLongW(window, GWLP_USERDATA, state as i32);
// ^^^^^^ truncates pointer to 32 bits
Run Code Online (Sandbox Code Playgroud)
和
SetWindowLongPtrW(window, GWLP_USERDATA, state as isize);
Run Code Online (Sandbox Code Playgroud)
GetWindowLongW只需要将呼叫替换为呼叫即可GetWindowLongPtrW。此处不需要进行其他更改。
请注意,虽然在针对 64 位体系结构时,-Ptr可以通过windows和windows-sys包立即使用这些变体,但对于 32 位目标来说,它们缺失(请参阅此 GitHub 问题)。您可以提供自己的实现,例如
#[allow(non_snake_case)]
#[cfg(target_pointer_width = "32")]
unsafe fn SetWindowLongPtrW(window: HWND, index: WINDOW_LONG_PTR_INDEX, value: isize) -> isize {
SetWindowLongW(window, index, value as _) as _
}
#[allow(non_snake_case)]
#[cfg(target_pointer_width = "32")]
unsafe fn GetWindowLongPtrW(window: HWND, index: WINDOW_LONG_PTR_INDEX) -> isize {
GetWindowLongA(window, index) as _
}
Run Code Online (Sandbox Code Playgroud)
有了它,您就可以简单地调用GetWindowLongPtrW/SetWindowLongPtrW而不考虑目标体系结构,就像使用 Windows SDK 标头编写 C/C++ 代码一样。