aboutsummaryrefslogtreecommitdiff
path: root/Src/Winamp/ExternalCOM.cpp
diff options
context:
space:
mode:
authorJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
committerJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
commit20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch)
tree12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/Winamp/ExternalCOM.cpp
parent537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff)
downloadwinamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz
Initial community commit
Diffstat (limited to 'Src/Winamp/ExternalCOM.cpp')
-rw-r--r--Src/Winamp/ExternalCOM.cpp520
1 files changed, 520 insertions, 0 deletions
diff --git a/Src/Winamp/ExternalCOM.cpp b/Src/Winamp/ExternalCOM.cpp
new file mode 100644
index 00000000..1fbed2f6
--- /dev/null
+++ b/Src/Winamp/ExternalCOM.cpp
@@ -0,0 +1,520 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author: Ben Allison benski@nullsoft.com
+ ** Created:
+ **/
+#include "Main.h"
+#include "ExternalCOM.h"
+#include "BrowserCOM.h"
+#include "CurrentSongCOM.h"
+#include "SkinCOM.h"
+#include "ApplicationCOM.h"
+#include "BookmarksCOM.h"
+#include "MediaCoreCOM.h"
+#include "DataStoreCOM.h"
+#include "JNetCOM.h"
+#include "SecurityCOM.h"
+#include "../nu/ConfigCOM.h"
+#include "../nu/AutoChar.h"
+#include "../nu/AutoCharFn.h"
+#include "./Winamp/JSAPI.h"
+#include "JSAPI2_ExternalObject.h"
+#include "JSAPI2_Security.h"
+
+static volatile LONG unique_dispid;
+
+enum
+{
+ DISPID_CONFIG = 0,
+ DISPID_JNET = 1,
+ INITIAL_DISPID = 776,
+};
+
+static ExternalCOM *externalCOM = NULL;
+
+HRESULT __cdecl JSAPI1_Initialize()
+{
+ if (NULL != externalCOM)
+ return S_FALSE;
+
+ ExternalCOM *temp = new ExternalCOM();
+ if (NULL == temp)
+ return E_OUTOFMEMORY;
+
+ externalCOM = temp;
+ return S_OK;
+}
+
+HRESULT __cdecl JSAPI1_Uninitialize()
+{
+ if (NULL == externalCOM)
+ return S_FALSE;
+
+ ExternalCOM *temp = externalCOM;
+ externalCOM = NULL;
+ temp->Release();
+
+ return S_OK;
+}
+
+HRESULT __cdecl JSAPI1_GetExternal(ExternalCOM **instance)
+{
+ if (NULL == instance)
+ return E_POINTER;
+
+ if (NULL == externalCOM)
+ {
+ *instance = NULL;
+ return E_UNEXPECTED;
+ }
+
+ externalCOM->AddRef();
+ *instance = externalCOM;
+
+ return S_OK;
+}
+
+HRESULT __cdecl JSAPI1_GetSkinCOM(SkinCOM **instance)
+{
+ ExternalCOM *external = 0;
+ HRESULT hr = JSAPI1_GetExternal(&external);
+ if (SUCCEEDED(hr) && external)
+ {
+ hr = external->GetSkinCOM(instance);
+ external->Release();
+ }
+ else
+ {
+ if (NULL == instance) hr = E_POINTER;
+ else *instance = NULL;
+ }
+ return hr;
+}
+
+HRESULT __cdecl JSAPI1_GetMediaCoreCOM(MediaCoreCOM **instance)
+{
+ ExternalCOM *external = 0;
+ HRESULT hr = JSAPI1_GetExternal(&external);
+ if (SUCCEEDED(hr) && external)
+ {
+ hr = external->GetMediaCoreCOM(instance);
+ external->Release();
+ }
+ else
+ {
+ if (NULL == instance) hr = E_POINTER;
+ else *instance = NULL;
+ }
+ return hr;
+}
+
+HRESULT __cdecl JSAPI1_GetCurrentSongCOM(CurrentSongCOM **instance)
+{
+ ExternalCOM *external = 0;
+ HRESULT hr = JSAPI1_GetExternal(&external);
+ if (SUCCEEDED(hr) && external)
+ {
+ hr = external->GetCurrentSongCOM(instance);
+ external->Release();
+ }
+ else
+ {
+ if (NULL == instance) hr = E_POINTER;
+ else *instance = NULL;
+ }
+ return hr;
+}
+
+HRESULT __cdecl JSAPI1_SkinChanged()
+{
+ SkinCOM *skinCOM = 0;
+ HRESULT hr = JSAPI1_GetSkinCOM(&skinCOM);
+ if (SUCCEEDED(hr) && skinCOM)
+ {
+ skinCOM->SkinChanged();
+ skinCOM->Release();
+ }
+ return hr;
+}
+
+HRESULT __cdecl JSAPI1_CurrentTitleChanged()
+{
+ CurrentSongCOM *songCOM = 0;
+ HRESULT hr = JSAPI1_GetCurrentSongCOM(&songCOM);
+ if (SUCCEEDED(hr) && songCOM)
+ {
+ songCOM->TitleChanged();
+ songCOM->Release();
+ }
+ return hr;
+}
+
+DISPID __cdecl JSAPI1_GenerateUniqueDispatchId()
+{
+ return (DISPID)InterlockedIncrement(&unique_dispid);
+}
+
+#define REGISTER_DISPATCH_EX(__name, __creator, __dispId, __pDisp)\
+ { __pDisp = new __creator;\
+ if (NULL != __pDisp) {\
+ __dispId = AddDispatch(__name, __pDisp);\
+ if (0 == __dispId) { (__pDisp)->Release(); (__pDisp) = NULL;}\
+ }\
+ }
+
+#define REGISTER_DISPATCH(__name, __creator)\
+ { DISPID __dispId; IDispatch *pDisp; \
+ REGISTER_DISPATCH_EX(__name, __creator, __dispId, pDisp);\
+ if (NULL != pDisp) pDisp->Release(); }
+
+static const wchar_t *api1_api2_key = L"1";
+
+ExternalCOM::ExternalCOM() : ref(1), mediaCoreCOM(NULL), skinCOM(NULL), songCOM(NULL), api2(0)
+{
+ InitializeCriticalSection(&tableLock);
+ unique_dispid = INITIAL_DISPID; // we can't count on the CRT to have initialized this yet.
+ configFilename[0]=0;
+
+ DISPID dispId = 0;
+ REGISTER_DISPATCH(L"Browser", BrowserCOM());
+ REGISTER_DISPATCH_EX(L"CurrentSong", CurrentSongCOM(), dispId, songCOM);
+ REGISTER_DISPATCH_EX(L"CurrentSkin", SkinCOM(), dispId, skinCOM);
+ REGISTER_DISPATCH(L"Application", ApplicationCOM());
+ REGISTER_DISPATCH(L"Bookmarks", BookmarksCOM());
+ REGISTER_DISPATCH_EX(L"MediaCore", MediaCoreCOM(), dispId, mediaCoreCOM);
+ REGISTER_DISPATCH(L"DataStore", DataStoreCOM());
+ REGISTER_DISPATCH(L"Security", SecurityCOM());
+ JSAPI2::security.SetBypass(api1_api2_key, true);
+ REGISTER_DISPATCH_EX(L"API2", JSAPI2::ExternalObject(api1_api2_key), dispId, api2);
+}
+
+ExternalCOM::~ExternalCOM()
+{
+ EnterCriticalSection(&tableLock);
+
+ for ( JSAPI::Dispatcher *l_dispatch_table : dispatchTable )
+ delete l_dispatch_table;
+
+ for ( ConfigCOM *l_config : configs )
+ l_config->Release();
+
+ LeaveCriticalSection(&tableLock);
+
+ DeleteCriticalSection(&tableLock);
+
+ if (NULL != mediaCoreCOM) mediaCoreCOM->Release();
+ if (NULL != songCOM) songCOM->Release();
+ if (NULL != skinCOM) skinCOM->Release();
+ if (NULL != api2) api2->Release();
+}
+
+#define CHECK_ID(str, id)\
+ if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, rgszNames[i], -1, L##str, -1))\
+ { rgdispid[i] = id; continue; }
+
+STDMETHODIMP ExternalCOM::GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid)
+{
+ UINT unknowns = 0;
+
+ EnterCriticalSection(&tableLock);
+ size_t tableCount = dispatchTable.size();
+
+ for (unsigned int i = 0;i != cNames; i++)
+ {
+ rgdispid[i]=DISPID_UNKNOWN;
+
+ for (size_t entry = 0; entry < tableCount; entry++)
+ {
+ if (!wcscmp(rgszNames[i], dispatchTable[entry]->name))
+ {
+ rgdispid[i] = dispatchTable[entry]->id;
+ break;
+ }
+ }
+
+ if (rgdispid[i] == DISPID_UNKNOWN && !wcscmp(rgszNames[i], L"Config"))
+ rgdispid[i] = DISPID_CONFIG;
+ else if (rgdispid[i] == DISPID_UNKNOWN && !wcscmp(rgszNames[i], L"JNetLib"))
+ rgdispid[i] = DISPID_JNET;
+ else if (rgdispid[i] == DISPID_UNKNOWN)
+ unknowns++;
+ }
+
+ LeaveCriticalSection(&tableLock);
+
+ if (0 != unknowns)
+ return DISP_E_UNKNOWNNAME;
+ else
+ return S_OK;
+}
+
+STDMETHODIMP ExternalCOM::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
+{
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP ExternalCOM::GetTypeInfoCount(unsigned int FAR * pctinfo)
+{
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP ExternalCOM::Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr)
+{
+ switch(dispid)
+ {
+ case DISPID_CONFIG:
+ {
+ JSAPI_VERIFY_METHOD(wFlags);
+ JSAPI_VERIFY_PARAMCOUNT(pdispparams, 1);
+
+ LPCWSTR configName;
+ JSAPI_GETSTRING(configName, pdispparams, 1, puArgErr);
+
+ if (NULL != pvarResult)
+ {
+ VariantInit(pvarResult);
+
+ ConfigCOM *config;
+ if (SUCCEEDED(GetConfig(configName, &config)))
+ {
+ V_VT(pvarResult) = VT_DISPATCH;
+ V_DISPATCH(pvarResult) = config;
+ }
+ else
+ {
+ V_VT(pvarResult) = VT_NULL;
+ }
+ }
+ }
+ return S_OK;
+
+ case DISPID_JNET:
+ {
+ VariantInit(pvarResult);
+ V_VT(pvarResult) = VT_DISPATCH;
+ V_DISPATCH(pvarResult) = new JNetCOM(pdispparams->rgvarg[0].pdispVal);
+ return S_OK;
+ }
+ break;
+ }
+
+ EnterCriticalSection(&tableLock);
+ size_t index = dispatchTable.size();
+ while(index--)
+ {
+ if (dispatchTable[index]->id == dispid)
+ {
+ VariantInit(pvarResult);
+ V_VT(pvarResult) = VT_DISPATCH;
+ V_DISPATCH(pvarResult) = dispatchTable[index]->object;
+ dispatchTable[index]->object->AddRef();
+ break;
+ }
+ }
+ LeaveCriticalSection(&tableLock);
+ if (((size_t)-1) != index) return S_OK;
+
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+STDMETHODIMP ExternalCOM::QueryInterface(REFIID riid, PVOID *ppvObject)
+{
+ if (!ppvObject)
+ return E_POINTER;
+ else if (IsEqualIID(riid, IID_IDispatch))
+ *ppvObject = (IDispatch *)this;
+ else if (IsEqualIID(riid, IID_IUnknown))
+ *ppvObject = this;
+ else
+ {
+ *ppvObject = NULL;
+ return E_NOINTERFACE;
+ }
+
+ AddRef();
+ return S_OK;
+}
+
+STDMETHODIMP_(ULONG) ExternalCOM::AddRef(void)
+{
+ return InterlockedIncrement((LONG*)&ref);
+}
+
+STDMETHODIMP_(ULONG) ExternalCOM::Release(void)
+{
+ if (0 == ref)
+ return ref;
+
+ LONG r = InterlockedDecrement((LONG*)&ref);
+ if (0 == r)
+ delete(this);
+
+ return r;
+}
+
+STDMETHODIMP ExternalCOM::QueryDispatchable(REFIID riid, Dispatchable **ppDispatchable)
+{
+ if (IsEqualIID(riid, JSAPI::IID_JSAPI_ifc_info))
+ {
+ *ppDispatchable = (JSAPI::ifc_info *)this;
+ }
+ else
+ {
+ *ppDispatchable = NULL;
+ return E_NOINTERFACE;
+ }
+ (*ppDispatchable)->AddRef();
+ return S_OK;
+}
+
+const wchar_t *ExternalCOM::GetUserAgent()
+{
+ return L"JSAPI1";
+}
+
+HRESULT ExternalCOM::GetConfig(LPCWSTR configName, ConfigCOM **config)
+{
+ if (NULL == config) return E_POINTER;
+
+ AutoChar nameAnsi(configName);
+ if (NULL == (const char*)nameAnsi)
+ {
+ *config = NULL;
+ return E_INVALIDARG;
+ }
+
+ EnterCriticalSection(&tableLock);
+
+ // check if there's already an open config object
+ size_t index = configs.size();
+ while (index-- && FALSE != configs[index]->IsEqual(nameAnsi));
+
+ if ((size_t)-1 == index)
+ {
+ if (L'\0' != configFilename[0] ||
+ NULL != PathCombineW(configFilename, CONFIGDIR, L"jscfg.ini"))
+ {
+ if (SUCCEEDED(ConfigCOM::CreateInstanceA(nameAnsi, AutoCharFn(configFilename), config)))
+ configs.push_back(*config);
+ }
+ }
+ else
+ {
+ *config = configs[index];
+ }
+
+ HRESULT hr = S_OK;
+ if (NULL != *config)
+ {
+ (*config)->AddRef();
+ }
+ else
+ hr = E_FAIL;
+
+ LeaveCriticalSection(&tableLock);
+
+ return hr;
+}
+
+HRESULT ExternalCOM::FindDispatch(DISPID dispId, IDispatch **instance)
+{
+ if (NULL == instance)
+ return E_POINTER;
+
+ EnterCriticalSection(&tableLock);
+ size_t index = dispatchTable.size();
+ while(index--)
+ {
+ if (dispatchTable[index]->id == dispId)
+ {
+ *instance = dispatchTable[index]->object;
+ break;
+ }
+ }
+ LeaveCriticalSection(&tableLock);
+
+ if (((size_t)-1) != index)
+ return S_OK;
+
+ *instance = NULL;
+ return S_FALSE;
+}
+
+DISPID ExternalCOM::AddDispatch(const wchar_t *name, IDispatch *object)
+{
+ if (NULL == object)
+ return 0;
+
+ DISPID id = JSAPI1_GenerateUniqueDispatchId();
+
+ JSAPI::Dispatcher *dispatcher = new JSAPI::Dispatcher(name, id, object);
+ if (NULL == dispatcher) return 0;
+
+ EnterCriticalSection(&tableLock);
+ dispatchTable.push_back(dispatcher);
+ LeaveCriticalSection(&tableLock);
+
+ return id;
+}
+
+BOOL ExternalCOM::RemoveDispatch(DISPID dispatchId)
+{
+ EnterCriticalSection(&tableLock);
+ size_t index = dispatchTable.size();
+ while(index--)
+ {
+ if (dispatchTable[index]->id == dispatchId)
+ {
+ JSAPI::Dispatcher *dispatcher = dispatchTable[index];
+ dispatchTable.erase(dispatchTable.begin() + index);
+ delete dispatcher;
+ break;
+ }
+ }
+ LeaveCriticalSection(&tableLock);
+ return (((size_t)-1) != index);
+}
+
+HRESULT ExternalCOM::GetSkinCOM(SkinCOM **instance)
+{
+ if (NULL == instance)
+ return E_POINTER;
+
+ *instance = skinCOM;
+ if (NULL != *instance)
+ (*instance)->AddRef();
+
+ return S_OK;
+}
+
+HRESULT ExternalCOM::GetMediaCoreCOM(MediaCoreCOM **instance)
+{
+ if (NULL == instance)
+ return E_POINTER;
+
+ *instance = mediaCoreCOM;
+ if (NULL != *instance)
+ (*instance)->AddRef();
+
+ return S_OK;
+}
+
+HRESULT ExternalCOM::GetCurrentSongCOM(CurrentSongCOM **instance)
+{
+ if (NULL == instance)
+ return E_POINTER;
+
+ *instance = songCOM;
+ if (NULL != *instance)
+ (*instance)->AddRef();
+
+ return S_OK;
+}
+
+#define CBCLASS ExternalCOM
+START_DISPATCH;
+CB(JSAPI_IFC_INFO_GETUSERAGENT, GetUserAgent)
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file