簡體   English   中英

如何以編程方式移動 Windows 任務欄?

[英]How to programmatically move Windows taskbar?

我想知道任何類型的 API 或解決方法(例如,腳本或注冊表)以將 Windows 任務欄移動(或調整大小)到另一個 position 包括另一個顯示器(如果雙顯示器)。 當然,我們可以使用鼠標移動任務欄,但我想通過程序或某種自動化方式移動它。

我試圖找到 Win32 API,但似乎沒有人做這項工作。

編輯:我對很多人的意見感到驚訝。 讓我解釋一下為什么我想要它。 在我的工作場所,我使用雙顯示器(分辨率不同),任務欄位於左側顯示器上,而主顯示器是右側顯示器。 但是,我經常通過遠程桌面連接到我工作場所的計算機。 遠程連接后切換到任務欄position。 這就是為什么我想制作一個簡單的程序來保存/恢復任務欄的 position。每天我都必須重新排列我的任務欄。 就是這樣。 我只是想要它給

我在 Windows 7 上也有這個需求。這是我使用 autohotkey 腳本執行此操作的方法:

; This script will try to drag and move the taskbar to where the *current* mouse
; cursor is

; 0x111: WM_COMMAND, 424: lock/unlock taskbar, http://www.codeproject.com/KB/miscctrl/Taskbar_Manipulation.aspx
RegRead, TaskbarLocked, HKEY_CURRENT_USER, SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced, TaskbarSizeMove
If TaskbarLocked = 0
  SendMessage 0x111, 424, , , ahk_class Shell_TrayWnd   

WinActivate ahk_class Shell_TrayWnd
MouseGetPos targetX, targetY
ControlGetPos x, y, w, h, MSTaskListWClass1, ahk_class Shell_TrayWnd
MouseMove x+1, y+1
MouseClickDrag Left, x+1, y+1, targetX, targetY, 10

; often after dragging the taskbar to left or right side of a monitor, even though
; there are enough room to show two columns of icons, it will only show one column,
; it seems showing or hiding an icon will fix this
Menu, Tray, NoIcon
Menu, Tray, Icon

; lock the taskbar if it was previously locked
If TaskbarLocked = 0
  SendMessage 0x111, 424, , , ahk_class Shell_TrayWnd   

我已經在帶有經典窗口主題的 Windows 7 上對此進行了測試。 要使用它,請分配一個熱鍵來調用此腳本,然后將鼠標光標定位到要將任務欄拖到的位置,然后按熱鍵。

任務欄是一個窗口。 使用SetWindowPos()移動它。 另見SHAppBarMessage()和 ABM_WINDOWPOSCHANGED。

盡管任務欄可能很特殊,Windows 可能不喜歡您四處移動它。 任務欄的Shell appbar API實現中有很多特殊情況。

要移動到另一個監視器,請使用EnumDisplayMonitors()GetMonitorInfo() 一些顯示器可能有負坐標。

我在 AutoHotkey 腳本中完成了這項任務,以防萬一您不關心所使用的語言。 它使用模擬的擊鍵和鼠標移動來移動您的任務欄。 我沒有自動解鎖/鎖定任務欄。

困難的部分是讓它可靠地工作。 許多代碼專門用於確保任務欄移動。 它仍然不能 100% 工作......從我所看到的情況來看,它有 10% 的時間失敗。 但是,它應該足以讓您入門!

如果我回到這個腳本以使其完美運行,我會在這里重新發布。

這是示例腳本(這里的突出顯示有點奇怪,因為語言是 AHK):

F3::
    reload
return

F5::
    MoveTaskbar(2,"bottom")
return

F6::
    MoveTaskbar(2,"left")
return

F7::
    MoveTaskbar(1,"top")
return

