ExternalCOM.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
  1. /** (c) Nullsoft, Inc. C O N F I D E N T I A L
  2. ** Filename:
  3. ** Project:
  4. ** Description:
  5. ** Author: Ben Allison [email protected]
  6. ** Created:
  7. **/
  8. #include "Main.h"
  9. #include "ExternalCOM.h"
  10. #include "BrowserCOM.h"
  11. #include "CurrentSongCOM.h"
  12. #include "SkinCOM.h"
  13. #include "ApplicationCOM.h"
  14. #include "BookmarksCOM.h"
  15. #include "MediaCoreCOM.h"
  16. #include "DataStoreCOM.h"
  17. #include "JNetCOM.h"
  18. #include "SecurityCOM.h"
  19. #include "../nu/ConfigCOM.h"
  20. #include "../nu/AutoChar.h"
  21. #include "../nu/AutoCharFn.h"
  22. #include "./Winamp/JSAPI.h"
  23. #include "JSAPI2_ExternalObject.h"
  24. #include "JSAPI2_Security.h"
  25. static volatile LONG unique_dispid;
  26. enum
  27. {
  28. DISPID_CONFIG = 0,
  29. DISPID_JNET = 1,
  30. INITIAL_DISPID = 776,
  31. };
  32. static ExternalCOM *externalCOM = NULL;
  33. HRESULT __cdecl JSAPI1_Initialize()
  34. {
  35. if (NULL != externalCOM)
  36. return S_FALSE;
  37. ExternalCOM *temp = new ExternalCOM();
  38. if (NULL == temp)
  39. return E_OUTOFMEMORY;
  40. externalCOM = temp;
  41. return S_OK;
  42. }
  43. HRESULT __cdecl JSAPI1_Uninitialize()
  44. {
  45. if (NULL == externalCOM)
  46. return S_FALSE;
  47. ExternalCOM *temp = externalCOM;
  48. externalCOM = NULL;
  49. temp->Release();
  50. return S_OK;
  51. }
  52. HRESULT __cdecl JSAPI1_GetExternal(ExternalCOM **instance)
  53. {
  54. if (NULL == instance)
  55. return E_POINTER;
  56. if (NULL == externalCOM)
  57. {
  58. *instance = NULL;
  59. return E_UNEXPECTED;
  60. }
  61. externalCOM->AddRef();
  62. *instance = externalCOM;
  63. return S_OK;
  64. }
  65. HRESULT __cdecl JSAPI1_GetSkinCOM(SkinCOM **instance)
  66. {
  67. ExternalCOM *external = 0;
  68. HRESULT hr = JSAPI1_GetExternal(&external);
  69. if (SUCCEEDED(hr) && external)
  70. {
  71. hr = external->GetSkinCOM(instance);
  72. external->Release();
  73. }
  74. else
  75. {
  76. if (NULL == instance) hr = E_POINTER;
  77. else *instance = NULL;
  78. }
  79. return hr;
  80. }
  81. HRESULT __cdecl JSAPI1_GetMediaCoreCOM(MediaCoreCOM **instance)
  82. {
  83. ExternalCOM *external = 0;
  84. HRESULT hr = JSAPI1_GetExternal(&external);
  85. if (SUCCEEDED(hr) && external)
  86. {
  87. hr = external->GetMediaCoreCOM(instance);
  88. external->Release();
  89. }
  90. else
  91. {
  92. if (NULL == instance) hr = E_POINTER;
  93. else *instance = NULL;
  94. }
  95. return hr;
  96. }
  97. HRESULT __cdecl JSAPI1_GetCurrentSongCOM(CurrentSongCOM **instance)
  98. {
  99. ExternalCOM *external = 0;
  100. HRESULT hr = JSAPI1_GetExternal(&external);
  101. if (SUCCEEDED(hr) && external)
  102. {
  103. hr = external->GetCurrentSongCOM(instance);
  104. external->Release();
  105. }
  106. else
  107. {
  108. if (NULL == instance) hr = E_POINTER;
  109. else *instance = NULL;
  110. }
  111. return hr;
  112. }
  113. HRESULT __cdecl JSAPI1_SkinChanged()
  114. {
  115. SkinCOM *skinCOM = 0;
  116. HRESULT hr = JSAPI1_GetSkinCOM(&skinCOM);
  117. if (SUCCEEDED(hr) && skinCOM)
  118. {
  119. skinCOM->SkinChanged();
  120. skinCOM->Release();
  121. }
  122. return hr;
  123. }
  124. HRESULT __cdecl JSAPI1_CurrentTitleChanged()
  125. {
  126. CurrentSongCOM *songCOM = 0;
  127. HRESULT hr = JSAPI1_GetCurrentSongCOM(&songCOM);
  128. if (SUCCEEDED(hr) && songCOM)
  129. {
  130. songCOM->TitleChanged();
  131. songCOM->Release();
  132. }
  133. return hr;
  134. }
  135. DISPID __cdecl JSAPI1_GenerateUniqueDispatchId()
  136. {
  137. return (DISPID)InterlockedIncrement(&unique_dispid);
  138. }
  139. #define REGISTER_DISPATCH_EX(__name, __creator, __dispId, __pDisp)\
  140. { __pDisp = new __creator;\
  141. if (NULL != __pDisp) {\
  142. __dispId = AddDispatch(__name, __pDisp);\
  143. if (0 == __dispId) { (__pDisp)->Release(); (__pDisp) = NULL;}\
  144. }\
  145. }
  146. #define REGISTER_DISPATCH(__name, __creator)\
  147. { DISPID __dispId; IDispatch *pDisp; \
  148. REGISTER_DISPATCH_EX(__name, __creator, __dispId, pDisp);\
  149. if (NULL != pDisp) pDisp->Release(); }
  150. static const wchar_t *api1_api2_key = L"1";
  151. ExternalCOM::ExternalCOM() : ref(1), mediaCoreCOM(NULL), skinCOM(NULL), songCOM(NULL), api2(0)
  152. {
  153. InitializeCriticalSection(&tableLock);
  154. unique_dispid = INITIAL_DISPID; // we can't count on the CRT to have initialized this yet.
  155. configFilename[0]=0;
  156. DISPID dispId = 0;
  157. REGISTER_DISPATCH(L"Browser", BrowserCOM());
  158. REGISTER_DISPATCH_EX(L"CurrentSong", CurrentSongCOM(), dispId, songCOM);
  159. REGISTER_DISPATCH_EX(L"CurrentSkin", SkinCOM(), dispId, skinCOM);
  160. REGISTER_DISPATCH(L"Application", ApplicationCOM());
  161. REGISTER_DISPATCH(L"Bookmarks", BookmarksCOM());
  162. REGISTER_DISPATCH_EX(L"MediaCore", MediaCoreCOM(), dispId, mediaCoreCOM);
  163. REGISTER_DISPATCH(L"DataStore", DataStoreCOM());
  164. REGISTER_DISPATCH(L"Security", SecurityCOM());
  165. JSAPI2::security.SetBypass(api1_api2_key, true);
  166. REGISTER_DISPATCH_EX(L"API2", JSAPI2::ExternalObject(api1_api2_key), dispId, api2);
  167. }
  168. ExternalCOM::~ExternalCOM()
  169. {
  170. EnterCriticalSection(&tableLock);
  171. for ( JSAPI::Dispatcher *l_dispatch_table : dispatchTable )
  172. delete l_dispatch_table;
  173. for ( ConfigCOM *l_config : configs )
  174. l_config->Release();
  175. LeaveCriticalSection(&tableLock);
  176. DeleteCriticalSection(&tableLock);
  177. if (NULL != mediaCoreCOM) mediaCoreCOM->Release();
  178. if (NULL != songCOM) songCOM->Release();
  179. if (NULL != skinCOM) skinCOM->Release();
  180. if (NULL != api2) api2->Release();
  181. }
  182. #define CHECK_ID(str, id)\
  183. if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, rgszNames[i], -1, L##str, -1))\
  184. { rgdispid[i] = id; continue; }
  185. STDMETHODIMP ExternalCOM::GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid)
  186. {
  187. UINT unknowns = 0;
  188. EnterCriticalSection(&tableLock);
  189. size_t tableCount = dispatchTable.size();
  190. for (unsigned int i = 0;i != cNames; i++)
  191. {
  192. rgdispid[i]=DISPID_UNKNOWN;
  193. for (size_t entry = 0; entry < tableCount; entry++)
  194. {
  195. if (!wcscmp(rgszNames[i], dispatchTable[entry]->name))
  196. {
  197. rgdispid[i] = dispatchTable[entry]->id;
  198. break;
  199. }
  200. }
  201. if (rgdispid[i] == DISPID_UNKNOWN && !wcscmp(rgszNames[i], L"Config"))
  202. rgdispid[i] = DISPID_CONFIG;
  203. else if (rgdispid[i] == DISPID_UNKNOWN && !wcscmp(rgszNames[i], L"JNetLib"))
  204. rgdispid[i] = DISPID_JNET;
  205. else if (rgdispid[i] == DISPID_UNKNOWN)
  206. unknowns++;
  207. }
  208. LeaveCriticalSection(&tableLock);
  209. if (0 != unknowns)
  210. return DISP_E_UNKNOWNNAME;
  211. else
  212. return S_OK;
  213. }
  214. STDMETHODIMP ExternalCOM::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
  215. {
  216. return E_NOTIMPL;
  217. }
  218. STDMETHODIMP ExternalCOM::GetTypeInfoCount(unsigned int FAR * pctinfo)
  219. {
  220. return E_NOTIMPL;
  221. }
  222. STDMETHODIMP ExternalCOM::Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr)
  223. {
  224. switch(dispid)
  225. {
  226. case DISPID_CONFIG:
  227. {
  228. JSAPI_VERIFY_METHOD(wFlags);
  229. JSAPI_VERIFY_PARAMCOUNT(pdispparams, 1);
  230. LPCWSTR configName;
  231. JSAPI_GETSTRING(configName, pdispparams, 1, puArgErr);
  232. if (NULL != pvarResult)
  233. {
  234. VariantInit(pvarResult);
  235. ConfigCOM *config;
  236. if (SUCCEEDED(GetConfig(configName, &config)))
  237. {
  238. V_VT(pvarResult) = VT_DISPATCH;
  239. V_DISPATCH(pvarResult) = config;
  240. }
  241. else
  242. {
  243. V_VT(pvarResult) = VT_NULL;
  244. }
  245. }
  246. }
  247. return S_OK;
  248. case DISPID_JNET:
  249. {
  250. VariantInit(pvarResult);
  251. V_VT(pvarResult) = VT_DISPATCH;
  252. V_DISPATCH(pvarResult) = new JNetCOM(pdispparams->rgvarg[0].pdispVal);
  253. return S_OK;
  254. }
  255. break;
  256. }
  257. EnterCriticalSection(&tableLock);
  258. size_t index = dispatchTable.size();
  259. while(index--)
  260. {
  261. if (dispatchTable[index]->id == dispid)
  262. {
  263. VariantInit(pvarResult);
  264. V_VT(pvarResult) = VT_DISPATCH;
  265. V_DISPATCH(pvarResult) = dispatchTable[index]->object;
  266. dispatchTable[index]->object->AddRef();
  267. break;
  268. }
  269. }
  270. LeaveCriticalSection(&tableLock);
  271. if (((size_t)-1) != index) return S_OK;
  272. return DISP_E_MEMBERNOTFOUND;
  273. }
  274. STDMETHODIMP ExternalCOM::QueryInterface(REFIID riid, PVOID *ppvObject)
  275. {
  276. if (!ppvObject)
  277. return E_POINTER;
  278. else if (IsEqualIID(riid, IID_IDispatch))
  279. *ppvObject = (IDispatch *)this;
  280. else if (IsEqualIID(riid, IID_IUnknown))
  281. *ppvObject = this;
  282. else
  283. {
  284. *ppvObject = NULL;
  285. return E_NOINTERFACE;
  286. }
  287. AddRef();
  288. return S_OK;
  289. }
  290. STDMETHODIMP_(ULONG) ExternalCOM::AddRef(void)
  291. {
  292. return InterlockedIncrement((LONG*)&ref);
  293. }
  294. STDMETHODIMP_(ULONG) ExternalCOM::Release(void)
  295. {
  296. if (0 == ref)
  297. return ref;
  298. LONG r = InterlockedDecrement((LONG*)&ref);
  299. if (0 == r)
  300. delete(this);
  301. return r;
  302. }
  303. STDMETHODIMP ExternalCOM::QueryDispatchable(REFIID riid, Dispatchable **ppDispatchable)
  304. {
  305. if (IsEqualIID(riid, JSAPI::IID_JSAPI_ifc_info))
  306. {
  307. *ppDispatchable = (JSAPI::ifc_info *)this;
  308. }
  309. else
  310. {
  311. *ppDispatchable = NULL;
  312. return E_NOINTERFACE;
  313. }
  314. (*ppDispatchable)->AddRef();
  315. return S_OK;
  316. }
  317. const wchar_t *ExternalCOM::GetUserAgent()
  318. {
  319. return L"JSAPI1";
  320. }
  321. HRESULT ExternalCOM::GetConfig(LPCWSTR configName, ConfigCOM **config)
  322. {
  323. if (NULL == config) return E_POINTER;
  324. AutoChar nameAnsi(configName);
  325. if (NULL == (const char*)nameAnsi)
  326. {
  327. *config = NULL;
  328. return E_INVALIDARG;
  329. }
  330. EnterCriticalSection(&tableLock);
  331. // check if there's already an open config object
  332. size_t index = configs.size();
  333. while (index-- && FALSE != configs[index]->IsEqual(nameAnsi));
  334. if ((size_t)-1 == index)
  335. {
  336. if (L'\0' != configFilename[0] ||
  337. NULL != PathCombineW(configFilename, CONFIGDIR, L"jscfg.ini"))
  338. {
  339. if (SUCCEEDED(ConfigCOM::CreateInstanceA(nameAnsi, AutoCharFn(configFilename), config)))
  340. configs.push_back(*config);
  341. }
  342. }
  343. else
  344. {
  345. *config = configs[index];
  346. }
  347. HRESULT hr = S_OK;
  348. if (NULL != *config)
  349. {
  350. (*config)->AddRef();
  351. }
  352. else
  353. hr = E_FAIL;
  354. LeaveCriticalSection(&tableLock);
  355. return hr;
  356. }
  357. HRESULT ExternalCOM::FindDispatch(DISPID dispId, IDispatch **instance)
  358. {
  359. if (NULL == instance)
  360. return E_POINTER;
  361. EnterCriticalSection(&tableLock);
  362. size_t index = dispatchTable.size();
  363. while(index--)
  364. {
  365. if (dispatchTable[index]->id == dispId)
  366. {
  367. *instance = dispatchTable[index]->object;
  368. break;
  369. }
  370. }
  371. LeaveCriticalSection(&tableLock);
  372. if (((size_t)-1) != index)
  373. return S_OK;
  374. *instance = NULL;
  375. return S_FALSE;
  376. }
  377. DISPID ExternalCOM::AddDispatch(const wchar_t *name, IDispatch *object)
  378. {
  379. if (NULL == object)
  380. return 0;
  381. DISPID id = JSAPI1_GenerateUniqueDispatchId();
  382. JSAPI::Dispatcher *dispatcher = new JSAPI::Dispatcher(name, id, object);
  383. if (NULL == dispatcher) return 0;
  384. EnterCriticalSection(&tableLock);
  385. dispatchTable.push_back(dispatcher);
  386. LeaveCriticalSection(&tableLock);
  387. return id;
  388. }
  389. BOOL ExternalCOM::RemoveDispatch(DISPID dispatchId)
  390. {
  391. EnterCriticalSection(&tableLock);
  392. size_t index = dispatchTable.size();
  393. while(index--)
  394. {
  395. if (dispatchTable[index]->id == dispatchId)
  396. {
  397. JSAPI::Dispatcher *dispatcher = dispatchTable[index];
  398. dispatchTable.erase(dispatchTable.begin() + index);
  399. delete dispatcher;
  400. break;
  401. }
  402. }
  403. LeaveCriticalSection(&tableLock);
  404. return (((size_t)-1) != index);
  405. }
  406. HRESULT ExternalCOM::GetSkinCOM(SkinCOM **instance)
  407. {
  408. if (NULL == instance)
  409. return E_POINTER;
  410. *instance = skinCOM;
  411. if (NULL != *instance)
  412. (*instance)->AddRef();
  413. return S_OK;
  414. }
  415. HRESULT ExternalCOM::GetMediaCoreCOM(MediaCoreCOM **instance)
  416. {
  417. if (NULL == instance)
  418. return E_POINTER;
  419. *instance = mediaCoreCOM;
  420. if (NULL != *instance)
  421. (*instance)->AddRef();
  422. return S_OK;
  423. }
  424. HRESULT ExternalCOM::GetCurrentSongCOM(CurrentSongCOM **instance)
  425. {
  426. if (NULL == instance)
  427. return E_POINTER;
  428. *instance = songCOM;
  429. if (NULL != *instance)
  430. (*instance)->AddRef();
  431. return S_OK;
  432. }
  433. #define CBCLASS ExternalCOM
  434. START_DISPATCH;
  435. CB(JSAPI_IFC_INFO_GETUSERAGENT, GetUserAgent)
  436. END_DISPATCH;
  437. #undef CBCLASS