http://bugs.winehq.org/show_bug.cgi?id=4436
------- Additional Comments From J.A.Gow@furrybubble.co.uk 2006-12-02 13:46 ------- Hmm, I've been doing some digging in the ole32 source. The first thing I tried is to remove the calls to AddRef for the parent object in the IStream constructor and destructor. This fixes the app, i.e. it runs, as now the file is closed when the IStorage object is deleted. However, it is not a viable fix as now we leak IStream objects that never get deleted until the process is terminated.
I have a couple of proposals to mention: I don't mind writing some code but I'd like some guidance in order not to go down the wrong path and waste time. Please let me know what you think:
1) Each IStorage object maintains a list of 'active' IStream objects that are opened/created and contained within this IStorage object. Upon deletion of the IStorage, all child IStreams are also destroyed, thereby preventing the memory leak. This part is easy (I have already coded and tested this) but the problem occurs when a well-behaved app actually does destroy the IStream before the IStorage. There needs to be some communication path between the IStream object and the IStorage object during execution of the IStream object destructor in order to remove the outgoing IStream from the IStorage's list of 'active' IStreams. Problem is, (and here my lack of knowledge of the Windows COM stuff hinders me) is that there is no published interface I can use. I could introduce a private interface, but this would only work if an IStream could be guaranteed only ever to be created as a child of an IStorage - this would break encapsulation. The other way would be to introduce another interface to IUnknown, so that IStream could call a method in its ancestor and the method would be guaranteed to exist, but would only be effective for an IStorage ancestor.
2) This would use a list similar to (1), but the list would exist in process global space outside the object hierarchy. As far as I can see this would bring with it a whole slew of issues related to multithreaded access to the list. Or would it? Is the ole32 API designed to be single-threaded? I am not sure, but if it is not, what locks would I need to use to mutex access to the list?
The first option would be my first choice, providing a workaround to avoid breakage of encapsulation can be found.