DEFINE CLASS SessionTracker AS CUSTOM DIMENSION aSessions[1,2] aSessions = NULL PROTECTED nNumSessions nNumSessions = 0 PROCEDURE AddSession * Record a new Session Object with the tracker LPARAMETERS toObjectRef IF toObjectRef.DataSession # 1 * Only register private datasessions WITH this * Record the session object - add to tail of list .nNumSessions = .nNumSessions + 1 DIMENSION .aSessions[.nNumSessions,2] .aSessions[.nNumSessions,1] = toObjectRef.DataSessionID .aSessions[.nNumSessions,2] = toObjectRef ENDWITH ENDIF RETURN (toObjectRef.DataSession # 1) ENDPROC PROCEDURE CheckRegisteredPrivateSessions RETURN this.nNumSessions ENDPROC PROCEDURE DropSession LPARAMETERS tnDataSessionID LOCAL lFound, nPtr WITH this lFound = .F. FOR nPtr = 1 TO .nNumSessions * Search the member array for this DataSessionID IF .aSessions[nPtr,1] = tnDataSessionID lFound = .T. EXIT ENDIF ENDFOR IF lFound IF .nNumSessions > 1 * Only delete the row if there is >1 row =ADEL(.aSessions, nPtr) DIMENSION .aSessions[.nNumSessions - 1,2] ELSE * With only 1 row, just null it out .aSessions = NULL ENDIF .nNumSessions = .nNumSessions - 1 ENDIF ENDWITH RETURN lFound ENDPROC PROCEDURE Destroy WITH this IF .nNumSessions # 0 LOCAL nPtr, oSessionObj FOR nPtr = 1 TO .nNumSessions oSessionObj = .aSessions[nPtr,2] IF VARTYPE(oSessionObj) = 'O' AND ! ISNULL(oSessionObj) oSessionObj.RemoveSession(.t.) ENDIF oSessionObj = NULL ENDFOR ENDIF .aSessions = NULL ENDWITH DODEFAULT() ENDPROC ENDDEFINE DEFINE CLASS RegSession AS Session PROTECTED oSessionTracker, lInvokeTracker oSessionTracker = NULL lInvokeTracker = .F. PROCEDURE Init LPARAMETER toSessionTracker * See if we were passed a tracker IF VARTYPE(toSessionTracker) = 'O' this.oSessionTracker = toSessionTracker ENDIF * Register session with private datasessions if there is a tracker IF this.DataSession = 2 AND ! ISNULL(this.oSessionTracker) this.lInvokeTracker = this.oSessionTracker.AddSession(this.DataSessionID,this) ENDIF * and whatever else is needed ENDPROC PROCEDURE RemoveSession LPARAMETER tlBypassTracker IF tlBypassTracker this.lInvokeTracker = .F. ENDIF RELEASE this ENDPROC PROCEDURE Destroy IF this.lInvokeTracker AND ! ISNULL(this.oSessionTracker) this.oSessionTracker.DropSession(this.DataSessionID) ENDIF this.oSessionTracker = NULL DODEFAULT() ENDPROC ENDDEFINE * In your mainline code oSessionTracker = CREATEOBJ('SessionTracker') * Each time you create a new session oMySessionObj = CREATEOBJ('RegSession',oSessionTracker) * To check how many private data sessions are registered ? oSessionTracker.CheckRegisteredPrivateSessions() * To see what data sessions are in use FOR nCtr = 1 TO oSessionTracker.CheckRegisteredPrivateSessions() ? oSessionTracker.aSessions[nCtr,1] ENDFOR * To get an object ref to the Session object owning a specific DataSessionID oSessionObject = NULL FOR nCtr = 1 TO oSessionTracker.CheckRegisteredPrivateSessions() IF oSessionTracker.aSessions[nCtr,1] = nDataSessionToFind oSessionObject = oSessionTracker.aSessions[nCtr,2] EXIT ENDIF ENDFORYou'd build your Session subclasses starting from the RegSession class. It's critical that the SessionTracker object have scope at least for the duration of the Session objects that it tracks, if for no other reason than it'll try to kill them off when it dies!