VBA COM 库中的 _B_var_Xxxxx 和 _B_str_Xxxxx 成员究竟是什么?
Exactly what are these _B_var_Xxxxx and _B_str_Xxxxx members in the VBA COM libraries?
想象一下下面的函数调用:
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
到底有什么用?
Web 对 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)
的 别名 (其中参数和 return 值都是隐式变体。
而且,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 of an informative and amusing series of articles by Sean Baxter, but also preserved with formatting, here.
缓和了 Web 令人发指的沉默
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_str_UCase
和_B_var_UCase
中的B
很难说清楚,但值得记住的是,在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
是提醒那些函数的作者return类型应该是 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();
}
并且可以在 DLL 导出中找到条目(527 和 528):
ordinal hint RVA name
...
527 C8 0005E8A0 rtcUpperCaseBstr
528 C9 00070418 rtcUpperCaseVar
....
想象一下下面的函数调用:
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
到底有什么用?
Web 对 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)
的 别名 (其中参数和 return 值都是隐式变体。
而且,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 of an informative and amusing series of articles by Sean Baxter, but also preserved with formatting, here.
缓和了 Web 令人发指的沉默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_str_UCase
和_B_var_UCase
中的B
很难说清楚,但值得记住的是,在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
是提醒那些函数的作者return类型应该是 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();
}
并且可以在 DLL 导出中找到条目(527 和 528):
ordinal hint RVA name
...
527 C8 0005E8A0 rtcUpperCaseBstr
528 C9 00070418 rtcUpperCaseVar
....