Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/vba/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在VBA中将控制台用作调试窗口_Vba_Excel - Fatal编程技术网

在VBA中将控制台用作调试窗口

在VBA中将控制台用作调试窗口,vba,excel,Vba,Excel,因此,我在Excel文档中运行了一些宏,并想知道是否有一种方法可以频繁地将文本输出到控制台窗口(基本上像立即窗口一样使用它) 我知道有多种方式可以将文本写入文件,我只想显示一些正在运行的进程的信息,而不使用即时窗口或Excel本身中的其他窗口 使用此选项可以帮助我显示一行,但我不想为每行打开一个新窗口: Call Shell("cmd.exe /K echo testInfo", vbNormalFocus) 我不想运行命令(除了echo?)来执行任务,它只是应该显示文本 提前感谢您的建议 编

因此,我在Excel文档中运行了一些宏,并想知道是否有一种方法可以频繁地将文本输出到控制台窗口(基本上像立即窗口一样使用它)

我知道有多种方式可以将文本写入文件,我只想显示一些正在运行的进程的信息,而不使用即时窗口或Excel本身中的其他窗口

使用此选项可以帮助我显示一行,但我不想为每行打开一个新窗口:

Call Shell("cmd.exe /K echo testInfo", vbNormalFocus)
我不想运行命令(除了echo?)来执行任务,它只是应该显示文本

提前感谢您的建议

编辑:

作为@JohnRC帖子的补充,我找到了一个没有外部应用程序的解决方案:

Call Shell("PowerShell.exe -noexit -command get-content " + strPath + " -wait")

在运行上述命令后,将信息记录到该位置的文本文件中就可以做到这一点。

我没有使用shell作为控制台来记录消息,而是使用文本文件来保存日志,并使用tail实用程序监视文件的输出(我使用了来自的WinTail,但我确信还有其他工具)。这是代码,我把它放在一个名为Log的单独vba模块中。然后调用Log.W“Message”来记录消息

Option Explicit

'// You need a reference to "Microsoft Scripting Runtime" library in VBA
Private oLog As Scripting.TextStream
Private bErr As Boolean


Private Sub INIT()
    '// Initialise the output log file

    '// Check if log file is already open, or there has been an error
    If bErr Then Exit Sub
    If Not oLog Is Nothing Then Exit Sub


    '// Open the log file for appending
    Dim ofso As New Scripting.FileSystemObject
    On Error Resume Next
    Set oLog = ofso.OpenTextFile("excel.log", ForAppending, True)

    '// Check that open was successful
    If Err.Number <> 0 Then
        MsgBox "Log file error: " & Err.Number & ": " & Err.Description
        bErr = True

        Exit Sub
    End If
    On Error GoTo 0

    '// Write a starting block to the log
    oLog.WriteLine "*"
    W "********************************** START"
    W "* Start of log " & Format(Date, "YYYY-MM-dd")
    W ""

End Sub

Public Sub W(sMsg)
    '// Writes a single line message to the log
    '// Initialize if required
        INIT
    '// Check for log file error
        If bErr Then Exit Sub

    '// Create the log line and write to log file
        Dim st As String
        st = Format(Now, "hh:mm:ss ")
        oLog.WriteLine st & sMsg

End Sub

Public Function ReportErr(Optional Loc As Variant = "") As Boolean
    '// Reports information from the Err object, if an error has occured

    '// Check if error has occurred, exit if not
    If Err.Number = 0 Then ReportErr = False: Exit Function

    '// Set return value
    ReportErr = True

    '// Initialize if required
    INIT

    '// Check for log file error
    If bErr Then Exit Function

    '// Write the error block to the log
    W "*********** ERROR ******* " & IIf(Len(Loc) > 0, "[" & Loc & "]", "")
    W "* Error #" & Err.Number

    If Len(Err.Description) > 0 Then
        W "* : " & Err.Description
        W "*************************"
    End If

