I've been copying the code from this repository https://github.com/zserge/tray into the nim-lang. I used the winim library. And I have a mistake, I haven't been able to fix it for two days! It's a pity to throw away such code. Here's the error:
D:\nim\test>main.exe
Traceback (most recent call last)
D:\nim\test\main.nim(189) main
D:\nim-1.6.14\lib\system\assign.nim(146) genericShallowAssign
D:\nim-1.6.14\lib\system\assign.nim(132) genericAssignAux
D:\nim-1.6.14\lib\system\assign.nim(25) genericAssignAux
D:\nim-1.6.14\lib\system\assign.nim(22) genericAssignAux
D:\nim-1.6.14\lib\system\assign.nim(140) genericAssignAux
SIGSEGV: Illegal storage access. (Attempt to read from nil?)
And here's my code:
import winim
import system
type
TrayMenu = object
text: cstring
disabled: cint
checked: cint
cb: proc (menu: ptr TrayMenu)
context: pointer
submenu: ptr TrayMenu
type
Tray = object
icon: cstring
menu: ptr TrayMenu
const
WM_TRAY_CALLBACK_MESSAGE = WM_USER + 1
WC_TRAY_CLASS_NAME = "TRAY"
ID_TRAY_FIRST = 1000
var
wc: WNDCLASSEX
nid: NOTIFYICONDATA
hwnd: HWND
hmenu: HMENU = 0
proc memset(dest: pointer, c: cint, count: size_t) {.importc: "memset", header: "<string.h>".}
proc trayWndProc(hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM): LRESULT =
# Ваш код для функции обратного вызова
case msg:
of WM_CLOSE:
DestroyWindow(hwnd)
return 0
of WM_DESTROY:
PostQuitMessage(0)
return 0
of WM_TRAY_CALLBACK_MESSAGE:
if lparam == WM_LBUTTONUP or lparam == WM_RBUTTONUP:
var p: POINT
GetCursorPos(p.addr)
SetForegroundWindow(hwnd)
let cmd = TrackPopupMenu(hmenu, TPM_LEFTALIGN or TPM_RIGHTBUTTON or
TPM_RETURNCMD or TPM_NONOTIFY,
p.x, p.y, 0, hwnd, nil)
SendMessage(hwnd, WM_COMMAND, cmd, 0)
return 0
of WM_COMMAND:
if wparam >= ID_TRAY_FIRST:
var item: MENUITEMINFO
item.cbSize = UINT(sizeof(MENUITEMINFO))
item.fMask = UINT(MIIM_ID) or UINT(MIIM_DATA)
if GetMenuItemInfo(hmenu, cast[UINT](wparam), false, item.addr):
let menu: ptr TrayMenu = cast[ptr TrayMenu](item.dwItemData)
if (menu != nil) and (not (menu.cb == nil)):
menu.cb(menu)
return 0;
else:
return 1;
return DefWindowProc(hwnd, msg, wparam, lparam)
proc trayMenu(m: ptr TrayMenu, id: UINT): HMENU =
var hmenu: HMENU = CreatePopupMenu()
while m != nil and m.text != nil:
if m.text == "-":
InsertMenuW(hmenu, id, MF_SEPARATOR, cast[UINT_PTR](TRUE), "")
else:
var item: MENUITEMINFO
memset(item.addr, 0, sizeof(item))
item.cbSize = UINT(sizeof(MENUITEMINFO))
item.fMask = MIIM_ID or MIIM_TYPE or MIIM_STATE or MIIM_DATA
item.fType = 0
item.fState = 0
if m.submenu != nil:
item.fMask = item.fMask or MIIM_SUBMENU
item.hSubMenu = trayMenu(m.submenu, id)
if m.disabled:
item.fState = item.fState or MFS_DISABLED
if m.checked:
item.fState = item.fState or MFS_CHECKED
item.wID = id
item.dwTypeData = cast[LPWSTR](m.text)
item.dwItemData = cast[ULONG_PTR](m)
InsertMenuItemW(hmenu, id, true, item.addr)
return hmenu
proc trayUpdate(tray: ptr Tray) =
var prevmenu: HMENU = hmenu
var id: UINT = ID_TRAY_FIRST
hmenu = trayMenu(tray.menu, id)
SendMessage(hwnd, WM_INITMENUPOPUP, WPARAM(hmenu), 0)
var icon: HICON
ExtractIconEx(tray.icon, 0, nil, icon.addr, 1)
DestroyIcon(nid.hIcon)
nid.hIcon = icon
Shell_NotifyIcon(NIM_MODIFY, nid.addr)
if prevmenu != 0:
DestroyMenu(prevmenu)
proc trayInit(tray: ptr Tray): int =
memset(wc.addr, 0, sizeof(wc))
wc.cbSize = UINT(sizeof(WNDCLASSEX))
wc.lpfnWndProc = cast[WNDPROC](trayWndProc)
wc.hInstance = GetModuleHandle(nil)
wc.lpszClassName = WC_TRAY_CLASS_NAME
if not bool(RegisterClassEx(wc.addr)):
return -1
hwnd = CreateWindowEx(0, WC_TRAY_CLASS_NAME, nil, 0, 0, 0, 0, 0, 0, 0, 0, cast[LPVOID](0))
if hwnd == 0:
return -1
UpdateWindow(hwnd)
memset(nid.addr, 0, sizeof(nid))
nid.cbSize = UINT(sizeof(NOTIFYICONDATA))
nid.hWnd = hwnd
nid.uID = 0
nid.uFlags = NIF_ICON or NIF_MESSAGE
nid.uCallbackMessage = WM_TRAY_CALLBACK_MESSAGE
Shell_NotifyIcon(NIM_ADD, nid.addr)
trayUpdate(tray)
return 0
proc trayLoop(blocking: int): int =
var msg: MSG
if blocking != 0:
GetMessage(addr(msg), cast[HWND](nil), 0, 0)
else:
PeekMessage(msg.addr, cast[HWND](nil), 0, 0, PM_REMOVE)
if msg.message == WM_QUIT:
return -1
TranslateMessage(msg.addr)
DispatchMessage(msg.addr)
return 0
proc trayExit() =
Shell_NotifyIcon(NIM_DELETE, nid.addr)
if nid.hIcon != 0:
DestroyIcon(nid.hIcon)
if hmenu != 0:
DestroyMenu(hmenu)
PostQuitMessage(0)
UnregisterClass(WC_TRAY_CLASS_NAME, GetModuleHandle(nil))
# Определите функцию обратного вызова для элемента меню
proc helloCb(menu: ptr TrayMenu) =
echo "Hello, World!"
# trayUpdate(tray.addr)
# Определите структуру и меню системного лотка
var tray: Tray
tray.icon = "icon.ico" # Укажите путь к значку
tray.menu[] = TrayMenu(text: "hello")
# Инициализируйте системный лоток
if trayInit(tray) != 0:
echo "Ошибка инициализации системного лотка"
quit(1)
# Запустите цикл обработки событий системного лотка
while true:
if trayLoop(1) == -1:
echo "0"
help fix the error please
Sorry I don't know how to help you, but our Windy library has a Tray API for windows: https://github.com/treeform/windy/blob/master/examples/tray.nim
You can either use windy or copy the code from windy to use in your App.
I hope that helps!
tray.menu[] = TrayMenu(text: "hello")
You need allocate tray.menu