Create a popup in Rust using Windows APIs - windows

I would like to create a dialog box or popup in Rust in a similar fashion to PowerShell.
I'm struggling to find documentation on the Windows APIs for this. The closest I've found so far is the CreateDialogA macro (Rust winapi equivalent).
I've found some things on it such as Creating a New Dialog Box (C++), but most of it is not applicable to a Rust project.
Perhaps dialoge template is relevant?

main.rs
extern crate winapi;
use std::ptr::null_mut as NULL;
use winapi::um::winuser;
fn main() {
let l_msg: Vec<u16> = "Wassa wassa wassup\0".encode_utf16().collect();
let l_title: Vec<u16> = "\u{20BF}itconnect\0".encode_utf16().collect();
unsafe {
winuser::MessageBoxW(NULL(), l_msg.as_ptr(), l_title.as_ptr(), winuser::MB_OK | winuser::MB_ICONINFORMATION);
}
}
This uses the MessageBoxW function.
The argument winuser::MB_OK can be winuser::MB_OK, winuser::MB_OKCANCEL, winuser::MB_ABORTRETRYIGNORE, winuser::MB_YESNOCANCEL, winuser::MB_YESNO, winuser::MB_RETRYCANCEL or winuser::MB_CANCELTRYCONTINUE.
The argument winuser::MB_ICONINFORMATION can be winuser::MB_ICONHAND, winuser::MB_ICONQUESTION, winuser:: MB_ICONEXCLAMATION or winuser::MB_ICONASTERISK.
Cargo.toml should include:
[dependencies.winapi]
version = "0.3"
features = ["winuser"]

Related

How to get args from WinMain or wWinMain in Rust?

