{player service} unit srv_player; interface uses windows,common,wat_api; function GetPlayerNote(name:PAnsiChar):pWideChar; function SetPlayerIcons(fname:pAnsiChar):integer; function LoadFromFile(fname:PAnsiChar):integer; function ProcessPlayerLink:integer; function ServicePlayer(wParam:WPARAM;lParam:LPARAM):int_ptr;cdecl; function SendCommand (wParam:WPARAM;lParam:LPARAM;flags:integer):int_ptr; procedure ClearPlayers; // options procedures procedure DefFillPlayerList (hwndList:HWND); procedure DefCheckPlayerList(hwndList:HWND); type MusEnumProc = function(param:PAnsiChar;lParam:LPARAM):bool;stdcall; function EnumPlayers(param:MusEnumProc;lParam:LPARAM):bool; // "Get info" procedures function CheckPlayers (var dst:tSongInfo;flags:cardinal):integer; function CheckFile (var dst:tSongInfo;flags:cardinal;timeout:cardinal):integer; function GetChangingInfo(var dst:tSongInfo;flags:cardinal):integer; function GetInfo (var dst:tSongInfo;flags:cardinal):integer; // support procedures procedure ClearSongInfoData(var dst:tSongInfo;withFree:bool); procedure ClearPlayerInfo (var dst:tSongInfo;withFree:bool); procedure ClearFileInfo (var dst:tSongInfo;withFree:bool); procedure ClearChangingInfo(var dst:tSongInfo;withFree:bool); procedure ClearTrackInfo (var dst:tSongInfo;withFree:bool); procedure CopyPlayerInfo (const src:tSongInfo;var dst:tSongInfo); procedure CopyFileInfo (const src:tSongInfo;var dst:tSongInfo); procedure CopyChangingInfo(const src:tSongInfo;var dst:tSongInfo); procedure CopyTrackInfo (const src:tSongInfo;var dst:tSongInfo); type pwPlayer = ^twPlayer; twPlayer = record This:pPlayerCell; Next:pwPlayer; end; const PlayerLink:pwPlayer=nil; implementation uses shellapi,CommCtrl ,appcmdapi,io,syswin,wrapper,srv_format,winampapi,msninfo,memini; type pPlyArray = ^tPlyArray; tPlyArray = array [0..10] of tPlayerCell; type pTmplCell = ^tTmplCell; tTmplCell = record p_class, p_text :PAnsiChar; p_class1, p_text1 :PAnsiChar; p_file :PAnsiChar; p_prefix :pWideChar; p_postfix:pWideChar; end; const StartSize = 32; Step = 8; buflen = 2048; const plyLink:pPlyArray=nil; PlyNum:integer=0; PlyMax:integer=0; function ProcessPlayerLink:integer; var ptr:pwPlayer; begin ptr:=PlayerLink; result:=0; while ptr<>nil do begin ServicePlayer(WAT_ACT_REGISTER,lparam(ptr.This)); ptr:=ptr^.Next; inc(result); end; end; function SetPlayerIcons(fname:pAnsiChar):integer; var i,j:integer; buf:array [0..255] of AnsiChar; p,pp:pAnsiChar; lhIcon:HICON; begin result:=LoadLibraryA(fname); if result<>0 then begin p:=StrCopyE(buf,'Player_'); i:=0; while i0 then begin if Icon<>0 then DestroyIcon(Icon); Icon:=lhIcon; end; end; inc(i); end; FreeLibrary(result); end; end; function EnumPlayers(param:MusEnumProc;lParam:LPARAM):bool; var tmp:pPlyArray; i,j:integer; begin if (PlyNum>0) and (@param<>nil) then begin GetMem(tmp,PlyNum*SizeOf(tPlayerCell)); move(PlyLink^,tmp^,PlyNum*SizeOf(tPlayerCell)); i:=0; j:=PlyNum; repeat if not param(tmp^[i].Desc,lParam) then break; inc(i); until i=j; FreeMem(tmp); result:=true; end else result:=false; end; procedure PreProcess; // BASS to start var i:integer; tmp:tPlayerCell; begin i:=1; while i<(PlyNum-1) do begin if (plyLink^[i].flags and WAT_OPT_FIRST)<>0 then begin tmp:=plyLink^[i]; move(plyLink^[0],plyLink^[1],SizeOf(tPlayerCell)*i); plyLink^[0]:=tmp; { move(plyLink^[i],tmp,SizeOf(tPlayerCell)); move(plyLink^[0],plyLink^[1],SizeOf(tPlayerCell)*i); move(tmp,plyLink^[0],SizeOf(tPlayerCell)); } break; end; inc(i); end; if (plyLink^[0].flags and WAT_OPT_LAST)<>0 then begin tmp:=plyLink^[0]; move(plyLink^[1],plyLink^[0],SizeOf(tPlayerCell)*(PlyNum-1)); plyLink^[PlyNum-1]:=tmp; { move(plyLink^[0],tmp,SizeOf(tPlayerCell)); move(plyLink^[1],plyLink^[0],SizeOf(tPlayerCell)*(PlyNum-1)); move(tmp,plyLink^[PlyNum-1],SizeOf(tPlayerCell)); } end; end; procedure PostProcess; // Winamp clone to the end var i,j:integer; tmp:tPlayerCell; begin i:=1; j:=PlyNum-1; while i0 then begin tmp:=plyLink^[i]; move(plyLink^[i+1],plyLink^[i],SizeOf(tPlayerCell)*(PlyNum-i-1)); plyLink^[PlyNum-1]:=tmp; { move(plyLink^[i],tmp,SizeOf(tPlayerCell)); move(plyLink^[i+1],plyLink^[i],SizeOf(tPlayerCell)*(PlyNum-i-1)); move(tmp,plyLink^[PlyNum-1],SizeOf(tPlayerCell)); }// break; i:=1; dec(j); continue; end; inc(i); end; end; function FindPlayer(desc:PAnsiChar):integer; var i:integer; begin if (desc<>nil) and (desc^<>#0) then begin i:=0; while i=0 then result:=plyLink^[i].Notes else result:=nil; end; procedure DefFillPlayerList(hwndList:HWND); var item:LV_ITEMA; lvc:TLVCOLUMN; i,newItem:integer; il:HIMAGELIST; //!! begin FillChar(item,SizeOf(item),0); FillChar(lvc,SizeOf(lvc),0); ListView_SetExtendedListViewStyle(hwndList, LVS_EX_CHECKBOXES); lvc.mask:=LVCF_FMT or LVCF_WIDTH; lvc.fmt:=LVCFMT_LEFT; lvc.cx:=160; ListView_InsertColumn(hwndList,0,lvc); item.mask:=LVIF_TEXT or LVIF_IMAGE; //!! i:=0; il:=ImageList_Create(16,16,ILC_COLOR32 or ILC_MASK,0,1); //!! while i=0 then begin if (plyLink^[i].flags and WAT_OPT_DISABLED)=0 then ListView_SetCheckState(hwndList,newItem,TRUE); end; inc(i); end; ImageList_Destroy(SendMessage(hwndList,LVM_SETIMAGELIST,LVSIL_SMALL,il)); //!! // ListView_SetColumnWidth(hwndList,0,LVSCW_AUTOSIZE); end; procedure DefCheckPlayerList(hwndList:HWND); var i,j,k:integer; item:LV_ITEMA; szTemp:array [0..109] of AnsiChar; p:pPlayerCell; begin FillChar(item,SizeOf(item),0); item.mask :=LVIF_TEXT; item.pszText :=@szTemp; item.cchTextMax:=100; k:=ListView_GetItemCount(hwndList)-1; for i:=0 to k do begin item.iItem:=i; SendMessageA(hwndList,LVM_GETITEMA,0,lparam(@item)); j:=FindPlayer(item.pszText); if j<>WAT_RES_NOTFOUND then begin p:=@plyLink^[j]; if ListView_GetCheckState(hwndList,i)=0 then p^.flags:=p^.flags or WAT_OPT_DISABLED else p^.flags:=p^.flags and not WAT_OPT_DISABLED; end; end; end; procedure ClearTemplate(tmpl:pTmplCell); begin with tmpl^ do begin mFreeMem(p_class); mFreeMem(p_text); mFreeMem(p_class1); mFreeMem(p_text1); mFreeMem(p_file); mFreeMem(p_prefix); mFreeMem(p_postfix); end; FreeMem(tmpl); end; function ServicePlayer(wParam:WPARAM;lParam:LPARAM):int_ptr;cdecl; var p:integer; i:integer; nl:pPlyArray; tmp:tPlayerCell; begin result:=WAT_RES_ERROR; if LoWord(wParam)=WAT_ACT_REGISTER then begin if pPlayerCell(lParam)^.Check=nil then exit; p:=0; end else p:=FindPlayer(PAnsiChar(lParam)); case LoWord(wParam) of WAT_ACT_REGISTER: begin p:=FindPlayer(pPlayerCell(lParam)^.Desc); if (p=WAT_RES_NOTFOUND) or ((wParam and WAT_ACT_REPLACE)<>0) then begin if (p<>WAT_RES_NOTFOUND) and ((plyLink^[p].flags and WAT_OPT_ONLYONE)<>0) then exit; if p=WAT_RES_NOTFOUND then begin p:=PlyNum; result:=WAT_RES_OK; if PlyNum=PlyMax then // expand array when append begin if PlyMax=0 then PlyMax:=StartSize else inc(PlyMax,Step); GetMem(nl,PlyMax*SizeOf(tPlayerCell)); if plyLink<>nil then begin move(plyLink^,nl^,PlyNum*SizeOf(tPlayerCell)); FreeMem(plyLink); end; plyLink:=nl; end; FillChar(plyLink^[p],SizeOf(tPlayerCell),0); // doubling notes if (pPlayerCell(lParam)^.Notes<>nil) and ((pPlayerCell(lParam)^.flags and WAT_OPT_TEMPLATE)=0) then begin i:=(StrLenW(pPlayerCell(lParam)^.Notes)+1)*SizeOf(WideChar); GetMem(plyLink^[p].Notes,i); move(pPlayerCell(lParam)^.Notes^,plyLink^[p].Notes^,i); end else plyLink^[p].Notes:=pPlayerCell(lParam)^.Notes; // doubling description i:=StrLen(pPlayerCell(lParam)^.Desc)+1; GetMem(plyLink^[p].Desc,i); move(pPlayerCell(lParam)^.Desc^,plyLink^[p].Desc^,i); // doubling url if pPlayerCell(lParam)^.URL<>nil then begin with plyLink^[p] do begin i:=StrLen(pPlayerCell(lParam)^.URL)+1; GetMem(URL,i); move(pPlayerCell(lParam)^.URL^,URL^,i); end; end else plyLink^[p].URL:=nil; inc(PlyNum); end else // existing player begin if (plyLink^[p].flags and WAT_OPT_TEMPLATE)=0 then result:=int_ptr(plyLink^[p].Check) else begin // remove any info from templates result:=WAT_RES_OK; ClearTemplate(pTmplCell(plyLink^[p].Check)); end; end; // fill info with plyLink^[p] do begin flags:=pPlayerCell(lParam)^.flags; if URL<>nil then flags:=flags or WAT_OPT_HASURL; if pPlayerCell(lParam)^.Icon<>0 then begin if icon<>0 then DestroyIcon(icon); icon:=CopyIcon(pPlayerCell(lParam)^.Icon); end; Init :=pPlayerCell(lParam)^.Init; DeInit :=pPlayerCell(lParam)^.DeInit; Check :=pPlayerCell(lParam)^.Check; GetStatus:=pPlayerCell(lParam)^.GetStatus; GetName :=pPlayerCell(lParam)^.GetName; GetInfo :=pPlayerCell(lParam)^.GetInfo; Command :=pPlayerCell(lParam)^.Command; if Init<>nil then tInitProc(Init); end; // PreProcess; PostProcess; end; end; WAT_ACT_UNREGISTER: begin if p<>WAT_RES_NOTFOUND then begin dec(PlyNum); if plyLink^[p].DeInit<>nil then tDeInitProc(plyLink^[p].DeInit); FreeMem(plyLink^[p].Desc); if (plyLink^[p].flags and WAT_OPT_TEMPLATE)<>0 then ClearTemplate(pTmplCell(plyLink^[p].Check)); if pWAT_RES_NOTFOUND then begin plyLink^[p].flags:=plyLink^[p].flags or WAT_OPT_DISABLED; result:=WAT_RES_DISABLED end; end; WAT_ACT_ENABLE: begin if p<>WAT_RES_NOTFOUND then begin plyLink^[p].flags:=plyLink^[p].flags and not WAT_OPT_DISABLED; result:=WAT_RES_ENABLED end; end; WAT_ACT_GETSTATUS: begin if p<>WAT_RES_NOTFOUND then begin if (plyLink^[p].flags and WAT_OPT_DISABLED)<>0 then result:=WAT_RES_DISABLED else result:=WAT_RES_ENABLED; end; end; WAT_ACT_SETACTIVE: begin if p>0 then begin tmp:=plyLink^[p]; move(plyLink^[0],plyLink^[1],SizeOf(tPlayerCell)*p); plyLink^[0]:=tmp; { move(plyLink^[p],tmp ,SizeOf(tPlayerCell)); move(plyLink^[0],plyLink^[1],SizeOf(tPlayerCell)*p); move(tmp ,plyLink^[0],SizeOf(tPlayerCell)); } end; // PreProcess; // PostProcess; end; end; end; function LoadFromFile(fname:PAnsiChar):integer; var buf:pAnsiChar; ptr:PAnsiChar; NumPlayers:integer; pcell:pTmplCell; rec:tPlayerCell; st,sec:pointer; begin result:=0; st:=OpenStorage(fname); if st=nil then exit; buf:=GetSectionList(st); ptr:=buf; NumPlayers:=0; while ptr^<>#0 do begin sec:=SearchSection(st,ptr); FillChar(rec,SizeOf(rec),0); GetMem(pcell,SizeOf(tTmplCell)); StrDup(pcell^.p_class ,GetParamSectionStr(sec,'class' )); StrDup(pcell^.p_text ,GetParamSectionStr(sec,'text' )); StrDup(pcell^.p_class1,GetParamSectionStr(sec,'class1')); StrDup(pcell^.p_text1 ,GetParamSectionStr(sec,'text1' )); StrDup(pcell^.p_file ,GetParamSectionStr(sec,'file' )); AnsiToWide(GetParamSectionStr(sec,'prefix' ),pcell^.p_prefix ); AnsiToWide(GetParamSectionStr(sec,'postfix'),pcell^.p_postfix); rec.URL :=GetParamSectionStr(sec,'url'); rec.Desc :=ptr; rec.flags:=GetParamSectionInt(sec,'flags') or WAT_OPT_TEMPLATE; rec.Check:=pointer(pcell); UTF8ToWide(GetParamSectionStr(sec,'notes'),rec.Notes); if ServicePlayer(WAT_ACT_REGISTER,lparam(@rec))=WAT_RES_ERROR then begin ClearTemplate(pcell); // mFreeMem(rec.URL); mFreeMem(rec.Notes); end else inc(NumPlayers); while ptr^<>#0 do inc(ptr); inc(ptr); end; FreeSectionList(buf); CloseStorage(st); result:=NumPlayers; end; function CheckTmpl(lwnd:HWND;cell:pTmplCell;flags:integer):HWND; var tmp,EXEName:PAnsiChar; ltmp,lcycle:boolean; lclass,ltext:PAnsiChar; begin lclass:=cell.p_class; ltext :=cell.p_text; lcycle:=false; repeat result:=lwnd; if (lclass<>nil) or (ltext<>nil) then repeat result:=FindWindowExA(0,result,lclass,ltext); if result=0 then break; // check filename if cell.p_file<>NIL then begin tmp:=Extract(GetEXEByWnd(result,EXEName),true); mFreeMem(EXEName); ltmp:=lstrcmpia(tmp,cell.p_file)=0; mFreeMem(tmp); if not ltmp then continue; end; exit; until false; if lcycle then break; lclass:=cell.p_class1; ltext :=cell.p_text1; if (lclass=nil) and (ltext=nil) then break; lcycle:=not lcycle; until false; end; // find active player function CheckAllPlayers(flags:integer;var status:integer; var PlayerChanged:bool):integer; const PrevPlayerName:PAnsiChar=nil; var stat,act,oldstat,i,j:integer; tmp:tPlayerCell; wwnd,lwnd:HWND; begin i:=0; result:=WAT_RES_NOTFOUND; PlayerChanged:=true; PreProcess; oldstat:=-1; act:=-1; stat:=WAT_MES_UNKNOWN; wwnd:=0; while i0 then begin lwnd:=CheckTmpl(lwnd,plyLink^[i].Check,plyLink^[i].flags); // find "Winamp" window if (lwnd<>THANDLE(WAT_RES_NOTFOUND)) and (lwnd<>0) and ((plyLink^[i].flags and WAT_OPT_WINAMPAPI)<>0) then begin wwnd:=WinampFindWindow(lwnd); if wwnd<>0 then stat:=WinampGetStatus(wwnd); end; end else begin with plyLink^[i] do begin lwnd:=tCheckProc(Check)(lwnd,flags); if (lwnd<>THANDLE(WAT_RES_NOTFOUND)) and (lwnd<>0) and (GetStatus<>nil) then stat:=tStatusProc(GetStatus)(lwnd); end; end; if (lwnd<>THANDLE(WAT_RES_NOTFOUND)) and (lwnd<>0) then begin if (stat=WAT_MES_PLAYING) or ((flags and WAT_OPT_CHECKALL)=0) then begin act :=i; result:=lwnd; break; end else begin case stat of WAT_MES_STOPPED: j:=00; WAT_MES_UNKNOWN: j:=10; WAT_MES_PAUSED : j:=20; else j:=00; end; if oldstat0 then break; until false; if (result<>WAT_RES_NOTFOUND) and (result<>0) and ((stat=WAT_MES_PLAYING) or ((flags and WAT_OPT_CHECKALL)=0)) then break; end; inc(i); end; if act>=0 then begin if result=1 then result:=0 //!! for example, mradio else if wwnd<>0 then result:=wwnd; if act>0 then // to first position begin tmp:=plyLink^[act]; move(plyLink^[0],plyLink^[1],SizeOf(tPlayerCell)*act); plyLink^[0]:=tmp; { move(plyLink^[act],tmp ,SizeOf(tPlayerCell)); move(plyLink^[0 ],plyLink^[1],SizeOf(tPlayerCell)*act); move(tmp ,plyLink^[0],SizeOf(tPlayerCell)); } end; if PrevPlayerName=plyLink^[0].Desc then PlayerChanged:=false else PrevPlayerName:=plyLink^[0].Desc; status:=stat; end else begin PrevPlayerName:=nil; status:=WAT_PLS_NOTFOUND+WAT_MES_UNKNOWN shl 16; end; PostProcess; end; function TranslateToApp(code:integer):integer; begin case code of WAT_CTRL_PREV : result:=APPCOMMAND_MEDIA_PREVIOUSTRACK; WAT_CTRL_PLAY : begin if IsW2K then // Win2k+ only result:=APPCOMMAND_MEDIA_PLAY_PAUSE else result:=APPCOMMAND_MEDIA_PLAY; end; WAT_CTRL_PAUSE: result:=APPCOMMAND_MEDIA_PLAY_PAUSE; WAT_CTRL_STOP : result:=APPCOMMAND_MEDIA_STOP; WAT_CTRL_NEXT : result:=APPCOMMAND_MEDIA_NEXTTRACK; WAT_CTRL_VOLDN: result:=APPCOMMAND_VOLUME_DOWN; WAT_CTRL_VOLUP: result:=APPCOMMAND_VOLUME_UP; else result:=-1; end; end; function SendCommand(wParam:WPARAM;lParam:LPARAM;flags:integer):int_ptr; var dummy:bool; wnd:HWND; lstat:integer; begin result:=WAT_RES_ERROR; wnd:=CheckAllPlayers(flags,lstat,dummy); if wnd<>THANDLE(WAT_RES_NOTFOUND) then if plyLink^[0].Command<>nil then result:=tCommandProc(plyLink^[0].Command)(wnd,wParam,lParam) else if (plyLink^[0].flags and WAT_OPT_WINAMPAPI)<>0 then result:=WinampCommand(wnd,wParam+(lParam shl 16)) else if (flags and WAT_OPT_APPCOMMAND)<>0 then begin result:=TranslateToApp(wParam); if result>=0 then result:=SendMMCommand(wnd,result); end; end; // Get Info (default) function GetSeparator(str:pWideChar):dword; begin result:=StrIndexW(str,' '#$2013' '); if result=0 then result:=StrIndexW(str,' - '); if result<>0 then begin result:=result-1 + (3 SHL 16); exit; end; result:=StrIndexW(str,#$2013); if result=0 then result:=StrIndexW(str,'-'); if result>0 then result:=result-1 + (1 SHL 16); end; function DefGetTitle(wnd:HWND;fname,wndtxt:pWideChar):pWideChar; var i:integer; tmp:pWideChar; begin if fname<>nil then tmp:=DeleteKnownExt(ExtractW(fname,true)) else tmp:=wndtxt; if tmp=nil then begin result:=nil; exit; end; StrDupW(result,tmp); i:=GetSeparator(result); if i>0 then StrCopyW(result,result+LoWord(i)+HiWord(i)); if fname<>nil then mFreeMem(tmp); end; function DefGetArtist(wnd:HWND;fname,wndtxt:pWideChar):pWideChar; var i:integer; tmp:pWideChar; begin if fname<>nil then tmp:=DeleteKnownExt(ExtractW(fname,true)) else tmp:=wndtxt; if tmp=nil then begin result:=nil; exit; end; StrDupW(result,tmp); i:=GetSeparator(result); if i>0 then result[LoWord(i)]:=#0; if fname<>nil then mFreeMem(tmp); end; function DefGetVersionText(ver:integer):pWideChar; begin if ver<>0 then begin mGetMem(result,10*SizeOf(WideChar)); IntToHex(result,ver); end else result:=nil; end; function DefGetWndText(wnd:HWND):pWideChar; var p:pWideChar; begin if wnd<>0 then begin result:=GetDlgText(wnd); if result<>nil then begin if (plyLink^[0].flags and WAT_OPT_TEMPLATE)<>0 then begin with pTmplCell(plyLink^[0].Check)^ do begin if p_prefix<>nil then begin p:=StrPosW(result,p_prefix); if p=result then StrCopyW(result,result+StrLenW(p_prefix)); end; if p_postfix<>nil then begin p:=StrPosW(result,p_postfix); if p<>nil then p^:=#0; end; end; end; end; end else result:=nil; end; procedure ClearSongInfoData(var dst:tSongInfo;withFree:bool); begin ClearPlayerInfo (dst,withFree); ClearChangingInfo(dst,withFree); ClearFileInfo (dst,withFree); ClearTrackInfo (dst,withFree); end; procedure CopyChangingInfo(const src:tSongInfo;var dst:tSongInfo); begin dst.time :=src.time; dst.volume :=src.volume; dst.wndtext:=src.wndtext; end; procedure ClearChangingInfo(var dst:tSongInfo;withFree:bool); begin dst.time :=0; dst.volume:=0; if withFree then mFreeMem(dst.wndtext) else dst.wndtext:=nil; end; procedure CopyFileInfo(const src:tSongInfo;var dst:tSongInfo); begin dst.fsize:=src.fsize; dst.date :=src.date; dst.mfile:=src.mfile; end; procedure ClearFileInfo(var dst:tSongInfo;withFree:bool); begin if withFree then mFreeMem(dst.mfile) else dst.mfile:=nil; dst.fsize:=0; dst.date :=0; end; procedure CopyPlayerInfo(const src:tSongInfo;var dst:tSongInfo); begin dst.player :=src.player; dst.txtver :=src.txtver; dst.url :=src.url; dst.icon :=src.icon; dst.plyver :=src.plyver; dst.plwnd :=src.plwnd; dst.winampwnd:=src.winampwnd; end; procedure ClearPlayerInfo(var dst:tSongInfo;withFree:bool); begin if withFree then begin mFreeMem(dst.player); mFreeMem(dst.txtver); mFreeMem(dst.url); if dst.icon<>0 then DestroyIcon(dst.icon); end else begin dst.player:=nil; dst.txtver:=nil; dst.url :=nil; end; dst.icon :=0; dst.plyver :=0; dst.plwnd :=0; dst.winampwnd:=0; end; procedure CopyTrackInfo(const src:tSongInfo;var dst:tSongInfo); begin dst.artist :=src.artist; dst.title :=src.title; dst.album :=src.album; dst.genre :=src.genre; dst.comment :=src.comment; dst.year :=src.year; dst.lyric :=src.lyric; dst.cover :=src.cover; dst.kbps :=src.kbps; dst.khz :=src.khz; dst.channels:=src.channels; dst.track :=src.track; dst.total :=src.total; dst.vbr :=src.vbr; dst.codec :=src.codec; dst.width :=src.width; dst.height :=src.height; dst.fps :=src.fps; end; procedure ClearTrackInfo(var dst:tSongInfo;withFree:bool); begin if withFree then begin mFreeMem(dst.artist); mFreeMem(dst.title); mFreeMem(dst.album); mFreeMem(dst.genre); mFreeMem(dst.comment); mFreeMem(dst.year); mFreeMem(dst.lyric); mFreeMem(dst.cover); end else begin dst.artist :=nil; dst.title :=nil; dst.album :=nil; dst.genre :=nil; dst.comment:=nil; dst.year :=nil; dst.lyric :=nil; dst.cover :=nil; end; dst.kbps :=0; dst.khz :=0; dst.channels:=0; dst.track :=0; dst.total :=0; dst.vbr :=0; dst.codec :=0; dst.width :=0; dst.height :=0; dst.fps :=0; end; function CheckPlayers(var dst:tSongInfo;flags:cardinal):integer; var PlayerChanged:bool; fname:pWideChar; begin result:=CheckAllPlayers(flags,dst.status,PlayerChanged); if result<>WAT_RES_NOTFOUND then begin if PlayerChanged then begin ClearPlayerInfo(dst,false); AnsiToWide(plyLink^[0].Desc,dst.player); dst.plwnd:=result; FastAnsiToWide(plyLink^[0].URL,dst.url); if plyLink^[0].icon<>0 then dst.icon:=CopyIcon(plyLink^[0].icon) else if result<>0 then begin if GetEXEByWnd(dst.plwnd,fname)<>nil then begin dst.icon:=ExtractIconW(hInstance,fname,0); if dst.icon=1 then dst.icon:=0; if dst.icon<>0 then plyLink^[0].icon:=CopyIcon(dst.icon); mFreeMem(fname); end; end; if plyLink^[0].GetInfo<>nil then tInfoProc(plyLink^[0].GetInfo)(dst,flags or WAT_OPT_PLAYERDATA) else if (plyLink^[0].flags and WAT_OPT_WINAMPAPI)<>0 then WinampGetInfo(wparam(@dst),flags or WAT_OPT_PLAYERDATA); if (plyLink^[0].flags and WAT_OPT_PLAYERINFO)=0 then if dst.txtver=NIL then dst.txtver:=DefGetVersionText(dst.plyver); result:=WAT_RES_NEWPLAYER; end else begin dst.plwnd:=result; // to prevent same player, another instance result:=WAT_RES_OK; end end; end; function CheckFile(var dst:tSongInfo;flags:cardinal;timeout:cardinal):integer; var fname:pWideChar; tmp:integer; remote,FileChanged:boolean; f:THANDLE; ftime:int64; begin if plyLink^[0].GetName<>nil then fname:=tNameProc(plyLink^[0].GetName)(dst.plwnd,flags) else fname:=nil; if (fname=nil) and (dst.plwnd<>0) then begin tmp:=0; if (flags and WAT_OPT_MULTITHREAD)<>0 then tmp:=tmp or gffdMultiThread; if (flags and WAT_OPT_KEEPOLD )<>0 then tmp:=tmp or gffdOld; fname:=GetFileFromWnd(dst.plwnd,KnownFileType,tmp,timeout); end; if fname<>nil then begin remote:=StrPosW(fname,'://')<>nil; // file changing time (local/lan only) if not remote then begin f:=Reset(fname); if f<>THANDLE(INVALID_HANDLE_VALUE) then begin GetFileTime(f,nil,nil,@ftime); CloseHandle(f); end; end; // same file if (dst.mfile<>nil) and (lstrcmpiw(dst.mfile,fname)=0) then begin if (not remote) and ((flags and WAT_OPT_CHECKTIME)<>0) then FileChanged:=dst.date<>ftime else FileChanged:=false; end else // new filename begin FileChanged:=true; end; // if not proper ext (we don't working with it) //!!!! check for remotes if (not remote) and (CheckExt(fname)=WAT_RES_NOTFOUND) then begin mFreeMem(fname); result:=WAT_RES_NOTFOUND; exit; end; if FileChanged {or isContainer(fname)} then begin ClearFileInfo(dst,false); dst.mfile:=fname; //!! must be when format recognized or remote dst.date:=ftime; //!! dst.fsize:=GetFSize(dst.mfile); result:=WAT_RES_NEWFILE; end else begin result:=WAT_RES_OK; mFreeMem(fname); end; end else begin result:=WAT_RES_NOTFOUND; end; end; // Get Info - main procedure function GetChangingInfo(var dst:tSongInfo;flags:cardinal):integer; begin result:=WAT_RES_OK; ClearChangingInfo(dst,false); if plyLink^[0].GetInfo<>nil then tInfoProc(plyLink^[0].GetInfo)(dst,flags or WAT_OPT_CHANGES) else if (plyLink^[0].flags and WAT_OPT_WINAMPAPI)<>0 then WinampGetInfo(wparam(@dst),flags or WAT_OPT_CHANGES); if (plyLink^[0].flags and WAT_OPT_PLAYERINFO)=0 then if dst.wndtext=NIL then dst.wndtext:=DefGetWndText(dst.plwnd); end; function GetInfo(var dst:tSongInfo;flags:cardinal):integer; var oldartist,oldtitle:pWideChar; fname:pWideChar; remote:boolean; lmsnInfo:pMSNInfo; begin result:=WAT_RES_OK; remote:=StrPosW(dst.mfile,'://')<>nil; // if remote or ((plyLink^[0].flags and WAT_OPT_PLAYERINFO)<>0) then oldartist:=dst.artist; oldtitle:=dst.title; ClearTrackInfo(dst,false); // info from player if plyLink^[0].GetInfo<>nil then tInfoProc(plyLink^[0].GetInfo)(dst,flags and not WAT_OPT_CHANGES) else if (plyLink^[0].flags and WAT_OPT_WINAMPAPI)<>0 then WinampGetInfo(wparam(@dst),flags and not WAT_OPT_CHANGES); // info from file GetFileFormatInfo(dst); if (plyLink^[0].flags and WAT_OPT_PLAYERINFO)=0 then with dst do begin if remote then fname:=nil else fname:=mfile; lmsnInfo:=GetMSNInfo; if lmsnInfo<>nil then begin if artist=NIL then StrDupW(artist,lmsnInfo.msnArtist); if title =NIL then StrDupW(title ,lmsnInfo.msnTitle); if album =NIL then StrDupW(album ,lmsnInfo.msnAlbum); end; if artist=NIL then artist:=DefGetArtist(plwnd,fname,wndtext); if title =NIL then title :=DefGetTitle (plwnd,fname,wndtext); end; if remote or ((plyLink^[0].flags and WAT_OPT_PLAYERINFO)<>0) or isContainer(dst.mfile) then begin if (oldartist=oldtitle) or ((oldartist<>nil) and (StrCmpW(dst.artist,oldartist)<>0)) or ((oldtitle <>nil) and (StrCmpW(dst.title ,oldtitle )<>0)) then begin result:=WAT_RES_NEWFILE; end; end; end; procedure ClearPlayers; begin if PlyNum>0 then begin repeat dec(PlyNum); with plyLink^[PlyNum] do begin if DeInit<>nil then tDeInitProc(DeInit); FreeMem(Desc); if URL<>nil then FreeMem(URL); if icon<>0 then DestroyIcon(icon); if (flags and WAT_OPT_TEMPLATE)<>0 then begin ClearTemplate(pTmplCell(Check)); mFreeMem(Notes); end else if Notes<>nil then FreeMem(Notes); end; until PlyNum=0; FreeMem(plyLink); end; end; end.