【问题标题】:How can I resize the desktop work area using the SPI_SETWORKAREA flag?如何使用 SPI_SETWORKAREA 标志调整桌面工作区的大小?
【发布时间】:2011-09-10 03:59:18
【问题描述】:

我一直在尝试调整桌面工作区(窗口最大化的区域)的大小。我找到了所需的 API,但似乎无法调整工作区的大小。它什么都不做。

我使用的是 Windows 7 Ultimate x64,所以我也尝试在 x64“模式”下编译它,但仍然没有运气。有人可以推动我朝着正确的方向前进吗?

这是我目前得到的:

[DllImport("user32.dll", EntryPoint = "SystemParametersInfoA")]
private static extern Int32 SystemParametersInfo(Int32 uAction, Int32 uParam, IntPtr lpvParam, Int32 fuWinIni);

private const Int32 SPIF_SENDWININICHANGE = 2;
private const Int32 SPIF_UPDATEINIFILE = 1;
private const Int32 SPIF_change = SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE;
private const Int32 SPI_SETWORKAREA = 47;
private const Int32 SPI_GETWORKAREA = 48;

public struct RECT
{
    public Int32 Left;
    public Int32 Right;
    public Int32 Top;
    public Int32 Bottom;
}

private static int SetWorkspace(RECT oRECT)
{
    IntPtr ptr = IntPtr.Zero;
    ptr = Marshal.AllocHGlobal(Marshal.SizeOf(oRECT));
    Marshal.StructureToPtr(oRECT, ptr, true);
    return SystemParametersInfo(SPI_SETWORKAREA, Marshal.SizeOf(oRECT), ptr, SPIF_change);
}

【问题讨论】:

  • 您到底为什么要调用该函数的 ASCII 版本,而不是宽版本?
  • 试试这个:SystemParametersInfo(SPI_SETWORKAREA, 1, &NewRect, SPIF_SENDCHANGE);

标签: c# .net windows winapi pinvoke


【解决方案1】:

以下代码应该可以正常工作:

// 1. Change the function to call the Unicode variant, where applicable.
// 2. Ask the marshaller to alert you to any errors that occur.
// 3. Change the parameter types to make marshaling easier. 
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SystemParametersInfo(
                                                int uiAction,
                                                int uiParam,
                                                ref RECT pvParam,
                                                int fWinIni);

private const Int32 SPIF_SENDWININICHANGE = 2;
private const Int32 SPIF_UPDATEINIFILE = 1;
private const Int32 SPIF_change = SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE;
private const Int32 SPI_SETWORKAREA = 47;
private const Int32 SPI_GETWORKAREA = 48;

[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
    public Int32 Left;
    public Int32 Top;   // top is before right in the native struct
    public Int32 Right;
    public Int32 Bottom;
}

private static bool SetWorkspace(RECT rect)
{
   // Since you've declared the P/Invoke function correctly, you don't need to
   // do the marshaling yourself manually. The .NET FW will take care of it.

   bool result = SystemParametersInfo(SPI_SETWORKAREA,
                                      IntPtr.Zero,
                                      ref RECT,
                                      SPIF_change);
   if (!result)
   {
       // Find out the error code
       MessageBox.Show("The last error was: " +
                       Marshal.GetLastWin32Error().ToString());
   }

   return result;
}

但我不太确定你想做什么。默认情况下,工作区是未被系统任务栏或应用程序桌面工具栏遮挡的屏幕部分。您将无法使其大于屏幕上可用的区域(不过,如果可以的话,这是巧妙的技巧!)。当您最大化它们时,您的窗口是否还没有填满整个屏幕?

即使在具有多个显示器的机器上,您也无法将工作区域设置为跨越多个显示器。 MSDN documentation 表示它仅限于设置包含指定矩形的监视器的工作区域:

在具有多个显示器的系统中,该函数设置包含指定矩形的显示器的工作区域。

【讨论】:

  • 您的代码修复了它,而且我的 RECT 点在屏幕之外。还是谢谢!
  • @Cody Gray。我面临着类似的问题。我正在从我的应用程序启动子第二个应用程序,并在第二个应用程序中执行 SetParent(2ndAppHandle, 1stAppHandle)。但现在我的第二个应用程序仅限于第一个屏幕。我正在尝试将工作区区域设置为第二个屏幕;但如上所述,它给出了 InvalidParameters 错误。你能帮我解决一下吗???
  • @Akshay 这与这个问题或这个答案有什么关系?
  • @CodyGray 我正在尝试将第二个/子应用程序的工作区区域设置为占用 2 个屏幕。因为当我通过设置 Window.Left > primaryMonitorWidth 在第二个监视器上移动我的第二个应用程序时,它被切断并且不显示,作为启动它的父/第一个应用程序,只有第一个屏幕的工作区。
  • 是的,跨进程使用 SetParent 存在各种问题。我从来没有真正尝试过做你所描述的事情。如果您希望我或其他人进行调查,您应该提出一个新问题。包括一个minimal reproducible example 来重现您的问题。你知道 SPI_SETWORKAREA 是一个 global 设置,对吧?它不接受窗口句柄或进程句柄作为参数,因此不可能特定于任何一个。函数名是一个线索:系统参数。 @akshay
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-17
  • 2012-06-17
  • 1970-01-01
  • 2012-10-13
相关资源
最近更新 更多