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