.386
.model flat, stdcall
option casemap :none

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

include bac.mac

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

; #########################################################################
IDC_FILELIST  EQU 1001
IDC_DISKCOMBO EQU 1002
; #########################################################################
; Отсутствующие константы
; ComboBoxEx
CBEM_INSERTITEM   EQU WM_USER+1
CBEM_SETIMAGELIST EQU WM_USER+2
CBEM_GETCOMBOCONTROL EQU WM_USER+6
COMBOBOXEXITEM STRUCT
  imask          dd ?
  iItem          dd ?
  pszText        dd ?
  cchTextMax     dd ?
  iImage         dd ?
  iSelectedImage dd ?
  iOverlay       dd ?
  iIndent        dd ?
  lParam         dd ?
COMBOBOXEXITEM ENDS
CBEIF_TEXT          EQU 1h
CBEIF_IMAGE         EQU 2h
CBEIF_SELECTEDIMAGE EQU 4h
CBEIF_OVERLAY       EQU 8h
CBEIF_INDENT        EQU 10h
CBEIF_LPARAM        EQU 20h
CBEIF_DI_SETITEM    EQU 10000000h
CBEN_ENDEDIT        EQU -805
NMCBEENDEDIT STRUCT

  hdr NMHDR <>
  fChanged BOOL ?
  iNewSelection DWORD ?
  szText db 260 dup(?)
  iWhy DWORD ?

NMCBEENDEDIT ENDS
; #########################################################################
WavePlayerProc proto :HWND, :UINT, :WPARAM, :LPARAM
InitDialog proto
FillDriveCombo proto
InitImages proto
AddDrive proto :DWORD, :DWORD
InitTempList proto
FillTLWithDirs proto
FillTLWithWavs proto
CopyTLtoFileList proto
DirListItemClick proto
LoadFileList proto
DirListItemChange proto
CBDirChange proto
FileListProc proto :HWND, :UINT, :WPARAM, :LPARAM
SetSoundEdit proto :DWORD
; #########################################################################
EXTERN hInstance:HINSTANCE
; #########################################################################

.data

szListBox db "LISTBOX", 0
szFileAll db "*.*", 0
szFileWave db "*.wav", 0
szDot db ".", 0

.data?

hwndPlay dd ?
hDirList dd ?
hDiskCombo dd ?
himgDisk dd ?
himgDir dd ?
hwndTL dd ?
hwndDC dd ?
hwndFL dd ?
OldListProc dd ?
icc INITCOMMONCONTROLSEX <>
szBuf db MAX_PATH dup(?)

.code

; #########################################################################
WavePlayerProc proc uses esi hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM

  .if uMsg == WM_INITDIALOG

    mtm hwndPlay, hWnd
    invoke InitDialog

  .elseif uMsg == WM_CLOSE

    invoke EndDialog, hWnd, 0

  .elseif uMsg == WM_COMMAND
     mov eax, wParam
    .if lParam == 0

    .else
      mov edx, wParam
      shr edx, 16
      .if ax == IDC_FILELIST
        .if dx == LBN_DBLCLK
          invoke DirListItemClick
        .elseif dx == LBN_SELCHANGE
          invoke DirListItemChange
        .endif
      .elseif ax == IDC_DISKCOMBO
        .if dx == CBN_SELCHANGE
          invoke CBDirChange
        .endif
      .endif
    .endif

  .else

    mov eax, FALSE
    ret

  .endif

    ret

WavePlayerProc endp
; #########################################################################
InitDialog proc

  invoke GetDlgItem, hwndPlay, IDC_FILELIST
  mov hDirList, eax
  invoke GetDlgItem, hwndPlay, IDC_DISKCOMBO
  mov hDiskCombo, eax
  invoke InitImages
  invoke FillDriveCombo
  invoke LoadFileList
  sdm hwndPlay,  IDC_DISKCOMBO, CBEM_GETCOMBOCONTROL, 0, 0
  mov hwndDC, eax
  invoke GetDlgItem, hwndPlay, IDC_FILELIST
  mov hwndFL, eax
  invoke SetWindowLong, eax, GWL_WNDPROC, addr FileListProc
  mov OldListProc, eax
  invoke SetFocus, hwndFL
  sdm hwndPlay,  IDC_FILELIST, LB_SETCURSEL, 0, 0

  ret

