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/replicant/component | |
parent | 537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff) | |
download | winamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz |
Initial community commit
Diffstat (limited to 'Src/replicant/component')
-rw-r--r-- | Src/replicant/component/ComponentManagerBase.cpp | 224 | ||||
-rw-r--r-- | Src/replicant/component/ComponentManagerBase.h | 43 | ||||
-rw-r--r-- | Src/replicant/component/ifc_component.h | 95 | ||||
-rw-r--r-- | Src/replicant/component/ifc_component_sync.h | 22 | ||||
-rw-r--r-- | Src/replicant/component/win/ComponentManager.cpp | 88 | ||||
-rw-r--r-- | Src/replicant/component/win/ComponentManager.h | 12 |
6 files changed, 484 insertions, 0 deletions
diff --git a/Src/replicant/component/ComponentManagerBase.cpp b/Src/replicant/component/ComponentManagerBase.cpp new file mode 100644 index 00000000..d375f088 --- /dev/null +++ b/Src/replicant/component/ComponentManagerBase.cpp @@ -0,0 +1,224 @@ +#include "ComponentManagerBase.h" +#include "foundation/error.h" +#include "nx/nxuri.h" + +ComponentManagerBase::ComponentManagerBase() +{ + phase=PHASE_INITIALIZE; + service_api=0; + component_sync=0; + framework_guid = INVALID_GUID; + application_guid = INVALID_GUID; +} + +int ComponentManagerBase::LateLoad(ifc_component *component) +{ + int ret; + + if (phase >= PHASE_REGISTERED) + { + ret = component->RegisterServices(service_api); + if (ret != NErr_Success) + { + int ret2 = component->Quit(service_api); + if (ret2 == NErr_TryAgain) + { + component_sync->Wait(1); + } + return ret; + } + } + + if (phase >= PHASE_LOADING) + { + ret = component->OnLoading(service_api); + if (ret != NErr_Success) + { + int ret2 = component->Quit(service_api); + if (ret2 == NErr_TryAgain) + { + component_sync->Wait(1); + } + return ret; + } + } + + if (phase >= PHASE_LOADED) + { + ret = component->OnLoaded(service_api); + if (ret != NErr_Success) + { + int ret2 = component->Quit(service_api); + if (ret2 == NErr_TryAgain) + { + component_sync->Wait(1); + } + return ret; + } + } + return NErr_Success; +} + +void ComponentManagerBase::SetServiceAPI(api_service *_service_api) +{ + this->service_api = _service_api; + service_api->QueryInterface(&component_sync); +} + +int ComponentManagerBase::Load() +{ + if (phase != PHASE_INITIALIZE) + return NErr_Error; + + int ret; + + /* RegisterServices phase */ + for (ComponentList::iterator itr=components.begin();itr!=components.end();) + { + ifc_component *component = *itr; + //ComponentList::iterator next=itr; + //next++; + ret = component->RegisterServices(service_api); + if (ret != NErr_Success) + { + int ret2 = component->Quit(service_api); + if (ret2 == NErr_TryAgain) + { + component_sync->Wait(1); + } + NXURIRelease(component->component_info.filename); + CloseComponent(component); + itr = components.erase(itr); + } + else + { + itr++; // = next; + } + } + + phase = PHASE_REGISTERED; + + /* OnLoading phase */ + for (ComponentList::iterator itr=components.begin();itr!=components.end();) + { + ifc_component *component = *itr; + //ComponentList::iterator next=itr; + //next++; + ret = component->OnLoading(service_api); + if (ret != NErr_Success) + { + int ret2 = component->Quit(service_api); + if (ret2 == NErr_TryAgain) + { + component_sync->Wait(1); + } + NXURIRelease(component->component_info.filename); + CloseComponent(component); + itr = components.erase(itr); + } + else + { + itr++; // = next; + } + } + + phase = PHASE_LOADING; + + /* OnLoaded phase */ + for (ComponentList::iterator itr = components.begin(); itr != components.end();) + { + ifc_component* component = *itr; + //ComponentList::iterator next = itr; + //next++; + ret = component->OnLoaded(service_api); + if (ret != NErr_Success) + { + int ret2 = component->Quit(service_api); + if (ret2 == NErr_TryAgain) + { + component_sync->Wait(1); + } + NXURIRelease(component->component_info.filename); + CloseComponent(component); + itr = components.erase(itr); + } + else + { + itr++; // = next; + } + } + + phase = PHASE_LOADED; + + return NErr_Success; +} + +int ComponentManagerBase::AddComponent(ifc_component *component) +{ + int err; + + if (NULL == component) + return NErr_BadParameter; + + if (phase > PHASE_LOADED) + return NErr_Error; + + if (component->component_info.wasabi_version != wasabi2_component_version + || component->component_info.nx_api_version != nx_api_version + || component->component_info.nx_platform_guid != nx_platform_guid) + { + return NErr_IncompatibleVersion; + } + + if (component->component_info.framework_guid != INVALID_GUID + && framework_guid != component->component_info.framework_guid) + { + return NErr_IncompatibleVersion; + } + + if (component->component_info.application_guid != INVALID_GUID + && application_guid != component->component_info.application_guid) + { + return NErr_IncompatibleVersion; + } + + for (ComponentList::iterator itr = components.begin(); itr != components.end(); itr++) + { + ifc_component *registered_component = *itr; + if (registered_component->component_info.component_guid == component->component_info.component_guid) + return NErr_Error; + } + + err = component->Initialize(service_api); + if (NErr_Success != err) + return err; + + /* if the component was added late, we'll need to run some extra stages */ + err = LateLoad(component); + if (NErr_Success != err) + return err; + + components.push_back(component); + + return NErr_Success; +} + +void ComponentManagerBase::SetFrameworkGUID(GUID guid) +{ + framework_guid = guid; +} + +GUID ComponentManagerBase::GetFrameworkGUID() +{ + return framework_guid; +} + +void ComponentManagerBase::SetApplicationGUID(GUID guid) +{ + application_guid = guid; +} + +GUID ComponentManagerBase::GetApplicationGUID() +{ + return application_guid; +} diff --git a/Src/replicant/component/ComponentManagerBase.h b/Src/replicant/component/ComponentManagerBase.h new file mode 100644 index 00000000..9559a3dd --- /dev/null +++ b/Src/replicant/component/ComponentManagerBase.h @@ -0,0 +1,43 @@ +#pragma once +#include "nx/nxuri.h" +#include "service/api_service.h" +#include "component/ifc_component.h" +#include <deque> +#include "component/ifc_component_sync.h" + +class ComponentManagerBase +{ +public: + void SetServiceAPI(api_service *service_api); + int Load(); + + void SetFrameworkGUID(GUID guid); + GUID GetFrameworkGUID(); + void SetApplicationGUID(GUID guid); + GUID GetApplicationGUID(); + + virtual int AddComponent(ifc_component *component); + +protected: + ComponentManagerBase(); + int LateLoad(ifc_component *mod); + enum Phase + { + PHASE_INITIALIZE=0, /* components are still being added */ + PHASE_REGISTERED=1, /* RegisterServices() has been called on all components */ + PHASE_LOADING=2, /* OnLoading() has been called on all components */ + PHASE_LOADED=3, /* OnLoaded() has been called on all components */ + }; + Phase phase; + typedef std::deque<ifc_component*> ComponentList; + ComponentList components; + api_service *service_api; + ifc_component_sync *component_sync; + + GUID framework_guid; + GUID application_guid; + +private: + /* your implementation needs to override this. You should call FreeLibrary(component->component_info.hModule); or dlclose(component->component_info.dl_handle); or similar */ + virtual void CloseComponent(ifc_component *component)=0; +}; diff --git a/Src/replicant/component/ifc_component.h b/Src/replicant/component/ifc_component.h new file mode 100644 index 00000000..370c4580 --- /dev/null +++ b/Src/replicant/component/ifc_component.h @@ -0,0 +1,95 @@ +#pragma once +#include "foundation/dispatch.h" +#include "service/api_service.h" + +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include <windows.h> +#endif + +#ifdef __APPLE__ +#include <CoreFoundation/CoreFoundation.h> /* for CFBundleRef */ +#endif + +#include "nx/nxapi.h" +#include "nx/nxuri.h" + + +/* see http://wiki.office.aol.com/wiki/Replicant/Component */ + +/* in very rare cases, this will get incremented */ +const int wasabi2_component_version = 0; + +struct WasabiComponentInfo +{ + /* these will be filled in by the host application loading your component */ +#if defined(_WIN32) + HMODULE hModule; +#elif defined(__APPLE__) + /* depending on whether your component is a bundle or a dylib, one of these will be filled */ + CFBundleRef bundle; + void *dl_handle; // pointer returned from dlopen +#else + void *dl_handle; // pointer returned from dlopen +#endif + nx_uri_t filename; + + /* these are filled in during ifc_component's constructor. You don't need to change these */ + int wasabi_version; /* major breaking changes to Wasabi (ABI changes, Dispatchable definition, etc) will change this. This is used to filter out components that are expecting something completely different than what the host API provides */ + int nx_api_version; /* major breaking changes to the NX API will change this. */ + GUID nx_platform_guid; /* platform that this is meant to link against. right now this mainly helps avoid loading android components on 'vanilla' linux, and vice-versa */ + + /* these are defaulted to INVALID_GUID. You can optionally override these in your Component's constructor */ + GUID component_guid; /* a unique identifier for your Component */ + GUID framework_guid; /* optionally set to the framework that your component is meant to work in. Can optionally be used as a filter by the Component Manager. This avoids loading, e.g., a replicant component on some completely different Wasabi-based framework */ + GUID application_guid; /* if your component is meant to work with a specific application, you can define it here. Can optionally be used as a filter by the Component Manager. */ +}; + +class NOVTABLE ifc_component : public Wasabi2::Dispatchable + //public wa::lists::node_ptr /* this is for internal use by the Component Manager! */ +{ +protected: + ifc_component(GUID component_guid) : Wasabi2::Dispatchable(DISPATCHABLE_VERSION) + { + memset(&component_info, 0, sizeof(component_info)); /* memsetting the whole thing avoids a bunch of ifdef code */ + component_info.wasabi_version = wasabi2_component_version; + component_info.nx_api_version = nx_api_version; + component_info.nx_platform_guid = nx_platform_guid; + component_info.component_guid = component_guid; + } + ~ifc_component() {} +public: + WasabiComponentInfo component_info; /* it's unusual for an interface to have data members, but this makes thing convienent */ + + int Initialize(api_service *_service_manager) { return Component_Initialize(_service_manager); } + int RegisterServices(api_service *_service_manager) { return Component_RegisterServices(_service_manager); } + int OnLoading(api_service *_service_manager) { return Component_OnLoading(_service_manager); } + int OnLoaded(api_service *_service_manager) {return Component_OnLoaded(_service_manager); } + + int OnClosing(api_service *_service_manager) { return Component_OnClosing(_service_manager); } + void DeregisterServices(api_service *_service_manager) { Component_DeregisterServices(_service_manager); } + int OnClosed(api_service *_service_manager) { return Component_OnClosed(_service_manager); } + int Quit(api_service *_service_manager) { return Component_Quit(_service_manager); } + + enum + { + DISPATCHABLE_VERSION, + }; +private: + /* these 4 will get called in sequence during component load, see http://wiki.office.aol.com/wiki/Replicant/Component for details */ + // TODO: get rid of default implementations, eventually + virtual int WASABICALL Component_Initialize(api_service *_service_manager) { return NErr_Success; } + virtual int WASABICALL Component_RegisterServices(api_service *_service_manager)=0; + virtual int WASABICALL Component_OnLoading(api_service *_service_manager) { return NErr_Success; } + virtual int WASABICALL Component_OnLoaded(api_service *_service_manager) { return NErr_Success; } + + virtual int WASABICALL Component_OnClosing(api_service *_service_manager) { return NErr_Success; } + virtual void WASABICALL Component_DeregisterServices(api_service *_service_manager)=0; + virtual int WASABICALL Component_OnClosed(api_service *_service_manager) { return NErr_Success; } + virtual int WASABICALL Component_Quit(api_service *_service_manager) { return NErr_Success; } +}; + + +extern "C" typedef ifc_component *(*GETCOMPONENT_FUNC)(); diff --git a/Src/replicant/component/ifc_component_sync.h b/Src/replicant/component/ifc_component_sync.h new file mode 100644 index 00000000..3e0bb74c --- /dev/null +++ b/Src/replicant/component/ifc_component_sync.h @@ -0,0 +1,22 @@ +#pragma once +#include "foundation/dispatch.h" + +// {667F8818-AECD-4017-80EE-C43E096E68C1} +static const GUID ifc_component_sync_interface_guid = +{ 0x667f8818, 0xaecd, 0x4017, { 0x80, 0xee, 0xc4, 0x3e, 0x9, 0x6e, 0x68, 0xc1 } }; + +class ifc_component_sync : public Wasabi2::Dispatchable +{ +protected: + ifc_component_sync() : Wasabi2::Dispatchable(DISPATCHABLE_VERSION) {} + ~ifc_component_sync() {} +public: + static GUID GetInterfaceGUID() { return ifc_component_sync_interface_guid; } + int Wait(size_t count) { return ComponentSync_Wait(count); } + enum + { + DISPATCHABLE_VERSION=0, + }; +private: + virtual int WASABICALL ComponentSync_Wait(size_t count)=0; +}; diff --git a/Src/replicant/component/win/ComponentManager.cpp b/Src/replicant/component/win/ComponentManager.cpp new file mode 100644 index 00000000..ff36fa38 --- /dev/null +++ b/Src/replicant/component/win/ComponentManager.cpp @@ -0,0 +1,88 @@ +#include "ComponentManager.h" +#include "foundation/error.h" +#include "nx/nxuri.h" + +int ComponentManager::AddComponent(nx_uri_t filename) +{ + if (phase > PHASE_LOADED) + return NErr_Error; + + HMODULE hLib = LoadLibraryW(filename->string); + if (hLib) + { + GETCOMPONENT_FUNC pr = (GETCOMPONENT_FUNC)GetProcAddress(hLib, "GetWasabi2Component"); + if (pr) + { + ifc_component *component = pr(); + if (component) + { + if (component->component_info.wasabi_version != wasabi2_component_version + || component->component_info.nx_api_version != nx_api_version + || component->component_info.nx_platform_guid != nx_platform_guid) + { + FreeLibrary(hLib); + return NErr_IncompatibleVersion; + } + + component->component_info.hModule = hLib; + component->component_info.filename = NXURIRetain(filename); + int ret = component->Initialize(service_api); + if (ret != NErr_Success) + { + NXURIRelease(component->component_info.filename); + FreeLibrary(hLib); + return ret; + } + + /* if the component was added late, we'll need to run some extra stages */ + ret = LateLoad(component); + if (ret != NErr_Success) + { + NXURIRelease(component->component_info.filename); + FreeLibrary(hLib); + return ret; + } + + components.push_back(component); + return NErr_Success; + } + } + return NErr_Error; + } + else + { + return NErr_FileNotFound; + } +} + +int ComponentManager::AddDirectory(nx_uri_t directory) +{ + WIN32_FIND_DATAW find_data = {0}; + + nx_uri_t directory_mask; + int ret = NXURICreateFromPath(&directory_mask, L"*.w6c", directory); + if (ret != NErr_Success) + return ret; + + HANDLE find_handle = FindFirstFileW(directory_mask->string, &find_data); + if (find_handle != INVALID_HANDLE_VALUE) + { + do + { + nx_uri_t w6c_filename; + if (NXURICreateFromPath(&w6c_filename, find_data.cFileName, directory) == NErr_Success) + { + AddComponent(w6c_filename); + NXURIRelease(w6c_filename); + } + } + while (FindNextFileW(find_handle,&find_data)); + FindClose(find_handle); + } + return NErr_Success; +} + +void ComponentManager::CloseComponent(ifc_component *component) +{ + FreeLibrary(component->component_info.hModule); +}
\ No newline at end of file diff --git a/Src/replicant/component/win/ComponentManager.h b/Src/replicant/component/win/ComponentManager.h new file mode 100644 index 00000000..9bc45245 --- /dev/null +++ b/Src/replicant/component/win/ComponentManager.h @@ -0,0 +1,12 @@ +#pragma once +#include "../ComponentManagerBase.h" + +class ComponentManager : public ComponentManagerBase +{ +public: + int AddComponent(nx_uri_t filename); + int AddDirectory(nx_uri_t directory); + +private: + void CloseComponent(ifc_component *component); +};
\ No newline at end of file |