在Rust中与Inno Setup的TNewCheckListBox交互遇阻求助
Inno Setup自动化:TNewCheckListBox交互瓶颈
问题概述
实现Inno Setup安装程序自动化时,已完成Button和Checkbox的交互,但无法与TNewCheckListBox正常交互:动态创建的TNewCheckBox句柄无法获取,也无法设置或切换选中状态,尝试CLBN_CHKCHANGE消息无效果。
现有代码
检查复选框状态函数
pub fn check_checklistbox_states() -> Vec<HWND> { let mut checkbox_handles: Vec<HWND> = Vec::new(); if let Some(checklistbox_hwnd) = find_checklistbox() { unsafe { let count = SendMessageW(checklistbox_hwnd, LB_GETCOUNT, WPARAM(0), LPARAM(0)); let count = count.0 as i32 as usize; println!("{:#?}", count); for index in 0..count { if let Some(text) = get_item_text(checklistbox_hwnd, index) { let state = SendMessageW(checklistbox_hwnd, LB_GETITEMDATA, WPARAM(index as usize), LPARAM(0)); let checked = state.0 as i32; let state_text = if checked != 0 { "Checked" } else { "Unchecked" }; let debug_checkbox = checklistbox_hwnd.0 as i32; println!("Item {}: {} - {} - {}", index + 1, text, state_text, debug_checkbox); // 示例:切换选中状态 let new_check_state = if checked != 0 { 0 } else { 1 }; // 在选中(1)和未选中(0)间切换 if (index >= 1) { // set_check(checklistbox_hwnd, index as c_int, new_check_state, BS_CHECKBOX as u32); let _ = PostMessageW(checklistbox_hwnd, CLBN_CHKCHANGE, WPARAM(1), LPARAM(0)); println!("sent"); } println!("should have clicked"); checkbox_handles.push(checklistbox_hwnd); // 这是列表框的句柄,不是单个项的 } } } } else { println!("TNewCheckListBox not found."); } checkbox_handles }
参考WinSCP实现的set_check相关代码
const LB_ERR: LRESULT = windows::Win32::Foundation::LRESULT(-1); #[repr(C)] struct AfxCheckData { m_n_check: c_int, m_b_enabled: BOOL, m_dw_user_data: DWORD, } impl AfxCheckData { fn new() -> Self { Self { m_n_check: 0, m_b_enabled: TRUE, m_dw_user_data: 0, } } }
fn invalidate_check(listbox_hwnd: HWND, n_index: i32) { unsafe { let mut rect: RECT = zeroed(); if SendMessageW(listbox_hwnd, LB_GETITEMRECT, WPARAM(n_index as usize), LPARAM(&mut rect as *mut RECT as isize)) != LB_ERR { InvalidateRect(listbox_hwnd.0 as *mut winapi::shared::windef::HWND__, &rect as *const RECT, 1); } } }
fn set_check(listbox_hwnd: HWND, n_index: i32, n_check: i32, m_n_style: u32) { if n_check == 2 && (m_n_style == BS_CHECKBOX as u32 || m_n_style == BS_AUTOCHECKBOX as u32) { return; } unsafe { let l_result = SendMessageW(listbox_hwnd, LB_GETITEMDATA, WPARAM(n_index as usize), LPARAM(0)); println!("{:#?}",l_result); if l_result != LB_ERR { let p_state: *mut AfxCheckData = if l_result == LRESULT(0) { Box::into_raw(Box::new(AfxCheckData::new())) } else { // unsafe { transmute(l_result) } Box::into_raw(Box::new(AfxCheckData::new())) }; (*p_state).m_n_check = n_check; if SendMessageW(listbox_hwnd, LB_SETITEMDATA, WPARAM(n_index as usize), LPARAM(p_state as isize)) == LB_ERR { eprintln!("Failed to set item data."); } invalidate_check(listbox_hwnd, n_index); } }}
遇到的具体问题
- 无法获取单个TNewCheckBox的句柄,CLBN_CHKCHANGE消息(尝试过
40和0x00000040两种常量定义)无效果 - 转换WinSCP的C++代码到Rust时,
transmute会触发STATUS_ACCESS_VIOLATION错误,移除后set_check函数无法正确工作 - 选中状态判断异常:实际未选中的项,输出显示为"Checked"
- 发送
LBN_DBLCLK消息时,复选框会消失
当前输出
Item 1: Main game files - Unchecked - 198748 should have clicked Item 2: Update DirectX - Checked - 198748 LRESULT( 400048848, ) sent should have clicked
期望
寻求简便的解决方案,实现TNewCheckListBox的选中状态切换和状态正确获取。
内容的提问来源于stack exchange,提问作者Carotide
相关产品推荐
相关产品推荐

