.NET обертка для IShellLink

Наконец-то дописал .NET обертку для IShellLink (см. серию постов начиная с Shortcuts, shell and COM apartments.). Теперь можно создавать и редактировать ярлыки прямо из PowerShell. :-)

Вот ссылка на исходный код проекта. Немного позже, если дойдут руки, выложу ссылку на готовую инсталляцию.

Вся полезная функциональность реализуется одним классом – ShellLink, который объединяет в себе три интерфейса: IShellLink, IShellLinkDataList и IPersistFile. Большая часть методов этих интерфейсов была переделана в .NET свойства для удобства использования.

PowerShell и CLSID_ShellLink используют разные модели COM apartments: PowerShell использует MTA, а CLSID_ShellLink, как и большинство объектов Shell, - STA. В результате, не получается вызывать методы интерфейса IShellLinkDataList, который не поддерживает маршалинг через границу apartments. Для решения этой проблемы используется ShellPS.dll, которая представляет собой не что иное, как proxy/stub DLL для интерфейса IShellLinkDataList (см. COM marshalling: создание proxy/stub на коленке.).

В собранном виде весь проект состоит из двух библиотек: ShellLib.dll, которая содержит реализацию класса ShellLink и всех вспомогательных классов, и ShellPS.dll. Обе библиотеки собираются с помощью WDK, причём для сборки ShellLib.dll требуется .NET библиотеки из поставки Visual Studio .NET 2005. Эта комбинация потребовала использования нетривиальных возможностей SOURCES в виде директивы LINKER_OPTIDATA.

Перед использованием, скомпилированные DLL нужно зарегистрировать:

regsvr32 ShellPS.dll
gacutil /i ShellLib.dll

После чего можно запустить PowerShell и исследовать новые возможности.

# Загружаем ShellLib.dll
[System.Reflection.Assembly]::Load(
    "shelllib, Version=1.0.1.1, Culture=neutral, 
    PublicKeyToken=e0a879bef00d4c8e, 
    processorArchitecture=x86")
| out-null

# Открываем ярлык "Command Prompt.lnk"
$filename = $env:USERPROFILE + 
    "\\Start Menu\\Programs\\Accessories\\Command Prompt.lnk"

$link = new-object ShellLib.ShellLink
$link.Load(
    $filename, 
    [ShellLib.EPersistFileModeFlags]::STGM_READWRITE)

$link

Последняя команда выведет текущие значения основных свойств ярлыка:

Покажем список всех доступных методов и свойств:

$link | get-member

Свойство ConsoleProps соответствует вкладкам “Options”, “Font”, “Layout” и “Colors” в стандартном окне свойств ярлыка. В данный момент свойство ConsoleProps не задано, что соответствует всем значениям по умолчанию:

Попробуем задать свой размер окна и шрифт:

$props = new-object ShellLib.NtConsoleProps
$props.wFillAttribute = 7
$props.wPopupFillAttribute = 245
$props.dwScreenBufferSize = new-object System.Drawing.Point(180, 3000)
$props.dwWindowSize = new-object System.Drawing.Point(180, 79)
$props.dwFontSize = new-object System.Drawing.Point(7, 12)
$props.uFontFamily = 54
$props.uFontWeight = 400
$props.FaceName = “Lucida Console”
$props.uCursorSize = 15
$props.bQuickEdit = 1
$props.bInsertMode = 1
$props.uHistoryBufferSize = 50
$props.uNumberOfHistoryBuffers = 4
$link.ConsoleProps = $props

Может показаться, что параметров слишком много, но на самом деле все значения можно просто скопировать из свойств созданного стандартными средствами ярлыка.

Теперь можно сохранить полученные изменения.

$link.Save($filename, 1)

В результате всех этих действий вот такой результат:

Осталось только оформить это всё в один скрипт и готово! :-)

comments powered by Disqus