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