;-------------------------------------------
; B.i.G. Alarm Clock 2.5 (c) Aquila, 2001
;-------------------------------------------
.386
.model flat, stdcall
option casemap :none

include windows.inc
include kernel32.inc
include gdi32.inc
include user32.inc
include comctl32.inc
include winmm.inc
include comdlg32.inc
include shell32.inc
include advapi32.inc
include masm32.inc

include bac.inc
include bac.mac

includelib kernel32.lib
includelib gdi32.lib
includelib user32.lib
includelib comctl32.lib
includelib winmm.lib
includelib comdlg32.lib
includelib shell32.lib
includelib advapi32.lib
includelib masm32.lib

; #########################################################################
ClockProc proto :HWND, :UINT, :WPARAM, :LPARAM
; Объявления функций меню
SetSoundMenuItem proto
SetProcessMenuItem proto
ExitMenuItem proto
AboutMenuItem proto
SoundPlayerMenuItem proto
BestSitesMenuItem proto
WavePlayerMenuItem proto
AutoMinimizeMenuItem proto
; Control'ы
UpDownClick proto :DWORD, :DWORD
VolumebarChange proto :DWORD
; Кнопки
PlayButtonClick proto
ChooseButtonClick proto
ProcessButtonClick proto
TimerCheckBoxClick proto
ProcessCheckBoxClick proto
SoundCheckBoxClick proto
; Работа с конфигурационным файлом
LoadCfg proto :DWORD
SaveCfg proto :DWORD
FillDefaultCfg proto :DWORD
SetupClock proto :DWORD
; Дополнительные функции
isItemChecked proto :HMENU, :UINT
PrepareOFN proto
AlarmTimerProc proto :HWND, :UINT, :UINT, :DWORD
CenterWindow proto :DWORD, :DWORD
InitTrayIcon proto
InitVolumeTrackbar proto
InitTooltips proto
ShowTrayMenu proto
SetSoundEdit proto :DWORD
InitCfgName proto
InstallAutorun proto
CheckAutorun proto
InitMainMenu proto
; Внешние функции
InitNOFOCUSEDITControl proto
InitNOINPUTEDITControl proto
AboutProc proto :HWND, :UINT, :DWORD, :DWORD
WavePlayerProc proto :HWND, :UINT, :DWORD, :DWORD
; #########################################################################
PUBLIC hwnd, hInstance
; #########################################################################

.data

szClockDialog  db "ClockDialog", 0
szAboutDialog  db "AboutDialog", 0
szWavePlayerDialog db "WavePlayerDialog", 0

szSound db "dspldeth.wav", 0
szFmtCopy db "%s", 0
szFmtEdit db "%02d", 0
szFmtCnt db "%s%s", 0
szNull db 0
szWaveFilter db "Звонки (*.wav)", 0, "*.wav", 0, 0
szAllFilter db "Программы и документы", 0, "*.*", 0, 0
szDefWaveExt db "wav", 0
szSoundTitle db "Выберите звонок", 0
szProcessTitle db "Выберите программу или документ", 0
szOpen db "open", 0
szTip db "B.i.G. Alarm Clock 2.5", 0
szWasmSite db "http://www.wasm.boom.ru", 0
szBigSite db "http://www.b-i-g.boom.ru", 0
szUgSite db "http://www.guia.nm.ru", 0
szCfgFileName db "\bac.cfg", 0
szTooltipClass db "tooltips_class32", 0
szTipPlay db "Проиграть звонок", 0
szTipRing db "Выбрать звонок", 0
szTipProcess db "Выбрать программу/документ", 0
szTrayMenu db "traymenu", 0
szAutoKey db "Software\Microsoft\Windows\CurrentVersion\Run", 0
szAutoKeyValue db "bac", 0
szBacMenu db "clock", 0

icc INITCOMMONCONTROLSEX <sizeof INITCOMMONCONTROLSEX, ICC_USEREX_CLASSES>

fSound   db 0
fRing    db 0
fProcess db 0
fRunning db 0
fWPlayer db 0
fShown   db 0

WM_TRAY EQU WM_USER + 100

.data?

hInstance dd ?
hIcon dd ?
hwnd HWND ?
hmenu HMENU ?
cfgClock CLOCKCFG <>
ofn OPENFILENAME <>
nd NOTIFYICONDATA <>
szBuf db 256 dup (?)
szFileName db 512 dup (?)
szSoundDir db 256 dup (?)
szProcessDir db 256 dup (?)
szCfgName db 256 dup (?)
idTimer dd ?
ddEstimateTick dd ?
hwndTooltip dd ?
hKey dd ?
bData dd ?
omenu dd ?

