有没有办法自动打开Excel文件并将其移动到右侧显示器?

问题描述 投票:0回答:1

我有一台有 2 个显示器的 VacationCalendar PC。我还有两个 Excel 电子表格,一个左一个,一个右一个。我想打开右侧的电子表格,并在脚本运行时将其移至右侧屏幕。

Excel 确实会记住它的最后一个窗口位置,但根据我的测试,它不会对单个电子表格执行此操作,它始终会在打开软件的最后一个显示器上打开电子表格。

这是我当前的批处理脚本:

@echo off
start excel.exe "C:\Users\vacationcalendar\Desktop\VacationCalendar_RIGHT.xlsx"
timeout /t 5 /nobreak >nul
powershell -Command "(new-object -ComObject WScript.Shell).SendKeys('{ESC}')"
timeout /t 1 /nobreak >nul
powershell -Command "(new-object -ComObject WScript.Shell).SendKeys('{#}{SHIFT}{RIGHT}')"
timeout /t 15 /nobreak >nul
start excel.exe "C:\Users\vacationcalendar\Desktop\VacationCalendar_LEFT.xlsx"

它打开正确的文件,然后等待 5 秒,然后发送 ESC 按键。这样做是因为当 Excel 文件打开时,一个单元格会突出显示。但我不相信它起作用,因为当它发送 {#}{SHIFT}{RIGHT} 击键时,它会将“#”符号放入突出显示的单元格中。

{#}{SHIFT}{RIGHT} 按键应该代表 WINKEY + SHIFT + 向右键,将窗口移动到右侧显示器。

我可以做得更好/学习如何让它发挥作用?

我尝试过的VBA宏:

Sub OpenAndPositionWorkbooks()
Dim ExcelApp As Object
Dim Workbook1 As Object
Dim Workbook2 As Object

' Create a new instance of Excel
Set ExcelApp = CreateObject("Excel.Application")
ExcelApp.Visible = True

' Open the first workbook and position it on the left monitor
Set Workbook1 = ExcelApp.Workbooks.Open("C:\Users\whull\Desktop\VacationCalendar_LEFT.xlsx")
Workbook1.Windows(1).WindowState = xlMaximized
Workbook1.Windows(1).Left = 0

' Open the second workbook and position it on the right monitor
Set Workbook2 = ExcelApp.Workbooks.Open("C:\Users\whull\Desktop\VacationCalendar_RIGHT.xlsx")
Workbook2.Windows(1).WindowState = xlMaximized
Workbook2.Windows(1).Left = Screen.Width \ Screen.TwipsPerPixelX

' Release objects
Set Workbook1 = Nothing
Set Workbook2 = Nothing
Set ExcelApp = Nothing
End Sub
excel vba windows powershell sendkeys
1个回答
0
投票

试试这个代码。这会将 Excel 文件移动到右侧监视器。我已经尝试过并且有效。我已经对代码进行了注释,因此您应该不会在理解它时遇到问题。

重要提示:由于我们使用的是VBA代码,因此您的文件需要保存为

.xlsm
而不是
.xlsx

在ThisWorkbook代码模块中。

Option Explicit

Private Declare PtrSafe Function SetWindowPos Lib "user32" (ByVal hwnd As LongPtr, _
ByVal hWndInsertAfter As LongPtr, ByVal x As Long, ByVal y As Long, _
ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long

Private Const SWP_NOSIZE As Long = &H1
Private Const SWP_NOACTIVATE As Long = &H10
Private Const SWP_NOZORDER As Long = &H4

Private Sub Workbook_Open()
    Dim leftPos As Long
    Dim appHwnd As Long
    
    '~~> Get the left position of the second monitor
    leftPos = GetSecondMonitorLeft()
    
    If leftPos = -1 Then
        MsgBox "No second monitor detected.", vbInformation
    Else
        '~~> Get the handle of the Excel application window
        appHwnd = Application.hwnd
        
        '~~> This is important because you can't move a maximized window
        Application.WindowState = xlNormal
        
        '~~> Move the application window to the second monitor
        SetWindowPos appHwnd, 0, leftPos, 0, 0, 0, _
        SWP_NOSIZE Or SWP_NOZORDER Or SWP_NOACTIVATE
        
        '~~> Maximize the application window
        Application.WindowState = xlMaximized
    End If
End Sub

在普通模块中

Option Explicit

Private Declare PtrSafe Function GetSystemMetrics32 Lib "user32" Alias _
"GetSystemMetrics" (ByVal nIndex As Long) As Long

Private Declare PtrSafe Function EnumDisplayMonitors Lib "user32" (ByVal hdc As LongPtr, _
ByVal lprcClip As LongPtr, ByVal lpfnEnum As LongPtr, ByVal dwData As LongPtr) As Boolean

Private Declare PtrSafe Function GetMonitorInfo Lib "user32.dll" Alias _
"GetMonitorInfoA" (ByVal hMonitor As LongPtr, ByRef lpmi As Any) As Long

Private Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias _
"RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)

Private Type RECT
    Left As Long
    Top As Long
    Right As Long
    Bottom As Long
End Type

Private Type monitorInfo
    cbSize As Long
    rcMonitor As RECT
    rcWork As RECT
    dwFlags As Long
End Type

Private Const SM_CMONITORS As Long = 80

'~~> This function gets the .Left of the 2nd monitor
Public Function GetSecondMonitorLeft() As Long
    Dim monitorCount As Integer
    Dim monitorInfo As monitorInfo
    Dim hdc As LongPtr
    Dim monCount As Long
    
    monitorInfo.cbSize = Len(monitorInfo)
    hdc = 0
    
    '~~> This will get the number of monitors
    monitorCount = GetSystemMetrics32(SM_CMONITORS)
    
    '~~> Check if there are at least 2 monitors
    If monitorCount >= 2 Then
        '~~> Get the information of the second monitor
        EnumDisplayMonitors 0, ByVal 0, AddressOf MonitorEnumProc, VarPtr(monitorInfo)
        
        monCount = monitorInfo.rcMonitor.Left
    Else
        '~~> If there is only 1 monitor, return -1
        monCount = -1
    End If
    
    GetSecondMonitorLeft = monCount
End Function

Private Function MonitorEnumProc(ByVal hMonitor As LongPtr, ByVal hdcMonitor As LongPtr, _
ByVal lprcMonitor As LongPtr, ByVal dwData As LongPtr) As Long
    Dim monitorInfo As monitorInfo
    
    monitorInfo.cbSize = Len(monitorInfo)
    GetMonitorInfo hMonitor, monitorInfo
    
    '~~> Here we copy the monitor info to the provided structure
    CopyMemory ByVal dwData, monitorInfo, Len(monitorInfo)
    
    '~~> Next enumeration
    MonitorEnumProc = 1
End Function

示例文件:

您可以从这里下载示例文件进行测试。

© www.soinside.com 2019 - 2024. All rights reserved.