Debug.Print 在 VBA

Debug.Print in VBA

In VBA Debug.Print 打印到 Immediate window.

我刚发现使用分号 (;) 会在 caret/text cursor 的位置打印,这看起来很奇怪。

Debug.Print "a" & "b" & "c"
Debug.Print ; "a"; "b"; "c"
Debug.Print "a", "b", "c"

打印以下内容。

abc
abc
a             b             c

这是我在文档中找到它并进一步了解它之前的主要问题。

Use a semicolon (;) to position the insertion point immediately following the last character displayed.

我现在的问题是是否可以像这样使用 named argument

Debug.Print object:="..."

Intellisense 通常有助于查找参数的名称,但它不会列出任何名称。

我也尝试了 objectoutputlist,就像文档中显示的那样,但它会引发错误。

Debug.Print在这方面有什么不同吗?

Debug 语句确实不同于其他所有内容。如果您在 对象浏览器 中查找 Debug 模块,您将找不到它,即使显示了隐藏的 classes 和成员。

Debug.PrintDebug.Assert 语句从字面上融入语言 [parser] 本身 - 这里的逗号并不意味着 "argument separator",而是 special-form 语法[显然] 为 Print 方法保留(注意:VBA 用户代码不能使用 Print 作为方法名称,它是保留的)。

所以 Debug 语句基本上是特殊类型的 关键字 。智能感知/参数 quick-info 显示为 参数列表 语法元素,但在语法上,Debug.Print 的 "arguments" 是一个 输出list,与 Print statement 完全一样。

请注意,VBE 会自动将 ? 标记转换为 Print 语句:

Debug.? --> Debug.Print

Print 有相当多的历史包袱:keyword/command(及其 ? shorthand)在旧的 BASIC 方言中用于输出东西到屏幕...或实际的 [点阵!] 打印机。

所以简短的回答是,Debug 语句是用关键字创建的,而不是成员调用 - 这就是为什么 IntelliSense 对它们没有任何用处,因为没有任何争论。

Rubberduck 项目有一个关于这些语句的有趣故事...因为实际上不可能解析典型的 Debug.Print 语句与任何其他隐式 callStmt (即它看起来和解析都像任何其他过程调用),我们必须给语句它自己的专用解析器规则,并且 "declare" 一个伪造的 DebugClass 模块并使 Print 成为 "method" 的 "class" 以便能够像我们处理其他 early-bound 标识符引用一样跟踪使用情况:

但实际上并没有这样的事情:带有 输出列表 的语句在解析器和编译器级别被嵌入到语言中,而实际上每个其他成员都称你为made in VBA 是某个模块的 member - 按 F2 并浏览 VBA 标准库的成员:你会发现 CLng 类型转换、NowDateAdd date/time 函数、MsgBoxDoEvents 以及许多其他函数 - 都属于某个模块。但是 Debug 语句更接近 StopResume 关键字,在较低级别处理。


进一步证明,除了表面上看到的以外,还有一个简单的事实,即 VBE 中的默认语法高亮显示会在明亮的 keyword-blue 中同时高亮显示 DebugPrint,如果你编译一个用 C# 编写的 COM-visible class:

[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
[Guid("6F25002E-2C9F-4D77-8CCB-A9C0E4FB2EF1")]
public interface ITestClass
{
    [DispId(1)]
    void Print(string value);
    [DispId(2)]
    void DoSomething();
}

[ComVisible(true)]
[ComDefaultInterface(typeof(ITestClass))]
[ClassInterface(ClassInterfaceType.None)]
[Guid("6F25002E-2C9F-4D77-9624-6CA79D4F088A")]
[ProgId("PrintTest.Class1")]
[EditorBrowsable(EditorBrowsableState.Always)]
public class Class1 : ITestClass
{
    public void Print(string value)
    {
        /* no-op */
    }

    public void DoSomething()
    {
        /* no-op */
    }
}

..然后从 VBA 代码调用它...

可以调用 DoSomething 方法,但 Print 方法将抛出错误 438 - 就像您尝试用 Debug 以外的任何东西来限定它时一样。那么 Print 如何在 Access 报告的 code-behind 中起作用呢?

接口没有记录,所以这纯粹是猜测,但是有一个 IVBPrint 接口看起来非常像 VBA 正在寻找的东西:

[
  odl,
  uuid(000204F0-0000-0000-C000-000000000046),
  nonextensible
]
interface IVBPrint : IUnknown {
    HRESULT _stdcall WriteText([in] BSTR strText);
    [propput]
    HRESULT _stdcall Column([in] long retVal);
    [propget]
    HRESULT _stdcall Column([out, retval] long* retVal);
};

如果是这样,那么error 438 is just VBA's way to say "IVBPrint implementation not found"