; invoke MessageBox, hwnd, addr szSound, addr szSound, MB_OK

.code

start:

  invoke GetModuleHandle, NULL
  mov hInstance, eax
  mov icc.dwSize, sizeof INITCOMMONCONTROLSEX
  mov icc.dwICC, ICC_WIN95_CLASSES + ICC_USEREX_CLASSES
  invoke InitCommonControlsEx, addr icc
  invoke InitNOFOCUSEDITControl
  invoke InitNOINPUTEDITControl
  invoke DialogBoxParam, hInstance, addr szClockDialog, NULL, addr ClockProc, NULL

  invoke ExitProcess, eax

ClockProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM

  .if uMsg == WM_INITDIALOG

    ; Двигаем окно в центр
    invoke GetDesktopWindow
    invoke CenterWindow, hWnd, eax
    ; Устанавливаем иконку окна
    invoke LoadIcon, hInstance, 10001
    mov hIcon, eax
    invoke SendMessage, hWnd, WM_SETICON, ICON_BIG, eax
    ; Инициализация переменных
    push hWnd
    pop hwnd
    invoke InitTrayIcon
    invoke InitMainMenu
    invoke PrepareOFN
    invoke InitCfgName
    invoke LoadCfg, addr cfgClock
    .if !eax
      invoke FillDefaultCfg, addr cfgClock
    .endif
    invoke SetupClock, addr cfgClock
    ; Тестирование звуковог оборудования
    invoke InitVolumeTrackbar
    ; Создание tooltip'ов
    invoke InitTooltips

  .elseif uMsg == WM_SHOWWINDOW

    .if (cfgClock.fTray == 1) && (!fShown)
      inc fShown
      invoke PostMessage, hwnd, WM_SYSCOMMAND, SC_MINIMIZE, 0
    .endif
    xor eax, eax
    ret

  .elseif uMsg == WM_CLOSE

    invoke Shell_NotifyIcon, NIM_DELETE, addr nd
    invoke SaveCfg, addr cfgClock
    invoke EndDialog, hwnd, 0

  .elseif uMsg == WM_COMMAND

    mov eax, wParam
    .if lParam == 0
      .if ax == IDM_EXIT
        invoke SendMessage, hwnd, WM_CLOSE, 0, 0
      .elseif ax == IDM_SETS
        invoke SetSoundMenuItem
      .elseif ax == IDM_SETP
        invoke SetProcessMenuItem
      .elseif ax == IDM_INFO
        invoke AboutMenuItem
      .elseif ax == IDM_WASM
        invoke ShellExecute, hwnd, addr szOpen, addr szWasmSite, NULL, addr szNull, 0
      .elseif ax == IDM_BIG
        invoke ShellExecute, hwnd, addr szOpen, addr szBigSite, NULL, addr szNull, 0
      .elseif ax == IDM_UG
        invoke ShellExecute, hwnd, addr szOpen, addr szUgSite, NULL, addr szNull, 0
      .elseif ax == IDM_WPLR
        invoke WavePlayerMenuItem
      .elseif ax == IDM_AURN
        invoke InstallAutorun
      .elseif ax == IDM_AUTR
        invoke AutoMinimizeMenuItem
      .elseif ax == IDM_SAVE
        invoke SaveCfg, addr cfgClock
      .elseif ax == IDT_TIME
        invoke SendDlgItemMessage, hwnd, IDC_TCHB, BM_CLICK, 0, 0
      .elseif ax == IDT_SND
        invoke SendDlgItemMessage, hwnd, IDC_SCHB, BM_CLICK, 0, 0
      .elseif ax == IDT_PROC
        invoke SendDlgItemMessage, hwnd, IDC_PCHB, BM_CLICK, 0, 0
      .endif
    .else
      mov edx, wParam
      shr edx, 16
      .if dx == BN_CLICKED      ; нажали на кнопку или checkbox
        .if ax == IDC_SB
          invoke SendMessage, hwnd, WM_COMMAND, IDM_SETS, 0
        .elseif ax == IDC_PRB
          invoke SendMessage, hwnd, WM_COMMAND, IDM_SETP, 0
        .elseif ax == IDC_PB
          invoke PlayButtonClick
        .elseif ax == IDC_TCHB
          invoke TimerCheckBoxClick
        .elseif ax == IDC_PCHB
          invoke ProcessCheckBoxClick
        .elseif ax == IDC_SCHB
          invoke SoundCheckBoxClick
        .endif
      .endif
    .endif

  ; Сообщения от up-down control'ов
  .elseif uMsg == WM_VSCROLL

    invoke GetDlgCtrlID, lParam
    mov edx, wParam
    shr edx, 16
    .if eax == IDC_HUP
      invoke UpDownClick, IDC_HED, edx
    .elseif eax == IDC_MUP
      invoke UpDownClick, IDC_MED, edx
    .elseif eax == IDC_LUP
      invoke UpDownClick, IDC_LED, edx
    .endif

    xor eax, eax
    ret

  .elseif uMsg == WM_HSCROLL

    invoke GetDlgCtrlID, lParam
    .if eax == IDC_VOL
      invoke VolumebarChange, wParam
    .endif

    xor eax, eax
    ret

  .elseif uMsg == WM_ACTIVATE

    invoke InitVolumeTrackbar

  .elseif uMsg == WM_SYSCOMMAND

    .if wParam == SC_MINIMIZE
      invoke ShowWindow, hwnd, SW_MINIMIZE
      invoke ShowWindow, hwnd, SW_HIDE
      xor eax, eax
      ret
    .endif

  .elseif uMsg == WM_TRAY

    .if lParam == WM_LBUTTONDOWN
      invoke ShowWindow, hwnd, SW_RESTORE
      invoke SetForegroundWindow, hwnd
    .elseif lParam == WM_RBUTTONDOWN
      invoke ShowTrayMenu
    .endif

  .else

    mov eax, FALSE
    ret

  .endif

  ret

