0% found this document useful (0 votes)
49 views12 pages

A Rust Temp

This document contains code examples for creating a basic GUI application using the WinAPI on Windows. It demonstrates how to initialize the winapi crate, define a window struct, register a window class, create a window instance, and setup a message loop to handle events. Later comments discuss updates needed to use the newer merged winapi crate and eliminate deprecated mem::uninitialized.

Uploaded by

KinjalKishor
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
49 views12 pages

A Rust Temp

This document contains code examples for creating a basic GUI application using the WinAPI on Windows. It demonstrates how to initialize the winapi crate, define a window struct, register a window class, create a window instance, and setup a message loop to handle events. Later comments discuss updates needed to use the newer merged winapi crate and eliminate deprecated mem::uninitialized.

Uploaded by

KinjalKishor
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 12

//==============================================

//winapi crate example


use std::io;

#[cfg(windows)] extern crate winapi;


use std::io::Error;

#[cfg(windows)]
fn print_message(msg: &str) -> Result<i32, Error> {
use std::ffi::OsStr;
use std::iter::once;
use std::os::windows::ffi::OsStrExt;
use std::ptr::null_mut;
use winapi::um::winuser::{MB_OK, MessageBoxW};
let wide: Vec<u16> = OsStr::new(msg).encode_wide().chain(once(0)).collect();
let ret = unsafe {
MessageBoxW(null_mut(), wide.as_ptr(), wide.as_ptr(), MB_OK)
};
if ret == 0 { Err(Error::last_os_error()) }
else { Ok(ret) }
}

#[cfg(not(windows))]
fn print_message(msg: &str) -> Result<(), Error> {
println!("{}", msg);
Ok(())
}

fn main() {
//println!("Hello, world!");
print_message("Hello, world!").unwrap();

let mut wait_for_exit = String::new();


io::stdin().read_line(&mut wait_for_exit)
.expect("Failed to read line");
}
//==============================================
//TheSatoshiChiba
#![windows_subsystem = "windows"]
extern crate winapi;
extern crate user32;
extern crate kernel32;

use std::ffi::OsStr;
use std::os::windows::ffi::OsStrExt;
use std::iter::once;
use std::mem;
use std::ptr::null_mut;
use std::io::Error;

use self::user32::{
DefWindowProcW,
RegisterClassW,
CreateWindowExW,
TranslateMessage,
DispatchMessageW,
GetMessageW,
};
use self::winapi::HWND;
use self::kernel32::GetModuleHandleW;

use self::winapi::winuser::{
MSG,
WNDCLASSW,
CS_OWNDC,
CS_HREDRAW,
CS_VREDRAW,
CW_USEDEFAULT,
WS_OVERLAPPEDWINDOW,
WS_VISIBLE,
};

fn win32_string( value : &str ) -> Vec<u16> {


OsStr::new( value ).encode_wide().chain( once( 0 ) ).collect()
}

struct Window {
handle : HWND,
}

fn create_window( name : &str, title : &str ) -> Result<Window, Error> {


let name = win32_string( name );
let title = win32_string( title );

unsafe {
let hinstance = GetModuleHandleW( null_mut() );
let wnd_class = WNDCLASSW {
style : CS_OWNDC | CS_HREDRAW | CS_VREDRAW,
lpfnWndProc : Some( DefWindowProcW ),
hInstance : hinstance,
lpszClassName : name.as_ptr(),
cbClsExtra : 0,
cbWndExtra : 0,
hIcon: null_mut(),
hCursor: null_mut(),
hbrBackground: null_mut(),
lpszMenuName: null_mut(),
};

RegisterClassW( &wnd_class );

let handle = CreateWindowExW(


0,
name.as_ptr(),
title.as_ptr(),
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
null_mut(),
null_mut(),
hinstance,
null_mut() );

if handle.is_null() {
Err( Error::last_os_error() )
} else {
Ok( Window { handle } )
}
}
}

fn handle_message( window : &mut Window ) -> bool {


unsafe {
let mut message : MSG = mem::uninitialized();
if GetMessageW( &mut message as *mut MSG, window.handle, 0, 0 ) > 0 {
TranslateMessage( &message as *const MSG );
DispatchMessageW( &message as *const MSG );

true
} else {
false
}
}
}

fn main() {
let mut window = create_window( "my_window", "Hello Windows" ).unwrap();

loop {
if !handle_message( &mut window ) {
break;
}
}
}

//=============================================================
//lightern
//winapi has been merged with user32 and kernel32 and I was thinking it would be
great, if you could update your guide for others, since I bet there are many people
like me wrestling with this.
// Let's put this so that it won't open console
#![windows_subsystem = "windows"]

