通过 PowerShell Pinvoking user32.dll "SetWindowCompositionAttribute"

Pinvoking user32.dll "SetWindowCompositionAttribute" via PowerShell

我一直在努力让 PowerShell 通过 Pinvoke 控制 SetWindowCompositionAttribute(将 Windows 10 Acrylic Blur effect 添加到 Windows 任务栏和其他 windows 通过 PowerShell)。

我很乐意发送简单的参数,例如 HWND 和各自的值(如下面的两个示例所示)。但是,我不确定如何增强下面的 PowerShell 代码,以便它也可以处理打包在结构中的发送参数。参见 SetWindowCompositionAttribute

我在 Delphi and AutoIt(而不是 PowerShell)中看到了执行此操作的代码示例。不幸的是,我无法弄清楚它们。

无论如何,下面是我的工作 PowerShell 代码和用法示例,演示了与 Windows API 的基本交互。我希望有人可以帮助我增强此代码(通过几个示例)以控制 SetWindowCompositionAttribute.

提供的各种功能

最终,我希望能够指定 hWnd,Windows class 名称,and/or Window 我希望添加模糊的组件的标题名称也;并且,如果可能,请指定 blur/transparency 的数量。

工作函数和示例用法:

$script:nativeMethods = @();

function Register-NativeMethod([string]$dll, [string]$methodSignature) {
    $script:nativeMethods += [PSCustomObject]@{ Dll = $dll; Signature = $methodSignature; }
}