ClockProc endp


; #########################################################################
;isItemChecked proc tMenu:HMENU, tItem:UINT

;  invoke GetMenuState, tMenu, tItem, MF_BYCOMMAND
;  test eax, MF_CHECKED
;  .if ZERO?
;    xor eax, eax
;  .else
;    mov eax, 1
;  .endif

;  ret

;isItemChecked endp
; ##########################################################################
FillDefaultCfg proc lpCC:DWORD

 mov eax, lpCC
 assume eax: ptr CLOCKCFG
 mov [eax].wHour, 0
 mov [eax].wMinute, 0
 mov [eax].wLength, 1
 mov [eax].fSound, 1
 mov [eax].fTimer, 0
 mov [eax].fProcess, 0
 invoke wsprintf, addr [eax].szSound, addr szFmtCopy, addr szSound
 invoke wsprintf, addr [eax].szProcess, addr szFmtCopy, addr szSound
; invoke RtlZeroMemory, addr [eax].szSoundDir, 256
; invoke RtlZeroMemory, addr [eax].szProcessDir, 256
 assume eax: nothing

 ret

FillDefaultCfg endp
; ##########################################################################
SetupClock proc uses edi lpCC:DWORD

  mov edi, lpCC
  assume edi: ptr CLOCKCFG

  ; Устанавливаем свойства up-down control'ов
  mov ax, 0                                     ; Часы
  shl eax, 16
  mov ax, 23
  invoke SendDlgItemMessage, hwnd, IDC_HUP, UDM_SETRANGE, 0, eax
  mov ax, 0                                     ; Минуты
  shl eax, 16
  mov ax, 59
  invoke SendDlgItemMessage, hwnd, IDC_MUP, UDM_SETRANGE, 0, eax
  mov ax, 0                                     ; Длительность
  shl eax, 16
  mov ax, 90
  invoke SendDlgItemMessage, hwnd, IDC_LUP, UDM_SETRANGE, 0, eax

  ; Установка начальной позиции up-down control'ов
  movzx eax, [edi].wHour
  invoke SendDlgItemMessage, hwnd, IDC_HUP, UDM_SETPOS, 0, eax
  movzx eax, [edi].wMinute
  invoke SendDlgItemMessage, hwnd, IDC_MUP, UDM_SETPOS, 0, eax
  movzx eax, [edi].wLength
  invoke SendDlgItemMessage, hwnd, IDC_LUP, UDM_SETPOS, 0, eax

  ; Отображение значений up-down control'ов в edit control'ах
  movzx eax, [edi].wHour                                       ; Часы
  invoke wsprintf, addr szBuf, addr szFmtEdit, eax
  invoke SetDlgItemText, hwnd, IDC_HED, addr szBuf

  movzx eax, [edi].wMinute                                     ; Минуты
  invoke wsprintf, addr szBuf, addr szFmtEdit, eax
  invoke SetDlgItemText, hwnd, IDC_MED, addr szBuf

  movzx eax, [edi].wLength                                     ; Длительность
  invoke wsprintf, addr szBuf, addr szFmtEdit, eax
  invoke SetDlgItemText, hwnd, IDC_LED, addr szBuf

  ; Отображение имен файлов звука и процесса
  invoke SetDlgItemText, hwnd, IDC_SED, addr [edi].szSound     ; Имя файла звука
  invoke SetDlgItemText, hwnd, IDC_PED, addr [edi].szProcess   ; Имя файла процесса

  ; Установка флажков
  .if [edi].fSound
    invoke CheckDlgButton, hwnd, IDC_SCHB, BST_CHECKED
  .endif
  .if [edi].fTimer
    invoke CheckDlgButton, hwnd, IDC_TCHB, BST_CHECKED
    invoke TimerCheckBoxClick
  .endif
  .if [edi].fProcess
    invoke CheckDlgButton, hwnd, IDC_PCHB, BST_CHECKED
  .endif
  .if [edi].fTray       ; Автосворачивание
    invoke CheckMenuItem, omenu, IDM_AUTR, MF_BYCOMMAND + MF_CHECKED
  .endif
  assume edi: nothing

  ret

