|
|
Line 20: |
Line 20: |
|
| |
|
| Register a forum account and contact [https://hydrogenaud.io/index.php?action=profile;u=84 Peter] with info about your component. | | Register a forum account and contact [https://hydrogenaud.io/index.php?action=profile;u=84 Peter] with info about your component. |
|
| |
| == Services ==
| |
| A service type is an interface class, deriving directly or indirectly from service_base class. A service type class must not have any data members; it can only provide virtual methods (to be overridden by service implementation), helper non-virtual methods built around virtual methods, static helper methods, and constants / enums. Each service interface class must have a static class_guid member, used for identification when enumerating services or querying for supported functionality. A service type declaration should declare a class with public virtual/helper/static methods, and use <code>FB2K_MAKE_SERVICE_INTERFACE() / FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT()</code> macro to implement standard service behaviors for the class; additionally, class_guid needs to be defined outside class declaration (e.g. <code>const GUID someclass::class_guid = {….};</code> ). Note that most of components will not declare their own service types, they will only implement existing ones declared in the SDK.
| |
|
| |
| A service implementation is a class derived from relevant service type class, implementing virtual methods declared by service type class. Note that service implementation class does not implement virtual methods declared by service_base; those are implemented automatically.
| |
|
| |
| You cannot directly instantiate a service implementation object because it's still missing virtual methods of service_base.
| |
|
| |
| <pre>
| |
| class myworker : public threaded_process_callback { /* threaded_process_callback methods overridden here */ };
| |
| auto obj = new myworker; // error
| |
| auto obj = fb2k::service_new<myworker>(); // good
| |
| service_ptr_t<myworker> obj = new service_impl_t<myworker>; // longer equivalent of fb2k::service_new<>, commonly used in older code, not auto-friendly
| |
| </pre>
| |
|
| |
| fb2k::service_new<> takes care of implementing common methods (service_base) needed by all services and returns an autopointer object that manages reference counting for you.
| |
|
| |
| Note that service_base methods:
| |
| * <code>service_add_ref()</code>
| |
| * <code>service_release()</code>
| |
| * <code>service_query()</code>
| |
| ... are only intended for autopointer classes and should never be called directly in your code.
| |
|
| |
| See also: [[Foobar2000:Development:Auto Pointers|Auto Pointers]]
| |
|
| |
| == Entrypoint services ==
| |
| An entrypoint service type is a special case of a service type that can be registered using service_factory templates, and then accessed from any point of service system (excluding DLL startup/shutdown code, such as code inside static object constructors/destructors). An entrypoint service type class must directly derive from service_base.
| |
|
| |
| Registered entrypoint services can be accessed using:
| |
|
| |
| * For services types with variable number of implementations registered:
| |
| * <code>enumerate()</code> static methods of the service class>
| |
| <pre>
| |
| for( auto ptr : someclass::enumerate() ) { /* do stuff with ptr */ }
| |
| </pre>
| |
| * Or, <code>service_enum_t<></code>, commonly used in older code:
| |
| <pre>
| |
| service_enum_t<someclass> e; service_ptr_t<someclass> ptr; while(e.next(ptr)) ptr->dosomething();
| |
| </pre>
| |
| * For services types with a single always-present implementation registered - such as core services like playlist_manager - using someclass::get(), e.g.:
| |
| <pre>
| |
| auto api = someclass::get(); api->dosomething(); api->dosomethingelse();
| |
| </pre>
| |
|
| |
| Using per-service-type defined static helper functions, e.g. <code>someclass::g_dosomething()</code> - those use relevant service enumeration methods internally.
| |
| An entrypoint service type must use <code>FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT()</code> macro to implement standard entrypoint service behaviors, as opposed to all other service types that use <code>FB2K_MAKE_SERVICE_INTERFACE()</code> macro instead.
| |
|
| |
| You can register your own entrypoint service implementations using <code>FB2K_SERVICE_FACTORY()</code> macro. It creates a static instance of your object and makes it available for everyone else to enumerate and access.
| |
| Some services need to be registered differently, see documentation of individual services for details.
| |
|
| |
| A typical entrypoint service implementation looks like this:
| |
| <pre>
| |
| class myinitquit : public initquit {
| |
| public:
| |
| void on_init() override {};
| |
| void on_quit() override {};
| |
| };
| |
| FB2K_SERVICE_FACTORY(myinitquit);
| |
| </pre>
| |
|
| |
| == Exception use ==
| |
| Most of API functions use C++ exceptions to signal failure conditions. All used exception classes must derive from <code>std::exception</code>; this design allows various instances of code to use single <code>catch()</code> line to obtain human-readable description of the problem to display.
| |
|
| |
| Additionally, special subclasses of exceptions are defined for use in specific conditions, such as <code>exception_io</code> for I/O failures. As a result, you must provide an exception handler whenever you invoke any kind of I/O code that may fail, unless in specific case calling context already handles exceptions (e.g. input implementation code - any exceptions should be forwarded to calling context, since exceptions are a part of input API).
| |
|
| |
| Implementations of global callback services such as <code>playlist_callback</code>, <code>playback_callback</code> or <code>library_callback</code> must not throw unhandled exceptions; behaviors in case they do are undefined (app termination is to be expected).
| |
|
| |
| == Storing configuration ==
| |
|
| |
| In order to create your entries in the foobar2000 configuration files, you must instantiate some objects that derive from <code>cfg_var</code> class. Those can be either predefined classes (<code>cfg_int</code>, <code>cfg_string</code>, etc) or your own classes implementing relevant methods.
| |
|
| |
| Each <code>cfg_var</code> instance has a GUID assigned, to identify its configuration file entry. The GUID is passed to its constructor (which implementations must take care of, typically by providing a constructor that takes a GUID and forwards it to <code>cfg_var</code> constructor).
| |
|
| |
| Note that <code>cfg_var</code> objects can only be instantiated statically (either directly as static objects, or as members of other static objects).
| |
|
| |
| It is encouraged to create your own configuration files in foobar2000 profile for more complex data to allow easy import / export / backup.
| |
|
| |
|
| == Further reading == | | == Further reading == |
Line 101: |
Line 25: |
| * [[Foobar2000:Development:Auto Pointers|Auto Pointers]] | | * [[Foobar2000:Development:Auto Pointers|Auto Pointers]] |
| * [[Foobar2000:Development:Debugging|Debugging]] | | * [[Foobar2000:Development:Debugging|Debugging]] |
| | * [[Foobar2000:Development:Exceptions|Exceptions]] |
| * [[Foobar2000:Development:Global Callbacks|Global Callbacks: tracking foobar2000 lifetime events]] | | * [[Foobar2000:Development:Global Callbacks|Global Callbacks: tracking foobar2000 lifetime events]] |
| | * [[Foobar2000:Development:Services|Services]] |
| | * [[Foobar2000:Development:Storing Configuration|Storing Configuration]] |
| * [[Foobar2000:Development:Threads|Threads]] | | * [[Foobar2000:Development:Threads|Threads]] |
What is a component
A foobar2000 component is a Windows Dynamic Link Library (DLL) extending the functionality of the foobar2000 application.
A foobar2000 component implements one or more entrypoint services and interacts with services provided by foobar2000 core or other components.
Each component has a single exported DLL function, foobar2000_get_interface()
, called on startup to initialize and discover entrypoint services your component. This function is generated automatically by the foobar2000_component_client module. Do not implement it yourself.
Packaging a component
Components are delivered to the user in form of fb2k-component file.
This is simply a renamed zip of your DLL.
If your component requires additional files, include them in the zip; foobar2000 will extract them to the folder containing your DLL upon installation.
Getting a component listed on foobar2000.org/components
Register a forum account and contact Peter with info about your component.
Further reading