; Move the taskbar
; dspNumber:    number.  device number (primary display is 1, secondary display is 2...)
; edge:         string.  Top, Right, Bottom, or Left
MoveTaskbar(dspNumber, edge)
{
    Critical 
    OutputDebug MoveTaskbar - called to move taskbar to display #%dspNumber% ("%edge%" edge)

    ; absolute coordinate system
    CoordMode, Mouse, Screen

    ; error checking for dspNumber
    SysGet, numMonitors, MonitorCount
    if (numMonitors<dspNumber)
    {
        OutputDebug MoveTaskbar - [ERROR] target monitor does not exist (dspNumber = "%dspNumber%")
        return
    }

    ; get screen position for target monitor
    SysGet, target, Monitor, %dspNumber%

    oX := 7
    oY := 7

    ; get coordinates for where to move the taskbar
    if (edge = "Top")
    {
        oX := (targetRight-targetLeft)/2
        trgX := oX+targetLeft
        trgY := targetTop+15
    }
    else if (edge = "Right")
    {
        oY := -(targetBottom-targetTop)/2
        trgX := targetRight-15
        trgY := -oY + targetTop
    }
    else if (edge = "Bottom")
    {
        oX := -(targetRight-targetLeft)/2
        trgX := -oX+targetLeft
        trgY := targetBottom-15
    }
    else if (edge = "Left")
    {
        oY := (targetBottom-targetTop)/2
        trgX := targetLeft+15
        trgY := oY+targetTop
    }
    else
    {
        OutputDebug MoveTaskbar - [ERROR] target edge was improperly specified (edge = "%edge%")
        return
    }
    trgX := round(trgX)
    trgY := round(trgY)
    oX := round(oX)
    oY := round(oY)

    OutputDebug MoveTaskbar - target location is (%trgX%,%trgY%)
    MouseGetPos, startX, startY
    OutputDebug MoveTaskbar - mouse is currently at (%startX%,%startY%)

    ; request the move mode (via context menu)
    SendInput #b
    SendInput !+{Space}
    SendInput m

    ; wait for the move mode to be ready
    Loop 
    {
        if A_Cursor = SizeAll
            break
    }
    OutputDebug MoveTaskbar - move mode is ready

    ; start the move mode
    SendInput {Right}   

    ; wait for the move mode to become active for mouse control
    Loop 
    {
        if A_Cursor = Arrow
            break
    }
    OutputDebug MoveTaskbar - move mode is active for mouse control

    ; move taskbar (and making sure it actually does move)
    offset := 7
    count := 0
    Loop
    {
        ; move the taskbar to the desired location
        OutputDebug MoveTaskbar - attempting to move mouse to (%trgX%,%trgY%)
        MouseMove, %trgX%, %trgY%, 0
        MouseGetPos, mX, mY, win_id
        WinGetClass, win_class, ahk_id %win_id%

        count += 1

        ; if the mouse didn't get where it was supposed to, try again
        If ((mX != trgX) or (mY != trgY))
        {
            OutputDebug MoveTaskbar - mouse didn't get to its destination (currently at (%mX%,%mY%)).  Trying the move again...
            continue
        }

        ; if the taskbar hasn't followed yet, wiggle the mouse!
        if (win_class != "Shell_TrayWnd")
        {
            OutputDebug MoveTaskbar - window with class "%win_class%" is under the mouse... wiggling the mouse until the taskbar gets over here

            ;offset := - offset
            trgX -= round(oX/2)
            trgY -= round(oY/2)
            oX := -oX
            oY := -oY
            if count = 50
            {
                OutputDebug, MoveTaskbar - wiggling isn't working, so I'm giving up.
                return
            }
        }
        else
            break
    }

    OutputDebug MoveTaskbar - taskbar successfully moved
    SendInput {Enter}
}

據我所知,Vista 及以后的版本會忽略任何試圖移動任務欄的程序。 舊方法是 ABM_SETPOS + MoveWindow,這不再適用於任務欄。 我知道仍然有效的唯一方法是模擬鼠標移動(點擊-移動-釋放)。 我讀過這種方法,但我自己從來沒有做過。

感謝您提出這個問題!

