想象一下下面的函数调用:
foo = UCase("bar")
我正在解析这段代码,并确定 UCase
是一个函数调用;现在我想将该函数调用解析为它在其中定义的 COM 库中的函数声明。
这个想法是实现一个代码检查,确定当 String
返回函数存在时何时使用 Variant
内置函数,就像这里的 UCase可以改用 $
。
似乎我所追求的函数在 COM 库中被声明为 _B_var_Ucase
和 _B_str_UCase
;我在 VBA.Strings
模块中获取一个 UCase
成员,但它返回 VT_VOID
- 换句话说,它是一个 过程,不是函数。
我可以硬编码一些特定于该组函数的逻辑,这样当我的解析器代码遇到 UCase
时,我可以连接 _B_var_
(对于 UCase $
,我可以将 _B_str_
) 连接到我要解析的标识符,如果幸运的话,我会得到我的解析器代码以正确地将引用分配给正确的构建-在函数声明中。
但这纯粹是猜测。
我知道 _var_
代表Variant
,_str_
代表String
,但我缺少的部分恰恰是如何将这些隐藏函数与我正在解析的 VBA 代码中的 UCase
函数调用相关联。
UCase("bar")
是对 VBA.Strings.UCase
过程 的调用吗?那么它作为一个函数是如何工作的呢?如果不是,那么 VBA 如何知道将 UCase
标记解释为对 _B_var_UCase
的调用?是否有我可以依赖的一致命名方案,或者 UCase
和 _B_var_UCase
之间是否存在我没有看到的关系? B
到底有什么用?
网络对 VBA 标准库的内部结构非常沉默,我希望这里的某人可能对此有所了解。
最佳答案
看看 TYPEATTR 结构,特别是 typekind 和 tdescAlias 成员。
typedef struct tagTYPEATTR {
GUID guid;
LCID lcid;
DWORD dwReserved;
MEMBERID memidConstructor;
MEMBERID memidDestructor;
LPOLESTR lpstrSchema;
ULONG cbSizeInstance;
TYPEKIND typekind;
WORD cFuncs;
WORD cVars;
WORD cImplTypes;
WORD cbSizeVft;
WORD cbAlignment;
WORD wTypeFlags;
WORD wMajorVerNum;
WORD wMinorVerNum;
TYPEDESC tdescAlias;
IDLDESC idldescType;
} TYPEATTR, *LPTYPEATTR;
tdescAlias
If typekind is TKIND_ALIAS, specifies the type for which this type is an alias.
所以,UCase(String)
是 _B_var_Ucase(String)
的别名 (其中参数和返回值都是隐式 Variant。
并且,UCase$(String As String) As String
是 _B_str_UCase(String As String) As String
的别名
您可以直接从VB/VBA 中调用这些底层函数,但必须使用方括号,因为_B_str_UCase
和 _B_var_UCase
不是 VB/VBA 中的有效标识符。
Dim s As String
Dim v As Variant
s = [_B_str_UCase]("abc")
v = [_B_var_UCase](Null)
's = "ABC"
'v = Null
Wayback Machine 的 cache 缓和了 Web 令人发指的沉默肖恩·巴克斯特 (Sean Baxter) 的一系列内容丰富且有趣的文章,但也保留了格式,here .
The TKIND_ALIAS type kind indicates description of a typedef. The name of the typedef is the name of the type (acquired through GetDocumentation), and the alias type is TYPEATTR::tdescAlias.
至于B
在_B_str_UCase
和 _B_var_UCase
很难说得很准确,但值得记住的是,在 COM 中,字符串实际上是 BSTR
A BSTR (Basic string or binary string) is a string data type that is used by COM, Automation, and Interop functions
此 MSDN article进一步说明:
COM code uses the BSTR to store a Unicode string, short for “Basic String”. (So called because this method of storing strings was developed for OLE Automation, which was at the time motivated by the development of the Visual Basic language engine.)
然后继续说:
If you write a function which takes an argument of type BSTR then you are required to accept NULL as a valid BSTR and treat it the same as a pointer to a zero-length BSTR. COM uses this convention, as do both Visual Basic and VBScript, so if you want to play well with others you have to obey this convention. If a string variable in VB happens to be an empty string then VB might pass it as NULL or as a zero-length buffer — it is entirely dependent on the internal workings of the VB program.
所以可能 B
是提醒那些函数的作者,返回类型应该 是一个BSTR,或者B 可能只是表示base 函数。我怀疑它对原始开发人员以外的任何人都很重要。
编辑
OleView 提供了这些细节:
module Strings{
[entry(527), helpcontext(0x000f6eab)]
BSTR _stdcall _B_str_UCase([in] BSTR String);
[entry(528), helpcontext(0x000f659b)]
VARIANT _stdcall _B_var_UCase([in] VARIANT* String);
}
interface _HiddenInterface {
[restricted, helpcontext(0x000f659b)]
void _stdcall UCase();
}
条目(527 和 528)可以在 DLL 导出中找到:
ordinal hint RVA name
...
527 C8 0005E8A0 rtcUpperCaseBstr
528 C9 00070418 rtcUpperCaseVar
....
关于vba - VBA COM 库中的这些 _B_var_Xxxxx 和 _B_str_Xxxxx 成员究竟是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36002870/