941 lines
23 KiB
C++
941 lines
23 KiB
C++
|
/** (c) Nullsoft, Inc. C O N F I D E N T I A L
|
||
|
** Filename: application.cpp
|
||
|
** Project: Winamp 5
|
||
|
** Description: Winamp's implementation of Wasabi's Application API.
|
||
|
** Also includes the main message loop.
|
||
|
** Author: Ben Allison benski@nullsoft.com
|
||
|
** Created:
|
||
|
**/
|
||
|
#include "main.h"
|
||
|
#include "application.h"
|
||
|
#include "../nu/AutoWide.h"
|
||
|
#include "api.h"
|
||
|
#include "../nu/ns_wc.h"
|
||
|
|
||
|
#define WIDEN2(x) L ## x
|
||
|
#define WIDEN(x) WIDEN2(x)
|
||
|
|
||
|
static UINT WINAMP_WM_DIRECT_MOUSE_WHEEL = WM_NULL;
|
||
|
static ATOM DIRECT_MOUSE_WHEEL_CONVERT_TO_MOUSE_WHEEL = 0;
|
||
|
|
||
|
static BOOL DirectMouseWheel_RegisterMessage()
|
||
|
{
|
||
|
WINAMP_WM_DIRECT_MOUSE_WHEEL = RegisterWindowMessageW(L"WINAMP_WM_DIRECT_MOUSE_WHEEL");
|
||
|
if (WM_NULL == WINAMP_WM_DIRECT_MOUSE_WHEEL)
|
||
|
return FALSE;
|
||
|
|
||
|
if (NULL != application)
|
||
|
application->DirectMouseWheel_InitBlackList();
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
IsDirectMouseWheelMessage(const UINT uMsg)
|
||
|
{
|
||
|
if (WM_NULL == WINAMP_WM_DIRECT_MOUSE_WHEEL)
|
||
|
{
|
||
|
if (FALSE == DirectMouseWheel_RegisterMessage())
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return (WINAMP_WM_DIRECT_MOUSE_WHEEL == uMsg);
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
DirectMouseWheel_EnableConvertToMouseWheel(HWND hwnd, BOOL enable)
|
||
|
{
|
||
|
if (FALSE != enable)
|
||
|
{
|
||
|
if (0 == DIRECT_MOUSE_WHEEL_CONVERT_TO_MOUSE_WHEEL)
|
||
|
{
|
||
|
DIRECT_MOUSE_WHEEL_CONVERT_TO_MOUSE_WHEEL = GlobalAddAtomW(L"DIRECT_MOUSE_WHEEL_CONVERT_TO_MOUSE_WHEEL");
|
||
|
if (0 == DIRECT_MOUSE_WHEEL_CONVERT_TO_MOUSE_WHEEL)
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (0 == SetPropW(hwnd, (const wchar_t*)MAKEINTATOM(DIRECT_MOUSE_WHEEL_CONVERT_TO_MOUSE_WHEEL), (HANDLE)1))
|
||
|
return FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (0 != DIRECT_MOUSE_WHEEL_CONVERT_TO_MOUSE_WHEEL)
|
||
|
RemovePropW(hwnd, (const wchar_t*)MAKEINTATOM(DIRECT_MOUSE_WHEEL_CONVERT_TO_MOUSE_WHEEL));
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
DirectMouseWheel_IsConvertToMouseWheelEnabled(HWND hwnd)
|
||
|
{
|
||
|
return(0 != DIRECT_MOUSE_WHEEL_CONVERT_TO_MOUSE_WHEEL &&
|
||
|
NULL != GetPropW(hwnd, (const wchar_t*)MAKEINTATOM(DIRECT_MOUSE_WHEEL_CONVERT_TO_MOUSE_WHEEL)));
|
||
|
}
|
||
|
|
||
|
Application::Application()
|
||
|
: shuttingdown(0), activeDialog(NULL), machineID(GUID_NULL), userID(GUID_NULL), sessionID(GUID_NULL),
|
||
|
threadStorageIndex(TLS_OUT_OF_INDEXES), messageHook(NULL), disableMessageHook(false)
|
||
|
{
|
||
|
tlsIndex = TlsAlloc();
|
||
|
}
|
||
|
|
||
|
Application::~Application()
|
||
|
{
|
||
|
if (NULL != messageHook)
|
||
|
{
|
||
|
UnhookWindowsHookEx(messageHook);
|
||
|
messageHook = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const wchar_t *Application::main_getAppName()
|
||
|
{
|
||
|
return WIDEN(APP_NAME);
|
||
|
}
|
||
|
|
||
|
const wchar_t *Application::main_getVersionString()
|
||
|
{
|
||
|
return WIDEN(APP_NAME) L" " WIDEN(APP_VERSION_STRING);
|
||
|
}
|
||
|
|
||
|
const wchar_t *Application::main_getVersionNumString()
|
||
|
{
|
||
|
return WIDEN(APP_VERSION);
|
||
|
}
|
||
|
|
||
|
unsigned int Application::main_getBuildNumber()
|
||
|
{
|
||
|
return BUILD_NUMBER;
|
||
|
}
|
||
|
|
||
|
// a guid for our app : {4BE592C7-6937-426a-A388-ACF0EBC88E93}
|
||
|
static const GUID WinampGUID =
|
||
|
{
|
||
|
0x4be592c7, 0x6937, 0x426a, { 0xa3, 0x88, 0xac, 0xf0, 0xeb, 0xc8, 0x8e, 0x93 }
|
||
|
};
|
||
|
|
||
|
GUID Application::main_getGUID()
|
||
|
{
|
||
|
return WinampGUID;
|
||
|
}
|
||
|
|
||
|
HANDLE Application::main_getMainThreadHandle()
|
||
|
{
|
||
|
if (hMainThread == 0)
|
||
|
return (HANDLE)0;
|
||
|
HANDLE h = (HANDLE)0;
|
||
|
DuplicateHandle(GetCurrentProcess(), hMainThread, GetCurrentProcess(), &h, 0, FALSE, DUPLICATE_SAME_ACCESS);
|
||
|
return h;
|
||
|
}
|
||
|
|
||
|
HINSTANCE Application::main_gethInstance()
|
||
|
{
|
||
|
return hMainInstance;
|
||
|
}
|
||
|
|
||
|
const wchar_t *Application::main_getCommandLine()
|
||
|
{
|
||
|
return GetCommandLineW();
|
||
|
}
|
||
|
|
||
|
void Application::main_shutdown(int deferred)
|
||
|
{
|
||
|
|
||
|
int x = static_cast<int>(SendMessageW(hMainWindow, WM_WA_IPC, 0, IPC_IS_EXIT_ENABLED));
|
||
|
|
||
|
if (!x)
|
||
|
return;
|
||
|
|
||
|
shuttingdown = 1;
|
||
|
|
||
|
SendMessageW(hMainWindow, WM_CLOSE, 0, 0);
|
||
|
}
|
||
|
|
||
|
void Application::main_cancelShutdown()
|
||
|
{
|
||
|
shuttingdown = 0;
|
||
|
}
|
||
|
|
||
|
int Application::main_isShuttingDown()
|
||
|
{
|
||
|
return shuttingdown;
|
||
|
}
|
||
|
|
||
|
const wchar_t *Application::path_getAppPath()
|
||
|
{
|
||
|
return PROGDIR;
|
||
|
}
|
||
|
|
||
|
const wchar_t *Application::path_getUserSettingsPath()
|
||
|
{
|
||
|
return CONFIGDIR;
|
||
|
}
|
||
|
|
||
|
const wchar_t *Application::path_getSkinSettingsPath()
|
||
|
{
|
||
|
return SKINDIR;
|
||
|
}
|
||
|
|
||
|
int Application::app_getInitCount()
|
||
|
{
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
void Application::app_addMessageProcessor(api_messageprocessor *processor)
|
||
|
{
|
||
|
messageProcessors.push_back(processor);
|
||
|
}
|
||
|
|
||
|
void Application::app_removeMessageProcessor(api_messageprocessor *processor)
|
||
|
{
|
||
|
//messageProcessors.eraseAll(processor);
|
||
|
auto it = messageProcessors.begin();
|
||
|
while (it != messageProcessors.end())
|
||
|
{
|
||
|
if (*it != processor)
|
||
|
{
|
||
|
it++;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
it = messageProcessors.erase(it);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Application::app_addModelessDialog(HWND hwnd)
|
||
|
{
|
||
|
OutputDebugStringA( "[Error] 'app_addModelessDialog' removed! Use 'ActiveDialog_Register' instead!\r\n" );
|
||
|
}
|
||
|
|
||
|
void Application::app_removeModelessDialog(HWND hwnd)
|
||
|
{
|
||
|
OutputDebugStringA( "[Error] 'app_removeModelessDialog' removed!Use 'ActiveDialog_Unregister' instead!\r\n" );
|
||
|
}
|
||
|
|
||
|
void Application::app_addAccelerators(HWND hwnd, HACCEL *phAccel, INT cAccel, UINT translateMode)
|
||
|
{
|
||
|
AccelMap::iterator accelIterator;
|
||
|
ACCELNODE *pList;
|
||
|
|
||
|
if (accelerators.size() > 0)
|
||
|
{
|
||
|
accelIterator = accelerators.end();
|
||
|
do
|
||
|
{
|
||
|
accelIterator--;
|
||
|
if (!IsWindow(accelIterator->first))
|
||
|
{
|
||
|
//app_removeAccelerators(accelIterator->first);
|
||
|
ACCELNODE* pList, * pNode;
|
||
|
pList = accelIterator->second;
|
||
|
while (pList)
|
||
|
{
|
||
|
pNode = pList;
|
||
|
pList = (pList->pNext) ? pList->pNext : NULL;
|
||
|
free(pNode);
|
||
|
}
|
||
|
accelIterator = accelerators.erase(accelIterator);
|
||
|
}
|
||
|
} while (accelIterator != accelerators.begin() && accelIterator != accelerators.end());
|
||
|
}
|
||
|
|
||
|
if (!IsWindow(hwnd) || !phAccel || cAccel <= 0) return;
|
||
|
|
||
|
accelIterator = accelerators.find(hwnd);
|
||
|
if(accelIterator != accelerators.end())
|
||
|
pList = accelIterator->second;
|
||
|
else
|
||
|
{
|
||
|
pList = (ACCELNODE*)calloc(1, sizeof(ACCELNODE));
|
||
|
if(pList)
|
||
|
{
|
||
|
accelerators.insert({hwnd, pList});
|
||
|
}
|
||
|
}
|
||
|
if (!pList) return;
|
||
|
while (pList->pNext) pList = pList->pNext;
|
||
|
|
||
|
while(cAccel--)
|
||
|
{
|
||
|
if (*phAccel)
|
||
|
{
|
||
|
ACCELNODE *pNode;
|
||
|
if (pList->hAccel)
|
||
|
{
|
||
|
pNode = (ACCELNODE*)calloc(1, sizeof(ACCELNODE));
|
||
|
pNode->pNext = NULL;
|
||
|
pList->pNext = pNode;
|
||
|
pList = pNode;
|
||
|
}
|
||
|
else pNode = pList;
|
||
|
|
||
|
pNode->hAccel = *phAccel;
|
||
|
pNode->translateMode = translateMode;
|
||
|
|
||
|
}
|
||
|
phAccel++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Application::app_removeAccelerators(HWND hwnd)
|
||
|
{
|
||
|
AccelMap::iterator iter = accelerators.find(hwnd);
|
||
|
if(iter == accelerators.end())
|
||
|
return;
|
||
|
|
||
|
ACCELNODE *pList, *pNode;
|
||
|
pList = iter->second;
|
||
|
while(pList)
|
||
|
{
|
||
|
pNode = pList;
|
||
|
pList = (pList->pNext) ? pList->pNext : NULL;
|
||
|
free(pNode);
|
||
|
}
|
||
|
accelerators.erase(hwnd);
|
||
|
}
|
||
|
|
||
|
int Application::app_getAccelerators(HWND hwnd, HACCEL *phAccel, INT cchAccelMax, BOOL bGlobal)
|
||
|
{
|
||
|
|
||
|
if (!hwnd || 0 == accelerators.size()) return 0;
|
||
|
if ((!phAccel && cchAccelMax) || (phAccel && !cchAccelMax)) return 0;
|
||
|
|
||
|
AccelMap::iterator accelIterator = accelerators.end();
|
||
|
INT count = 0;
|
||
|
|
||
|
do
|
||
|
{
|
||
|
accelIterator--;
|
||
|
for (ACCELNODE *pNode = accelIterator->second; NULL != pNode; pNode = pNode->pNext)
|
||
|
{
|
||
|
if (accelIterator->first == hwnd ||
|
||
|
(bGlobal && (TRANSLATE_MODE_GLOBAL == pNode->translateMode ||
|
||
|
(TRANSLATE_MODE_CHILD == pNode->translateMode && IsChild(accelIterator->first, hwnd)))))
|
||
|
{
|
||
|
if (phAccel && cchAccelMax)
|
||
|
{
|
||
|
*phAccel = pNode->hAccel;
|
||
|
phAccel++;
|
||
|
cchAccelMax--;
|
||
|
}
|
||
|
count++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
while (accelIterator != accelerators.begin() && (!phAccel || cchAccelMax));
|
||
|
|
||
|
return count;
|
||
|
}
|
||
|
|
||
|
void Application::app_registerGlobalWindow(HWND hwnd)
|
||
|
{
|
||
|
for (std::vector<HWND>::const_iterator e = globalWindows.begin(); e != globalWindows.end(); e++)
|
||
|
{
|
||
|
if (*e == hwnd) return;
|
||
|
}
|
||
|
globalWindows.push_back(hwnd);
|
||
|
}
|
||
|
|
||
|
void Application::app_unregisterGlobalWindow(HWND hwnd)
|
||
|
{
|
||
|
for (std::vector<HWND>::iterator e = globalWindows.begin(); e != globalWindows.end(); e++)
|
||
|
{
|
||
|
if (*e == hwnd)
|
||
|
{
|
||
|
globalWindows.erase(e);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
bool Application::FilterMessage(MSG *msg) // returns 1 if you should Dispatch the message, will handle TranslateMessage for you
|
||
|
{
|
||
|
if (msg->hwnd != NULL && msg->hwnd != hMainWindow && msg->hwnd != hEQWindow // && msg.hwnd != hMBWindow
|
||
|
&& msg->hwnd != hPLWindow && msg->hwnd != hVideoWindow)
|
||
|
{
|
||
|
HWND hWndParent = NULL;
|
||
|
HWND temphwnd = msg->hwnd;
|
||
|
if (GetClassLong(temphwnd, GCW_ATOM) == (INT)32770)
|
||
|
hWndParent = temphwnd;
|
||
|
|
||
|
/*while (*/temphwnd = GetParent(temphwnd)/*)*/ ;
|
||
|
{
|
||
|
if (GetClassLong(temphwnd, GCW_ATOM) == (INT)32770)
|
||
|
hWndParent = temphwnd;
|
||
|
}
|
||
|
|
||
|
if (NULL != hWndParent)
|
||
|
{
|
||
|
BOOL processed;
|
||
|
|
||
|
disableMessageHook = true;
|
||
|
processed = IsDialogMessageW(hWndParent, msg);
|
||
|
disableMessageHook = false;
|
||
|
|
||
|
if (FALSE != processed)
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
//if (msg->message == WM_KEYDOWN || msg->message == WM_SYSKEYDOWN ||
|
||
|
// msg->message == WM_KEYUP || msg->message == WM_SYSKEYUP)
|
||
|
//{
|
||
|
//if (IsChild(hMBWindow,msg.hwnd) && TranslateAccelerator(hMBWindow,hAccel[3],&msg)) continue;
|
||
|
TranslateMessage(msg);
|
||
|
//}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
bool Application::isGlobalWindow(HWND hwnd)
|
||
|
{
|
||
|
for (std::vector<HWND>::const_iterator e = globalWindows.begin(); e != globalWindows.end(); e++)
|
||
|
{
|
||
|
if (*e == hwnd || IsChild(*e, hwnd)) return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool Application::app_translateAccelerators(MSG *msg)
|
||
|
{
|
||
|
if (accelerators.size() > 0)
|
||
|
{
|
||
|
AccelMap::iterator accelIterator = accelerators.end();
|
||
|
do
|
||
|
{
|
||
|
accelIterator--;
|
||
|
for (ACCELNODE *pNode = accelIterator->second; NULL != pNode; pNode = pNode->pNext)
|
||
|
{
|
||
|
if (((TRANSLATE_MODE_GLOBAL == pNode->translateMode && isGlobalWindow(msg->hwnd)) ||
|
||
|
accelIterator->first == msg->hwnd ||
|
||
|
(TRANSLATE_MODE_CHILD == pNode->translateMode && IsChild(accelIterator->first, msg->hwnd))) &&
|
||
|
TranslateAcceleratorW(accelIterator->first, pNode->hAccel, msg))
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
while (accelIterator != accelerators.begin());
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
Application::DirectMouseWheel_RegisterSkipClass(ATOM klass)
|
||
|
{
|
||
|
size_t index;
|
||
|
|
||
|
if (klass < 0xC000)
|
||
|
return false;
|
||
|
|
||
|
index = directMouseWheelBlackList.size();
|
||
|
while(index--)
|
||
|
{
|
||
|
if (directMouseWheelBlackList[index] == klass)
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
directMouseWheelBlackList.push_back(klass);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
Application::DirectMouseWheel_UnregisterSkipClass(ATOM klass)
|
||
|
{
|
||
|
size_t index;
|
||
|
|
||
|
if (klass < 0xC000)
|
||
|
return false;
|
||
|
|
||
|
index = directMouseWheelBlackList.size();
|
||
|
while(index--)
|
||
|
{
|
||
|
if (directMouseWheelBlackList[index] == klass)
|
||
|
{
|
||
|
directMouseWheelBlackList.erase(directMouseWheelBlackList.begin() + index);
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
Application::DirectMouseWheel_EnableConvertToMouseWheel(HWND hwnd, BOOL enable)
|
||
|
{
|
||
|
return (0 != ::DirectMouseWheel_EnableConvertToMouseWheel(hwnd, enable));
|
||
|
}
|
||
|
|
||
|
void
|
||
|
Application::DirectMouseWheel_InitBlackList()
|
||
|
{
|
||
|
size_t index;
|
||
|
WNDCLASSW klassInfo;
|
||
|
ATOM klassAtom;
|
||
|
|
||
|
const static LPCWSTR defaultBlackListNames[] =
|
||
|
{
|
||
|
L"msctls_trackbar32",
|
||
|
L"msctls_updown32",
|
||
|
L"SysHeader32",
|
||
|
};
|
||
|
|
||
|
const static ATOM defaultBlackListAtoms[] =
|
||
|
{
|
||
|
0xC017, // button
|
||
|
0xC018, // edit
|
||
|
0xC019, // static
|
||
|
0xC01C, // combobox
|
||
|
};
|
||
|
|
||
|
for (index = 0; index < ARRAYSIZE(defaultBlackListAtoms); index++)
|
||
|
{
|
||
|
directMouseWheelBlackList.push_back(defaultBlackListAtoms[index]);
|
||
|
}
|
||
|
|
||
|
for (index = 0; index < ARRAYSIZE(defaultBlackListNames); index++)
|
||
|
{
|
||
|
klassAtom = (ATOM)GetClassInfoW(NULL, defaultBlackListNames[index], &klassInfo);
|
||
|
if (0 != klassAtom)
|
||
|
directMouseWheelBlackList.push_back(klassAtom);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
Application::DirectMouseWheel_ProccessMessage(MSG *msg)
|
||
|
{
|
||
|
HWND targetWindow;
|
||
|
ATOM targetAtom;
|
||
|
DWORD targetProcessId;
|
||
|
POINT mousePoint;
|
||
|
size_t index, listSize;
|
||
|
|
||
|
if (msg->message != WM_MOUSEWHEEL)
|
||
|
return false;
|
||
|
|
||
|
if (WM_NULL == WINAMP_WM_DIRECT_MOUSE_WHEEL)
|
||
|
{
|
||
|
if (FALSE == DirectMouseWheel_RegisterMessage())
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
POINTSTOPOINT(mousePoint, msg->lParam);
|
||
|
targetWindow = WindowFromPoint(mousePoint);
|
||
|
|
||
|
if (NULL == targetWindow || targetWindow == msg->hwnd)
|
||
|
return false;
|
||
|
|
||
|
GetWindowThreadProcessId(targetWindow, &targetProcessId);
|
||
|
if (targetProcessId != GetCurrentProcessId())
|
||
|
return false;
|
||
|
|
||
|
if (FALSE == IsWindowEnabled(targetWindow))
|
||
|
return false;
|
||
|
|
||
|
listSize = directMouseWheelBlackList.size();
|
||
|
index = 0;
|
||
|
|
||
|
while(index != listSize)
|
||
|
{
|
||
|
targetAtom = (ATOM)GetClassLongPtrW(targetWindow, GCW_ATOM);
|
||
|
for(index = 0; index < listSize; index++)
|
||
|
{
|
||
|
if (targetAtom == directMouseWheelBlackList[index])
|
||
|
{
|
||
|
targetWindow = GetAncestor(targetWindow, GA_PARENT);
|
||
|
if (NULL == targetWindow || targetWindow == msg->hwnd)
|
||
|
return false;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (FALSE != DirectMouseWheel_IsConvertToMouseWheelEnabled(targetWindow))
|
||
|
{
|
||
|
SendMessageW(targetWindow, WM_MOUSEWHEEL, msg->wParam, msg->lParam);
|
||
|
return true;
|
||
|
}
|
||
|
else if (0 != SendMessageW(targetWindow, WINAMP_WM_DIRECT_MOUSE_WHEEL, msg->wParam, msg->lParam))
|
||
|
return true;
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
HWND ActiveChildWindowFromPoint( HWND hwnd, POINTS cursor_s, const int *controls, size_t controlsCount )
|
||
|
{
|
||
|
POINT pt;
|
||
|
RECT controlRect;
|
||
|
HWND controlWindow;
|
||
|
|
||
|
POINTSTOPOINT( pt, cursor_s );
|
||
|
|
||
|
while ( controlsCount-- )
|
||
|
{
|
||
|
controlWindow = GetDlgItem( hwnd, controls[ controlsCount ] );
|
||
|
|
||
|
if ( controlWindow != NULL && GetClientRect( controlWindow, &controlRect ) != FALSE )
|
||
|
{
|
||
|
MapWindowPoints( controlWindow, HWND_DESKTOP, (POINT *) &controlRect, 2 );
|
||
|
|
||
|
if ( PtInRect( &controlRect, pt ) != FALSE )
|
||
|
{
|
||
|
unsigned long windowStyle = (unsigned long) GetWindowLongPtrW( controlWindow, GWL_STYLE );
|
||
|
|
||
|
if ( ( ( WS_VISIBLE | WS_DISABLED ) & windowStyle ) == WS_VISIBLE )
|
||
|
return controlWindow;
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
BOOL DirectMouseWheel_ProcessDialogMessage(HWND hwnd, unsigned int uMsg, WPARAM wParam, LPARAM lParam, const int controls[], int controlslen)
|
||
|
{
|
||
|
if (FALSE != ::IsDirectMouseWheelMessage(uMsg))
|
||
|
{
|
||
|
HWND targetWindow = ::ActiveChildWindowFromPoint(hwnd, MAKEPOINTS(lParam), controls, controlslen);
|
||
|
if (NULL != targetWindow)
|
||
|
{
|
||
|
SendMessageW(targetWindow, WM_MOUSEWHEEL, wParam, lParam);
|
||
|
SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, (long)TRUE);
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
BOOL Application::DirectMouseWheel_ProcessDialogMessage(HWND hwnd, unsigned int uMsg, WPARAM wParam, LPARAM lParam, const int controls[], int controlslen)
|
||
|
{
|
||
|
return ::DirectMouseWheel_ProcessDialogMessage(hwnd, uMsg, wParam, lParam, controls, controlslen);
|
||
|
}
|
||
|
|
||
|
void Application::ActiveDialog_Register(HWND hwnd)
|
||
|
{
|
||
|
activeDialog = hwnd;
|
||
|
}
|
||
|
|
||
|
void Application::ActiveDialog_Unregister(HWND hwnd)
|
||
|
{
|
||
|
if (hwnd == activeDialog)
|
||
|
activeDialog = NULL;
|
||
|
}
|
||
|
|
||
|
HWND Application::ActiveDialog_Get()
|
||
|
{
|
||
|
return activeDialog;
|
||
|
}
|
||
|
|
||
|
/* Plugins can register a 'Message Processor' to tap into the main message loop
|
||
|
for some purposes (Dialog message handling, ActiveX/ATL/COM, wxWidgets)
|
||
|
this is the only way to make sure all messages are processed correctly
|
||
|
@see api_application::app_addMessageProcessor() and api_messageprocessor.h
|
||
|
*/
|
||
|
|
||
|
bool Application::ProcessMessageLight( MSG *msg )
|
||
|
{
|
||
|
/* messageProcessors is the list of registered Message Processors */
|
||
|
for ( api_messageprocessor *processor : messageProcessors )
|
||
|
{
|
||
|
disableMessageHook = true;
|
||
|
|
||
|
if ( processor->ProcessMessage( msg ) ) // it'll return true if it wants to eat the message
|
||
|
{
|
||
|
disableMessageHook = false;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
disableMessageHook = false;
|
||
|
|
||
|
if ( false != DirectMouseWheel_ProccessMessage( msg ) )
|
||
|
return true;
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool Application::ProcessMessage( MSG *msg )
|
||
|
{
|
||
|
if ( ProcessMessageLight( msg ) != false )
|
||
|
return true;
|
||
|
|
||
|
if ( ( msg->message == WM_KEYDOWN || msg->message == WM_SYSKEYDOWN ) && app_translateAccelerators( msg ) )
|
||
|
return true;
|
||
|
|
||
|
|
||
|
if ( activeDialog != NULL )
|
||
|
{
|
||
|
disableMessageHook = true;
|
||
|
|
||
|
if ( IsDialogMessageW( activeDialog, msg ) != FALSE )
|
||
|
{
|
||
|
disableMessageHook = false;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
disableMessageHook = false;
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
intptr_t Application::app_messageLoopStep()
|
||
|
{
|
||
|
MSG msg;
|
||
|
|
||
|
if (PeekMessageW(&msg, NULL, 0, 0, TRUE))
|
||
|
{
|
||
|
if (msg.message == WM_QUIT)
|
||
|
{
|
||
|
PostQuitMessage((int)msg.wParam);
|
||
|
return msg.wParam ; // abandoned due to WM_QUIT
|
||
|
}
|
||
|
|
||
|
if (!ProcessMessage(&msg) && !FilterMessage(&msg))
|
||
|
DispatchMessageW(&msg);
|
||
|
|
||
|
if (WM_NCDESTROY == msg.message)
|
||
|
DirectMouseWheel_EnableConvertToMouseWheel(msg.hwnd, FALSE);
|
||
|
|
||
|
return msg.wParam;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
LRESULT CALLBACK Application::MessageHookProc( INT code, WPARAM wParam, LPARAM lParam )
|
||
|
{
|
||
|
if ( application == NULL || application->messageHook == NULL )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if ( application->disableMessageHook == false )
|
||
|
{
|
||
|
switch ( code )
|
||
|
{
|
||
|
case MSGF_DIALOGBOX:
|
||
|
case MSGF_MESSAGEBOX:
|
||
|
if ( false != application->ProcessMessageLight( (MSG *) lParam ) )
|
||
|
return 1;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
application->disableMessageHook = false;
|
||
|
|
||
|
return CallNextHookEx( application->messageHook, code, wParam, lParam );
|
||
|
}
|
||
|
|
||
|
WPARAM Application::MessageLoop()
|
||
|
{
|
||
|
if ( messageHook == NULL )
|
||
|
messageHook = SetWindowsHookEx( WH_MSGFILTER, MessageHookProc, NULL, GetCurrentThreadId() );
|
||
|
|
||
|
for ( ;;)
|
||
|
{
|
||
|
DWORD dwStatus = MsgWaitForMultipleObjectsEx( 0, NULL, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE | MWMO_INPUTAVAILABLE );
|
||
|
|
||
|
if ( dwStatus == WAIT_OBJECT_0 )
|
||
|
{
|
||
|
MSG msg;
|
||
|
while ( PeekMessageW( &msg, NULL, 0, 0, PM_REMOVE ) )
|
||
|
{
|
||
|
if ( msg.message == WM_QUIT )
|
||
|
return msg.wParam;
|
||
|
|
||
|
if ( !ProcessMessage( &msg ) && !FilterMessage( &msg ) )
|
||
|
DispatchMessageW( &msg );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
WPARAM WinampMessageLoop()
|
||
|
{
|
||
|
return WASABI_API_APP->MessageLoop();
|
||
|
}
|
||
|
|
||
|
const wchar_t *Application::path_getWorkingPath()
|
||
|
{
|
||
|
return config_cwd;
|
||
|
}
|
||
|
|
||
|
void Application::path_setWorkingPath(const wchar_t *newPath)
|
||
|
{
|
||
|
StringCchCopyW(config_cwd, MAX_PATH, newPath);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
int Application::GetMachineID(GUID *id)
|
||
|
{
|
||
|
// TODO: stuff this in the registry
|
||
|
if (machineID == GUID_NULL)
|
||
|
{
|
||
|
if (!GetPrivateProfileStruct(app_name, "mid", (LPVOID)&machineID, sizeof(machineID), INI_FILE) || machineID == GUID_NULL)
|
||
|
{
|
||
|
UuidCreate(&machineID);
|
||
|
WritePrivateProfileStruct(app_name, "mid", (LPVOID)&machineID, sizeof(machineID), INI_FILE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
*id = machineID;
|
||
|
return API_APPLICATION_SUCCESS;
|
||
|
}
|
||
|
*/
|
||
|
int Application::GetUserID(GUID *id)
|
||
|
{
|
||
|
if (userID == GUID_NULL)
|
||
|
{
|
||
|
config_uid_ft = (char)GetPrivateProfileIntW(L"Winamp", L"uid_ft", 0, INI_FILE);
|
||
|
|
||
|
wchar_t uid_str[512] = {0};
|
||
|
if (!GetPrivateProfileStructA(app_name, "uid", (LPVOID)&userID, sizeof(userID), INI_FILEA) || userID == GUID_NULL)
|
||
|
{
|
||
|
// attempt to restore the client uid after an uninstall, lost config file, etc
|
||
|
readwrite_client_uid(0, uid_str);
|
||
|
if (uid_str[0])
|
||
|
{
|
||
|
WritePrivateProfileStringW(AutoWide(app_name), L"uid", uid_str, INI_FILE);
|
||
|
}
|
||
|
|
||
|
if (!GetPrivateProfileStructA(app_name, "uid", (LPVOID)&userID, sizeof(userID), INI_FILEA) || userID == GUID_NULL)
|
||
|
{
|
||
|
UuidCreate(&userID);
|
||
|
WritePrivateProfileStructA(app_name, "uid", (LPVOID)&userID, sizeof(userID), INI_FILEA);
|
||
|
GetPrivateProfileStringW(AutoWide(app_name), L"uid", L"", uid_str, ARRAYSIZE(uid_str), INI_FILE);
|
||
|
readwrite_client_uid(1, uid_str);
|
||
|
// if done then no need to re-do it at a later point
|
||
|
config_uid_ft = 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// and just to make sure, if this is like a new run then we'll need to force into the registry
|
||
|
if (!config_uid_ft)
|
||
|
{
|
||
|
config_uid_ft = 1;
|
||
|
GetPrivateProfileStringW(AutoWide(app_name), L"uid", L"", uid_str, ARRAYSIZE(uid_str), INI_FILE);
|
||
|
readwrite_client_uid(1, uid_str);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
*id = userID;
|
||
|
|
||
|
return API_APPLICATION_SUCCESS;
|
||
|
}
|
||
|
|
||
|
int Application::GetSessionID(GUID *id)
|
||
|
{
|
||
|
if (sessionID == GUID_NULL)
|
||
|
UuidCreate(&sessionID);
|
||
|
|
||
|
*id = sessionID;
|
||
|
return API_APPLICATION_SUCCESS;
|
||
|
}
|
||
|
|
||
|
size_t Application::AllocateThreadStorage()
|
||
|
{
|
||
|
return (size_t)InterlockedIncrement(&threadStorageIndex);
|
||
|
}
|
||
|
|
||
|
void *Application::GetThreadStorage(size_t index)
|
||
|
{
|
||
|
std::vector<void*> *ptrlist = (std::vector<void*> *)TlsGetValue(tlsIndex);
|
||
|
if (!ptrlist)
|
||
|
return 0;
|
||
|
|
||
|
if ((index+1) > ptrlist->size())
|
||
|
return 0;
|
||
|
|
||
|
return ptrlist->at(index);
|
||
|
}
|
||
|
|
||
|
void Application::SetThreadStorage(size_t index, void *value)
|
||
|
{
|
||
|
std::vector<void*> *ptrlist = (std::vector<void*> *)TlsGetValue(tlsIndex);
|
||
|
if (!ptrlist)
|
||
|
{
|
||
|
ptrlist = new std::vector<void*>;
|
||
|
TlsSetValue(tlsIndex, ptrlist);
|
||
|
}
|
||
|
size_t ptrlist_size = ptrlist->size();
|
||
|
if ((index+1) > ptrlist_size)
|
||
|
{
|
||
|
ptrlist->reserve(index+1);
|
||
|
for (size_t i=ptrlist_size;i<=index;i++)
|
||
|
{
|
||
|
ptrlist->push_back(0);
|
||
|
}
|
||
|
}
|
||
|
ptrlist->at(index) = value;
|
||
|
}
|
||
|
|
||
|
const wchar_t *Application::getATFString()
|
||
|
{
|
||
|
return config_titlefmt;
|
||
|
}
|
||
|
|
||
|
int Application::getScaleX(int x)
|
||
|
{
|
||
|
return ScaleX(x);
|
||
|
}
|
||
|
|
||
|
int Application::getScaleY(int y)
|
||
|
{
|
||
|
return ScaleY(y);
|
||
|
}
|
||
|
|
||
|
#define CBCLASS Application
|
||
|
START_DISPATCH;
|
||
|
CB(API_APPLICATION_MAIN_GETAPPNAME, main_getAppName)
|
||
|
CB(API_APPLICATION_MAIN_GETVERSIONSTRING, main_getVersionString)
|
||
|
CB(API_APPLICATION_MAIN_GETVERSIONSTRING2, main_getVersionNumString)
|
||
|
CB(API_APPLICATION_MAIN_GETBUILDNUMBER, main_getBuildNumber)
|
||
|
CB(API_APPLICATION_MAIN_GETGUID, main_getGUID)
|
||
|
CB(API_APPLICATION_MAIN_GETMAINTHREADHANDLE, main_getMainThreadHandle)
|
||
|
CB(API_APPLICATION_MAIN_GETHINSTANCE, main_gethInstance)
|
||
|
CB(API_APPLICATION_MAIN_GETCOMMANDLINE, main_getCommandLine)
|
||
|
VCB(API_APPLICATION_MAIN_SHUTDOWN, main_shutdown)
|
||
|
VCB(API_APPLICATION_MAIN_CANCELSHUTDOWN, main_cancelShutdown)
|
||
|
CB(API_APPLICATION_MAIN_ISSHUTTINGDOWN, main_isShuttingDown)
|
||
|
CB(API_APPLICATION_PATH_GETAPPPATH, path_getAppPath)
|
||
|
CB(API_APPLICATION_PATH_GETUSERSETTINGSPATH, path_getUserSettingsPath)
|
||
|
CB(API_APPLICATION_PATH_GETSKINSETTINGSPATH, path_getSkinSettingsPath)
|
||
|
CB(API_APPLICATION_APP_GETINITCOUNT, app_getInitCount)
|
||
|
CB(API_APPLICATION_APP_MESSAGELOOPSTEP, app_messageLoopStep)
|
||
|
VCB(API_APPLICATION_APP_ADDMESSAGEPROCESSOR, app_addMessageProcessor)
|
||
|
VCB(API_APPLICATION_APP_REMOVEMESSAGEPROCESSOR, app_removeMessageProcessor)
|
||
|
VCB(API_APPLICATION_APP_ADDMODELESSDIALOG, app_addModelessDialog)
|
||
|
VCB(API_APPLICATION_APP_REMOVEMODELESSDIALOG, app_removeModelessDialog)
|
||
|
VCB(API_APPLICATION_APP_ADDACCELERATORS, app_addAccelerators)
|
||
|
VCB(API_APPLICATION_APP_REMOVEACCELERATORS, app_removeAccelerators)
|
||
|
CB(API_APPLICATION_APP_TRANSLATEACCELERATORS, app_translateAccelerators);
|
||
|
CB(API_APPLICATION_APP_GETACCELERATORS, app_getAccelerators);
|
||
|
VCB(API_APPLICATION_APP_REGISTERGLOBALWINDOW, app_registerGlobalWindow);
|
||
|
VCB(API_APPLICATION_APP_UNREGISTERGLOBALWINDOW, app_unregisterGlobalWindow);
|
||
|
CB(API_APPLICATION_PATH_GETWORKINGPATH, path_getWorkingPath);
|
||
|
VCB(API_APPLICATION_PATH_SETWORKINGPATH, path_setWorkingPath);
|
||
|
CB(API_APPLICATION_DIRECTMOUSEWHEEL_REGISTERSKIPCLASS, DirectMouseWheel_RegisterSkipClass);
|
||
|
CB(API_APPLICATION_DIRECTMOUSEWHEEL_UNREGISTERSKIPCLASS, DirectMouseWheel_UnregisterSkipClass);
|
||
|
CB(API_APPLICATION_DIRECTMOUSEWHEEL_ENABLECONVERTTOMOUSEWHEEL, DirectMouseWheel_EnableConvertToMouseWheel);
|
||
|
CB(API_APPLICATION_DIRECTMOUSEWHEEL_PROCESSDIALOGMESSAGE, DirectMouseWheel_ProcessDialogMessage);
|
||
|
VCB(API_APPLICATION_ACTIVEDIALOG_REGISTER, ActiveDialog_Register);
|
||
|
VCB(API_APPLICATION_ACTIVEDIALOG_UNREGISTER, ActiveDialog_Unregister);
|
||
|
CB(API_APPLICATION_ACTIVEDIALOG_GET, ActiveDialog_Get);
|
||
|
/*
|
||
|
CB(API_APPLICATION_GETMACHINEID, GetMachineID);
|
||
|
*/
|
||
|
CB(API_APPLICATION_GETUSERID, GetUserID);
|
||
|
CB(API_APPLICATION_GETSESSIONID, GetSessionID);
|
||
|
CB(API_APPLICATION_ALLOCATETHREADSTORAGE, AllocateThreadStorage);
|
||
|
CB(API_APPLICATION_GETTHREADSTORAGE, GetThreadStorage);
|
||
|
VCB(API_APPLICATION_SETTHREADSTORAGE, SetThreadStorage);
|
||
|
CB(API_APPLICATION_GETATFSTRING, getATFString);
|
||
|
CB(API_APPLICATION_GETSCALEX, getScaleX);
|
||
|
CB(API_APPLICATION_GETSCALEY, getScaleY);
|
||
|
END_DISPATCH;
|
||
|
#undef CBCLASS
|