End Function
选项显式
“//您需要在VBA中引用“Microsoft脚本运行时”库
私有oLog作为Scripting.TextStream
作为布尔的私有bErr
私有子初始化()
“//初始化输出日志文件
“//检查日志文件是否已打开,或者是否存在错误
如果是bErr,则退出Sub
如果不是oLog,则退出Sub
“//打开日志文件进行追加
作为新的Scripting.FileSystemObject
出错时继续下一步
设置oLog=ofso.OpenTextFile(“excel.log”,ForAppending,True)
“//检查打开是否成功
如果错误号为0,则
MsgBox“日志文件错误:&Err.Number&:”&Err.Description
bErr=真
出口接头
如果结束
错误转到0
“//将起始块写入日志
oLog.WriteLine“*”
W“***************************************开始”
W“*日志开始”和格式(日期,“YYYY-MM-dd”)
W“
端接头
公共事务副秘书长(sMsg)
“//将单行消息写入日志
'//如果需要初始化
初始化
“//检查日志文件错误
如果是bErr,则退出Sub
“//创建日志行并写入日志文件
暗线
st=格式(现在为“hh:mm:ss”)
oLog.WriteLine街和sMsg
端接头
公共函数ReportErr(可选Loc作为Variant=”“)作为布尔值
“//如果发生错误,则报告来自Err对象的信息
“//检查是否发生错误,如果没有则退出
如果Err.Number=0,则ReportErr=False:退出函数
'//设置返回值
ReportErr=True
'//如果需要初始化
初始化
“//检查日志文件错误
如果是bErr,则退出函数
“//将错误块写入日志
W“**********错误*******”&IIf(Len(Loc)>0,“[”&Loc&“]”,“”)
W“*错误号”&错误号
如果Len(错误描述)>0,则
W“*:”错误描述(&R)
W“**************************”
如果结束
端函数

用WinTail跟踪日志文件意味着日志的输出会在写入后立即显示,因此您可以在程序运行时监视日志。

好的,因为我在前面的回答中得到了一些反对票,我想我应该尝试提供请求的实际答案,即提供一种向命令提示符窗口发送日志消息的方法。这是

此解决方案作为VBA类实现,该类将消息作为注释行发送到单独运行的命令提示符窗口,该窗口的标题中有文本“ExcelLog”。此命令提示符必须单独启动。最简单的方法是创建一个名为“ExcelLog”的快捷方式来运行CMD,然后当该快捷方式打开时,命令提示窗口的标题中将显示“ExcelLog”

在电子表格中添加类cConsole的代码(如下),然后在VBA代码中创建该类的全局实例,并使用方法
.W“message”
将文本消息作为注释行发送到控制台(在这种情况下,使用前缀
将其标识为注释)

cConsole类查找任何具有必需标题的命令提示符窗口,然后将注释消息发送到该窗口。如果找不到该窗口,它将跳过该操作,以便Excel VBA代码继续执行而不报告错误。此外,如果在Excel VBA开始运行后打开命令提示窗口,则cConsole将自动连接到该窗口并开始/继续发送消息。这意味着您可以随时关闭和重新打开命令提示符ExcelLog窗口,而不会中断VBA代码的执行

这似乎对我的设置工作正常。我认为这比简单地跟踪一个文本文件要麻烦得多,但是-嘿,你付了钱,做出了选择

下面是cConsole类的代码

Option Explicit

'// cConsole class
'// This class wraps an interface to a separately-started command prompt
'// window to which messages are sent as comments, so that the command prompt
'// window can be used as a real-time scrolling log from Excel.

'// Each instance of this class creates its own connection to the
'// command prompt window which must have a title containing the text
'// "ExcelLog". If such a window is not open then messages are not
'// logged. The command prompt window can be opened after messages
'// have started, and it will be connected when the next message is
'// sent.

'// The simplest way to set up the necessary command prompt window is to
'// create a shortcut on the desktop the name "ExcelLog" which runs CMD

