Does anyone know whether we need to call object.Release for a Direct COM object in PB9?
Documentation does not say either way only that setting an object to NOTHING releases memory and resources.
A variable holds the interface and will call .release() for you.
The variable will be set to empty or nothing (read: invalid pointer)
When all variables holding the same object instance are released, the data and internal allocation will be cleared.
When the variable goes out of scope or when set to nothing it will call release, never call it yourself unless you are 'misusing' the object's interface.
I do that in some cases, for example to hold the interface in a long integer.
When a long is cleared, the release() will not called of course and so i have to make sure it does.
Sweet!
I figured as much and have been programming it that way, but without knowing for sure.
Y, i have some cases where i have aggregated COM objects and have to manage the addref and release myself...
Thanks!
Oh btw, to be clear, i was talking about variant, dispatch and interface for variables but you seem to understand that :)
These 3 are supported by PB to be released (or manually) if they contain a com interface.
Ok, new question. Does PB9 automatically call release on INSTANCE variables in a CLASS?
Considering the example class below...when an instance of the class "test" is destroyed or goes out of scope, what happens to the instance variable 'var1'? Is PB calling relase on all internal object references before releasing the class itself? Or do we need to do release/NOTHING in a destructor?
CLASS test
INSTANCE var1 AS ISomething
INTERFACE ITest
INHERIT IUNKNOWN
METHOD t()
var1 = CLASS "Something"
END METHOD
END INTERFACE
END CLASS
PB releases all stuff for you but this discussion has been on the pb forum as well.
A logical error is made really quick.
For example my main interface held a reference to a 'child' item interface and this child also to the main.
A circular reference that is and is not going to be released (chicken - egg).
Your question can be solved by yourself by using an OutputDebugString() in the release call.
This is how i develop my code to be sure it is released as anticipated.
Quote
Considering the example class below...when an instance of the class "test" is destroyed or goes out of scope, what happens to the instance variable 'var1'? Is PB calling relase on all internal object references before releasing the class itself?
Yes, it releases the instance variables.
Ok, another question then...
When working in loops, i have a variable that i instantiate inside the loop, and set it to nothing just before the next iteration.
I'm concerned that this may not be safe since when the function completes, PB may try to call release on an object that already has a ref count of zero. Am i overly concerned?
Consider the following function:
FUNCTION myLoop(obj as ISomeObject)
DIM x AS INTEGER
FOR x = 0 TO obj.Count
DIM subObj as ISubObject
subObj = obj.item(x)
...
{some work is done on subObj}
...
subObj = NOTHING '// need to explicitly free the object to avoid a memory/handle leak
NEXT
END FUNCTION
Will PB already know that subObj has a ref count of zero and not call release?
OR
Will PB call release anyway and swallow any error about the ref count being at or less than zero?
Regards,
Eriq
Quote
Am i overly concerned?
Yes, you are :)
Quote
Will PB already know that subObj has a ref count of zero and not call release?
OR
Will PB call release anyway and swallow any error about the ref count being at or less than zero?
PB can't know if the reference count is zero, but it doesn't need it. After setting subObj = NOTHING, the pointer hold by that variable is 0, and PB is clever enough to know that calling Release with a NULL pointer will cause a GPF, therefore it does nothing.
BTW even subObj = NOTHING in the loop isn't needed, because PB will call Release before assigning a new value to it (unless the pointer is already 0). In fact, you don't ever need to set an object variable to Nothing unless you want release objects in an orderly manner.
PB's object variables are smart pointers. Only if you manipulate them in an unsupported way, like poking a value (something I do often, but I know what I'm doing), may you need to be concerned about AddRef and Release.
Very nice. Thanks much.
I'm a MAPI programmer and always have to be concerned about such.
-Eriq
Ok, i thought i had this all figured out...
I'm getting a memory access violation when my object's lifetime expires.
I know this because the debugger runs fine until is step out of my function.
I placed brakepoints in DESTROY for my class, and it bombs after leaving the DESTROY function.
So, what do we need to know about passing objects in to other object's methods?
Does PB call addref every time? Could there be times where passing an object reference doesn't trigger addref?
If i figure it out before you do, i'll update this thread.
-Eriq
Quote
Does PB call addref every time?
Every time you pass it by value.
Quote
Could there be times where passing an object reference doesn't trigger addref?
If you pass it by reference.
Do not set an object variable passed by reference to Nothing unless you first have called AddRef.
>Do not set an object variable passed by reference to Nothing unless you first have called AddRef.
Huh?
I set this to nothing when passed byref, it releases the variable just fine.
I often do this to reuse an existing var and a previously set object must be released of course.
?
If you pass an object variable by reference, the reference count isn't incremented, therefore you must not set it to NOTHING.
#COMPILE EXE
#DIM ALL
#INCLUDE "windows.inc"
#INCLUDE "REGEXP.INC"
SUB Foo (BYREF pRegExp AS IRegExp)
pRegExp = NOTHING ' <-- don't do this
END SUB
FUNCTION PBMAIN () AS LONG
LOCAL pRegExp AS IRegExp
pRegExp = NEWCOM "VBScript.RegExp"
Foo pRegExp
' Now pRegExp is a null reference
' If you try to use it, it will GPF
END FUNCTION
I think we have a miscommunication, i do this all the time like:
Class Class1
Class Method Destroy
MsgBox "D"
End Method
Interface Interface1: Inherit IUnknown
Property Get DateValue() As String
Property = "11"
End Property
End Interface
End Class
Function CreateTheObject( ByRef o As Interface1 ) As Long
o = Class "Class1"
End Function
Called like:
Local c As Interface1
c = Class "Class1"
CreateTheObject( c )
Passing c means the address of c and therefore the same principles apply as using code in the original procedure.
The msgbox is executed twice.. as should.
Your example isn't wrong just that you say don't do this.. i guess you mean don't do this if you suspect the var passed should still have an object.
Of course..
Quote
The msgbox is executed twice. as should.
Of course. When you do o = Class "Class1", PB calls c.Release and assigns to it the pointer of the new create class. But the question asked by Eriq was "Could there be times where passing an object reference doesn't trigger addref?", and the answer is when you pass it by reference.
Ah fun with COM. It never dies.
I figured it out.
I did in deed have a situation, buried deep, that was a weak reference in which i was forced to call addref on my own.
The problem was (mainly because of my lack of experience with PB directly) that i was also asuming that i needed to call release since i called addref.
When i commented out the release code, all was working fine.
Seems PB is smarter than we thought. If an object var has a non-null object handle (as in OBJPTR(var) <> 0) then PB will call release when it goes out of scope, regardless of how the object was instantiated.
I suppose i could have also fixed it by calling release AND setting to object to nothing, or even just setting it to nothing, since var=NOTHING calls release (if necessary) and also sets the object pointer to zero.
i ended up just commenting the code to state that although addref was called, PB will call release.
For any that care about the specifics of what i'm doing...i'm working with MAPI profiles and there's a HACK that has to be used with some profiles where you pickup an object that exists only at an offset of a current one. That's why i have a coded addref.
here's a link to some explanation of the HACK. http://mapispy.com/articles/prprovider/MAPIProfileProvider.htm
Look for the text 'HACK CENTRAL' in the page and you see the C++ version of the hack.
Thanks guys.