@@ -47,8 +47,16 @@ extern "system" {
4747 ) -> i32 ;
4848 fn FindWindowW ( lpClassName : LPCWSTR , lpWindowName : LPCWSTR ) -> HWND ;
4949 fn PostMessageW ( hWnd : HWND , Msg : UINT , wParam : WPARAM , lParam : LPARAM ) -> BOOL ;
50+ fn CreateWindowExW (
51+ dwExStyle : u32 , lpClassName : * const u16 , lpWindowName : * const u16 ,
52+ dwStyle : u32 , x : i32 , y : i32 , nWidth : i32 , nHeight : i32 ,
53+ hWndParent : HWND , hMenu : isize , hInstance : isize , lpParam : * mut std:: ffi:: c_void ,
54+ ) -> HWND ;
55+ fn DestroyWindow ( hWnd : HWND ) -> i32 ;
5056}
5157
58+ const HWND_MESSAGE : HWND = -3 ; // Message-only window parent
59+
5260/// Button combinations for message boxes
5361#[ allow( dead_code) ]
5462enum MsgBtnType {
@@ -424,6 +432,51 @@ pub fn show_notification(
424432 NotifyIconType :: Error => NIIF_ERROR ,
425433 } ;
426434
435+ let title_w = to_wide ( title. to_string ( ) ) ;
436+ let msg_w = to_wide ( msg. to_string ( ) ) ;
437+ let tip_w = to_wide ( PROCESS_NAME ) ;
438+
439+ // Set tooltip (shown on hover)
440+ for ( i, & c) in tip_w. iter ( ) . take ( 127 ) . enumerate ( ) {
441+ nid. szTip [ i] = c;
442+ }
443+ // Set balloon title
444+ for ( i, & c) in title_w. iter ( ) . take ( 63 ) . enumerate ( ) {
445+ nid. szInfoTitle [ i] = c;
446+ }
447+ // Set balloon message
448+ for ( i, & c) in msg_w. iter ( ) . take ( 255 ) . enumerate ( ) {
449+ nid. szInfo [ i] = c;
450+ }
451+
452+ // First, try to delete any existing icon with the same ID (cleanup from previous calls)
453+ unsafe { Shell_NotifyIconW ( NIM_DELETE , & nid) } ;
454+
455+ // 创建一个仅用于接收消息的隐藏系统窗口 (Message-only window)
456+ let class_name = to_wide ( "STATIC" ) ; // 使用系统自带静态类
457+ let hwnd = unsafe {
458+ CreateWindowExW (
459+ 0 ,
460+ class_name. as_ptr ( ) ,
461+ ptr:: null ( ) , // 无名
462+ 0 , 0 , 0 , 0 , 0 ,
463+ HWND_MESSAGE ,
464+ 0 , 0 , ptr:: null_mut ( )
465+ )
466+ } ;
467+
468+ let mut nid: NOTIFYICONDATAW = unsafe { std:: mem:: zeroed ( ) } ;
469+ nid. cbSize = std:: mem:: size_of :: < NOTIFYICONDATAW > ( ) as u32 ;
470+ nid. hWnd = hwnd;
471+ nid. uID = STANDALONE_NOTIFY_ICON_ID ;
472+ nid. uFlags = NIF_ICON | NIF_TIP | NIF_INFO ;
473+ nid. hIcon = unsafe { LoadIconW ( 0 , IDI_APPLICATION ) } ;
474+ nid. dwInfoFlags = match icon_type {
475+ NotifyIconType :: Info => NIIF_INFO ,
476+ NotifyIconType :: Warning => NIIF_WARNING ,
477+ NotifyIconType :: Error => NIIF_ERROR ,
478+ } ;
479+
427480 let title_w = to_wide ( title) ;
428481 let msg_w = to_wide ( msg) ;
429482 let tip_w = to_wide ( PROCESS_NAME ) ;
@@ -455,9 +508,12 @@ pub fn show_notification(
455508 thread:: sleep ( std:: time:: Duration :: from_millis ( timeout_ms) ) ;
456509 let mut cleanup_nid: NOTIFYICONDATAW = unsafe { std:: mem:: zeroed ( ) } ;
457510 cleanup_nid. cbSize = std:: mem:: size_of :: < NOTIFYICONDATAW > ( ) as u32 ;
458- cleanup_nid. hWnd = 0 ;
511+ cleanup_nid. hWnd = hwnd ; // 对应当初的hwnd
459512 cleanup_nid. uID = STANDALONE_NOTIFY_ICON_ID ;
460- unsafe { Shell_NotifyIconW ( NIM_DELETE , & cleanup_nid) } ;
513+ unsafe {
514+ Shell_NotifyIconW ( NIM_DELETE , & cleanup_nid) ;
515+ DestroyWindow ( hwnd) ; // 释放伪窗口
516+ } ;
461517 } ) ;
462518
463519 true
0 commit comments