如何使用 PowerShell 在 Windows 中切换飞行模式?

问题描述 投票:0回答:1

我想使用 PowerShell 以编程方式在 Windows 中切换飞行模式。经过一番研究,我发现这可以通过 COM 接口和本机 Windows API 来完成。下面是我编写的一个脚本,它使用 P/Invoke 成功切换了飞行模式。

windows powershell airplane-mode
1个回答
0
投票

下面是一个 PowerShell 脚本,它使用 COM 接口和本机 Windows API 在 Windows 中切换飞行模式。

# script for toggling the airplane mode in Windows
# [email protected]

cls
remove-variable * -ea 0
$ErrorActionPreference = 'stop'

Add-Type -TypeDefinition @'
using System;
using System.Runtime.InteropServices;

public static class NativeMethods {
    [DllImport("ole32.dll")]
    public static extern int CoInitialize(IntPtr pv);
    [DllImport("ole32.dll")]
    public static extern void CoUninitialize();
    [DllImport("ole32.dll")]
    public static extern uint CoCreateInstance(Guid clsid, IntPtr pv, uint ctx, Guid iid, out IntPtr ppv);
}

[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate int GetSystemRadioStateDelegate(IntPtr cg, out int ie, out int se, out int p3);

[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate int SetSystemRadioStateDelegate(IntPtr ptr, int state);

[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate int ReleaseDelegate(IntPtr ptr);
'@

$CLSID = '581333F6-28DB-41BE-BC7A-FF201F12F3F6'
$IID   = 'DB3AFBFB-08E6-46C6-AA70-BF9A34C30AB7'
$CRID  = '73726163-6574-676e-6965-736531333131'
$mrs   = [System.Runtime.InteropServices.Marshal]

try {
    $irm  = 0
    $null = [NativeMethods]::CoInitialize(0)
    $null = [NativeMethods]::CoCreateInstance($CLSID, 0, 4, $IID, [ref]$irm)

    $comPtr  = $mrs::ReadIntPtr($irm)
    $methodPtr  = [IntPtr[]]::new(8)
    $mrs::Copy($comPtr, $methodPtr, 0, $methodPtr.Length)

    $getState = $mrs::GetDelegateForFunctionPointer($methodPtr[5], [GetSystemRadioStateDelegate])
    $setState = $mrs::GetDelegateForFunctionPointer($methodPtr[6], [SetSystemRadioStateDelegate])
    $release  = $mrs::GetDelegateForFunctionPointer($methodPtr[2], [ReleaseDelegate])

    # get the current airplane mode:
    $oldState, $p2, $p3 = (0,0,0)
    $null = $getState.Invoke($irm, [ref]$oldState, [ref]$p2, [ref]$p3)

    # toggle the state of the airplane mode (# 0=airplane_mode, 1=normal_mode):
    $newState = !$oldState
    $null = $setState.Invoke($irm, $newState)
    $null = $release.Invoke($irm)
}
finally {
    $null = [NativeMethods]::CoUninitialize()
}

此 PowerShell 脚本通过使用 P/Invoke 直接与 COM 接口和本机 Windows API 交互来切换 Windows 中的飞行模式。下面详细介绍了脚本的工作原理以及为什么需要特定元素。


代码逻辑解释

  1. 初始化和设置:

    • 该脚本使用
      Add-Type
      定义所需的 COM 方法和委托以包含 C# 代码。它使用
      CoInitialize
      初始化 COM 库,并使用
      CoCreateInstance
      创建 COM 对象的实例。
  2. 使用

    $methodPtr
    进行方法解析:

    • $methodPtr
      是从 COM 对象的虚拟函数表 (vtable) 中提取的指针数组。该表包含对象方法的内存地址。
    • 使用
      Marshal.Copy
      ,函数指针被复制到
      $methodPtr
      ,使各个方法可以通过其索引访问。
  3. 使用

    $methodPtr
    方法:

    • $methodPtr[5]
      :调用
      GetSystemRadioState
      获取当前飞行模式状态。
    • $methodPtr[6]
      :调用
      SetSystemRadioState
      设置(或切换)飞行模式。
    • $methodPtr[2]
      :使用后调用
      Release
      释放COM对象。
  4. vtable 中的方法列表:
    COM 对象通过

    $methodPtr
    :

    公开以下方法
    • Method 0
      QueryInterface
      (COM 对象通信的内部)。
    • Method 1
      AddRef
      (增加引用计数)。
    • Method 2
      Release
      (减少引用计数,释放资源)。
    • Method 5
      GetSystemRadioState
      (获取当前飞行模式状态)。
    • Method 6
      SetSystemRadioState
      (切换或设置飞行模式)。
    • 其他索引可能代表额外的内部或保留方法。
  5. 切换飞行模式:

    • 该脚本使用
      0
      委托检索飞行模式的当前状态(
      1
      表示启用,
      GetSystemRadioState
      表示禁用)。
    • 它通过否定当前值来切换状态,并使用
      SetSystemRadioState
      委托应用新状态。
  6. 清洁:

    • 使用
      Release
      方法释放COM对象,并调用
      CoUninitialize
      来清理COM环境。

为什么需要
[UnmanagedFunctionPointer]

[UnmanagedFunctionPointer]
属性至关重要,因为它允许脚本定义表示非托管函数指针的托管委托。这些是从 COM 对象的 vtable 调用方法所必需的。

  1. 与本机代码交互:

    • vtable 中的 COM 方法是在本机代码中实现的,不能直接从托管 .NET 方法中调用。
    • 具有
      [UnmanagedFunctionPointer]
      的委托充当桥梁,使托管代码能够与非托管函数指针进行交互。
  2. 指定调用约定:

    • CallingConvention.StdCall
      确保方法调用遵循 COM 对象使用的正确调用约定。
    • 不匹配的调用约定可能会导致运行时错误、内存损坏或崩溃。
  3. 映射方法签名:

    • 该属性确保托管委托的签名(参数、返回类型)与非托管方法的签名完全匹配,避免类型不匹配和未定义的行为。

此脚本演示了 PowerShell 如何与 COM 接口交互以实现高级 Windows 功能,例如切换飞行模式,而无需依赖外部工具或 GUI。

© www.soinside.com 2019 - 2024. All rights reserved.