You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust调用Windows API获取EDIT控件文本失败求助

解决Windows API获取EDIT控件文本为空的问题

直接上基于windows crate 0.58.0的可运行完整实现代码:

use windows::{
    core::*,
    Win32::{
        Foundation::*,
        Graphics::Gdi::*,
        System::LibraryLoader::GetModuleHandleW,
        UI::WindowsAndMessaging::*,
    },
};

const ID_PORT_EDIT: i32 = 1;
const ID_START_BUTTON: i32 = 2;

struct ServerWindow {
    hwnd: HWND,
}

impl ServerWindow {
    fn new() -> Result<Self> {
        let instance = unsafe { GetModuleHandleW(None)? };

        let wc = WNDCLASSEXW {
            cbSize: std::mem::size_of::<WNDCLASSEXW>() as u32,
            style: CS_HREDRAW | CS_VREDRAW,
            lpfnWndProc: Some(Self::window_proc),
            hInstance: instance,
            lpszClassName: w!("ServerWindowClass"),
            ..Default::default()
        };

        unsafe {
            RegisterClassExW(&wc)?;

            let hwnd = CreateWindowExW(
                0,
                wc.lpszClassName,
                w!("Port-Controlled Server"),
                WS_OVERLAPPEDWINDOW & !WS_MAXIMIZEBOX,
                CW_USEDEFAULT, CW_USEDEFAULT, 350, 150,
                None, None, instance, None,
            )?;

            // 创建PORT输入框
            CreateWindowExW(
                0,
                w!("EDIT"),
                w!("8080"), // 默认端口值
                WS_CHILD | WS_VISIBLE | WS_BORDER | ES_NUMBER,
                20, 30, 150, 25,
                hwnd,
                ID_PORT_EDIT as HMENU,
                instance,
                None,
            )?;

            // 创建START按钮
            CreateWindowExW(
                0,
                w!("BUTTON"),
                w!("START"),
                WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
                180, 30, 100, 25,
                hwnd,
                ID_START_BUTTON as HMENU,
                instance,
                None,
            )?;

            Ok(Self { hwnd })
        }
    }

    fn show(&self) -> Result<()> {
        unsafe {
            ShowWindow(self.hwnd, SW_SHOW);
            UpdateWindow(self.hwnd);
            Ok(())
        }
    }

    unsafe extern "system" fn window_proc(
        hwnd: HWND,
        msg: u32,
        wparam: WPARAM,
        lparam: LPARAM,
    ) -> LRESULT {
        match msg {
            WM_COMMAND => {
                let cmd = wparam.0 as u16;
                let ctrl_id = wparam.0 >> 16;

                if ctrl_id == ID_START_BUTTON && cmd == BN_CLICKED {
                    // 获取PORT输入框句柄
                    let edit_hwnd = GetDlgItem(hwnd, ID_PORT_EDIT);
                    if edit_hwnd.is_invalid() {
                        return LRESULT(0);
                    }

                    // 第一步:获取文本长度(不含宽字符终止符)
                    let text_len = GetWindowTextLengthW(edit_hwnd);
                    if text_len == 0 {
                        MessageBoxW(hwnd, w!("请输入端口号"), w!("错误"), MB_OK | MB_ICONERROR);
                        return LRESULT(0);
                    }

                    // 第二步:分配缓冲区,额外+1以容纳终止符
                    let mut buffer = vec![0u16; (text_len + 1) as usize];
                    // 第三步:读取文本到缓冲区
                    let copied_len = GetWindowTextW(edit_hwnd, buffer.as_mut_slice());

                    if copied_len == text_len {
                        // 转换为Rust字符串(仅取有效长度部分)
                        if let Ok(port_str) = String::from_utf16(&buffer[..text_len as usize]) {
                            if let Ok(port) = port_str.parse::<u16>() {
                                MessageBoxW(
                                    hwnd,
                                    &format!("启动服务器,端口:{}", port).encode_utf16().collect::<Vec<_>>(),
                                    w!("成功"),
                                    MB_OK | MB_ICONINFORMATION,
                                );
                                // 此处添加你的服务器启动逻辑
                            } else {
                                MessageBoxW(hwnd, w!("无效的端口号"), w!("错误"), MB_OK | MB_ICONERROR);
                            }
                        }
                    } else {
                        MessageBoxW(hwnd, w!("获取端口失败"), w!("错误"), MB_OK | MB_ICONERROR);
                    }
                }
                LRESULT(0)
            }
            WM_DESTROY => {
                PostQuitMessage(0);
                LRESULT(0)
            }
            _ => DefWindowProcW(hwnd, msg, wparam, lparam),
        }
    }
}

fn main() -> Result<()> {
    let window = ServerWindow::new()?;
    window.show()?;

    let mut msg = MSG::default();
    unsafe {
        while GetMessageW(&mut msg, None, 0, 0).into() {
            TranslateMessage(&msg);
            DispatchMessageW(&msg);
        }
    }

    Ok(())
}

核心修复点:

  • 必须先用GetWindowTextLengthW获取准确的文本长度(该长度不包含宽字符终止符\0),所以分配缓冲区时要额外加1。
  • 确保GetDlgItem正确拿到EDIT控件的句柄,避免因句柄无效导致读取失败。
  • 使用GetWindowTextW时,传入的缓冲区长度要足够,读取完成后只取有效长度的内容转换为Rust字符串,避免包含末尾的空字符。

内容的提问来源于stack exchange,提问作者David Peinado

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 06:22:39