#[cfg(windows)] extern crate winapi;


// https://docs.rs/winapi/*/x86_64-pc-windows-msvc/winapi/um/libloaderapi/
index.html?search=winuser

use std::ffi::OsStr;
use std::os::windows::ffi::OsStrExt;
use std::iter::once;
use std::mem;
use std::ptr::null_mut;
use std::io::Error;

use self::winapi::shared::windef::HWND;
use self::winapi::um::libloaderapi::GetModuleHandleW;
use self::winapi::um::winuser::{
DefWindowProcW,
RegisterClassW,
CreateWindowExW,
TranslateMessage,
DispatchMessageW,
GetMessageW,
};
use self::winapi::um::winuser::{
MSG,
WNDCLASSW,
CS_OWNDC,
CS_HREDRAW,
CS_VREDRAW,
CW_USEDEFAULT,
WS_OVERLAPPEDWINDOW,
WS_VISIBLE,
};

// ----------------------------------------------------

// We have to encode text to wide format for Windows


#[cfg(windows)]
fn win32_string( value : &str ) -> Vec<u16> {
OsStr::new( value ).encode_wide().chain( once( 0 ) ).collect()
}

// Window struct
#[cfg(windows)]
struct Window {
handle : HWND,
}

// Create window function


#[cfg(windows)]
fn create_window( name : &str, title : &str ) -> Result<Window, Error> {
let name = win32_string( name );
let title = win32_string( title );

unsafe {

// Create handle instance that will call GetModuleHandleW, which grabs the
instance handle of WNDCLASSW (check third parameter)
let hinstance = GetModuleHandleW( null_mut() );

// Create "class" for window, using WNDCLASSW struct (different from Window
our struct)
let wnd_class = WNDCLASSW {
style : CS_OWNDC | CS_HREDRAW | CS_VREDRAW, // Style
lpfnWndProc : Some( DefWindowProcW ), // The
callbackfunction for any window event that can occur in our window!!! Here you
could react to events like WM_SIZE or WM_QUIT.
hInstance : hinstance, // The
instance handle for our application which we can retrieve by calling
GetModuleHandleW.
lpszClassName : name.as_ptr(), // Our class
name which needs to be a UTF-16 string (defined earlier before unsafe). as_ptr()
(Rust's own function) returns a raw pointer to the slice's buffer
cbClsExtra : 0,
cbWndExtra : 0,
hIcon: null_mut(),
hCursor: null_mut(),
hbrBackground: null_mut(),
lpszMenuName: null_mut(),
};
// We have to register this class for Windows to use
RegisterClassW( &wnd_class );

// More info:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms632680(v=vs.85).aspx
// Create a window based on registered class
let handle = CreateWindowExW(
0, // dwExStyle
name.as_ptr(), // lpClassName, name of
the class that we want to use for this window, which will be the same that we have
registered before.
title.as_ptr(), // lpWindowName
WS_OVERLAPPEDWINDOW | WS_VISIBLE, // dwStyle
CW_USEDEFAULT, // Int x
CW_USEDEFAULT, // Int y
CW_USEDEFAULT, // Int nWidth
CW_USEDEFAULT, // Int nHeight
null_mut(), // hWndParent
null_mut(), // hMenu
hinstance, // hInstance
null_mut() ); // lpParam

if handle.is_null() {
Err( Error::last_os_error() )
} else {
Ok( Window { handle } )
}
}
}

