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
相关产品推荐
相关产品推荐

