» Создание своего инсталлятора на NSIS. Ассоциации файлов. Макросы

K.A.V.
www.oszone.net
22.02.2010
Автор: hb860
Последнее обновление: 22.02.2010


Продолжая серию публикаций о скриптовом языке NSIS, рассмотрим, как средствами NSIS зарегистрировать типы файлов за устанавливаемым приложением.
Для начала немного теории. Все ассоциации типов файлов с программами в операционных системах Microsoft Windows представлены в реестре, в кусте HKEY_CLASSES_ROOT. Этот куст является представлением, полученным в результате слияния узлов HKEY_CURRENT_USER\Software\Classes и HKEY_LOCAL_MACHINE\Software\Classes. Общими словами, HKEY_CLASSES_ROOT предназначен для чтения, а не для чтения, но не для записи и служит также для обеспечения обратной совместимости со старыми приложениями. Но не будем углубляться в иторию развития системного реестра, а рассмотрим, в каком виде ассоциации файлов хранятся.
В общем случае, тип файла является зарегистрированным за приложением, если в системном реестре ему соответствует следующая структура разделов и ключей:

HKEY_CLASSES_ROOT
     .ext
          (Default) = ApplicationVendor.MyProgram
     ApplicationVendor.MyProgram
          (Default) = MyProgram Application


В данном примере ".ext" - это расширение файла. Значение по умолчанию ApplicationVendor.MyProgram является именем подраздела в HKEY_CLASSES_ROOT, где описано, с помощью какого приложения открыть это расширение. В текущем примере это "MyProgram Application". Подобный подход позволяет устанавливать одно и тоже приложение сразу для нескольких расширений файлов. Подробней об это можно почитать в MSDN.
Исходя из информации MSDN, можно сделать вывод, что целесообразно создавать структуру ассоциаций файлов либо в ветке реестра HKEY_LOCAL_MACHINE\Software\Classes, либо в HKEY_CURRENT_USER\Software\Classes, причем последняя имеет приоритет, и при построении представления HKEY_CLASSES_ROOT будет иметь приоритет над HKEY_LOCAL_MACHINE. Эту особенность необходимо учитывать при реализации регистрации типов файлов за устанавливаемым приложением.

В данной статье я буду использовать ветку HKEY_LOCAL_MACHINE\Software\Classes.

В качестве варианта реализации предлагается создать макрос, который будет вызываться для регистрации конкретного типа файлов. Для этого воспользуемся командой скриптового языка !macro. Синтаксис использования:
!macro macro_name [parameter][...]

Команда !macro, как нетрудно догадаться, создает макрос с именем macro_name. Макросом считаются все строчки кода между ключевыми словами !macro и the !macroend. Чтобы вызывать макрос из тела скрипта, необходимо использовать хорошо знакомую по предыдущим публикациям команду !insertmacro. При определении макроса можно указать, что он может принимать один или несколько параметров. Выглядит это примерно так:
!macro macro_name parameter1 parameter2

Внутри макроса обращение к параметрам производится примерно также, как к константам, например:
DetailPrint " ${parameter1}"
DetailPrint "${parameter2}"


Чтобы конкретизировать задачу, разберем регистрацию типов файлов на примере популярного медиа-проигрывателя Winamp. Макрос, ассоциирующий за ним конкретный тип файлов, будет выглядеть следующим образом:
!macro RegisterExtension extenstion 
WriteRegStr HKLM "Software\Classes\.${extenstion}" "" "Winamp.File"

WriteRegStr HKLM "Software\Classes\Winamp.File" "" "Winamp Media File"
WriteRegStr HKLM "Software\Classes\Winamp.File\DefaultIcon" "" "$INSTDIR\winamp.exe,1"
WriteRegStr HKLM "Software\Classes\Winamp.File\shell" "" "Play"
WriteRegStr HKLM "Software\Classes\Winamp.File\shell\Play" "" "&Play in Winamp"
WriteRegStr HKLM "Software\Classes\Winamp.File\shell\Play\command" "" "$\"$INSTDIR\winamp.exe$\" $\"%1$\""
WriteRegStr HKLM "Software\Classes\Winamp.File\shell\open\command" "" "$\"$INSTDIR\winamp.exe$\" $\"%1$\""
WriteRegStr HKLM "Software\Classes\Winamp.File\shell\ListBookmark" "" "Add to Winamp's &Bookmark list"
WriteRegStr HKLM "Software\Classes\Winamp.File\shell\ListBookmark\command" "" "$\"$INSTDIR\winamp.exe$\"/BOOKMARK $\"%1$\""
WriteRegStr HKLM "Software\Classes\Winamp.File\shell\Enqueue" "" "&Enqueue in Winamp"
WriteRegStr HKLM "Software\Classes\Winamp.File\shell\Enqueue\command" "" "$\"$INSTDIR\winamp.exe$\"/ADD $\"%1$\""
!macroend


Данный код создает примерно вот такую структуру разделов и ключей в системном реестре:

HKEY_LOCAL_MACHINE
    Software
        Classes
            .mp3
                (default)=Winamp.File
            Winamp.File
                (default)=Winamp Media File
                DefaultIcon
                    (default)=c:\program files\winamp\winamp.exe,1
                    shell
                        Play=&Play in Winamp
                            command
                                (default)="c:\program files\winamp\winamp.exe" "%1$"
                        Open
                            command     
                                (default)="c:\program files\winamp\winamp.exe" "%1$"
                        ListBookmark
                            (default)=Add to Winamp's &Bookmark list
                            command
                                (default)="c:\program files\winamp\winamp.exe"/BOOKMARK "%1$"
                        Enqueue
                            (default)=&Enqueue in Winamp
                            command
                                (default)="c:\program files\winamp\winamp.exe$"/ADD "%1$"

Этот достаточно простой пример иллюстрирует общий подход к регистрации типов файлов за устанавливаемым приложением. Созданный макрос принимает только один параметр - расширение файла без точки, его тело линейное и состоит исключительно из вызова функции WriteRegStr.

С выходом операционной системы Windows Vista в системе ассоциаций произошли некоторые изменения. Системы линейки NT6.x имеют такую функциональность, как "Программы по умолчанию", выполненную в виде апплета панели управления. Этот апплет позволяет переключать программу-обработчик типов "на лету". Если необходимо, чтобы помимо регистрации типа файла, устанавливаемое приложение стало ещё и обработчиком по умолчанию, следует несколько доработать макрос.
Необходимо добавить следующие строчки:
!macro RegisterExtension extenstion 
WriteRegStr HKLM "Software\Classes\.${extenstion}" "" "Winamp.File"

WriteRegStr HKLM "Software\Classes\Winamp.File" "" "Winamp Media File"
WriteRegStr HKLM "Software\Classes\Winamp.File\DefaultIcon" "" "$INSTDIR\winamp.exe,1"
WriteRegStr HKLM "Software\Classes\Winamp.File\shell" "" "Play"
WriteRegStr HKLM "Software\Classes\Winamp.File\shell\Play" "" "&Play in Winamp"
WriteRegStr HKLM "Software\Classes\Winamp.File\shell\Play\command" "" "$\"$INSTDIR\winamp.exe$\" $\"%1$\""
WriteRegStr HKLM "Software\Classes\Winamp.File\shell\open\command" "" "$\"$INSTDIR\winamp.exe$\" $\"%1$\""
WriteRegStr HKLM "Software\Classes\Winamp.File\shell\ListBookmark" "" "Add to Winamp's &Bookmark list"
WriteRegStr HKLM "Software\Classes\Winamp.File\shell\ListBookmark\command" "" "$\"$INSTDIR\winamp.exe$\"/BOOKMARK $\"%1$\""
WriteRegStr HKLM "Software\Classes\Winamp.File\shell\Enqueue" "" "&Enqueue in Winamp"
WriteRegStr HKLM "Software\Classes\Winamp.File\shell\Enqueue\command" "" "$\"$INSTDIR\winamp.exe$\"/ADD $\"%1$\""
; ставим приложением по умолчанию для текущего пользователя
DeleteRegKey HKCU "Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.${extenstion}\UserChoice"
WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.${extenstion}\UserChoice" "Progid" "Winamp.File"
!macroend


Добавленный код удаляет из ветки реестра, в которой хранятся предпочтения текущего пользователя о программах по умолчанию, сведения о расширении .extenstion, и прописывает туда идентификатор Winamp. Возникает вопрос, зачем удалять старое значение, а не просто его перезаписать? Дело в том, что на ряд разделов в ветке HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts по умолчанию отсутствуют права на запись пользователем, однако, на удаление они имеются.

Вызов макроса регистрации типов файлов
Вызов макроса, как было указано выше, производится командной !insertmacro. Одним из возможных вариантов реализации является создание группы секций "Ассоциации файлов", в которой каждое расширение будет представлено отдельной секцией, таким образом, конечный пользователь сможет решить для себя, какие ассоциации ему закреплять за устанавливаемым приложением, а какие - нет. Пример кода:
SectionGroup "Ассоциации файлов"
        Section "MP3"
            !insertmacro RegisterExtension "mp3"
        SectionEnd    
        Section "wav"
            !insertmacro RegisterExtension "wav"
        SectionEnd    
        ....
    SectionGroupEnd 

Удаление ассоциаций файлов при деинсталляции приложения
Согласно MSDN, операционная система Windows перестает считать тип файла ассоциированным, если в реестре отсутствует описание приложения-обработчика. Таким образом, применительно к вышеуказанному примеру, достаточно удалить раздел HKLM\Software\Classes\Winamp.File для снятия всех ассоциация при удалении Winamp. Можно эту операцию оформить вызовом команды DeleteRegKey в секции деисталлятора:
Section Uninstall
    ...
    DeleteRegKey HKLM "Software\Classes\Winamp.File"
    ...
    SectionEnd


Однако, правилом хорошего тона считается резервирование значения предыдущего обработчика и его восстановление при деинсталляции вашего приложения. Где его хранить и в каком виде - дело вкуса.

Вместо резюме
В данной статье был рассмотрен общий поход регистрации типов файлов за устанавливаемым приложением, а также их удаление при помощи скрипта исталлятора NSIS. Следует отметить, что приложение Winamp было рассмотрено исключительно для примера, так как его родной инсталлятор предлагает схожую функциональность, и более того, само приложение поддерживает ключи командной строки, устанавливающие ассоциации файлов, но это уже выходит за рамки настоящей публикации.