#[cfg(windows)]
// Create message handling function with which to link to hook window to Windows
messaging system
// More info:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms644927(v=vs.85).aspx
fn handle_message( window : &mut Window ) -> bool {
unsafe {
let mut message : MSG = mem::uninitialized();

// Get message from message queue with GetMessageW


if GetMessageW( &mut message as *mut MSG, window.handle, 0, 0 ) > 0 {
TranslateMessage( &message as *const MSG ); // Translate message into
something meaningful with TranslateMessage
DispatchMessageW( &message as *const MSG ); // Dispatch message with
DispatchMessageW

true
} else {
false
}
}
}
#[cfg(windows)]
fn main() {
let mut window = create_window( "my_window", "Portfolio manager
pro" ).unwrap();

loop {
if !handle_message( &mut window ) {
break;
}
}
}
//=============================================================
//rokit
//modules like winuser are gated behind a feature flag. You have to explicitly add
them to your Cargo.toml.
[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3.5", features = ["winuser", "libloaderapi"] }
//=============================================================
//bobahop
// I would suggest a tweak to handle_message to eliminate the deprecated call to
mem::uninitialized() by replacing it with mem::MaybeUninit.
fn handle_message(window: &mut Window) -> bool {
unsafe {
//let mut message: MSG = mem::uninitialized();
let message = mem::MaybeUninit::<MSG>::uninit();
// Get message from message queue with GetMessageW
if GetMessageW(message.as_ptr() as *mut MSG, window.handle, 0, 0) > 0 {
TranslateMessage(message.as_ptr() as *const MSG); // Translate message
into something meaningful with TranslateMessage
DispatchMessageW(message.as_ptr() as *const MSG); // Dispatch message
with DispatchMessageW

true
} else {
false
}
}
}
//=============================================================
//bobahop
#![windows_subsystem = "windows"]
// #![allow(unused_assignments)]
// #![allow(unused_imports)]
// #![allow(unused_variables)]
// #![allow(dead_code)]
#![allow(non_snake_case)]
extern crate winapi;
use std::ffi::OsStr;
use std::io::Error;
use std::iter::once;
use std::mem;
use std::mem::{size_of, zeroed};
use std::os::raw::c_void;
use std::os::windows::ffi::OsStrExt;
use std::ptr::null_mut;

use self::winapi::shared::guiddef::{GUID, LPIID};


use self::winapi::shared::minwindef::{HMODULE, LOWORD, LPARAM, LRESULT, TRUE, UINT,
WPARAM};
use self::winapi::shared::windef::{HBRUSH, HMENU, HWND, RECT};
use self::winapi::shared::winerror::{E_INVALIDARG, RPC_E_CHANGED_MODE, SUCCEEDED,
S_FALSE, S_OK};
use self::winapi::um::combaseapi::{CoCreateInstance, CoInitializeEx, IIDFromString,
CLSCTX_ALL};
use self::winapi::um::libloaderapi::GetModuleHandleW;
use self::winapi::um::objbase::COINIT_APARTMENTTHREADED;
use self::winapi::um::shobjidl::IFileOpenDialog;
use self::winapi::um::shobjidl_core::CLSID_FileOpenDialog;
use self::winapi::um::wingdi::TextOutA;
use self::winapi::um::winuser::{
BeginPaint, CreateWindowExW, DefWindowProcW, DestroyWindow, DispatchMessageW,
EndPaint,
FillRect, GetMessageW, GetWindowLongPtrW, InvalidateRect, LoadCursorW,
MessageBoxW,
PostQuitMessage, RegisterClassW, SetCursor, SetWindowLongPtrW, TrackMouseEvent,
TranslateMessage, UpdateWindow,
};
use self::winapi::um::winuser::{
BS_DEFPUSHBUTTON, COLOR_WINDOW, CREATESTRUCTW, CS_HREDRAW, CS_OWNDC,
CS_VREDRAW, CW_USEDEFAULT,
GWLP_USERDATA, IDC_ARROW, IDOK, MB_OK, MB_OKCANCEL, MSG, TME_LEAVE,
TRACKMOUSEEVENT, WM_CLOSE,
WM_COMMAND, WM_CREATE, WM_DESTROY, WM_MOUSELEAVE, WM_MOUSEMOVE, WM_PAINT,
WNDCLASSW, WS_CHILD,
WS_OVERLAPPEDWINDOW, WS_TABSTOP, WS_VISIBLE,
};
// ----------------------------------------------------

fn open_file_dialog(hWnd: HWND) {
unsafe {
let msg: &str;
let retval = CoInitializeEx(null_mut(), COINIT_APARTMENTTHREADED);
let msgother = &format!("{}{}", "return value: ", retval);
match retval {
S_OK => msg = "OK",
S_FALSE => msg = "False",
E_INVALIDARG => msg = "Invalid argument",
RPC_E_CHANGED_MODE => msg = "Changed modes",
_ => msg = msgother,
}
if retval != S_OK && retval != S_FALSE {
msg_box(hWnd, msg, "CoInitialize", MB_OK);
return;
}
let riid: LPIID = &mut zeroed::<GUID>();
let retval = IIDFromString(
wstr("{D57C7288-D4AD-4768-BE02-9D969532D960}").as_ptr(),
riid,
);
if retval == E_INVALIDARG {
//let msgother = &format!("{}{}", "return value: ", retval);
msg_box(hWnd, "Invalid argument", "IIDFromString", MB_OK);
return;
}
let mut pFileOpen: *mut IFileOpenDialog = &mut zeroed::<IFileOpenDialog>();
let retval = CoCreateInstance(
&CLSID_FileOpenDialog,
null_mut(),
CLSCTX_ALL,
riid,
<*mut *mut IFileOpenDialog>::cast(&mut pFileOpen),
);
if !SUCCEEDED(retval) {
let msgother = &format!("{}{}", "return value: ", retval);
msg_box(hWnd, msgother, "CoCreateInstance", MB_OK);
return;
}
(*pFileOpen).Show(hWnd);
}
}

fn wstr(value: &str) -> Vec<u16> {


//converts str to a utf-16 Vector and appends null terminator
OsStr::new(value).encode_wide().chain(once(0)).collect()
}

struct Window {
handle: HWND,
}

struct BobWindow {
inWindow: isize,
}

enum BtnId {
Btn1 = 1,
Btn2 = 2,
}
impl BtnId {
fn from_u32(value: u32) -> BtnId {
match value {
1 => BtnId::Btn1,
2 => BtnId::Btn2,
_ => panic!("Unknown value {}", value),
}
}
}

fn btn1_click(hWnd: HWND) {
msg_box(hWnd, "You touched me!", "Clicked button 1!", MB_OK);
}

fn btn2_click(hWnd: HWND) {
open_file_dialog(hWnd);
}

fn is_mouse_in(hWnd: HWND) -> bool {


unsafe {
let bw = GetWindowLongPtrW(hWnd, GWLP_USERDATA) as *mut BobWindow;
match (*bw).inWindow {
0 => false,
1 => true,
_ => false,
}
}
}

fn get_rect() -> RECT {


RECT {
left: 0,
top: 0,
right: 125,
bottom: 25,
}
}

unsafe extern "system" fn MyWindowProcW(


hWnd: HWND,
Msg: UINT,
wParam: WPARAM,
lParam: LPARAM,
) -> LRESULT {
match Msg {
WM_CREATE => {
let bw = (*(lParam as *mut CREATESTRUCTW)).lpCreateParams as *mut
BobWindow;
SetWindowLongPtrW(hWnd, GWLP_USERDATA, bw as isize);
create_button(wstr("button1"), BtnId::Btn1, 50, 100, 100, 25, hWnd);
create_button(wstr("button2"), BtnId::Btn2, 250, 100, 100, 25, hWnd);
0
}
WM_CLOSE => {
if msg_box(hWnd, "Really quit?", "Are you serious?", MB_OKCANCEL) ==
IDOK {
DestroyWindow(hWnd);
}
0
}
WM_COMMAND => {
let id = BtnId::from_u32(LOWORD(wParam as u32) as u32);
match id {
BtnId::Btn1 => {
btn1_click(hWnd);
}
BtnId::Btn2 => {
btn2_click(hWnd);
}
}
0
}
WM_DESTROY => {
PostQuitMessage(0);
0
}
WM_PAINT => {
let mut ps = zeroed();
let hdc = BeginPaint(hWnd, &mut ps);
FillRect(hdc, &ps.rcPaint, (COLOR_WINDOW + 1) as HBRUSH);
let mouse_status = format!("{}{}", "mouse is in: ", is_mouse_in(hWnd));
TextOutA(
hdc,
5,
5,
mouse_status.as_ptr() as *const i8,
mouse_status.len() as i32,
);
EndPaint(hWnd, &mut ps);
0
}
WM_MOUSELEAVE => {
let bw = GetWindowLongPtrW(hWnd, GWLP_USERDATA) as *mut BobWindow;
(*bw).inWindow = 0;
let myupdate = get_rect();
InvalidateRect(hWnd, &myupdate, TRUE);
UpdateWindow(hWnd);
0
}
WM_MOUSEMOVE => {
//only want to set cursor and mouse event once
if is_mouse_in(hWnd) {
return 0;
}
let bw = GetWindowLongPtrW(hWnd, GWLP_USERDATA) as *mut BobWindow;
(*bw).inWindow = 1;
//more info: https://www.codeproject.com/Questions/279139/Mouse-leave-
message-is-not-received-when-it-leaves
//WM_MOUSELEAVE would not fire without this
let mut tme: TRACKMOUSEEVENT =
*(mem::MaybeUninit::<TRACKMOUSEEVENT>::uninit().as_ptr() as *mut
TRACKMOUSEEVENT);
tme.hwndTrack = hWnd;
tme.dwFlags = TME_LEAVE;
tme.dwHoverTime = 1;
tme.cbSize = size_of::<TRACKMOUSEEVENT>() as u32;
TrackMouseEvent(&mut tme as *mut _ as *mut TRACKMOUSEEVENT);
//Had to do this or cursor was eternal spinny on startup.
//If it moved out of client area to top of window it turned into arrow
//and stayed arrow when returned to the client area,
//But if moved left, right, or down out of client area and returned to
client area
//it turned into and stayed a resize cursor.
SetCursor(LoadCursorW(null_mut(), IDC_ARROW));
let myupdate = get_rect();
InvalidateRect(hWnd, &myupdate, TRUE);
UpdateWindow(hWnd);
0
}
_ => DefWindowProcW(hWnd, Msg, wParam, lParam),
}
}

fn msg_box(hWnd: HWND, msg: &str, title: &str, btns: UINT) -> i32 {
unsafe { MessageBoxW(hWnd, wstr(msg).as_ptr(), wstr(title).as_ptr(), btns) }
}

fn create_button(btn_name: Vec<u16>, id: BtnId, x: i32, y: i32, w: i32, h: i32,


parent: HWND) {
unsafe {
CreateWindowExW(
0,
wstr("button").as_ptr(),
btn_name.as_ptr(),
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
x,
y,
w,
h,
parent,
id as u32 as HMENU,
GetModuleHandleW(null_mut()),
null_mut(),
);
}
}

fn create_window(hinstance: HMODULE, name: &str, title: &str) -> Result<Window,


Error> {
let name = wstr(name);
let title = wstr(title);
//need to box the struct onto the heap
//or inWindow will always have the same value as LONG_PTR returned by
GetWindowLongPtrW
let bobbie = Box::new(BobWindow { inWindow: 0 });

unsafe {
//More info:
https://docs.microsoft.com/en-us/windows/win32/learnwin32/creating-a-window
let wnd_class = WNDCLASSW {
style: CS_OWNDC | CS_HREDRAW | CS_VREDRAW, // Style
lpfnWndProc: Some(MyWindowProcW), // The callbackfunction for any
window event that can occur in our window!!! Here you could react to events like
WM_SIZE or WM_QUIT.
hInstance: hinstance, // The instance handle for our application which
we can retrieve by calling GetModuleHandleW.
lpszClassName: name.as_ptr(), // Our class name which needs to be a
UTF-16 string (defined earlier before unsafe). as_ptr() (Rust's own function)
returns a raw pointer to the slice's buffer
cbClsExtra: 0,
cbWndExtra: 0,
hIcon: null_mut(),
hCursor: null_mut(),
hbrBackground: null_mut(),
lpszMenuName: null_mut(),
};

// We have to register this class for Windows to use


RegisterClassW(&wnd_class);

// More info:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms632680(v=vs.85).aspx
// Create a window based on registered class
let handle = CreateWindowExW(
0, // dwExStyle
name.as_ptr(), // lpClassName, name of the class that we want to use
for this window, which will be the same that we have registered before.
title.as_ptr(), // lpWindowName
WS_OVERLAPPEDWINDOW | WS_VISIBLE, // dwStyle
CW_USEDEFAULT, // Int x
CW_USEDEFAULT, // Int y
CW_USEDEFAULT, // Int nWidth
CW_USEDEFAULT, // Int nHeight
null_mut(), // hWndParent
null_mut(), // hMenu
hinstance, // hInstance
//now that it's on the heap, unbox the struct into a pointer
Box::into_raw(bobbie) as *mut BobWindow as *mut c_void,
);

if handle.is_null() {
Err(Error::last_os_error())
} else {
Ok(Window { handle })
}
}
}

// Create message handling function with which to link to hook window to Windows
messaging system
// More info:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms644927(v=vs.85).aspx
fn handle_message(window: &mut Window) -> bool {
unsafe {
let message = mem::MaybeUninit::<MSG>::uninit();
if GetMessageW(message.as_ptr() as *mut MSG, window.handle, 0, 0) > 0 {
TranslateMessage(message.as_ptr() as *const MSG); // Translate message
into something meaningful with TranslateMessage
DispatchMessageW(message.as_ptr() as *const MSG); // Dispatch message
with DispatchMessageW

true
} else {
false
}
}
}

fn main() {
show_window();
}

fn show_window() {
//Create handle instance that will call GetModuleHandleW, which grabs the
instance handle of WNDCLASSW (check third parameter)
let hinstance = unsafe { GetModuleHandleW(null_mut()) };

let mut window = create_window(hinstance, "BobsWindow", "Bob Hoeppner's


Window").unwrap();
while handle_message(&mut window) {}
}
//================================

You might also like