【问题标题】:Pinvoking user32.dll "SetWindowCompositionAttribute" via PowerShell通过 PowerShell 调用 user32.dll “SetWindowCompositionAttribute”
【发布时间】:2021-02-02 01:58:07
【问题描述】:

我一直在努力让 PowerShell 通过 Pinvoke 控制 SetWindowCompositionAttribute(通过 PowerShell 向 Windows 任务栏和其他窗口添加 Windows 10 Acrylic Blur 效果)。

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

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

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

最终,我希望能够指定 hWnd、Windows 类名和/或我希望添加模糊的组件的窗口标题名称;如果可能,请指定模糊/透明度的量。

工作功能和示例用法:

$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)

【问题讨论】:

  • 如果提供了正确的结构定义,p/invokeit 肯定是可行的。但是,您是否考虑过使用DwmSetWindowAttribute?似乎在做同样的事情,但采用“简单”输入值
  • 谢谢。知道我在哪里看到了如何使用它为窗口启用 Win10 Acrylic Blur 效果的示例吗?最终,我想这样做.. 使用 Powershell。
  • 不是这个问题的答案,但是如果你知道如何在 C# 中做某事,那么你也可以在 PowerShell 中轻松完成,看看@987654326 @查看如何在powershell中运行C#代码。

标签: c# powershell pinvoke


【解决方案1】:

编辑:添加了带有颜色着色的“丙烯酸”模糊选项。移动窗户时似乎有点慢。

这就是你所追求的吗?

函数运行前的窗口:

函数运行后的窗口(@98​​7654327@):

主要代码:

$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

【讨论】:

  • 这做得很漂亮!我可以为桌面上的各种 Windows 添加模糊效果;包括 Windows 文件资源管理器。我无法为 Windows 10 任务栏添加模糊效果。也许,我没有指定正确的 MainWindowHandle?有什么提示可以添加模糊任务栏?
  • @MKANET - 我原以为它会是exploer.exe 进程的句柄。 (并且任何更改都会影响文件资源管理器和任务栏)
  • @PMental,非常感谢。它工作得很好。我无法以任何方式影响 Windows 任务栏;即使指定 explorer.exe 的MainWindowHandle。最后,如何指定模糊效果的gradientcolor 值?不用担心,如果它需要大量代码更改。
  • @MKANET 它确实适用于我计算机上的任务栏,使用 explorer.exe 句柄,但出于某种原因,只有在您首先打开资源管理器窗口时才会这样做。不太清楚为什么。不确定渐变色是否用于模糊效果,但如果我能找到适合的东西,我可以看看。
  • @MKANET HWND handle = FindWindow(L"Shell_TrayWnd", NULL);(C++ 代码)获取正确的任务栏句柄。
【解决方案2】:

我可以看到您通过在 Powershell 脚本中嵌入/构建 C# 源代码来调用这些 Windows API 函数。这可能是要走的路,尽管我认为我不会费心尝试“添加”方法并逐段构建 C# 源代码(因为使用您的系统声明 SetWindowCompositionAttribute 不会那么容易)。

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

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

因为有点长,我将这个类保存为要点here,但正如我所说,它由一堆互操作结构和方法定义组成,然后是一个公共方法,简化了对SetWindowCompositionAttribute 的访问。

PS:如果SetWindowCompositionAttribute 被证明太难以包装,DwmSetWindowAttribute 可能是一个可行的替代方案。您还会发现,尽管有时需要对其进行调整,但 http://pinvoke.net/ 被证明是互操作定义的可行来源。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-03-12
    • 2012-03-23
    • 2012-09-27
    • 2012-10-14
    • 1970-01-01
    • 2010-12-05
    • 2020-12-13
    相关资源
    最近更新 更多