No, this isn't a question about my relationship with reality...
....param: ppErrors (lpvoid) errorBuffer := COMTaskMemory new: itemCount * HRESULT byteSize. errors := StructureArray fromAddress: errorBuffer length: itemCount elementClass: HRESULT. The above code was implemented in a COMImplementaiton object. Then the idea was to pass back the StructureArray in a parameter. However doing this: ppErrors value: errors detach results in occasionaly walkbacks at unexplained times where the Dolphin image will lock up and give "unable to read" errors. It appears to be a finalization problem. Whereas: ppErrors value: errorBuffer detach does not *seem* to cause this problem. In looking at the different detach methods, they appear to try to do the same thing (obviously in diffent ways). Should I expect this? As I thought that detaching either errors or errorBuffer would result in the same thing. Eric |
Eric,
> ....param: ppErrors (lpvoid) > > errorBuffer := COMTaskMemory new: itemCount * HRESULT byteSize. > errors := StructureArray fromAddress: errorBuffer length: itemCount > elementClass: HRESULT. > > The above code was implemented in a COMImplementaiton object. Then the > idea was to pass back the StructureArray in a parameter. Where is errorBuffer defined?. If it is as a local variable within the method then that might be the problem. When the method ends, and you return the errors object, there are no references left to the errorBuffer object so the grabage collector reclaims it. This leaves the memory at the address that errors is pointing at free for reuse. In order to prevent garbage collection you have to maintain a reference to the actual Smalltalk object and not just a reference to the address of the object. As a *temporary* fix, use a Global to hold the buffer and see if the problem goes away. NB If the method is called more than once then this won't work as the second call will cause the reference to buffer created by the first to be lost and garbaged (Smalltalk at: #MyErrorBuffer) put: (COMTaskMemory new: itemCount * HRESULT byteSize). errors := StructureArray fromAddress: (Smalltalk at: #MyErrorBuffer) length: itemCount elementClass: HRESULT. A better way might be to use an instance variable but that depends a lot on the class the above is implemented in. However, if #detach'ing the error buffer does work then maybe (i.e. out of my depth here!) this maintains a reference to the COMTaskMemory (or it's underlying collection) for you that prevents the memory being reused and is the way to go? > Should I expect this? As I thought that detaching either errors or > errorBuffer would result in the same thing. I don't really know, the above is based on similar problems I had when using the "normal" windows structures. Probably worth a look at though? Ian |
In reply to this post by Eric Winger-4
Eric
You wrote in message news:[hidden email]... > No, this isn't a question about my relationship with reality... > > > ....param: ppErrors (lpvoid) > > errorBuffer := COMTaskMemory new: itemCount * HRESULT byteSize. > errors := StructureArray fromAddress: errorBuffer length: itemCount > elementClass: HRESULT. > > The above code was implemented in a COMImplementaiton object. Then the > idea was to pass back the StructureArray in a parameter. > > However doing this: > > ppErrors value: errors detach > > results in occasionaly walkbacks at unexplained times where the Dolphin > image will lock up and give "unable to read" errors. It appears to be a > finalization problem. > > Whereas: > > ppErrors value: errorBuffer detach > > does not *seem* to cause this problem. > > In looking at the different detach methods, they appear to try to do the > same thing (obviously in diffent ways). > > Should I expect this? Yes. >...As I thought that detaching either errors or > errorBuffer would result in the same thing. No. The StructureArray does not own the memory block you've associated with it using #fromAddress:etc, it is merely a reference to it, and therefore it doesn't modify the pointer object in any way when you detach it. In this case the pointer is a finalizable object which will delete the associated COM task memory heap block when it is GC'd, unless you explicitly detach it. In other words the memory was allocated by COMTaskMemory class>>new:, and is owned by the COMTaskMemory instance, not by the StructureArray. Therefore to prevent the memory evaporating at an inconvenient time, you must detach the COMTaskMemory pointer, not the StructureArray. Regards Blair |
Hi Blair,
> No. The StructureArray does not own the memory block you've associated with > it using #fromAddress:etc, it is merely a reference to it, and therefore it > doesn't modify the pointer object in any way when you detach it. In this > case the pointer is a finalizable object which will delete the associated > COM task memory heap block when it is GC'd, unless you explicitly detach it. > In other words the memory was allocated by COMTaskMemory class>>new:, and is > owned by the COMTaskMemory instance, not by the StructureArray. Therefore to > prevent the memory evaporating at an inconvenient time, you must detach the > COMTaskMemory pointer, not the StructureArray. I found the copy vs. reference behavior of the various external memory classes to be somewhat unclear, in that I was frequently uncertain of which of the two was going to happen with any particular message. Most of the external interfacing that I do now allocates memory in Dolphin and passes a pointer to a DLL to run various tight loops in C/C++; that typcially just works. Hooking Dolphin objects to externally allocated memory is a little trickier. In fairness, I haven't looked at it much (haven't needed to) since I stopped using DCOM. I was never sure whether the missing element is more explicit comments in the image or a cookbook in the EducationCentre or on the Wiki. Looking over http://www.object-arts.com/wiki/html/Dolphin/ExternalInterfacing.htm it's obvious that (surprise<g>) I never got around to writing the recipe part of it. My advice to the Wiki editors of the world would be to keep the "interview" section, and, add a cookbook section that lists problems and their solution. If the cookbook idea isn't appropriate or easy to do, maybe a table to cross-reference copying vs. not with types of memory and/or contents??? Have a good one, Bill -- Wilhelm K. Schwab, Ph.D. [hidden email] |
In reply to this post by Blair McGlashan
Blair McGlashan wrote:
> > > No. The StructureArray does not own the memory block you've associated with > it using #fromAddress:etc, it is merely a reference to it, and therefore it > doesn't modify the pointer object in any way when you detach it. In this > case the pointer is a finalizable object which will delete the associated > COM task memory heap block when it is GC'd, unless you explicitly detach it. > In other words the memory was allocated by COMTaskMemory class>>new:, and is > owned by the COMTaskMemory instance, not by the StructureArray. Therefore to > prevent the memory evaporating at an inconvenient time, you must detach the > COMTaskMemory pointer, not the StructureArray. > > If I understand correctly, it becomes vitally important when using external structures, that one detach the appropriate memory object, not any "users" of said memory. It's almost as if the ExternalStructure in this example could be considered a view on a memory model. And that view has a lifetime of its own independent of its underlying model. Thanks for the responses guys. Eric |
Free forum by Nabble | Edit this page |