ReadProcessMemory returning errors - windows

When I use the ReadProcessMemory function from the windows-rs package it returns 0. This is wrong, so I used the GetLastError() function and it returned "Only part of a ReadProcessMemory or WriteProcessMemory request was completed."
Here is the code for ReadProcessMemory:
unsafe{
let mut healthValue: i32 = 0;
ReadProcessMemory(
hProcess,
0xE6A848 as *mut c_void,
healthValue as *mut c_void,
std::mem::size_of::<i32> as usize,
&mut 0
);
println!("{}", healthValue);
match GetLastError().ok() {
Ok(_) => println!("no eror"),
Err(t) => println!("error: {}", t),
}
};
The code to get handle to the process:
let hProcess: HANDLE;
unsafe{
match OpenProcess(PROCESS_ALL_ACCESS, false, procId as u32) {
Ok(T) => hProcess = T,
Err(A) => {
hProcess = INVALID_HANDLE_VALUE;
println!("hproc is INVALID");
}
}
}
I have checked and the ProcId is right, I have used cheat engine to get the memory address, both apps are run in 32-bit, and my trainer is being run as admin. None of these have helped.

Fixed it by changing healthValue as *mut c_void to ptr::addr_of_mut!(healthValue) as *mut c_void.

Related

Why do SetWindowLongW and GetWindowLongW strip pointers' first 2 digits?