InitDialog endp
; #########################################################################
FillDriveCombo proc uses ebx
  LOCAL counter:DWORD

  ; Начальная инициализация
  invoke InitImages
  invoke InitTempList
  ; Получаем строку, содержащую все логические диски
  invoke GetLogicalDriveStrings, MAX_PATH, addr szBuf
  mov ebx, offset szBuf
  ; Анализируем полученную строку
  mov counter, 0
  .repeat
    invoke AddDrive, ebx, counter
    add ebx, 4
    inc counter
  .until byte ptr [ebx+1] == 0

  ret

FillDriveCombo endp
; #########################################################################
InitImages proc

  ; создаем и заполняем image list listview
  invoke ImageList_Create, 16, 16, ILC_COLOR8 + ILC_MASK, 2, 10
  mov himgDir, eax
  invoke LoadBitmap, hInstance, 10101           ; folder
  invoke ImageList_AddMasked, himgDir, eax, 00CBCBCBh
  invoke LoadBitmap, hInstance, 10102           ; sound
  invoke ImageList_AddMasked, himgDir, eax, 00CBCBCBh
  ; создаем и заполняем image list combo box'а
  invoke ImageList_Create, 16, 16, ILC_COLOR8 + ILC_MASK, 3, 10
  mov himgDisk, eax
  invoke LoadBitmap, hInstance, 10103           ; floppy
  invoke ImageList_AddMasked, himgDisk, eax, 00CBCBCBh
  invoke LoadBitmap, hInstance, 10104           ; hdd
  invoke ImageList_AddMasked, himgDisk, eax, 00CBCBCBh
  invoke LoadBitmap, hInstance, 10105           ; cdrom
  invoke ImageList_AddMasked, himgDisk, eax, 00CBCBCBh
  ; Устанавливаем прозрачность
  invoke ImageList_SetBkColor, himgDisk, CLR_NONE
  invoke ImageList_SetBkColor, himgDir, CLR_NONE
  ; Ассоциируем image list'ы с соответсвующими контролами
  invoke SendDlgItemMessage, hwndPlay,  IDC_DISKCOMBO, CBEM_SETIMAGELIST, 0, himgDisk

  ret

InitImages endp
; #########################################################################
AddDrive proc drvname:DWORD, counter:DWORD
  LOCAL cbi:COMBOBOXEXITEM

  mov cbi.imask, CBEIF_TEXT + CBEIF_IMAGE + CBEIF_SELECTEDIMAGE
  mtm cbi.iItem, counter
  mtm cbi.pszText, drvname
  ; Определяем тип привода
  invoke GetDriveType, ebx
  .if eax == DRIVE_REMOVABLE
    mov edx, 0
  .elseif eax == DRIVE_CDROM
    mov edx, 2
  .else
    mov edx, 1
  .endif
  mov cbi.iImage, edx
  mov cbi.iSelectedImage, edx
  invoke SendDlgItemMessage, hwndPlay,  IDC_DISKCOMBO, CBEM_INSERTITEM, 0, addr cbi

  ret

AddDrive endp
; #########################################################################
InitTempList proc

  invoke CreateWindowEx, NULL, addr szListBox, NULL, LBS_HASSTRINGS + LBS_SORT, 1000, 1000, 100, 100, hwndPlay,  \
                         NULL, hInstance, NULL
  mov hwndTL, eax

  ret

InitTempList endp
; #########################################################################
FillTLWithDirs proc
  LOCAL ff:WIN32_FIND_DATA
  LOCAL fh:HANDLE
  LOCAL fDot:DWORD

  ; Очищаем список
  invoke SendMessage, hwndTL, LB_RESETCONTENT, 0, 0
  ; Делаем пробег по текущей директории и добавляем во временный список директории
  invoke FindFirstFile, addr szFileAll, addr ff
  mov fh, eax
  invoke lstrcmp, addr szDot, addr ff.cFileName
  mov fDot, eax
  .repeat
    .if (ff.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY && fDot)
      invoke SendMessage, hwndTL, LB_ADDSTRING, 0, addr ff.cFileName
    .endif
    invoke FindNextFile, fh, addr ff
    inc fDot
  .until eax == 0

  ret

