Balloon WinApi 弹出窗口中的非 ascii 字符

Non ascii characters in Balloon WinApi popup

我尝试显示带有 Unicode 文本的气球弹出窗口,但我总是看到里面有 ??? 个字符。当标题 (szInfoTitle) 不包含 non-ascii 个字符时,一切正常。

下面是完整的 F# 示例:

  type NotifyIconData =
    struct
      val mutable cbSize: System.Int32  // DWORD
      val mutable hWnd: System.IntPtr // HWND
      val mutable uID: System.Int32 // UINT
      val mutable uFlags: System.Int32  // UINT
      val mutable uCallbackMessage: System.Int32  // UINT
      val mutable hIcon: System.IntPtr  // HICON
      [<MarshalAs(UnmanagedType.ByValTStr, SizeConst=128)>]
      val mutable szTip: System.String  // char[128]
      val mutable dwState: System.Int32  // DWORD
      val mutable dwStateMask: System.Int32  // DWORD
      [<MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)>]
      val mutable szInfo: System.String // char[256]
      val mutable uTimeoutOrVersion: System.Int32  // UINT
      [<MarshalAs(UnmanagedType.ByValTStr, SizeConst=64)>]
      val mutable szInfoTitle: System.String // char[64]
      val mutable dwInfoFlags: System.Int32  // DWORD
      val mutable guidItem: Guid
      val mutable hBalloonIcon: IntPtr //HIcon
    end

  [<DllImport("shell32.dll", SetLastError = true)>]
  extern bool Shell_NotifyIcon(uint dwMessage, NotifyIconData& pnid)

  [<DllImport("kernel32.dll")>]
  extern IntPtr GetConsoleWindow();

  let createNotify hwnd =
    let mutable data = NotifyIconData()
    data.cbSize <- Marshal.SizeOf(typedefof<NotifyIconData>)
    data.hWnd <- hwnd
    data.uID <- 0
    data.uFlags <- 0x00000001 ||| 0x00000002 ||| 0x00000004 ||| 0x00000008 ||| 0x00000020 ||| 0x00000080
    data.szTip <- "Tooltip"
    data.dwState <- 0
    data.dwStateMask <- 0x00000001 ||| 0x00000002
    data.guidItem <- Guid.NewGuid ()
    data.hIcon <- PInvoke.User32.LoadIcon(IntPtr.Zero, IntPtr(32512))
    let result = Shell_NotifyIcon(uint NotifyCommand.Add, &(data))

    data.uTimeoutOrVersion <- 4

    let versionResult = Shell_NotifyIcon(uint NotifyCommand.SetVersion, &(data))
    data

  let createBalloon message (d: NotifyIconData) =
    let mutable data = d
    
    data.uFlags <-  0x00000010 ||| 0x00000020
    data.dwInfoFlags <- 4
    data.hBalloonIcon <- PInvoke.User32.LoadIcon(IntPtr.Zero, IntPtr(32512))
    data.szInfo <- message
    data.szInfoTitle <- "Balloon два dva dede ąęśćóŌ"
    data.uTimeoutOrVersion <- 30000
    let result = Shell_NotifyIcon(uint NotifyCommand.Modify, &(data))

    result

  let showBallon hwnd message =
    GetConsoleWindow ()
    |> createNotify 
    |> createBalloon message

我尝试使用 Shell.NotifyIconW 但它也不起作用。

除了Shell_NotifyIconW,你还需要检查你的NOTIFYICONDATA是否是支持Unicode的宽字节版本。检查 cbSize 你得到:

  • x86 ANSI : cbSize = 508
  • x86 统一码:cbSize = 956
  • x86 编码:cbSize = 528
  • x86 ANSI : cbSize = 976

在我的测试中,使用没有任何字符集设置的示例,默认 cbSize = 528(ansi 版本),您需要将结构和函数的字符集明确指定为 unicode:

[<StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)>]
type NotifyIconData =
  struct
    val mutable cbSize: System.Int32  // DWORD
    val mutable hWnd: System.IntPtr // HWND
    val mutable uID: System.Int32 // UINT
    val mutable uFlags: System.Int32  // UINT
    val mutable uCallbackMessage: System.Int32  // UINT
    val mutable hIcon: System.IntPtr  // HICON
    [<MarshalAs(UnmanagedType.ByValTStr, SizeConst=128)>]
    val mutable szTip: System.String  // char[128]
    val mutable dwState: System.Int32  // DWORD
    val mutable dwStateMask: System.Int32  // DWORD
    [<MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)>]
    val mutable szInfo: System.String // char[256]
    val mutable uTimeoutOrVersion: System.Int32  // UINT
    [<MarshalAs(UnmanagedType.ByValTStr, SizeConst=64)>]
    val mutable szInfoTitle: System.String // char[64]
    val mutable dwInfoFlags: System.Int32  // DWORD
    val mutable guidItem: Guid
    val mutable hBalloonIcon: IntPtr //HIcon
  end

[<DllImport("shell32.dll", CharSet = CharSet.Unicode)>]
extern bool Shell_NotifyIcon(UInt32 dwMessage, NotifyIconData& pnid)

另外Shell_NotifyIcon文档中也没有说明可以使用错误码