Using winapi in Rust to get a bitmap from a window - winapi

.. Hi, I have this code :
#[cfg(windows)] extern crate winapi;
use winapi::um::winuser::{FindWindowW, GetClientRect, GetWindowDC, GetDC, ReleaseDC};
use winapi::um::wingdi::{CreateBitmap, CreateCompatibleBitmap, CreateCompatibleDC, SelectObject, GetObjectW, SaveDC, DeleteDC, DeleteObject};
use std::ptr::null_mut;
use std::mem::zeroed;
use std::ffi::OsStr;
use std::iter::once;
use std::os::windows::ffi::OsStrExt;
#[cfg(windows)]
fn find_window(name: &str) {
let window: Vec<u16> = OsStr::new(name).encode_wide().chain(once(0)).collect();
let hwnd = unsafe { FindWindowW(null_mut(), window.as_ptr()) };
if hwnd != null_mut() {
println!("Window found");
let mut my_rect = unsafe { zeroed::<winapi::shared::windef::RECT>() };
let _client_rect = unsafe { GetClientRect(hwnd, &mut my_rect) };
let w = my_rect.right - my_rect.left;
let h = my_rect.bottom - my_rect.top;
let hwnd_dc = unsafe { GetWindowDC(hwnd) };
let mem_dc = unsafe { CreateCompatibleDC(hwnd_dc) };
let bmp = unsafe { CreateCompatibleBitmap(mem_dc, w, h) };
//SelectObject(mem_dc, bmp); <== Problem is here
//DeleteObject(bmp); <== Same problem here
unsafe { DeleteDC(mem_dc) };
unsafe { ReleaseDC(hwnd, hwnd_dc) };
}
else {
println!("Window not found");
}
}
fn main() {
find_window("Firefox"); // just for test
}
If I cargo run this, I get :
SelectObject(mem_dc, bmp);
| ^^^ expected enum `std::ffi::c_void`, found enum `winapi::shared::windef::HBITMAP__`
So I get it, it doesn't want that bitmap pointer, but in the win32 documentation, it says that this function (SelectObject) accepts a Device Context (mem_dc) and an object created by some function like CreateCompatibleBitmap.
https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-selectobject
The binding in Rust accepts the two same arguments but it seems to want that std::ffi::c_void but looking a the Rust doc, I don't get what it is exactly.
Can you help me finding what's wrong ? Thanks.

Add:
use winapi::shared::windef::{HBITMAP, HBITMAP__, HGDIOBJ, HWND, POINT, RECT, SIZE};
...
unsafe {SelectObject(mem_dc, bmp as HGDIOBJ)};
unsafe {DeleteObject(bmp as HGDIOBJ)};

Related

strange process names when trying to get a PID in rust with the Windows api

Hello my goal is to create a rust function which takes a process name as string and returns a PID.
I came up with this function:
pub unsafe fn get_proc_id(proc_name: String) -> u32 {
let mut proc_id: u32 = 0;
let mut h_snap = windows::Win32::System::Diagnostics::ToolHelp::CreateToolhelp32Snapshot(
TH32CS_SNAPPROCESS,
0,
);
let h_snap = match h_snap {
Ok(t) => t,
Err(e) => panic!("eror {}", e),
};
let mut proc_entry: PROCESSENTRY32 = PROCESSENTRY32 {
..PROCESSENTRY32::default()
};
proc_entry.dwSize = std::mem::size_of::<PROCESSENTRY32>() as u32;
let entry_ptr = &mut proc_entry as *mut PROCESSENTRY32;
if windows::Win32::System::Diagnostics::ToolHelp::Process32First(h_snap, entry_ptr).as_bool() {
loop {
let mut proc_exe_string: String = String::new();
if proc_exe_string.eq(&proc_name) {
proc_id = proc_entry.th32ProcessID;
break;
}
for e in proc_entry.szExeFile {
if e.0 != 0 {
proc_exe_string.push(e.0 as char)
}
}
println!("{}", proc_exe_string);
if !Process32Next(h_snap, entry_ptr).as_bool() {
break;
}
}
}
CloseHandle(h_snap);
return proc_id; }
The function prints some strange process names. for example I'm looking for "ac_client.exe" however the function shows this process as ac_client.exeexe.exeee and this is similar for most process names. some other examples:
chrome.exexeexe.exeee
Discord.exer.exee.exee

Why do SetWindowLongW and GetWindowLongW strip pointers' first 2 digits?

