我想使用 PowerShell 以编程方式在 Windows 中切换飞行模式。经过一番研究,我发现这可以通过 COM 接口和本机 Windows API 来完成。下面是我编写的一个脚本,它使用 P/Invoke 成功切换了飞行模式。
下面是一个 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 中的飞行模式。下面详细介绍了脚本的工作原理以及为什么需要特定元素。
初始化和设置:
Add-Type
定义所需的 COM 方法和委托以包含 C# 代码。它使用 CoInitialize
初始化 COM 库,并使用 CoCreateInstance
创建 COM 对象的实例。使用
$methodPtr
进行方法解析:
$methodPtr
是从 COM 对象的虚拟函数表 (vtable) 中提取的指针数组。该表包含对象方法的内存地址。Marshal.Copy
,函数指针被复制到 $methodPtr
,使各个方法可以通过其索引访问。使用
$methodPtr
方法:
$methodPtr[5]
:调用 GetSystemRadioState
获取当前飞行模式状态。$methodPtr[6]
:调用 SetSystemRadioState
设置(或切换)飞行模式。$methodPtr[2]
:使用后调用Release
释放COM对象。vtable 中的方法列表:
COM 对象通过
$methodPtr
: 公开以下方法
Method 0
:QueryInterface
(COM 对象通信的内部)。Method 1
:AddRef
(增加引用计数)。Method 2
:Release
(减少引用计数,释放资源)。Method 5
:GetSystemRadioState
(获取当前飞行模式状态)。Method 6
:SetSystemRadioState
(切换或设置飞行模式)。切换飞行模式:
0
委托检索飞行模式的当前状态(1
表示启用,GetSystemRadioState
表示禁用)。SetSystemRadioState
委托应用新状态。清洁:
Release
方法释放COM对象,并调用CoUninitialize
来清理COM环境。[UnmanagedFunctionPointer]
?[UnmanagedFunctionPointer]
属性至关重要,因为它允许脚本定义表示非托管函数指针的托管委托。这些是从 COM 对象的 vtable 调用方法所必需的。
与本机代码交互:
[UnmanagedFunctionPointer]
的委托充当桥梁,使托管代码能够与非托管函数指针进行交互。指定调用约定:
CallingConvention.StdCall
确保方法调用遵循 COM 对象使用的正确调用约定。映射方法签名:
此脚本演示了 PowerShell 如何与 COM 接口交互以实现高级 Windows 功能,例如切换飞行模式,而无需依赖外部工具或 GUI。