PowerShell调用非托管代码:枚举类型处理问题排查
问题描述
我正在使用PowerShell调用userenv.dll中的组策略更新API(RefreshPolicy和RefreshPolicyEx)。以下调用RefreshPolicy的代码可正常运行:
$sig =@' [DllImport("userenv.dll", SetLastError = true, ExactSpelling = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool RefreshPolicy([MarshalAs(UnmanagedType.Bool)] bool bMachine); '@
$mytype = add-type -memberdefinition $sig -Name "Win32RefreshGP" -Namespace Win32Functions -PassThru $mytype::RefreshPolicy($false) # 刷新用户策略
但尝试导入包含枚举的RefreshPolicyEx定义时出现问题:
$sigEx =@' public enum RefreshPolicyOption:uint { RP_FORCE = 1, RP_SYNC = 2 } [DllImport("userenv.dll", SetLastError = true, ExactSpelling = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool RefreshPolicyEx([MarshalAs(UnmanagedType.Bool)] bool bMachine, RefreshPolicyOption dwOptions = 0); '@
$mytypeEx = add-type -memberdefinition $sigEx -Name "Win32RefreshGP" -Namespace Win32Functions -PassThru $mytypeEx::RefreshPolicyEx($false) # 刷新用户策略
调用时抛出错误:
Method invocation failed because [System.Object[]] does not contain a method named 'RefreshPolicyEx'.
At line:1 char:1
- $mytypeEx::RefreshPolicyEx($false) # Refresh the user policy
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException + FullyQualifiedErrorId : MethodNotFound
怀疑是类型定义中使用枚举导致的问题,已尝试切换单/双引号,预期能像C#中正常工作,求解决思路。
解决思路
问题核心是Add-Type的-PassThru参数特性:当你在同一个-MemberDefinition中定义多个类型(此处为枚举RefreshPolicyOption和包含方法的类),-PassThru会返回一个包含所有生成类型的数组,而非单个类型对象。直接用$mytypeEx::RefreshPolicyEx调用时,实际是在数组对象上查找方法,自然会失败。
修复方案1:从返回数组中提取目标类
Add-Type返回的数组中,第一个元素是枚举,第二个是包含RefreshPolicyEx方法的类,通过索引提取即可:
$mytypeEx = Add-Type -MemberDefinition $sigEx -Name "Win32RefreshGP" -Namespace Win32Functions -PassThru $gpClass = $mytypeEx[1] # 提取包含方法的类 $gpClass::RefreshPolicyEx($false)
修复方案2:将枚举和类分开定义
先单独创建枚举类型,再定义包含方法的类,此时-PassThru会返回单个类型对象:
# 先定义枚举 $enumSig = @' public enum RefreshPolicyOption:uint { RP_FORCE = 1, RP_SYNC = 2 } '@ Add-Type -MemberDefinition $enumSig -Name "RefreshPolicyOption" -Namespace Win32Functions # 再定义RefreshPolicyEx方法 $methodSig = @' [DllImport("userenv.dll", SetLastError = true, ExactSpelling = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool RefreshPolicyEx([MarshalAs(UnmanagedType.Bool)] bool bMachine, Win32Functions.RefreshPolicyOption dwOptions = 0); '@ $mytypeEx = Add-Type -MemberDefinition $methodSig -Name "Win32RefreshGP" -Namespace Win32Functions -PassThru $mytypeEx::RefreshPolicyEx($false)
修复方案3:不使用-PassThru,直接通过命名空间调用
如果不需要返回类型对象,可去掉-PassThru,直接用完整命名空间+类名调用方法:
Add-Type -MemberDefinition $sigEx -Name "Win32RefreshGP" -Namespace Win32Functions [Win32Functions.Win32RefreshGP]::RefreshPolicyEx($false) # 也可使用枚举值实现强制刷新: [Win32Functions.Win32RefreshGP]::RefreshPolicyEx($false, [Win32Functions.RefreshPolicyOption]::RP_FORCE)
内容的提问来源于stack exchange,提问作者shocko
相关产品推荐
相关产品推荐