I am trying to make application state working in Rust.
I got the Rust application state part from windows-rs sample line 357 and modified it a little to work with my code. The only problem is, it did not work as expected...
As you can see from the comments in the code below, my problem is that after using the mentioned two functions my pointer (state) loses its first two digits.
Every time I run this, the first two digits are always missing.
How can I solve this?
extern "system" fn wndproc(window: HWND, message: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT {
unsafe {
match message as u32 {
WM_NCCREATE => {
// ORIGINAL address given to CreateWindowExW: 0xb678ddf730
let cs = lparam as *const CREATESTRUCTW;
let state = (*cs).lpCreateParams as *mut State;
println!("{:?}", state); // OUTPUT: 0xb678ddf730 (correct)
// After using the two functions:
SetWindowLongW(window, GWLP_USERDATA, state as i32);
let state = GetWindowLongW(window, GWLP_USERDATA) as *mut State;
println!("{:?}", state); // OUTPUT: 0x78ddf730 (missing first 2 digits "b6")
1
}
...
Full code:
#![allow(dead_code)]
//#![allow(unused_)]
#![allow(unused_variables)]
use windows_sys::{
Win32::Foundation::*,
Win32::Graphics::Gdi::ValidateRect,
Win32::System::LibraryLoader::GetModuleHandleW,
Win32::UI::WindowsAndMessaging::*,
};
fn u16_str(string: &str) -> Vec<u16> {
let mut result: Vec<u16> = string.encode_utf16().collect();
result.push(0);
result
}
#[derive(Debug)]
struct State {
name: String,
}
fn main() {
unsafe {
let instance = GetModuleHandleW(std::ptr::null());
let wc = WNDCLASSEXW {
cbSize: std::mem::size_of::<WNDCLASSEXW>() as u32,
hCursor: LoadCursorW(0, IDC_ARROW),
hInstance: instance,
lpszClassName: u16_str("asd").as_ptr(),
style: CS_HREDRAW | CS_VREDRAW,
lpfnWndProc: Some(wndproc),
cbClsExtra: 0,
cbWndExtra: 0,
hIcon: 0,
hbrBackground: 0,
lpszMenuName: std::ptr::null(),
hIconSm: 0,
};
RegisterClassExW(&wc);
let mut state = State {
name: String::from("name"),
};
println!("{:?}", &mut state as *mut _);
CreateWindowExW(
0,
u16_str("asd").as_ptr(),
u16_str("Ablak 1 áéőüűö").as_ptr(),
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
0, 0, instance, &mut state as *mut _ as _,
);
let mut message = std::mem::zeroed();
while GetMessageW(&mut message, 0, 0, 0) != 0 {
DispatchMessageW(&message);
}
}
}
extern "system" fn wndproc(window: HWND, message: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT {
unsafe {
match message as u32 {
WM_NCCREATE => {
let cs = lparam as *const CREATESTRUCTW;
let state = (*cs).lpCreateParams as *mut State;
println!("{:?}", state);
SetWindowLongW(window, GWLP_USERDATA, state as i32);
let state = GetWindowLongW(window, GWLP_USERDATA) as *mut State;
println!("{:?}", state);
1
}
WM_PAINT => {
//let state = GetWindowLongPtrW(window, GWLP_USERDATA) as *mut State;
//println!("{:?}", state);
//println!("{}", GetLastError());
println!("paint");
ValidateRect(window, std::ptr::null());
0
}
WM_DESTROY => {
println!("WM_DESTROY");
PostQuitMessage(0);
0
}
_ => DefWindowProcW(window, message, wparam, lparam),
}
}
}
Cargo.toml:
...
[dependencies.windows-sys]
version = "0.36.1"
features = [
"Win32_Foundation",
"Win32_System_LibraryLoader",
"Win32_Graphics_Gdi",
"Win32_Graphics_Direct2D",
"Win32_UI_WindowsAndMessaging",
]
The GetWindowLongW and SetWindowLongW API calls can only store 32-bit values. 32 bits is the size of a pointer for 32-bit architectures. Since you are targeting a 64-bit architecture, you'll have to follow the advice from the documentation:
If you are retrieving a pointer or a handle, this function has been superseded by the GetWindowLongPtrW function. (Pointers and handles are 32 bits on 32-bit Windows and 64 bits on 64-bit Windows.) To write code that is compatible with both 32-bit and 64-bit versions of Windows, use GetWindowLongPtrW.
and
This function has been superseded by the SetWindowLongPtr function. To write code that is compatible with both 32-bit and 64-bit versions of Windows, use the SetWindowLongPtr function.
You'll have to replace
SetWindowLongW(window, GWLP_USERDATA, state as i32);
// ^^^^^^ truncates pointer to 32 bits
with
SetWindowLongPtrW(window, GWLP_USERDATA, state as isize);
The GetWindowLongW calls merely need to be replaced with GetWindowLongPtrW calls. Other changes aren't required here.
Note that while the -Ptr variants are immediately available through the windows and windows-sys crates when targeting a 64-bit architecture, they are missing for 32-bit targets (see this GitHub issue). You can provide your own implementation, e.g.
#[allow(non_snake_case)]
#[cfg(target_pointer_width = "32")]
unsafe fn SetWindowLongPtrW(window: HWND, index: WINDOW_LONG_PTR_INDEX, value: isize) -> isize {
SetWindowLongW(window, index, value as _) as _
}
#[allow(non_snake_case)]
#[cfg(target_pointer_width = "32")]
unsafe fn GetWindowLongPtrW(window: HWND, index: WINDOW_LONG_PTR_INDEX) -> isize {
GetWindowLongA(window, index) as _
}
With that in place you can simply call GetWindowLongPtrW/SetWindowLongPtrW irrespective of target architecture, same as when writing C/C++ code using the Windows SDK headers.

How to safely wrap win32's PSTR or PWSTR in an Option type (e.g. Option<&OsStr>)?

I am trying to create a safe wrapper around some Win32 APIs using Microsoft's windows crate like so:
use windows::{Win32::Foundation::*, Win32::System::Threading::*};
fn create_process(app_name: &std::ffi::OsStr) -> bool {
let mut startup_info: STARTUPINFOW = unsafe { std::mem::zeroed() };
startup_info.cb = std::mem::size_of::<STARTUPINFOW>() as u32;
let mut process_info: PROCESS_INFORMATION = unsafe {std::mem::zeroed() };
unsafe {
let success = CreateProcessW(
app_name, // lpapplicationname
None, // lpcommandname
std::ptr::null(), // lpprocessattributes
std::ptr::null(), // lpthreadattributes
true, // binherithandles
CREATE_SUSPENDED, // dwcreationflags
std::ptr::null(), // lpenvironment
&startup_info, // lpstartupinfo
&mut process_info // lpprocessinformation
).as_bool();
success
}
}
fn main() {
let app = std::ffi::OsStr::new("C:\\Windows\\system32\\notepad.exe");
let success = create_process(app);
print!("{}", success);
}
This works as expected.
However, the documentation for CreateProcessW states that
The lpApplicationName parameter can be NULL.
Thus, I would like to wrap the &OsStr in an Option<&OsStr> so I can use None when no lpApplicationName is needed.
But I cannot find a way to convert from Option<&OsStr> to anything that satisfies IntoParam<'a, PWSTR> for lpApplicationName.
As of #1801 &OsStr should implement IntoParam<PWSTR>. Since null() also implements it, you should be able to write:
use windows::core::{IntoParam, Param};
let app_name_param: Param<'_, PWSTR> = if let Some(app_name) = app_name {
app_name.into_param()
} else {
Param::None
};
...and pass app_name_param to CreateProcessW.
(I can't test this because I run on Linux, where Foundation/mod.rs fails to compile due to requiring std::os::windows::ffi::OsStrExt.)

Win32 OpenGL Window in rust: unable to load certain function pointers

#[cfg(windows)] extern crate winapi;
#[cfg(windows)] use winapi::shared::windef::HWND;
#[cfg(windows)] use winapi::shared::windef::HMENU;
#[cfg(windows)] use winapi::shared::windef::HBRUSH;
#[cfg(windows)] use winapi::shared::minwindef::HINSTANCE;
#[cfg(windows)] use winapi::shared::minwindef::UINT;
#[cfg(windows)] use winapi::shared::minwindef::DWORD;
#[cfg(windows)] use winapi::shared::minwindef::WPARAM;
#[cfg(windows)] use winapi::shared::minwindef::LPARAM;
#[cfg(windows)] use winapi::shared::minwindef::LRESULT;
#[cfg(windows)] use winapi::um::winnt::LPCWSTR;
#[cfg(windows)] use winapi::um::winuser::WS_OVERLAPPEDWINDOW;
#[cfg(windows)] use winapi::um::winuser::WS_VISIBLE;
#[cfg(windows)] use winapi::um::winuser::WNDCLASSW;
#[cfg(windows)] use std::os::windows::ffi::OsStrExt;
#[cfg(windows)] use std::ffi::OsStr;
#[cfg(windows)] use std::os::raw::c_void;
#[cfg(windows)] use winapi::um::libloaderapi::GetProcAddress;
#[cfg(windows)] use gl::types::*;
// Vertex data
static VERTEX_DATA: [GLfloat; 6] = [0.0, 0.5, 0.5, -0.5, -0.5, -0.5];
// Shader sources
static VS_SRC: &'static str = "
#version 150
in vec2 position;
void main() {
gl_Position = vec4(position, 0.0, 1.0);
}";
static FS_SRC: &'static str = "
#version 150
out vec4 out_color;
void main() {
out_color = vec4(1.0, 1.0, 1.0, 1.0);
}";
mod gl
{
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
}
#[cfg(windows)]
fn to_wstring(str : &str) -> Vec<u16>
{
let v : Vec<u16> =
OsStr::new(str).encode_wide().chain(Some(0).into_iter()).collect();
v
}
#[cfg(windows)]
pub unsafe extern "system" fn window_proc(h_wnd :HWND,
msg :UINT, w_param :WPARAM, l_param :LPARAM) -> LRESULT
{
if msg == winapi::um::winuser::WM_DESTROY {
winapi::um::winuser::PostQuitMessage(0i32);
}
return winapi::um::winuser::DefWindowProcW(h_wnd, msg, w_param, l_param);
}
fn draw_gl_scene(window_width: i32, window_height: i32,
h_dc: winapi::shared::windef::HDC)
{
unsafe
{
let module = winapi::um::libloaderapi::LoadLibraryW(to_wstring("opengl32.dll") .as_ptr());
// gl::load_with(|s| GetProcAddress(module,
// s.as_ptr() as *const i8) as *const c_void);
gl::Viewport::load_with(|s| GetProcAddress(module,
s.as_ptr() as *const i8) as *const c_void);
if gl::Viewport::is_loaded() {
gl::Viewport(0, 0, window_width, window_height);
} else {
panic!("gl::Viewport was not loaded")
}
gl::ClearColor::load_with(|s| GetProcAddress(module,
s.as_ptr() as *const i8) as *const c_void);
if gl::ClearColor::is_loaded() {
gl::ClearColor(0.12109375f32, 0.12109375f32, 0.12109375f32, 1.0f32);
} else {
panic!("gl::ClearColor was not loaded")
}
gl::GetError::load_with(|s| GetProcAddress(module,
s.as_ptr() as *const i8) as *const c_void);
let error_check_value: GLenum = gl::GetError();
/*
gl::CreateShader::load_with(|s| GetProcAddress(module,
s.as_ptr() as *const i8) as *const c_void);
let mut vertex_shader_id = 0u32;
if gl::CreateShader::is_loaded() {
vertex_shader_id = gl::CreateShader(gl::VERTEX_SHADER);
} else {
panic!("gl::CreateShader was not loaded")
}
*/
/*
let c_str = std::ffi::CString::new(VS_SRC.as_bytes()).unwrap();
gl::ShaderSource::load_with(|s| GetProcAddress(module,
s.as_ptr() as *const i8) as *const c_void);
if gl::ShaderSource::is_loaded() {
gl::ShaderSource(vertex_shader_id, 1, &c_str.as_ptr(), std::ptr::null_mut());
} else {
// panic!("gl::ShaderSource was not loaded")
}
gl::CompileShader::load_with(|s| GetProcAddress(module,
s.as_ptr() as *const i8) as *const c_void);
if gl::CompileShader::is_loaded() {
gl::CompileShader(vertex_shader_id);
} else {
// panic!("gl::CompileShader was not loaded")
}
let mut vertex_array_id: GLuint = 0u32;
gl::GenVertexArrays::load_with(|s| GetProcAddress(module,
s.as_ptr() as *const i8) as *const c_void);
if gl::GenVertexArrays::is_loaded() {
gl::GenVertexArrays(1, &mut vertex_array_id as *mut u32);
} else {
panic!("gl::GenVertexArrays was not loaded")
}
*/
gl::Clear::load_with(|s| GetProcAddress(module,
s.as_ptr() as *const i8) as *const c_void);
if gl::Clear::is_loaded() {
gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT | gl::STENCIL_BUFFER_BIT);
} else {
panic!("gl::Clear was not loaded")
}
winapi::um::wingdi::SwapBuffers(h_dc);
}
}
fn main()
{
unsafe
{
let class_name = to_wstring("OpenGL");
let h_instance = winapi::um::libloaderapi::GetModuleHandleW(std::ptr::null_mut());
let wnd = WNDCLASSW {
style: 0,
lpfnWndProc: Some(window_proc),
cbClsExtra: 0,
cbWndExtra: 0,
hInstance: h_instance,
hIcon: winapi::um::winuser::LoadIconW(0 as HINSTANCE,
winapi::um::winuser::IDI_APPLICATION),
hCursor: winapi::um::winuser::LoadCursorW(0 as HINSTANCE,
winapi::um::winuser::IDI_APPLICATION),
hbrBackground: 16 as HBRUSH,
lpszMenuName: 0 as LPCWSTR,
lpszClassName: class_name.as_ptr(),
};
winapi::um::winuser::RegisterClassW(&wnd);
let window_width = 640;
let window_height = 480;
let h_wnd_window = winapi::um::winuser::CreateWindowExW(0, class_name.as_ptr(),
to_wstring("OpenGL Example").as_ptr(), WS_OVERLAPPEDWINDOW | WS_VISIBLE,
0, 0, window_width, window_height, 0 as HWND, 0 as HMENU, h_instance,
std::ptr::null_mut());
let mut msg = winapi::um::winuser::MSG {
hwnd : 0 as HWND,
message : 0 as UINT,
wParam : 0 as WPARAM,
lParam : 0 as LPARAM,
time : 0 as DWORD,
pt : winapi::shared::windef::POINT { x: 0, y: 0, },
};
let h_dc = winapi::um::winuser::GetDC(h_wnd_window);
let pfd = winapi::um::wingdi::PIXELFORMATDESCRIPTOR {
nSize: std::mem::size_of::<winapi::um::wingdi::PIXELFORMATDESCRIPTOR>() as u16,
nVersion: 1,
dwFlags: winapi::um::wingdi::PFD_DRAW_TO_WINDOW
| winapi::um::wingdi::PFD_SUPPORT_OPENGL | winapi::um::wingdi::PFD_DOUBLEBUFFER,
iPixelType: winapi::um::wingdi::PFD_TYPE_RGBA,
cColorBits: 64,
cRedBits: 0,
cRedShift: 0,
cGreenBits: 0,
cGreenShift: 0,
cBlueBits: 0,
cBlueShift: 0,
cAlphaBits: 0,
cAlphaShift: 0,
cAccumBits: 0,
cAccumRedBits: 0,
cAccumGreenBits: 0,
cAccumBlueBits: 0,
cAccumAlphaBits: 0,
cDepthBits: 32,
cStencilBits: 8,
cAuxBuffers: 0,
iLayerType: winapi::um::wingdi::PFD_MAIN_PLANE,
bReserved: 0,
dwLayerMask: 0,
dwVisibleMask: 0,
dwDamageMask: 0,
};
let pixel_format = winapi::um::wingdi::ChoosePixelFormat(h_dc,
&pfd as *const winapi::um::wingdi::PIXELFORMATDESCRIPTOR);
winapi::um::wingdi::SetPixelFormat(h_dc, pixel_format,
&pfd as *const winapi::um::wingdi::PIXELFORMATDESCRIPTOR);
let h_rc = winapi::um::wingdi::wglCreateContext(h_dc);
winapi::um::wingdi::wglMakeCurrent(h_dc, h_rc);
winapi::um::winuser::ShowWindow(h_wnd_window, winapi::um::winuser::SW_SHOW);
loop
{
if winapi::um::winuser::PeekMessageW(&mut msg, 0u32 as HWND, 0u32, 0u32,
winapi::um::winuser::PM_REMOVE) > 0i32 {
if msg.message == winapi::um::winuser::WM_QUIT {
break;
} else {
winapi::um::winuser::TranslateMessage(&mut msg);
winapi::um::winuser::DispatchMessageW(&mut msg);
}
} else {
draw_gl_scene(window_width, window_height, h_dc);
}
}
}
}
The above code is the version of my implementation of the outdated project located here: https://www.codeproject.com/tips/1053658/win-gui-programming-in-rust-language/
Using the latest version of winapi and gl_generator as the sole two dependencies, I expanded on the starter code to successfully render an OpenGL context in tandem with the Win32 API as opposed to the glfw as suggested by the contributors of the cargo crate gl-rs. When run on a Windows machine, this project as it is presents a dark screen, as seen in this link.
Any further attempt to render something more substantial has been fruitless thus far, due to an inability to load any function pointers that relate to shaders or vertex buffer objects.
If you comb over the function draw_gl_scene, you'll see that I have a generic "load_with" function commented out and a series of function-specific "load_with" functions alongside execution code or panics depending on whether the function in question "is_loaded". The generic "load_with" I've curbed for the time being until writing function-specific "load-with" functions is no longer tenable.
As for CreateShader, ShaderSource, CompileShader, and GenVertexArrays, none of them successfully load if I uncomment any of them. I'm sure this is a user error, The odds that one of winapi and gl-rs or an anomalistic interaction between winapi and gl_generator is the cause is unlikely. I'm at my wit's end as to how to resolve this. I appreciate your time if you've read this far.
Read the wiki and this too about loading OGL pointers.
Briefly, for Windows:
GetProcAddress is only valid for OpenGL <= 1.1
wglGetProcAddress is only valid for OpenGL > 1.1
Also, the use of shaders requires OpenGL >= 2.0. Better go with OGL >= 3.2 Core Profile. For this context:
You need a proper context for OpenGL >= 3.0, which is created with the use of wglCreateContextAttribsARB.
You need a valid and current context to get the pointer to wglCreateContextAttribsARB itself by using wglGetProcAddress.
This context may be temporary. It can be created with wglCreateContext. You can delete it after you got that pointer; and the create the "real" context.
.

Cannot scroll up in Windows console using winapi and kernel32

I need to scroll through the Windows console. For that, I'm using code from a Microsoft C example that I've rewritten in Rust. I make use of the winapi and kernel32 crates. I know the code is not written according to the Rust guidelines, it is just for demonstration purposes only:
extern crate kernel32;
extern crate winapi;
use std::mem;
fn main() {
for i in 0..100 {
println!("Just some data to scroll over {}", i);
}
scroll_up(10);
}
pub fn scroll_up(rows: i16) {
let hStdout: winapi::HANDLE;
let mut csbiInfo: winapi::CONSOLE_SCREEN_BUFFER_INFO = unsafe { mem::zeroed() };
let mut srctWindow: winapi::SMALL_RECT = unsafe { mem::zeroed() };
unsafe {
// Get the current screen buffer size and window position.
hStdout = kernel32::GetStdHandle(winapi::STD_OUTPUT_HANDLE);
kernel32::GetConsoleScreenBufferInfo(hStdout, &mut csbiInfo);
}
// Set srctWindow to the current window size and location.
srctWindow = csbiInfo.srWindow;
// Check whether the window is too close to the screen buffer top
if srctWindow.Top >= rows {
srctWindow.Top -= rows; // move top up
srctWindow.Bottom -= rows; // move bottom up
unsafe {
if (kernel32::SetConsoleWindowInfo(hStdout, winapi::TRUE, &srctWindow) == 1) {
// println!("SUCSESS");
} else {
println!("failed");
}
}
} else {
println!("failed");
}
}
pub fn scroll_down(rows: i16) {
let hStdout: winapi::HANDLE;
let mut csbiInfo: winapi::CONSOLE_SCREEN_BUFFER_INFO = unsafe { mem::zeroed() };
let mut srctWindow: winapi::SMALL_RECT = unsafe { mem::zeroed() };
unsafe {
// Get the current screen buffer size and window position.
hStdout = kernel32::GetStdHandle(winapi::STD_OUTPUT_HANDLE);
kernel32::GetConsoleScreenBufferInfo(hStdout, &mut csbiInfo);
}
// Set srctWindow to the current window size and location.
srctWindow = csbiInfo.srWindow;
// Check whether the window is too close to the screen buffer top
if srctWindow.Bottom < csbiInfo.dwSize.Y - rows {
srctWindow.Top += rows; // move top down
srctWindow.Bottom += rows; // move bottom down
unsafe {
if (kernel32::SetConsoleWindowInfo(hStdout, winapi::TRUE, &srctWindow) == 1) {
// println!("SUCSESS");
} else {
println!("failed");
}
}
} else {
println!("failed");
}
}
I can scroll down n lines:
I can not scroll up n lines. What could possibly go wrong here?
Cargo dependencies:
winapi = "0.2.8"
kernel32-sys = "0.2.1"

Resources