在 PowerShell 脚本中使用 Win32 GetStringTypeW()
Using Win32 GetStringTypeW() in a PowerShell script
我想在 PowerShell 脚本中使用 Win32 GetStringTypeW() 方法。
我在 C# 中找到了正确的签名,下面的代码在那里工作得很好:
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
private static extern uint GetStringTypeW(uint dwInfoType, string lpSrcStr, int cchSrc, out ushort lpCharType);
private const uint CT_CTYPE1 = 0x0001;
public void MyMethod(string strIn) {
ushort[] lpCharType = new ushort[strIn.Length];
GetStringTypeW(CT_CTYPE1, strIn, strIn.Length, out lpCharType[0]);
// Do stuff with lpCharType
}
lpCharType
数组填充了 16 位无符号整数;一个用于传入的字符串的每个字符。可以通过按位比较来检查整数,以找出字符串中存在哪些 types 个字符。
我在 PowerShell 中将该 C# 代码翻译成以下内容:
$MethodDefinition = @'
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
public static extern uint GetStringTypeW(uint dwInfoType, string lpSrcStr, int cchSrc, out ushort lpCharType);
'@
$Kernel32 = Add-Type -MemberDefinition $MethodDefinition -Name 'Kernel32' -Namespace 'Win32' -PassThru
[System.UInt32] $CT_CTYPE1 = 0x0001
[System.UInt16[]] $lpCharType = [System.UInt16[]]::new($strIn.Length)
$Kernel32::GetStringTypeW($CT_CTYPE1, $strIn, $strIn.Length, [ref] $lpCharType[0])
# Do stuff with $lpCharType
这不会用任何东西填充 $lpCharType
,并且根据我使用该代码的方式,我还可以使用 System.AccessViolationException: Attempted to read or write protected memory.
完全杀死 PowerShell
似乎内存中发生了一些我不完全理解的奇怪事情,所以有人对如何让它工作有什么建议吗?
注意:有趣的是,如果我尝试传入单个 UInt16
参数而不是它们的数组,它会填充一个适当的整数值,因此代码可以正常工作,但当然,它不能保存多个值,这并不能解决访问冲突问题。
如果必须,我可以向 $MethodDefinition
添加中间 C# 方法以接受来自 PowerShell 的字符串,调用 GetStringTypeW(),然后 return 输出,但我希望尽可能避免用 C# 代码填充我的 PowerShell 脚本。
如zett42 points out, in PowerShell you cannot obtain a reference to an individual element of a value-type array, as discussed in .
但是,您可以在 P/Invoke 声明中简单地使用 array 参数,并从 PowerShell 中将数组作为一个整体传递:
$MethodDefinition = @'
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
public static extern uint GetStringTypeW(uint dwInfoType,
string lpSrcStr,
int cchSrc,
ushort[] lpCharType); // Declared as array, w/o `out`
'@
$Kernel32 = Add-Type -MemberDefinition $MethodDefinition -Name 'Kernel32' -Namespace 'Win32' -PassThru
[System.UInt32] $CT_CTYPE1 = 0x0001
$strIn = 'A!'
[uint16[]] $lpCharType = [uint16[]]::new($strIn.Length)
$ok = $Kernel32::GetStringTypeW($CT_CTYPE1, $strIn, -1, $lpCharType)
$lpCharType # -> 897, 528
我想在 PowerShell 脚本中使用 Win32 GetStringTypeW() 方法。
我在 C# 中找到了正确的签名,下面的代码在那里工作得很好:
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
private static extern uint GetStringTypeW(uint dwInfoType, string lpSrcStr, int cchSrc, out ushort lpCharType);
private const uint CT_CTYPE1 = 0x0001;
public void MyMethod(string strIn) {
ushort[] lpCharType = new ushort[strIn.Length];
GetStringTypeW(CT_CTYPE1, strIn, strIn.Length, out lpCharType[0]);
// Do stuff with lpCharType
}
lpCharType
数组填充了 16 位无符号整数;一个用于传入的字符串的每个字符。可以通过按位比较来检查整数,以找出字符串中存在哪些 types 个字符。
我在 PowerShell 中将该 C# 代码翻译成以下内容:
$MethodDefinition = @'
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
public static extern uint GetStringTypeW(uint dwInfoType, string lpSrcStr, int cchSrc, out ushort lpCharType);
'@
$Kernel32 = Add-Type -MemberDefinition $MethodDefinition -Name 'Kernel32' -Namespace 'Win32' -PassThru
[System.UInt32] $CT_CTYPE1 = 0x0001
[System.UInt16[]] $lpCharType = [System.UInt16[]]::new($strIn.Length)
$Kernel32::GetStringTypeW($CT_CTYPE1, $strIn, $strIn.Length, [ref] $lpCharType[0])
# Do stuff with $lpCharType
这不会用任何东西填充 $lpCharType
,并且根据我使用该代码的方式,我还可以使用 System.AccessViolationException: Attempted to read or write protected memory.
似乎内存中发生了一些我不完全理解的奇怪事情,所以有人对如何让它工作有什么建议吗?
注意:有趣的是,如果我尝试传入单个 UInt16
参数而不是它们的数组,它会填充一个适当的整数值,因此代码可以正常工作,但当然,它不能保存多个值,这并不能解决访问冲突问题。
如果必须,我可以向 $MethodDefinition
添加中间 C# 方法以接受来自 PowerShell 的字符串,调用 GetStringTypeW(),然后 return 输出,但我希望尽可能避免用 C# 代码填充我的 PowerShell 脚本。
如zett42 points out, in PowerShell you cannot obtain a reference to an individual element of a value-type array, as discussed in
但是,您可以在 P/Invoke 声明中简单地使用 array 参数,并从 PowerShell 中将数组作为一个整体传递:
$MethodDefinition = @'
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
public static extern uint GetStringTypeW(uint dwInfoType,
string lpSrcStr,
int cchSrc,
ushort[] lpCharType); // Declared as array, w/o `out`
'@
$Kernel32 = Add-Type -MemberDefinition $MethodDefinition -Name 'Kernel32' -Namespace 'Win32' -PassThru
[System.UInt32] $CT_CTYPE1 = 0x0001
$strIn = 'A!'
[uint16[]] $lpCharType = [uint16[]]::new($strIn.Length)
$ok = $Kernel32::GetStringTypeW($CT_CTYPE1, $strIn, -1, $lpCharType)
$lpCharType # -> 897, 528