在PowerShell脚本中使用Win32 GetStringTypeW()



我想在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位无符号整数填充;传入的字符串的每个字符对应一个。可以使用按位比较检查整数,以找出字符串中存在哪些类型的字符。

我将c#代码翻译成PowerShell中的如下代码:

$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与任何东西,这取决于我如何使用该代码,我也可以杀死PowerShell完全与System.AccessViolationException: Attempted to read or write protected memory.

似乎有一些奇怪的事情发生在内存中,我不完全理解,所以有没有人有任何建议如何使它工作?

注意:有趣的是,如果我尝试传递单个UInt16参数而不是它们的数组,它会被一个适当的整数值填充,因此代码类型有效,但当然,它不能容纳多个值,这并不能解决访问冲突。

如果我必须,我可以在$MethodDefinition中添加一个c#方法来接受来自PowerShell的字符串,调用GetStringTypeW(),并返回输出,但我希望避免用c#代码填充PowerShell脚本。

正如zett42指出的那样,在PowerShell中,您无法获得对值类型数组中单个元素的引用,如本回答所述。

然而,你可以简单地在p/Invoke声明中使用数组参数,并从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

最新更新