FillTLWithDirs endp
; #########################################################################
FillTLWithWavs proc
  LOCAL ff:WIN32_FIND_DATA
  LOCAL fh:HANDLE

  ; Очищаем список
  invoke SendMessage, hwndTL, LB_RESETCONTENT, 0, 0
  ; Делаем пробег по текущей директории и добавляем во временный список директории
  invoke FindFirstFile, addr szFileWave, addr ff
  mov fh, eax
  .if eax != -1
    .repeat
      invoke SendMessage, hwndTL, LB_ADDSTRING, 0, addr ff.cFileName
      invoke FindNextFile, fh, addr ff
    .until eax == 0
  .endif

  ret

FillTLWithWavs endp
; #########################################################################
CopyTLtoFileList proc uses ebx
  LOCAL iquan:DWORD

  ; Получаем количество элементов во временном списке
  invoke SendMessage, hwndTL, LB_GETCOUNT, 0, 0
  mov iquan, eax
  ; Копируем данные из временного списка в наш список
  xor ebx, ebx
  .while (ebx < iquan)
    invoke SendMessage, hwndTL, LB_GETTEXT, ebx, addr szBuf
    sdm hwndPlay,  IDC_FILELIST, LB_ADDSTRING, 0, addr szBuf
    inc ebx
  .endw

  ret

CopyTLtoFileList endp
; #########################################################################
DirListItemClick proc
  LOCAL rv:DWORD

  ; Получаем имя файла
  sdm hwndPlay,  IDC_FILELIST, LB_GETCURSEL, 0, 0
  sdm hwndPlay,  IDC_FILELIST, LB_GETTEXT, eax, addr szBuf
  ; Получаем аттрибуты файла
  invoke GetFileAttributes, addr szBuf
  ; Если директория - выводим ее содержимое, если wav - 'выбираем' его
  .if eax & FILE_ATTRIBUTE_DIRECTORY
    invoke SetCurrentDirectory, addr szBuf
    invoke LoadFileList
  .else
    invoke GetFullPathName, addr szBuf, MAX_PATH, addr szBuf, addr rv
    invoke SetSoundEdit, addr szBuf
    invoke SendMessage, hwndPlay, WM_CLOSE, 0, 0
  .endif
  sdm hwndPlay, IDC_FILELIST, LB_SETCURSEL, 0, 0

  ret

DirListItemClick endp
; #########################################################################
LoadFileList proc

  sdm hwndPlay, IDC_FILELIST, LB_RESETCONTENT, 0, 0
  invoke FillTLWithDirs
  invoke CopyTLtoFileList
  invoke FillTLWithWavs
  invoke CopyTLtoFileList

  ret

LoadFileList endp
; #########################################################################
DirListItemChange proc

  ; Получаем имя файла и проигрываем его
  sdm hwndPlay, IDC_FILELIST, LB_GETCURSEL, 0, 0
  sdm hwndPlay, IDC_FILELIST, LB_GETTEXT, eax, addr szBuf
  invoke GetFileAttributes, addr szBuf
  .if !(eax & FILE_ATTRIBUTE_DIRECTORY)
    invoke PlaySound, NULL, 0, 0
    invoke PlaySound, addr szBuf, NULL, SND_FILENAME + SND_ASYNC + SND_NOWAIT
  .endif

  ret

DirListItemChange endp
; #########################################################################
CBDirChange proc

  invoke SendMessage, hwndDC, CB_GETCURSEL, 0, 0
  invoke SendMessage, hwndDC, CB_GETLBTEXT, eax, addr szBuf
  invoke SetCurrentDirectory, addr szBuf
  .if eax
    invoke LoadFileList
  .endif

  ret

CBDirChange endp
; #########################################################################
FileListProc proc hList:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD

  .if uMsg == WM_KEYUP
    mov eax, wParam
    .if al == VK_RETURN
      invoke DirListItemClick
    .else
      invoke CallWindowProc, OldListProc, hList, uMsg, wParam, lParam
      ret
    .endif

  .else

    invoke CallWindowProc, OldListProc, hList, uMsg, wParam, lParam
    ret

  .endif

  xor eax, eax
  ret

FileListProc endp
; #########################################################################

end