【问题标题】:How to programmatically move Windows taskbar?如何以编程方式移动 Windows 任务栏?
【发布时间】:2011-01-05 06:24:03
【问题描述】:

我想知道任何类型的 API 或解决方法(例如脚本或注册表),以将 Windows 任务栏移动(或调整大小)到另一个位置,包括另一个显示器(如果是双显示器)。当然,我们可以使用鼠标移动任务栏,但我想通过程序或某种自动化方式移动它。

我试图找到 Win32 API,但似乎没有人做这项工作。

编辑:我对很多人的意见感到惊讶。让我解释一下我为什么想要它。在我的工作场所,我使用双显示器(分辨率不同),任务栏放在左显示器上,而主显示器是右显示器。但是,我经常通过远程桌面连接到我的工作电脑。远程连接后,切换任务栏位置。这就是为什么我想制作一个可以保存/恢复任务栏位置的简单程序。每天我都必须重新排列我的任务栏。而已。我只想要

【问题讨论】:

  • 为什么投反对票?这是一个精心设计的问题。至于可疑的意图,我看到这里的回答要糟糕得多......
  • 嗯,Thomas,可以说这个问题没有用,因为它不是程序应该做的任务。但是,我们并不真正知道 Minjang 计划的意图,所以让我们都猜疑一下,好吗?
  • “不是程序应该做的任务”——真的吗?你是如何得出这个结论的 Rob?如果您曾经在多显示器环境中工作过,那么您就会知道这些类型的应用程序(例如 UltraMon - realtimesoft.com/ultramon)几乎是必不可少的。谁指定了你应该做什么程序的上帝?这是一个非常好的问题;来自我的 +1。
  • 这种类型的关注可以在任何应用程序中提出。此问题中没有任何内容表明您所关心的动机。
  • 杰拉德,你误解了我写的东西。我在给 Thomas 一个理由,有人可能用来证明投票反对这个问题是正当的。我没有说我投了反对票,我没有说如果我投了它会是我的理由,我也没有说这是真的。这显然是一些人认为程序不应该做的事情。因此,认为不应该这样做的人可能会认为询问如何去做的问题不是一个有用的问题。 (顺便说一句,我现在正在使用多显示器设置,而且我根本不认为这些程序是必不可少的。我看不到自己使用 Ultramon 的任何功能。)

标签: c++ windows winapi


【解决方案1】:

我在 Windows 7 上也有此需求。以下是我使用自动热键脚本执行此操作的方法:

; 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 上对此进行了测试。要使用此功能,请指定一个热键来调用此脚本,然后将鼠标光标定位到要将任务栏拖到的位置,然后按热键。

【讨论】:

  • 完美运行!谢谢! (为了我的分辨率和主题,我不得不将精确坐标调整为 x+10, y-35)
  • 正是我所需要的,这让我发疯了。谢谢!注意:我必须使用 w 和 h 变量来为不同的任务栏起始位置定义单独的偏移量。
  • 适用于 Windows 10。我对其稍作修改以使任务栏始终大小相同,并将其添加到调度程序以在工作站解锁时运行。
【解决方案2】:

任务栏是一个窗口。使用SetWindowPos() 移动它。另请参阅 SHAppBarMessage() 和 ABM_WINDOWPOSCHANGED。

虽然任务栏可能很特殊,Windows 可能不喜欢你移动它。任务栏的 Shell appbar API 实现有很多特殊情况。

要移动到另一台显示器,请使用 EnumDisplayMonitors()GetMonitorInfo()。有些显示器可能有负坐标。

【讨论】:

  • 这是一个糟糕的主意。请不要对您的客户这样做。
  • 直到 OP 告诉我们他为什么要这样做,我们才知道。有两件事需要考虑:是否可能以及这是一个好主意。我们在这里只考虑前者而不考虑后者。虽然我通常同意移动用户任务栏并不好,但我也可以看到至少两个有效案例可以根据用户请求移动它。既然我们不知道,我们尽量不要评判太多。
  • @jeffamaphone:我们在这里是因为我们选择在这里。你是谁说我们只是为了一个人而不是另一个人?
【解决方案3】:

我在 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}
}

【讨论】:

    【解决方案4】:

    据我所知,Vista 及更高版本会忽略任何试图移动任务栏的程序。旧方法是 ABM_SETPOS + MoveWindow,这不再适用于任务栏。我知道仍然有效的唯一方法是模拟鼠标移动(点击移动释放)。我读过这种方法,但我自己从来没有做过。

    【讨论】:

      【解决方案5】:

      感谢您提出这个问题!

      它现在是 Windows 10,我遇到了同样的问题,我制作了一个脚本来在 2 个屏幕设置和只有电视的电影之间切换。切换回 2 个屏幕设置后,任务栏又回到了右侧的显示器上,就像您所经历的一样。

      我找到了一个解决方案,涉及修改定义任务栏位置的注册表项

      这是说的关键: HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\StuckRects3

      打开注册表编辑器当你的任务栏在正确的位置和大小时(Win+R,输入regedit”,回车),然后导航到上面的关键路径。你应该找到一个二进制文件名为“设置”的值如下所示:

      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 是 f8 ff ff ea 05 00 00 60 00 00 00 01 0 0 00

      您的数字可能会有所不同,但这并不重要。导航到该值后,只需单击菜单中的文件>导出操作,然后使用顶部菜单中的文件->导出选项,并将 .reg 文件 保存在系统文件夹中(C:\Windows\ System32)。确保导出范围设置为“选定分支”,因此只有该值受到影响。这将创建一个注册表脚本,它将恢复您的任务栏的确切位置。

      但是,如果您只是在脚本上使用“合并”选项,您将看不到更改,因为您需要重新启动 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 短暂闪烁,因为任务栏和桌面将重置

      您可以从任务中调用此脚本,或创建一个快捷方式,设置为以管理员身份运行以使其更容易!

      我希望这个答案能传达给你,即使是“有点”迟到了 XD

      欢迎您!

      【讨论】:

      • 感谢您为我省去了查找正确 reg 密钥的麻烦 :D 我将其与 taskchd 结合使用,以免获得 UAC 提示(没有完全停用它)。您必须专门使用它来调用regedit,以这种方式启动bat会提示UAC进行regedit winhelponline.com/blog/…
      【解决方案6】:

      SHAppBarMessage(ABM_SETPOS,...)

      【讨论】:

      • ABM_GETTASKBARPOS 检索任务栏的位置。但是,ABM_SETPOS 不能正常工作。我通过查找“Shell_TrayWnd”获得了任务栏的 hWnd。 (我使用的是 Windows 7)但是,没有运气。 MoveWindow/SetWindowPos 和任何其他 ABM_* 都不起作用。但是,谢谢。
      【解决方案7】:

      这是一个使用 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 注册表流的第 13 位:

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

      之后,它会杀死 explorer.exe 进程,等待大约 5 秒钟,如果 explorer 没有再次启动,它将启动一个新实例。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-01-03
        • 1970-01-01
        • 1970-01-01
        • 2011-05-06
        • 1970-01-01
        • 2010-10-15
        • 2022-01-12
        • 1970-01-01
        相关资源
        最近更新 更多