function Add-NativeMethods() {
    $nativeMethodsCode = $script:nativeMethods | % { "
        [DllImport(`"$($_.Dll)`")]
        public static extern $($_.Signature);
    " }

    Add-Type @"
        using System;
        using System.Runtime.InteropServices;
        public class NativeMethods {
            $nativeMethodsCode
        }
"@
}

#Build class and registers them:
Add-NativeMethods


#Example 1:
Register-NativeMethod "user32.dll" "bool SetForegroundWindow(IntPtr hWnd)"
[NativeMethods]::SetForegroundWindow((Get-Process -name notepad).MainWindowHandle)

#Example 2:
Register-NativeMethod "user32.dll" "bool ShowWindow(IntPtr hWnd, int nCmdShow)"
[NativeMethods]::ShowWindow((Get-Process -name notepad).MainWindowHandle, 0)

我可以看到您通过 Powershell 脚本中的 embedding/building C# 源代码调用这些 Windows API 函数。这可能是要走的路,尽管我认为我不会费心尝试 'add' 方法并逐段构建 C# 源代码(因为声明 SetWindowCompositionAttribute 使用您的系统不会是那样简单)。

首先,由于 SetWindowCompositionAttribute 接受复杂参数,因此您必须在 C# 代码中声明底层结构,然后您可以公开简化 SetWindowCompositionAttribute 使用的 C# 方法,供Powershell 端。

通过谷歌搜索(只需输入 TheMethodINeedToWrap C#),我很快找到了一些资源。我将这些发现混合到一个 C# class 中,它公开了一个(足够简单,可以通过 Powershell 调用)方法来模糊 window。我的测试结果并不理想,因为我得到了一个模糊的 window 边框,但内部和控件看起来很奇怪(一定与 winforms and/or 和 window 创建参数有关),但至少我得到了一些东西。

因为它有点长,我把这个class保存为要点here,但正如我所说,它由一堆互操作结构和方法定义组成,然后是public 方法简化了对 SetWindowCompositionAttribute.

的访问

PS:如果 SetWindowCompositionAttribute 证明太难包装,DwmSetWindowAttribute may be a viable aleternative. You'll also find that, although it sometimes needs tweaking, http://pinvoke.net/ 证明是互操作定义的可行来源。

编辑:添加了带有颜色着色的“亚克力”模糊选项。虽然移动 windows 左右时似乎有点慢。

这就是你想要的吗?

Window 在 运行 函数之前:

Window 在 运行 函数之后 (Set-WindowBlur -MainWindowHandle 853952 -Enable):

主要代码:

$SetWindowComposition = @'
[DllImport("user32.dll")]
public static extern int SetWindowCompositionAttribute(IntPtr hwnd, ref WindowCompositionAttributeData data);

[StructLayout(LayoutKind.Sequential)]
public struct WindowCompositionAttributeData {
    public WindowCompositionAttribute Attribute;
    public IntPtr Data;
    public int SizeOfData;
}

public enum WindowCompositionAttribute {
    WCA_ACCENT_POLICY = 19
}

public enum AccentState {
    ACCENT_DISABLED = 0,
    ACCENT_ENABLE_BLURBEHIND = 3,
    ACCENT_ENABLE_ACRYLICBLURBEHIND = 4
}

[StructLayout(LayoutKind.Sequential)]
public struct AccentPolicy {
    public AccentState AccentState;
    public int AccentFlags;
    public int GradientColor;
    public int AnimationId;
}
'@
Add-Type -MemberDefinition $SetWindowComposition -Namespace 'WindowStyle' -Name 'Blur'
function Set-WindowBlur {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory)]
        [int]
        $MainWindowHandle,
        [Parameter(ParameterSetName='Enable',Mandatory)]
        [switch]
        $Enable,
        [Parameter(ParameterSetName='Acrylic',Mandatory)]
        [switch]
        $Acrylic,
        # Color in BGR hex format (for ease, will just be used as an integer), eg. for red use 0x0000FF
        [Parameter(ParameterSetName='Acrylic')]
        [ValidateRange(0x000000, 0xFFFFFF)]
        [int]
        $Color= 0x000000,
        # Transparency 0-255, 0 full transparency and 255 is a solid $Color
        [Parameter(ParameterSetName='Acrylic')]
        [ValidateRange(0, 255)]
        [int]
        $Transparency = 80,
        [Parameter(ParameterSetName='Disable',Mandatory)]
        [switch]
        $Disable
    )
    $Accent = [WindowStyle.Blur+AccentPolicy]::new()
    switch ($PSCmdlet.ParameterSetName) {
        'Enable' {
            $Accent.AccentState = [WindowStyle.Blur+AccentState]::ACCENT_ENABLE_BLURBEHIND
        }
        'Acrylic' {
            $Accent.AccentState = [WindowStyle.Blur+AccentState]::ACCENT_ENABLE_ACRYLICBLURBEHIND
            $Accent.GradientColor = $Transparency -shl 24 -bor ($Color -band 0xFFFFFF)
        }
        'Disable' {
            $Accent.AccentState = [WindowStyle.Blur+AccentState]::ACCENT_DISABLED
        }
    }
    $AccentStructSize = [System.Runtime.InteropServices.Marshal]::SizeOf($Accent)
    $AccentPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($AccentStructSize)
    [System.Runtime.InteropServices.Marshal]::StructureToPtr($Accent,$AccentPtr,$false)
    $Data = [WindowStyle.Blur+WindowCompositionAttributeData]::new()
    $Data.Attribute = [WindowStyle.Blur+WindowCompositionAttribute]::WCA_ACCENT_POLICY
    $Data.SizeOfData = $AccentStructSize
    $Data.Data = $AccentPtr
    $Result = [WindowStyle.Blur]::SetWindowCompositionAttribute($MainWindowHandle,[ref]$Data)
    if ($Result -eq 1) {
        Write-Verbose "Successfully set Window Blur status."
    }
    else {
        Write-Verbose "Warning, couldn't set Window Blur status."
    }
    [System.Runtime.InteropServices.Marshal]::FreeHGlobal($AccentPtr)
}

使用 call 类似的东西:

Set-WindowBlur -MainWindowHandle 1114716 -Acrylic -Color 0xFF0000 -Transparency 50
Set-WindowBlur -MainWindowHandle 1114716 -Disable
Set-WindowBlur -MainWindowHandle 1114716 -Enable

改编自:https://gist.github.com/riverar/fd6525579d6bbafc6e48 来自: https://github.com/riverar/sample-win32-acrylicblur/blob/master/MainWindow.xaml.cs