compon.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480
  1. #include <precomp.h>
  2. #include <bfc/wasabi_std.h>
  3. #include "compon.h"
  4. //#include <api/wac/main.h> // CUT!
  5. #ifndef WASABINOMAINAPI
  6. #include <api/metadb/metadb.h>
  7. #include <api/wac/papi.h>
  8. #endif
  9. #include <api/script/objects/compoobj.h>
  10. #include <api/wndmgr/container.h>
  11. #include <api/skin/skinparse.h>
  12. #include <api/wac/wac.h>
  13. #include <api/script/objects/wacobj.h>
  14. #include <api/wnd/wndtrack.h>
  15. #include <api/script/objecttable.h>
  16. #include <api/config/items/cfgitemi.h>
  17. #include <bfc/loadlib.h>
  18. //#include <bfc/util/profiler.h>
  19. #include <api/locales/xlatstr.h>
  20. #include <bfc/file/recursedir.h>
  21. #include <api/service/svc_enum.h>
  22. #include <api/service/services.h>
  23. #include <api/service/servicei.h>
  24. #include <api/skin/skin.h>
  25. #include <api/script/scriptmgr.h>
  26. #include <bfc/parse/pathparse.h>
  27. #ifndef WASABINOMAINAPI
  28. #include <api/api1.h>
  29. #endif
  30. #include <api/application/wkc.h>
  31. #include <api/wndmgr/skinembed.h>
  32. #include <api/script/objects/compoobj.h>
  33. #include <api/wnd/usermsg.h>
  34. #include <bfc/util/inifile.h>
  35. class CShutdownCallback {
  36. public:
  37. virtual void rl_onShutdown()=0;
  38. };
  39. extern GUID baseGUID;
  40. static TList<GUID> loadlist, banlist;
  41. // compon.cpp : maintains the list of installed components, and installs
  42. // each one
  43. // keep a list of component pointers as well as instances
  44. class component_slot
  45. {
  46. public:
  47. #ifndef WASABINOMAINAPI
  48. component_slot(Library *_dll, WaComponent *_wac, ComponentAPI *_api, GUID g, const wchar_t *orig_path)
  49. : dll(_dll), wac(_wac), path(orig_path), guid(g), componentapi(_api) {
  50. #else
  51. component_slot(Library *_dll, WaComponent *_wac, GUID g, const wchar_t *orig_path)
  52. : dll(_dll), wac(_wac), path(orig_path), guid(g) {
  53. #endif
  54. int fnlen = wcslen(Wasabi::Std::filename(orig_path));
  55. path.trunc(-fnlen);
  56. postonregsvcs = 0;
  57. postoncreate = 0;
  58. loadearly = 0; // will be filled in later
  59. }
  60. ~component_slot() {
  61. #ifndef WASABINOMAINAPI
  62. if (dll != NULL) PAPI::destroyAPI(componentapi);
  63. #endif
  64. delete dll;
  65. }
  66. void registerServices() {
  67. #ifndef WASABINOMAINAPI
  68. if (!postonregsvcs) wac->registerServices(componentapi);
  69. #else
  70. if (!postonregsvcs) wac->registerServices(WASABI_API_SVC);
  71. #endif
  72. postonregsvcs = 1;
  73. }
  74. void onCreate() {
  75. if (!postoncreate) wac->onCreate();
  76. postoncreate = 1;
  77. }
  78. Library *dll;
  79. WaComponent *wac; // we don't delete this
  80. StringW path;
  81. GUID guid; // prevent spoofing
  82. #ifndef WASABINOMAINAPI
  83. ComponentAPI *componentapi;
  84. #endif
  85. int postoncreate;
  86. int postonregsvcs;
  87. int loadearly;
  88. };
  89. static PtrList<component_slot> components;
  90. /*static PtrList<cd_entry> cd_list;
  91. static PtrList<ComponentObject> co_list;*/
  92. // the minimum SDK version # we accept
  93. const int WA_COMPONENT_VER_MIN = WA_COMPONENT_VERSION;
  94. static int postComponentCommand(GUID guid, const wchar_t *command, int p1, int p2, void *ptr, int ptrlen, int waitforanswer);
  95. class ComponPostEntry {
  96. public:
  97. ComponPostEntry(GUID pguid, const wchar_t *pcommand, int pp1, int pp2, void *pptr, int pptrlen, int pwait) :
  98. guid(pguid), command(pcommand), p1(pp1), p2(pp2), ptr(pptr), ptrlen(pptrlen), waitforanswer(pwait),
  99. posted(0), result(0) { }
  100. GUID guid;
  101. StringW command;
  102. int p1, p2;
  103. void *ptr;
  104. int ptrlen;
  105. int waitforanswer;
  106. int posted;
  107. int result;
  108. };
  109. static PtrList<StringW> preloads;
  110. void ComponentManager::addStaticComponent(WaComponent *component) {
  111. GUID guid = component->getGUID();
  112. if (!checkGUID(guid)) return; // guid check (banlist etc.)
  113. #ifndef WASABINOMAINAPI
  114. // reuse main api *
  115. components.addItem(new component_slot(NULL, component, api, guid, NULL));
  116. #else
  117. components.addItem(new component_slot(NULL, component, guid, NULL));
  118. #endif
  119. }
  120. void ComponentManager::addPreloadComponent(const wchar_t *filename)
  121. {
  122. foreach(preloads)
  123. if (PATHEQL(filename, preloads.getfor()->getValue())) return;// no dups
  124. endfor
  125. preloads.addItem(new StringW(filename));
  126. }
  127. void ComponentManager::loadPreloads() {
  128. foreach(preloads)
  129. load(preloads.getfor()->getValue());
  130. endfor
  131. preloads.deleteAll();
  132. }
  133. void ComponentManager::load(const wchar_t *filename) {
  134. // ensure no duplicate filenames
  135. foreach(components)
  136. if (PATHEQL(filename, components.getfor()->dll->getName())) return;
  137. endfor
  138. #ifdef WA3COMPATIBILITY
  139. // let kernel controller test the file
  140. WasabiKernelController *wkc = Main::getKernelController();
  141. if (wkc && !wkc->testComponent(filename)) return;
  142. #endif
  143. // check if they have an ini (to get guid faster)
  144. StringW inifile = filename;
  145. const wchar_t *ext = Wasabi::Std::extension(inifile);
  146. int len = wcslen(ext);
  147. inifile.trunc(-len);
  148. inifile.cat(L"ini");
  149. IniFile ini(inifile);
  150. GUID ini_guid = ini.getGuid(L"component", L"guid");
  151. if (!checkGUID(ini_guid, TRUE)) return;
  152. // PR_ENTER2("load component", filename);
  153. // attach the DLL
  154. Library *dll = new Library(filename);
  155. if (!dll->load()) {
  156. delete dll;
  157. return;
  158. }
  159. // check the version of SDK it was compiled with
  160. WACGETVERSION wac_get_version = (WACGETVERSION)dll->getProcAddress("WAC_getVersion");
  161. if (wac_get_version == NULL) {
  162. delete dll;
  163. return;
  164. }
  165. int version = (*wac_get_version)();
  166. if (version < WA_COMPONENT_VER_MIN || // defined above
  167. version > WA_COMPONENT_VERSION) { // from wac.h
  168. delete dll;
  169. return;
  170. }
  171. // init the dll itself
  172. WACINIT wacinit = (WACINIT)dll->getProcAddress("WAC_init");
  173. if (wacinit != NULL) (*wacinit)(dll->getHandle());
  174. WACENUMCOMPONENT wec = (WACENUMCOMPONENT)dll->getProcAddress("WAC_enumComponent");
  175. if (wec == NULL) {
  176. delete dll;
  177. return;
  178. }
  179. // fetch the pointer
  180. WaComponent *wac = (*wec)(0);
  181. GUID guid = wac->getGUID();
  182. if (ini_guid != INVALID_GUID && guid != ini_guid) {
  183. delete dll;
  184. DebugString("guids didn't match! %s", filename);
  185. return;
  186. }
  187. // check if we want to load this GUID
  188. if (!checkGUID(guid)) {
  189. delete dll;
  190. return;
  191. }
  192. #ifndef WASABINOMAINAPI
  193. // allocate an api pointer bound to their GUID
  194. ComponentAPI *newapi = PAPI::createAPI(wac, guid);
  195. if (newapi == NULL) {
  196. delete dll;
  197. return;
  198. }
  199. #endif
  200. PathParserW pp(filename);
  201. StringW path;
  202. for (int i=0;i<pp.getNumStrings()-1;i++)
  203. {
  204. path.AppendFolder(pp.enumString(i));
  205. }
  206. wac->setComponentPath(path);
  207. // keep track of dll handles for shutdown
  208. components.addItem(new component_slot(dll, wac,
  209. #ifndef WASABINOMAINAPI
  210. newapi,
  211. #endif
  212. guid, filename));
  213. // PR_LEAVE();
  214. }
  215. const wchar_t *ComponentManager::getComponentPath(GUID g) {
  216. foreach(components)
  217. if (g == components.getfor()->guid) {
  218. return components.getfor()->path;
  219. }
  220. endfor
  221. return NULL;
  222. }
  223. void ComponentManager::startupDBs() {
  224. /* for (int i=0;i<components.getNumItems();i++)
  225. MetaDB::addComponentDB(components.enumItem(i)->wac);*/
  226. }
  227. void ComponentManager::shutdownDBs() {
  228. #ifndef WASABINOMAINAPI
  229. for (int i = 0; i < components.getNumItems(); i++) {
  230. //MetaDB::getBaseDB()->removeComponentDB(components[i]->wac);
  231. (static_cast<ComponentAPI1 *>(components[i]->componentapi))->shutdownDB();
  232. }
  233. #else
  234. //MULTIAPI-FIXME: solve the shutdownDB puzzle
  235. #endif
  236. }
  237. void ComponentManager::unloadAll() {
  238. // cable out! let 'er go!
  239. // deleteAllCD(); // deletes compwnds
  240. foreach(components)
  241. components.getfor()->wac->deregisterServices();
  242. endfor
  243. foreach(components)
  244. components.getfor()->wac->onDestroy();
  245. endfor
  246. components.deleteAll(); // free the DLLs, and kill their API *'s
  247. }
  248. int ComponentManager::checkGUID(GUID &g, int invalid_ok) {
  249. // no invalid guid
  250. if (!invalid_ok && g == INVALID_GUID) return FALSE;
  251. // check against banlist
  252. if (banlist.haveItem(g)) return FALSE;
  253. // check against load-only list
  254. if (loadlist.getNumItems() && !loadlist.haveItem(g)) return FALSE;
  255. // ensure no duplicate GUIDs
  256. foreach(components)
  257. if (g == components.getfor()->guid) {
  258. //CUT StringPrintf s("%s and %s", components.getfor()->dll->getName(), filename);
  259. //CUT Std::messageBox(s, "Duplicate component guid", MB_OK);
  260. return FALSE;
  261. }
  262. endfor
  263. // ok
  264. return TRUE;
  265. }
  266. WaComponent *ComponentManager::enumComponent(int component) {
  267. if (component < 0 || component >= components.getNumItems()) return NULL;
  268. return components[component]->wac;
  269. }
  270. void ComponentManager::loadAll(const wchar_t *path) {
  271. #if 0//CUT
  272. static const char *loadorder[] = {
  273. "wasabi.system/pngload.wac",
  274. "wasabi.player/core.wac",
  275. "metrics.wac", // so metrics dialog appears before the splash screen
  276. "winamp/winamp.wac", // so splash screen displays right after startup
  277. "winamp/pledit.wac",
  278. "winamp/library.wac",
  279. "preferences.wac", // so prefs has the system groups at the top
  280. "skinswitch.wac", // so skinswitch is the first non internal prefs screen, ignored if not present. fucko: need to modify prefs system so we don't need to load in any particular order
  281. NULL
  282. };
  283. for (int i = 0; loadorder[i] != NULL; i++) {
  284. StringPrintf fn("%s%s%s", WACDIR, DIRCHARSTR, loadorder[i]);
  285. ComponentManager::load(fn);
  286. }
  287. #endif
  288. RecurseDir dir(path, L"*.*");// have to do *.* to get subdirs
  289. while (dir.next()) {
  290. StringPathCombine fn(dir.getPath(), dir.getFilename());
  291. const wchar_t *ext = Wasabi::Std::extension(fn);
  292. if (!WCSICMP(ext, L"wac"))
  293. ComponentManager::load(fn);
  294. }
  295. }
  296. void ComponentManager::postLoad(int f) { // two-level startup procedure
  297. // note we're calling the slot, not the component directly
  298. // allow punk-ass bitches to load early if need be
  299. foreach(components)
  300. if ((components.getfor()->loadearly = !!components.getfor()->wac->onNotify(WAC_NOTIFY_LOADEARLY))) {
  301. components.getfor()->registerServices();
  302. }
  303. endfor
  304. foreach(components)
  305. if (!components.getfor()->loadearly)
  306. components.getfor()->registerServices();
  307. endfor
  308. foreach(components)
  309. components.getfor()->onCreate();
  310. endfor
  311. if (f) ObjectTable::loadExternalClasses();
  312. }
  313. void ComponentManager::broadcastNotify(int cmd, int param1, int param2) {
  314. foreach(components)
  315. if ((components.getfor()->loadearly = !!components.getfor()->wac->onNotify(WAC_NOTIFY_LOADEARLY, cmd, param1, param2)))
  316. components.getfor()->wac->onNotify(cmd, param1, param2);
  317. endfor
  318. foreach(components)
  319. if (!components.getfor()->loadearly)
  320. components.getfor()->wac->onNotify(cmd, param1, param2);
  321. endfor
  322. }
  323. void ComponentManager::sendNotify(GUID guid, int cmd, int param1, int param2) {
  324. WaComponent *wac = getComponentFromGuid(guid);
  325. if (wac)
  326. wac->onNotify(cmd, param1, param2);
  327. }
  328. int ComponentManager::sendCommand(GUID guid, const wchar_t *command, int p1, int p2, void *ptr, int ptrlen) {
  329. if (command == NULL) return 0;
  330. WaComponent *wac = getComponentFromGuid(guid);
  331. if (wac) return wac->onCommand(command, p1, p2, ptr, ptrlen);
  332. return 0;
  333. }
  334. int ComponentManager::postCommand(GUID guid, const wchar_t *command, int p1, int p2, void *ptr, int ptrlen, int waitforanswer) {
  335. #ifdef WA3COMPATIBILITY // todo: make thread id part of application api
  336. if(Std::getCurrentThreadId()==Main::getThreadId() && waitforanswer) {
  337. // if it is already the main thread calling, just pass the command to sendCommand
  338. return sendCommand(guid,command,p1,p2,ptr,ptrlen);
  339. }
  340. #endif
  341. ComponPostEntry *cpe=new ComponPostEntry(guid,command,p1,p2,ptr,ptrlen,waitforanswer);
  342. componPostEntries.addItem(cpe);
  343. #ifdef WIN32
  344. #ifdef WA3COMPATIBILITY // todo: make this a call to application api
  345. PostMessage(Main::gethWnd(),UMSG_COMPON_POSTMESSAGE,0,0); // ask the main thread to call mainthreadpostCommands();
  346. #endif
  347. #else
  348. PostMessage(None,UMSG_COMPON_POSTMESSAGE,0,0); // ask the main thread to call mainthreadpostCommands();
  349. #endif
  350. if(waitforanswer) {
  351. while(!cpe->posted) Sleep(1);
  352. int res=cpe->result;
  353. componPostEntries.removeItem(cpe);
  354. delete(cpe);
  355. return res;
  356. }
  357. return 0; // cpe will get deleted by mainthreadpostCommands();
  358. }
  359. void ComponentManager::broadcastCommand(const wchar_t *command, int p1, int p2, void *ptr, int ptrlen) {
  360. if (command == NULL) return;
  361. for (int i = 0; i < components.getNumItems(); i++) {
  362. components[i]->wac->onCommand(command, p1, p2, ptr, ptrlen);
  363. }
  364. }
  365. int ComponentManager::getNumComponents() {
  366. return components.getNumItems();
  367. }
  368. GUID ComponentManager::getComponentGUID(int c) {
  369. if (c >= components.getNumItems()) return INVALID_GUID;
  370. return components[c]->guid;
  371. }
  372. const wchar_t *ComponentManager::getComponentName(GUID g)
  373. {
  374. WaComponent *wac = getComponentFromGuid(g);
  375. if (wac)
  376. return wac->getName();
  377. return NULL;
  378. }
  379. CfgItem *ComponentManager::getCfgInterface(GUID g) {
  380. WaComponent *wac = getComponentFromGuid(g);
  381. if (wac == NULL) return NULL;
  382. return wac->getCfgInterface(0);
  383. }
  384. WaComponent *ComponentManager::getComponentFromGuid(GUID g) {
  385. if (g == INVALID_GUID) return NULL;
  386. for (int i=0;i<components.getNumItems();i++) {
  387. if (g == components[i]->guid)
  388. return components[i]->wac;
  389. }
  390. return NULL;
  391. }
  392. void ComponentManager::mainThread_handlePostCommands() {
  393. // critical section
  394. for(int i=0;i<componPostEntries.getNumItems();i++) {
  395. ComponPostEntry *cpe=componPostEntries[i];
  396. if(!cpe->posted) {
  397. sendCommand(cpe->guid,cpe->command.getValue(),cpe->p1,cpe->p2,cpe->ptr,cpe->ptrlen);
  398. if(cpe->waitforanswer) cpe->posted=1;
  399. else {
  400. delete cpe;
  401. componPostEntries.removeByPos(i);
  402. i--;
  403. }
  404. }
  405. }
  406. }
  407. PtrList<ComponPostEntry> ComponentManager::componPostEntries;