[AccessD] Building a control class

John W Colby jwcolby at gmail.com
Thu Mar 12 13:30:46 CDT 2009


That is interesting stuff, thanks.

Salakhetdinov Shamil wrote:
>> Again I have no idea how the system does this 
>> "under the covers".
>>     
>
> Hi John,
>
> I suppose WithEvents are implemented "under the covers" using COM Connection Points:
>
> http://www.techvanguards.com/com/concepts/connectionpoints.asp
>
> BTW, MS Access custom classes' instances are in fact COM classes built on-the-fly I guess. Form/Report Modules (Code Behind) are also COM class instances...
>
> --
> Shamil
>
>
> -----Original Message-----
> From: John W Colby <jwcolby at gmail.com>
> To: Access Developers discussion and problem solving<accessd at databaseadvisors.com>
> Date: Thu, 12 Mar 2009 12:48:20 -0400
> Subject: Re: [AccessD] Building a control class
>
>   
>> A.D.
>>
>>     
>>> 1.1 - It would be interesting to examine the grounds for concluding that assigning "[Event Procedure]" to a given event in control's property sheet becomes the cause for that event to fire, which would not have happened otherwise (if this value were left blank).
>>>       
>> This one is easy to test. 
>>
>> 1) Build an event stub in the form or class. 
>> 2) Place a message box or debug.print statement in the stub. 
>> 3) Make sure the [Event Procedure] test is NOT in the property. 
>> 4) Cause the event to fire.  Click in the control to cause the click 
>> event etc.
>> 5) Observe that your code in the event stub does not execute.
>> 6) Place the [Event Procedure] text in the property.
>> 7) Cause the event to fire.  Click in the control to cause the click 
>> event etc.
>> 8) Notice that your code does in fact execute.
>>
>>     
>>> (a) Various events inherent to a control keep firing as and when merited, irrespective of the value assigned in property sheet. 
>>>       
>> There is simply no way to determine this since the mechanism is buried back in the Access code.  I suppose if you had sufficiently sophisticated debug tools and could step through code at the machine code (PCode) level you might be able to watch this, but you and I cannot do so.
>>
>>     
>>> (b) If any such event is required to be trapped and acted upon in VBA code, it needs two components, namely (i) An event stub in VBA module and (ii) Explicit hooking via assignment of "[Event Procedure]" in the property sheet. Omission of either component will render the event trap ineffective.
>>>       
>> This is absolutely the case, two parts are in fact required, at least to make anything useful occur.  
>>  
>> (c) If any such event is required to be trapped  and acted upon in a function or macro, the trap is confined to a single component, i.e. assignment of function or macro in the property sheet using equal sign.
>>
>> This too is the case.  Again I have no idea how the system does this 
>> "under the covers".  Notice that even if an event stub exists, if an 
>> =MyFunction() is placed in the event property the function is called and 
>> not the event stub.
>>
>> I suspect that there is an "in memory" table built of jump points for 
>> the code when an event is raised.  In the case of the =MyFunction(), the 
>> only entry in the table is the entry point to MyFunction().  In the case 
>> of [Event Procedure] in the property, the code searches for every loaded 
>> object (classes in forms and our classes) which dimension WithEvents the 
>> object raising the event, and then searches in the class for event 
>> stubs.  Any such stubs are loaded into the table as a jump point.  In 
>> fact my guess is that these tables are built as class instances are 
>> loaded, then "hooked up" as an object loads that has events that need to 
>> jump to these jump points. 
>>
>> Look at what happens. 
>>
>> 1) A class loads.  It has an object dimensioned WithEvents, in other 
>> words a variable ready but not filled.  The jump points are NOT HOOKED 
>> YET.  VB has been notified that this class instance MAY SINK EVENTS for 
>> that object, it has not yet declared that the class WILL SINK EVENTS for 
>> that object.  Even if you have event stubs there is nothing yet that 
>> says the class instance WILL sink events.
>> 2) At some point in time that dimensioned variable is SET = an object 
>> passed in.  At this point the jump points MAY OR MAY NOT be hooked.  If 
>> the object already has the event property set to [Event Procedure] then 
>> the jump table hooks up the object's event to the event stub in the 
>> class.  If the object event property is not yet set to [Event Property] 
>> then the jump table is not yet hooked to the event stub.
>> 3) At some point in time the object event property is set to [Event 
>> Property].  AT THIS POINT the jump table is "hooked" to the event stub.  
>> Any events raised by this property of this object now has code that can 
>> execute out in the class we are discussing.  NOTICE, that there may be 
>> event stubs hooked in this one or dozens of instances of this class.  In 
>> fact there may be other entirely different classes also hooking this 
>> same event for this same object, and they all get hooked up at the 
>> instance that [Event Property] is set, and unhooked at the instant that 
>> [Event Property] is cleared (set to empty string).
>> 4) At some point in time the object's event property is set to an empty 
>> string, deleting the [Event Property].  At that point the jump table is 
>> unhooked, and the event stub in ANY AND EVERY OBJECT with an event stub 
>> for this object's property loses the ability to sink the event.  
>> Remember that the event can be sunk in one or dozens of class instances.
>>
>> While I write of a jump table, this is just a not particularly educated 
>> guess as to how it actually works.  But something like this has to be 
>> going on under the covers.  The event property itself is almost 
>> certainly a function in the object that when you write the [Event 
>> Procedure] string into the property begins to execute code that does the 
>> hooking / unhooking.
>>
>> Notice that even more than this simple explanation is going on because 
>> events can pass parameters, so something similar to a stack has to be 
>> set up for the parameters (if any) passed in.
>>
>> 1.3 - In support of 1.2 above, it could be said that it requires an event to fire so as even to become aware of the entry in property sheet (whether "[Event Procedure]" or "=MyFunction()"). For example, if a non-existent function were assigned to an event property, access will respond with a message (not able to find the function).
>>
>> In a manner of speaking yes.  Basically something has to go check the 
>> jump table to see if any jump points have been set up.
>>
>>     
>>> 2 - Need for setting up pointers to labels attached to controls:
>>>       
>>     Access offers a ready made collection of labels belonging to a control, and the count of this collection is usually 1 or Nil. Using a custom function, the available pointer to the control itself could be used to get the attached label via this tiny collection, whenever needed.
>>
>> AFAICT each control has a controls collection, the label is in the 
>> controls collection.  The "usually" is the key here.  I have not done 
>> extensive testing of position but I am gun shy of assuming that 
>> collection object 1 is the label, i.e. assuming a fixed position in the 
>> collection.  I just iterate the collection looking for an object of type 
>> Label.  If the label is in fact the first object, my code gets the 
>> pointer and immediately exits the iteration loop.
>>
>> So yes, I could just run my function every time but why?  Run it once 
>> and provide a pointer to the label.  In fact once I have a label 
>> variable I can also allow a control (clsCtlXXX) to be handed a pointer 
>> to a label that is not even in it's controls collection.  In the case of 
>> a continuous form the control's label is often stripped off the control 
>> and placed up in the form's header section.  By providing a property to 
>> the label in my class, I can (and do) intentionally "program" a control 
>> in this scenario to "own" the label up in the form's header section.  It 
>> could in fact point to ANY label, but this is the specific scenario that 
>> I needed to handle and is the one I use most often when the label is not 
>> in the control's control collection.
>>
>> Classes (and wrappers in particular) give us a slew of abilities that we 
>> wouldn't otherwise have.  Once you start using wrapper classes, light 
>> bulbs start going off.  Oh wow..., now I can add this behavior to my 
>> combo or text box etc.
>>
>> A.D.Tejpal wrote:
>>     
>>> John,
>>>
>>>     Thanks for kindly clarifying various points so thoroughly. It is really nice to have the benefit of your experience and deep understanding. Your views are requested on certain supplementary points placed below:
>>>
>>>     1 - Firing of control events:
>>>     1.1 - It would be interesting to examine the grounds for concluding that assigning "[Event Procedure]" to a given event in control's property sheet becomes the cause for that event to fire, which would not have happened otherwise (if this value were left blank).
>>>     1.2 - An alternative explanation could be:
>>>     (a) Various events inherent to a control keep firing as and when merited, irrespective of the value assigned in property sheet. 
>>>     (b) If any such event is required to be trapped and acted upon in VBA code, it needs two components, namely (i) An event stub in VBA module and (ii) Explicit hooking via assignment of "[Event Procedure]" in the property sheet. Omission of either component will render the event trap ineffective.
>>>     (c) If any such event is required to be trapped  and acted upon in a function or macro, the trap is confined to a single component, i.e. assignment of function or macro in the property sheet using equal sign.
>>>     1.3 - In support of 1.2 above, it could be said that it requires an event to fire so as even to become aware of the entry in property sheet (whether "[Event Procedure]" or "=MyFunction()"). For example, if a non-existent function were assigned to an event property, access will respond with a message (not able to find the function).
>>>
>>>     2 - Need for setting up pointers to labels attached to controls:
>>>     Access offers a ready made collection of labels belonging to a control, and the count of this collection is usually 1 or Nil. Using a custom function, the available pointer to the control itself could be used to get the attached label via this tiny collection, whenever needed.
>>>
>>> Best wishes,
>>> A.D. Tejpal
>>> ------------
>>>   
>>>       
>> -- 
>> John W. Colby
>> www.ColbyConsulting.com
>>
>> -- 
>> AccessD mailing list
>> AccessD at databaseadvisors.com
>> http://databaseadvisors.com/mailman/listinfo/accessd
>> Website: http://www.databaseadvisors.com
>>
>>     
>
>   

-- 
John W. Colby
www.ColbyConsulting.com




More information about the AccessD mailing list