返回列表 发帖

[问题求助] 如何让PowerShell创建的窗口居中显示在已打开的某窗口中央

下面的代码可以在屏幕中央显示一个窗口, 我想让窗口显示在已打开的记事本窗口中央, 如果没有记事本窗口才显示在屏幕中央, 还没搜索到相关的资料
Add-Type -AssemblyName system.Windows.Forms
Add-Type -AssemblyName system.Drawing
$Form = New-Object windows.Forms.Form
$Form.Size = New-Object drawing.Size(200, 120)
$Form.startposition = "centerscreen"
$Form.Text = "Test of Form"
$Form.MaximizeBox = $false
$Form.MinimizeBox = $false
$Form.Font = New-Object drawing.Font("Times New Roman", 10, [Drawing.FontStyle]::Bold)
$Form.BackColor = "LightBlue"
$Form.FormBorderStyle = "FixedSingle"
$Form.ShowDialog()COPY

用winapi
cls
#Windows API
$code=@'
    using System.Runtime.InteropServices;
    public static class WinApi{
        public struct Rect {
            public uint left;
            public uint top;
            public uint right;
            public uint bottom;
        };
        [DllImport("user32.dll")]
        public static extern bool SetWindowPos(uint hwnd,uint hpart,uint x,uint y,uint cx,uint cy,uint flags);
        [DllImport("user32.dll")]
        public static extern bool GetWindowRect(uint hwnd,ref Rect rect);
    }
'@
Add-Type -TypeDefinition $code
Add-Type -AssemblyName system.Windows.Forms
Add-Type -AssemblyName system.Drawing
$Form = New-Object windows.Forms.Form
$Form.Size = New-Object drawing.Size(200, 120)
$Form.Text = "Test of Form"
$Form.MaximizeBox = $false
$Form.MinimizeBox = $false
$Form.Font = New-Object drawing.Font("Times New Roman", 10, [Drawing.FontStyle]::Bold)
$Form.BackColor = "LightBlue"
$Form.FormBorderStyle = "FixedSingle"
$rect = New-Object 'WinApi+Rect'
$hwnd = (Get-Process notepad -ErrorAction SilentlyContinue| Select-Object -First 1).MainWindowHandle
if($hwnd -eq $null){
    $Form.StartPosition = 'CenterScreen'
} else {
    [void][WinApi]::GetWindowRect([int32]$hwnd,[ref]$rect)
    $x = $rect.left + ($rect.right - $rect.left - $Form.Width)/2
    $y = $rect.top + ($rect.bottom - $rect.top - $Form.Height)/2
    [WinApi]::SetWindowPos([int32]$Form.Handle,$null,$x,$y,0,0,1)
}
$Form.ShowDialog()COPY

TOP

回复 2# went


多谢大佬,

有两个问题请教:
1. 在我理解New-Object后应该跟着已经存在的类名, 但没有这个类
$rect = New-Object 'WinApi+Rect'   

2.如果记事本窗口处于最小化时, 执行代码, 也会有响应, 但是只在任务栏上显示一个按钮, 点它也没反应,
能否加个判断, 如果有记事本程序运行着, 先激活它一下变成当前窗口,然后再执行代码?

TOP

本帖最后由 went 于 2022-11-25 10:48 编辑

回复 3# 小白龙


    Rect是自定义的结构体
    不想用结构体也可以直接传数组参数
cls
#Windows API
$code=@'
    using System.Runtime.InteropServices;
    public static class WinApi{
        [DllImport("user32.dll")]
        public static extern bool SetWindowPos(uint hwnd,uint hpart,uint x,uint y,uint cx,uint cy,uint flags);
        [DllImport("user32.dll")]
        public static extern bool GetWindowRect(uint hwnd,uint[] arr);
        [DllImport("user32.dll")]
        public static extern bool ShowWindow(uint hwnd,uint show);
    }
'@
Add-Type -TypeDefinition $code
Add-Type -AssemblyName system.Windows.Forms
Add-Type -AssemblyName system.Drawing
$Form = New-Object windows.Forms.Form
$Form.Size = New-Object drawing.Size(200, 120)
$Form.Text = "Test of Form"
$Form.MaximizeBox = $false
$Form.MinimizeBox = $false
$Form.Font = New-Object drawing.Font("Times New Roman", 10, [Drawing.FontStyle]::Bold)
$Form.BackColor = "LightBlue"
$Form.FormBorderStyle = "FixedSingle"
$hwnd = (Get-Process notepad -ErrorAction SilentlyContinue| Select-Object -First 1).MainWindowHandle
if($hwnd -eq $null){
    $Form.StartPosition = 'CenterScreen'
} else {
    $arr = New-Object 'int32[]'(4)
    [void][WinApi]::ShowWindow([int32]$hwnd,1)
    [void][WinApi]::GetWindowRect([int32]$hwnd,$arr)
    $x = $arr[0] + ($arr[2] - $arr[0] - $Form.Width)/2
    $y = $arr[1] + ($arr[3] - $arr[1] - $Form.Height)/2
    [void][WinApi]::SetWindowPos([int32]$Form.Handle,$null,$x,$y,0,0,1)
}
$Form.ShowDialog()COPY
1

评分人数

TOP

本帖最后由 小白龙 于 2022-11-25 13:08 编辑

回复 4# went


大佬技术666

我对C#不太懂, 但看起来还是前面的相对好理解一些,
另外, 请教大佬:
自定义的结构体,在新建其对象时, 必须要下面这种 类名+结构名 格式吗必须要+加号? 我改其它的名字都报错

'WinApi+Rect'

TOP

我是按tab自动补全出来的
试了下内部类和结构,在Powershell里都要用 [外部类名+内部类名]来表示
$code=@'
    public static class A{
        public static class A1 {}
    }
    public static class B{
        public struct B1 {}
        public class B2{}
    }
    public class C{
        public class C1{}
    }
    public struct D{}
'@
Add-Type -TypeDefinition $code
#A & A+A1 & B 为静态类不能实例化对象
New-Object 'B+B1'
New-Object 'B+B2'
New-Object 'C'
New-Object 'C+C1'
New-Object 'D'COPY

TOP

回复 6# went

非常感谢大佬详细解释,

我一直以为一个类里只能包含方法, 属性, 您上面的代码中, 类里又嵌套了各种类, 还包含了结构, 实在太复杂了,

下面是#2楼的第42行代码, 我把$null改成0也能运行, 我看后面也有两个0 这里用$null有什么含义吗
[WinApi]::SetWindowPos($Form.Handle, $null, $x, $y, 0, 0, 1)

[WinApi]::SetWindowPos($Form.Handle, 0, $x, $y, 0, 0, 1)

TOP

$null即0,只是类型不同,前者为指针,后者为数字,在winapi里面没有区别

TOP

回复 8# went

多谢大佬指教

TOP

返回列表