Доброго времени суток! Собственно интересует сабж. Можно как-то обойтись без этогодурацкого командлета, который к тому же для компиляции кода создаёт временный файл в папке temp? Есть ли более, скажем так, изящные способы вызова WinAPI?
Модуль PsReflec (https://github.com/mattifestation/PSReflect)t - http://www.powershellmagazine.com/2014/09/25/easily-defining-enums-structs-and-win32-functions-in-memory/
greg zakharov
02-09-2016, 09:50
Альтернативных способов более, чем достаточно. Начнем с того, что непосредственно Add-Type можно "перегрузить" с помощью прокси-функции, добавив в него поддержку, скажем, Python, который адепты "синего" не жалуют, а между тем с его помощью вызов апишных функций упрощается в разы. Можно посредством рефлексии задействовать сигнатуры апишных функций, определенных в сборках самого фреймворка.
$ptr = [Runtime.InteropServices.Marshal]::AllocHGlobal(48)
if ([Regex].Assembly.GetType(
'Microsoft.Win32.NativeMethods'
).GetMethod(
'NtQuerySystemInformation'
).Invoke($null, @(3, $ptr, 48, 0)) -eq 0) {
[TimeSpan]::FromMilliseconds(
[Runtime.InteropServices.Marshal]::ReadInt64($ptr, 8) -
[Runtime.InteropServices.Marshal]::ReadInt64($ptr)
)
}
[Runtime.InteropServices.Marshal]::FreeHGlobal($ptr)
Пример выше вычисляет uptime системы.
Шагаем дальше.
Рефлексия в купе с обобщенными делегатами так же позволяет вызывать апишные функции.
$max, $min, $cur = [Byte[]]@(0, 0, 0, 0), [Byte[]]@(0, 0, 0, 0), [Byte[]]@(0, 0, 0, 0)
if ((New-PSDllObject).def(
'ntdll', 'NtQueryTimerResolution',
'[Func[[Byte[]], [Byte[]], [Byte[]], Int32]]'
).Invoke($max, $min, $cur) -eq 0) {
$max, $min, $cur | ForEach-Object { [BitConverter]::ToInt32($_, 0) / 10000 }
}
New-PSDllObject - это набросок модуля $psdll (https://github.com/gregzakh/psdll), совмещающий в себе несколько техник вызова winapi. Что же непосредственно кода выше. Следует иметь в виду, что обобщенные делегаты Action и Func не поддерживают параметры с модификаторами ref/out, но это ограничение в некоторых случаях обходится в виде передачи в качестве параметра вызываемой функции массива байт.
В том же $psdll определен метод pin - эквивалент DllImport в C#.
$psdll = New-PSDllObject
$e = $psdll.enum('NT_PRODUCT_TYPE', [UInt32], @{
NtProductWinNt = 1
NtProductLanManNt = 2
NtProductServer = 3
})
[UInt32]$product = 0
$p = $psdll.pin('ntdll', 'RtlGetProductType', [Boolean], @([UInt32].MakeByRefType()))
if ($p::RtlGetProductType([ref]$product)) {
$product -as $e
}
Следует иметь в виду, что $psdll не тестировался всесторонне, хотя и является реинкарнацией другого мого черновика.
Есть и другоие варианты, но перечислять их здесь все слишком утомительно.
Модуль PsReflec (https://github.com/mattifestation/PSReflect)t - http://www.powershellmagazine.com/2014/09/25/easily-defining-enums-structs-and-win32-functions-in-memory/
Отличительная черта всех MVP'шников давать ссылку на собрата, причём благо ссылка была стоящая, а то так, барахло плодящее в домене приложений кучу сборок. Не айс.
Альтернативных способов более, чем достаточно...Весьма познавательно, спасибо. $psdll при беглом осмотре оказался неплохой штуковиной, правда несколько надуманно в ней создание перечислений. На счёт структур совсем непонятно, может исправите или объясните более подробно?
greg zakharov
04-09-2016, 13:33
Объясняю. Все это писалось для себя, так как подавляющее большинство использует Add-Type, поэтому вряд ли здесь последует детальное описание. Ко всему прочему вопрос был о WinAPI, а не о сторонних расширениях ;)
vBulletin v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.