SetupClock endp
; ##########################################################################
PlayButtonClick proc

  invoke GetDlgItemText, hwnd, IDC_SED, addr szBuf, 255
  invoke PlaySound, addr szBuf, NULL, SND_FILENAME + SND_SYNC + SND_NOWAIT

  ret

PlayButtonClick endp
; ##########################################################################
UpDownClick proc idCtrl:DWORD, num:DWORD

  invoke wsprintf, addr szBuf, addr szFmtEdit, num
  invoke SetDlgItemText, hwnd, idCtrl, addr szBuf

  ret

UpDownClick endp
; ##########################################################################
PrepareOFN proc

  ; Подготовка общей части структуры OPENFILENAME
  invoke RtlZeroMemory, addr ofn, sizeof ofn
  mov ofn.lStructSize, sizeof ofn
  push hwnd
  pop ofn.hwndOwner
  push hInstance
  pop ofn.hInstance
  mov ofn.lpstrFile, offset szFileName
  mov ofn.nMaxFile, 512
  mov ofn.Flags, OFN_FILEMUSTEXIST + OFN_PATHMUSTEXIST + OFN_HIDEREADONLY

  ret

PrepareOFN endp
; ##########################################################################
SetSoundMenuItem proc

  ; Очищение буфера
  invoke RtlZeroMemory, addr szFileName, 512
  ; Заполнение структуры ofn
  mov ofn.lpstrTitle, offset szSoundTitle
  mov ofn.lpstrFilter, offset szWaveFilter
  mov ofn.lpstrDefExt, offset szDefWaveExt

  ; Вызов диалогового окна открытия файлов и обработка результатов
  invoke GetOpenFileName, addr ofn
  .if !eax
    invoke SendDlgItemMessage, hwnd, IDC_SCHB, BM_SETCHECK, BST_UNCHECKED, 0
    invoke SoundCheckBoxClick
  .endif
  invoke SetDlgItemText, hwnd, IDC_SED, addr szFileName

  ret

SetSoundMenuItem endp
; ##########################################################################
SetProcessMenuItem proc

  ; Очищение буфера
  invoke RtlZeroMemory, addr szFileName, 512
  ; Заполнение структуры ofn
  mov ofn.lpstrTitle, offset szProcessTitle
  mov ofn.lpstrFilter, offset szAllFilter
  mov ofn.lpstrDefExt, NULL

  ; Вызов диалогового окна открытия файлов и обработка результатов
  invoke GetOpenFileName, addr ofn
  .if !eax
    invoke SendDlgItemMessage, hwnd, IDC_PCHB, BM_SETCHECK, BST_UNCHECKED, 0
  .endif
  invoke SetDlgItemText, hwnd, IDC_PED, addr szFileName
  ret

SetProcessMenuItem endp
; ##########################################################################
TimerCheckBoxClick proc

  invoke SendDlgItemMessage, hwnd, IDC_TCHB, BM_GETCHECK, 0, 0
  .if eax == BST_CHECKED
    invoke SetTimer, NULL, NULL, 1000, addr AlarmTimerProc
    mov idTimer, eax
  .elseif  eax == BST_UNCHECKED
    invoke KillTimer, NULL, idTimer
    mov fRunning, 0
    mov fProcess, 0
    mov fRing, 0
  .endif

  ret

TimerCheckBoxClick endp
; ##########################################################################
ProcessCheckBoxClick proc

  invoke SendDlgItemMessage, hwnd, IDC_PCHB, BM_GETCHECK, 0, 0
  .if eax == BST_CHECKED
    invoke GetDlgItemText, hwnd, IDC_PED, addr szBuf, 255
    invoke lstrcmp, addr szBuf, addr szNull
    .if !eax
      ; Заполнение структуры ofn
      mov ofn.lpstrTitle, offset szProcessTitle
      mov ofn.lpstrFilter, offset szAllFilter
      mov ofn.lpstrDefExt, NULL
      ; Вызов диалогового окна открытия файлов и обработка результатов
      invoke GetOpenFileName, addr ofn
      .if !eax
        invoke SendDlgItemMessage, hwnd, IDC_PCHB, BM_SETCHECK, BST_UNCHECKED, 0
      .endif
      invoke SetDlgItemText, hwnd, IDC_PED, addr szFileName
    .endif
  .elseif eax == BST_UNCHECKED
    ; invoke SetDlgItemText, hwnd, IDC_PED, addr szNull
  .endif

  ret