'// Usage - - - - - - - - - - - -
'//
'//     Dim oConsole As New cConsole
'//     :
'//     oConsole.W "Message to be written to the console"
'//


'// Windows functions to get window handles etc
Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" _
(ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" _
(ByVal hWnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" _
(ByVal hWnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
Private Declare Function SetForegroundWindow Lib "user32" _
  (ByVal hWnd As Long) As Long


'// Handle of the excel log window
Private hLogWindow As Long


Private Sub Class_Initialize()
'// On instantiation, attempts to find the ExcelLog window
    findExcelLogWindow

End Sub

Public Sub W(sMsg As String)
    '// Public function used to send the given message
    '// as a comment line to the linked window
   SendToConsole ":: " & sMsg
End Sub
Private Sub SendToConsole(Command As String)
    '// Connects to and sends a command line to the command prompt
    '// window that is being used as the log

    Dim res As Boolean

    '// Check that a connection has been made and
    '// attempt to connect if not
    If hLogWindow = 0 Then
        findExcelLogWindow
        If hLogWindow = 0 Then Exit Sub
    End If

        On Error Resume Next

                Do
                    '// Attempt to bring the logging window to the foreground
                     res = SetForegroundWindow(hLogWindow)

                    '// Check if successful, and send the command if so
                    If res Then
                        SendKeys Command & vbCrLf
                        Exit Do
                    Else
                        '// Not successful, so try reconnecting to the logging window
                        findExcelLogWindow

                        '// If we cannot connect, just exit without sending anything
                        If hLogWindow = 0 Then Exit Sub
                    End If

                Loop

                '// Check if there has been any error
                If Err.Number <> 0 Then
                    hLogWindow = 0
                    MsgBox "Error: " & Err.Number & vbCrLf & Err.Description
                End If

        On Error GoTo 0

End Sub
Private Function findExcelLogWindow() As Long
    '// This function looks for a command prompt window that has the text
    '// ExcelLog in the title
    Dim nLen As Long
    Dim sData As String

    Dim Class As String
    Dim Title As String

    '// Get handle to the first window
    hLogWindow = 0

    '// Check each window in turn
    Do

            hLogWindow = FindWindowEx(0&, hLogWindow, vbNullString, vbNullString)

            '// Check that a window was found
            If hLogWindow = 0 Then Exit Do

            '// Get the class name of the window
            sData = String$(100, Chr$(0))
            nLen = GetClassName(hLogWindow, sData, 100)
            Class = Left$(sData, nLen)

            '// Get the title of the window
            sData = String$(100, Chr$(0))
            nLen = GetWindowText(hLogWindow, sData, 100)
            Title = Left$(sData, nLen)

            '// Check if the required window has been found
            If Class = "ConsoleWindowClass" And InStr(Title, "ExcelLog") > 0 Then

                '// Initialise the window to remove any prompt text
                SendToConsole "PROMPT $S"

                '// Write some initial messages
                Me.W "*******************"
                Me.W "[" & ThisWorkbook.Name & "] connected to console at " & Now
                Me.W ""

                '// Return the handle to the log window
                findExcelLogWindow = hLogWindow
                Exit Function


            End If



    Loop

    '// The log window was not found, so return zero
    findExcelLogWindow = 0

End Function
结果如下

您可以写入文件,然后使用1个命令将文件输出到控制台窗口。像这样使用命令行的问题是,您可以传递的字符数量有限。您能不能不直接写入模式用户表单?宏在运行时会隐藏任何office应用程序的所有组件(由于复杂的原因,我在此无法进一步解释)所以我需要一些外部的东西。可能是重复的。我没有尝试重定向任何输入,也没有尝试通过shell运行.exe,所以威胁并不能解决@Brandon Barney从高层看的问题。。。这似乎是一个有效的解决办法。为什么投票被否决?
Option Explicit

Private oCons As New cConsole

Private Sub Image1_MouseMove(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
    oCons.W "MouseMove " & X & ", " & Y

End Sub