microsoft / win32metadata

Tooling to generate metadata for Win32 APIs in the Windows SDK.
Other
1.34k stars 116 forks source link

Bug: Compiler complains that HWND doesn't implement IntoParam<Handle, CopyType> #1660

Closed darklajid closed 1 year ago

darklajid commented 1 year ago

Which crate is this about?

windows

Crate version

0.48

Summary

Creating a window using CreateWindowExA I hold on to a HWND. A few lines later I try to RegisterDeviceNotificationA and pass that HWND as the first argument of type HANDLE. I'm not sure if things would blow up the way I cast the second parameter for the function, but we don't even get that far - Rust claims a HWND isn't/cannot be turned into a HANDLE..

Toolchain version/configuration

rustup show Default host: x86_64-pc-windows-msvc rustup home: C:\Users\Ben.rustup

stable-x86_64-pc-windows-msvc (default) rustc 1.68.2 (9eb3afe9e 2023-03-27)

Reproducible example

use windows::Win32::Devices::Usb::GUID_DEVINTERFACE_USB_DEVICE;
use windows::s;
use std::ffi::c_void;
use windows::Win32::Foundation::*;
use windows::Win32::System::LibraryLoader::GetModuleHandleA;
use windows::Win32::UI::WindowsAndMessaging::*;

fn main() -> anyhow::Result<()> {
    create_window();

    Ok(())
}

fn create_window() -> anyhow::Result<()> {
    unsafe {
        let instance = GetModuleHandleA(None)?;
        debug_assert!(instance.0 != 0);

        let window_class = s!("window");

        let wc: WNDCLASSA = WNDCLASSA {
            hInstance: instance,
            lpszClassName: window_class,

            style: CS_HREDRAW | CS_VREDRAW,
            lpfnWndProc: Some(wndproc),
            ..Default::default()
        };

        let atom = RegisterClassA(&wc);
        debug_assert!(atom != 0);

        let hwnd = CreateWindowExA(
            WINDOW_EX_STYLE::default(),
            window_class,
            s!("This is a sample window"),
            WINDOW_STYLE(0), //WS_OVERLAPPEDWINDOW | WS_VISIBLE,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            None,
            None,
            instance,
            None,
        );

        unsafe {
            let mut dev_interface = DEV_BROADCAST_DEVICEINTERFACE_A::default();
            dev_interface.dbcc_classguid = GUID_DEVINTERFACE_USB_DEVICE;
            RegisterDeviceNotificationA(hwnd, &mut dev_interface as *mut _ as *mut c_void, DEVICE_NOTIFY_WINDOW_HANDLE);
        }

        let mut message = MSG::default();
        while GetMessageA(&mut message, None, 0, 0).into() {
            DispatchMessageA(&message);
        }

        Ok(())
    }
}

extern "system" fn wndproc(window: HWND, message: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT {
    unsafe {
        match message {
            WM_DESTROY => {
                println!("WM_DESTROY");
                PostQuitMessage(0);
                LRESULT(0)
            }
            _ => DefWindowProcA(window, message, wparam, lparam),
        }
    }
}

Crate manifest

[package]
name = "usb_fun"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
anyhow = "=1.0.70"

strum = { version = "0.25", features = ["derive"] }

crossterm = "0.26"
inquire = "0.6"

[dependencies.windows]
version = "0.48"
features = [
  "Win32_Foundation",
  "Win32_Graphics_Gdi",
  "Win32_System_LibraryLoader",
  "Win32_UI_WindowsAndMessaging",
  "Win32_Devices_Usb"
]

Expected behavior

A HWND is a HANDLE as far as I understand. I should be able to pass it as one

Actual behavior

cargo check Checking usb_fun v0.1.0 (W:\usb_fun) error[E0277]: the trait bound windows::Win32::Foundation::HWND: CanInto<HANDLE> is not satisfied --> src\main.rs:51:41 51 RegisterDeviceNotificationA(hwnd, &mut devinterface as *mut as *mut c_void, DEVICE_NOTIFY_WINDOW_HANDLE); --------------------------- ^^^^ the trait CanInto<HANDLE> is not implemented for windows::Win32::Foundation::HWND
required by a bound introduced by this call
 = help: the following other types implement trait `CanInto<T>`:
           <CreatedHDC as CanInto<HDC>>
           <HBITMAP as CanInto<HGDIOBJ>>
           <HBRUSH as CanInto<HGDIOBJ>>
           <HCURSOR as CanInto<HICON>>
           <HFONT as CanInto<HGDIOBJ>>
           <HPALETTE as CanInto<HGDIOBJ>>
           <HPEN as CanInto<HGDIOBJ>>
           <HRGN as CanInto<HGDIOBJ>>
           <IInspectable as CanInto<IUnknown>>
 = note: required for `windows::Win32::Foundation::HWND` to implement `IntoParam<HANDLE, CopyType>`

note: required by a bound in windows::Win32::UI::WindowsAndMessaging::RegisterDeviceNotificationA --> C:\Users\Ben.cargo\registry\src\github.com-1ecc6299db9ec823\windows-0.48.0\src\Windows\Win32\UI\WindowsAndMessaging\mod.rs:3037:9 | 3037 | P0: ::windows::core::IntoParam, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in RegisterDeviceNotificationA

For more information about this error, try rustc --explain E0277. error: could not compile usb_fun due to previous error

Additional comments

No response

kennykerr commented 1 year ago

The AlsoUsableFor attribute is needed for this conversion to apply automatically. I'll transfer the issue to the Win32 metadata repo for consideration.

In the short term, a workaround is to convert it yourself. Something like HANDLE(hwnd.0).