ProcessCheckBoxClick endp
; ##########################################################################
SoundCheckBoxClick proc

  invoke SendDlgItemMessage, hwnd, IDC_SCHB, BM_GETCHECK, 0, 0
  .if eax == BST_CHECKED
    ; Установка продолжительности звонка
    invoke SendDlgItemMessage, hwnd, IDC_LUP, UDM_SETPOS, 0, 1
    invoke UpDownClick, IDC_LED, 1
    ; Установка (если необходимо) звонка
    invoke GetDlgItemText, hwnd, IDC_SED, addr szBuf, 255
    invoke lstrcmp, addr szBuf, addr szNull
    .if !eax
      ; Заполнение структуры ofn
      mov ofn.lpstrTitle, offset szSoundTitle
      mov ofn.lpstrFilter, offset szWaveFilter
      mov ofn.lpstrDefExt, NULL
      ; Вызов диалогового окна открытия файлов и обработка результатов
      invoke GetOpenFileName, addr ofn
      .if !eax
        invoke SendDlgItemMessage, hwnd, IDC_SCHB, BM_SETCHECK, BST_UNCHECKED, 0
      .endif
      invoke SetDlgItemText, hwnd, IDC_SED, addr szFileName
    .endif

  .elseif eax == BST_UNCHECKED
    invoke SendDlgItemMessage, hwnd, IDC_LUP, UDM_SETPOS, 0, 0
    invoke UpDownClick, IDC_LED, 0
  .endif

  ret

SoundCheckBoxClick endp
; ##########################################################################
AlarmTimerProc proc uses edi hWnd:HWND, uMsg:UINT, idEvent:UINT, dwTime:DWORD
  LOCAL dwHour:DWORD
  LOCAL dwMinute:DWORD
  LOCAL dwLength:DWORD
  LOCAL lTime:SYSTEMTIME

  .if fRunning
    ret
  .endif
  ; Получаем данные из edit control'ов
  invoke SendDlgItemMessage, hwnd, IDC_HUP, UDM_GETPOS, 0, 0
  mov dwHour, eax
  invoke SendDlgItemMessage, hwnd, IDC_MUP, UDM_GETPOS, 0, 0
  mov dwMinute, eax
  invoke SendDlgItemMessage, hwnd, IDC_LUP, UDM_GETPOS, 0, 0
  mov dwLength, eax
  ; Получаем местное время
  invoke GetLocalTime, addr lTime
  ; Если наступило заданное время
  mov eax, dwHour
  mov edx, dwMinute
  inc fRunning
  .if ax == lTime.wHour && dx == lTime.wMinute
    ;-= Запуск (если необходимо) процесса
    .if !fProcess
      invoke SendDlgItemMessage, hwnd, IDC_PCHB, BM_GETCHECK, 0, 0
      .if eax == BST_CHECKED
        invoke GetDlgItemText, hwnd, IDC_PED, addr szBuf, 255
        invoke lstrcmp, addr szBuf, addr szNull
        .if eax
          invoke ShellExecute, hwnd, addr szOpen, addr szBuf, addr szNull, NULL, SW_SHOW
        .endif
        inc fProcess
      .endif
    .endif
    ;-= Звук.
    .if !fRing
      invoke SendDlgItemMessage, hwnd, IDC_LUP, UDM_GETPOS, 0, 0
      movzx eax, ax
      mov edx, 60000
      mul edx
      add eax, dwTime    ; получили время (в тиках), когда нужно прекращать звонить
      mov ddEstimateTick, eax
      inc fRing
    .endif
  .endif
  .if fRing
    mov edx, dwTime
    .if edx > ddEstimateTick
      dec fRing
    .else
      invoke SendDlgItemMessage, hwnd, IDC_SCHB, BM_GETCHECK, 0, 0
      .if eax == BST_CHECKED
        invoke PlayButtonClick
      .endif
    .endif
  .endif
  dec fRunning

  ret

