Last time, we learned about the difference between SafeÂArrayÂAccessÂData and SafeÂArrayÂAddÂRef. I noted that SafeÂArrayÂAddÂRef was a latecomer that was added to an existing API and that one of the design concerns was to minimize the impact upon existing code. When extending an existing API, a major concern is what the new feature means for people who were using the earlier version of the API.
One design principle for extending an API is “pay for play”: Programs can call the new API to get access to new features, but programs that choose not to do so are unaffected, and the old code continues to work as it did before. It is acceptable to add additional requirements for people who want to use the new feature, such as, “If you intend to reverse the polarity of a widget, you must pass the AllowÂPolarityÂReversal flag when creating the widget.” Pre-existing code won’t pass that flag, but they also won’t be trying to reverse the polarity.
For SAFEARRAY, the story is a little trickier because the code that created the SAFEARRAY is not the code that is calling SafeÂArrayÂAddÂRef. Therefore, you cannot impose new requirements on the caller of SafeÂArrayÂCreate because you don’t control that code. The whole point of SafeÂArrayÂAddÂRef is to allow a function to defend itself from malicious behavior in the code that created the SAFEARRAY.
Another design issue is that when you add a new feature to an API, you want to make it easy for people who are already using that API to use the feature. If somebody asks, “How do I solve this problem?”, “Make these major changes to the underlying architecture of your program” will not be received well.
In the case of SAFEARRAY, the problem is compounded by the fact that the SAFEARRAY structure is itself public, so we have to assume that people are accessing the members in it without going through the wrapper functions like SafeÂArrayÂGetÂDim or SafeÂArrayÂGetÂElemsize. There is nowhere to put the reference count without breaking those people.
So how do you record a reference count when there is nowhere to record a reference count?
You have to maintain the reference counts externally.
The system maintains two process-wide tables table to track reference counts, one for tracking data block reference counts and another for tracking array descriptor reference counts. The table is indexed by the pointer to the data block or array descriptor, and the value is the reference count, if not zero. If a reference count drops to zero, then it is erased from the table. That way, the table contains reference counts only for actively-referenced items.
Okay, that ends our digression. Next time, we’ll try to answer a customer’s question about SafeÂArrayÂAddÂRef.
Couldn’t that information be stored at a negative offset of the pointer, the same way the BSTR length is?