如何在嵌入的Lua中调用WinRT .NET Framework类型与方法?
在MUSHclient Lua中实现Windows通知:替代外部工具的COM/FFI方案
你当前用os.execute调用外部toast工具的方式确实繁琐,下面提供两种更直接的方案,基于你提到的COM和FFI能力:
方案一:通过luacom调用WinRT COM接口
WinRT的Windows.UI.Notifications.ToastNotificationManager本质是基于COM的,所以可以用luacom直接调用。步骤很清晰:
- 初始化COM环境(MUSHclient可能已经做了,但显式调用更稳妥)
- 获取Toast通知管理器实例,构造符合Windows要求的XML通知内容
- 创建并发送通知
示例代码:
local luacom = require "luacom" -- 初始化COM luacom.InitializeCOM() -- 创建ToastNotificationManager实例 local toastManager = luacom.CreateObject("Windows.UI.Notifications.ToastNotificationManager") if not toastManager then error("没法创建ToastNotificationManager实例") end -- 获取通用的通知发送器(用Windows.Default就能正常显示) local notifier = toastManager:CreateToastNotifier("Windows.Default") -- 构造Toast的XML内容(必须符合Windows的Toast格式) local toastXml = [[ <toast> <visual> <binding template="ToastGeneric"> <text>MUSHclient通知</text> <text>这是Lua脚本发的Toast通知</text> </binding> </visual> </toast> ]] -- 创建XML文档对象并加载内容 local xmlDoc = luacom.CreateObject("Windows.Data.Xml.Dom.XmlDocument") xmlDoc:LoadXml(toastXml) -- 创建Toast通知对象并发送 local toast = luacom.CreateObject("Windows.UI.Notifications.ToastNotification", xmlDoc) notifier:Show(toast) -- 可选:释放COM资源 luacom.UninitializeCOM()
注意:如果你的MUSHclient版本较旧,luacom可能不支持WinRT COM对象,这时候可以试试下面的FFI方案。
方案二:通过LuaJIT FFI调用Windows API
如果COM方式行不通,用FFI调用原生API也是个选项。如果不需要严格的Toast通知,用系统托盘通知会简单很多;要是一定要Toast,就得手动绑定大量WinRT接口,比较麻烦,这里先给托盘通知的示例:
local ffi = require "ffi" -- 声明Windows API的结构体和函数 ffi.cdef[[ typedef struct { UINT cbSize; UINT uFlags; HWND hWnd; UINT uID; HICON hIcon; char szTip[128]; DWORD dwState; DWORD dwStateMask; char szInfo[256]; union { UINT uTimeout; UINT uVersion; } DUMMYUNIONNAME; char szInfoTitle[64]; DWORD dwInfoFlags; GUID guidItem; HICON hBalloonIcon; } NOTIFYICONDATAA; BOOL Shell_NotifyIconA(DWORD dwMessage, NOTIFYICONDATAA* pnid); ]] local shell32 = ffi.load("shell32") -- 构造通知数据 local nid = ffi.new("NOTIFYICONDATAA") nid.cbSize = ffi.sizeof(nid) nid.uFlags = 0x00000010 -- NIF_INFO标记,指定显示气泡信息 nid.szInfoTitle = "MUSHclient托盘通知" nid.szInfo = "这是Lua脚本发的托盘通知" nid.dwInfoFlags = 0x00000001 -- 显示信息图标 -- 发送通知(NIM_ADD是添加图标并显示气泡) shell32.Shell_NotifyIconA(0x00000000, nid) -- 可选:5秒后删除托盘图标 local function remove_notification() shell32.Shell_NotifyIconA(0x00000002, nid) -- NIM_DELETE删除图标 end utils.timer(5, remove_notification)
方案对比
- COM方式:完美匹配你想要的
ToastNotificationManager,代码直观,能实现标准Windows Toast,但依赖luacom对WinRT的兼容性。 - FFI方式:灵活性强,但Toast实现复杂度高,托盘通知则简单直接,适合不需要标准Toast的场景。
内容的提问来源于stack exchange,提问作者Danj
相关产品推荐
相关产品推荐