AlarmTimerProc endp
; ##########################################################################
CenterWindow proc hWnd:DWORD, hwndParent:DWORD
  local rc:RECT
  local rp:RECT
  local cxlen:DWORD
  local cylen:DWORD
  local pxlen:DWORD
  local pylen:DWORD
  local xpos:DWORD
  local ypos:DWORD

  ; Получаем метpику центpиpуемого окна
  invoke GetWindowRect, hWnd, addr rc
  ; Получаем метpику pодительского окна
  invoke GetWindowRect, hwndParent, addr rp

  ; Вычисляем pазмеpы центpиpуемого окна
  mov eax, rc.right
  sub eax, rc.left
  mov cxlen, eax
  mov eax, rc.bottom
  sub eax, rc.top
  mov cylen, eax
  ; Вычисляем pазмеpы pодительского окна
  mov eax, rp.right
  sub eax, rp.left
  mov pxlen, eax
  mov eax, rp.bottom
  sub eax, rp.top
  mov pylen, eax
  ; Получаем относительные кооpдинаты по длине
  mov eax, pxlen
  mov edx, cxlen
  shr eax, 1
  shr edx, 1
  sub eax, edx
  mov xpos, eax
  ; Получаем относительные кооpдинаты по высоте
  mov eax, pylen
  mov edx, cylen
  shr eax, 1
  shr edx, 1
  sub eax, edx
  mov ypos, eax
  ; Делаем из относительных кооpдинат абсолютные
  mov eax, xpos
  add eax, rp.left
  mov xpos, eax
  mov eax, ypos
  add eax, rp.top
  mov ypos, eax
  ; Двигаем центpиpуемое окно
  invoke MoveWindow, hWnd, xpos, ypos, cxlen, cylen, TRUE

  ret

CenterWindow endp
; ##########################################################################
AboutMenuItem proc

  invoke DialogBoxParam, hInstance, addr szAboutDialog, hwnd, addr AboutProc, NULL

  ret

AboutMenuItem endp
; ##########################################################################
InitTrayIcon proc

  ; Инициализация данных
  mov nd.cbSize, sizeof NOTIFYICONDATA
  push hwnd
  pop nd.hwnd
  mov nd.uID, 1
  mov nd.uCallbackMessage, WM_TRAY
  invoke LoadIcon, hInstance, 10001
  push eax
  pop nd.hIcon
  invoke wsprintf, addr nd.szTip, addr szFmtCopy, addr szTip
  mov nd.uFlags, NIF_ICON + NIF_MESSAGE + NIF_TIP
  ; Добавление иконки
  invoke Shell_NotifyIcon, NIM_ADD, addr nd

  ret

InitTrayIcon endp
; ##########################################################################
LoadCfg proc cfg:DWORD
  LOCAL hFile:HANDLE
  LOCAL rv:DWORD

  invoke RtlZeroMemory, cfg, sizeof CLOCKCFG
  invoke CreateFile, addr szCfgName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, \
         FILE_ATTRIBUTE_NORMAL, NULL
  .if eax == -1
    xor eax, eax
    ret
  .endif
  mov hFile, eax
  invoke ReadFile, hFile, cfg, sizeof CLOCKCFG, addr rv, NULL
  invoke CloseHandle, hFile
  mov eax, 1

  ret

LoadCfg endp
; ##########################################################################
SaveCfg proc cfg:DWORD
  LOCAL hFile:HANDLE
  LOCAL rv:DWORD

  invoke RtlZeroMemory, cfg, sizeof CLOCKCFG
  ; Заполнение структуры
  mov edi, cfg
  assume edi: ptr CLOCKCFG
  invoke SendDlgItemMessage, hwnd, IDC_HUP, UDM_GETPOS, 0, 0
  mov [edi].wHour, ax
  invoke SendDlgItemMessage, hwnd, IDC_MUP, UDM_GETPOS, 0, 0
  mov [edi].wMinute, ax
  invoke SendDlgItemMessage, hwnd, IDC_LUP, UDM_GETPOS, 0, 0
  mov [edi].wLength, ax
  invoke SendDlgItemMessage, hwnd, IDC_TCHB, BM_GETCHECK, 0, 0
  mov [edi].fTimer, al
  invoke SendDlgItemMessage, hwnd, IDC_SCHB, BM_GETCHECK, 0, 0
  mov [edi].fSound, al
  invoke SendDlgItemMessage, hwnd, IDC_PCHB, BM_GETCHECK, 0, 0
  mov [edi].fProcess, al
  invoke GetDlgItemText, hwnd, IDC_SED, addr [edi].szSound, 255
  invoke GetDlgItemText, hwnd, IDC_PED, addr [edi].szProcess, 255
  invoke GetMenuState, omenu, IDM_AUTR, MF_BYCOMMAND
  .if eax == MF_UNCHECKED
    mov [edi].fTray, 0
  .elseif eax == MF_CHECKED
    mov [edi].fTray, 1
  .endif
  assume edi: nothing
  ; Сохранение конфигурации
  invoke CreateFile, addr szCfgName, GENERIC_WRITE, NULL, NULL, CREATE_ALWAYS, \
         FILE_ATTRIBUTE_NORMAL, NULL
  mov hFile, eax
  invoke WriteFile, hFile, cfg, sizeof CLOCKCFG, addr rv, NULL
  invoke CloseHandle, hFile

  ret