I am trying to learn how to work with raw Win32 API's and am following the tutorial here, but cannot, for the life of me, figure out how to pass int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) function signature to work. I do understand the int WINAPI isn't needed...but how do I get all of those parameters to pass to WinAPI calls? Especially hInstance and nCmdShow?
My Goal
Get hInstance and nShowCmd from
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) {}
into a Rust program, perhaps something like:
fn main(/* args, such as hInstance, nShowCmd here /*) {
}
or, the more likely way:
fn main() {
std::env::/* hopefully something like args() /*;
}
What I've tried
I've tried getting the args, but this just passes the command-line arguments that I used to spawn the program, just as args[0] being the name of the program, which is the expected behavior. Also, calling args_os() gives the same result.
I've also tried to set the windows subsystem, but the previous behavior is the same, not the desired behavior...
#![windows_subsystem = "windows"]
I am able to get the hInstance handle by manually calling GetModuleHandle() and passing in a null pointer, but have no idea how to get the nShowCmd manually.
Important Note
I am using the windows crate, which is what I would like to use.
Any help to this eluding mystery would be much appreciated!
P.S. My window does open, and everything works fine, as expected, including working with FFI, and all the crazies involved there, lol. But I just would like to understand how this is done. One can get by without the nShowCmd, but I would really like to be able to understand how this is done in rust. I also cannot overwrite the fn main() function signature, so not sure how to go about it.
WinMain is the user-provided entry point of a Windows application. The raw application entry point as seen by the OS is far simpler:
DWORD CALLBACK RawEntryPoint(void);
It is now up to language support libraries to recover the startup information and call into the user-provided entry point (see WinMain is just the conventional name for the Win32 process entry point for details):
GetModuleHandle(NULL) for hInstance
hPrevInstance is always NULL in 32-bit and 64-bit Windows
GetCommandLine for the unparsed command line passed to the program
GetStartupInfo for lots of state information, including the wShowWindow that corresponds to nCmdShow
If you have Visual Studio installed you can have a look inside exe_common.inl to see how the C and C++ support libraries go about this.
With Rust things are unfortunately more complex. Even though the compiler and linker repurpose MSVC's CRT implementation responsible for extracting the information that would be passed into WinMain, I'm not aware of a way to get a hold of this from Rust.
You're going to have to recover that information manually. Getting to the nCmdShow parameter is a bit more involved, so let's illustrate that here:
// build.rs
// Using windows-rs 0.17.2; version 0.10.0 and later should be just fine
fn main() {
windows::build!(Windows::Win32::System::Threading::GetStartupInfoW,)
}
// src/main.rs
mod bindings {
windows::include_bindings!();
}
use bindings::Windows::Win32::System::Threading::{GetStartupInfoW, STARTUPINFOW};
fn main() {
let mut si = STARTUPINFOW {
cb: std::mem::size_of::<STARTUPINFOW>() as u32,
..Default::default()
};
unsafe { GetStartupInfoW(&mut si) };
let cmd_show = si.wShowWindow as i32;
println!("nCmdShow: {:?}", cmd_show);
}
With that you now have access to a value that corresponds to the nCmdShow parameter passed into WinMain when compiling for C or C++ (roughly, anyway). Ideally you would need to see whether dwFlags contains the STARTF_USESHOWWINDOW bit, and fabricate a reasonable default when it doesn't.
That said, I'm not even sure what purpose the nCmdShow argument passed into WinMain serves. As explained under ShowWindow, using that value doesn't have any effect when it is populated from caller-provided information.
Update 2021-10-28
Starting with version 0.22.1 the windows crate comes with pre-built bindings, making it a lot easier to consume the Windows API. The following implements the same program using the pre-built bindings in place of compile-time code generation.
Cargo.toml
[package]
name = "startup_info"
version = "0.0.0"
edition = "2021"
[dependencies.windows]
version = "0.22.1"
features = ["Win32_Foundation", "Win32_System_Threading"]
main.rs
use windows::Win32::System::Threading::{GetStartupInfoW, STARTUPINFOW};
fn main() {
let mut si = STARTUPINFOW {
cb: std::mem::size_of::<STARTUPINFOW>() as u32,
..Default::default()
};
unsafe { GetStartupInfoW(&mut si) };
let cmd_show = si.wShowWindow as i32;
println!("nCmdShow: {:?}", cmd_show);
}
There is this function in Kernel32: GetStartupInfo() that in windows-rs seems to be mapped to bindings::Windows::Win32::System::Threading::GetStartupInfoW.
This function fills a STARTUPINFOW structure that has, between a lot of useful fields, WORD wShowWindow that has the same value as the last argument in WinMain().
The funny thing about WinMain is that there is nothing magic in it, it is just the function that the real entry point function, WinMainCRTStartup calls from the CRT initialization code. You can get an idea of how it does its thing by looking at the equivalent Wine source code. There you can see that your idea of calling GetModuleHandle(NULL) to get the hInstance is the right one.

Rust WINAPI outputting HMODULE value

I am trying to write a simle rust console application that calls into WINAPI.
I will ommit the obvious use and extern crate parts of my code. Here it is:
fn win32_string(value : &str ) -> Vec<u16> {
OsStr::new( value ).encode_wide().chain( once( 0 ) ).collect()
}
fn main() {
println!("===== Rust Windows experiment #1 =====");
let module_name = win32_string("ntdll.dll");
let h_instance: HMODULE;
unsafe {
h_instance = GetModuleHandleW(module_name.as_ptr());
}
println!("Value of h_instance: {:#?}", h_instance);
}
I am building it against the target triple:
[build]
target = "i686-pc-windows-msvc"
As you can see I am targeting to build a 32 bit application. Now the output of my program is the following:
===== Rust Windows experiment #1 =====
Value of h_instance: 0x00007ffb61c40000
It is showing a 64 bit address. How can this happen? Am I writing the HMODULE value wrongly to the console, or what am I doing wrong?
With help from rodrigo: The build tag is supposed to be included in the .cargo\config file instead of the cargo.toml file, in order for the compiler to pick it up. :) After changing that the issue is now fixed. :)

How do I safely wrap a callback to pass to Windows FFI?

I am trying to write a wrapper on top of winapi. I want to wrap functions that accept pointers for callback functions.
As an example, consider this:
// The unsafe callback type the FFI function accepts
type UnsafeCallback = unsafe extern "system" fn(exception_info: *mut ExceptionInfo) -> u32;
// The safe callback type my function should accept
type SafeCallback = fn(exception_info: &ConvertedExceptionInfo) -> u32;
The functions that will be used:
// The function exposed by winapi
unsafe extern "system" fn SetExceptionHandler(handler: UnsafeCallback);
// The function I want to expose in my library
fn SetExceptionHandler(handler: SafeCallback);
I want to create a wrapping function that looks like this:
unsafe extern "system" fn(exception_info: *mut ExceptionInfo) -> u32 {
let result = panic::catch_unwind(|| {
// Convert ExceptionInfo into ConvertedExceptionInfo. I know this is undefined behavior, but its only here
// to demonstrate program flow
let converted_exception_info: ConvertedExceptionInfo = (*exception_info).into();
// Call the corresponding safe function (as to how we get the function pointer here, that's
// the whole question)
return safe_callback(&converted_exception_info);
});
return match result {
Ok(val) => val,
Err(_) => _
};
}
I can think of two possibilities to create this wrapping function:
Creating a wrapping function at runtime
Create a closure or similar construct inside the safe
SetExceptionHandler method.
I have no idea how to get the closure across the FFI boundary.
Exposing a conversion macro and generating the function at compile time
Edit the SetExceptionHandler function to accept the UnsafeCallback
type.
Then I could create a macro that generates the wrapping function at compile time and expose this macro to the user.
I would have to expose unsafe extern parameters again, so it is not
how I would prefer to do it.
I have no idea how to structure such a macro or if this is even possible.
Is my first idea possible and feasible? If so, how could this be done?
If not, is writing a macro like the second idea possible and feasible? If so, how could this be done?
Based on
How do I create a Rust callback function to pass to a FFI function?
How do I convert a Rust closure to a C-style callback?
How do I pass a closure through raw pointers as an argument to a C function?
I get the impression that my first idea is probably not possible with the exception of something called trampolining.
Is trampolining possible in safe Rust and in this situation?
After much searching, i have found a blog post that explains a nice solution for the problem of wrapping callbacks. Article here

Why does Rust export its whole standard library when building a DLL?

I'm currently trying to write a dynamic library with Rust which will be loaded from a existing program. I need to export a few functions with specific names and calling conventions. Everything works, but as soon as I use anything from the standard library:
The DLL size balloons to over 3MiB (Not exactly pretty, but I could live with that)
The whole standard library gets exported from the DLL. Here is a lists with all exports: http://pastebin.com/LsG1u96C (5100 functions)
Am I missing some compiler switch?
I compile the following code with rustc without any options:
#![crate_type = "dylib"]
#![feature(std_misc)]
use std::ffi::CString;
#[link(name = "user32")]
#[allow(non_snake_case)]
extern "stdcall" {
fn MessageBoxA(hWnd: u32, lpText: *const i8, lpCaption: *const i8, uType: u32) -> u32;
}
#[no_mangle]
#[allow(non_snake_case)]
pub unsafe extern "stdcall" fn _AddLuaState(lua_state_ptr: u32)
{
let info_str = format!("Lua State Created: {}!", lua_state_ptr);
let info_cstring = CString::new(info_str).unwrap();
let caption = CString::new("Hello from my Rust Library!").unwrap();
MessageBoxA(0, info_cstring.as_ptr(), caption.as_ptr(), 0);
}
_AddLuaState#4 is the only function that should be exported.
This is on a Windows 8.1 machine with rustc 1.0.0-nightly (522d09dfe 2015-02-19) (x86)
Update: It looks like when compiling a dynamically linked file with rustc -C prefer-dynamic, the DLL size shrinks to 60kiB and there are only 3 extra exports (http://pastebin.com/G0AYZrpF) which all look quite reasonable. But I'd still prefer a statically linked library.
Recently the new crate type "cdylib" has been added that likely better fits your use-case. Replace the first line of your source file with:
#![crate_type = "cdylib"]
When using the Cargo package manager instead of directly calling rustc update Cargo.toml to contain the following lines:
[lib]
crate-type = ["cdylib"]
For more details have a look at Rust pull request #33553.
In my test it decreased the size of the following simple "Hello World" DLL from 650k (dylib) down to 8k (cdylib). Also the number of exported symbols is decreased massively.
#[no_mangle]
pub extern fn hello_rust() -> *const u8 {
"Hello, world!\0".as_ptr()
}

Overloading conflict with vector types __m128, __m256 in GCC

I've started playing around with AVX instructions on the new Intel's Sandy Bridge processor. I'm using GCC 4.5.2, TDM-GCC 64bit build of MinGW64.
I want to overload operator<< for ostream to be able to print out the vector types __m256, __m128 etc to the console. But I'm running into an overloading conflict. The 2nd function in the following code produces an error "conflicts with previous declaration void f(__vector(8) float)":
void f(__m128 v) {
cout << 4;
}
void f(__m256 v) {
cout << 8;
}
It seems that the compiler cannot distinguish between the two types and consideres them both f(float __vector).
Is there a way around this? I haven't been able to find anything online. Any help is greatly appreciated.
I accidentally stumbled upon the answer when having a similar problem with function templates. In this case, the GCC error message actually suggested a solution:
add -fabi-version=4 compiler option.
This solves my problem, and hopefully doesn't cause any issues when linking the standard libraries.
One can read more about ABI (Application Binary Interface) and GCC at ABI Policy and Guidelines and ABI specification. ABI specifies how the functions names are mangled when the code is compiled into object files. Apparently, ABI version 3 used by GCC by default cannot distinguish between the various vector types.
I was unsatisfied with the solution of changing compiler ABI flags to solve this, so I went looking for a different solution. It seems they encountered this issue in writing the Eigen library - see this source file for details http://eigen.tuxfamily.org/dox-devel/SSE_2PacketMath_8h_source.html
My solution to this is a slightly tweaked version of theirs:
template <typename T, unsigned RegisterSize>
struct Register
{
using ValueType = T;
enum { Size = RegisterSize };
inline operator T&() { return myValue; }
inline operator const T&() const { return myValue; }
inline Register() {}
inline Register(const T & v) : myValue(v) {} // Not explicit
inline Register & operator=(const T & v)
{
myValue = v;
return *this;
}
T myValue;
};
using Register4 = Register<__m128, 4u>;
using Register8 = Register<__m256, 8u>;
// Could provide more declarations for __m128d, __m128i, etc. if needed
Using the above, you can overload on Register4, Register8, etc. or produce template functions taking Registers without running into linking issues and without changing ABI settings.

Resources