如何在不同进程上按下按钮(nunit.exe)

本文关键字:按钮 nunit exe 进程 | 更新日期: 2023-09-27 18:20:10

我已经为我录制了这个附加到进程(nunit.exe)的宏。现在我想在我要附加的进程的窗口上按下一个按钮(名为"Run"),但如何?我已经录制了这个宏:

Sub DebugNUnit()
DTE.ExecuteCommand("Tools.ExternalCommand6")
'need a short delay for nunit process to appear in process list:
Threading.Thread.Sleep(200)
Try
    Dim dbg2 As EnvDTE80.Debugger2 = DTE.Debugger
    Dim trans As EnvDTE80.Transport = dbg2.Transports.Item("Default")
    Dim dbgeng(1) As EnvDTE80.Engine
    dbgeng(0) = trans.Engines.Item("Managed (v4.0)")
    Dim proc2 As EnvDTE80.Process2 = dbg2.GetProcesses(trans, "myPC").Item("nunit.exe")
    proc2.Attach2(dbgeng)
Catch ex As System.Exception
    MsgBox(ex.Message)
End Try
End Sub

更新:我已经根据这个的答案调整了脚本

Sub DebugNUnit()
    DTE.ExecuteCommand("Tools.ExternalCommand6")
    'need a short delay for nunit process to appear in process list:
    Threading.Thread.Sleep(200)
    Try
        Dim dbg2 As EnvDTE80.Debugger2 = DTE.Debugger
        Dim trans As EnvDTE80.Transport = dbg2.Transports.Item("Default")
        Dim dbgeng(1) As EnvDTE80.Engine
        dbgeng(0) = trans.Engines.Item("Managed (v4.0)")
        Dim proc2 As EnvDTE80.Process2 = dbg2.GetProcesses(trans, "myPC").Item("nunit.exe")
        proc2.Attach2(dbgeng)
        'added this because we may need a short delay for nunit gui to load
        '(would prefer to replace it with a wait on some loaded event or something)
        Threading.Thread.Sleep(5000)
        'use Process.Handle or Process.MainWindowHandle? anyway, both do not seem to work.. are the parameters incorrect?
        Dim ButtonHandle As IntPtr = FindWindowEx(System.Diagnostics.Process.GetProcessById(proc2.ProcessID).Handle, 0, "Button", "Run")
        'Dim ButtonHandle As IntPtr = FindWindowEx(System.Diagnostics.Process.GetProcessById(proc2.ProcessID).MainWindowHandle, 0, "Button", "Run")
        SendMessage(ButtonHandle, &HF5, 0, 0)
    Catch ex As System.Exception
        MsgBox(ex.Message)
    End Try
End Sub

但是(通过Tools.ExternalCommand6)启动的nunit用户界面上的"运行"按钮仍然没有被按下。这是有道理的,因为按钮句柄似乎总是0。为什么?有人提出解决方案吗?

更新:我已经根据编辑后的答案调整了脚本,如下

Option Strict Off
Option Explicit Off
Imports System
Imports EnvDTE
Imports EnvDTE80
Imports EnvDTE90
Imports EnvDTE90a
Imports EnvDTE100
Imports System.Diagnostics
Imports System.Runtime.InteropServices
Imports System.Windows.Forms
Public Module RecordingModule
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
    Private Function PostMessage(ByVal hWnd As IntPtr, ByVal Msg As UInteger, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Boolean
End Function
Sub DebugNUnit()
    DTE.ExecuteCommand("Tools.ExternalCommand6")
    'need a short delay for nunit processes to appear in process list:
    Threading.Thread.Sleep(1000)
    Try
        Dim dbg2 As EnvDTE80.Debugger2 = DTE.Debugger
        Dim trans As EnvDTE80.Transport = dbg2.Transports.Item("Default")
        Dim dbgeng(1) As EnvDTE80.Engine
        dbgeng(0) = trans.Engines.Item("Managed (v4.0)")
        Dim proc2nunitagent As EnvDTE80.Process2 = dbg2.GetProcesses(trans, Environment.MachineName).Item("nunit-agent.exe")
        Dim proc2nunit As EnvDTE80.Process2 = dbg2.GetProcesses(trans, Environment.MachineName).Item("nunit.exe")
        proc2nunitagent.Attach2(dbgeng)
        PostMessage(System.Diagnostics.Process.GetProcessById(proc2nunit.ProcessID).MainWindowHandle, &H100, Keys.Alt Or Keys.R, IntPtr.Zero)
    Catch ex As System.Exception
        MsgBox(ex.Message + Environment.NewLine + ex.StackTrace)
    End Try
End Sub
End Module

我使用的是nunit 2.5.7,为了连接和调试,你需要连接到nunit代理,然后在nunit gui上按run,对于更新版本的nunit,你可以连接到nuinit gui。

上面的脚本仅使用Visual Studio和nunit二进制文件就可以从Visual Studio IDE进行nunit调试。您所需要做的就是将nunit设置为一个外部工具(以当前项目为参数),创建一个自定义工具栏,并在该工具栏中添加一个使用上述脚本的按钮。这将启动nunit,连接到它,开始运行测试,并在断点处中断。

还有一件事:在nunit gui中,在Tools(工具)->Settings(设置)->Tree Display(树显示)中禁用"Save Visual state of each Project",否则nunit gui将记住上次运行的测试,如果那不是你想要调试的测试,那将是一件痛苦的事。

可能的改进:在启动nunit之前先构建。

如何在不同进程上按下按钮(nunit.exe)

试试这个:

<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
Private Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal Msg As UInteger, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
End Function
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
Private Shared Function FindWindowEx(ByVal parentHandle As IntPtr, ByVal childAfter As IntPtr, ByVal lclassName As String, ByVal windowTitle As String) As IntPtr
End Function
Dim ButtonHandle As IntPtr = FindWindowEx(YOURPROCESS.HANDLE, 0, "Button", "&Run")
SendMessage(ButtonHandle, &HF5, 0, 0)

EDIT:看起来NUint是一个.NET应用程序,这意味着你无法轻松获得按钮句柄。你可以在Spy++的帮助下亲眼看到这一点。

我注意到按钮Run有一个ALT + R的键盘快捷键,所以你可以使用这个代码:

<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
Private Shared Function PostMessage(ByVal hWnd As IntPtr, ByVal Msg As UInteger, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Boolean
End Function
PostMessage(MAIN_WINDOW_HANDLE, &H100, Keys.Alt Or Keys.R, IntPtr.Zero)

我测试了一下,效果很好。