[英]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 位无符号整数填充; 一个用于传入的字符串的每个字符。可以通过按位比较来检查整数,以找出字符串中存在哪些类型的字符。
我在 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.
似乎 memory 中发生了一些我不完全理解的奇怪事情,那么有人对如何使其工作有任何建议吗?
注意:有趣的是,如果我尝试传入单个UInt16
参数而不是它们的数组,它会填充一个正确的 integer 值,因此代码可以正常工作,但当然,它不能容纳多个值,这并不能解决访问冲突。
如果必须的话,我可以向$MethodDefinition
添加中间方法 C# 以接受来自 PowerShell 的字符串,调用 GetStringTypeW(),并返回 output,但我希望尽可能避免使用 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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.