Skip to main content

Notice

Please note that most of the software linked on this forum is likely to be safe to use. If you are unsure, feel free to ask in the relevant topics, or send a private message to an administrator or moderator. To help curb the problems of false positives, or in the event that you do find actual malware, you can contribute through the article linked here.
Topic: How does a plugin tell its version information? (Read 4455 times) previous topic - next topic
0 Members and 1 Guest are viewing this topic.

How does a plugin tell its version information?

Hey!

Today I've managed to write something that doesn't crash the player in C. It was all cool and fun to do that, but I still can't call it a plugin yet. I'm getting a popup message saying

Quote
Failed to load DLL: foo_test.dll
Reason: No version information found.


I found the DECLARE_COMPONENT_VERSION macro which declares a class named componentversion_myimpl and a variable called g_componentversion_myimpl_factory. But do I need to pass them to the player? How do I tell it the plugin's version and stuff?

Cheers!

 

How does a plugin tell its version information?

Reply #1
The version information is mandatory since the ability to check for component updates was added. The DECLARE_COMPONENT_VERSION macro creates an instance of a componentversion service implementation which is added to the list of service implementations exported by the component.

Do you really use C instead of C++?

How does a plugin tell its version information?

Reply #2
Thanks! I suspect the service implementation gets added somewhere at

Code: [Select]
static service_factory_single_t<componentversion_myimpl> g_componentversion_myimpl_factory;


But I might be wrong since my C++ knowledge is pretty low. I looked at the declarations of service_factory_single_t and service_impl_single_t, and there was really nothing interesting. Could you point me at the places where the magic happens that adds to and exports that list?

The player calls the only exported function, foobar2000_get_interface, first, then get_version and get_service_list methods of the foobar2000_client implementation. I have a feeling that the return value of get_service_list is exported services (possibly a linked list of them, I'm not sure as the documentation is so brief!), am I right? It's not clear to me how do the services get added though.

Quote
Do you really use C instead of C++?

Yes, and it's pure fun!

How does a plugin tell its version information?

Reply #3
You should not expect to have much luck using pretty much any part of the foobar2000 SDK from C.
It's all in glorious C++, and many aspects of it mandate inheriting from interfaces and instantiating factory templates with your types.
The only way you could use it from C is if someone makes limited and silly C-style bindings for a subset of the API.
Stay sane, exile.

How does a plugin tell its version information?

Reply #4
many aspects of it mandate inheriting from interfaces
You can program the virtual funtion pointer tables (vtables) by hand.
and instantiating factory templates with your types.
You can build the list of factory instances in the entry point function before you return it.

I think it is certainly possible even though it may be cumbersome. I remember some guys even had fun writing foobar2000 components in Pascal. Where it gets really tricky are the parts of the API that use C++ exceptions.

How does a plugin tell its version information?

Reply #5
Thanks! I suspect the service implementation gets added somewhere at
Yes, the constructor of the factory class does that. Constructors of global variables are run automatically by the C++ runtime, so by the time your component entry function accesses the list, the list already contains all the service factory instances [EDIT] if you use C++[/EDIT].

How does a plugin tell its version information?

Reply #6
Thanks a lot! Armed with a debugger I found the problem yesterday: I were providing the wrong GUID. foobar2000 tests each plugin for the entry point, player version compatibility, valid service list (singly linked), and finally scans the list for a service with m_guid == {10BB3EBD-DDF7-4975-A3CC-23084829453E}, which is obviosly GUID of componentversion.

The other problem I encountered was different calling convention. Methods (non-static only, as Wikipedia ensures) in Visual C++ are getting called using thiscall, i.e. `this` pointer is passed through ECX and the callee cleans the stack. I've been doing that using cdecl, breaking both rules. Luckily, GCC starting with version 4.6 provides __thiscall keyword, which seems to be compatible with VS's thiscall.

I'm now at the stage of implementing pfc::string_base. I'm going to post the code when the proof-of-concept is done, just for fun.

How does a plugin tell its version information?

Reply #7
Yes, you can implement a component by using a very small magnet too.
The presence and implementation of vtables is a compiler-specific thing, and is utterly undocumented in the compiler vendors documentation.
If this makes you feel happy, then do so, but for the love of $deity, don't ever release anything based on your reverse-engineered assumptions about the runtime implementation of VC++, because it _will_ be incompete and it _will_ ruin stability of end-user installations of foobar2000.

The last thing I need is to get component crash blame because someone else can't be arsed to use a language properly and instead build a false impression of it, smashing the integrity of the process.

Please, foosion, just because you _can_ implement runtime derivation of types and manual construction of symbols that mangle like C++ doesn't mean that it's remotely "writing components in C".

Your statements can and will be misconstrued by idiots everywhere, and they will fuck up.
Stay sane, exile.

How does a plugin tell its version information?

Reply #8
As for skink - beware of trying to making anything based on reverse-engineered implementation details.
That's in violation of the SDK license and will most probably lead to violent bannination of any released components.
Stay sane, exile.

How does a plugin tell its version information?

Reply #9
Yes, you can implement a component by using a very small magnet too.
The presence and implementation of vtables is a compiler-specific thing, and is utterly undocumented in the compiler vendors documentation.
If this makes you feel happy, then do so, but for the love of $deity, don't ever release anything based on your reverse-engineered assumptions about the runtime implementation of VC++, because it _will_ be incompete and it _will_ ruin stability of end-user installations of foobar2000.

The last thing I need is to get component crash blame because someone else can't be arsed to use a language properly and instead build a false impression of it, smashing the integrity of the process.

Please, foosion, just because you _can_ implement runtime derivation of types and manual construction of symbols that mangle like C++ doesn't mean that it's remotely "writing components in C".

Your statements can and will be misconstrued by idiots everywhere, and they will fuck up.


FWIW, Clang tries to be as much compatible with VS as the patents allow that: https://github.com/llvm-mirror/clang/blob/m...ableBuilder.cpp Apart from the Clang source and VC++ ABI documentation, there are a few articles about reverse-engineering the ABI in the Web. Finally, we all surely know two useful flags: /d1reportAllClassLayout and /d1reportSingleClassLayoutXXXX!

These methods (especially the last one) should be enough for building a stable component for foobar2000 in C. If, for any reason, the ABI changes, either *all* newly built or *all* old plugins will be incompatible with the player, no matter in what language they were written. That's the weak part of the SDK - a C ABI or even COM ABI wouldn't cause this problem. From the top of my head, I could name a foobar2000 component which crashes constantly. Written in C++.

Thanks for calling me an idiot :-) After all, I didn't force anyone to do same thing, neither I did distribute anything. I were just seeking help here.

How does a plugin tell its version information?

Reply #10
Zao: I agree that "technically possible" and "recommendable" are two different things for exactly the reasons you and skink have mentioned. If someone - like skink - seeks a challenge for his or her personal amusement and education, I don't have a problem with that.

I also did not have the impression that skink was interested in making a full-blown component and release it to the public. Even though most obstables can be overcome some way or another, re-implementing a sufficiently large subset of the foobar2000 SDK eventually gets rather tedious and boring because it is repetitive work.