VFS plugin for dynamic collection of files

I'm trying to create a VFS which will represent a dynamic and constantly changing set of images (beyond the capabilities of a static coll://)

I have it hooked up to the point I can view an image, from my VFS, inside the built-in internal viewer frame. I want to extend this to be compatible with d8viewer.exe but am failing. I can reroute VFS_ContextVerb via VFSCVRES_CHANGE but this just opens the image off local disk. d8viewer.exe seems to have no sense of the "collection" at that point like col:// does. How does d8viewer.exe limit itself to the files in the col:// ? Somehow you guys make that work.

Additionally, if I try to open my VFS directly from d8viewer.exe, I.e., d8viewer.exe "mycol://" I can trace the calls:


But nothing happens, d8viewer silently exits. What are you looking for with these VFSPROP_FUNCAVAILABILITY calls? I.e., what does d8viewer.exe want to get back to start showing images from the VFS? I return true for VFSPROP_SHOWPICTURESDIRECTLY, for VFS_GetLastError I say ERROR_NO_MORE_FILES

Also, it never calls VFS_ReadFile. Is that because it thinks something has gone wrong? What are the failure cases that would stop it from calling VFS_ReadFile ?


All d8viewer.exe does is send a message to Opus passing the supplied command line along. It doesn't have any internal logic of its own and doesn't know anything about collections etc. itself.

When Opus gets the message it converts it into the command show file="<filename>" listsiblings. The outcome of that should be exactly the same as running that command direct from an Opus button.

Thanks for the clarification. It's strange that I can get the image to display on the internal viewer frame and I can even get the lister to show the image in thumbnail mode... But when I run "SHOW" on the image it consistently crashes opus to the desktop.

Right when I run SHOW it queries VFSPROP_SHOWPICTURESDIRECTLY and I respond true. The only dependencies for showing pictures directly is VFS_CreateFile and VFS_ReadFile and we know I have those working because they are used by the internal viewer and in the thumbnail calls.

I must be missing something

You're saying Opus actually crashes when you do that?

Can you provide us with your plugin DLL so we can debug it at our end?

Ya I just rebooted to make sure things weren't in a strange state and I can crash it right off the bat after rebooting. If I debugger attach the process it doesn't appear to be in my code cause it can't inspect... but don't get me wrong I'm sure I'm to blame.


Let me know how to send it I can give you the whole Visual C++ sln along with the DLL

Zip it up and email it to crashdumps@gpsoft.com.au is the best way.

Thanks it's sent.

Thanks for that. I don't see a crash here when I try it. I traced it through to see where the Show function is failing and it seems to be because you don't implement either VFS_GetFileAttr() or VFS_GetFileInformation(). The Show function uses one or other of those to check that the file it's about to load actually exists. Maybe try implementing one of them and see if it gets any further!

Ya that solved it. I just hooked up VFS_GetFileAttrW and hardcoded it to return true and Show started working. In my defense the very last paragraph of the SDK manual indicates that VFSPROP_SHOWPICTURESDIRECTLY only has a dependency on CreateFile and ReadFile... but other parts of the manual do mention hooking up Attr and Information.

I'm not sure what the crashing was all about but I'm sure I'm corrupting memory somewhere.

Thanks for your help!

No worries, let us know if you need any other info.

Thanks everything is going great. My VFS can render directories and lots of files now.

I do have another question. If I create a simple collection, called coll://abc

Where is it getting the information for the Location column from? I.e., it knows the true path of these files on disk instead of referencing coll://abc. In my VFS, the Location field is populated as "mycoll://" but I'd like it to be the true paths just as coll:// does.

This is probably the same question, but if I select aaa.jpg in the coll://abc collection and run "Clipboard COPYNAMES" it will copy "D:\Pictures\aaa.jpg" to the clipboard. How does it know that? If I do the same thing in my VFS, it copies something like "mycoll://aaa.jpg". I'd like my VFS to behave just like coll:// does, I.e., know the true paths not reference VFS paths.


Some things may not be possible for a plugin to do, as we have a lot of internal code specific to our own collections.

You can try returning the (undocumented) capability flag (1uLL << 12) from VFS_GetCapabilities(). If that's set then Opus should call your VFS_GetPathDisplayNameW() function for the Location field, which will let you return the true location.

Thanks for sharing that trick!

Hi @Jon I have run into a bit of trouble. For dwCapabilities I am setting:


But Opus does not seem to want to respect VFSCAPABILITY_MOVEBYRENAME. If I move a file from one folder to another, it will invoke a copy/write operation by reading the old file and then opening the new file for write.

I know I have VFS_MoveFileW hooked up because it will call it if I rename a file in the same directory. Can you check that VFSCAPABILITY_MOVEBYRENAME is respected for moving files from one folder to another and let me know if there are any hidden dependencies which will cause it not to be used and fall back to creating a copy instead?


At the moment it doesn't seem like there's a way to make this work for plugins sorry; it's calling a different function that currently isn't exported in the plugin API. We'll add it in the next update.

Thank you for looking into it and letting me know. I feel like an explorer pushing the boundaries of what people have tried with VFS.

I look forward to the update where this is available!


Hi Jon. I'll report this because it is a very strange behavior but a low priority to fix because I think I can work around it.

While viewing an image off my VFS in the standalone viewer, if I bind a key to run a script such as "python C:\myscript.py {filepath}", instead of {filepath} being something relative to my VFS, it is:


If I change {filepath} to {sourcepath}, I can see a valid path relative to my VFS, I.e.,


So I figured I could work around this by using some combination of {sourcepath}/{file} but the very strange thing is that the presence of {file} in the arguments changes the result of {sourcepath}. If {file} is present in the command, {sourcepath} becomes:


I have worked around all of that by switching to VBScript and using:


This correctly extracts the fullpath filename, relative to my VFS, which was being viewed.

External programs usually won't know how to handle VFS paths (they can't talk to the VFS plugin) so Opus normally extracts files to a temp directory and passes those to the external program.

What is your aim when sending the filepath to Python? Is it running a script that knows how to interpret the VFS paths? Or is it just doing something to the file at the end of the path?

Is the aim to send it the file's real path, not the VFS plugin path or a temp file?

Hi Leo. The python code is constructing all of the content inside the VFS so it knows all about the paths involved. I want to pass it the VFS path, which I can do with the VBScript code which is a suitable workaround. I just thought the interaction of {sourcepath} and {file} was inconsistent.

In that case, you can use the @nolocalizefiles modifier to disable automatic extraction when using things like {filepath}.

The way it works is by design and consistent with what it aims to do.

  • {sourcepath} on its own wouldn't make sense to convert into a temp directory, since it'd just be an empty temp dir. Any program which acts on a folder, rather than a file, is not going to be able to work on a folder within a VFS unless it understands the VFS.

  • {file} is always the filename on its own, which never changes.

  • Joining {sourcepath} and {file} together just joins two together, whatever they are.

    (Note that {sourcepath}{file} is not always the same as {filepath}, even for normal folders, because you may be in Flat View, where the files are not directly below {sourcepath}, or a Collection where they are not really below it at all.)

  • {filepath} gets you the path to the file, which will trigger automatic extraction to temp when passing it to external programs, unless it is suppressed.

Suppression can be done via @nolocalizefiles for individual buttons, or by the VFS plugin universally. But if you do it via the plugin then it would happen all the time, which you probably don't want.