PowerShell 5.1调用C#实现Focus Assist状态查询报错求助
解决PowerShell 5.1中调用Focus Assist状态检查代码的报错问题
问题根源
报错的核心原因有两个:
- PowerShell 5.1基于.NET Framework运行,
Add-Type不会自动引入核心命名空间,原代码缺少System和System.Runtime.InteropServices命名空间引用,导致编译器无法识别uint、DllImport等类型与特性。 - 原代码直接将
IntPtr强制转换为枚举的逻辑错误,pBuffer是指向返回数据的内存指针,需读取指针指向的实际值才能得到正确状态。
修复后的完整代码
$Focus = @{ Namespace = "WinAPI" Name = "Focus" Language = "CSharp" MemberDefinition = @" using System; using System.Runtime.InteropServices; [DllImport("NtDll.dll", SetLastError = true)] private static extern uint NtQueryWnfStateData(IntPtr pStateName, IntPtr pTypeId, IntPtr pExplicitScope, out uint nChangeStamp, out IntPtr pBuffer, ref uint nBufferSize); [StructLayout(LayoutKind.Sequential)] public struct WNF_STATE_NAME { [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public uint[] Data; public WNF_STATE_NAME(uint Data1, uint Data2) : this() { uint[] newData = new uint[2]; newData[0] = Data1; newData[1] = Data2; Data = newData; } } public enum FocusAssistState { NOT_SUPPORTED = -2, FAILED = -1, OFF = 0, PRIORITY_ONLY = 1, ALARMS_ONLY = 2 }; public static FocusAssistState GetFocusAssistState() { IntPtr pStateName = IntPtr.Zero; IntPtr pBuffer = IntPtr.Zero; try { WNF_STATE_NAME WNF_SHEL_QUIETHOURS_ACTIVE_PROFILE_CHANGED = new WNF_STATE_NAME(0xA3BF1C75, 0xD83063E); uint nBufferSize = (uint)Marshal.SizeOf(typeof(int)); pStateName = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(WNF_STATE_NAME))); Marshal.StructureToPtr(WNF_SHEL_QUIETHOURS_ACTIVE_PROFILE_CHANGED, pStateName, false); uint status = NtQueryWnfStateData(pStateName, IntPtr.Zero, IntPtr.Zero, out uint nChangeStamp, out pBuffer, ref nBufferSize); if (status == 0 && pBuffer != IntPtr.Zero) { int stateValue = Marshal.ReadInt32(pBuffer); return (FocusAssistState)stateValue; } } catch { } finally { if (pStateName != IntPtr.Zero) Marshal.FreeHGlobal(pStateName); if (pBuffer != IntPtr.Zero) Marshal.FreeHGlobal(pBuffer); } return FocusAssistState.FAILED; } "@ } if (-not ("WinAPI.Focus" -as [type])) { Add-Type @Focus } [WinAPI.Focus]::GetFocusAssistState()
关键修改说明
- 添加命名空间引用:在C#代码开头加入
using System;和using System.Runtime.InteropServices;,解决类型识别错误。 - 修复状态值读取逻辑:用
Marshal.ReadInt32(pBuffer)读取指针指向的实际整数状态,再转换为枚举类型,替代原代码直接转换IntPtr的错误逻辑。 - 完善内存管理:添加
finally块确保pStateName和pBuffer的内存被正确释放,避免内存泄漏。 - 调整缓冲区大小:将缓冲区大小改为
Marshal.SizeOf(typeof(int)),匹配WNF返回的状态数据类型(4字节整数)。
内容的提问来源于stack exchange,提问作者Sanctuary
相关产品推荐
相关产品推荐