它現在是 Windows 10,我遇到了同樣的問題,我制作了一個腳本來在 2 個屏幕設置和電影電視之間切換。 切換回 2 個屏幕設置后,任務欄又回到了正確的顯示器上,就像您所經歷的那樣。

我找到了一個解決方案,涉及修改定義任務欄位置的注冊表項

這是所說的鍵:HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\StuckRects3

在任務欄處於正確位置和大小時打開注冊表編輯器(Win+R,鍵入 regedit”,回車),然后導航到上面的關鍵路徑。您應該找到一個名為“Settings”的二進制值,如下所示:

30 00 00 00 fe ff ff 02 00 00 00 03 00 00 00 4e 00 00 00 32 00 00 00 80 f8 ff ff b2 01 00 00 0 0 ff 0 0 0 ff 0 0 0 ea

您的數字可能會有所不同,但這並不重要。 導航到該值后,只需單擊菜單中的文件>導出操作,然后使用頂部菜單中的文件->導出選項,並將 .reg 文件保存在您的系統文件夾 (C:\\Windows\\System32) 中 確保導出范圍設置為“Selected Branch”,這樣只有這個值會受到影響。 這將創建一個注冊表腳本,該腳本將恢復任務欄的確切位置。

但是,如果您只是在腳本上使用“合並”選項,您將看不到更改,因為您需要重新啟動 explorer.exe 進程 為此,您可以簡單地在 noptepad 中制作一個批處理腳本,如下所示:

@echo off
%windir%\system32\regedit.exe /s file.reg
taskkill /f /im explorer.exe
start explorer.exe
end

只需將第二行中的“file.reg”替換為您之前創建的 .reg 腳本的完整文件名,然后將該文件另存為“.bat”。

以管理員身份運行此腳本會將任務欄重置到應有的位置。 您將看到 ui 短暫閃爍,因為任務欄和桌面將重置

您可以從 Task 調用此腳本,或者創建一個設置為以管理員身份運行的快捷方式,以使其更容易!

我希望這個答案能傳達給你,即使是“有點”遲到 XD

歡迎您!

這是 PowerShell 的解決方案。我的代碼基於此處答案中提供的解決方案:

2,3 | ForEach-Object {
    $local:regPath = "HKCU:\$(
        )SOFTWARE\Microsoft\Windows\$(
            )CurrentVersion\Explorer\StuckRects$_"
    $s = Get-ItemProperty $regPath |
        Select-Object -ExpandProperty Settings
    $s[12] = 2
    Set-ItemProperty -Path $regPath -Name Settings -Value $s
}

# Restart the Explorer process so that registry is read again
Get-Process Explorer | Stop-Process
$local:stop = $false
do {
    Start-Sleep -Seconds 5
    $stop = Get-Process Explorer -ErrorAction SilentlyContinue
    if( $stop ) { continue }
    Write-Host -ForegroundColor Yellow "$(
        )Explorer hasn't auto-started, attempting to restart..."
    Start-Process Explorer
} until ( $stop )

代碼將更改為2 (右側) Settings注冊表 stream 的第 13 個 position 在以下鍵:

HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\StuckRects2
HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\StuckRects3

之后,它會殺死explorer.exe進程,等待大約 5 秒,如果 explorer 沒有再次啟動,它將啟動一個新實例。

SHAppBarMessage(ABM_SETPOS,...)

根據我的經驗,左右兩側的任務欄與體驗的 rest 不兼容。 即使是頂部也有預覽出現在頂部屏幕之外的問題。

對我來說,這在 windows 11 中有效,可以在頂部和底部之間切換任務欄。

$RegistryPath =  'HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\StuckRects3'
$Name = "Settings"

$NewValue = Get-ItemProperty -Path $RegistryPath
$NewValue.Settings[12] = 4-$NewValue.Settings[12]

Set-ItemProperty -Path $RegistryPath -Name $Name -Value $NewValue.Settings
Stop-Process -Name "Explorer"

資源管理器在被終止時自動啟動,因此無需手動啟動。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM