12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526 |
- #define PLUGIN_NAME L"Nullsoft Tray Control"
- #define PLUGIN_VERSION L"2.49"
- // Winamp general purpose plug-in mini-SDK
- // Copyright (C) 1997, Justin Frankel/Nullsoft
- // Modifications and useability enhancements by DrO aka Darren Owen 2006-2014
- #include <windows.h>
- #include <commctrl.h>
- #include <shlwapi.h>
- #include "../winamp/gen.h"
- #include "../winamp/wa_ipc.h"
- #include "../winamp/ipc_pe.h"
- #include "resource.h"
- #include "winampcmd.h"
- #include "api__gen_tray.h"
- #include <strsafe.h>
- #ifndef _DEBUG
- BOOL WINAPI _DllMainCRTStartup(HINSTANCE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
- {
- DisableThreadLibraryCalls(hInst);
- return TRUE;
- }
- #endif
- #define NUM_ICONS 8
- #define FOURWAY_NUM 7
- #define SYSTRAY_ICON_BASE 1024
- // used for Win7+ usage inorder to get the direct location of the icon instead of the prior hacks (thanks MS!)
- typedef HRESULT (WINAPI *SHELL_NOTIFYICONGETRECT)(const NOTIFYICONIDENTIFIER* identifier, RECT* iconLocation);
- SHELL_NOTIFYICONGETRECT g_Shell_NotifyIconGetRect = 0;
- // Use a guid to uniquely identify our icon
- class __declspec(uuid("B4E5FE9B-6A22-450e-9565-941EF50CFEEB")) CompactIcon;
- // wasabi based services for localisation support
- api_service *WASABI_API_SVC = 0;
- api_language *WASABI_API_LNG = 0;
- HINSTANCE WASABI_API_LNG_HINST = 0, WASABI_API_ORIG_HINST = 0;
- int config_enabled = 0,
- xporhigher = 0,
- custom_enabled = 0,
- winver = 0,
- flip = 0,
- on = 1,
- update_file = 0,
- isX64 = 0,
- no_uninstall = 1,
- dlg_init = 0;
- UINT s_uTaskbarRestart=0;
- HWND configwnd = 0;
- WNDPROC lpWndProcOld = 0;
- HICON Icons[NUM_ICONS] = {0}, dummyIcon = 0;
- HBITMAP compact = 0;
- fileinfo2W file = {0};
- wchar_t ico_pack[MAX_PATH] = {0},
- ico_pack_base[MAX_PATH] = {0},
- ico_pack_safe[MAX_PATH] = {0},
- wa_path[MAX_PATH] = {0},
- *ini_file = 0,
- szDescription[256] = {0};
- int tips[NUM_ICONS] = {
- IDS_PREVIOUS_TRACK,
- IDS_PLAY_PAUSE,
- IDS_STOP,
- IDS_NEXT_TRACK,
- IDS_OPEN_FILE,
- IDS_COMPACT_MODE,
- IDS_DECREASE_VOLUME,
- IDS_INCREASE_VOLUME,
- };
- int tips_ex[NUM_ICONS] = {
- IDS_HOLD_CTRL,
- IDS_HOLD_CTRL,
- IDS_HOLD_SHIFT,
- -1,
- -1,
- // IDS_WIN2K_PLUS,
- -1,
- IDS_CTRL_TO_DECREASE,
- IDS_CTRL_TO_INCREASE,
- };
- LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
- BOOL CALLBACK ConfigProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam);
- HICON CreateInternalIcon(void);
- int FileExists(char* filename);
- void config(void);
- void quit(void);
- int init(void);
- void config_write();
- void config_read();
- extern "C" winampGeneralPurposePlugin plugin =
- {
- GPPHDR_VER_U,
- "nullsoft(gen_tray.dll)",
- init,
- config,
- quit,
- };
- extern "C" __declspec(dllexport) winampGeneralPurposePlugin * winampGetGeneralPurposePlugin() { return &plugin; }
- HWND GetPlaylistWnd(HWND winamp){
- HWND pl_wnd = 0;
- // get the playlist editor window (either v2.9x method or the older
- // for compatibility incase < 2.9x are used
- if(SendMessage(winamp,WM_WA_IPC,0,IPC_GETVERSION) >= 0x2900)
- {
- pl_wnd = (HWND)SendMessage(winamp,WM_WA_IPC,IPC_GETWND_PE,IPC_GETWND);
- }
- if(!pl_wnd)
- {
- pl_wnd = FindWindow(L"Winamp PE",0);
- }
- return pl_wnd;
- }
- void FormCompactText(wchar_t* szTip, int szTipLength){
- int got = 0;
- // only update if we really have to (to better mimick Winamp's title behaviour, etc)
- // otherwise we query in all cases which can often reflect what appears to be the wrong information since
- // the current playlist entry is altered, etc on playlist modification hence an incorrect observation
- if(!update_file){
- update_file = 1;
- file.fileindex = (int)SendMessage(GetPlaylistWnd(plugin.hwndParent),WM_WA_IPC,IPC_PE_GETCURINDEX,0);
- got = (int)SendMessage(GetPlaylistWnd(plugin.hwndParent),WM_WA_IPC,IPC_PE_GETINDEXTITLEW,(LPARAM)&file);
- }
- // if it returns 0 then track information was received
- if(!got && file.filetitle[0]){
- int time = (int)SendMessage(plugin.hwndParent,WM_WA_IPC,0,IPC_GETOUTPUTTIME);
- wchar_t buf[MAX_PATH*2] = {0}, temp[1024] = {0}, *t = temp, *p = 0;
- int over = 0, state = 0, blah = 0;
- wchar_t stateStr[32] = {0};
- switch(SendMessage(plugin.hwndParent,WM_WA_IPC,0,IPC_ISPLAYING)){
- case 0:
- WASABI_API_LNGSTRINGW_BUF(IDS_STOPPED_STR,stateStr,32);
- state = lstrlen(stateStr);
- break;
- case 3:
- WASABI_API_LNGSTRINGW_BUF(IDS_PAUSED_STR,stateStr,32);
- state = lstrlen(stateStr);
- break;
- }
- p = file.filetitle;
- while(p && *p){
- *t++ = *p++;
- if(*(p-1) == '&'){
- *t++ = '&';
- *t++ = '&';
- }
- }
- *t = 0;
- StringCchPrintf(buf,MAX_PATH*2,L"%d. %s",(file.fileindex)+1,file.filetitle);
- over = lstrlen(buf);
- if(over > szTipLength - 1){over = szTipLength - 1;}
- lstrcpyn(szTip,buf,szTipLength);
- if(time != -1){
- time = time/1000;
- if(file.filelength[0]){
- StringCchPrintf(buf,MAX_PATH*2,L" [%02d:%02d/%s]",(time/60),time%60,file.filelength);
- blah = lstrlen(buf);
- }
- else{
- StringCchPrintf(buf,MAX_PATH*2,L" [%02d:%02d]",(time/60),time%60);
- blah = lstrlen(buf);
- }
- }
- if((over + blah + state) > szTipLength){
- int adj = szTipLength-blah-state-1;
- szTip[adj] = 0;
- szTip[adj-1] = L'.';
- szTip[adj-2] = L'.';
- szTip[adj-3] = L'.';
- }
- if(time != -1){
- StringCchCat(szTip,szTipLength,buf);
- }
- if(state){
- StringCchCat(szTip,szTipLength,stateStr);
- }
- }
- // fall back to the Winamp version just incase
- else{
- wchar_t temp[16] = {0};
- StringCchPrintf(temp,16,L"%X",SendMessage(plugin.hwndParent,WM_WA_IPC,0,IPC_GETVERSION));
- StringCchPrintf(szTip,szTipLength,L"Winamp %c.%s",temp[0],&temp[2]);
- }
- }
- void free_icons(void){
- int i = 0;
- for (i = 0; i < NUM_ICONS; i++)
- {
- if( Icons[i] ) {
- DestroyIcon(Icons[i]);
- Icons[i] = 0;
- }
- }
- if(dummyIcon) {
- DestroyIcon(dummyIcon);
- dummyIcon = 0;
- }
- if(compact) {
- DeleteObject(compact);
- }
- }
- void do_icons(int force)
- {
- static int l=0;
- int i=NUM_ICONS;
- if (l == config_enabled && !force) return;
- if( force ) free_icons();
- while (i--)
- {
- if (l & (1<<i))
- {
- NOTIFYICONDATAW tnid={0};
- tnid.cbSize=sizeof(NOTIFYICONDATAW);
- tnid.hWnd=plugin.hwndParent;
- tnid.uID=i+SYSTRAY_ICON_BASE;
- Shell_NotifyIcon(NIM_DELETE, &tnid);
- }
- }
- l=config_enabled;
- if(!on) {return;}
- // have to do XP+ specific changes here in order for the icon addition order to appear as expected and not back to front!
- for (i = (xporhigher?(NUM_ICONS-1):0); (xporhigher?i>-1:i < NUM_ICONS); (xporhigher?i --:i ++))
- {
- if (config_enabled & (1<<i))
- {
- // check if an icon pack has not been set or it's not a valid file that's being passed
- // if so then need to use the default icons
- if (!ico_pack[0] || !PathFileExists(ico_pack) )
- {
- if (!Icons[i]) Icons[i] = LoadIcon(plugin.hDllInstance,MAKEINTRESOURCE(IDI_ICON1+i));
- if (i == 5) {
- compact = (HBITMAP)LoadImage(plugin.hDllInstance,MAKEINTRESOURCE(IDB_BITMAP1),IMAGE_BITMAP,0,0,LR_SHARED);
- Icons[i] = CreateInternalIcon();
- }
- }
- else
- {
- wchar_t* icpb = 0;
- lstrcpyn(ico_pack_base,ico_pack,ARRAYSIZE(ico_pack_base));
- icpb = ico_pack_base + lstrlen(ico_pack_base) - 1;
- while(icpb && *icpb && *icpb != L'\\'){icpb = CharPrev(ico_pack,icpb);}
- if (icpb) *icpb = 0;
- if (!Icons[i]){
- wchar_t entry[MAX_PATH] = {0}, buf[MAX_PATH] = {0};
- int compact_loaded = 0;
- StringCchPrintf(entry,MAX_PATH,L"ico%d",i+1);
- GetPrivateProfileString(L"tray icon pack",entry,buf,buf,ARRAYSIZE(buf),ico_pack);
- StringCchPrintf(entry,MAX_PATH,L"%s\\%s",ico_pack_base,buf);
- Icons[i] = (HICON)LoadImage(0,entry,(i != 5?IMAGE_ICON:IMAGE_BITMAP),0,0,LR_LOADFROMFILE|LR_SHARED);
- if (i == 5) {
- compact = (HBITMAP)Icons[i];
- if(compact) {
- compact_loaded = 1;
- }
- }
- // if this fails then we use the built-in versions
- if (!Icons[i]) Icons[i] = LoadIcon(plugin.hDllInstance,MAKEINTRESOURCE(IDI_ICON1+i));
- if (i == 5) {
- if (!compact_loaded) {
- compact = (HBITMAP)LoadImage(plugin.hDllInstance,MAKEINTRESOURCE(IDB_BITMAP1),IMAGE_BITMAP,0,0,LR_SHARED);
- }
- Icons[i] = CreateInternalIcon();
- }
- }
- }
- {
- NOTIFYICONDATAW tnid={0};
- tnid.cbSize=sizeof(NOTIFYICONDATAW);
- tnid.hWnd=plugin.hwndParent;
- tnid.uID=i+SYSTRAY_ICON_BASE;
- tnid.uFlags=NIF_ICON | NIF_TIP | NIF_MESSAGE | NIF_GUID;
- tnid.uCallbackMessage=WM_USER + 2707;
- tnid.hIcon=Icons[i];
- if(i != 5)
- StringCchPrintf(tnid.szTip,sizeof(tnid.szTip)/sizeof(wchar_t),L"%s - Winamp",WASABI_API_LNGSTRINGW(tips[i]));
- else
- FormCompactText(tnid.szTip,(sizeof(tnid.szTip)/sizeof(wchar_t)));
- Shell_NotifyIcon(NIM_ADD, &tnid);
- }
- }
- }
- }
- void config(void)
- {
- if(!IsWindow(configwnd))
- WASABI_API_DIALOGBOXW(IDD_DIALOG1,0,ConfigProc);
- else
- SetActiveWindow(configwnd);
- }
- void quit(void)
- {
- config_enabled=0;
- do_icons(0);
- free_icons();
- }
- BOOL CALLBACK FindTrayWnd(HWND hwnd, LPARAM lParam)
- {
- wchar_t szClassName[256] = {0};
- GetClassName(hwnd, szClassName, 255); // Did we find the Main System Tray? If so, then get its size and quit
- if (!lstrcmpi(szClassName, L"TrayNotifyWnd"))
- {
- HWND* pWnd = (HWND*)lParam;
- *pWnd = hwnd;
- return FALSE;
- }
-
- //Original code I found on Internet were seeking here for system clock and it was assumming that clock is on the right side of tray.
- //After that calculated size of tray was adjusted by removing space occupied by clock.
- //This is not a good idea - some clocks are ABOVE or somewhere else on the screen. I found that is far safer to just ignore clock space.
- return TRUE;
- }
- BOOL CALLBACK FindToolBarInTrayWnd(HWND hwnd, LPARAM lParam)
- {
- wchar_t szClassName[256] = {0};
- GetClassName(hwnd, szClassName, 255); // Did we find the Main System Tray? If so, then get its size and quit
- if (!lstrcmpi(szClassName, L"ToolbarWindow32"))
- {
- HWND* pWnd = (HWND*)lParam;
- *pWnd = hwnd;
- return FALSE;
- }
- return TRUE;
- }
- HWND GetTrayNotifyWnd(BOOL a_bSeekForEmbedToolbar)
- {
- HWND hWndTrayNotifyWnd = 0, hWndShellTrayWnd = FindWindow(L"Shell_TrayWnd", 0);
- if (hWndShellTrayWnd)
- {
- EnumChildWindows(hWndShellTrayWnd, FindTrayWnd, (LPARAM)&hWndTrayNotifyWnd);
-
- if(hWndTrayNotifyWnd && IsWindow(hWndTrayNotifyWnd))
- {
- HWND hWndToolBarWnd = 0;
- EnumChildWindows(hWndTrayNotifyWnd, FindToolBarInTrayWnd, (LPARAM)&hWndToolBarWnd);
- if(hWndToolBarWnd)
- {
- return hWndToolBarWnd;
- }
- }
- return hWndTrayNotifyWnd;
- }
- return hWndShellTrayWnd;
- }
- typedef BOOL (WINAPI *ISWOW64PROCESS)(HANDLE hProcess,PBOOL Wow64Process);
- BOOL IsRunningX64(void){
- ISWOW64PROCESS iswow64process = (ISWOW64PROCESS)GetProcAddress(GetModuleHandle(L"kernel32"),"IsWow64Process");
- if (iswow64process) {
- BOOL Wow64Process = 0;
- if(iswow64process(GetCurrentProcess(),&Wow64Process)){
- return Wow64Process;
- }
- }
- return FALSE;
- }
- struct TRAYDATA
- {
- HWND hwnd;
- UINT uID;
- UINT uCallbackMessage;
- DWORD Reserved[2];
- HICON hIcon;
- };
- typedef struct _TBBUTTON64 {
- int iBitmap;
- int idCommand;
- BYTE fsState;
- BYTE fsStyle;
- BYTE bReserved[6]; // padding for alignment
- DWORD_PTR dwData;
- INT_PTR iString;
- } TBBUTTON64, NEAR* PTBBUTTON64, *LPTBBUTTON64;
- typedef const TBBUTTON64 *LPCTBBUTTON64;
- // this is used on Win7+ installs where the OS has a direct api to allow for the querying of the icon position
- // most likely added natively due to the notification area fly out
- BOOL NotifyIconGetRect(LPRECT a_rcIcon){
- if(g_Shell_NotifyIconGetRect){
- NOTIFYICONIDENTIFIER niid = {sizeof(NOTIFYICONIDENTIFIER),plugin.hwndParent,SYSTRAY_ICON_BASE+5,0};
- return SUCCEEDED(g_Shell_NotifyIconGetRect(&niid,a_rcIcon));
- }
- return FALSE;
- }
- //First tracking method: attaches to Tray process and reads data directly, is fast and reliable but will fail if user uses non standard tray software
- //It was suggested by Neal Andrews with VB example: http://www.codeproject.com/shell/ctrayiconposition.asp?select=999036&forumid=14631&df=100#xx999036xx
- //Ported to C++ by Ireneusz Zielinski
- //Made vaguely 64-bit compatible in v2.2 of this plugin
- BOOL FindOutPositionOfIconDirectly(HWND a_hWndOwner, const int a_iButtonID, LPRECT a_rcIcon)
- {
- if(!NotifyIconGetRect(a_rcIcon))
- {
- DWORD dwTrayProcessID = -1, tbSize = (isX64?sizeof(TBBUTTON64):sizeof(TBBUTTON));
- HANDLE hTrayProc = NULL;
- int iButtonsCount = 0, iButton = 0;
- LPVOID lpData = 0, lpData2 = 0;
- BOOL bIconFound = FALSE;
- //first of all let's find a Tool bar control embed in Tray window
- HWND hWndTray = GetTrayNotifyWnd(TRUE);
- if (hWndTray == NULL)
- {
- return FALSE;
- }
- //now we have to get an ID of the parent process for system tray
- GetWindowThreadProcessId(hWndTray, &dwTrayProcessID);
- if(!dwTrayProcessID)
- {
- return FALSE;
- }
- // need to use the older PROCESS_ALL_ACCESS define as it otherwise causes
- // this to fail on all XP machines but will still work ok on Vista / Win7
- #define PROCESS_ALL_ACCESS_XP (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFF)
- hTrayProc = OpenProcess(PROCESS_ALL_ACCESS_XP/*PROCESS_ALL_ACCESS*/, 0, dwTrayProcessID);
- if(hTrayProc == NULL)
- {
- return FALSE;
- }
- //now we check how many buttons is there - should be more than 0
- iButtonsCount = (int)SendMessage(hWndTray, TB_BUTTONCOUNT, 0, 0);
- //We want to get data from another process - it's not possible to just send messages like TB_GETBUTTON with a localy
- //allocated buffer for return data. Pointer to localy allocated data has no usefull meaning in a context of another
- //process (since Win95) - so we need to allocate some memory inside Tray process.
- //We allocate sizeof(TBBUTTON) bytes of memory - because TBBUTTON is the biggest structure we will fetch. But this buffer
- //will be also used to get smaller pieces of data like RECT structures.
- lpData = VirtualAllocEx(hTrayProc, NULL, tbSize, MEM_COMMIT, PAGE_READWRITE);
- if(lpData == NULL || iButtonsCount < 1)
- {
- CloseHandle(hTrayProc);
- return FALSE;
- }
- for(iButton = 0; iButton < iButtonsCount; iButton++)
- {
- HWND hWndOfIconOwner = 0;
- int iIconId = 0;
- //first let's read TBUTTON information about each button in a task bar of tray
- SIZE_T dwBytesRead = -1;
- TBBUTTON64 buttonData64 = {0};
- TBBUTTON buttonData = {0};
- TRAYDATA traydata = {0};
- SendMessage(hWndTray, TB_GETBUTTON, iButton, (LPARAM)lpData);
- ReadProcessMemory(hTrayProc, lpData, (isX64?(LPVOID)&buttonData64:&buttonData), tbSize, &dwBytesRead);
- if(dwBytesRead < tbSize)
- {
- continue;
- }
- // now let's read extra data associated with each button: there will be a HWND of the window that created an icon and icon ID
- ReadProcessMemory(hTrayProc, (LPCVOID)(isX64?buttonData64.dwData:buttonData.dwData), (LPVOID)&traydata, sizeof(TRAYDATA), &dwBytesRead);
- if(dwBytesRead < sizeof(TRAYDATA))
- {
- continue;
- }
- // will get the hwnd and icon id of the 'button' being checked factoring for x86 and x64 structures
- if(!isX64)
- {
- hWndOfIconOwner = traydata.hwnd;
- iIconId = traydata.uID;
- }
- else
- {
- LPARAM *tb = (LPARAM*)&traydata;
- hWndOfIconOwner = (HWND)tb[0];
- iIconId = (int)tb[2];
- }
- if(hWndOfIconOwner != a_hWndOwner || iIconId != a_iButtonID)
- {
- continue;
- }
- //we found our icon - in WinXP/Vista+ it could be hidden - let's check it:
- if(buttonData.fsState & TBSTATE_HIDDEN)
- {
- break;
- }
- //now just ask a tool bar of rectangle of our icon
- SendMessage(hWndTray, TB_GETITEMRECT, iButton, (LPARAM)lpData);
- ReadProcessMemory(hTrayProc, lpData, a_rcIcon, sizeof(RECT), &dwBytesRead);
- if(dwBytesRead < sizeof(RECT))
- {
- continue;
- }
- MapWindowPoints(hWndTray, NULL, (LPPOINT)a_rcIcon, 2);
- bIconFound = TRUE;
- break;
- }
- VirtualFreeEx(hTrayProc, lpData, 0, MEM_RELEASE);
- VirtualFreeEx(hTrayProc, lpData2, 0, MEM_RELEASE);
- CloseHandle(hTrayProc);
- return bIconFound;
- }
- return TRUE;
- }
- HICON CreateInternalIcon(void)
- {
- HICON hGrayIcon = 0;
- HDC hMainDC = 0, hMemDC1 = 0, hMemDC2 = 0;
- BITMAP bmp = {0};
- ICONINFO csII = {0}, csGrayII = {0};
- // destroy the old version of the icon where possible otherwise we'll get a resource leak
- // which can have a nasty effect if allowed to grow too large
- if(Icons[5]){
- DestroyIcon(Icons[5]);
- }
- // create a dummy base icon with which to work on (saves having to bundle a blank on in the dll)
- if(!dummyIcon){dummyIcon = CreateIcon(plugin.hDllInstance,32,32,1,32,0,0);}
- if(!GetIconInfo(dummyIcon,&csII)){return 0;}
- if(!(hMainDC = GetDC(plugin.hwndParent)) || !(hMemDC1 = CreateCompatibleDC(hMainDC)) || !(hMemDC2 = CreateCompatibleDC(hMainDC))){
- return 0;
- }
- if(GetObject(csII.hbmColor,sizeof(BITMAP),&bmp))
- {
- int width = 0, height = 0;
- csGrayII.hbmColor = CreateBitmap((width = csII.xHotspot*2),(height = csII.yHotspot*2),bmp.bmPlanes,bmp.bmBitsPixel,0);
- if(csGrayII.hbmColor){
- int is_playing = (int)SendMessage(plugin.hwndParent,WM_WA_IPC,0,IPC_ISPLAYING), dwLoopY = 0, dwLoopX = 0;
- // this is used for the temporary bitmap where the mask is created for the transparency (magic pink fun)
- HBITMAP hAndMask = CreateCompatibleBitmap(hMemDC2,width,height);
- HDC hAndMaskDC = CreateCompatibleDC(hMemDC2);
- SelectObject(hAndMaskDC,hAndMask);
- HBITMAP hOldBmp1 = (HBITMAP)SelectObject(hMemDC1,csII.hbmColor);
- HBITMAP hOldBmp2 = (HBITMAP)SelectObject(hMemDC2,csGrayII.hbmColor);
- SetStretchBltMode(hMemDC2,COLORONCOLOR);
- // play or pause or 'blank' image would go here
- SelectObject(hMemDC1,compact);
- // not the most elegant code but it'll correctly select the play/pause icon as needed based on
- // the current playback state and it's flip play/pause state as appropriately
- StretchBlt(hMemDC2,0,0,16,16,hMemDC1,(!is_playing?0:(is_playing!=1?(flip?32:0):32)),0,8,8,SRCCOPY);
- // open or stop image would go here
- StretchBlt(hMemDC2,16,0,16,16,hMemDC1,(!is_playing?8:40),0,8,8,SRCCOPY);
- // previous track image
- StretchBlt(hMemDC2,0,16,16,16,hMemDC1,16,0,8,8,SRCCOPY);
- // next track image
- StretchBlt(hMemDC2,16,16,16,16,hMemDC1,24,0,8,8,SRCCOPY);
- // process the image now that we've generated it
- for(dwLoopX=0;dwLoopX<width;++dwLoopX)
- {
- for(dwLoopY=0;dwLoopY<height;++dwLoopY)
- {
- COLORREF MainBitPixel = GetPixel(hMemDC2,dwLoopX,dwLoopY);
- // checks for magic pink and then will remove it and clear/set the relevant areas in the image mask
- if(MainBitPixel == 0xff00ff)
- {
- SetPixel(hAndMaskDC,dwLoopX,dwLoopY,RGB(255,255,255));
- SetPixel(hMemDC2,dwLoopX,dwLoopY,RGB(0,0,0));
- }
- else
- {
- SetPixel(hAndMaskDC,dwLoopX,dwLoopY,RGB(0,0,0));
- SetPixel(hMemDC2,dwLoopX,dwLoopY,MainBitPixel);
- }
- }
- }
- // set the mask for the transparent areas, etc
- csGrayII.hbmMask = hAndMask;
- DeleteDC(hAndMaskDC);
- SelectObject(hMemDC1,hOldBmp1);
- SelectObject(hMemDC2,hOldBmp2);
- csGrayII.fIcon = 1;
- hGrayIcon = CreateIconIndirect(&csGrayII);
- DeleteObject(hAndMask);
- }
- DeleteObject(csGrayII.hbmColor);
- DeleteObject(csGrayII.hbmMask);
- }
- DeleteObject(csII.hbmColor);
- DeleteObject(csII.hbmMask);
- DeleteDC(hMemDC1);
- DeleteDC(hMemDC2);
- ReleaseDC(plugin.hwndParent,hMainDC);
- return hGrayIcon;
- }
- LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
- {
- // this will detect the start of playback and allow us to query for the new compact mode text
- // done in 2.1+ to resolve issues with the compact mode text not updating correctly in all cases
- if(lParam == IPC_PLAYING_FILE){
- update_file=0;
- }
- if((lParam == IPC_CB_MISC && wParam == IPC_CB_MISC_STATUS)){
- if (config_enabled & (1<<5)) {
- NOTIFYICONDATAW tnid={0};
- tnid.cbSize=sizeof(NOTIFYICONDATAW);
- tnid.hWnd=plugin.hwndParent;
- tnid.uID=1029;
- tnid.uFlags=NIF_ICON|NIF_TIP;
- tnid.hIcon=(Icons[5] = CreateInternalIcon());
- // force an update if stopping and the playlist is clear
- if(!SendMessage(hwnd,WM_WA_IPC,0,IPC_ISPLAYING)){
- if(!SendMessage(hwnd,WM_WA_IPC,0,IPC_GETLISTLENGTH)){
- file.filetitle[0] = 0;
- update_file=0;
- }
- }
- FormCompactText(tnid.szTip,(sizeof(tnid.szTip)/sizeof(wchar_t)));
- Shell_NotifyIcon(NIM_MODIFY,&tnid);
- }
- }
- if(message == WM_TIMER && wParam == 64){
- if (config_enabled & (1<<5)) {
- if(SendMessage(hwnd,WM_WA_IPC,0,IPC_ISPLAYING) == 3){
- NOTIFYICONDATAW tnid={0};
- tnid.cbSize=sizeof(NOTIFYICONDATAW);
- flip = !flip;
- tnid.hWnd=plugin.hwndParent;
- tnid.uID=1029;
- tnid.uFlags=NIF_ICON|NIF_TIP;
- tnid.hIcon=(Icons[5] = CreateInternalIcon());
- FormCompactText(tnid.szTip,(sizeof(tnid.szTip)/sizeof(wchar_t)));
- Shell_NotifyIcon(NIM_MODIFY,&tnid);
- }
- else
- {
- NOTIFYICONDATAW tnid={0};
- // this resets the play/pause flashing so it's in a known state when not paused
- tnid.cbSize=sizeof(NOTIFYICONDATAW);
- tnid.hWnd=plugin.hwndParent;
- tnid.uID=1029;
- tnid.uFlags=(flip?NIF_ICON:0)|NIF_TIP;
- // only re-create the icon when it's needed to be done otherwise, just update the tooltip
- if(flip)
- {
- tnid.hIcon=(Icons[5] = CreateInternalIcon());
- }
- flip = 0;
- FormCompactText(tnid.szTip,sizeof(tnid.szTip)/sizeof(wchar_t));
- Shell_NotifyIcon(NIM_MODIFY,&tnid);
- }
- }
- }
- if (message == WM_USER+2707)
- {
- switch (LOWORD(lParam))
- {
- case WM_LBUTTONDOWN:
- if (config_enabled) switch (LOWORD(wParam))
- {
- // previous icon
- case 1024:
- {
- int a;
- if ((a= (int)SendMessage(hwnd,WM_USER,0,IPC_ISPLAYING)) == 0) // not playing, let's hit prev
- {
- SendMessage(hwnd,WM_COMMAND,WINAMP_BUTTON1,0);
- }
- else if (a != 3) // restart or full previous action
- {
- if ((GetKeyState(VK_CONTROL)&0x1000) && SendMessage(hwnd,WM_USER,0,IPC_GETOUTPUTTIME) > 2000 )
- {
- SendMessage(hwnd,WM_COMMAND,WINAMP_BUTTON2,0); // restart (only on a ctrl+click)
- }
- else
- {
- SendMessage(hwnd,WM_COMMAND,WINAMP_BUTTON1,0); // move to the previous track and then start
- }
- }
- else
- { // prev
- SendMessage(hwnd,WM_COMMAND,WINAMP_BUTTON1,0);
- }
- }
- return 0;
- // play/pause icon
- case 1025:
- if ((GetKeyState(VK_CONTROL)&0x1000) ) // restart the current track
- {
- SendMessage(hwnd,WM_COMMAND,WINAMP_BUTTON4,0);
- SendMessage(hwnd,WM_COMMAND,WINAMP_BUTTON2,0);
- }
- else
- {
- // do play/pause switching to maintain current usability of the plugin
- SendMessage(hwnd,WM_COMMAND,WINAMP_BUTTON2+(SendMessage(hwnd,WM_USER,0,IPC_ISPLAYING) == 1),0);
- }
- return 0;
- // stop icon
- case 1026:
- SendMessage(hwnd,WM_COMMAND,WINAMP_BUTTON4 + ((GetKeyState(VK_SHIFT) & 0x1000)?100:0) ,0);
- return 0;
- // next icon
- case 1027:
- SendMessage(hwnd,WM_COMMAND,WINAMP_BUTTON5,0);
- return 0;
- // open file(s) icon
- case 1028:
- SetForegroundWindow(hwnd);
- if (GetKeyState(VK_CONTROL) & (1<<15))
- SendMessage(hwnd,WM_COMMAND,WINAMP_FILE_LOC,0);
- else if (GetKeyState(VK_SHIFT) & (1<<15))
- SendMessage(hwnd,WM_COMMAND,WINAMP_FILE_DIR,0);
- else
- SendMessage(hwnd,WM_COMMAND,WINAMP_FILE_PLAY,0);
- return 0;
- // 4way mode handling, etc
- case 1029:
- {
- RECT rc = {0}, r = {0};
- // Note: this isn't compatible with hidden icons on Win7 (still to be fixed for v2.4)
- if(FindOutPositionOfIconDirectly(hwnd,1029,&rc))
- {
- int i = 0,
- // on at least Win7 (possibly earlier) the icon size is different than a fixed size
- // so for v2.3 we're just going to split the icon based on the reported size rather
- // than assuming it is a 16x16 (really 18x18 icon) as Win7's taskbar is different!
- height = (rc.bottom-rc.top)/2,
- width = (rc.right-rc.left)/2,
- x[4] = {0,width,0,width},
- y[4] = {0,0,height,height};
- POINT pt = {0};
- GetCursorPos(&pt);
- for(i = 0; i < 4; i++)
- {
- CopyRect(&r,&rc);
- r.right = r.left+x[i]+width;
- r.bottom = r.top+y[i]+height;
- if(PtInRect(&r,pt))
- {
- switch(i)
- {
- // play/pause icon
- case 0:
- if ((GetKeyState(VK_CONTROL)&0x1000) ) // restart the current track
- {
- SendMessage(hwnd,WM_COMMAND,WINAMP_BUTTON4,0);
- SendMessage(hwnd,WM_COMMAND,WINAMP_BUTTON2,0);
- }
- else
- {
- // do play/pause switching to maintain current usability of the plugin
- SendMessage(hwnd,WM_COMMAND,WINAMP_BUTTON2+(SendMessage(hwnd,WM_USER,0,IPC_ISPLAYING) == 1),0);
- }
- break;
- // open file(s) / stop icon
- case 1:
- if(!SendMessage(hwnd,WM_USER,0,IPC_ISPLAYING)){
- SetForegroundWindow(hwnd);
- if (GetKeyState(VK_CONTROL) & (1<<15))
- SendMessage(hwnd,WM_COMMAND,WINAMP_FILE_LOC,0);
- else if (GetKeyState(VK_SHIFT) & (1<<15))
- SendMessage(hwnd,WM_COMMAND,WINAMP_FILE_DIR,0);
- else
- SendMessage(hwnd,WM_COMMAND,WINAMP_FILE_PLAY,0);
- }
- else{
- SendMessage(hwnd,WM_COMMAND,WINAMP_BUTTON4 + ((GetKeyState(VK_SHIFT) & 0x1000)?100:0) ,0);
- }
- break;
- // previous icon
- case 2:
- {
- int a;
- if ((a= (int)SendMessage(hwnd,WM_USER,0,IPC_ISPLAYING)) == 0) // not playing, let's hit prev
- {
- SendMessage(hwnd,WM_COMMAND,WINAMP_BUTTON1,0);
- }
- else if (a != 3) // restart or full previous action
- {
- if ((GetKeyState(VK_CONTROL)&0x1000) && SendMessage(hwnd,WM_USER,0,IPC_GETOUTPUTTIME) > 2000 )
- {
- SendMessage(hwnd,WM_COMMAND,WINAMP_BUTTON2,0); // restart (only on a ctrl+click)
- }
- else
- {
- SendMessage(hwnd,WM_COMMAND,WINAMP_BUTTON1,0); // move to the previous track and then start
- }
- }
- else
- { // prev
- SendMessage(hwnd,WM_COMMAND,WINAMP_BUTTON1,0);
- }
- }
- break;
- // next icon
- case 3:
- SendMessage(hwnd,WM_COMMAND,WINAMP_BUTTON5,0);
- break;
- }
- break;
- }
- }
- }
- }
- return 0;
- // vol down
- case 1030:
- {
- int curvol = (int)SendMessage(hwnd,WM_WA_IPC,-666,IPC_SETVOLUME)-((GetKeyState(VK_CONTROL)&0x1000)?30:10);
- if(curvol<0){curvol = 0;}
- SendMessage(hwnd,WM_WA_IPC,curvol,IPC_SETVOLUME);
- }
- return 0;
- // vol up
- case 1031:
- {
- int curvol = (int)SendMessage(hwnd,WM_WA_IPC,-666,IPC_SETVOLUME)+((GetKeyState(VK_CONTROL)&0x1000)?30:10);
- if(curvol>255){curvol = 255;}
- SendMessage(hwnd,WM_WA_IPC,curvol,IPC_SETVOLUME);
- }
- return 0;
- }
- break;
- case WM_RBUTTONDOWN:
- if (config_enabled) switch (LOWORD(wParam))
- {
- // previousicon
- case 1024:
- {
- SendMessage(hwnd,WM_COMMAND,WINAMP_BUTTON5,0);
- }
- break;
- // next icon
- case 1027:
- {
- int a;
- if ((a= (int)SendMessage(hwnd,WM_USER,0,IPC_ISPLAYING)) == 0) // not playing, let's hit prev
- {
- SendMessage(hwnd,WM_COMMAND,WINAMP_BUTTON1,0);
- }
- else if (a != 3) // restart or full previous action
- {
- if ((GetKeyState(VK_CONTROL)&0x1000) && SendMessage(hwnd,WM_USER,0,IPC_GETOUTPUTTIME) > 2000 )
- {
- SendMessage(hwnd,WM_COMMAND,WINAMP_BUTTON2,0); // restart (only on a ctrl+click)
- }
- else
- {
- SendMessage(hwnd,WM_COMMAND,WINAMP_BUTTON1,0); // move to the previous track and then start
- SendMessage(hwnd,WM_COMMAND,WINAMP_BUTTON2,0);
- }
- }
- else
- { // prev
- SendMessage(hwnd,WM_COMMAND,WINAMP_BUTTON1,0);
- }
- }
- break;
- // vol down
- case 1031:
- {
- int curvol = (int)SendMessage(hwnd,WM_WA_IPC,-666,IPC_SETVOLUME)-((GetKeyState(VK_CONTROL)&0x1000)?30:10);
- if(curvol<0){curvol = 0;}
- SendMessage(hwnd,WM_WA_IPC,curvol,IPC_SETVOLUME);
- }
- return 0;
- // vol up
- case 1030:
- {
- int curvol = (int)SendMessage(hwnd,WM_WA_IPC,-666,IPC_SETVOLUME)+((GetKeyState(VK_CONTROL)&0x1000)?30:10);
- if(curvol>255){curvol = 255;}
- SendMessage(hwnd,WM_WA_IPC,curvol,IPC_SETVOLUME);
- }
- return 0;
- }
- break;
- }
- }
- {
- int ret = (int)CallWindowProc(lpWndProcOld,hwnd,message,wParam,lParam);
- // do this after passing the main batch of messages onto Winamp/rest of the subclass chain so
- // that Winamp will restore its tray icon first and then we do ours (otherwise it looks silly)
- if(message == s_uTaskbarRestart)
- {
- // have to force the icons to be displayed since there are none in the tray at this point
- do_icons(1);
- }
- return ret;
- }
- }
- // GetWindowsVersionRunningOnCompact(...)
- //
- // Function to get the version of windows being run on
- //
- // Optionally a 'short version[2]' can be passed into the
- // function as 'GetWindowsVersionRunningOnCompact(version)'
- // which allows the OS version to be returned for the user to
- // be able to make use of
- //
- int GetWindowsVersionRunningOnCompact(DWORD* version)
- {
- OSVERSIONINFO osvi = {sizeof(OSVERSIONINFO),0};
- int ver_detect = -1;
- // Win9x detection
- //
- // Windows 95 - Major 4 & Minor 0 ver_detect = 1
- // Windows 98 - Major 4 & Minor 10 ver_detect = 2
- // Windows ME - Major 4 & Minor 90 ver_detect = 3
- //
- // Win NT detection
- //
- // Windows NT 3.51 - Major 3 & Minor 51 ver_detect = 4
- // Windows NT 4 - Major 4 & Minor 0 ver_detect = 5
- // Windows 2000 - Major 5 & Minor 0 ver_detect = 6
- // Windows XP - Major 5 & Minor 1 ver_detect = 7
- // Windows Server 2003 - Major 5 & Minor 2 ver_detect = 8
- // Windows Vista - Major 6 & Minor 0 ver_detect = 9
- // Windows 7 - Major 6 & Minor 1 ver_detect = 9
- // Windows 8 - Major 6 & Minor 2 ver_detect = 9
- // Windows 8.1 - Major 6 & Minor 3 ver_detect = 9
- // Windows 10 - Major 10 & Minor 0 ver_detect = 10
- // Windows 11 - Major 11 & Minor 0 ver_detect = 11
- //
- // Unknown OS version ver_detect = -1
- GetVersionEx(&osvi);
- // is it a Win9x platform that we are running on?
- if(osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
- {
- // Windows 98 (4.10)
- if(osvi.dwMinorVersion == 10){
- ver_detect = 2;
- }
- // Windows ME (4.90)
- else if(osvi.dwMinorVersion == 90){
- ver_detect = 3;
- }
- // Windows 95 (4.0)
- else {
- ver_detect = 1;
- }
- }
- // is it a WinNT platform that we are running on?
- else if(osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)
- {
- // Windows NT 4 (4.0)
- if(osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0)
- {
- ver_detect = 5;
- }
- else if(osvi.dwMajorVersion == 5)
- {
- // Windows XP (5.1)
- if(osvi.dwMinorVersion == 1)
- {
- ver_detect = 7;
- }
- // Windows Server 2003 (5.2)
- else if(osvi.dwMinorVersion == 2)
- {
- ver_detect = 8;
- }
- // Windows 2000 (5.0)
- else
- {
- ver_detect = 6;
- }
- }
- // Windows Vista/7/8/8.1 (6.0)
- else if(osvi.dwMajorVersion == 6)
- {
- ver_detect = 9;
- }
- // Windows 10 (10.0)
- else if(osvi.dwMajorVersion == 10)
- {
- ver_detect = 10;
- }
- // Windows 11 (11.0)
- else if(osvi.dwMajorVersion == 11)
- {
- ver_detect = 11;
- }
- // Windows NT 3.51 (3.51)
- else
- {
- ver_detect = 4;
- }
- }
- else
- {
- ver_detect = -1;
- }
- // copies the value into the structure
- if(version)
- {
- *version = MAKELONG(osvi.dwMinorVersion,osvi.dwMajorVersion);
- }
- return ver_detect;
- }
- void GetWinampPath(void)
- {
- wchar_t* p = wa_path;
- p += GetModuleFileName(0,wa_path,ARRAYSIZE(wa_path)) - 1;
- while(p && *p && *p != L'\\'){p = CharPrev(wa_path,p);}
- if (p) *p = 0;
- }
- int init(void)
- {
- // loader so that we can get the localisation service api for use
- WASABI_API_SVC = (api_service*)SendMessage(plugin.hwndParent, WM_WA_IPC, 0, IPC_GET_API_SERVICE);
- if (WASABI_API_SVC == (api_service*)1) WASABI_API_SVC = NULL;
- if (!WASABI_API_SVC || WASABI_API_SVC == (api_service *)1)
- return GEN_INIT_FAILURE;
- xporhigher = ((winver=GetWindowsVersionRunningOnCompact(0))>6);
- isX64 = IsRunningX64();
- s_uTaskbarRestart = RegisterWindowMessage(TEXT("TaskbarCreated"));
- g_Shell_NotifyIconGetRect = (SHELL_NOTIFYICONGETRECT)GetProcAddress(GetModuleHandle(L"SHELL32"),"Shell_NotifyIconGetRect");
- waServiceFactory *sf = WASABI_API_SVC->service_getServiceByGuid(languageApiGUID);
- if (sf) WASABI_API_LNG = reinterpret_cast<api_language*>(sf->getInterface());
- // need to have this initialised before we try to do anything with localisation features
- WASABI_API_START_LANG(plugin.hDllInstance,GenTrayLangGUID);
- StringCchPrintf(szDescription, ARRAYSIZE(szDescription),
- WASABI_API_LNGSTRINGW(IDS_NULLSOFT_TRAY_CONTROL), PLUGIN_VERSION);
- plugin.description = (char*)szDescription;
- GetWinampPath();
- config_read();
- if (IsWindowUnicode(plugin.hwndParent))
- lpWndProcOld = (WNDPROC)SetWindowLongPtrW(plugin.hwndParent,GWLP_WNDPROC,(LPARAM)WndProc);
- else
- lpWndProcOld = (WNDPROC)SetWindowLongPtrA(plugin.hwndParent,GWLP_WNDPROC,(LPARAM)WndProc);
- do_icons(0);
- return 0;
- }
- static HCURSOR link_hand_cursor;
- LRESULT link_handlecursor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
- {
- LRESULT ret = CallWindowProcW((WNDPROC)GetPropW(hwndDlg, L"link_proc"), hwndDlg, uMsg, wParam, lParam);
- // override the normal cursor behaviour so we have a hand to show it is a link
- if(uMsg == WM_SETCURSOR)
- {
- if((HWND)wParam == hwndDlg)
- {
- if(!link_hand_cursor)
- {
- link_hand_cursor = LoadCursor(NULL, IDC_HAND);
- }
- SetCursor(link_hand_cursor);
- return TRUE;
- }
- }
- return ret;
- }
- void link_startsubclass(HWND hwndDlg, UINT id){
- HWND ctrl = GetDlgItem(hwndDlg, id);
- if(!GetPropW(ctrl, L"link_proc"))
- {
- SetPropW(ctrl, L"link_proc",
- (HANDLE)SetWindowLongPtrW(ctrl, GWLP_WNDPROC, (LONG_PTR)link_handlecursor));
- }
- }
- BOOL CALLBACK ConfigProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)
- {
- switch (uMsg)
- {
- case WM_INITDIALOG:
- {
- int count = CB_ERR;
- configwnd = hwndDlg;
- dlg_init = 1;
- link_startsubclass(hwndDlg,IDC_LINK);
- CheckDlgButton(hwndDlg,IDC_ONOFF,on?BST_CHECKED:BST_UNCHECKED);
- for (int i = 0; i < NUM_ICONS; i++)
- {
- wchar_t str[512] = {0}, tmp[256] = {0}, tmp2[256] = {0};
- CheckDlgButton(hwndDlg,IDC_PREV+i,(config_enabled&(1<<i))?BST_CHECKED:BST_UNCHECKED);
- StringCchPrintf(str,512,L"%s %s",
- WASABI_API_LNGSTRINGW_BUF(tips[i],tmp2,256),
- (tips_ex[i]!=-1?WASABI_API_LNGSTRINGW_BUF(tips_ex[i],tmp,256):L""));
- SetDlgItemText(hwndDlg,IDC_PREV+i,str);
- EnableWindow(GetDlgItem(hwndDlg,IDC_PREV+i),on);
- }
- EnableWindow(GetDlgItem(hwndDlg,IDC_COMBO2),on);
- EnableWindow(GetDlgItem(hwndDlg,IDC_BUTTON1),custom_enabled && on);
- EnableWindow(GetDlgItem(hwndDlg,IDC_EDIT1),custom_enabled && on);
- SetDlgItemText(hwndDlg,IDC_EDIT1,ico_pack_safe);
-
- dlg_init = 0;
- WIN32_FIND_DATA findfile = {0};
- wchar_t use[MAX_PATH] = {0};
- StringCchPrintf(use,MAX_PATH,L"%s\\Plugins\\Tray_Control\\*.*",wa_path);
- HANDLE hFind = FindFirstFile(use, &findfile);
- while(hFind && hFind != INVALID_HANDLE_VALUE)
- {
- if(findfile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY){
- WIN32_FIND_DATA subfile = {0};
- StringCchPrintf(use,MAX_PATH,L"%s\\Plugins\\Tray_Control\\%s\\*.icp",
- wa_path,findfile.cFileName,findfile.cFileName);
- HANDLE hsubFind = FindFirstFile(use,&subfile);
- while(hsubFind && hsubFind != INVALID_HANDLE_VALUE){
- wchar_t icpname[MAX_PATH] = {0};
- StringCchPrintf(icpname,MAX_PATH,
- L"%s\\Plugins\\Tray_Control\\%s\\%s",
- wa_path,findfile.cFileName,subfile.cFileName);
- if(PathFileExists(icpname))
- {
- // need to ideally make this one work with CharPrev(..)
- wchar_t* p = subfile.cFileName + lstrlen(subfile.cFileName) - 1;
- while(p && *p && *p != L'.'){p = CharPrevW(subfile.cFileName, p);}
- if (p) *p = 0;
- if(!lstrcmpiW(findfile.cFileName,subfile.cFileName))
- {
- SendDlgItemMessageW(hwndDlg,IDC_COMBO2,CB_ADDSTRING,0,(LPARAM)subfile.cFileName);
- }
- else
- {
- wchar_t str[MAX_PATH] = {0};
- int insertpos = 0;
- StringCchPrintf(str,MAX_PATH,L"%s\\%s",findfile.cFileName,subfile.cFileName);
- insertpos = (int)SendDlgItemMessage(hwndDlg,IDC_COMBO2,CB_ADDSTRING,0,(LPARAM)str);
- if(insertpos != CB_ERR)
- {
- SendDlgItemMessage(hwndDlg,IDC_COMBO2,CB_SETITEMDATA,insertpos,1);
- }
- }
- }
- // if there are no more files then stop the search
- if(hsubFind && !FindNextFile(hsubFind, &subfile))
- {
- FindClose(hsubFind);
- hsubFind = 0;
- }
- }
- }
- // if there are no more files then stop the search
- if(hFind && !FindNextFileW(hFind, &findfile))
- {
- FindClose(hFind);
- hFind = 0;
- }
- }
- EnableWindow(GetDlgItem(hwndDlg,IDC_EDIT1),custom_enabled);
- EnableWindow(GetDlgItem(hwndDlg,IDC_BUTTON1),custom_enabled);
- EnableWindow(GetDlgItem(hwndDlg,IDC_PREV6),winver>=6 && on);
- SendDlgItemMessage(hwndDlg,IDC_COMBO2,CB_INSERTSTRING,0,
- (LPARAM)WASABI_API_LNGSTRINGW(IDS_DEFAULT_ICONS));
- SendDlgItemMessage(hwndDlg,IDC_COMBO2,CB_INSERTSTRING,
- (count = (int)SendDlgItemMessage(hwndDlg,IDC_COMBO2,CB_GETCOUNT,0,0)),
- (LPARAM)WASABI_API_LNGSTRINGW(IDS_CUSTOM_ICON_PACK));
- if (!custom_enabled)
- {
- if(ico_pack[0])
- {
- wchar_t base[MAX_PATH] = {0}, *pack = 0, use[MAX_PATH] = {0};
- StringCchPrintf(use,MAX_PATH,L"%s\\Plugins\\Tray_Control\\",wa_path);
- lstrcpyn(base,ico_pack,ARRAYSIZE(base));
- if(StrStrI(base,use))
- {
- pack = PathFindFileName(base);
- if (pack && *pack)
- {
- PathRemoveExtension(pack);
- }
- }
- count = (int)SendDlgItemMessage(hwndDlg,IDC_COMBO2,CB_FINDSTRINGEXACT,0,(LPARAM)pack);
- if(count == CB_ERR)
- {
- count = 0;
- }
- }
- else
- {
- count = 0;
- }
- }
- SendDlgItemMessage(hwndDlg,IDC_COMBO2,CB_SETCURSEL,count,0);
- SetFocus(GetDlgItem(hwndDlg,IDC_COMBO2));
- }
- break;
- // mimicks the get... links in the winamp preferences
- case WM_DRAWITEM:
- {
- DRAWITEMSTRUCT* lpdis = (DRAWITEMSTRUCT*)lParam;
- if(lpdis->CtlID == IDC_LINK)
- {
- HFONT OldFont = 0;
- LOGFONT lf = {0};
- RECT rc = lpdis->rcItem, r = {0};
- POINT pt = {0};
- int in = 0;
- wchar_t gicpStr[128] = {0};
-
- WASABI_API_LNGSTRINGW_BUF(IDS_GET_ICON_PACKS,gicpStr,128);
- GetObject(GetCurrentObject(lpdis->hDC,OBJ_FONT),sizeof(lf),&lf);
- lf.lfUnderline = TRUE;
- OldFont = (HFONT)SelectObject(lpdis->hDC,CreateFontIndirect(&lf));
- // Calculate needed size of the control
- DrawText(lpdis->hDC,gicpStr,-1,&rc,DT_VCENTER|DT_SINGLELINE|DT_CALCRECT);
- // Make some more room so the focus rect won't cut letters off
- rc.right = min(rc.right + 2, lpdis->rcItem.right);
- GetWindowRect(lpdis->hwndItem,&r);
- GetCursorPos(&pt);
- in = PtInRect(&r,pt);
- SetTextColor(lpdis->hDC,(COLORREF)RGB((in?255:0),0,(!in?255:0)));
- // Draw the text
- DrawText(lpdis->hDC,gicpStr,-1,&rc,DT_CENTER|DT_VCENTER|DT_SINGLELINE);
- DeleteObject(SelectObject(lpdis->hDC, OldFont));
- }
- }
- break;
- case WM_COMMAND:
- if (LOWORD(wParam) >= IDC_PREV && LOWORD(wParam) <= IDC_PREV+NUM_ICONS)
- {
- config_enabled=0;
- for (int i = 0; i < NUM_ICONS; i++)
- if (IsDlgButtonChecked(hwndDlg,IDC_PREV+i))
- config_enabled |= 1<<i;
- do_icons(0);
- }
-
- else if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
- {
- GetDlgItemText(hwndDlg,IDC_EDIT1,ico_pack_safe,ARRAYSIZE(ico_pack_safe));
- config_write();
- EndDialog(hwndDlg,0);
- configwnd = 0;
- }
- else if (LOWORD(wParam) == IDC_ONOFF)
- {
- on = (IsDlgButtonChecked(hwndDlg,LOWORD(wParam))==BST_CHECKED);
- for (int i = 0; i < NUM_ICONS; i++)
- {
- EnableWindow(GetDlgItem(hwndDlg,IDC_PREV+i),on);
- }
- EnableWindow(GetDlgItem(hwndDlg,IDC_PREV6),winver>=6 && on);
- EnableWindow(GetDlgItem(hwndDlg,IDC_COMBO2),on);
- EnableWindow(GetDlgItem(hwndDlg,IDC_BUTTON1),custom_enabled && on);
- EnableWindow(GetDlgItem(hwndDlg,IDC_EDIT1),custom_enabled && on);
-
- do_icons(1);
- }
- else if (LOWORD(wParam) == ID_INFO)
- {
- wchar_t str[2560] = {0}, str1[2048] = {0};
- StringCchPrintf(str, 2560, WASABI_API_LNGSTRINGW_BUF(IDS_CONFIG_INFO, str1, 2048), wa_path);
- MessageBoxW(hwndDlg,str,szDescription,0);
- }
- else if (LOWORD(wParam) == IDC_LINK && HIWORD(wParam) == BN_CLICKED)
- {
- SendMessage(plugin.hwndParent,WM_WA_IPC,(WPARAM)"https://winampheritage.com/plugin/nullsoft-tray-control-plug-in-icon-pack/222396",IPC_OPEN_URL);
- }
- else if (LOWORD(wParam) == IDC_BUTTON1)
- {
- OPENFILENAME of = {sizeof(OPENFILENAME),0};
- wchar_t titleStr[128], filterStr[128] = {0};
- of.hwndOwner = hwndDlg;
- of.hInstance = plugin.hDllInstance;
- of.lpstrFilter = WASABI_API_LNGSTRINGW_BUF(IDS_OFD_FILTER_STR,filterStr,128);
- StringCchCat(filterStr+lstrlen(filterStr)+1,128,L"*.icp");
- of.nMaxCustFilter = 64;
- of.lpstrFile = ico_pack;
- of.nMaxFile = ARRAYSIZE(ico_pack);
- of.lpstrTitle = WASABI_API_LNGSTRINGW_BUF(IDS_OFD_TITLE_STR,titleStr,128);
- of.nMaxFileTitle = lstrlen(of.lpstrTitle);
- of.Flags = OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT|OFN_EXPLORER|OFN_PATHMUSTEXIST|OFN_CREATEPROMPT|OFN_ENABLESIZING|OFN_ALLOWMULTISELECT;
- of.lpstrDefExt = L"icp";
- if(GetOpenFileName(&of))
- {
- SetDlgItemText(hwndDlg,IDC_EDIT1,ico_pack);
- do_icons(1);
- }
- }
- else if (LOWORD(wParam) == IDC_EDIT1 && HIWORD(wParam)==EN_CHANGE)
- {
- if(!dlg_init)
- {
- GetDlgItemText(hwndDlg,IDC_EDIT1,ico_pack,ARRAYSIZE(ico_pack));
- do_icons(1);
- }
- }
- else if (LOWORD(wParam) == IDC_COMBO2 && HIWORD(wParam)== CBN_SELCHANGE)
- {
- wchar_t buf[MAX_PATH] = {0};
- int cursel = (int)SendDlgItemMessage(hwndDlg,IDC_COMBO2,CB_GETCURSEL,0,0);
- SendDlgItemMessage(hwndDlg,IDC_COMBO2,CB_GETLBTEXT,cursel,(LPARAM)buf);
- custom_enabled=0;
- if(cursel && cursel != CB_ERR)
- {
- if(cursel != (SendDlgItemMessage(hwndDlg,IDC_COMBO2,CB_GETCOUNT,0,0)-1))
- {
- // this will detect if it was a multi-entry style icon pack and form as required
- if(!SendDlgItemMessage(hwndDlg,IDC_COMBO2,CB_GETITEMDATA,cursel,0))
- {
- StringCchPrintf(ico_pack,MAX_PATH,L"%s\\Plugins\\Tray_Control\\%s\\%s.icp",wa_path,buf,buf);
- }
- else
- {
- StringCchPrintf(ico_pack,MAX_PATH,L"%s\\Plugins\\Tray_Control\\%s.icp",wa_path,buf);
- }
- }
- else
- {
- custom_enabled=1;
- GetDlgItemText(hwndDlg,IDC_EDIT1,ico_pack,ARRAYSIZE(ico_pack));
- }
- }
- else
- {
- ico_pack[0] = 0;
- }
- EnableWindow(GetDlgItem(hwndDlg,IDC_EDIT1),custom_enabled);
- EnableWindow(GetDlgItem(hwndDlg,IDC_BUTTON1),custom_enabled);
- do_icons(1);
- }
- break;
- }
- return FALSE;
- }
- void config_read(void)
- {
- // this will only correctly work with Winamp 2.9+/5.x+
- // see IPC_GETINIFILE for a way to query the location of Winamp.ini correctly
- // whatever version of Winamp is being run on
- // as of v2.41 this now uses IPC_GETINIFILEW though it's trivial to use
- // IPC_GETINIFILE as a fallback on older clients (built for 5.58+)
- ini_file=(wchar_t*)SendMessage(plugin.hwndParent,WM_USER,0,IPC_GETINIFILEW);
- config_enabled = GetPrivateProfileInt(PLUGIN_NAME,L"BEN",config_enabled,ini_file);
- custom_enabled = GetPrivateProfileInt(PLUGIN_NAME,L"custom",custom_enabled,ini_file);
- on = GetPrivateProfileInt(PLUGIN_NAME,L"on",on,ini_file);
- GetPrivateProfileString(PLUGIN_NAME,L"ico_pack",ico_pack,ico_pack,ARRAYSIZE(ico_pack),ini_file);
- GetPrivateProfileString(PLUGIN_NAME,L"ico_pack_safe",ico_pack_safe,ico_pack_safe,ARRAYSIZE(ico_pack_safe),ini_file);
- }
- void config_write(void)
- {
- if(!no_uninstall) return;
- wchar_t string[32] = {0};
- StringCchPrintf(string,32,L"%d",config_enabled);
- WritePrivateProfileString(PLUGIN_NAME,L"BEN",string,ini_file);
- WritePrivateProfileString(PLUGIN_NAME,L"ico_pack",ico_pack,ini_file);
- WritePrivateProfileString(PLUGIN_NAME,L"ico_pack_safe",ico_pack_safe,ini_file);
- StringCchPrintf(string,32,L"%d",custom_enabled);
- WritePrivateProfileString(PLUGIN_NAME,L"custom",string,ini_file);
- StringCchPrintf(string,32,L"%d",on);
- WritePrivateProfileString(PLUGIN_NAME,L"on",string,ini_file);
- }
- #ifdef __cplusplus
- extern "C" {
- #endif
- __declspec(dllexport) int winampUninstallPlugin(HINSTANCE hDllInst, HWND hwndDlg, int param){
- // prompt to remove our settings with default as no (just incase)
- if(MessageBoxW(hwndDlg,WASABI_API_LNGSTRINGW(IDS_DO_YOU_ALSO_WANT_TO_REMOVE_SETTINGS),
- szDescription,MB_YESNO|MB_DEFBUTTON2) == IDYES)
- {
- WritePrivateProfileString(PLUGIN_NAME,0,0,ini_file);
- no_uninstall = 0;
- }
- // as we're doing too much in subclasses, etc we cannot allow for on-the-fly removal so need to do a normal reboot
- return GEN_PLUGIN_UNINSTALL_REBOOT;
- }
- #ifdef __cplusplus
- }
- #endif
|