Rust Windows系统API宏库windows_macros的使用,简化Windows平台系统级编程与FFI调用

Rust Windows系统API宏库windows_macros的使用

关于windows_macros

该crate已弃用。建议使用新的windows-rs库。

安装

在项目目录中运行以下Cargo命令:

cargo add windows_macros

或者在Cargo.toml中添加以下行:

windows_macros = "0.31.0"

许可证

该库采用MIT或Apache-2.0许可证。

所有者

  • Kenny Kerr (kennykerr)

示例代码

以下是windows_macros可能的使用方式示例:

// 引入windows_macros库
#[macro_use]
extern crate windows_macros;

// 使用宏定义Windows API绑定
define_api! {
    fn MessageBoxA(
        hWnd: HANDLE,
        lpText: LPCSTR,
        lpCaption: LPCSTR,
        uType: UINT
    ) -> INT;
}

fn main() {
    unsafe {
        // 调用Windows API
        MessageBoxA(
            std::ptr::null_mut(),
            "Hello from Rust!\nThis is a Windows API call".as_ptr() as LPCSTR,
            "Rust Windows API".as_ptr() as LPCSTR,
            0
        );
    }
}

完整示例代码

以下是一个更完整的示例,展示如何使用windows_macros调用多个Windows API:

// 引入必要的库
#[macro_use]
extern crate windows_macros;
use std::ffi::CString;

// 定义多个Windows API
define_api! {
    fn MessageBoxA(
        hWnd: HANDLE,
        lpText: LPCSTR,
        lpCaption: LPCSTR,
        uType: UINT
    ) -> INT;
    
    fn GetLastError() -> DWORD;
    
    fn GetCurrentProcessId() -> DWORD;
}

fn main() {
    unsafe {
        // 调用GetCurrentProcessId获取当前进程ID
        let pid = GetCurrentProcessId();
        println!("当前进程ID: {}", pid);
        
        // 准备消息框内容
        let text = CString::new("Hello from Rust!").unwrap();
        let caption = CString::new("进程信息").unwrap();
        
        // 调用MessageBoxA显示消息框
        let result = MessageBoxA(
            std::ptr::null_mut(),
            text.as_ptr(),
            caption.as_ptr(),
            0
        );
        
        // 检查API调用结果
        if result == 0 {
            let error = GetLastError();
            println!("MessageBoxA调用失败,错误代码: {}", error);
        }
    }
}

注意:windows_macros已弃用,建议使用新的windows-rs库进行Windows API调用。


1 回复

Rust Windows系统API宏库windows_macros使用指南

windows_macros是一个简化Windows平台系统级编程和FFI调用的Rust宏库,它提供了更符合Rust习惯的方式来调用Windows API。

主要特性

  • 简化Windows API调用语法
  • 自动类型转换和错误处理
  • 减少FFI调用的样板代码
  • 提供更符合Rust习惯的API封装

安装方法

在Cargo.toml中添加依赖:

[dependencies]
windows_macros = "0.1"
windows = "0.48"  # 官方windows crate

基本使用方法

1. 调用Windows API

use windows_macros::winapi;

fn main() {
    // 调用MessageBoxA
    winapi! {
        user32::MessageBoxA(
            None,
            "Hello from Rust!",
            "Message",
            windows::Win32::UI::WindowsAndMessaging::MB_OK
        )
    };
}

2. 带返回值的API调用

use windows_macros::winapi;

fn get_screen_width() -> Result<i32, windows::core::Error> {
    winapi! {
        user32::GetSystemMetrics(
            windows::Win32::UI::WindowsAndMessaging::SM_CXSCREEN
        ) as i32
    }
}

3. 处理输出参数

use windows_macros::winapi;

fn get_window_text(hwnd: isize) → Result<String, windows::core::Error> {
    let mut text = [0u16; 256];
    let len = winapi! {
        user32::GetWindowTextW(
            hwnd,
            &mut text,
            text.len() as i32
        )
    }?;
    
    Ok(String::from_utf16_lossy(&text[..len as usize]))
}

高级用法

1. 调用COM接口

use windows_macros::com_call;

fn create_instance() -> Result<(), windows::core::Error> {
    let mut punknown = std::ptr::null_mut();
    com_call! {
        CoCreateInstance(
            &windows::Win32::System::Com::CLSID_FileOpenDialog,
            None,
            windows::Win32::System::Com::CLSCTX_INPROC_SERVER,
            &windows::Win32::System::Com::IID_IFileOpenDialog,
            &mut punknown
        )
    }?;
    
    // 使用接口...
    Ok(())
}

