As a SoC project I'll try to improve the integration of wine with the Unix shells. My first step will be to implement the freedesktop.org Trash. I've written some code that doesn't add any new features but shows how I want to add it. I'd like to know if this is a good design? The main idea is not to hard-code one implementation of things like the Trash into shell32 - not everything is standardized by the freedesktop and even if it would this might not work on other systems like MacOS X. We should allow for many implementations. The correct one is loaded depending on a registry settings (so that a winecfg entry can be added). My implementation uses COM objects as it's standard dlls provides support for such tasks. Currently there is one interface (IWineShellIntegration) that acts as a factory for specialized objects. That could also be implemented using COM Aggregation - when we do that we could use QueryInterface instead of GetIntegrationObejct. Some COM objects can run in the address space of the calling process - e.g. the trash can be implemented like that. For others it would be a waist of resources (e.g. there is no need for every process to watch is the file associations have changed) - it's enough to load them only once. The explorer seems to be a good candidate to create such objects. In the attached patch there is one specialized interface - the IWineTrash. The SHELL_DeleteFile[AW] is patched to use it - it shows a different icon if the file can be trashed (these are not the correct icons as wine's shell32 uses a message box instead of a special dialog) and calls the trash method then. Currently there is only one built-in trash that can't trash anything. (note that SHELL_DeleteFile is called in the folders that are decendents of My Computer. If choose delete on a file that is a decendent of the '/', it will be deleted without a warning).
Mikolaj Zalewski
I think the general approach is good.
The way you handle the built in implementation seems odd to me. I think setting the registry key to make the freedesktop.org version as the default would be good enough.
I'm not convinced we need IWineShellIntegration. I think it would be cleaner to directly create an IWineTrash object.
/Ulrich
On Thu, Jun 01, 2006 at 10:12:12PM +0200, Miko??aj Zalewski wrote:
As a SoC project I'll try to improve the integration of wine with the Unix shells. My first step will be to implement the freedesktop.org Trash. I've written some code that doesn't add any new features but shows how I want to add it. I'd like to know if this is a good design? The main idea is not to hard-code one implementation of things like the Trash into shell32 - not everything is standardized by the freedesktop and even if it would this might not work on other systems like MacOS X. We should allow for many implementations. The correct one is loaded depending on a registry settings (so that a winecfg entry can be added). My implementation uses COM objects as it's standard dlls provides support for such tasks. Currently there is one interface (IWineShellIntegration) that acts as a factory for specialized objects. That could also be implemented using COM Aggregation - when we do that we could use QueryInterface instead of GetIntegrationObejct. Some COM objects can run in the address space of the calling process - e.g. the trash can be implemented like that. For others it would be a waist of resources (e.g. there is no need for every process to watch is the file associations have changed) - it's enough to load them only once. The explorer seems to be a good candidate to create such objects. In the attached patch there is one specialized interface - the IWineTrash. The SHELL_DeleteFile[AW] is patched to use it - it shows a different icon if the file can be trashed (these are not the correct icons as wine's shell32 uses a message box instead of a special dialog) and calls the trash method then. Currently there is only one built-in trash that can't trash anything. (note that SHELL_DeleteFile is called in the folders that are decendents of My Computer. If choose delete on a file that is a decendent of the '/', it will be deleted without a warning).
Mikolaj Zalewski
I think the general approach is good.
The way you handle the built in implementation seems odd to me. I think setting the registry key to make the freedesktop.org version as the default would be good enough.
If we don't have built-in trash etc. objects then when we add a new object we will require all the implementations have it, with no backward compatibility. However this should not be a big problem as the freedesktop.org implementation can be kept up-to-date with shell32 and the other implementation can fallback to it if they don't support a specific object.
I'm not convinced we need IWineShellIntegration. I think it would be cleaner to directly create an IWineTrash object.
If we integrate more closely with the desktop environments we may need to have one central object that will know that e.g. KDE 3.4 uses the freedesktop.org Trash but KDE 3.3 has it's own Trash implementation. If we read the Trash CLSID from the registry such an implementation would require creating proxy classes or hacks in the class factory. Also by storing only one CLSID we don't have a problem which implementation to use if a new kind of objects is introduced.
Of course when we use COM aggregation instead of a factory pattern we will have all the interfaces visible under one CLSID so we will be able to construct a IWineTrash directly with the main object hidden behind the scene.
Mikolaj Zalewski
On Fri, 02 Jun 2006 20:16:25 +0200, Mikolaj Zalewski wrote:
Of course when we use COM aggregation instead of a factory pattern we will have all the interfaces visible under one CLSID so we will be able to construct a IWineTrash directly with the main object hidden behind the scene.
Argh, this is exactly what Alexandre meant! :)
The number of developers that understand COM aggregation and all the baroque rules that make it up is very, very low. A simple ops struct of function pointers as used in the wineserver or kernel would be fine here ... COM adds an awful lot of complexity that really isn't needed at all (eg you must call CoInitialize, which means caring about apartments, which means possibly instantiating a STA when windows wouldn't, which means pain).
thanks -mike
The number of developers that understand COM aggregation and all the baroque rules that make it up is very, very low. A simple ops struct of function pointers as used in the wineserver or kernel would be fine here ... COM adds an awful lot of complexity that really isn't needed at all (eg you must call CoInitialize, which means caring about apartments, which means possibly instantiating a STA when windows wouldn't, which means pain).
OK, I won't insist on aggregation :). As for apartments I've thought that something like that: HRESULT res=CoInitializeEx(NULL, COINIT_MULTITHREADED); /* working with objects with ThreadingModel Both */ if (SUCCEEDED(res)) CoUninitialize();
won't have any side effects. But if the number of developers that knows about COM is low then maybe that it's better to use simple ops structs instead.
Mikolaj Zalewski
PS: I will be absent during the next week so I won't be able to reply to e-mails.
On 6/3/06, Mikołaj Zalewski mikolaj@zalewski.pl wrote:
OK, I won't insist on aggregation :). As for apartments I've thought that something like that: HRESULT res=CoInitializeEx(NULL, COINIT_MULTITHREADED); /* working with objects with ThreadingModel Both */ if (SUCCEEDED(res)) CoUninitialize();
won't have any side effects.
Well, you'd be possibly changing the apartment of the current thread, which is not allowed IIRC.
But if the number of developers that knows about COM is low then maybe that it's better to use simple ops structs instead.
I'd say so...
thanks -mike
Mikołaj Zalewski wrote:
The number of developers that understand COM aggregation and all the baroque rules that make it up is very, very low. A simple ops struct of function pointers as used in the wineserver or kernel would be fine here ... COM adds an awful lot of complexity that really isn't needed at all (eg you must call CoInitialize, which means caring about apartments, which means possibly instantiating a STA when windows wouldn't, which means pain).
OK, I won't insist on aggregation :). As for apartments I've thought that something like that: HRESULT res=CoInitializeEx(NULL, COINIT_MULTITHREADED); /* working with objects with ThreadingModel Both */ if (SUCCEEDED(res)) CoUninitialize();
won't have any side effects. But if the number of developers that knows about COM is low then maybe that it's better to use simple ops structs instead.
As long as the lifetime of the objects doesn't outlive the lifetime of the apartment (which dies in the CoUninitialize call) then it is fine, although trying to change the apartment of the current thread will cause builtin ole32 to print an ERR at the console.
Mikołaj Zalewski mikolaj@zalewski.pl writes:
The main idea is not to hard-code one implementation of things like the Trash into shell32 - not everything is standardized by the freedesktop and even if it would this might not work on other systems like MacOS X. We should allow for many implementations. The correct one is loaded depending on a registry settings (so that a winecfg entry can be added). My implementation uses COM objects as it's standard dlls provides support for such tasks. Currently there is one interface (IWineShellIntegration) that acts as a factory for specialized objects. That could also be implemented using COM Aggregation - when we do that we could use QueryInterface instead of GetIntegrationObejct.
I think using COM for that sort of thing is overkill. Besides, you most likely want to put all of that in the explorer process, and communicate with shell32 using the same protocol that Microsoft is using, like we do already for the system tray.
Alexandre Julliard wrote:
I think using COM for that sort of thing is overkill.
If we want to allow multiple implementations then using a structure with callback functions is probably the easiest way. If we are using structures with callback functions then why not to make it COM interfaces - IMHO the overhead of adding the QueryInterface, AddRef, Release is relatively small and we obtain structures with which probably most of developpers are more of less familliar.
Besides, you most likely want to put all of that in the explorer process, and communicate with shell32 using the same protocol that Microsoft is using, like we do already for the system tray.
For the Trash I don't know if there is any protocol. I've placed a DELETE security audit on a file and it was the application trashing the file that triggered it - so it seems Windows also doesn't need to communicate with the explorer. For things like file associations, to maintain compatibility we will need to keep the settings in the registry. What we can do is to mirror the changes to the Linux database. That's a feature that is not present in Windows so we can choose a protocol.
Mikolaj Zalewski