diff options
author | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
---|---|---|
committer | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
commit | 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch) | |
tree | 12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/Winamp/main.cpp | |
parent | 537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff) | |
download | winamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz |
Initial community commit
Diffstat (limited to 'Src/Winamp/main.cpp')
-rw-r--r-- | Src/Winamp/main.cpp | 1892 |
1 files changed, 1892 insertions, 0 deletions
diff --git a/Src/Winamp/main.cpp b/Src/Winamp/main.cpp new file mode 100644 index 00000000..b92dda2d --- /dev/null +++ b/Src/Winamp/main.cpp @@ -0,0 +1,1892 @@ +/** (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( ®istrar, 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
\ No newline at end of file |