SaveCfg endp
; ##########################################################################
InitVolumeTrackbar proc
  LOCAL volume:DWORD

  invoke waveOutGetNumDevs
  .if !eax                               ; Нет звуковой карты
    invoke GetDlgItem, hwnd, IDC_VOL
    invoke EnableWindow, eax, FALSE
    ret
  .endif

  ; Настройка трекбара
  invoke SendDlgItemMessage, hwnd, IDC_VOL, TBM_SETTICFREQ, 16384, 0
  invoke SendDlgItemMessage, hwnd, IDC_VOL, TBM_SETRANGEMAX, TRUE, 65535
  ; Установка бегунка
  invoke waveOutGetVolume, 0, addr volume
  mov eax, volume
  shl eax, 16
  shr eax, 16
  invoke SendDlgItemMessage, hwnd, IDC_VOL, TBM_SETPOS, TRUE, eax

  ret

InitVolumeTrackbar endp
; ##########################################################################
VolumebarChange proc wParam
  LOCAL pos:DWORD
  LOCAL code:DWORD

  mov eax, wParam
  xor edx, edx
  mov dx, ax
  mov code, edx
  shr eax, 16
  mov pos, eax

  .if code == TB_ENDTRACK
    invoke SendDlgItemMessage, hwnd, IDC_VOL, TBM_GETPOS, 0, 0
    push ax
    shl eax, 16
    pop ax
    invoke waveOutSetVolume, 0, eax
  .endif

  ret

VolumebarChange endp
; ##########################################################################
InitTooltips proc
  LOCAL tt:TOOLINFO

  ; Создание tooltip-окна
  invoke CreateWindowEx, NULL, addr szTooltipClass, NULL, TTS_ALWAYSTIP, \
                         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, \
                         NULL, NULL, hInstance, NULL
  mov hwndTooltip, eax
  ; Заполнение общих элементов структуры
  mov tt.cbSize, sizeof tt
  mov tt.uFlags, TTF_SUBCLASS + TTF_IDISHWND
  mtm tt.hWnd, hwnd
  ; Добавление кнопки "Play"
  invoke GetDlgItem, hwnd, IDC_PB
  mov tt.uId, eax
  mtm tt.lpszText, offset szTipPlay
  invoke SendMessage, hwndTooltip, TTM_ADDTOOL, 0, addr tt
  ; Добавление кнопки "Ring"
  invoke GetDlgItem, hwnd, IDC_SB
  mov tt.uId, eax
  mtm tt.lpszText, offset szTipRing
  invoke SendMessage, hwndTooltip, TTM_ADDTOOL, 0, addr tt
  ; Добавление кнопки "Play"
  invoke GetDlgItem, hwnd, IDC_PRB
  mov tt.uId, eax
  mtm tt.lpszText, offset szTipProcess
  invoke SendMessage, hwndTooltip, TTM_ADDTOOL, 0, addr tt

  ret

InitTooltips endp
; ##########################################################################
ShowTrayMenu proc
  LOCAL pt:POINT
  LOCAL sm:HMENU

  ; Получение необходимых хэндлов
  invoke GetCursorPos, addr pt
  invoke SetForegroundWindow, hwnd
  invoke LoadMenu, hInstance, addr szTrayMenu
  invoke GetSubMenu, eax, 0
  mov sm, eax
  ; Установление свойств меню
  invoke SendDlgItemMessage, hwnd, IDC_TCHB, BM_GETCHECK, 0, 0
  .if eax == BST_CHECKED
    mov edx, MF_BYPOSITION + MF_CHECKED
  .else
    mov edx, MF_BYPOSITION + MF_UNCHECKED
  .endif
  invoke CheckMenuItem, sm, 0, edx
  invoke SendDlgItemMessage, hwnd, IDC_SCHB, BM_GETCHECK, 0, 0
  .if eax == BST_CHECKED
    mov edx, MF_BYPOSITION + MF_CHECKED
  .else
    mov edx, MF_BYPOSITION + MF_UNCHECKED
  .endif
  invoke CheckMenuItem, sm, 1, edx
  invoke SendDlgItemMessage, hwnd, IDC_PCHB, BM_GETCHECK, 0, 0
  .if eax == BST_CHECKED
    mov edx, MF_BYPOSITION + MF_CHECKED
  .else
    mov edx, MF_BYPOSITION + MF_UNCHECKED
  .endif
  invoke CheckMenuItem, sm, 2, edx
  invoke GetMenuState, omenu, IDM_AURN, MF_BYCOMMAND
  .if eax == MF_CHECKED
    invoke CheckMenuItem, sm, IDM_AURN, MF_BYCOMMAND + MF_CHECKED
  .endif
  invoke GetMenuState, omenu, IDM_AUTR, MF_BYCOMMAND
  .if eax == MF_CHECKED
    invoke CheckMenuItem, sm, IDM_AUTR, MF_BYCOMMAND + MF_CHECKED
  .endif
  ; Отображение меню
  invoke TrackPopupMenu, sm, TPM_RIGHTALIGN, pt.x, pt.y, NULL, hwnd, NULL
  invoke PostMessage,hwnd,WM_NULL,0,0

  ret

