Instead of using DllMain, use the VFS_Init and VFS_Uninit functions which Opus will call. Note that they are ref-counted. See this post for more details..
DllMain is a bad place to do things beause you're not allowed to call most APIs from within DllMain. You can create and destroy critical sections there, but not much else. (Unfortunately, Microsoft don't provide a proper list of what you can and cannot do, but if it involves an Windows API call, or calling anything else which might call an API, then it's probably not allowed, with a handful of exceptions. The MSDN docs on DllMain have a bit more info but the best guidance I know of is in a series of blog posts by Raymond Chen and Larry Osterman.)
Frequent loading and unloading can happen. If a plugin is not used for about 10 minutes then Opus may unload it. I think during startup Opus will also always load, unload and then reload plugins, due to a quirk in how we do things. So it's best to design the plugins so they can be loaded and unloaded quickly.
If it is a problem then we may be able to provide a way for a plugin to say "never unload me," but if it's doing something time consuming when it is loaded then that will still slow-down launching Opus at least, so it would always be better if loading can be made as fast as possible (e.g. by caching data).
As an example unrealted to plugins, when Opus loads an IconSet for the first time, it converts it into a format which can be loaded much quicker and saves the converted copy in a cache folder. Creating the cached version actually increases the amount of time it takes to load the IconSet for the first time, but after that one-off hit the IconSet can be loaded very quickly directly from the cache. (Of course, it also checks that date on the real icon set so that if it changes, the cached version is thrown away and re-created.)
At the same time, don't "prematurely optimise." For example, most of my plugins load and parse an XML config file whenever they are loaded and I worried that slow down startup, when sometimes the config is never even used. I thought about making the config load the first time it was actually needed, instead, but when I timed the startup, all the plugins put together spent an insignificant amount of time loading their configs. So I left things as they were, because the extra complexity (and potential bugs) would have been for nothing.
All of that sounds fine and shouldn't be a problem with the current API.
It may require a restart of Opus for new Pythyon VFS modules to be seen by Opus, but I'm guessing these won't be things that people add & remove throughout the day so that seems okay.
Opus can/will call your plugin even while the Preferences dialog is open. e.g. You can open Prefs and configure the 7z plugin, while still using a 7z archive in another window.
It's also possible for more than one plugin configuration window to be open at a time, FWIW. Or at least for the plugin to be asked to do that (it doesn't have to comply). (It's not easy to do via Preferences, but people can create buttons which open a particular plugin config dialogs, and then click the buttons from differnet windows.)
If it needs to, your plugin can choose to block those things from happening by detecting the situation and failing the API calls, but it's something you'd have to do in the plugin and Opus (by design) won't prevent it from happening.
Of course, this can lead to weird situations. If someone is in the middle of copying data out of a VFS plugin which they then disable, what should happen? That's up to you, really. With the archives plugin, I generally take the approach that if an operation has started then it should be able to finish, but there are some cases where you'll get an error message instead, which I think is fine. (People turning things on and off while those things are being used shouldn't be too surprised.)
Definitely, that should speed things up quite a bit.
I don't know how Python works internally, but even if the DLL has a distinct name, it could still conflict with another Python DLL loaded into the same process if they use named objects or similar.
If there's a worry about conflicts with other shell extensions etc. using different versions of the same DLLs/frameworks, I think it would be worth thinking about hosting Python and the scripts in a separate process, and writing an Opus VFS plugin which effectively proxies calls between Opus and that process. Doing that would also mean you can control when you are loaded and unloaded, since the process could choose to stay running when Opus unloads the plugin, and may give you more control over threading issues (if any).
Making things run out-of-process is extra work, but it's a lot easier to do if it's done from the start, rather than finding out later that it's a good idea and trying to retrofit it.
We usually put them in the same folder as the plugin itself.
If there are a lot of DLLs, it'd be better to put them in a subfolder to keep things tidy.
(Also, any .DLL file will be loaded by Opus to see if it is a plugin, so it's not great to put lots of extra files in the plugin dirs. Opus has a hardcoded "blacklist" of DLL names it knows are not worth loading, so we can add the Python DLLs to that if needed, but if there are a lot of them then putting them in a subdirectory would be better all round.)
Is changing the DLL path neccessary? If it's done incorrectly it can cause security/compatibility issues and is also difficult to do properly in multi-threaded apps like Opus (since the DLL path is shared by all threads), so it's best avoided (but sometimes can't be avoided, of course).
Normally, it's best to call LoadLibrary with the full path to a library, and well-written DLLs should be fine with that regardless of where the DLL path or current directory is at the time. (Not all DLLs are well-written, of course!)
Of course, if you host Python out-of-process (that is, in your own exe which the plugin talks to, rather than everything in dopus.exe itself) then many of these problems go away.
I'll be idling in #dopus on QuakeNet. (I'll have the channel minimized but hopefully the IRC client will properly highlight it if there's any activity. If not, nudge me with a private message. Or I may just be asleep or AFK. )
Using C++/CLI may make sense, if .Net stuff is looked at eventually. I used it briefly in the past for a similar task and it seemed to make it quite easy to bridge C++ into .Net (not surprising, really, hehe). It can also act as a thin layer which calls into the main C# code.
C++/CLI is much better than the older Managed C++, but of course still suffers from the fact that so few people use it and thus there aren't always good places to look for advice. This sort of thing is probably where it shines, though.