winamp/Src/Winamp/main.cpp

1892 lines
52 KiB
C++
Raw Permalink Normal View History

2024-09-24 14:54:57 +02:00
/** (c) Nullsoft, Inc. C O N F I D E N T I A L
** Filename: main.cpp
** Project: Winamp
** Description: Winamp initialization code
** Author: Justin Frankel
** Created: April 1997
**/
#include "main.h"
#include <windowsx.h>
#include "../Agave/Language/lang.h"
#include <stdarg.h>
#include "vis.h"
#include "fft.h"
#include "gen.h"
#include "../nu/ns_wc.h"
#include "../nu/AutoWide.h"
#include "../nu/AutoChar.h"
#include "menuv5.h"
#include "../Plugins/General/gen_ml/ml.h"
#include "wa_dlg.h"
#include "strutil.h"
#include "./setup/setupfactory.h"
#include "./commandLink.h"
#include "AppRefCount.h"
#include <unknwn.h>
#include <shlwapi.h>
#include <shobjidl.h>
#include "WAT/WAT.h"
#ifndef WM_DWMSENDICONICTHUMBNAIL
#define WM_DWMSENDICONICTHUMBNAIL 0x0323
#endif
#include "Agave/Language/api_language.h"
#ifndef WM_DWMSENDICONICLIVEPREVIEWBITMAP
#define WM_DWMSENDICONICLIVEPREVIEWBITMAP 0x0326
#endif
#ifndef THBN_CLICKED
#define THBN_CLICKED 0x1800
#endif
typedef HRESULT( WINAPI *CHANGEWINDOWMESSAGEFILTER )( UINT message, DWORD dwFlag );
static HMODULE user32Lib = 0;
static CHANGEWINDOWMESSAGEFILTER changeWMFilter;
static BOOL changeWMLoadTried = FALSE;
//#define BENSKI_TEST_WM_PRINTCLIENT
static UINT WM_TASKBARCREATED;
static UINT WM_TASKBARBUTTONCREATED;
LARGE_INTEGER freq;
UINT g_scrollMsg;
UINT songChangeBroadcastMessage = 0;
int g_noreg;
int disable_skin_borders = 0;
int no_notify_play = 0;
int last_no_notify_play = 0;
int main_delta_carryover = 0;
int g_restartonquit = 0;
char g_audiocdletter[ 4 ] = { 0 };
int g_audiocdletters = 0;
const char app_name[] = "Winamp", app_version[] = APP_VERSION, app_version_string[] = APP_VERSION_STRING; // application name and version strings
int g_fullstop;
char *app_date = __DATE__;
int g_stopaftercur;
int is_install;
HWND hTooltipWindow, hEQTooltipWindow, hVideoTooltipWindow, hPLTooltipWindow;
HWND hMainWindow = NULL; // main window
HWND hEQWindow, hPLWindow, /*hMBWindow, */hVideoWindow, hExternalVisWindow = NULL;
HWND g_dialog_box_parent = NULL; // used by IPC_SETDIALOGBOXPARENT (FG, 5/19/03)
HINSTANCE language_pack_instance;
HINSTANCE hMainInstance; // program instance
HANDLE hMainThread; // main thread handle
DWORD mainThreadId; // main thread ID
HMENU main_menu = 0, top_menu = 0, g_submenus_bookmarks1 = 0,
g_submenus_bookmarks2 = 0, g_submenus_skins1 = 0,
g_submenus_skins2 = 0, g_submenus_vis = 0,
g_submenus_options = 0, g_submenus_lang = 0,
g_submenus_play = 0;
int g_submenus_lang_id = 0;
int g_video_numaudiotracks = 1;
int g_video_curaudiotrack = 0;
int bStartPlaying = 0;
int paused = 0;
int playing = 0;
wchar_t caption[ CAPTION_SIZE ] = { 0 }; // current program caption
wchar_t FileName[ FILENAME_SIZE ] = { 0 }; // current file name
wchar_t FileTitle[ FILETITLE_SIZE ] = { 0 }; // current file title
wchar_t FileTitleNum[ FILETITLE_SIZE ] = { 0 }; // current file title + track position
int eggstat = 0; // used for easter eggs
int g_srate, g_brate, g_nch, g_srate_exact;
int last_brate = -1;
int g_need_titleupd = 0;
int g_need_infoupd = 0;
int g_SkinTop, g_BookmarkTop, g_LangTop;
int g_mm_optionsbase_adj = 0; //used by IPC_ADJUST_OPTIONSMENUPOS
int g_mm_ffwindowsbase_adj = 0; //used by IPC_ADJUST_FFWINDOWSMENUPOS
int g_mm_ffoptionsbase_adj = 0; //used by IPC_ADJUST_FFOPTIONSMENUPOS
int g_has_video_plugin = 0;
int g_no_video_loaded = 0; //filled in by in_init
char playlist_custom_font[ 128 ] = { 0 };
wchar_t playlist_custom_fontW[ 128 ] = { 0 };
int config_custom_plfont = 1;
int disable_skin_cursors = 0;
int vis_fullscreen = 0;
struct ITaskbarList3 *pTaskbar3 = NULL;
static LRESULT Main_OnSysCommand( HWND hwnd, UINT cmd, int x, int y );
HWND find_otherwinamp( wchar_t * );
#undef HANDLE_WM_NCACTIVATE
#define HANDLE_WM_NCACTIVATE(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(BOOL)(fn)((hwnd), (BOOL)(wParam), (HWND)(lParam), 0L)
int stat_isit = 1; // used for faster version checkig
wchar_t szAppName[ 64 ] = { 0 }; // window class name, generated on the fly.
EXTERN_C BOOL eggTyping = FALSE;
static char eggstr[] = "NULLSOFT";
UINT USER_CONSENT_EVENT_ID = 123456;
int g_exit_disabled = 0;
int g_safeMode = 0;
HANDLE g_hEventRunning;
int bNoHwndOther = 0;
static void CreateEQPresets()
{
if ( !PathFileExistsW( EQDIR1 ) )
{
int x;
struct
{
char *s;
unsigned char tab[ 10 ];
}
eqsets[] =
{
{"Classical", {31, 31, 31, 31, 31, 31, 44, 44, 44, 48}},
{"Club", {31, 31, 26, 22, 22, 22, 26, 31, 31, 31}},
{"Dance", {16, 20, 28, 32, 32, 42, 44, 44, 32, 32}},
{"Flat", {31, 31, 31, 31, 31, 31, 31, 31, 31, 31}},
{"Laptop speakers/headphones", {24, 14, 23, 38, 36, 29, 24, 16, 11, 8}},
{"Large hall", {15, 15, 22, 22, 31, 40, 40, 40, 31, 31}},
{"Party", {20, 20, 31, 31, 31, 31, 31, 31, 20, 20}},
{"Pop", {35, 24, 20, 19, 23, 34, 36, 36, 35, 35}},
{"Reggae", {31, 31, 33, 42, 31, 21, 21, 31, 31, 31}},
{"Rock", {19, 24, 41, 45, 38, 25, 17, 14, 14, 14}},
{"Soft", {24, 29, 34, 36, 34, 25, 18, 16, 14, 12}},
{"Ska", {36, 40, 39, 33, 25, 22, 17, 16, 14, 16}},
{"Full Bass", {16, 16, 16, 22, 29, 39, 46, 49, 50, 50}},
{"Soft Rock", {25, 25, 28, 33, 39, 41, 38, 33, 27, 17}},
{"Full Treble", {48, 48, 48, 39, 27, 14, 6, 6, 6, 4}},
{"Full Bass & Treble", {20, 22, 31, 44, 40, 29, 18, 14, 12, 12}},
{"Live", {40, 31, 25, 23, 22, 22, 25, 27, 27, 28}},
{"Techno", {19, 22, 31, 41, 40, 31, 19, 16, 16, 17}},
};
for ( x = 0; x < sizeof( eqsets ) / sizeof( eqsets[ 0 ] ); x++ )
writeEQfile_init( EQDIR1, eqsets[ x ].s, eqsets[ x ].tab );
}
}
void BuildAppName()
{
StringCchCopyW( szAppName, 64, L"Winamp v1.x" );
StringCchPrintfW( caption, CAPTION_SIZE, L"%S %S", app_name, app_version_string );
}
static void CALLBACK DisplayUserConsentMessageBox( HWND hwnd, UINT uMsg, UINT_PTR eventId, DWORD time )
{
KillTimer( hMainWindow, USER_CONSENT_EVENT_ID );
if ( config_user_consent_join_channels != -1 )
{
return;
}
wchar_t titleStr[ 32 ] = { 0 };
int msgboxID = MessageBoxW(
NULL,
WASABI_API_LNGSTRINGW( IDS_RC_CHANNEL_MESSAGE ),
WASABI_API_LNGSTRINGW_BUF( IDS_RC_CHANNEL_TITLE, titleStr, 32 ),
MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON1
);
switch ( msgboxID )
{
case IDYES:
config_user_consent_join_channels = 1;
config_newverchk_rc = 1;
config_newverchk = 1;
break;
case IDNO:
config_user_consent_join_channels = 0;
config_newverchk_rc = 0;
config_newverchk = 1;
break;
}
}
// creates (but does not show) main window
int CreateMainWindow()
{
if ( !IsWindow( hMainWindow ) )
{
WNDCLASSW wcW = { 0 };
wcW.style = CS_DBLCLKS;
wcW.lpfnWndProc = Main_WndProc;
wcW.hInstance = hMainInstance;
wcW.hIcon = LoadIconW( hMainInstance, MAKEINTRESOURCE( ICON_XP ) );
wcW.hCursor = NULL;
wcW.lpszClassName = szAppName;
if ( !RegisterClassW( &wcW ) )
return 0;
if ( !CreateWindowExW( WS_EX_ACCEPTFILES, szAppName, L"Winamp", WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX | WS_BORDER | WS_CAPTION,
config_wx, config_wy, 0, 0, // WM_CREATE will size it
NULL, NULL, hMainInstance, NULL ) )
{
return 0;
}
}
return 1;
}
wchar_t *getGUIDstr( const GUID guid, wchar_t *target )
{
StringCchPrintfW( target, 40, L"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}\0",
(int)guid.Data1, (int)guid.Data2, (int)guid.Data3,
(int)guid.Data4[ 0 ], (int)guid.Data4[ 1 ], (int)guid.Data4[ 2 ], (int)guid.Data4[ 3 ],
(int)guid.Data4[ 4 ], (int)guid.Data4[ 5 ], (int)guid.Data4[ 6 ], (int)guid.Data4[ 7 ] );
return target;
}
BOOL parseMessageCommands( HWND hwnd_other, int bCommand, int bCmdParam )
{
if ( LOWORD( bCommand ) ) // attempt to send the action to it
{
if ( HIWORD( bCommand ) == 1 )
{
SendMessageW( hwnd_other, WM_WA_IPC, bCmdParam, MAKELPARAM( LOWORD( bCommand ), 0 ) );
return TRUE;
}
else if ( HIWORD( bCommand ) == 2 )
{
// these need some additional processing which is easier to do once we're loaded
if ( LOWORD( bCommand ) == EQ_PANLEFT || LOWORD( bCommand ) == EQ_PANRIGHT ||
LOWORD( bCommand ) == IPC_SETPANNING )
{
int pan = IPC_GETPANNING( hwnd_other );
if ( LOWORD( bCommand ) == EQ_PANLEFT ) pan -= 12;
else if ( LOWORD( bCommand ) == EQ_PANRIGHT ) pan += 12;
else pan = bCmdParam;
if ( pan < -127 ) pan = -127;
if ( pan > 127 ) pan = 127;
SendMessageW( hwnd_other, WM_WA_IPC, pan, IPC_SETPANNING );
}
else if ( LOWORD( bCommand ) == IPC_ISPLAYING )
{
int command = SendMessageW( hwnd_other, WM_WA_IPC, 0, IPC_ISPLAYING );
switch ( command )
{
case 1: // playing so need to pause
command = WINAMP_BUTTON3;
break;
default: // stopped so start playing
command = WINAMP_BUTTON2;
break;
}
SendMessageW( hwnd_other, WM_COMMAND, command, 0 );
}
return TRUE;
}
else
{
SendMessageW( hwnd_other, WM_COMMAND, bCommand, 0 );
if ( LOWORD( bCommand ) == WINAMP_JUMPFILE )
{
// TODO need to make this locale independant...
HWND jumpWnd = FindWindowW( NULL, L"Jump to file" );
if ( IsWindow( jumpWnd ) )
{
SetForegroundWindow( jumpWnd );
}
}
return TRUE;
}
}
return FALSE;
}
static int PassToOtherWinamp( wchar_t *lpszCmdParam, HWND hwnd_other, int bAdd, int bBookmark, int bHandle, int bCommand, int bCmdParam )
{
// if we have command line params, pass to other winamp window
if ( lpszCmdParam && *lpszCmdParam )
{
int skinExit = 0;
int bC = 0;
HANDLE hSem = NULL;
HINSTANCE existingWLZ = 0, templng = 0;
DWORD_PTR vn = 0;
// check if we're using a language pack with the already open winamp process
// and if so then we're going to use the winamp.lng from it on the messagebox
// only if we had a success and the other winamp returned the correct value
// within the timeout period (can't be having it lock up so revert if needed)
if ( SendMessageTimeout( hwnd_other, WM_WA_IPC, 1, IPC_GETLANGUAGEPACKINSTANCE, SMTO_NORMAL, 5000, &vn ) && !vn )
{
DWORD processid = 0;
HANDLE hwaProcess = NULL;
SIZE_T bread = 0;
wchar_t lng_path_copy[ MAX_PATH ] = { 0 }, dirmask[ MAX_PATH ] = { 0 }, gs[ 40 ] = { 0 };
WIN32_FIND_DATAW d = { 0 };
GetWindowThreadProcessId( hwnd_other, &processid );
hwaProcess = OpenProcess( PROCESS_VM_READ, FALSE, processid );
ReadProcessMemory( hwaProcess, (wchar_t *)SendMessageW( hwnd_other, WM_WA_IPC, 3, IPC_GETLANGUAGEPACKINSTANCE ), lng_path_copy, MAX_PATH, &bread );
CloseHandle( hwaProcess );
getGUIDstr( WinampLangGUID, gs );
PathCombineW( dirmask, lng_path_copy, L"*.lng" );
HANDLE h = FindFirstFileW( dirmask, &d );
if ( h != INVALID_HANDLE_VALUE )
{
do
{
PathCombineW( dirmask, lng_path_copy, d.cFileName );
templng = LoadLibraryExW( dirmask, NULL, LOAD_LIBRARY_AS_IMAGE_RESOURCE | LOAD_LIBRARY_AS_DATAFILE );
if ( !templng ) templng = LoadLibraryW( dirmask );
if ( templng )
{
wchar_t s[ 39 ] = { 0 };
if ( LoadStringW( templng, LANG_DLL_GUID_STRING_ID, s, 39 ) )
{
if ( !_wcsnicmp( gs, s, 38 ) )
{
existingWLZ = Lang_FakeWinampLangHInst( templng );
}
else
FreeLibrary( templng );
}
else
FreeLibrary( templng );
}
} while ( FindNextFileW( h, &d ) );
FindClose( h );
}
}
lpszCmdParam = CheckSkin( lpszCmdParam, hwnd_other, &skinExit );
if ( skinExit )
{
// restore the language pack settings now that we've done the override and clean up as needed
if ( existingWLZ )
{
Lang_FakeWinampLangHInst( existingWLZ );
FreeLibrary( templng );
}
return TRUE;
}
skinExit = 0;
lpszCmdParam = CheckLang( lpszCmdParam, hwnd_other, &skinExit );
// restore the language pack settings now that we've done the override and clean up as needed
if ( existingWLZ )
{
Lang_FakeWinampLangHInst( existingWLZ );
FreeLibrary( templng );
}
if ( skinExit )
return TRUE;
hSem = CreateSemaphoreA( 0, 0, 65535, "WinampExplorerHack1" );
if ( hSem && GetLastError() != ERROR_ALREADY_EXISTS )
{
bC = 1;
if ( !bAdd && !bBookmark && !bHandle )
{
SendMessageW( hwnd_other, WM_WA_IPC, 0, IPC_DELETE_INT );
}
}
if ( hSem )
{
ReleaseSemaphore( hSem, 1, NULL );
if ( bBookmark )
{
static wchar_t tmp[ MAX_PATH ];
StringCchPrintfW( tmp, MAX_PATH, L"/BOOKMARK %s", lpszCmdParam );
lpszCmdParam = tmp;
}
else if ( bHandle )
{
static wchar_t tmp[ MAX_PATH ];
StringCchPrintfW( tmp, MAX_PATH, L"/HANDLE %s", lpszCmdParam );
lpszCmdParam = tmp;
}
parseCmdLine( lpszCmdParam, hwnd_other );
WaitForSingleObject( hSem, 5000 );
if ( bC )
{
int n = 500;
if ( !bAdd && !bBookmark && !bHandle ) SendMessageW( hwnd_other, WM_WA_IPC, 0, IPC_STARTPLAY_INT );
Sleep( 200 );
for ( ;;)
{
if ( WaitForSingleObject( hSem, 100 ) == WAIT_TIMEOUT )
{
if ( WaitForSingleObject( hSem, 900 ) == WAIT_TIMEOUT )
{
break;
}
else
{
ReleaseSemaphore( hSem, 1, NULL );
n--;
}
}
else
{
ReleaseSemaphore( hSem, 1, NULL );
Sleep( 100 );
n--;
}
}
}
CloseHandle( hSem );
}
}
else
{
if ( !parseMessageCommands( hwnd_other, bCommand, bCmdParam ) )
{
ShowWindow( hwnd_other, SW_RESTORE );
SetForegroundWindow( hwnd_other );
}
}
return TRUE;
}
DWORD CALLBACK MainThread( LPVOID param );
extern wchar_t vidoutbuf_save[ 1024 ];
static LPWSTR lpszCmdParam = 0;
static int bAdd = 0, bBookmark = 0,
bHandle = 0, bCommand = 0,
bCmdParam = 0, bAllowCompat = 0;
void ShowSafeModeMessage( int mode )
{
if ( g_safeMode && ( g_safeMode != 3 ) )
{
wchar_t title[ 256 ] = { 0 }, message[ 512 ] = { 0 };
MSGBOXPARAMSW msgbx = { sizeof( MSGBOXPARAMSW ),0 };
if ( !mode )
{
msgbx.lpszText = getStringW( ( g_safeMode == 2 ? IDS_SAFE_MODE_ALL : IDS_SAFE_MODE_NORMAL ), message, 512 );
msgbx.lpszCaption = getStringW( IDS_START_SAFE_MODE, title, 256 );
}
else
{
msgbx.lpszText = getStringW( IDS_FAILED_SAFE_MODE_MSG, message, 512 );
msgbx.lpszCaption = getStringW( IDS_FAILED_SAFE_MODE, title, 256 );
}
msgbx.lpszIcon = MAKEINTRESOURCEW( 102 );
msgbx.hInstance = hMainInstance;
msgbx.dwStyle = MB_USERICON;
MessageBoxIndirectW( &msgbx );
}
}
#ifdef BETA
time_t inline get_compile_time( char const *time )
{
char s_month[ 5 ] = { 0 };
int day = 0, year = 0;
struct tm t = { 0 };
static const char month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
sscanf( time, "%s %d %d", s_month, &day, &year );
t.tm_mon = ( ( strstr( month_names, s_month ) - month_names ) / 3 );
t.tm_mday = day;
t.tm_year = year - 1900;
t.tm_isdst = -1;
return mktime( &t );
}
#endif
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInst, LPSTR unused /*lpszCmdParam*/, int nCmdShow )
{
INITCOMMONCONTROLSEX icex = { sizeof( icex ), ICC_WIN95_CLASSES | ICC_DATE_CLASSES };
InitCommonControlsEx( &icex );
QueryPerformanceFrequency( &freq );
#if 0
#ifdef BETA
// gives ~4 weeks from a build compile to when it'll show this (should be enough time)
time_t now = time( 0 ), compile = get_compile_time( app_date );
struct tm *tn = localtime( &now );
tn->tm_sec = tn->tm_min = tn->tm_hour = 0;
now = mktime( tn );
if ( ( now - compile ) >= 2678400 )
{
/* Skip the executable name in the commandline */
/* and check for /UNREG which we will allow so */
/* an expired beta can be uninstalled properly */
lpszCmdParam = GetCommandLineW();
lpszCmdParam = FindNextCommand( lpszCmdParam );
ParseParametersExpired( lpszCmdParam );
MSGBOXPARAMSW msgbx = {
sizeof( MSGBOXPARAMSW ),
0,
GetModuleHandle( NULL ),
L"This beta version of Winamp is now over 4 weeks old.\n\n"
L"Please update to the latest Winamp version available.",
L"Winamp Beta Expired",
MB_USERICON,
MAKEINTRESOURCEW( 102 ),
0, 0, 0
};
MessageBoxIndirectW( &msgbx );
ShellExecuteW( NULL, L"open", L"http://www.winamp.com/media-player", NULL, NULL, SW_SHOWNORMAL );
return 0;
}
#endif
#endif
DWORD threadId = 0, res = 0;
HANDLE mainThread = nullptr;
int cmdShow = nCmdShow;
/*void *refCounter = */InitAppRefCounterObject( GetCurrentThreadId() );
//SHSetInstanceExplorer((IUnknown *)refCounter);
SetErrorMode( SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS );
// don't load from working directory !!!!!
// requires XP SP3+
SetDllDirectoryW( L"" );
GetModuleFileNameW( NULL, SHAREDDIR, MAX_PATH );
PathRemoveFileSpecW( SHAREDDIR );
PathAppendW( SHAREDDIR, L"Shared" );
// load supporting dlls from the Winamp\Shared directory
SetDllDirectoryW( SHAREDDIR );
hMainInstance = hInstance;
/* Skip the executable name in the commandline */
lpszCmdParam = GetCommandLineW();
lpszCmdParam = FindNextCommand( lpszCmdParam );
BuildAppName();
init_config();
LoadPathsIni();
lpszCmdParam = ParseParameters( lpszCmdParam, &bAdd, &bBookmark, &bHandle, &cmdShow, &bCommand, &bCmdParam, &bAllowCompat );
setup_config();
// ensure we've got things set up as needed for safe mode being always on so we
// don't incorrectly prompt about entering it from using IPC_RESTARTSAFEWINAMP.
int mode = _r_i( "allowcompat", 0 );
if ( mode ) bAllowCompat = 1;
if ( !bAllowCompat && read_compatmode() )
{
MSGBOXPARAMSW msgbx = {
sizeof( MSGBOXPARAMSW ),
0,
GetModuleHandle( NULL ),
L"Winamp appears to have been started with Windows program compatibility mode enabled.\n\n"
L"This is not a recommended way to run Winamp as it can often cause problems with how Winamp works e.g. causing it to randomly crash."
L"\n\n\nAre you sure you want to continue to run Winamp like this?\n\n\n"
L"If you choose 'No', you can disable this by right-clicking winamp.exe, choosing 'Properties' and selecting the 'Compatibility' tab, "
L"followed by unchecking 'Run this program in compatibility mode for:' and run Winamp again.",
L"Winamp",
MB_USERICON | MB_YESNO | MB_DEFBUTTON2,
MAKEINTRESOURCEW( 102 ),
0, 0, 0
};
if ( MessageBoxIndirectW( &msgbx ) == IDNO )
{
return 0;
}
}
CoInitializeEx( 0, COINIT_MULTITHREADED );
// ensure we've got things set up as needed for safe mode being always on so we
// don't incorrectly prompt about entering it from using IPC_RESTARTSAFEWINAMP.
mode = _r_i( "safemode", 0 );
if ( mode ) g_safeMode = 3;
if ( 0 == ( 128 & is_install ) )
{
HWND hwnd_other = find_otherwinamp( lpszCmdParam );
if ( IsWindow( hwnd_other ) )
{
// unable to start safe mode so inform the user
ShowSafeModeMessage( 1 );
int x = PassToOtherWinamp( lpszCmdParam, hwnd_other, bAdd, bBookmark, bHandle, bCommand, bCmdParam );
CoUninitialize();
return x;
}
}
// unable to start safe mode so inform the user
ShowSafeModeMessage( 0 );
mainThread = CreateThread( 0, 0, MainThread, (LPVOID)cmdShow, 0, &threadId );
while ( !AppRefCount_CanQuit() )
{
DWORD dwStatus = MsgWaitForMultipleObjectsEx( 1, &mainThread, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE | MWMO_INPUTAVAILABLE );
if ( dwStatus == WAIT_OBJECT_0 + 1 )
{
MSG msg;
while ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
{
if ( msg.message == WM_QUIT )
return msg.wParam;
DispatchMessage( &msg );
}
}
else if ( dwStatus == WAIT_OBJECT_0 )
{
GetExitCodeThread( mainThread, &res );
CloseHandle( mainThread );
AppRefCount_Release();
}
}
return 0;
}
static BOOL LoadWMFilter()
{
if ( !changeWMLoadTried )
{
user32Lib = LoadLibraryA( "user32.dll" );
if ( user32Lib )
changeWMFilter = (CHANGEWINDOWMESSAGEFILTER)GetProcAddress( user32Lib, "ChangeWindowMessageFilter" );
changeWMLoadTried = TRUE;
}
return user32Lib && changeWMFilter;
}
VOID CALLBACK PrefsShowProc( HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime )
{
KillTimer( hwnd, idEvent );
if ( IsWindow( prefs_hwnd ) )
SetForegroundWindow( prefs_hwnd );
}
void load_gen_crasher()
{
// this will load gen_crasher.dll as applicable (included in beta builds but not release mode by default)
// with extra checks to ensure it's 'valid' (as can be) so we could drop it into release builds as needed
wchar_t crasherDll[ MAX_PATH ] = { 0 };
PathCombineW( crasherDll, PLUGINDIR, L"gen_crasher.dll" );
HMODULE hm = LoadLibraryW( crasherDll );
if ( hm )
{
int( __cdecl * StartHandler )( wchar_t *iniPath ) = NULL;
*(FARPROC *)&StartHandler = GetProcAddress( hm, "StartHandler" );
if ( StartHandler )
{
wchar_t iniPath[ MAX_PATH ] = { 0 };
if ( SUCCEEDED( StringCchPrintfW( iniPath, MAX_PATH, L"%s\\Plugins", CONFIGDIR ) ) )
{
winampGeneralPurposePluginGetter pr = (winampGeneralPurposePluginGetter)GetProcAddress( hm, "winampGetGeneralPurposePlugin" );
if ( pr )
{
winampGeneralPurposePlugin *plugin = pr();
if ( plugin && plugin->version == GPPHDR_VER_U )
{
char desc[ 128 ] = { 0 };
lstrcpynA( desc, plugin->description, sizeof( desc ) );
if ( desc[ 0 ] && !memcmp( desc, "nullsoft(", 9 ) )
{
char *p = strrchr( desc, ')' );
if ( p )
{
*p = 0;
if ( !_wcsicmp( L"gen_crasher.dll", AutoWide( desc + 9 ) ) )
{
StartHandler( iniPath );
}
else
FreeLibrary( hm );
}
else
FreeLibrary( hm );
}
else
FreeLibrary( hm );
}
else
FreeLibrary( hm );
}
else
FreeLibrary( hm );
}
else
FreeLibrary( hm );
}
else
FreeLibrary( hm );
}
}
DWORD CALLBACK MainThread( LPVOID param )
{
language_pack_instance = hMainInstance;
playlistStr[ 0 ] = 0;
playlistStr[ 18 ] = 0; // keep the last byte null terminated (and don't overwrite) so we can be smoewhat thread-safe (may have junk data, but it won't read outside the array)
vidoutbuf_save[ 0 ] = 0;
vidoutbuf_save[ 1023 ] = 0; // keep the last byte null terminated (and don't overwrite) so we can be smoewhat thread-safe (may have junk data, but it won't read outside the array)
mainThreadId = GetCurrentThreadId();
DuplicateHandle( GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &hMainThread, 0, FALSE, DUPLICATE_SAME_ACCESS );
InitializeCriticalSection( &embedcs );
CoInitialize( 0 );
Wasabi_Load();
plstring_init();
/*Browser_Create();*/
// check if it's gen_crasher.dll that's being removed and skip loading it so uninstall will work
bool skip_crasher = false;
wchar_t buf[ 1024 ] = { 0 };
_r_sW( "remove_genplug", buf, 1024 );
if ( buf[ 0 ] )
skip_crasher = !wcsicmp( PathFindFileNameW( buf ), L"gen_crasher.dll" );
if ( !skip_crasher )
load_gen_crasher();
if ( ( 128 & is_install ) || ( !g_noreg && GetPrivateProfileIntW( L"WinampReg", L"NeedReg", 1, INI_FILE ) ) )
{
is_install = 128; // nothing else
Setup_RegisterService();
}
draw_firstinit();
WM_TASKBARCREATED = RegisterWindowMessageA( "TaskbarCreated" );
g_scrollMsg = RegisterWindowMessageA( "MSWHEEL_ROLLMSG" );
WM_TASKBARBUTTONCREATED = RegisterWindowMessageW( L"TaskbarButtonCreated" );
if ( LoadWMFilter() )
{
changeWMFilter( WM_TASKBARBUTTONCREATED, 1/*MSGFLT_ADD*/ );
changeWMFilter( WM_DWMSENDICONICTHUMBNAIL, 1/*MSGFLT_ADD*/ );
changeWMFilter( WM_DWMSENDICONICLIVEPREVIEWBITMAP, 1/*MSGFLT_ADD*/ );
changeWMFilter( WM_COMMAND, 1/*MSGFLT_ADD*/ ); //for thumbnail toolbar buttons
}
CommandLink_RegisterClass( hMainInstance );
Skin_CleanupAfterCrash();
Lang_CleanupAfterCrash();
{
int langExit = 0;
lpszCmdParam = CheckLang( lpszCmdParam, 0, &langExit );
if ( langExit )
{
Lang_EndLangSupport();
Lang_CleanupZip();
return TRUE;
}
}
if ( !g_safeMode )
{
language_pack_instance = Lang_InitLangSupport( hMainInstance, WinampLangGUID );
Lang_FollowUserDecimalLocale();
}
if ( bBookmark )
{
w5s_init();
if ( !in_init() )
{
w5s_deinit();
Wasabi_Unload();
RemoveRegistrar();
CoUninitialize();
ExitProcess( 0 );
}
Bookmark_AddCommandline( lpszCmdParam );
in_deinit();
w5s_deinit();
Wasabi_Unload();
RemoveRegistrar();
CoUninitialize();
ExitProcess( 0 );
}
{
int skinExit = 0;
lpszCmdParam = CheckSkin( lpszCmdParam, 0, &skinExit );
if ( skinExit )
{
return TRUE;
}
}
{
// remove general purpose plug-in (if set)
wchar_t buf[ 1024 ] = { 0 };
_r_sW( "remove_genplug", buf, 1024 );
if ( buf[ 0 ] )
{
IFileTypeRegistrar *registrar = 0;
if ( GetRegistrar( &registrar, true ) == 0 && registrar )
{
registrar->DeleteItem( buf );
// if gen_crasher is requested to remove, also remove reporter.exe
if ( skip_crasher )
{
GetModuleFileNameW( NULL, buf, MAX_PATH );
PathRemoveFileSpecW( buf );
PathCombineW( buf, buf, L"reporter.exe" );
registrar->DeleteItem( buf );
}
registrar->Release();
}
_w_s( "remove_genplug", 0 );
}
}
fft_init();
SpectralAnalyzer_Create();
JSAPI1_Initialize();
stats_init();
w5s_init();
if ( !in_init() )
{
w5s_deinit();
Wasabi_Unload();
RemoveRegistrar();
CoUninitialize();
ExitProcess( 0 );
}
out_init();
vis_init();
if ( lpszCmdParam && *lpszCmdParam && !bAdd && !bHandle )
config_read( 1 );
else
config_read( 0 );
CreateEQPresets();
if ( is_install )
DoInstall( is_install );
reg_associated_filetypes( 0 );
if ( config_splash ) splashDlg( SPLASH_DELAY ); // display splash screen if desired
PlayList_getcurrent( FileName, FileTitle, FileTitleNum ); // update filename and filetitle if a list was loaded
songChangeBroadcastMessage = RegisterWindowMessageW( L"WinampSongChange" );
if ( !InitApplication( hMainInstance ) )
{
LPMessageBox( NULL, IDS_ERRORINIT, IDS_ERROR, MB_OK );
return FALSE;
}
if ( !InitInstance( hMainInstance, (int)param ) )
{
LPMessageBox( NULL, IDS_ERRORINIT, IDS_ERROR, MB_OK );
return FALSE;
}
if ( !bHandle )
{
if ( *lpszCmdParam ) // if command line parameters, parse them
{
parseCmdLine( lpszCmdParam, 0 );
plEditRefresh();
{
if ( config_shuffle )
PlayList_randpos( -BIGINT );
if ( !bAdd )
bStartPlaying = 1;
}
}
else // otherwise, we're using our loaded playlist
{
if ( config_shuffle ) PlayList_randpos( -BIGINT );
PlayList_getcurrent( FileName, FileTitle, FileTitleNum );
}
}
//SetCurrentDirectoryW(config_cwd);
plEditSelect( PlayList_getPosition() );
Ole_initDragDrop();
if ( !( GetAsyncKeyState( VK_RCONTROL ) & 0x8000 ) || !( GetAsyncKeyState( VK_LCONTROL ) & 0x8000 ) )
{
load_genplugins(); // load general purpose plugins
if ( !Skin_Check_Modern_Support() )
{
wchar_t msg[ 512 ] = { 0 };
StringCchPrintfW( msg, 512, getStringW( IDS_NO_MODERN_SKIN_SUPPORT, NULL, 0 ), config_skin );
MessageBoxW( NULL, msg, getStringW( IDS_SKIN_LOAD_ERROR, NULL, 0 ), MB_ICONWARNING | MB_OK | MB_TOPMOST );
}
}
//disable video menu if no video plugins are present or configured as disabled
if ( !g_has_video_plugin )
{
RemoveMenu( main_menu, WINAMP_OPTIONS_VIDEO, MF_BYCOMMAND );
RemoveMenu( GetSubMenu( v5_top_menu, 3 ), WINAMP_OPTIONS_VIDEO, MF_BYCOMMAND );
g_mm_optionsbase_adj -= 1;
}
set_aot( 0 ); // in case our gen plugins did anything fun
set_priority();
{
int v = _r_i( "show_prefs", 0 );
if ( v != 0 )
{
if ( v > 0 ) prefs_last_page = v;
_w_i( "show_prefs", 0 );
PostMessageW( hMainWindow, WM_COMMAND, WINAMP_OPTIONS_PREFS, 0 );
SetTimer( hMainWindow, 969, 1, PrefsShowProc );
}
}
if ( bStartPlaying )
{
PlayList_getcurrent( FileName, FileTitle, FileTitleNum );
SendMessageW( hMainWindow, WM_COMMAND, WINAMP_BUTTON2, 0 );
//SendMessageW(hMainWindow,WM_WA_IPC,0,IPC_STARTPLAY);
draw_paint( NULL );
}
WADlg_init( hMainWindow );
SetTimer( hMainWindow, USER_CONSENT_EVENT_ID, 5000, DisplayUserConsentMessageBox );
#ifdef BENSKI_TEST_WM_PRINTCLIENT
SetTimer( hMainWindow, 9999, 10000, 0 );
#endif
if ( bHandle && *lpszCmdParam )
PostMessageW( hMainWindow, WM_WA_IPC, (WPARAM)lpszCmdParam, IPC_HANDLE_URI );
parseMessageCommands( hMainWindow, bCommand, bCmdParam );
WPARAM exitParam = WinampMessageLoop();
JSAPI1_Uninitialize();
unload_genplugins();
w5s_deinit();
stats_save();
SpectralAnalyzer_Destroy();
/*Browser_Destroy();*/
//RaiseException(0x0000DEAD,0,0,0);
Ole_uninitDragDrop();
if ( g_restartonquit )
{
char buf[ MAX_PATH ] = "\"";
STARTUPINFO si = { sizeof( si ), };
PROCESS_INFORMATION pi;
GetModuleFileNameA( NULL, buf + 1, sizeof( buf ) - 1 );
StringCchCatA( buf, MAX_PATH, "\"" );
if ( g_restartonquit == 2 )
StringCchCatA( buf, MAX_PATH, " /SAFE=1" );
CreateProcessA( NULL, buf, NULL, NULL, FALSE, 0, NULL, NULL, (LPSTARTUPINFOA)&si, &pi );
}
RemoveRegistrar();
Wasabi_Unload();
CoUninitialize();
return exitParam;
} // WinMain
void MoveOffscreen( HWND hwnd )
{
RECT r;
GetWindowRect( hwnd, &r );
SetWindowPos( hwnd, 0, r.left, OFFSCREEN_Y_POS, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
}
int g_showcode, deferring_show = 0;
#include "../Plugins/General/gen_ml/ml_ipc.h"
extern librarySendToMenuStruct mainSendTo = { 0 };
// used to delay / filter out quick IPC_SETDIALOGBOXPARENT messages
// to try to prevent the aero-peek buttons failing / part loading
#define AEROPEEKLOAD 0xC0DE+5
VOID CALLBACK TaskButtonCreated( HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime )
{
KillTimer( hwnd, idEvent );
OnTaskbarButtonCreated( TRUE );
}
void UpdateAudioCDMenus( HMENU hmenu )
{
wchar_t buf[ 32 ] = { 0 };
if ( IsMenu( hmenu ) && in_get_extended_fileinfoW( L"cda://", L"ext_cdda", buf, ARRAYSIZE( buf ) ) && buf[ 0 ] == L'1' )
{
for ( int i = 0; i < 5; i++ )
{
DeleteMenu( hmenu, ID_MAIN_PLAY_AUDIOCD + i, MF_BYCOMMAND );
}
MENUITEMINFOW i = { sizeof( i ), MIIM_TYPE | MIIM_DATA | MIIM_ID, MFT_STRING, };
i.wID = ID_MAIN_PLAY_AUDIOCD;
DWORD drives = GetLogicalDrives();
g_audiocdletters = 0;
int need_sep = 1;
for ( int drivemask = 0; drivemask < 32; drivemask++ )
{
if ( drives & ( 1 << drivemask ) )
{
int old_error_mode = SetErrorMode( SEM_FAILCRITICALERRORS );
wchar_t str[ 64 ] = { 0 }, tmp[ 64 ] = { 0 }, vol_buf[ 40 ] = { 0 }, empty[ 64 ] = { 0 };
DWORD system_flags = 0, max_file_len = 0;
char c = ( 'A' + drivemask );
StringCchPrintfW( str, 64, L"%c:\\", c );
if ( GetDriveTypeW( str ) == DRIVE_CDROM )
{
if ( need_sep )
{
MENUITEMINFO i2 = { sizeof( i2 ), MIIM_TYPE | MIIM_ID, MFT_SEPARATOR, };
i2.wID = ID_MAIN_PLAY_AUDIOCD_SEP;
InsertMenuItem( hmenu, 4, TRUE, &i2 );
need_sep = 0;
}
GetVolumeInformationW( str, vol_buf, ARRAYSIZE( vol_buf ), 0, &max_file_len, &system_flags, 0, 0 );
SetErrorMode( old_error_mode );
StringCchPrintfW( str, 256, getStringW( IDS_AUDIO_CD, tmp, 64 ), c, ( vol_buf[ 0 ] ? vol_buf : getStringW( IDS_EMPTY, empty, 64 ) ) );
g_audiocdletter[ g_audiocdletters ] = c;
i.dwTypeData = str;
i.cch = (UINT)wcslen( str );
InsertMenuItemW( hmenu, 4 + g_audiocdletters, TRUE, &i );
i.wID++;
g_audiocdletters++;
if ( g_audiocdletters == 4 )
break;
}
}
}
}
}
// Main Winamp window procedure
// we use message crackers when available, write our own for the ones that aren't
LRESULT CALLBACK Main_WndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
if ( uMsg == g_scrollMsg )
{
wParam <<= 16;
uMsg = WM_MOUSEWHEEL;
}
if ( uMsg == WM_TASKBARCREATED )
{
if ( systray_intray )
{
systray_restore();
systray_minimize( caption );
}
return 0;
}
if ( uMsg == WM_TASKBARBUTTONCREATED )
{
OnTaskbarButtonCreated( TRUE );
KillTimer( hMainWindow, AEROPEEKLOAD );
SetTimer( hMainWindow, AEROPEEKLOAD, 250, TaskButtonCreated );
return 0;
}
if ( IsDirectMouseWheelMessage( uMsg ) != FALSE )
{
SendMessageW( hwnd, WM_MOUSEWHEEL, wParam, lParam );
return TRUE;
}
switch ( uMsg )
{
case WM_INITMENUPOPUP:
{
HMENU hMenu = (HMENU)wParam;
if ( wParam && hMenu == mainSendTo.build_hMenu && mainSendTo.mode == 1 )
{
int IPC_LIBRARY_SENDTOMENU = wa_register_ipc( ( WPARAM ) & "LibrarySendToMenu" );
if ( IPC_LIBRARY_SENDTOMENU > 65536 && SendMessageW( hMainWindow, WM_WA_IPC, (WPARAM)&mainSendTo, IPC_LIBRARY_SENDTOMENU ) == 0xffffffff )
mainSendTo.mode = 2;
}
if ( config_usecursors && !disable_skin_cursors )
{
if ( Skin_Cursors[ 2 ] )
SetCursor( Skin_Cursors[ 2 ] );
else
SetCursor( LoadCursorW( NULL, IDC_ARROW ) );
}
else
SetCursor( LoadCursorW( NULL, IDC_ARROW ) );
if ( hMenu == main_menu )
{
MENUITEMINFOW l_menu_info = { sizeof( l_menu_info ), };
l_menu_info.fMask = MIIM_TYPE;
l_menu_info.fType = MFT_STRING;
l_menu_info.dwTypeData = getStringW( IDS_WINAMP_MENUITEM, NULL, 0 );
l_menu_info.cch = (UINT)wcslen( l_menu_info.dwTypeData );
SetMenuItemInfoW( main_menu, 0, TRUE, &l_menu_info );
EnableMenuItem( main_menu, WINAMP_FILE_QUIT, MF_BYCOMMAND | ( g_exit_disabled ? MF_GRAYED : MF_ENABLED ) );
}
else if ( hMenu == g_submenus_play )
{
UpdateAudioCDMenus( g_submenus_play );
}
else if ( hMenu == g_submenus_bookmarks1 || hMenu == g_submenus_bookmarks2 )
{
MENUITEMINFOW l_menu_info = { sizeof( l_menu_info ), };
FILE *fp = 0;
int a = 34768;
int offs = 3;
int count = GetMenuItemCount( hMenu ) + 1;
if ( hMenu != g_submenus_bookmarks1 )
offs = 0;
l_menu_info.fMask = MIIM_TYPE | MIIM_DATA | MIIM_ID;
l_menu_info.fType = MFT_STRING;
l_menu_info.wID = 34768;
// this will remove the "(no bookmarks)" item from Main menu->Play->Bookmsrk
// if it still exists -> removed as of 5.55 since we handle the menu better.
if ( !offs ) RemoveMenu( hMenu, ID_MAIN_PLAY_BOOKMARK_NONE, MF_BYCOMMAND );
// remove all of the items we might have added - do by command for certainty
while ( count )
{
if ( !RemoveMenu( hMenu, a++, MF_BYCOMMAND ) ) break;
count--;
}
fp = _wfopen( BOOKMARKFILE8, L"rt" );
if ( fp )
{
while ( 1 )
{
char ft[ 4096 ] = { 0 }, fn[ MAX_PATH ] = { 0 };
fgets( fn, MAX_PATH, fp );
if ( feof( fp ) ) break;
fgets( ft, 4096, fp );
if ( feof( fp ) ) break;
if ( ft[ 0 ] && fn[ 0 ] )
{
if ( fn[ lstrlenA( fn ) - 1 ] == '\n' ) fn[ lstrlenA( fn ) - 1 ] = 0;
if ( ft[ lstrlenA( ft ) - 1 ] == '\n' ) ft[ lstrlenA( ft ) - 1 ] = 0;
if ( ft[ 0 ] && fn[ 0 ] )
{
l_menu_info.dwTypeData = AutoWideDup( ft, CP_UTF8 );
l_menu_info.cch = lstrlenW( l_menu_info.dwTypeData );
RemoveMenu( hMenu, l_menu_info.wID, MF_BYCOMMAND );
InsertMenuItemW( hMenu, l_menu_info.wID + offs - 34768, TRUE, &l_menu_info );
l_menu_info.wID++;
}
}
}
fclose( fp );
}
g_BookmarkTop = l_menu_info.wID;
// put in a place holder item if there were no read bookmarks
if ( g_BookmarkTop == 34768 )
{
l_menu_info.dwTypeData = getStringW( IDS_NO_BOOKMARKS, NULL, 0 );
l_menu_info.cch = lstrlenW( l_menu_info.dwTypeData );
InsertMenuItemW( hMenu, l_menu_info.wID + offs - 34768, TRUE, &l_menu_info );
EnableMenuItem( hMenu, l_menu_info.wID, MF_BYCOMMAND | MF_GRAYED );
}
}
else if ( hMenu == g_submenus_skins1 || hMenu == g_submenus_skins2 )
{
MENUITEMINFOW l_menu_info = { sizeof( l_menu_info ), };
HANDLE h;
WIN32_FIND_DATAW d = { 0 };
wchar_t dirmask[ MAX_PATH ] = { 0 };
l_menu_info.fMask = MIIM_TYPE | MIIM_DATA | MIIM_ID | MIIM_STATE;
l_menu_info.fType = MFT_STRING;
l_menu_info.wID = 32768;
PathCombineW( dirmask, SKINDIR, L"*" );
if ( !config_skin[ 0 ] )
CheckMenuItem( hMenu, 32767, MF_CHECKED );
else
CheckMenuItem( hMenu, 32767, MF_UNCHECKED );
h = FindFirstFileW( dirmask, &d );
if ( h != INVALID_HANDLE_VALUE )
{
int a = 0, mod_got = 0, bento_got = 0, checked = 0;
do
{
if ( !wcscmp( d.cFileName, L"." ) || !wcscmp( d.cFileName, L".." ) ) continue;
if ( ( d.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) ||
!_wcsicmp( extensionW( d.cFileName ), L"zip" ) ||
!_wcsicmp( extensionW( d.cFileName ), L"wal" ) ||
!_wcsicmp( extensionW( d.cFileName ), L"wsz" ) )
{
if ( !_wcsicmp( config_skin, d.cFileName ) )
{
l_menu_info.fState = MFS_CHECKED | MFS_ENABLED;
checked = 1;
}
else
{
l_menu_info.fState = MFS_UNCHECKED | MFS_ENABLED;
}
if ( d.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
l_menu_info.dwItemData = 0;
else
{
if ( !_wcsicmp( extensionW( d.cFileName ), L"zip" ) )
l_menu_info.dwItemData = 1;
else if ( !_wcsicmp( extensionW( d.cFileName ), L"wal" ) )
l_menu_info.dwItemData = 4;
else
l_menu_info.dwItemData = 2;
extensionW( d.cFileName )[ -1 ] = 0;
}
l_menu_info.dwTypeData = d.cFileName;
l_menu_info.cch = (UINT)wcslen( d.cFileName );
if ( !a )
if ( !RemoveMenu( hMenu, l_menu_info.wID + 4 - 32768, MF_BYPOSITION ) )
a = 1;
if ( !l_menu_info.dwItemData && !_wcsicmp( d.cFileName, MODERN_SKIN_NAME ) )
{
mod_got = 1;
InsertMenuItemW( hMenu, 4, TRUE, &l_menu_info );
}
else if ( !_wcsicmp( d.cFileName, BENTO_SKIN_NAME ) )
{
// place below classic + modern (if it exists)
bento_got = 1;
InsertMenuItemW( hMenu, 4 + mod_got, TRUE, &l_menu_info );
}
else if ( !_wcsicmp( d.cFileName, BIG_BENTO_SKIN_NAME ) )
{
// place below classic + modern + normal bento (if it exists)
InsertMenuItemW( hMenu, 4 + mod_got + bento_got, TRUE, &l_menu_info );
}
else
InsertMenuItemW( hMenu, l_menu_info.wID + 4 - 32768, TRUE, &l_menu_info );
l_menu_info.wID++;
}
} while ( l_menu_info.wID < 34700 && FindNextFileW( h, &d ) );
FindClose( h );
g_SkinTop = l_menu_info.wID;
while ( !a ) if ( !RemoveMenu( hMenu, l_menu_info.wID++ + 4 - 32768, MF_BYPOSITION ) ) a = 1;
if ( !checked ) CheckMenuItem( hMenu, 32767, MF_CHECKED );
}
}
else if ( ( hMenu == g_submenus_lang ) && config_wlz_menu )
{
MENUITEMINFOW l_menu_info = { sizeof( l_menu_info ), };
HANDLE h;
WIN32_FIND_DATAW d = { 0 };
wchar_t dirmask[ MAX_PATH ] = { 0 };
l_menu_info.fMask = MIIM_TYPE | MIIM_DATA | MIIM_ID | MIIM_STATE;
l_menu_info.fType = MFT_STRING;
l_menu_info.wID = 34700;
PathCombineW( dirmask, LANGDIR, L"*" );
l_menu_info.dwTypeData = L"English (US)";
l_menu_info.cch = (UINT)wcslen( l_menu_info.dwTypeData );
InsertMenuItemW( hMenu, l_menu_info.wID - 34700, TRUE, &l_menu_info );
l_menu_info.wID++;
CheckMenuItem( hMenu, 34700, ( !config_langpack[ 0 ] ? MF_CHECKED : MF_UNCHECKED ) );
h = FindFirstFileW( dirmask, &d );
if ( h != INVALID_HANDLE_VALUE )
{
int a = 0, checked = 0;
do
{
if ( !wcscmp( d.cFileName, L"." ) || !wcscmp( d.cFileName, L".." ) ) continue;
if ( ( d.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) ||
!_wcsicmp( extensionW( d.cFileName ), L"zip" ) ||
!_wcsicmp( extensionW( d.cFileName ), L"wlz" ) )
{
if ( !_wcsicmp( config_langpack, d.cFileName ) )
{
l_menu_info.fState = MFS_CHECKED | MFS_ENABLED;
checked = 1;
}
else
{
l_menu_info.fState = MFS_UNCHECKED | MFS_ENABLED;
}
if ( d.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
{
wchar_t check[ MAX_PATH ] = { 0 };
PathCombineW( check, LANGDIR, d.cFileName );
PathCombineW( check, check, L"winamp.lng" );
if ( !PathFileExistsW( check ) )
continue;
l_menu_info.dwItemData = 0;
}
else
{
if ( !_wcsicmp( extensionW( d.cFileName ), L"zip" ) )
l_menu_info.dwItemData = 1;
else
l_menu_info.dwItemData = 2;
extensionW( d.cFileName )[ -1 ] = 0;
}
l_menu_info.dwTypeData = d.cFileName;
l_menu_info.cch = (UINT)wcslen( d.cFileName );
if ( !a )
if ( !RemoveMenu( hMenu, l_menu_info.wID - 34700, MF_BYPOSITION ) )
a = 1;
InsertMenuItemW( hMenu, l_menu_info.wID - 34700, TRUE, &l_menu_info );
l_menu_info.wID++;
}
} while ( l_menu_info.wID < 34800 && FindNextFileW( h, &d ) );
FindClose( h );
g_LangTop = l_menu_info.wID;
while ( !a )
if ( !RemoveMenu( hMenu, l_menu_info.wID++ - 34700, MF_BYPOSITION ) )
a = 1;
if ( !checked )
CheckMenuItem( hMenu, 34700, MF_CHECKED );
}
}
break;
}
case WM_DISPLAYCHANGE:
Main_OnDisplayChange( hwnd );
break;
case WM_WA_SYSTRAY:
return ( Main_OnWASystray( hwnd, (int)LOWORD( lParam ) ) ? 0 : -1L );
case WM_WA_MPEG_EOF:
return ( Main_OnWAMPEGEOF( hwnd ) ? 0 : -1L ); // sent by decode thread
case WM_WA_IPC:
return ( Main_OnIPC( hwnd, lParam, (int)(DWORD)wParam ) );
HANDLE_MSG( hwnd, WM_COMMAND, Main_OnCommand );
HANDLE_MSG( hwnd, WM_SYSCOMMAND, Main_OnSysCommand );
HANDLE_MSG( hwnd, WM_CREATE, Main_OnCreate );
HANDLE_MSG( hwnd, WM_QUERYNEWPALETTE, Main_OnQueryNewPalette );
HANDLE_MSG( hwnd, WM_PALETTECHANGED, Main_OnPaletteChanged );
HANDLE_MSG( hwnd, WM_SIZE, Main_OnSize );
HANDLE_MSG( hwnd, WM_DROPFILES, Main_OnDropFiles );
HANDLE_MSG( hwnd, WM_TIMER, Main_OnTimer );
HANDLE_MSG( hwnd, WM_PAINT, draw_paint );
case WM_PRINTCLIENT:
draw_printclient( (HDC)wParam, lParam );
return 0;
HANDLE_MSG( hwnd, WM_RBUTTONUP, Main_OnRButtonUp );
HANDLE_MSG( hwnd, WM_LBUTTONDBLCLK, Main_OnLButtonDblClk );
HANDLE_MSG( hwnd, WM_LBUTTONUP, Main_OnLButtonUp );
HANDLE_MSG( hwnd, WM_LBUTTONDOWN, Main_OnLButtonDown );
HANDLE_MSG( hwnd, WM_MOUSEMOVE, Main_OnMouseMove );
case WM_CONTEXTMENU:
SendMessageW( hwnd, WM_COMMAND, WINAMP_MAINMENU, 0 );
return 0;
case WM_CAPTURECHANGED:
return Main_OnCaptureChanged( (HWND)lParam );
HANDLE_MSG( hwnd, WM_DESTROY, Main_OnDestroy );
HANDLE_MSG( hwnd, WM_CLOSE, Main_OnClose );
case WM_NCACTIVATE:
{
LRESULT result = (LRESULT)(DWORD)(BOOL)(Main_OnNCActivate)( ( hwnd ), (BOOL)( wParam ), (HWND)( lParam ), 0L );
if ( IsIconic( hwnd ) )
break;
else
return result;
}
case WM_NCHITTEST:
if ( IsIconic( hwnd ) )
break;
return (LRESULT)(DWORD)(UINT)(Main_OnNCHitTest)( ( hwnd ), (int)(short)LOWORD( lParam ), (int)(short)HIWORD( lParam ) );
case WM_NCCALCSIZE:
if ( IsIconic( hwnd ) )
break;
return (LRESULT)(DWORD)(UINT)Main_OnNCCalcSize( hwnd, (BOOL)wParam, (NCCALCSIZE_PARAMS *)lParam );
HANDLE_MSG( hwnd, WM_ENDSESSION, Main_OnEndSession );
case WM_QUERYENDSESSION:
return !!SendMessageW( hwnd, WM_WA_IPC, 0, IPC_HOOK_OKTOQUIT );
case WM_KEYDOWN:
{
static int pos;
TCHAR buf[ 2 ] = { (TCHAR)wParam, 0 };
CharUpperBuff( buf, 1 );
if ( buf[ 0 ] == eggstr[ pos ] )
{
eggTyping = TRUE;
if ( !eggstr[ ++pos ] )
{
eggTyping = FALSE;
eggstat = !eggstat;
pos = 0;
draw_tbar( 1, config_windowshade, eggstat );
}
}
else
pos = 0;
break;
}
case WM_NCPAINT:
return 0;
case WM_COPYDATA:
return Main_OnCopyData( (HWND)wParam, (COPYDATASTRUCT *)lParam );
case WM_GETTEXT:
return Main_OnGetText( (wchar_t *)lParam, (int)wParam );
case WM_NOTIFY:
{
LPTOOLTIPTEXTW tt = (LPTOOLTIPTEXTW)lParam;
if ( tt->hdr.hwndFrom = hTooltipWindow )
{
switch ( tt->hdr.code )
{
case TTN_SHOW:
SetWindowPos( tt->hdr.hwndFrom, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE );
break;
case TTN_NEEDTEXTW:
{
LPTOOLTIPTEXTW tt = (LPTOOLTIPTEXTW)lParam;
wchar_t booga[ 81 ] = { 0 };
GetWindowTextW( hwnd, booga, 79 );
booga[ 79 ] = 0;
StringCchCopyW( tt->szText, 80, booga );
tt->lpszText = tt->szText;
return 0;
}
}
}
break;
}
case WM_SETFOCUS:
if ( !config_mw_open )
{
if ( config_pe_open )
SetForegroundWindow( hPLWindow );
else if ( config_eq_open )
SetForegroundWindow( hEQWindow );
// else if (config_mb_open) SetForegroundWindow(hMBWindow);
else if ( config_video_open )
SetForegroundWindow( hVideoWindow );
else
{
EnterCriticalSection( &embedcs );
{
embedWindowState *p = embedwndlist;
while ( p )
{
if ( IsWindowVisible( p->me ) )
{
SetForegroundWindow( p->me );
break;
}
p = p->link;
}
}
LeaveCriticalSection( &embedcs );
}
}
break;
case WM_KILLFOCUS:
{
if ( !config_mw_open )
{
if ( config_pe_open )
SetForegroundWindow( hPLWindow );
else if ( config_eq_open )
SetForegroundWindow( hEQWindow );
// else if (config_mb_open) SetForegroundWindow(hMBWindow);
else if ( config_video_open )
SetForegroundWindow( hVideoWindow );
else
{
EnterCriticalSection( &embedcs );
{
embedWindowState *p = embedwndlist;
while ( p )
{
if ( IsWindowVisible( p->me ) )
{
SetForegroundWindow( p->me );
break;
}
p = p->link;
}
}
LeaveCriticalSection( &embedcs );
}
}
break;
}
case WM_MOUSEWHEEL:
{
// because some people don't like it
if ( config_nomwheel )
break;
int zDelta = GET_WHEEL_DELTA_WPARAM( wParam ), dLines;
// if the delta changes then ignore prior carryover
// hopefully this will go with the expected action.
if ( zDelta < 0 && main_delta_carryover > 0 || zDelta > 0 && main_delta_carryover < 0 )
main_delta_carryover = 0;
// otherwise add on the carryover from the prior message
else
zDelta += main_delta_carryover;
if ( 0 == ( MK_MBUTTON & LOWORD( wParam ) ) )
zDelta *= 2;
dLines = zDelta / WHEEL_DELTA;
main_delta_carryover = zDelta - dLines * WHEEL_DELTA;
if ( 0 != dLines )
{
zDelta = ( dLines > 0 ) ? dLines : -dLines;
if ( 0 != ( MK_MBUTTON & LOWORD( wParam ) ) )
{
if ( dLines >= 0 )
dLines = WINAMP_FFWD5S;
else
dLines = WINAMP_REW5S;
}
else
{
if ( dLines >= 0 )
dLines = WINAMP_VOLUMEUP;
else
dLines = WINAMP_VOLUMEDOWN;
}
while ( zDelta-- )
{
SendMessageW( hwnd, WM_COMMAND, dLines, 0 );
}
}
break;
}
case WM_DWMSENDICONICTHUMBNAIL:
{
int x = HIWORD( lParam );
int y = LOWORD( lParam );
OnIconicThumbnail( x, y );
}
break;
#if 0
case WM_DWMSENDICONICLIVEPREVIEWBITMAP:
{
//MessageBoxA(NULL, "winamp/live", "winamp/live", MB_OK);
OnThumbnailPreview();
}
break;
#endif
case WM_MOVE:
#if 0
if ( (int)LOWORD( lParam ) < 32768 && (int)HIWORD( lParam ) < 32768 )
{
if (/*(int)LOWORD(lParam) != 3000 && */(int)HIWORD( lParam ) != OFFSCREEN_Y_POS )
{
if ( (int)LOWORD( lParam ) != config_wx ||
(int)HIWORD( lParam ) != config_wy )
if ( config_keeponscreen & 1 )
{
config_wx = (int)LOWORD( lParam );
config_wy = (int)HIWORD( lParam );
set_aot( 1 );
}
}
}
#endif
break;
case WM_SETCURSOR:
switch ( HIWORD( lParam ) )
{
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_XBUTTONDOWN:
DisabledWindow_OnMouseClick( hwnd );
break;
}
if ( config_usecursors && !disable_skin_cursors )
{
if ( (HWND)wParam == hMainWindow && HIWORD( lParam ) == WM_MOUSEMOVE )
ui_handlecursor();
return TRUE;
}
else
SetCursor( LoadCursorW( NULL, IDC_ARROW ) );
break;
}
return ( DefWindowProcW( hwnd, uMsg, wParam, lParam ) );
}
static LRESULT Main_OnSysCommand( HWND hwnd, UINT cmd, int x, int y )
{
// char buf[512];
// wsprintf(buf,"got WM_SYSCOMMAND %08x\n",cmd);
// OutputDebugString(buf);
// video
if ( ( ( cmd & 0xfff0 ) == SC_SCREENSAVE || ( cmd & 0xfff0 ) == SC_MONITORPOWER ) && config_video_noss && video_isVideoPlaying() )
{
return -1;
}
if ( !Main_OnCommand( hwnd, cmd, (HWND)x, (UINT)y ) )
FORWARD_WM_SYSCOMMAND( hwnd, cmd, x, y, DefWindowProcW );
return 1;
}
static LRESULT WINAPI browseCheckBoxProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
switch ( uMsg )
{
case WM_INITDIALOG:
{
if ( !( config_rofiob & 2 ) )
CheckDlgButton( hwndDlg, IDC_CHECK1, BST_CHECKED );
break;
}
case WM_COMMAND:
{
if ( LOWORD( wParam ) == IDC_CHECK1 )
{
config_rofiob &= ~2;
if ( !IsDlgButtonChecked( hwndDlg, IDC_CHECK1 ) )
config_rofiob |= 2;
config_write( 0 );
}
break;
}
}
return 0;
}
BOOL CALLBACK browseEnumProc( HWND hwnd, LPARAM lParam )
{
char cl[ 32 ] = { 0 };
GetClassNameA( hwnd, cl, ARRAYSIZE( cl ) );
if ( !lstrcmpiA( cl, WC_TREEVIEWA ) )
{
PostMessageW( hwnd, TVM_ENSUREVISIBLE, 0, (LPARAM)TreeView_GetSelection( hwnd ) );
return FALSE;
}
return TRUE;
}
int CALLBACK WINAPI BrowseCallbackProc( HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData )
{
switch ( uMsg )
{
case BFFM_INITIALIZED:
{
SetWindowTextW( hwnd, getStringW( ( !lpData ? IDS_OPENDIR : IDS_ADD_FOLDER ), NULL, 0 ) );
SendMessageW( hwnd, BFFM_SETSELECTIONW, 1, (LPARAM)config_cwd );
HWND h = FindWindowExW( hwnd, NULL, NULL, L"__foo" );
if ( h )
ShowWindow( h, SW_HIDE );
h = LPCreateDialogW( IDD_BROWSE_RECDLG, hwnd, browseCheckBoxProc );
SetWindowPos( h, 0, 4, 4, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
ShowWindow( h, SW_SHOWNA );
// this is not nice but it fixes the selection not working correctly on all OSes
EnumChildWindows( hwnd, browseEnumProc, 0 );
}
}
return 0;
}
LRESULT sendMlIpc( int msg, WPARAM param )
{
static LRESULT IPC_GETMLWINDOW;
static HWND mlwnd;
if ( !IPC_GETMLWINDOW ) IPC_GETMLWINDOW = wa_register_ipc( ( WPARAM ) & "LibraryGetWnd" );
if ( !mlwnd || (int)mlwnd == 1 )
mlwnd = (HWND)SendMessageW( hMainWindow, WM_WA_IPC, 0, IPC_GETMLWINDOW );
if ( param == 0 && msg == 0 ) return (LRESULT)mlwnd;
if ( IsWindow( mlwnd ) )
return SendMessageW( mlwnd, WM_ML_IPC, param, msg );
return 0;
}
void tealike_crappy_code( unsigned long v[ 2 ], unsigned long k[ 4 ] )
{
unsigned long y = v[ 0 ], z = v[ 1 ], sum = 0, /* set up */
delta = 0x9e3779b9UL, n = 32; /* key schedule constant*/
while ( n-- > 0 )
{
/* basic cycle start */
sum += delta;
y += ( ( z << 4 ) + k[ 0 ] ) ^ ( z + sum ) ^ ( ( z >> 5 ) + k[ 1 ] );
z += ( ( y << 4 ) + k[ 2 ] ) ^ ( y + sum ) ^ ( ( y >> 5 ) + k[ 3 ] ); /* end cycle */
}
v[ 0 ] = y; v[ 1 ] = z;
}
// command line parsing, for IPC or normal modes
// goes to a lot of trouble to look for "'s.
HWND find_otherwinamp( wchar_t *cmdline )
{
int y = 0;
wchar_t buf[ MAX_PATH ] = { 0 };
StringCchPrintfW( buf, MAX_PATH, L"%s_%x_CLASS", szAppName, APP_VERSION_NUM );
again:
g_hEventRunning = CreateEventW( 0, 1, 0, buf );
if ( g_hEventRunning && GetLastError() == ERROR_ALREADY_EXISTS )
{
int x;
CloseHandle( g_hEventRunning );
g_hEventRunning = 0;
// check for window for 4s, then give up
if ( !bNoHwndOther && ( !config_minst || *cmdline ) ) for ( x = 0; x < 40; x++ )
{
HWND lhwnd = NULL;
int failed = 0;
while ( ( lhwnd = FindWindowExW( NULL, lhwnd, szAppName, NULL ) ) )
{
DWORD_PTR vn = 0; //APP_VERSION_NUM
if ( lhwnd == hMainWindow )
continue;
if ( !SendMessageTimeout( lhwnd, WM_WA_IPC, 0, IPC_GETVERSION, SMTO_NORMAL, 5000, &vn ) )
{
failed = 1;
}
else if ( vn == APP_VERSION_NUM ) return lhwnd;
}
if ( failed ) return NULL; // no valid winamp windows, but one that fucked up
Sleep( 100 );
}
if ( y++ < 20 ) goto again;
}
return NULL;
}
// returns 0 if showing/hiding sould be aborted
int Ipc_WindowToggle( INT_PTR which, INT_PTR how )
{
return SendMessageW( hMainWindow, WM_WA_IPC, which, how ? IPC_CB_ONSHOWWND : IPC_CB_ONHIDEWND );
}
//}
#ifdef BENSKI_TEST_WM_PRINTCLIENT
static void PrintWindow( HWND hWnd )
{
HDC hDCMem = CreateCompatibleDC( NULL );
HBITMAP hBmp = NULL;
RECT rect;
GetWindowRect( hWnd, &rect );
{
HDC hDC = GetDC( hWnd );
hBmp = CreateCompatibleBitmap( hDC, rect.right - rect.left, rect.bottom - rect.top );
ReleaseDC( hWnd, hDC );
}
{
HGDIOBJ hOld = SelectObject( hDCMem, hBmp );
SendMessageW( hWnd, WM_PRINT, (WPARAM)hDCMem, PRF_CHILDREN | PRF_CLIENT | PRF_ERASEBKGND | PRF_NONCLIENT | PRF_OWNED );
SelectObject( hDCMem, hOld );
}
DeleteObject( hDCMem );
OpenClipboard( hWnd );
EmptyClipboard();
SetClipboardData( CF_BITMAP, hBmp );
CloseClipboard();
}
#endif