如何解决通过WinApi32显示气球弹出窗口
我想显示一个气球弹出框而不添加对Windows.Forms的依赖关系。因此,我决定使用Shell_NotifyIcon
中的Shell32
。这是我编写的代码(从F#转换为C#),应该创建一个通知图标,然后显示一个气球。
struct NotifyIconData {
public system.int32 cbSize;
public system.intPtr hWnd; // HWND
public system.int32 uID; // UINT
public system.int32 uFlags; // UINT
public system.int32 uCallbackMessage; // UINT
public system.intPtr hIcon; // HICON
[MarshalAs(UnmanagedType.ByValTStr,SizeConst=128)]
public System.String szTip; // char[128]
public system.int32 dwState; // DWORD
public system.int32 dwStateMask; // DWORD
[MarshalAs(UnmanagedType.ByValTStr,SizeConst=256)]
public System.String szInfo; // char[256]
public system.int32 uTimeoutOrVersion; // UINT
[MarshalAs(UnmanagedType.ByValTStr,SizeConst=64)]
public System.String szInfoTitle; // char[64]
public system.int32 dwInfoFlags; // DWORD
public Guid guidItem;
public IntPtr hBalloonIcon; //HIcon
}
[DllImport("shell32.dll",SetLastError = true)]
extern bool Shell_NotifyIcon(uint dwMessage,ref NotifyIconData pnid);
[DllImport("kernel32.dll")]
extern IntPtr GetConsoleWindow();
public NotifyIconData CreateNotify (IntPtr hwnd)
{
var data = new NotifyIconData();
data.cbSize = sizeof(NotifyIconData);
data.hWnd = hwnd;
data.uID = 0;
data.uFlags = 0x00000001 | 0x00000002 | 0x00000004 | 0x00000008 | 0x00000020 | 0x00000080; // NIF_MESSAGE | NIF_ICON | NIF_TIP | NIF_STATE | NIF_GUID | NIF_SHOWTIP;
data.szTip = "Tooltip";
data.dwState = 0;
data.dwStateMask = 0x00000001 ||| 0x00000002; // NIS_SHAREDICON | NIS_HIDDEN
data.guidItem = Guid.NewGuid ();
data.hIcon = PInvoke.User32.LoadIcon(IntPtr.Zero,IntPtr(32512));
var result = Shell_NotifyIcon(0x00000000u,&(data));
data.uVersion = 4;
var versionResult = Shell_NotifyIcon(0x00000004u,&(data));
return data;
}
public bool CreateBalloon (string message,NotifyIconData data)
{
data.uFlags = 0x00000010 | 0x00000020; // NIF_INFO | NIF_GUID
data.dwInfoFlags = 0x00000000; // NO ICON
data.szInfo = message;
data.szInfoTitle = "Balloon title";
data.hBalloonIcon = PInvoke.User32.LoadIcon(IntPtr.Zero,IntPtr(32512));
var result = Shell_NotifyIcon(0x000000001u,&(data));
return result
}
public bool ShowBalloon (string message)
{
let hwnd = GetConsoleWindow();
var notify = CreateNotify (hwnd);
return CreateBalloon (message,notify);
}
我可以在日志中观察到一切似乎都很好,看不到任何错误。
2020-10-13T15:34:23.880+00 724 INFO create notify error 0,true
2020-10-13T15:34:23.889+00 724 INFO set version error 0,true
2020-10-13T15:34:23.889+00 724 INFO baloon error 0,true
但是气球没有出现在屏幕上。我想知道错误的位置(也许我错过了调用某些函数或应该设置图标的位置(现在我忽略了它)?)。 我还尝试过:
- 首先创建气球,而不先创建通知,
- 调用“
SetThreadDesktop(OpenInputDesktop(0u,true,GENERIC_ALL)) from user32
”,然后再调用“显示气球”。
但是它仍然不起作用。
这是用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 <- sizeof<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 title"
data.uTimeoutOrVersion <- 50000
let result = Shell_NotifyIcon(uint NotifyCommand.Modify,&(data))
result
let showBallon hwnd message =
GetConsoleWindow ()
|> createNotify
|> createBalloon message
解决方法
您提供的示例似乎可以在C#控制台应用程序中工作:
public static NotifyIconData CreateNotify(IntPtr hwnd)
{
var data = new NotifyIconData();
data.cbSize = Marshal.SizeOf(typeof(NotifyIconData));
data.hWnd = hwnd;
data.uID = 0;
data.uFlags = 0x00000001 | 0x00000002 | 0x00000004 | 0x00000008 | 0x00000020 | 0x00000080; // NIF_MESSAGE | NIF_ICON | NIF_TIP | NIF_STATE | NIF_GUID | NIF_SHOWTIP;
data.szTip = "Tooltip";
data.dwState = 0;
data.dwStateMask = 0x00000001 | 0x00000002; // NIS_SHAREDICON | NIS_HIDDEN
data.guidItem = Guid.NewGuid();
var result = Shell_NotifyIcon(0x00000000u,ref data);
data.uTimeoutOrVersion = 4;
var versionResult = Shell_NotifyIcon(0x00000004u,ref data);
return data;
}
public static bool CreateBalloon(string message,NotifyIconData data)
{
data.uFlags = 0x00000010 | 0x00000020; // NIF_INFO | NIF_GUID
data.dwInfoFlags = 0x00000000; // NO ICON
data.szInfo = message;
data.szInfoTitle = "Balloon title";
var result = Shell_NotifyIcon(0x000000001u,ref data);
return result;
}
public static bool ShowBalloon(string message)
{
IntPtr hwnd = GetConsoleWindow();
var notify = CreateNotify(hwnd);
return CreateBalloon(message,notify);
}
static void Main(string[] args)
{
bool ret = ShowBalloon("test");
Console.WriteLine("Hello World!");
}
对我来说,还有一个简单的示例工作:
static void Main(string[] args)
{
//ShowBalloon("test");
var data = new NOTIFYICONDATA();
data.cbSize = Marshal.SizeOf(typeof(NOTIFYICONDATA));
data.uID = 0;
data.uFlags = 0x00000010; // NIF_INFO
data.dwInfoFlags = 0x00000000; // NO ICON
data.szInfo = "test";
data.szInfoTitle = "Balloon title";
bool result = Shell_NotifyIcon(0x00000001,ref data);
Console.WriteLine("Hello World!");
}
,
@Drake的答案向我显示了错误的位置,因此我向运行中的C#示例和F#示例添加了更可靠的日志记录(由于我认为C#和F#之间的代码是1:1)。问题在于设置cbSize
的值。我使用sizeof
来计算NotifyIconData
结构的大小。但如here所述,sizeof
将返回System.Type
而不是NotifyIconData
的大小。因此,我将sizeof
更改为Marshal.SizeOf(typedefof<NotifyIconData>)
,一切按预期开始工作。
以下是C#应用程序的日志(正如Drake所说的那样,它工作正常)
... when I create notify icon
cbSize: 528,hwnd: 983580,uid: 0,uflags: 175,sztip: Tooltip,dwState: 0,dwStateMask: 3,guidItem: 9367e9cd-1fc2-4312-83dd-22b6e03486b9
... when version is set
cbSize: 528,guidItem: 9367e9cd-1fc2-4312-83dd-22b6e03486b9
... when we enter `createBalloon` function
cbSize: 528,guidItem: 9367e9cd-1fc2-4312-83dd-22b6e03486b9
... after balloon creation
cbSize: 528,uflags: 48,guidItem: 9367e9cd-1fc2-4312-83dd-22b6e03486b9
以下是F#版本的日志:
... when I create notify icon
cbSize: 96,hwnd: 591150n,sztip: "Tooltip",guidItem: 1ee87d18-ef8d-48ba-aee9-f197de6425a4
... when version is set
cbSize: 96,guidItem: 1ee87d18-ef8d-48ba-aee9-f197de6425a4
... when we enter `createBalloon` function
cbSize: 96,guidItem: 1ee87d18-ef8d-48ba-aee9-f197de6425a4
... after balloon creation
cbSize: 96,guidItem: 1ee87d18-ef8d-48ba-aee9-f197de6425a4
这是完全可用的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 title"
data.uTimeoutOrVersion <- 50000
let result = Shell_NotifyIcon(uint NotifyCommand.Modify,&(data))
result
let showBallon hwnd message =
GetConsoleWindow ()
|> createNotify
|> createBalloon message
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。