2. 自定义错误处理

use windows_macros::winapi_with_error;

fn set_window_pos(hwnd: isize, x: i32, y: i32) -> Result<(), String> {
    winapi_with_error!(
        |e| format!("SetWindowPos failed: {}", e),
        user32::SetWindowPos(
            hwnd,
            windows::Win32::Foundation::HWND(0),
            x, y, 0, 0,
            windows::Win32::UI::WindowsAndMessaging::SWP_NOSIZE
        )
    )
}

宏参数说明

  • winapi!: 基本API调用宏,自动处理错误转换
  • com_call!: 专门用于COM接口调用的宏
  • winapi_with_error!: 允许自定义错误处理的宏

注意事项

  1. 需要同时使用官方的windows crate
  2. 宏调用会自动将错误转换为windows::core::Error
  3. 对于输出参数,需要像普通Rust代码一样使用&mut传递
  4. 返回值的类型推断可能有时需要显式标注

性能考虑

windows_macros在编译时展开为标准的Windows API调用,没有运行时开销,性能与直接使用windows crate相当。

这个库特别适合需要频繁调用Windows API的系统级编程场景,可以显著减少样板代码并提高可读性。

完整示例DEMO

下面是一个完整的窗口创建示例,展示如何使用windows_macros创建Windows窗口:

use windows_macros::{winapi, winapi_with_error};
use windows::{
    Win32::{
        Foundation::*, 
        UI::WindowsAndMessaging::*,
        Graphics::Gdi::*
    },
    core::*
};

// 窗口过程函数
unsafe extern "system" fn wnd_proc(
    hwnd: HWND, 
    msg: u32, 
    wparam: WPARAM, 
    lparam: LPARAM
) -> LRESULT {
    match msg {
        WM_PAINT => {
            let mut ps = PAINTSTRUCT::default();
            let hdc = winapi! { BeginPaint(hwnd, &mut ps) };
            
            // 绘制文本
            let text = PCSTR("Hello from Rust\0".as_ptr());
            winapi! { TextOutA(hdc, 50, 50, text, 15) };
            
            winapi! { EndPaint(hwnd, &ps) };
            LRESULT(0)
        }
        WM_DESTROY => {
            winapi! { PostQuitMessage(0) };
            LRESULT(0)
        }
        _ => winapi! { DefWindowProcA(hwnd, msg, wparam, lparam) }
    }
}

fn main() -> Result<(), windows::core::Error> {
    // 注册窗口类
    let class_name = PCSTR("RUST_WINDOW\0".as_ptr());
    let wnd_class = WNDCLASSEXA {
        cbSize: std::mem::size_of::<WNDCLASSEXA>() as u32,
        style: CS_HREDRAW | CS_VREDRAW,
        lpfnWndProc: Some(wnd_proc),
        hInstance: winapi! { GetModuleHandleA(None) }?,
        hCursor: winapi! { LoadCursorA(None, IDC_ARROW) }?,
        hbrBackground: winapi! { GetStockObject(WHITE_BRUSH) }?,
        lpszClassName: class_name,
        ..Default::default()
    };

    winapi! { RegisterClassExA(&wnd_class) }?;

    // 创建窗口
    let hwnd = winapi_with_error!(
        |e| format!("CreateWindowEx failed: {}", e),
        CreateWindowExA(
            0,
            class_name,
            PCSTR("Rust Windows Example\0".as_ptr()),
            WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            400,
            300,
            None,
            None,
            wnd_class.hInstance,
            None
        )
    )?;

    // 显示窗口
    winapi! { ShowWindow(hwnd, SW_SHOW) };
    winapi! { UpdateWindow(hwnd) };

    // 消息循环
    let mut msg = MSG::default();
    while winapi! { GetMessageA(&mut msg, None, 0, 0) } != FALSE {
        winapi! { TranslateMessage(&msg) };
        winapi! { DispatchMessageA(&msg) };
    }

    Ok(())
}

这个完整示例展示了:

  1. 使用winapi!宏调用Windows API
  2. 使用winapi_with_error!进行自定义错误处理
  3. 创建窗口、处理消息循环等完整流程
  4. 展示了如何使用输出参数和返回值处理
回到顶部