Imagine the following function call:
foo = UCase("bar")
I'm parsing this code, and determine that UCase
is a function call; now I want to resolve that function call to the declaration of the function in the COM library it's defined in.
The idea is to implement a code inspection that determines when a Variant
built-in function is used when a String
-returning function exists, like here UCase$
could be used instead.
It seems the functions I'm after are declared as _B_var_Ucase
and _B_str_UCase
in the COM library; I'm picking up a UCase
member in the VBA.Strings
module, but it's returning VT_VOID
- in other words it's a procedure, not a function.
I could hard-code some logic specific to that group of functions, so that when my resolver code encounters UCase
I can concatenate _B_var_
(and for UCase$
, I can concatenate _B_str_
) to the identifier I'm trying to resolve, and if I'm lucky I'll get my resolver code to correctly assign the reference to the correct built-in function declaration.
But it's pure guesswork.
I know _var_
stands for Variant
and _str_
stands for String
, but the part I'm missing is exactly how to relate these hidden functions to, say, that UCase
function call in the VBA code I'm parsing.
Is UCase("bar")
a call to the VBA.Strings.UCase
procedure? Then how does it work as a function? And if not, then how does VBA know to interpret the UCase
token as a call to _B_var_UCase
? Is there a consistent naming scheme I can rely on, or is there a relationship between UCase
and _B_var_UCase
that I'm not seeing? And what's the B
for anyway?
The web is outrageously silent about the innards of the VBA standard library, I hope someone here might know something about it.
Take a look at the TYPEATTR structure, and in particular, the typekind and tdescAlias members.
So,
UCase(String)
is an Alias for_B_var_Ucase(String)
(where the parameter and the return value are both implicitly Variant.And,
UCase$(String As String) As String
is an Alias for_B_str_UCase(String As String) As String
You can call these underlying functions directly from VB/VBA, but you must use square brackets because
_B_str_UCase
and_B_var_UCase
aren't valid identifiers in VB/VBA.The outrageous silence of the web is tempered by the Wayback Machine's cache of an informative and amusing series of articles by Sean Baxter, but also preserved with formatting, here.
As for the
B
in_B_str_UCase
and_B_var_UCase
it's hard to say exactly, but it's worth remembering that, in COM, a string is actually a BSTRThis MSDN article goes further and states:
and then goes on to say:
So maybe the
B
is to remind the authors of those functions that the return type should be a BSTR, or maybe the B just means base function. I doubt it is important to anyone other than the original developers.EDIT
OleView gives these details:
And the entries (527 and 528) can be found in the DLL exports: