microsoft / windows-rs

Rust for Windows
https://kennykerr.ca/rust-getting-started/
Apache License 2.0
10.35k stars 486 forks source link

Different signatures for DLGPROC and WNDPROC #3115

Closed Ekopalypse closed 3 months ago

Ekopalypse commented 3 months ago

Suggestion

Currently DLGPROC is defined to return an isize value, while WNDPROC assumes a LRESULT value. Shouldn't both have identical signatures? For example, if I want to create a custom dialog class, I need to register WNDCLASSEXW, which requires a WNDPROC, and then call e.g. CreateDialogParamW, which in turn requires a DLGPROC, ... or is there a misunderstanding on my part?

tim-weis commented 3 months ago

The declarations are consistent with DLGPROC and WNDPROC. While INT_PTR and LRESULT resolve to the same type at the ABI[^1], window procedures and dialog procedures follow different protocols. To support the dialog manager, a dialog procedure must return not one, but two pieces of information (see Returning values from a dialog procedure).

Consequently, window procedures and dialog procedures cannot be used interchangeably.

For the case where you want to create a dialog that's implemented by a custom window class, you have to register a window procedure that delegates unhandled messages to DefDlgProc (note that DefDlgProc is a window procedure, not a dialog procedure). In this scenario, I believe you can call CreateDialogParam without passing a dialog procedure; after all, you've already customized dialog behavior via the custom window class.

In essence: DLGPROC and WNDPROC have the same binary signature but cannot be used interchangeably. The windows crate uses the type system to (artificially) make them incompatible. In doing this it prevented you from implementing a bug.

[^1]: Here is the definition for LRESULT in the windows-sys crate.

Ekopalypse commented 3 months ago

@tim-weis - thanks for the quick reply and thanks for the advice/explanations. Regarding not passing the dialog/window procedure, I was of the opinion that this did not work in the sense that the dialog could not be terminated. But it could be that I made a mistake when testing. I will have another look at this. Have a nice weekend.