Download as txt, pdf, or txt
Download as txt, pdf, or txt
You are on page 1of 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