I am trying to make application state working in Rust.
I got the Rust application state part from windows-rs sample line 357 and modified it a little to work with my code. The only problem is, it did not work as expected...
As you can see from the comments in the code below, my problem is that after using the mentioned two functions my pointer (state) loses its first two digits.
Every time I run this, the first two digits are always missing.
How can I solve this?
extern "system" fn wndproc(window: HWND, message: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT {
unsafe {
match message as u32 {
WM_NCCREATE => {
// ORIGINAL address given to CreateWindowExW: 0xb678ddf730
let cs = lparam as *const CREATESTRUCTW;
let state = (*cs).lpCreateParams as *mut State;
println!("{:?}", state); // OUTPUT: 0xb678ddf730 (correct)
// After using the two functions:
SetWindowLongW(window, GWLP_USERDATA, state as i32);
let state = GetWindowLongW(window, GWLP_USERDATA) as *mut State;
println!("{:?}", state); // OUTPUT: 0x78ddf730 (missing first 2 digits "b6")
1
}
...
Full code:
#![allow(dead_code)]
//#![allow(unused_)]
#![allow(unused_variables)]
use windows_sys::{
Win32::Foundation::*,
Win32::Graphics::Gdi::ValidateRect,
Win32::System::LibraryLoader::GetModuleHandleW,
Win32::UI::WindowsAndMessaging::*,
};
fn u16_str(string: &str) -> Vec<u16> {
let mut result: Vec<u16> = string.encode_utf16().collect();
result.push(0);
result
}
#[derive(Debug)]
struct State {
name: String,
}
fn main() {
unsafe {
let instance = GetModuleHandleW(std::ptr::null());
let wc = WNDCLASSEXW {
cbSize: std::mem::size_of::<WNDCLASSEXW>() as u32,
hCursor: LoadCursorW(0, IDC_ARROW),
hInstance: instance,
lpszClassName: u16_str("asd").as_ptr(),
style: CS_HREDRAW | CS_VREDRAW,
lpfnWndProc: Some(wndproc),
cbClsExtra: 0,
cbWndExtra: 0,
hIcon: 0,
hbrBackground: 0,
lpszMenuName: std::ptr::null(),
hIconSm: 0,
};
RegisterClassExW(&wc);
let mut state = State {
name: String::from("name"),
};
println!("{:?}", &mut state as *mut _);
CreateWindowExW(
0,
u16_str("asd").as_ptr(),
u16_str("Ablak 1 áéőüűö").as_ptr(),
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
0, 0, instance, &mut state as *mut _ as _,
);
let mut message = std::mem::zeroed();
while GetMessageW(&mut message, 0, 0, 0) != 0 {
DispatchMessageW(&message);
}
}
}
extern "system" fn wndproc(window: HWND, message: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT {
unsafe {
match message as u32 {
WM_NCCREATE => {
let cs = lparam as *const CREATESTRUCTW;
let state = (*cs).lpCreateParams as *mut State;
println!("{:?}", state);
SetWindowLongW(window, GWLP_USERDATA, state as i32);
let state = GetWindowLongW(window, GWLP_USERDATA) as *mut State;
println!("{:?}", state);
1
}
WM_PAINT => {
//let state = GetWindowLongPtrW(window, GWLP_USERDATA) as *mut State;
//println!("{:?}", state);
//println!("{}", GetLastError());
println!("paint");
ValidateRect(window, std::ptr::null());
0
}
WM_DESTROY => {
println!("WM_DESTROY");
PostQuitMessage(0);
0
}
_ => DefWindowProcW(window, message, wparam, lparam),
}
}
}
Cargo.toml:
...
[dependencies.windows-sys]
version = "0.36.1"
features = [
"Win32_Foundation",
"Win32_System_LibraryLoader",
"Win32_Graphics_Gdi",
"Win32_Graphics_Direct2D",
"Win32_UI_WindowsAndMessaging",
]
The GetWindowLongW and SetWindowLongW API calls can only store 32-bit values. 32 bits is the size of a pointer for 32-bit architectures. Since you are targeting a 64-bit architecture, you'll have to follow the advice from the documentation:
If you are retrieving a pointer or a handle, this function has been superseded by the GetWindowLongPtrW function. (Pointers and handles are 32 bits on 32-bit Windows and 64 bits on 64-bit Windows.) To write code that is compatible with both 32-bit and 64-bit versions of Windows, use GetWindowLongPtrW.
and
This function has been superseded by the SetWindowLongPtr function. To write code that is compatible with both 32-bit and 64-bit versions of Windows, use the SetWindowLongPtr function.
You'll have to replace
SetWindowLongW(window, GWLP_USERDATA, state as i32);
// ^^^^^^ truncates pointer to 32 bits
with
SetWindowLongPtrW(window, GWLP_USERDATA, state as isize);
The GetWindowLongW calls merely need to be replaced with GetWindowLongPtrW calls. Other changes aren't required here.
Note that while the -Ptr variants are immediately available through the windows and windows-sys crates when targeting a 64-bit architecture, they are missing for 32-bit targets (see this GitHub issue). You can provide your own implementation, e.g.
#[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 _
}
With that in place you can simply call GetWindowLongPtrW/SetWindowLongPtrW irrespective of target architecture, same as when writing C/C++ code using the Windows SDK headers.

UpdateLayeredWindow returns code 6 (ERROR_INVALID_HANDLE)

I'm trying to make a fully transparent window with winapi to later serve as an overlay. It seems to work as far as creating window and registering the class goes, but the UpdateLayeredWindow function seems to have issues with the window handle as GetLastError returns code 6. I'm not sure what exactly causes it.
Without Updating window appears, is interactable, and works ok. After my attempt to update it, it disappears (not transparent though, since events pass to the desktop), and I get error 6.
A puzzling thing is that I still get the messages as the loop doesn't stop until I force quit the process.
#![windows_subsystem = "windows"]
use kernel32::{GetLastError, GetModuleHandleW};
use std::ffi::OsStr;
use std::iter::once;
use std::os::windows::ffi::OsStrExt;
use std::ptr;
use std::ptr::{null, null_mut};
use user32::CreateWindowExW;
use winapi::shared::minwindef::{HINSTANCE, LPARAM, LRESULT, UINT, WPARAM};
use winapi::shared::windef::{HDC__, HWND, HWND__, POINT, SIZE};
use winapi::um::wingdi::{
CreateCompatibleDC, DeleteDC, AC_SRC_ALPHA, AC_SRC_OVER, BLENDFUNCTION, RGB,
};
use winapi::um::winuser::{
DefWindowProcW, DispatchMessageW, GetDC, GetMessageW, RegisterClassW, ReleaseDC,
TranslateMessage, UpdateLayeredWindow, CS_HREDRAW, CS_OWNDC, CS_VREDRAW, CW_USEDEFAULT, MSG,
ULW_COLORKEY, WNDCLASSW, WS_EX_LAYERED, WS_EX_TOOLWINDOW, WS_OVERLAPPED, WS_VISIBLE,
};
fn win32_string(value: &str) -> Vec<u16> {
OsStr::new(value).encode_wide().chain(once(0)).collect()
}
struct BasicWindow {
window_class: WNDCLASSW,
window_handle: *mut HWND__,
mem_DC: Option<*mut HDC__>,
screen_DC: Option<*mut HDC__>,
}
impl BasicWindow {
fn new(class_name: String, window_name: String) -> Self {
unsafe {
let hinstance = GetModuleHandleW(null_mut());
let wnd_class = WNDCLASSW {
style: CS_HREDRAW | CS_OWNDC | CS_VREDRAW,
lpfnWndProc: Some(DefWindowProcW),
hInstance: hinstance as HINSTANCE,
lpszClassName: win32_string(&class_name).as_ptr(),
cbClsExtra: 0,
cbWndExtra: 0,
hIcon: null_mut(),
hCursor: null_mut(),
hbrBackground: null_mut(),
lpszMenuName: null_mut(),
};
let atom = RegisterClassW(&wnd_class);
let handle: *mut HWND__ = CreateWindowExW(
WS_EX_LAYERED | WS_EX_TOOLWINDOW,
win32_string(&class_name).as_ptr(),
win32_string(&window_name).as_ptr(),
WS_OVERLAPPED | WS_VISIBLE,
0,
0,
1920,
1080,
null_mut(),
null_mut(),
hinstance,
null_mut(),
) as *mut HWND__;
println!("handle: {:?}", handle);
return Self {
window_class: wnd_class,
window_handle: handle,
mem_DC: None,
screen_DC: None,
};
}
}
pub unsafe fn make_transparent(&mut self) {
self.screen_DC = Some(GetDC(null_mut()));
self.mem_DC = Some(CreateCompatibleDC(GetDC(self.window_handle))); //Some(CreateCompatibleDC(self.screen_DC.unwrap()));
let mut blend_s = BLENDFUNCTION {
BlendOp: AC_SRC_OVER,
BlendFlags: 0,
SourceConstantAlpha: 255,
AlphaFormat: AC_SRC_ALPHA,
};
let outcome = UpdateLayeredWindow(
self.window_handle,
self.screen_DC.unwrap(),
&mut POINT { x: 0, y: 0 },
&mut SIZE { cx: 1920, cy: 1080 },
self.mem_DC.unwrap(),
&mut POINT { x: 0, y: 0 },
RGB(255, 255, 255),
&mut blend_s,
ULW_COLORKEY,
);
println!("outcome: {:?}", outcome);
println!("err was: {:?}", GetLastError());
}
// pub unsafe fn event_job(hWnd: HWND__, Msg: UINT, wParam: WPARAM, lParam: LPARAM) -> LRESULT {
//
// }
}
fn main() {
let mut win: BasicWindow = BasicWindow::new("hewwo".to_owned(), "UwU".to_owned());
unsafe {
win.make_transparent();
loop {
let mut msg: MSG = std::mem::uninitialized();
if GetMessageW(&mut msg as *mut MSG, win.window_handle, 0, 0).is_positive() {
TranslateMessage(&msg as *const MSG);
DispatchMessageW(&msg as *const MSG);
} else {
break;
}
}
match win.mem_DC {
Some(mut hDC) => {
println!("releasing mem_dc with outcome: {:?}", DeleteDC(hDC));
println!(
"releasing screen_dc with outcome: {:?}",
ReleaseDC(win.window_handle, win.screen_DC.unwrap())
);
}
_ => {}
}
}
}
Cargo.toml:
[package]
name = "catso"
version = "0.1.0"
authors = ["HerbyBoi <grassyZest#gmail.com>"]
edition = "2018"
[dependencies]
winapi = "0.3.9"
widestring = "0.4.3"
user32-sys = "0.2.0"
kernel32-sys="0.2.2"
[features]
default=["winapi/winuser","winapi/minwindef","winapi/windef","winapi/wingdi"]

WMI releases my implementation of IWbemQuerySink too many times (ExecQueryAsync): refcount turns negative

I've implemented the IWbemQuerySink in rust, in order to use ExecQueryAsync. Code is available in this pull request but I'll post the relevant bits here.
TLDR;
WMI is calling Release() 5 times on my QuerySink implementation, 1 which is understandable, and 4 which are not... There is only 1 call to AddRef by WMI, so the question is: where do this 4 other calls to Release comes from and is there a way to prevent them from happening?
With a lot of details
Here is a simplified implementation, it is working great:
use winapi::{
um::wbemcli::{
{IWbemClassObject,IWbemObjectSink, IWbemObjectSinkVtbl},
WBEM_S_NO_ERROR,
},
shared::{
ntdef::HRESULT,
wtypes::BSTR,
},
ctypes::{
c_long,
},
};
use com_impl::{ComImpl, VTable, Refcount};
use wio::com::ComPtr;
#[repr(C)]
#[derive(ComImpl)]
#[interfaces(IWbemObjectSink)]
pub struct QuerySink {
vtbl: VTable<IWbemObjectSinkVtbl>,
refcount: Refcount,
}
impl QuerySink {
pub fn new() -> ComPtr<IWbemObjectSink> {
let ptr = QuerySink::create_raw();
let ptr = ptr as *mut IWbemObjectSink;
unsafe { ComPtr::from_raw(ptr) }
}
}
// AddRef and Release methods are provided by com_impl
#[com_impl::com_impl]
unsafe impl IWbemObjectSink for QuerySink {
pub unsafe fn indicate(
&self,
_lObjectCount: c_long,
_apObjArray: *mut *mut IWbemClassObject
) -> HRESULT {
WBEM_S_NO_ERROR as i32
}
pub unsafe fn set_status(
&self,
_lFlags: c_long,
_hResult: HRESULT,
_strParam: BSTR,
_pObjParam: *mut IWbemClassObject
) -> HRESULT {
WBEM_S_NO_ERROR as i32
}
}
Let's try to use it in a simple call to ExecQueryAsync:
pub fn exec_async_query_native_wrapper(
&self,
query: impl AsRef<str>,
) -> Result<(), WMIError> {
let query_language = BStr::from_str("WQL")?;
let query = BStr::from_str(query.as_ref())?;
let p_sink: ComPtr<IWbemObjectSink> = QuerySink::new();
unsafe {
check_hres((*self.svc()).ExecQueryAsync(
query_language.as_bstr(),
query.as_bstr(),
WBEM_FLAG_BIDIRECTIONAL as i32,
ptr::null_mut(),
p_sink.as_raw(),
))?;
}
Ok(())
}
When executing it in a test, this code panics because the release function is called too many times, and the Refcount becomes negative:
attempt to subtract with overflow', C:\Users\apennamen\.cargo\registry\src\github.com-1ecc6299db9ec823\com-impl-0.1.1\src\lib.rs:139:9
stack backtrace:
0: std::panicking::begin_panic_handler
at /rustc/b32e6e6ac8921035177256ab6806e6ab0d4b9b94\/library\std\src\panicking.rs:493
1: core::panicking::panic_fmt
at /rustc/b32e6e6ac8921035177256ab6806e6ab0d4b9b94\/library\core\src\panicking.rs:92
2: core::panicking::panic
at /rustc/b32e6e6ac8921035177256ab6806e6ab0d4b9b94\/library\core\src\panicking.rs:50
3: com_impl::Refcount::release
at C:\Users\apennamen\.cargo\registry\src\github.com-1ecc6299db9ec823\com-impl-0.1.1\src\lib.rs:139
4: wmi::query_sink::QuerySink::__com_impl__IUnknown__Release
at .\src\query_sink.rs:31
5: CoMarshalInterface
6: CoMarshalInterface
.....
After some tests, I found that the Release method is called 4 times more than it should be by WMI. So when adding 4 calls to AddRef, the code works just fine. This is of course not satisfying as maybe tomorrow it will be 5 calls, or 10 or 2...
I don't know how to handle this problem, hopefully someone else ran into it
This is a hacky working code:
pub fn exec_async_query_native_wrapper(
&self,
query: impl AsRef<str>,
) -> Result<(), WMIError> {
let query_language = BStr::from_str("WQL")?;
let query = BStr::from_str(query.as_ref())?;
let p_sink: ComPtr<IWbemObjectSink> = QuerySink::new();
unsafe {
// FIXME hack the RefCount
for _ in 0..4 { p_sink.AddRef(); }
check_hres((*self.svc()).ExecQueryAsync(
query_language.as_bstr(),
query.as_bstr(),
WBEM_FLAG_BIDIRECTIONAL as i32,
ptr::null_mut(),
p_sink.as_raw(),
))?;
}
Ok(())
}
}
Thank you for reading this far :)
EDIT :
Here is the expanded macro code:
#[cfg(feature = "async-query")]
pub(crate) mod query_sink {
use winapi::{
um::wbemcli::{
{IWbemClassObject, IWbemObjectSink, IWbemObjectSinkVtbl}, WBEM_S_NO_ERROR,
WBEM_STATUS_COMPLETE,
},
shared::{
ntdef::HRESULT,
wtypes::BSTR,
winerror::{E_POINTER, E_FAIL},
},
ctypes::{c_long},
};
use com_impl::{ComImpl, VTable, Refcount};
use log::{trace, warn};
use std::ptr::NonNull;
use wio::com::ComPtr;
use crate::result_enumerator::IWbemClassWrapper;
use crate::WMIError;
/// Implementation for [IWbemObjectSink](https://learn.microsoft.com/en-us/windows/win32/api/wbemcli/nn-wbemcli-iwbemobjectsink).
/// This [Sink](https://en.wikipedia.org/wiki/Sink_(computing))
/// receives asynchronously the result of the query,
/// through Indicate calls. When finished,the SetStatus method
/// is called.
/// # <https://learn.microsoft.com/fr-fr/windows/win32/wmisdk/example--getting-wmi-data-from-the-local-computer-asynchronously>
#[repr(C)]
#[interfaces(IWbemObjectSink)]
pub struct QuerySink {
vtbl: VTable<IWbemObjectSinkVtbl>,
refcount: Refcount,
}
impl QuerySink {
fn create_raw() -> *mut Self {
Box::into_raw(Box::new(QuerySink {
vtbl: <Self as com_impl::BuildVTable<_>>::static_vtable(),
refcount: Default::default(),
}))
}
}
unsafe impl com_impl::BuildVTable<winapi::um::unknwnbase::IUnknownVtbl> for QuerySink {
const VTBL: winapi::um::unknwnbase::IUnknownVtbl = winapi::um::unknwnbase::IUnknownVtbl {
AddRef: Self::__com_impl__IUnknown__AddRef,
Release: Self::__com_impl__IUnknown__Release,
QueryInterface: Self::__com_impl__IUnknown__QueryInterface,
};
fn static_vtable() -> com_impl::VTable<winapi::um::unknwnbase::IUnknownVtbl> {
com_impl::VTable::new(&Self::VTBL)
}
}
#[allow(non_snake_case)]
impl QuerySink {
#[inline(never)]
unsafe extern "system" fn __com_impl__IUnknown__AddRef(
this: *mut winapi::um::unknwnbase::IUnknown,
) -> u32 {
let this = &*(this as *const Self);
this.refcount.add_ref()
}
#[inline(never)]
unsafe extern "system" fn __com_impl__IUnknown__Release(
this: *mut winapi::um::unknwnbase::IUnknown,
) -> u32 {
let ptr = this as *mut Self;
let count = (*ptr).refcount.release();
if count == 0 {
Box::from_raw(ptr);
}
count
}
#[inline(never)]
unsafe extern "system" fn __com_impl__IUnknown__QueryInterface(
this: *mut winapi::um::unknwnbase::IUnknown,
riid: *const winapi::shared::guiddef::IID,
ppv: *mut *mut winapi::ctypes::c_void,
) -> winapi::shared::winerror::HRESULT {
if ppv.is_null() {
return winapi::shared::winerror::E_POINTER;
}
if winapi::shared::guiddef::IsEqualIID(
&*riid,
&<winapi::um::unknwnbase::IUnknown as winapi::Interface>::uuidof(),
) || winapi::shared::guiddef::IsEqualIID(
&*riid,
&<IWbemObjectSink as winapi::Interface>::uuidof(),
) {
*ppv = this as *mut winapi::ctypes::c_void;
winapi::shared::winerror::S_OK
} else {
*ppv = std::ptr::null_mut();
winapi::shared::winerror::E_NOINTERFACE
}
}
}
impl QuerySink {
pub fn new() -> ComPtr<IWbemObjectSink> {
let ptr = QuerySink::create_raw();
let ptr = ptr as *mut IWbemObjectSink;
unsafe { ComPtr::from_raw(ptr) }
}
}
unsafe impl com_impl::BuildVTable<IWbemObjectSinkVtbl> for QuerySink {
const VTBL: IWbemObjectSinkVtbl = IWbemObjectSinkVtbl {
parent: <Self as com_impl::BuildVTable<_>>::VTBL,
Indicate: Self::__com_impl_stub__IWbemObjectSink__Indicate,
SetStatus: Self::__com_impl_stub__IWbemObjectSink__SetStatus,
};
fn static_vtable() -> com_impl::VTable<IWbemObjectSinkVtbl> {
com_impl::VTable::new(&Self::VTBL)
}
}
#[allow(non_snake_case)]
impl QuerySink {
#[inline(never)]
unsafe extern "system" fn __com_impl_stub__IWbemObjectSink__Indicate(
this: *mut IWbemObjectSink,
__com_arg_0: c_long,
__com_arg_1: *mut *mut IWbemClassObject,
) -> HRESULT {
let this = &*(this as *const Self);
Self::__com_impl_body__IWbemObjectSink__Indicate(this, __com_arg_0, __com_arg_1)
}
#[inline(never)]
unsafe extern "system" fn __com_impl_stub__IWbemObjectSink__SetStatus(
this: *mut IWbemObjectSink,
__com_arg_0: c_long,
__com_arg_1: HRESULT,
__com_arg_2: BSTR,
__com_arg_3: *mut IWbemClassObject,
) -> HRESULT {
let this = &*(this as *const Self);
Self::__com_impl_body__IWbemObjectSink__SetStatus(
this,
__com_arg_0,
__com_arg_1,
__com_arg_2,
__com_arg_3,
)
}
#[inline(always)]
unsafe extern "system" fn __com_impl_body__IWbemObjectSink__Indicate(
&self,
lObjectCount: c_long,
apObjArray: *mut *mut IWbemClassObject,
) -> HRESULT {
WBEM_S_NO_ERROR as i32
}
#[inline(always)]
unsafe extern "system" fn __com_impl_body__IWbemObjectSink__SetStatus(
&self,
lFlags: c_long,
_hResult: HRESULT,
_strParam: BSTR,
_pObjParam: *mut IWbemClassObject,
) -> HRESULT {
WBEM_S_NO_ERROR as i32
}
}
}

Undefined reference to function even though it should be reachable

Error message:
error: linking with `x86_64-w64-mingw32-gcc` failed: exit code: 1
|
<a lot of paths and args>
C:\Users\wikto\IdeaProjects\test/src/main.rs:297: undefined reference to `WaitForDebugEventEx'
Part of main.rs, I can share the rest if needed.
mod winapi;
use winapi::*;
unsafe fn debug_loop(&mut self, process_id: DWORD) {
let mut continue_status = DBG_CONTINUE;
let mut debug_event = std::mem::zeroed::<DEBUG_EVENT>();
let debug_event = &mut debug_event;
while WaitForDebugEventEx(debug_event, INFINITE) != 0 {
//something
}
}
Part of winapi.rs
#[link(name = "Kernel32")]
extern "C" {
pub fn WaitForDebugEventEx(
lpDebugEvent: *mut DEBUG_EVENT,
dwMilliseconds: DWORD,
) -> BOOL;
}
Is there anything I'm doing wrong or maybe it's a problem with mingw32-gcc?

Cast a ptr::null() to a Windows handle

I'm trying to use the winapi crate to create a GUI for my VST plugin. Functions like user32::SetMenu need some handles, some of which can be NULL.
The following method is called when the plugin is loaded:
fn open(&mut self, window: *mut c_void) {
unsafe {
let menu = user32::CreateMenu();
let sub_menu = user32::CreateMenu();
let hwnd: HWND = window as HWND;
user32::SetMenu(hwnd, menu);
let mut data = OsString::from("heee");
let raw = &mut data as *mut _ as LPWSTR;
let mut menu_item = MENUITEMINFOW {
cbSize: 0,
fMask: 0o0000_0020 | 0o0000_0040,
fType: 0,
fState: 0,
wID: MENUITEM_ID,
hSubMenu: sub_menu,
hbmpChecked: ptr::null() as HBITMAP,
hbmpUnchecked: ptr::null() as HBITMAP,
dwItemData: 0,
dwTypeData: raw,
cch: 0,
hbmpItem: ptr::null() as *mut _,
};
menu_item.cbSize = mem::size_of_val(&menu_item) as u32;
user32::InsertMenuItemW(menu, MENUITEM_ID, 0, &menu_item);
}
self.open = true;
}
However, I can't pass NULL for the handles:
hbmpChecked: ptr::null() as HBITMAP,
I get the error message
hbmpChecked: ptr::null() as HBITMAP,
^^^^^^^^^ cannot infer type for `_`
I can't find a solution in the docs of winapi/user32.
Here is how HBITMAP is defined in winapi:
type HBITMAP = *mut HBITMAP__;
This makes HBITMAP a mutable raw pointer. ptr::null() returns a const raw pointer. You should use ptr::null_mut() instead, as it returns a mutable raw pointer, so the compiler will be able to infer the correct type.

Resources