ShowTrayMenu endp
; ##########################################################################
WavePlayerMenuItem proc

  invoke DialogBoxParam, hInstance, addr szWavePlayerDialog, hwnd, addr WavePlayerProc, NULL

  ret

WavePlayerMenuItem endp
; ##########################################################################
SetSoundEdit proc lpFileName:DWORD

  sdm hwnd, IDC_SED, WM_SETTEXT, 0, lpFileName

  ret

SetSoundEdit endp
; ##########################################################################
InitCfgName proc

  ; Получаем путь
  invoke GetCurrentDirectory, 256, addr szBuf
  invoke wsprintf, addr szCfgName, addr szFmtCnt, addr szBuf, addr szCfgFileName

  ret

InitCfgName endp
; ##########################################################################
InstallAutorun proc
  LOCAL mi:MENUITEMINFO

  invoke GetMenuState, omenu, IDM_AURN, MF_BYCOMMAND
  .if eax == MF_UNCHECKED
    invoke RegOpenKeyEx, HKEY_LOCAL_MACHINE, addr szAutoKey, 0, KEY_WRITE, addr hKey
    invoke GetModuleFileName, hInstance, addr szBuf, MAX_PATH
    invoke lstrlen, addr szBuf
    invoke RegSetValueEx, hKey, addr szAutoKeyValue, 0, REG_SZ, addr szBuf, eax
    invoke RegCloseKey, hKey
  .elseif eax == MF_CHECKED
    invoke RegOpenKeyEx, HKEY_LOCAL_MACHINE, addr szAutoKey, 0, KEY_WRITE, addr hKey
    invoke RegDeleteValue, hKey, addr szAutoKeyValue
    invoke RegCloseKey, hKey
  .endif
  ; Устанавливаем характеристики свойств меню
  invoke CheckAutorun
  .if !eax
    invoke CheckMenuItem, omenu, IDM_AURN, MF_BYCOMMAND + MF_CHECKED
  .else
    invoke CheckMenuItem, omenu, IDM_AURN, MF_BYCOMMAND + MF_UNCHECKED
  .endif

  ret

InstallAutorun endp
; #########################################################################
CheckAutorun proc
  LOCAL rv:DWORD
  LOCAL bsize:DWORD

  mov bsize, MAX_PATH
  invoke RegOpenKeyEx, HKEY_LOCAL_MACHINE, addr szAutoKey, 0, KEY_READ, addr hKey
  invoke RegQueryValueEx, hKey, addr szAutoKeyValue, 0, addr rv, addr szBuf, addr bsize
  push eax
  invoke RegCloseKey, hKey
  pop eax

  ret

CheckAutorun endp
; #########################################################################
InitMainMenu proc

  ; Получаем хэндлы меню окна и подменю 'Опции'
  invoke GetMenu, hwnd
  mov hmenu, eax
  invoke GetSubMenu, hmenu, 0
  mov omenu, eax
  ; Устанавливаем характеристики свойств меню
  invoke CheckAutorun      ; Автозагрузка
  .if !eax
    invoke CheckMenuItem, omenu, IDM_AURN, MF_BYCOMMAND + MF_CHECKED
  .endif

  ret

InitMainMenu endp
; #########################################################################
AutoMinimizeMenuItem proc

  invoke GetMenuState, omenu, IDM_AUTR, MF_BYCOMMAND
  .if eax == MF_UNCHECKED
    invoke CheckMenuItem, omenu, IDM_AUTR, MF_BYCOMMAND + MF_CHECKED
  .elseif eax == MF_CHECKED
    invoke CheckMenuItem, omenu, IDM_AUTR, MF_BYCOMMAND + MF_UNCHECKED
  .endif

  ret

AutoMinimizeMenuItem endp
; #########################################################################

end start