Создание Windows-приложений на основе Visual C#

Создание пакетов установки

Разбить на страницы
Показывать лекцию целиком
Для работы с данной лекцией используйте примеры.

Для установки на компьютер большинства программ достаточно просто вставить компакт диск с программой в дисковод и, следуя несложным инструкциям, скопировать ее на жесткий диск. В результате мы получаем возможность запускать программу одним из нескольких способов — щелкая на ярлыке на Рабочем столе, выбирая ее группу в меню Пуск или просто дважды щелкая на файле, расширение которого связано с этой программой. Мы не задумываемся, из каких частей состоит программа, как они взаимодействуют, а некоторые пользователи даже не представляют, где эти части находятся. В этой лекции мы научимся создавать дистрибутивы, или пакеты установки, предоставляющие возможность распространять программы с минимумом усилий со стороны конечного пользователя.

Сборки. Утилита ildasm.exe

Приложение всегда состоит из одной или более сборок. Сборка — это функциональная единица, имеющая версию и описание, которую можно использовать в других приложениях. Для каждой сборки можно прописывать отдельные разрешения (подробнее о разрешениях см. лекцию 10).

В самом простом случае, сборка — это приложение, которое состоит из одного функционального модуля — класса. В большинстве случаев в приложении может быть несколько сборок, и каждая может иметь свои вспомогательные файлы. При выполнении все сборки приложения должны существовать и к ним должен быть открыт доступ. Каждая сборка должна быть независимой. У любой сборки есть метаданные, которые описывают сборку и содержат версию.

Содержимое сборки можно просмотреть, запустив дизассемблер "Microsoft Intermediate Language Disassembler" (ildasm.exe). Рассмотрим следующий пример — создадим простое консольное приложение, которое выводит на экран строку Hello World:

using System;

namespace SimpleApp
{
    class Class1
    {
      [STAThread]
      static void Main(string[] args)
      {
        Console.WriteLine("Hello World");
      }
    }
}

Утилиту ildasm.exe можно запустить двумя способами — перейти по адресу C:\Program Files\Microsoft Visual Studio .NET 2003\SDK\v1.1\Bin и запустить непосредственно файл ildasm.exe или перейти в Пуск\Все программы\ Microsoft Visual Studio .NET 2003 \ Visual Studio .NET Tools \ Visual Studio .NET 2003 Command Prompt и в появившейся командной строке ввести

ildasm.exe

После того как приложение запустится, откроем только что созданную сборку (файл SimpleApp.exe из папки bin/Debug), (рис. 9.1).

(рис 9.1) Сборка SimpleApp, открытая с помощью утилиты ildasm.exe

Как мы знаем, у класса всегда есть конструктор. Если он не был создан вручную, компилятор создаст конструктор по умолчанию. В утилите он называется .ctor. Также в созданной нами программе есть метод Main, который принимает строковый массив и не возвращает значений. Щелкаем на методе Main два раза. Открывается окно с MSIL (Microsoft Intermediate Language) кодом этого метода. Здесь видим строковую переменную ldstr со значением "Hello World" и запуск статического метода WriteLine класса Console (рис. 9.2).

(рис 9.2) MSIL-код метода Main

На рис. 9.2 я снова привел окно утилиты ildasm.exe: щелкнув на кнопку прокрутки, замечаем номер версии сборки — 1.0.2300.26912.

Частные сборки

Программы, которые написаны на языках, поддерживаемых библиотекой .NET Framework, и на C# в частности, компилируются в код MSIL, которые затем среда CLR (Common Language Runtime) преобразует в машинный код.

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

Частные сборки отвечают тем же требованиям, что и обычные, но предназначены они для использования только в одном приложении и, как правило, лежат в той же папке, что и использующее их приложение. Частная сборка может находиться не только в корневой папке, но и во вложенных папках корневого каталога. Приложение ссылается на частную сборку по ее частному имени, которое содержится в метаданных. Когда среда CLR ищет частную сборку для применения, она использует частное имя сборки для поиска, причем поиск осуществляется в корневом каталоге и дочерних подкаталогах. Среда не будет искать сборку в родительской папке каталога.

Если мы хотим использовать любой путь для размещения сборки, то следует воспользоваться методом LoadFrom класса Assembly и указать ему адрес нахождения файла со сборкой. Класс Assembly находится в пространстве имен System.Reflection. Создайте новое консольное приложение и назовите его SimpleAssembly. Удалите все фрагменты кода, оставив только следующий участок:

using System;

namespace SimpleAssembly
{  
    public class Class
    {
      public static string HelloWorld()
      {
        return "hello world";
      }
    }
}

Скомпилировав приложение (Ctrl+Shift+B), мы получим сборку SimpleAssembly.dll. Теперь создадим еще одно консольное приложение — UsingLoadFrom, в папку bin/Debug которого помещаем файл SimpleAssembly.dll. В методе LoadFrom считываем содержимое сборки SimpleAssembly.dll:

using System;
using System.Reflection;

namespace UsingLoadFrom
{
  class Class1
  {
    [STAThread]
    static void Main(string[] args)
    {
      Assembly privateAss = 
Assembly.LoadFrom("SimpleAssembly.dll");
      MethodInfo info = 
     privateAss.GetTypes()[0].GetMethod("HelloWorld");
      Object obj = info.Invoke(null, null);
      Console.WriteLine("Результат выполнения метода: {0}", 
obj);
    }
  }
}

Результатом запуска этого приложения будет вывод на экран строки Hellow World — результата метода HelloWorld сборки SimpleAssembly.dll.

Рассматриваемые листинги предельно просты. Тем не менее на диске, прилагаемом к книге, вы найдете приложения SimpleAssembly и UsingLoadFrom (Code\Glava9\ SimpleAssembly и UsingLoadFrom).

Сборки со строгим именем

Обычные сборки могут быть без труда декомпилированы, и код в них может быть повторно использован. Для коммерческих приложений это недопустимо. Сборки, подписанные строгим именем, позволяют обеспечить безопасность, защиту кода, облегчить применение их в несколько приложениях, а также управлять версионностью сборок. Строгое имя является уникальным обозначением сборки. Оно гарантирует невозможность замены вашей сборки другой.

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

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

Строгое имя сборки гарантирует ее уникальность и защиту от декомпиляции.

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

Сборка со строгим именем может располагаться в любых местах — корневой папке приложения, произвольной папке локального или удаленного компьютеров, в Интернете.

Одни и те же сборки могут быть использованы в нескольких приложениях. Можно не дублировать эти сборки, а разместить их в так называемом глобальном КЭШе сборок (Global Assembly Cache) — централизованном хранилище сборок. В результате получается значительный выигрыш в размере приложения. В GAC может храниться несколько версий одной сборки, и он может управлять ими. Если сборку разместили в GAC, то она автоматически становится публичной — доступной другим приложениям. Если, напротив, использование подписанной сборки другими приложениями не требуется — достаточно поместить ее в корневую папку приложения.

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

Создание сборки со строгим именем

В комплект поставки Microsoft Visual Studio .NET входят утилиты Microsoft .NET Framework Tools, применяемые для дополнительной работы с приложениями и компонентами. Файлы большинства утилит располагаются в каталоге С\Program Files\Microsoft Visual Studio .NET 2003\SDK\v1.1\Bin. Описание со ссылками на дополнительные справочные ресурсы находится в в папке Bin в документе StartTools.htm. В этой и следующей лекциях мы рассмотрим работу с несколькими утилитами.

Создание сборки со строгим именем сводится к созданию закрытого ключа для шифрования хэш-кода сборки. Для этого используется утилита sn.exe. Непосредственный запуск из папки Bin не позволит приступить к работе — подобно прочим утилитам, ее функции доступны из командной строки. Для запуска sn.exe из командной строки WindowsДля запуска командной строки Windows выбираем "Пуск\Выполнить" и вводим cmd. Сочетание клавиш Windows+R также запускает строку "Выполнить". указываем путь к каталогу и название (рис. 9.3).

(рис 9.3) Запуск sn.exe из командной строки Windows

Более удобный способ работы с утилитами — использование командной строки Visual Studio .NET. Для ее запуска выбираем Пуск\Все программы\ Microsoft Visual Studio .NET 2003 \ Visual Studio .NET Tools \ Visual Studio .NET 2003 Command Prompt и просто вводим название утилиты (рис. 9.4):

sn.exe
(рис 9.4) Запуск sn.exe из командной строки Visual Studio.NET

Далее мы будем использовать командную строку Visual Studio .NET. В любом случае появляется справка утилиты, которую затем снова можно вывести, набрав одну из команд:

sn.exe - ?
sn.exe –h

Для создания закрытого ключа вводим команду (рис. 9.5):

sn.exe – k "Путь к папке для сохранения ключа\Название ключа.Расширение"
(рис 9.5) Ключ StrongKey.snk был записан в указанную директорию

Вместо расширения key можно поставить любое другое. Расширением по умолчанию является .snk. После того как закрытый ключ создан, необходимо прикрепить его к приложению. В окне Solution Explorer проекта дважды щелкаем на файле AssemblyInfo.cs. Если Атрибут [assembly: AssemblyKeyFile("")] содержит путь к закрытому ключу, компилятор использует его для шифрования данных (рис. 9.6).

(рис 9.6) Использование атрибута [assembly: AssemblyKeyFile("")] для прикрепления ключа к приложению

Также с помощью атрибута [assembly] можно указать версию сборки, настройки культуры и другие параметры (рис. 9.7).

(рис 9.7) Информация о сборке в атрибутах [assembly]

Сборки, подписанные строгим именем, добавляются в проект так же, как и обычные сборки. Для этого в окне Solution Explorer щелкаем правой кнопкой мыши на папке References и в появившемся контекстном меню выбираем пункт Add Reference… . По умолчанию окно Add Reference открывается на вкладке .NET, в которой нажимаем на кнопку Browse и выбираем сборку. В листинг текущего приложения добавляем пространство имен, применяемое в сборке, используя ключевое слово using. После компиляции сборка будет добавлена в проект.

Защита сборок. Утилита ilasm.exe

Главное преимущество использования сборок, подписанных строгим именем, — защита их от декомпиляции. Запустим снова утилиту ildasm.exe и откроем приложение, выводящее на экран строку Hello World — SimpleApp. В меню "Файл" выбираем пункт Dump (или просто нажимаем Ctrl+D). В появившемся окне Dump options оставляем значения без изменений и нажимаем OK. Называем новый файл SimpleAppCrack.il и сохраняем его При этом мы сохранили содержимое нашего приложения в виде кода MSIL. Закрываем утилиту ildasm.exe.

Открываем файл SimpleAppCrack.il с помощью блокнота и изменяем строку Hello World на Hello World Cracked (рис. 9.8).

(рис 9.8) Изменение MSIL-кода

Сохраняем файл и закрываем его. Теперь нам нужно преобразовать MSIL код в исполняемый exe-файл. Для этого воспользуемся еще одной утилитой — ilasm.exe. В командной строке Visual Studio .NET набираем название утилиты и путь к файлу с MSIL-кодом (рис. 9.9):

ilasm.exe Путь к файлу\файл.il
(рис 9.9) Использование утилиты ilasm.exe для преобразования кода MSIL в исполняемый exe-файл

В папке с исходным файлом SimpleAppCrack.il появится файл SimpleAppCrack.EXE. Для просмотра его содержимого в командной строке указываем путь к нему и его название (рис. 9.10).

(рис 9.10) Запуск измененного файла SimpleAppCrack.EXE

Скопируйте всю папку с приложением SimpleApp и назовите его ProtectedSimpleApp. Откроем приложение и подпишем сборку строгим именем StrongKey.snk. Далее проделаем те же самые действия и попытаемся запустить измененный файл — появляется исключение System.IO.FileLoadExeption (рис. 9.11).

(рис 9.11) Ошибка при попытке запустить измененную сборку, подписанную строгим именем

На диске, прилагаемом к книге, вы найдете приложение ProtectedSimpleApp (Code\Glava9\ ProtectedSimpleApp).

Утилита .NET Reflector. Как вскрывать защищенные сборки

При использовании утилиты ildasm.exe бросается в глаза аскетичный дизайн приложения и неудобство работы с ней. Невозможность изменения размеров информационной панели сборки, расположенной внизу программы, открытие блоков кода в отдельных окнах, отображение только MSIL-кода наводит на мысль, что разработчики среды .NET сознательно оставили минимальную функциональность приложения для сведения общения с ним пользователей к минимуму. Программа .NET Reflector (версия 4.1.84.0) — единственный существующий браузер классов .NET-компонент, позволяющий просматривать метаданные, IL-инструкции и XML-документацию сборок, а также декомпилировать их, – гораздо более удобная утилита. Она имеет статус freeware, поэтому вы можете найти ее на диске, прилагаемом к книге, — Code\Glava9\ Reflector.zip, или скачать с сайта разработчика — http://www.aisto.com/roeder/dotnet. Рассмотрим, как просмотреть содержимое сборки, подписанной строгим именем, и использовать код в своих целях. Запустим программу, откроем пункт меню File\Open и выберем файл ProtectedSimpleAppCrack.EXE, который нам не удалось запустить (см. рис. 9.11). Выделив название сборки, на панели Disassembler увидим содержимое значение атрибутов [assembly] (если у вас не открыта панель Disassembler, выберите Tools/Disassembler) (рис. 9.12).

(рис 9.12) Главное окно программы .NET Reflector, на панели Disassembler выведены значения атрибутов [assembly]

Обратите внимание на параметр AssemblyKeyFile панели Disassembler — мы действительно работаем со сборкой, подписанной строгим именем! Каждый объект, отображаемый на панели, является ссылкой, щелкая на которую, мы переходим к соответствующему классу. Открыв окно Options — в пункте меню View\Options, можно выбрать язык отображения объектов, что является своеобразным переводчиком (рис. 9.13)!

(рис 9.13) Выбор языка в окне Options

Выбрав язык C# и перемещаясь по объектам любой сборки, можно копировать и вставлять код прямо в свой листинг (рис. 9.14).

(рис 9.14) Представление кода сборки на языке C#

Утилита не имеет возможности сохранять изменения в сборках (по крайней мере, описываемая версия), но в большинстве случаев вполне достаточно просмотреть и при необходимости скопировать весь код или фрагмент.

Глобальный кэш сборок GAC (Global Assembly Cache). Утилита gacutil.exe

Глобальный кэш сборок (Global Assembly Cashe, GAC) — это хранилище сборок, одновременно используемых несколькими приложениями. Такие сборки называются публичными. GAC может содержать в себе несколько сборок, отличающихся друг от друга только версией. На вашем компьютере GAC находится в каталоге C:\WINDOWS\assembly (рис. 9.15).

(рис 9.15) Глобальный кэш сборок, GAC

Все сборки, находящиеся в GAC, подписаны строгим именем — при установке сборки среда Common Language Runtime проверяет сборку на уникальность и сравнивает ее с другими, уже имеющимися сборками.

Управлять глобальным хранилищем сборок можно несколькими способами. Первый способ — с помощью утилиты gacutil.exe, файл которой располагается в папке C\Program Files\Microsoft Visual Studio .NET 2003\SDK\v1.1\Bin\ gacutil.exe. Для работы с ней, как и большинством других утилит в командной строке Visual Studio.NET, следует ввести

gacutil.exe

При этом появляется описание команд утилиты (рис. 9.16), среди которых нас интересуют всего три:

/i или –i: установка  сборки в GAC;
/l или –l: вывод списка  установленных сборок;
/u или –u: удаление сборки.
(рис 9.16) Запуск утилиты в командной строке Visual Studio .NET

Управление сборками при помощи утилиты gacutil.exe — не самый удобный способ. Более широкие возможности управления сборками предоставляет консоль MMC (Microsoft Management Console), для запуска которой в окне Выполнить (Run) набираем mmc (рис. 9.17).

(рис 9.17) Запуск консоли MMC

В появившемся окне выбираем в меню "Консоль\Добавить или удалить оснастку …" (рис. 9.18).

(рис 9.18) Добавление оснастки

Оснасткой называется основной тип инструментов, которые можно добавить на консоль. В данном случае оснасткой будет глобальный кэш сборок. В окне "Добавить\Удалить оснастку" нажимаем кнопку "Добавить" и в появившемся списке выбираем .NET Framework 1.1 Configuration (рис. 9.19).

(рис 9.19) Добавление оснастки .NET Framework 1.1 Configuration

В открывшемся окне можно управлять сборками — добавлять их или удалять (рис. 9.20).

(рис 9.20) Удаление сборки

Не удаляйте сборки, которые вам неизвестны, — вы можете нарушить работоспособность некоторых программ!

Настройка политики выполнения сборок и контроля версий

Консоль MMC предоставляет возможность настройки политики выполнения сборок и контроля версий. Рассмотрим практическое использование контроля версий сборок. Создайте новое консольное приложение и назовите его AssVersion. Полный листинг этого приложения:

using System;
namespace LibVersion
{
  /// <summary>
  /// Класс для тестирования контроля версий сборок.
  /// </summary>
  public class MyClass
  {
    /// <summary>
    /// Метод, возвращающий текущую версию сборки.
    /// <summary>
    /// <returns></returns>
    public static string GetString()
    {
      return "Version 1";
    }
  }
}

В файле AssemblyInfo.cs изменяем значения атрибутов [assembly:]:

// Жестко прописываем  версию сборки
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyDelaySign(false)]
// Указываем закрытый ключ, созданный утилитой sn.exe
[assembly: AssemblyKeyFile("C:\\StrongKey.snk")] 
[assembly: AssemblyKeyName("")]

При попытке скомпилировать приложение появляется ошибка — наше приложение не содержит точки входа:

Program 'D:\Code\Glava9\AssVersion\obj\Debug\
AssVersion.exe' does not have an entry point defined

Мы удалили метод Main, поэтому возникает это исключение при попытке создания консольного приложения. Нам нужно скомпилировать проект как класс библиотеки, для этого в окне Solution Explorer щелкаем правой кнопкой на названии проекта AssVersion и в появившемся контекстном меню выбираем пункт Properties. Изменяем свойство Output Type на значение Class Library, закрываем окно свойств проекта и снова скомпилируем его.

Добавим теперь созданную сборку в GAC. В консоли MMC щелкаем правой кнопкой мыши на названии Assembly Cache и выбираем пункт Add… (рис. 9.21).

(рис 9.21) Добавление сборки в GAC из консоли MMC

Переходим в папку bin/Debug и выбираем файл AssVersion.dll. В результате в списке сборок появляется добавленная сборка AssVersion.dll (рис. 9.22).

(рис 9.22) Добавленная сборка AssVersion.dll в списке GAC

Создадим теперь новое консольное приложение UsingMyClassFromGAC, которое будет ссылаться на эту сборку и использовать ее метод. В окне Solution Explorer щелкаем правой кнопкой мыши на папке References и в появившемся контекстном меню выбираем пункт Add Reference (рис. 9.23).

(рис 9.23) Добавление ссылки к проекту

В появившемся окне Add Reference нажимаем кнопку Browse и выбираем сборку AssVersion.dll из каталога AssVersion\bin\Debug\ AssVersion.dll. Подключаем пространство имен для использования этой сборки и вызываем ее метод:

using System;
//Подключаем пространство имен:
using AssVersion;

namespace UsingMyClassFromGAC
{
  
  class Class1
  {
    
  
      [STAThread]
    static void Main(string[] args)
    {
      // Получаем строку с помощью метода GetString
      string stringFromMethod = MyClass.GetString();
      // Выводим строку на экран
      Console.WriteLine(stringFromMethod);
    }

  
  }
}

Компилируем приложение и затем запускаем его из командной строкиПри запуске приложения непосредственно из среды Visual Studio .NET происходит прямое обращение по ссылке к сборке, находящейся в своей папке, а при запуске через командную строку CLR проверяет наличие сборки в GAC. Visual Studio .NET (рис. 9.24).

(рис 9.24) Результат запуска приложения UsingMyClassFromGAC из командной строки

Изменим теперь сборку AssVersion — возвращаемое методом значение — на Version 2:

public static string GetString()
  {
    return "Version 2";
}

Изменим файл AssemblyInfo.cs:

// Жестко прописываем  новую версию сборки
[assembly: AssemblyVersion("2.0.0.0")]

Скомпилируем сборку и добавим ее в GAC. В результате в списке сборок появится две версии (рис. 9.25).

(рис 9.25) Список сборок содержит две версии AssVersion — 1.0.0.0 и 2.0.0.0

Снова запустим приложение UsingMyClassFromGAC из командной строки. Результат не изменился, по-прежнему выводится текст Version 1.

Перейдем теперь к настройке управления версиями сборок. В консоли управления .NET Framework 1.1 открываем вкладку Configured Assemblies и выбираем задачу Configure an Assembly (рис. 9.26).

(рис 9.26) Список задач на вкладке Configured Assemblies консоли управления .NET Framework 1.1

В открывшемся окне конфигурирования сборки (рис. 9.27) переключатель стоит по умолчанию на значении Choose an Assembly from the assembly cache, нажимаем кнопку Choose Assembly для перехода к списку сборок.

(рис 9.27) Окно конфигурирования сборок

Далее появляется список сборок GAC. Прокручиваем список до конца, выбираем AssVersion версии 1.0.0.0 и нажимаем кнопку Select (рис. 9.28).

(рис 9.28) Выбор сборки AssVersion версии 1.0.0.0 из списка сборок

Далее нажимаем кнопку "Готово". В появившемся окне свойств сборки переключаемся на вкладку Binding Policy и в поле Requested Version вводим номер первой версии сборки (1.0.0.0), а в поле New Version — номер второй версии сборки (2.0.0.0) (рис. 9.29).

(рис 9.29) Определение версий сборок

Нажимаем кнопку OK, завершая конфигурирование сборки. В результате этих действий мы определили порядок версий сборок AssVersion, и теперь среда CLR при обращении в GAC будет извлекать более новую версию сборки. В командной строке Visual Studio .NET снова запустим приложение UsingMyClassFromGAC.exe, которое будет извлекать версию сборки 2.0.0.0 (рис. 9.30).

(рис 9.30) После завершения конфигурирования сборки приложение UsingMyClassFromGAC.exe использует новую версию AssVersion 2.0.0.0

На диске, прилагаемом к книге, вы найдете приложения AssVersion и UsingMyClassFromGAC (Code\Glava9\ AssVersion и UsingMyClassFromGAC).

Управление политиками сборок

В консоли MMC предусмотрены средства управления политиками версий сборок. В оснастке .NET Configuration 1.1 выбираем вкладку Confugured Assemblies и переходим по ссылке View List of Configured Assemblies. Открывается список сборок, для которых были определены политики. Выбирая нужную сборку и щелкая на ней правой кнопкой мыши, можно изменять свойства политики или удалить ее (рис. 9.31).

(рис 9.31) Изменение свойств политики управления версиями сборки

В этом же окне при щелчке правой кнопкой мыши на свободном поле и выборе пункта Add открывается окно конфигурирования сборки Configure an Assembly (рис. 9.27).

Файлы конфигурации приложения

Файлы конфигурации приложения — это XML-файлы, которые хранят индивидуальные настройки приложения, такие как строки подключения к базам данных Connection String, адреса удаленных компьютеров и т.д. При загрузке приложения CLR проверяет наличие файла конфигурации и в случае его нахождения считывает из него данные.

Файлы конфигурации имеют расширение .config и располагаются в той же самой папке, что и файл приложения. Название файлов конфигурации формируется от имени приложения — файл NameApplication.exe.config принадлежит приложению NameApplication.exe.

Файлы конфигурации, поскольку они являются документами XML, содержат иерархическую структуру. Главным элементом иерархии является элемент <configuration>. Из-за того, что файл конфигурации представляет собой "правильный" XML-файл, все его элементы чувствительны к регистру символов. В таблице 9.1 представлены некоторые элементы и их атрибуты, которые могут находиться в файле конфигурации.

Элементы и атрибуты XML-файлов конфигурации
ЭлементОписание элементаАтрибутОписание атрибутаОбязательно ли наличие атрибута
<configuration> Корневой элемент файла конфигурации. Вся находящаяся в нем информация считывается средой CLR при запуске приложения
<runtime> Вложенный элемент configuration, содержит информацию о подключаемых сборках в процессе выполнения
<assemblyBinding> Вложенный элемент runtime, содержит информацию о версиях подключаемых сборок и их расположении
<dependedAssembly> Вложенный элемент assemblyBinding, содержит информацию о каждой из подключаемых сборок
<assemblyIdentity> Вложенный элемент dependedAssembly, содержащий частное имя сборки, культуру, открытый ключ Name Частное имя сборки Да
publicKeyToken Открытый ключ сборки, если она подписана строгим именем Нет
Culture Культура, указанная в сборке Нет
<bindingRedirect> Вложенный элемент dependedAssembly, содержит информацию об изменении версии сборки oldVersion Старая версия сборки, которую нужно заменить Да
newVersion Новая версия сборки, на которую нужно заменить старую Да
<codeBase> Вложенный элемент dependedAssembly, содержит путь до сборки со строгим именем Version Версия сборки Да
Href Адрес подключаемой сборки Да
<probing> Указывает вложенные папки, в которых могут находиться подключаемые сборки privatePath Содержит названия каталогов, в которых могут находиться подключаемые сборки. Все указанные каталоги должны быть вложенными Да
<publisherPolicy> Указывает, использовать ли настройки издателя. Если этот элемент расположен в элементе dependedAssembly, то политика распространяется только на указанную сборку, в противном случае политика распространяется на все указанные в файле конфигурации сборки Apply Указывает, применять ли политику издателя к сборкам. Возможные значения — yes и no Да

Выше мы использовали политику управления версиями сборок для указания применения в приложении более новой версии сборки. Сделаем то же самое, используя файл конфигурации.

Скопируйте приложение AssVersion и назовите его AssVersionOne. Изменим строку, возвращаемую методом, на Version One:

using System;

namespace AssVersion
{
  public class MyClass
  {
    
    public static string GetString()
    {
      return "Version One";
    }
  
}

}

Устанавливаем следующие значения атрибутов файла AssemblyInfo.cs:

[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyKeyFile("C:\\StrongKey.snk")]

Компилируем сборку, закрываем проект, копируем всю его папку и называем ее AssVersionTwo. Снова меняем значение возвращаемой строки и значения атрибутов в AssemblyInfo.cs:

using System;

namespace AssVersion
{
  
  public class MyClass
  {
    public static string GetString()
    {
      return "Version Two";
    }
  
}

[assembly: AssemblyVersion("2.0.0.0")]

Компилируем это приложение и добавляем обе сборки в GAC при помощи консоли MMC, предварительно удалив из списка сборки, использованные нами в прошлом примере. Не забудьте также удалить политику управления версиями сборок! Теперь займемся приложением, которое будет использовать эти сборки. Скопируйте папку проекта UsingMyClassFromGAC и назовите ее UsingAssemblyConfig. Открываем проект, в окне Solution Explorer удаляем ссылку на сборку AssVersion и добавляем новую ссылку на сборку из проекта AssVersionOne. Запускаем проект из командной строки Visual Studio .NET (рис. 9.32).

(рис 9.32) Результат запуска приложения UsingAssemblyConfig

Приложение возвращает текстовую строку из первой сборки — Version One. Добавим теперь файл конфигурации приложения — щелкаем правой кнопкой мыши в окне Solution Explorer и в меню выбираем Add\Add New Item… . В появившемся окне прокручиваем список шаблонов до самого конца и выбираем шаблон Application configuration file, и не изменяя его названияПри этом мы добавляем рабочий файл конфигурации — в папке проекта появится файл App.config. Псоле компиляции проекта в папке bin\Debug появится файл конфигурации UsingMyClassFromGAC.exe.config, который будет использоваться в приложении. — App.config — нажимаем OK. Я привожу его содержимое для сборки, подписанной ключом StrongKey.snk:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="AssVersion" publicKeyToken="b19037b107de741b"  
         culture="neutral" />
        <bindingRedirect oldVersion="1.0.0.0" newVersion="2.0.0.0" />  
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

В этом коде мы указываем имя сборки — Ass Version, открытый ключ для приложения (publicKeyToken) — b19037b107de741b и культуру сборки — neutral. Если до этого момента вы воспроизводили все действия самостоятельно, то открытый ключ будет другим. Для просмотра сведений о сборке и открытого ключа, в частности, в консоли MMC, щелкните правой кнопкой на выбранной сборке, выберите ее свойства и в появившемся окне скопируйте значение publicKeyToken (рис. 9.33).

(рис 9.33) Открытый ключ приложения publicKeyToken в окне свойств сборки

Компилируем приложение и запускаем его в командной строке. Результатом выполнения программы будет текст VersionTwo (рис. 9.34).

(рис 9.34) Результат запуска приложения с конфигурационным файлом

Мы не указывали ссылку на сборку новой версии — среда CLR при запуске приложения считала данные о версиях сборок из файла конфигурации, нашла новую версию в GAC и вывела его содержимое в приложение. Этот прием используется для обновления программ через Интернет: пользователь скачивает пакет обновлений, содержащий одну или несколько новых сборок, которые установочный пакет помещает в GAC. В конфигурационном файле приложения заранее заданы названия новых версий сборок — и тогда среда CLR запускает обновленную версию программы без перезагрузки операционной системы. Если сборка не была помещена в GAC, то в конфигурационном файле следует указать путь к новой версии сборки при помощи тега <codeBase>.

На диске, прилагаемом к книге, вы найдете приложения AssVersionOne, AssVersionTwo и UsingAssemblyConfig (Code\Glava9\AssVersionOne, AssVersionTwo, UsingAssemblyConfig).

Создание пакетов установки

Установка программы представляет собой копирование сборок и файлов, необходимых для работы приложения, в определенную папку на компьютере пользователя. При этом также происходит интеграция приложения в операционную систему Windows — добавление иконок на рабочий стол, в меню "Пуск", в контекстное меню правой кнопки мыши. Для слежения за лицензионным использованием программы или сохранением пользовательских настроек приложения следует предусмотреть возможность автоматического внесения изменений в реестр при установке. Если размер программы достаточно велик, файлы подлежат также архивации, и тогда установка программы сопровождается ее извлечением из архива. Первое знакомство пользователя с вашим приложением начинается именно с установки, и поэтому даже если сама программа очень хорошая, но ее трудно устанавливать, большинство пользователей откажутся от ее использования. Установка приложения должна отвечать следующим критериям:

  • Запуск программы установки происходит один раз.
  • Программа установки имеет название Setup.exe или Install.exe, и ее легко найти среди файлов установки.
  • Если программа распространяется на CD, то вставка диска в привод приводит к автоматическому запуску установки либо к появлению заставки, на которой при переходе по гиперссылке начинается установка.
  • Каждый шаг установки предполагает оптимальный вариант по умолчанию.
  • Информация, показанная при установке, необходима и достаточна, и обращение к файлу Readme не является обязательным.
  • Одна программа установки работает на всех поддерживаемых приложением версиях операционной системы.
  • Практически все крупные пакеты, такие как Microsoft Office или Adobe Photoshop, отвечают этим требованиям.

    Распространение приложений, написанных на языке C#, одном из языков платформы .NET, обладает важной особенностью: для работы программы необходимо наличие установленной в операционной системе библиотеки .NET Framework. Достаточно однократного включения в пакет установки этой библиотеки для последующей установки самих приложений платформы .NET в чистом виде, т. е. только файлов, созданных непосредственно вами. Проблема в том, что размер библиотеки .NET Framework и дополнительных утилит может достигать 50-70 Мб, что является одной из причин затруднительного распространения приложений через Интернет. На сегодняшний день .NET Framework 1.1 встроен только в операционную систему Windows 2003 Server family. Однако через несколько лет, с выходом и массовым распространением Windows Longhorn можно ожидать частичного решения этой проблемы — новая версия операционной системы будет содержать в себе библиотеку .NET Framework.

    Существует несколько способов переноса готового приложения на компьютер пользователя.

    Так называемая установка XCOPY – это простое копирование папки с приложением. Программа будет работать, если на компьютере установлен .NET Framework и ключи реестра не используются. Приложение может содержать только частные и подписанные строгим именем сборки. При подобной установке не происходит автоматической генерации иконок на рабочем столе или меню "Пуск". Для удаления приложения достаточно просто удалить его папку. Этот способ установки неприменим для распространения коммерческих приложений.

    Среда Visual Studio .NET предоставляет возможность создания пакетов дистрибутивов, позволяющих пользователю с минимумом усилий устанавливать приложение на свой компьютер. Получаемый в результате файл Windows Installer 2.0 позволяет установить, изменить или удалить приложение с компьютера пользователя. С помощью Windows Installer можно также управлять глобальным КЭШем сборок.

    Для распространения одной сборки используются файлы-кабинеты (.cab – files.). Cab-файл должен иметь то же самое имя, что и сборка, находящаяся в нем. Например, если cab-файл содержит сборку Assembly.dll, то он должен называться Assembly.cab. После того как вы создадите cab-файл, его можно будет загрузить используемым приложением, указав его адрес в теге codeBase файла конфигурации.

    Итак, существует три вида распространения сборок и приложений. С установкой XCOPY вы сталкивались при использовании готовых приложений с диска, прилагаемого к книге, — копировали их на свой компьютер и запускали exe-файл из папки bin\Debug. Распространение одной сборки — задача, встречаемая при создании патчей (дополнений) к программам и технически выполняемая достаточно просто. Наибольший интерес представляет создание полных пакетов установки, к рассмотрению которого мы и приступим.

    Создание простого пакета установки без библиотеки .NET Framework

    В качестве исходного приложения для распространения возьмем проект NotepadCSharp, c которым мы работали во второй лекции. На панели инструментов Standard среды Visual Studio .NET расположен список Solution Configurations, значения которого определяют режим компиляции приложения (рис. 9.35).

    (рис 9.35) Панель инструментов Standard и режим компиляции Debug

    Это режим компиляции, принятый по умолчанию, при его запуске появляется папка bin\Debug, которая содержит, кроме готового exe-файла, отладочную информацию. Приложение, подлежащее распространению, должно состоять только из рабочих файлов, поэтому в списке Solution Configurations выбираем режим Release и снова компилируем приложение. При этом в проекте появится папка bin\Release с готовым приложением.

    Пакеты установки можно создавать непосредственно в текущем проекте приложения, но мы сделаем отдельный пакет. Создайте папку и назовите ее NotepadCSharpSetup. Теперь запустите Visual Studio.NET и создайте новый проект в папке NotepadCSharpSetup, тип проекта Setup and Deployment Projects, шаблон — Setup Project, название — NotepadCSharpSetup (рис. 9.36).

    (рис 9.36) Создание проекта установки

    В окне Solution Explorer щелкаем на названии проекта — NotepadCSharp и затем переходим в окно его свойств, щелкая на вкладку Properties (или нажав клавишу F4) — именно так, а не по щелчку в пункте Properties контекстного меню! Дело в том, что в контекстном меню содержатся свойства самого проекта (рис. 9.37), а в окне Properties — свойства пакета установки (рис. 9.38), которые нам и нужно настроить.

    (рис 9.38) Свойства проекта установки(рис 9.37) Свойства пакета установки

    В свойствах самого проекта можно указать название выходного файла (Output file name), тип сжатия (Compression) — та самая архивация, которой подвергают все большие программы и даже цифровую подпись (Authenticode signature). В свойствах пакета установки следует указать имя автора и производителя, сайт продукта и его поддержки, телефоны, — примерный вариант заполнения этих свойств указан на рис. 9.38.

    Добавим файл NotepadCSharp.exe, который нам предстоит упаковать. Щелкаем правой кнопкой на папке Application Folder и выбираем пункт Add/File (рис. 9.39).

    (рис 9.39) Добавления файла приложения в проект установки

    Переходим в папку bin/Release и выбираем файл NotepadCSharp.exe. Добавим ярлыки приложения в пакет — они будут появляться при установке программы на Рабочем столе и в меню "Пуск". Щелкаем правой кнопкой на имени добавленной сборки и выбираем пункт Create Shortcut to Notepad CSharp.exe. Создадим два ярлыка и переименуем их (рис. 9.40).

    (рис 9.40) Добавление ярлыков к приложению

    Теперь "хватаем" мышью по очереди эти ярлыки и помещаем их в папки User's Desktop и User's Programs Menu (рис. 9.41).

    (рис 9.41) Перемещение ярлыков в папки User's Desktop и User's Programs Menu

    Переходим в папку User’s Desktop и, выделив ярлык, открываем окно его свойств. В поле свойства Icon щелкаем на значение Browse из выпадающего списка, в появившемся окне снова щелкаем на кнопку Browse. В окне Select Item in Project в выпадающем списке "Look in:" выбираем значение Application Folder и щелкаем на ставшую доступной кнопку Add File… . Иконка приложения расположена в каталоге NotepadCSharp\Icon\README.ICO, выбираем ее и закрываем окна Select Item in Project и Icon. Проделываем то же самое для изображения иконки папки User's Programs Menu.

    В процессе установки будет появляться несколько диалоговых окон, созданных по шаблону. Изменим немного интерфейс этих окон и текст на них. Для этого щелкаем в окне Solution Explorer на кнопке User Interface Editor (рис. 9.42).

    (рис 9.42) Кнопка User Interface Editor и деревья диалоговых окон

    Появляется два дерева диалоговых окон, мы будем редактировать формы дерева Install. Выделяем форму Welcome и переходим к его свойствам. Свойство BannerBitmap позволяет добавлять баннер размером 497х69 пикселей на диалоговое окно. В поле значения этого свойства выбираем Browse — и перед нами появляется уже знакомое окно Select Item in Project, добавляем в это окно баннер Bannersetup.bmp из папки NotepadCSharp\Icon. Переходим к надписям, которые будут располагаться на форме. В свойстве CopyrightWarning приводится текст предупреждения об авторских правах, оставим его без изменений — вы можете изменить его в своем проекте. В свойстве WelcomeText заменяем слова [ProductName] на NotepadC#. Текст надписей оставим на английском языке – кириллица отображается некорректно. В свойствах BannerBitmap следующих форм InstallationFolder, Confirm Installation и Progress также устанавливаем баннер Bannersetup.bmp. В последней форме изменяем текст свойства UpdateText на Thank you for your choice! и снова устанавливаем баннер. Устанавливаем режим Release и компилируем проект. Переходим в папку NotepadCSharpSetup\NotepadCSharp\Release и запускаем файл установки Setup.Exe (рис. 9.43).

    (рис 9.43) Форма Welcome пакета установки

    После выполнения всех шагов мастера программа устанавливается и становится доступной с рабочего стола (рис. 9.44), из меню "Пуск" (рис. 9.45) и рабочей папки приложения (рис. 9.46).

    (рис 9.45) Иконка приложения на Рабочем столе(рис 9.44) Иконка в меню пуск(рис 9.46) Иконка в рабочей папке

    Удалить программу можно с помощью стандартной утилиты "Установка и удаления программ" операционной системы Windows.

    На диске, прилагаемом к книге, вы найдете проект установки (Сode\Glava9\NotepadCSharpSetup\NotepadCSharp\NotepadCSharp.sln).

    Изменение каталога установки

    По умолчанию, программа устанавливается в каталог [ProgramFiles][Производитель (NotepadSoft)]\[ProductName (NotepadCSharp)] (см. рис. 9.46). Для изменения пути в проекте установки щелкаем правой кнопкой на папке Application Folder и меняем свойство DefaultLocation (рис. 9.47).

    (рис 9.47) Изменения каталога установки

    Добавление ключей реестра на компьютер пользователя

    Для добавления ключей реестра на компьютер пользователя при установке приложения их следует включить в пакет установки. В окне Solution Explorer нажимаем на кнопку Registry Editor (рис. 9.48).

    (рис 9.48) Добавление ключей реестра

    В появившемся окне Registry выбираем нужную ветвь реестра и создаем нужный параметр (рис. 9.49).

    (рис 9.49) Добавление ключа в выбранный раздел реестра

    При установке приложения созданный ключ будет добавлен в реестр компьютера пользователя.

    Добавление публичных сборок в GAC

    При создании нового проекта установки папка Global Assembly Cache скрыта по умолчанию. Для отображения этой папки в окне File System щелкаем правой кнопкой мыши на File System on Target Machine и выбираем Add Special Folder\Global Assembly Cache Folder. На появившейся папке снова щелкаем правой кнопкой и выбираем один из трех вариантов — конечный результат указанного проекта, файл или сборку из GAC данного компьютера (рис. 9.50).

    (рис 9.50) Выбор источника сборки

    При выборе сборки из GAC (Assembly) появляется список сборок, из которого следует выбрать нужные (рис. 9.51).

    (рис 9.51) Добавление сборки из GAC данного компьютера

    При установке программы выбранные сборки автоматически будут добавлены в GAC на компьютере пользователя.

    Добавление библиотеки .NET Framework

    Скорее всего, на компьютере пользователя не будет библиотеки .NET Framework, необходимой для работы приложения, которое написано на C#. Пакет установки .NET Framework — размеромРазмер может варьировать в зависимости от версии библиотеки и количества включенных в него компоненттов. Я имею в виду версию .NET Framework 1.1. около 23 Мб, называется dotnetfx.exe. В проекте в список зависимостей проекта автоматически включается файл dotnetfxredist_x86_enu.msm, который по умолчанию отмечен как исключенный (excluded) из результирующего пакета установки (рис. 9.52).

    (рис 9.52) В список зависимостей проекта установки входит файл библиотеки

    Однако при снятии галочки Exclude и попытке включения библиотеки в пакет установки возникает ошибка:

    dotNETFXRedist_x86_enu.msm must not be used to redistribute the .NET Framework.  
    Please exclude this merge module.

    Скорее всего, вначале предполагалось включать таким образом .NET Framework в состав инсталляций Но сейчас этот merge module используется только с одной целью: он предотвращает автоматическое включение в проект некоторых DLL, входящих в CLR.

    Итак, сейчас .NET Framework не может быть объединен с пакетом установки вашей программы непосредственно в среде Visual Studio .NET. Однако существует несколько способов включения библиотеки в состав дистрибутива.

    При компиляции пакета установки в папке Release проекта создается три файла – NameApplication.msi, Setup.exe и Setup.ini. NameApplication.msi — это основной файл Windows Installer 2.0, содержащий все необходимые для установки приложения файлы. Setup.exe — программа, предназначенная для запуска файла .msi. С помощью этого файла устанавливается дополнительное программное обеспечение, необходимое приложению. И, наконец, Setup.ini — это конфигурационный файл приложения Setup.exe.

    Установка приложения не начнется, пока Windows Installer не определитДля получения информации об установленных версиях .NET Framework используем реестр HKEY_LOCAL_MACHINE\Software\Microsoft\.NETFramework, ключ InstallRoot — директория, куда устанавливается .NET Framework — обычно это C:\WINDOWS\Microsoft.NET\Framework. Если такого каталога на диске нет, то .NET Framework не установлен. HKEY_LOCAL_MACHINE\Software\Microsoft\.NETFramework\Policy ключи вида \vX.X содержат информацию об установленных версиях .NET Framework на компьютере пользователя установленный .NET Framework. Этот порядок можно изменить с помощью утилиты bootstrapper.exe, заменяющей существующий setup.exe на новый, который позволяет устанавливать .NET Framework на компьютер пользователя. Свойству Bootstrap проекта установки устанавливаем значение None (см. рис. 9.37) — в результате при компиляции создастся только файл .msi. Теперь извлекаем из архива утилиту bootstrapper.exe в папку Release c файлом .msi. Также в эту папку помещаем пакет установки .NET Framework — dotnetfx.exe. В результате в папке будет четыре файла — .msi, setup.exe, setup.ini и dotnetfx.exe. Открываем файл setup.ini и меняем его содержимое следующим образом:

  • "Msi=FxCopSourceSetup.msi" изменяем на Msi=ВашMSIФайл.msi;
  • удаляем комментарий со строки 'FxInstallerPath=c: (нужно удалить символ ') и изменяем на расположение файла dotnetfx.exe. Например, если dotnetfx.exe расположен в том же каталоге, что и setup.exe, то вместо адреса нужно написать FxInstallerPath=.
  • После завершения этих действий пакет установки будет готов. Если Windows Installer обнаружит предыдущую версию .NET Framework или не обнаружит ее вообще на машине пользователя, то он ее обновит или установит.

    На диске, прилагаемом к книге, вы найдете архив утилиты bootstrapper.exe (Code\Glava9\ bootstrapper.exe).

    Я не привожу утилиту dotnetfx.exe из-за ее значительного размера, ее новую версию можно найти на официальном сайте MicrosoftЯ также не привожу ссылок — версии утилит быстро меняются и ссылки устаревают, воспользуйтесь поиском на сайте Microsoft..

    Другие библиотеки для работы приложения — MDAC, Jet и Crystal Reports

    К сожалению, библиотека .NET Framework представляет не исчерпывающий набор компонент для работы приложения. Если приложение использует доступ к базе данных (используется пространство имен System.Data), потребуется также установка Microsoft Data Access Components (MDAC). MDAC распространяется в виде файла установки mdac_typ.exe. Для работы отчетов Crystal Reports (CR) на машине клиента должен быть установлен Crystal Reports Free Runtime — набор библиотек и лицензия. Компоненты, так же как и сама библиотека .NET Framework, периодически обновляются, актуальные версии доступны на сайте Microsoft.

    Изменение пользовательского интерфейса установочного пакета

    При создании пакета установки для приложения NotepadC# мы изменяли пользовательский интерфейс форм, предложенных мастером. Среда Visual Studio .NET позволяет также добавлять отдельные формы в диалог установки. Добавим в этот пакет форму с лицензионным соглашением.

    Открываем проект NotepadCSharp и снова переходим на вкладку User Interface Editor, щелкнув на одноименной вкладке в окне Solution Explorer. Щелкаем правой кнопкой мыши на группе Start ветви Install и выбираем пункт меню Add Dialog. В появившемся окне шаблонов выделяем форму License Agreement и нажимаем ОК (рис. 9.53).

    (рис 9.53) Форма License Agreement

    Теоретически можно добавить любое диалоговое окно в любой раздел проекта установки, но добавление диалогового окна Finish в раздел Start приведет к ошибке компиляции. Лицензионное соглашение обычно появляется сразу после окна приветствия — управлять расположением формы можно, просто перетаскивая ее или используя контекстное меню (рис. 9.54).

    (рис 9.54) Расположение формы в списке

    В свойстве LicenseFile из выпадающего списка выбираем Browse и добавляем файл license.rtf из каталога Code\Glava9\NotepadCSharpSetup\ license.rtf. В этом файле содержится фрагмент стандартного определения прав между производителем и конечным пользователем. Добавим также баннер Bannersetup.bmp, который мы использовали также для оформления других форм. Компилируем проект. Теперь при установке программы появляется окно с лицензионным соглашением (рис. 9.55).

    (рис 9.55) Диалоговое окно с лицензионным соглашением. Попробуйте добавить файл лицензионного соглашения на русском языке

    Использование данных, получаемых при установке

    При установке некоторых программ требуется определять не только каталог установки, но и другие параметры, необходимые для работы приложения. Рассмотрим использование данных пользователя для пакета, устанавливающего базу данныхДля этого примера вам потребуется установленная СУБД SQL Server . Создайте новую библиотеку (тип проекта — Visual C# Projects, шаблон — Class Library) и назовите ее InstallerClass. В окне Solution Explorer щелкаем правой кнопкой на названии проекта и выбираем пункт меню Add New Item. В появившемся окне выбираем шаблон Installer Class и называем его CustomActionDB (рис. 9.56).

    (рис 9.56) Добавление шаблона Installer Class

    Удаляем из проекта Class1.cs. В окне Server Explorer на заголовке Data Connection щелкаем правой кнопкой мыши и выбираем пункт Add Connection. В открывшемся окне на вкладке "Подключение" выбираем или вводим название SQL-сервера (для подключения к локальному серверу вводим "(local)"), выбираем для входа в сеть учетные сведения Windows NT, а в выпадающем списке названий баз данных выбираем или вводим master. Завершив настройку соединения, проверяем подключение и нажимаем OK. В окне Solution Explorer щелкаем правой кнопкой на классе CustomActionDB и выбираем View Designer. Из окна Toolbox добавляем объект SqlConnection и в свойстве ConnectionString указываем только что созданное подключение. В окне Solution Explorer щелкаем правой кнопкой на названии проекта и добавляем к нему TextFile, который называем sqlScript.txt (рис. 9.57).

    (рис 9.57) Добавленный текстовый файл sqlScript.txt

    В этом текстовом файле вводим SQL-запрос на создание таблицы:

    CREATE TABLE [dbo].[Employees] (
    [Name] [char] (30) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
    [Rsvp] [int] NULL ,
    [Requests] [nvarchar] (4000) COLLATE SQL_Latin1_General_CP1_CI_AS NULL 
    ) ON [PRIMARY];
    
    ALTER TABLE [dbo].[Employees] WITH NOCHECK ADD 
    CONSTRAINT [PK_Employees] PRIMARY KEY CLUSTERED 
    (
    [Name]
    ) ON [PRIMARY];

    В окне Properties файла sqlScript.txt устанавливаем значение свойства Build Action на Embedded Resource (рис. 9.58):

    (рис 9.58) Свойство Build Action для файла sqlScript.txt

    Добавляем в класс CustomActionDB код, считывающий текстовый файл:

    /// <summary>
        /// Считывание  текста из файла.
        /// </summary>
        /// <param name="name">Название файла.</param>
        /// <returns></returns>
        private string GetSql(string name)
        {
          try
          {
            // Получаем текущий объект класса Assembly
            System.Reflection.Assembly asm = System.Reflection.Assembly.GetExecutingAssembly();
            // Получаем объект класса Stream к ресурсам текущей сборки.
            System.IO.Stream str = asm.GetManifestResourceStream(asm.GetName().Name + "." + name);
            // Считываем и возвращаем содержимое.
            System.IO.StreamReader reader = new System.IO.StreamReader(str);
            return reader.ReadToEnd();
          }
          catch(Exception ex)
          {
            // Отлавливаем возникшие исключения.
            System.Windows.Forms.MessageBox.Show("В методе GetSql возникла ошибка: "+ex.Message);
            throw ex;
          }    
        }
        /// <summary>
        /// Выполнение SQL-запроса.
        /// </summary>
        /// <param name="databaseName">Название базы данных.</param>
        /// <param name="sql">Текст команды.</param>
        private void ExecuteSql(string databaseName, string sql)
        {
          // Создаем объект класса SqlCommand.
          System.Data.SqlClient.SqlCommand comm = new System.Data.SqlClient.SqlCommand(sql, sqlConnection1);
          // Открываем соединение.
          comm.Connection.Open();
          // Изменяем используемую базу данных.
          comm.Connection.ChangeDatabase(databaseName);
          try
          {
            // Выполняем команду.
            comm.ExecuteNonQuery();
          }
          finally
          {
            // Закрываем соединение.
            comm.Connection.Close();
          }
        }
        /// <summary>
        /// Создание таблицы в базе данных.
        /// </summary>
        /// <param name="databaseName">Название базы данных.</param>
        protected void AddDBTable(string databaseName)
        {      
          try
          {
            // Создаем новую базу данных.
            this.ExecuteSql("master", "CREATE DATABASE " + databaseName);
            // Создаем таблицу в новой базе данных.
            this.ExecuteSql(databaseName, this.GetSql("sqlScript.txt"));
          }
          catch(Exception ex)
          {
            System.Windows.Forms.MessageBox.Show("В методе AddDBTable возникла ошибка: "+ex.Message);
          }
        }
        /// <summary>
        /// Перегружаем метод Install
        /// </summary>
        /// <param name="stateSaver">Параметр по умолчанию.</param>
        public override void Install(IDictionary stateSaver)
        {    
          base.Install (stateSaver);
          // В качестве названия БД передаем введенное значение пользователем.
          this.AddDBTable(this.Context.Parameters["dbname"]);
        }

    Компилируем библиотеку. При этом возникает исключение — класс библиотеки не содержит ссылки на пространство имен Windows:

    The type or namespace name 'Windows' does not exist in the class or namespace
     'System' (are you missing an assembly reference?)

    Для добавления ссылки на это пространство имен щелкаем правой кнопкой мыши на папке References в окне Solution Explorer и выбираем пункт Add References…(рис.рис. 9.59).

    (рис 9.59) Добавление ссылки на пространство имен

    В появившемся списке выбираем пространство имен System.Windows.Forms и добавляем его. Снова компилируем приложение. В окне Solution Explorer щелкаем правой кнопкой на заголовке Solution ‘Installer Class’(1 project) и выбираем Add\New Project. В появившемся окне добавляем проект установки (тип проекта — Setup And Deployment Projects, шаблон – Setup Project) и называем его CustomActionSetup.

    Открываем меню изменения пользовательского интерфейса. Добавьте в раздел Start новое диалоговое окно Textboxes (A) и нажмите ОК (рис. 9.60).

    (рис 9.60) Добавление диалогового окна

    Размещаем добавленное окно под диалоговым окном Installation Folder (рис. 9.61).

    (рис 9.61) Расположение добавленного окна

    Устанавливаем следующие свойства окна:

    Banner Text Add the data base name Укажите имя базы данных.
    Body Text We need this data to create the Data base, that used by our program Эти данные необходимы для создания новой базы данных приложения на вашем сервере баз данных
    Edit1Label Data Base Name Название базы данных
    Edit1Property CUSTOMTEXTA1 Текст, вводимый пользователем

    Свойствам Edit2Visible, Edit3Visible и Edit4Visible устанавливаем значение false.

    В окне Solution Explorer нажимаем на кнопку Custom Actions Editor. В открывшемся окне выделяем папку Install и в контекстном меню выбираем Add Custom Action (рис. 9.62):

    (рис 9.62) Добавление Custom Action

    В окне Select Item in Project в папке Application Folder нажимаем на кнопку Add Output. В Add Project output Group выбираем элемент Primary output и нажимаем OK (рис. 9.63).

    (рис 9.63) Выбор Custom Action

    Свойству CustomActionData созданного элемента Primary Output from InstallerClass (Active) устанавливаем значение /dbname=[CUSTOMTEXTA1] (рис. 9.64).

    (рис 9.64) Изменение свойств CustomActionData

    В результате у нас получилось приложение, состоящее из двух проектов. В окне Solution Explorer щелкаем правой кнопкой на названии проекта InstallerClass и выбираем пункт меню Build. Проделываем то же самое для проекта CustomActionSetup. В папке CustomActionSetup\Release появились файлы установки, запускаем Setup.exe. В процессе установки появляется окно для введения названия новой базы данных (рис. 9.65).

    (рис 9.65) Определение названия создаваемой базы данных

    После установки приложения появится новая база данных SQL — в этом можно будет убедиться, запустив программу Enterprise Manager из группы Microsoft SQL Server в меню "Пуск". В рассмотренном примере использовалась локальная база данных — для установки БД на компьютере пользователя необходимо указать сервер базы данных с помощью пользовательского интерфейса проекта.

    На диске, прилагаемом к книге, вы найдете проекты InstallerClass и CustomActionSetup (Code\Glava9\ InstallerClass и CustomActionSetup).

    Создание автозагрузочного диска

    Если программа распространяется на компакт-диске, лучше всего сделать этот диск автозагрузочным — при его вставке в лоток автоматически запустится программа установки. Для этого в файле autorun.inf, получаемом из обычного текстового файла, указываем иконку autorun.ico и файл setup.exe для запуска (рис. 9.66).

    (рис 9.66) Содержимое автозагрузочного диска

    Для предоставления пользователю выбора программ из списка можно сделать html-страницу, с которой будут даваться гиперссылки на файлы установки setup.exe. программ. При размещении файла index.htm и иконки autorun.ico в корневом каталоге диска содержимое autorun.inf примет слендующий вид:

    [autorun]
    OPEN=explorer.exe index.htm
    ICON=AUTORUN.ICO

    На диске, прилагаемом к книге, вы найдете папку AUTORUN со всем содержимым для автоматического запуска программы установки (Code\Glava9\ AUTORUN).

    Страницы:
    Для работы с данной лекцией используйте примеры.

    Для установки на компьютер большинства программ достаточно просто вставить компакт диск с программой в дисковод и, следуя несложным инструкциям, скопировать ее на жесткий диск. В результате мы получаем возможность запускать программу одним из нескольких способов — щелкая на ярлыке на Рабочем столе, выбирая ее группу в меню Пуск или просто дважды щелкая на файле, расширение которого связано с этой программой. Мы не задумываемся, из каких частей состоит программа, как они взаимодействуют, а некоторые пользователи даже не представляют, где эти части находятся. В этой лекции мы научимся создавать дистрибутивы, или пакеты установки, предоставляющие возможность распространять программы с минимумом усилий со стороны конечного пользователя.

    Сборки. Утилита ildasm.exe

    Приложение всегда состоит из одной или более сборок. Сборка — это функциональная единица, имеющая версию и описание, которую можно использовать в других приложениях. Для каждой сборки можно прописывать отдельные разрешения (подробнее о разрешениях см. лекцию 10).

    В самом простом случае, сборка — это приложение, которое состоит из одного функционального модуля — класса. В большинстве случаев в приложении может быть несколько сборок, и каждая может иметь свои вспомогательные файлы. При выполнении все сборки приложения должны существовать и к ним должен быть открыт доступ. Каждая сборка должна быть независимой. У любой сборки есть метаданные, которые описывают сборку и содержат версию.

    Содержимое сборки можно просмотреть, запустив дизассемблер "Microsoft Intermediate Language Disassembler" (ildasm.exe). Рассмотрим следующий пример — создадим простое консольное приложение, которое выводит на экран строку Hello World:

    using System;
    
    namespace SimpleApp
    {
        class Class1
        {
          [STAThread]
          static void Main(string[] args)
          {
            Console.WriteLine("Hello World");
          }
        }
    }

    Утилиту ildasm.exe можно запустить двумя способами — перейти по адресу C:\Program Files\Microsoft Visual Studio .NET 2003\SDK\v1.1\Bin и запустить непосредственно файл ildasm.exe или перейти в Пуск\Все программы\ Microsoft Visual Studio .NET 2003 \ Visual Studio .NET Tools \ Visual Studio .NET 2003 Command Prompt и в появившейся командной строке ввести

    ildasm.exe

    После того как приложение запустится, откроем только что созданную сборку (файл SimpleApp.exe из папки bin/Debug), (рис. 9.1).

    (рис 9.1) Сборка SimpleApp, открытая с помощью утилиты ildasm.exe

    Как мы знаем, у класса всегда есть конструктор. Если он не был создан вручную, компилятор создаст конструктор по умолчанию. В утилите он называется .ctor. Также в созданной нами программе есть метод Main, который принимает строковый массив и не возвращает значений. Щелкаем на методе Main два раза. Открывается окно с MSIL (Microsoft Intermediate Language) кодом этого метода. Здесь видим строковую переменную ldstr со значением "Hello World" и запуск статического метода WriteLine класса Console (рис. 9.2).

    (рис 9.2) MSIL-код метода Main

    На рис. 9.2 я снова привел окно утилиты ildasm.exe: щелкнув на кнопку прокрутки, замечаем номер версии сборки — 1.0.2300.26912.

    Частные сборки

    Программы, которые написаны на языках, поддерживаемых библиотекой .NET Framework, и на C# в частности, компилируются в код MSIL, которые затем среда CLR (Common Language Runtime) преобразует в машинный код.

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

    Частные сборки отвечают тем же требованиям, что и обычные, но предназначены они для использования только в одном приложении и, как правило, лежат в той же папке, что и использующее их приложение. Частная сборка может находиться не только в корневой папке, но и во вложенных папках корневого каталога. Приложение ссылается на частную сборку по ее частному имени, которое содержится в метаданных. Когда среда CLR ищет частную сборку для применения, она использует частное имя сборки для поиска, причем поиск осуществляется в корневом каталоге и дочерних подкаталогах. Среда не будет искать сборку в родительской папке каталога.

    Если мы хотим использовать любой путь для размещения сборки, то следует воспользоваться методом LoadFrom класса Assembly и указать ему адрес нахождения файла со сборкой. Класс Assembly находится в пространстве имен System.Reflection. Создайте новое консольное приложение и назовите его SimpleAssembly. Удалите все фрагменты кода, оставив только следующий участок:

    using System;
    
    namespace SimpleAssembly
    {  
        public class Class
        {
          public static string HelloWorld()
          {
            return "hello world";
          }
        }
    }

    Скомпилировав приложение (Ctrl+Shift+B), мы получим сборку SimpleAssembly.dll. Теперь создадим еще одно консольное приложение — UsingLoadFrom, в папку bin/Debug которого помещаем файл SimpleAssembly.dll. В методе LoadFrom считываем содержимое сборки SimpleAssembly.dll:

    using System;
    using System.Reflection;
    
    namespace UsingLoadFrom
    {
      class Class1
      {
        [STAThread]
        static void Main(string[] args)
        {
          Assembly privateAss = 
    Assembly.LoadFrom("SimpleAssembly.dll");
          MethodInfo info = 
         privateAss.GetTypes()[0].GetMethod("HelloWorld");
          Object obj = info.Invoke(null, null);
          Console.WriteLine("Результат выполнения метода: {0}", 
    obj);
        }
      }
    }

    Результатом запуска этого приложения будет вывод на экран строки Hellow World — результата метода HelloWorld сборки SimpleAssembly.dll.

    Рассматриваемые листинги предельно просты. Тем не менее на диске, прилагаемом к книге, вы найдете приложения SimpleAssembly и UsingLoadFrom (Code\Glava9\ SimpleAssembly и UsingLoadFrom).

    Сборки со строгим именем

    Обычные сборки могут быть без труда декомпилированы, и код в них может быть повторно использован. Для коммерческих приложений это недопустимо. Сборки, подписанные строгим именем, позволяют обеспечить безопасность, защиту кода, облегчить применение их в несколько приложениях, а также управлять версионностью сборок. Строгое имя является уникальным обозначением сборки. Оно гарантирует невозможность замены вашей сборки другой.

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

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

    Строгое имя сборки гарантирует ее уникальность и защиту от декомпиляции.

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

    Сборка со строгим именем может располагаться в любых местах — корневой папке приложения, произвольной папке локального или удаленного компьютеров, в Интернете.

    Одни и те же сборки могут быть использованы в нескольких приложениях. Можно не дублировать эти сборки, а разместить их в так называемом глобальном КЭШе сборок (Global Assembly Cache) — централизованном хранилище сборок. В результате получается значительный выигрыш в размере приложения. В GAC может храниться несколько версий одной сборки, и он может управлять ими. Если сборку разместили в GAC, то она автоматически становится публичной — доступной другим приложениям. Если, напротив, использование подписанной сборки другими приложениями не требуется — достаточно поместить ее в корневую папку приложения.

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

    Создание сборки со строгим именем

    В комплект поставки Microsoft Visual Studio .NET входят утилиты Microsoft .NET Framework Tools, применяемые для дополнительной работы с приложениями и компонентами. Файлы большинства утилит располагаются в каталоге С\Program Files\Microsoft Visual Studio .NET 2003\SDK\v1.1\Bin. Описание со ссылками на дополнительные справочные ресурсы находится в в папке Bin в документе StartTools.htm. В этой и следующей лекциях мы рассмотрим работу с несколькими утилитами.

    Создание сборки со строгим именем сводится к созданию закрытого ключа для шифрования хэш-кода сборки. Для этого используется утилита sn.exe. Непосредственный запуск из папки Bin не позволит приступить к работе — подобно прочим утилитам, ее функции доступны из командной строки. Для запуска sn.exe из командной строки WindowsДля запуска командной строки Windows выбираем "Пуск\Выполнить" и вводим cmd. Сочетание клавиш Windows+R также запускает строку "Выполнить". указываем путь к каталогу и название (рис. 9.3).

    (рис 9.3) Запуск sn.exe из командной строки Windows

    Более удобный способ работы с утилитами — использование командной строки Visual Studio .NET. Для ее запуска выбираем Пуск\Все программы\ Microsoft Visual Studio .NET 2003 \ Visual Studio .NET Tools \ Visual Studio .NET 2003 Command Prompt и просто вводим название утилиты (рис. 9.4):

    sn.exe
    (рис 9.4) Запуск sn.exe из командной строки Visual Studio.NET

    Далее мы будем использовать командную строку Visual Studio .NET. В любом случае появляется справка утилиты, которую затем снова можно вывести, набрав одну из команд:

    sn.exe - ?
    sn.exe –h

    Для создания закрытого ключа вводим команду (рис. 9.5):

    sn.exe – k "Путь к папке для сохранения ключа\Название ключа.Расширение"
    (рис 9.5) Ключ StrongKey.snk был записан в указанную директорию

    Вместо расширения key можно поставить любое другое. Расширением по умолчанию является .snk. После того как закрытый ключ создан, необходимо прикрепить его к приложению. В окне Solution Explorer проекта дважды щелкаем на файле AssemblyInfo.cs. Если Атрибут [assembly: AssemblyKeyFile("")] содержит путь к закрытому ключу, компилятор использует его для шифрования данных (рис. 9.6).

    (рис 9.6) Использование атрибута [assembly: AssemblyKeyFile("")] для прикрепления ключа к приложению

    Также с помощью атрибута [assembly] можно указать версию сборки, настройки культуры и другие параметры (рис. 9.7).

    (рис 9.7) Информация о сборке в атрибутах [assembly]

    Сборки, подписанные строгим именем, добавляются в проект так же, как и обычные сборки. Для этого в окне Solution Explorer щелкаем правой кнопкой мыши на папке References и в появившемся контекстном меню выбираем пункт Add Reference… . По умолчанию окно Add Reference открывается на вкладке .NET, в которой нажимаем на кнопку Browse и выбираем сборку. В листинг текущего приложения добавляем пространство имен, применяемое в сборке, используя ключевое слово using. После компиляции сборка будет добавлена в проект.

    Защита сборок. Утилита ilasm.exe

    Главное преимущество использования сборок, подписанных строгим именем, — защита их от декомпиляции. Запустим снова утилиту ildasm.exe и откроем приложение, выводящее на экран строку Hello World — SimpleApp. В меню "Файл" выбираем пункт Dump (или просто нажимаем Ctrl+D). В появившемся окне Dump options оставляем значения без изменений и нажимаем OK. Называем новый файл SimpleAppCrack.il и сохраняем его При этом мы сохранили содержимое нашего приложения в виде кода MSIL. Закрываем утилиту ildasm.exe.

    Открываем файл SimpleAppCrack.il с помощью блокнота и изменяем строку Hello World на Hello World Cracked (рис. 9.8).

    (рис 9.8) Изменение MSIL-кода

    Сохраняем файл и закрываем его. Теперь нам нужно преобразовать MSIL код в исполняемый exe-файл. Для этого воспользуемся еще одной утилитой — ilasm.exe. В командной строке Visual Studio .NET набираем название утилиты и путь к файлу с MSIL-кодом (рис. 9.9):

    ilasm.exe Путь к файлу\файл.il
    (рис 9.9) Использование утилиты ilasm.exe для преобразования кода MSIL в исполняемый exe-файл

    В папке с исходным файлом SimpleAppCrack.il появится файл SimpleAppCrack.EXE. Для просмотра его содержимого в командной строке указываем путь к нему и его название (рис. 9.10).

    (рис 9.10) Запуск измененного файла SimpleAppCrack.EXE

    Скопируйте всю папку с приложением SimpleApp и назовите его ProtectedSimpleApp. Откроем приложение и подпишем сборку строгим именем StrongKey.snk. Далее проделаем те же самые действия и попытаемся запустить измененный файл — появляется исключение System.IO.FileLoadExeption (рис. 9.11).

    (рис 9.11) Ошибка при попытке запустить измененную сборку, подписанную строгим именем

    На диске, прилагаемом к книге, вы найдете приложение ProtectedSimpleApp (Code\Glava9\ ProtectedSimpleApp).

    Утилита .NET Reflector. Как вскрывать защищенные сборки

    При использовании утилиты ildasm.exe бросается в глаза аскетичный дизайн приложения и неудобство работы с ней. Невозможность изменения размеров информационной панели сборки, расположенной внизу программы, открытие блоков кода в отдельных окнах, отображение только MSIL-кода наводит на мысль, что разработчики среды .NET сознательно оставили минимальную функциональность приложения для сведения общения с ним пользователей к минимуму. Программа .NET Reflector (версия 4.1.84.0) — единственный существующий браузер классов .NET-компонент, позволяющий просматривать метаданные, IL-инструкции и XML-документацию сборок, а также декомпилировать их, – гораздо более удобная утилита. Она имеет статус freeware, поэтому вы можете найти ее на диске, прилагаемом к книге, — Code\Glava9\ Reflector.zip, или скачать с сайта разработчика — http://www.aisto.com/roeder/dotnet. Рассмотрим, как просмотреть содержимое сборки, подписанной строгим именем, и использовать код в своих целях. Запустим программу, откроем пункт меню File\Open и выберем файл ProtectedSimpleAppCrack.EXE, который нам не удалось запустить (см. рис. 9.11). Выделив название сборки, на панели Disassembler увидим содержимое значение атрибутов [assembly] (если у вас не открыта панель Disassembler, выберите Tools/Disassembler) (рис. 9.12).

    (рис 9.12) Главное окно программы .NET Reflector, на панели Disassembler выведены значения атрибутов [assembly]

    Обратите внимание на параметр AssemblyKeyFile панели Disassembler — мы действительно работаем со сборкой, подписанной строгим именем! Каждый объект, отображаемый на панели, является ссылкой, щелкая на которую, мы переходим к соответствующему классу. Открыв окно Options — в пункте меню View\Options, можно выбрать язык отображения объектов, что является своеобразным переводчиком (рис. 9.13)!

    (рис 9.13) Выбор языка в окне Options

    Выбрав язык C# и перемещаясь по объектам любой сборки, можно копировать и вставлять код прямо в свой листинг (рис. 9.14).

    (рис 9.14) Представление кода сборки на языке C#

    Утилита не имеет возможности сохранять изменения в сборках (по крайней мере, описываемая версия), но в большинстве случаев вполне достаточно просмотреть и при необходимости скопировать весь код или фрагмент.

    Глобальный кэш сборок GAC (Global Assembly Cache). Утилита gacutil.exe

    Глобальный кэш сборок (Global Assembly Cashe, GAC) — это хранилище сборок, одновременно используемых несколькими приложениями. Такие сборки называются публичными. GAC может содержать в себе несколько сборок, отличающихся друг от друга только версией. На вашем компьютере GAC находится в каталоге C:\WINDOWS\assembly (рис. 9.15).

    (рис 9.15) Глобальный кэш сборок, GAC

    Все сборки, находящиеся в GAC, подписаны строгим именем — при установке сборки среда Common Language Runtime проверяет сборку на уникальность и сравнивает ее с другими, уже имеющимися сборками.

    Управлять глобальным хранилищем сборок можно несколькими способами. Первый способ — с помощью утилиты gacutil.exe, файл которой располагается в папке C\Program Files\Microsoft Visual Studio .NET 2003\SDK\v1.1\Bin\ gacutil.exe. Для работы с ней, как и большинством других утилит в командной строке Visual Studio.NET, следует ввести

    gacutil.exe

    При этом появляется описание команд утилиты (рис. 9.16), среди которых нас интересуют всего три:

    /i или –i: установка  сборки в GAC;
    /l или –l: вывод списка  установленных сборок;
    /u или –u: удаление сборки.
    (рис 9.16) Запуск утилиты в командной строке Visual Studio .NET

    Управление сборками при помощи утилиты gacutil.exe — не самый удобный способ. Более широкие возможности управления сборками предоставляет консоль MMC (Microsoft Management Console), для запуска которой в окне Выполнить (Run) набираем mmc (рис. 9.17).

    (рис 9.17) Запуск консоли MMC

    В появившемся окне выбираем в меню "Консоль\Добавить или удалить оснастку …" (рис. 9.18).

    (рис 9.18) Добавление оснастки

    Оснасткой называется основной тип инструментов, которые можно добавить на консоль. В данном случае оснасткой будет глобальный кэш сборок. В окне "Добавить\Удалить оснастку" нажимаем кнопку "Добавить" и в появившемся списке выбираем .NET Framework 1.1 Configuration (рис. 9.19).

    (рис 9.19) Добавление оснастки .NET Framework 1.1 Configuration

    В открывшемся окне можно управлять сборками — добавлять их или удалять (рис. 9.20).

    (рис 9.20) Удаление сборки

    Не удаляйте сборки, которые вам неизвестны, — вы можете нарушить работоспособность некоторых программ!

    Настройка политики выполнения сборок и контроля версий

    Консоль MMC предоставляет возможность настройки политики выполнения сборок и контроля версий. Рассмотрим практическое использование контроля версий сборок. Создайте новое консольное приложение и назовите его AssVersion. Полный листинг этого приложения:

    using System;
    namespace LibVersion
    {
      /// <summary>
      /// Класс для тестирования контроля версий сборок.
      /// </summary>
      public class MyClass
      {
        /// <summary>
        /// Метод, возвращающий текущую версию сборки.
        /// <summary>
        /// <returns></returns>
        public static string GetString()
        {
          return "Version 1";
        }
      }
    }

    В файле AssemblyInfo.cs изменяем значения атрибутов [assembly:]:

    // Жестко прописываем  версию сборки
    [assembly: AssemblyVersion("1.0.0.0")]
    [assembly: AssemblyDelaySign(false)]
    // Указываем закрытый ключ, созданный утилитой sn.exe
    [assembly: AssemblyKeyFile("C:\\StrongKey.snk")] 
    [assembly: AssemblyKeyName("")]

    При попытке скомпилировать приложение появляется ошибка — наше приложение не содержит точки входа:

    Program 'D:\Code\Glava9\AssVersion\obj\Debug\
    AssVersion.exe' does not have an entry point defined

    Мы удалили метод Main, поэтому возникает это исключение при попытке создания консольного приложения. Нам нужно скомпилировать проект как класс библиотеки, для этого в окне Solution Explorer щелкаем правой кнопкой на названии проекта AssVersion и в появившемся контекстном меню выбираем пункт Properties. Изменяем свойство Output Type на значение Class Library, закрываем окно свойств проекта и снова скомпилируем его.

    Добавим теперь созданную сборку в GAC. В консоли MMC щелкаем правой кнопкой мыши на названии Assembly Cache и выбираем пункт Add… (рис. 9.21).

    (рис 9.21) Добавление сборки в GAC из консоли MMC

    Переходим в папку bin/Debug и выбираем файл AssVersion.dll. В результате в списке сборок появляется добавленная сборка AssVersion.dll (рис. 9.22).

    (рис 9.22) Добавленная сборка AssVersion.dll в списке GAC

    Создадим теперь новое консольное приложение UsingMyClassFromGAC, которое будет ссылаться на эту сборку и использовать ее метод. В окне Solution Explorer щелкаем правой кнопкой мыши на папке References и в появившемся контекстном меню выбираем пункт Add Reference (рис. 9.23).

    (рис 9.23) Добавление ссылки к проекту

    В появившемся окне Add Reference нажимаем кнопку Browse и выбираем сборку AssVersion.dll из каталога AssVersion\bin\Debug\ AssVersion.dll. Подключаем пространство имен для использования этой сборки и вызываем ее метод:

    using System;
    //Подключаем пространство имен:
    using AssVersion;
    
    namespace UsingMyClassFromGAC
    {
      
      class Class1
      {
        
      
          [STAThread]
        static void Main(string[] args)
        {
          // Получаем строку с помощью метода GetString
          string stringFromMethod = MyClass.GetString();
          // Выводим строку на экран
          Console.WriteLine(stringFromMethod);
        }
    
      
      }
    }

    Компилируем приложение и затем запускаем его из командной строкиПри запуске приложения непосредственно из среды Visual Studio .NET происходит прямое обращение по ссылке к сборке, находящейся в своей папке, а при запуске через командную строку CLR проверяет наличие сборки в GAC. Visual Studio .NET (рис. 9.24).

    (рис 9.24) Результат запуска приложения UsingMyClassFromGAC из командной строки

    Изменим теперь сборку AssVersion — возвращаемое методом значение — на Version 2:

    public static string GetString()
      {
        return "Version 2";
    }

    Изменим файл AssemblyInfo.cs:

    // Жестко прописываем  новую версию сборки
    [assembly: AssemblyVersion("2.0.0.0")]

    Скомпилируем сборку и добавим ее в GAC. В результате в списке сборок появится две версии (рис. 9.25).

    (рис 9.25) Список сборок содержит две версии AssVersion — 1.0.0.0 и 2.0.0.0

    Снова запустим приложение UsingMyClassFromGAC из командной строки. Результат не изменился, по-прежнему выводится текст Version 1.

    Перейдем теперь к настройке управления версиями сборок. В консоли управления .NET Framework 1.1 открываем вкладку Configured Assemblies и выбираем задачу Configure an Assembly (рис. 9.26).

    (рис 9.26) Список задач на вкладке Configured Assemblies консоли управления .NET Framework 1.1

    В открывшемся окне конфигурирования сборки (рис. 9.27) переключатель стоит по умолчанию на значении Choose an Assembly from the assembly cache, нажимаем кнопку Choose Assembly для перехода к списку сборок.

    (рис 9.27) Окно конфигурирования сборок

    Далее появляется список сборок GAC. Прокручиваем список до конца, выбираем AssVersion версии 1.0.0.0 и нажимаем кнопку Select (рис. 9.28).

    (рис 9.28) Выбор сборки AssVersion версии 1.0.0.0 из списка сборок

    Далее нажимаем кнопку "Готово". В появившемся окне свойств сборки переключаемся на вкладку Binding Policy и в поле Requested Version вводим номер первой версии сборки (1.0.0.0), а в поле New Version — номер второй версии сборки (2.0.0.0) (рис. 9.29).

    (рис 9.29) Определение версий сборок

    Нажимаем кнопку OK, завершая конфигурирование сборки. В результате этих действий мы определили порядок версий сборок AssVersion, и теперь среда CLR при обращении в GAC будет извлекать более новую версию сборки. В командной строке Visual Studio .NET снова запустим приложение UsingMyClassFromGAC.exe, которое будет извлекать версию сборки 2.0.0.0 (рис. 9.30).

    (рис 9.30) После завершения конфигурирования сборки приложение UsingMyClassFromGAC.exe использует новую версию AssVersion 2.0.0.0

    На диске, прилагаемом к книге, вы найдете приложения AssVersion и UsingMyClassFromGAC (Code\Glava9\ AssVersion и UsingMyClassFromGAC).

    Управление политиками сборок

    В консоли MMC предусмотрены средства управления политиками версий сборок. В оснастке .NET Configuration 1.1 выбираем вкладку Confugured Assemblies и переходим по ссылке View List of Configured Assemblies. Открывается список сборок, для которых были определены политики. Выбирая нужную сборку и щелкая на ней правой кнопкой мыши, можно изменять свойства политики или удалить ее (рис. 9.31).

    (рис 9.31) Изменение свойств политики управления версиями сборки

    В этом же окне при щелчке правой кнопкой мыши на свободном поле и выборе пункта Add открывается окно конфигурирования сборки Configure an Assembly (рис. 9.27).

    Файлы конфигурации приложения

    Файлы конфигурации приложения — это XML-файлы, которые хранят индивидуальные настройки приложения, такие как строки подключения к базам данных Connection String, адреса удаленных компьютеров и т.д. При загрузке приложения CLR проверяет наличие файла конфигурации и в случае его нахождения считывает из него данные.

    Файлы конфигурации имеют расширение .config и располагаются в той же самой папке, что и файл приложения. Название файлов конфигурации формируется от имени приложения — файл NameApplication.exe.config принадлежит приложению NameApplication.exe.

    Файлы конфигурации, поскольку они являются документами XML, содержат иерархическую структуру. Главным элементом иерархии является элемент <configuration>. Из-за того, что файл конфигурации представляет собой "правильный" XML-файл, все его элементы чувствительны к регистру символов. В таблице 9.1 представлены некоторые элементы и их атрибуты, которые могут находиться в файле конфигурации.

    Элементы и атрибуты XML-файлов конфигурации
    ЭлементОписание элементаАтрибутОписание атрибутаОбязательно ли наличие атрибута
    <configuration> Корневой элемент файла конфигурации. Вся находящаяся в нем информация считывается средой CLR при запуске приложения
    <runtime> Вложенный элемент configuration, содержит информацию о подключаемых сборках в процессе выполнения
    <assemblyBinding> Вложенный элемент runtime, содержит информацию о версиях подключаемых сборок и их расположении
    <dependedAssembly> Вложенный элемент assemblyBinding, содержит информацию о каждой из подключаемых сборок
    <assemblyIdentity> Вложенный элемент dependedAssembly, содержащий частное имя сборки, культуру, открытый ключ Name Частное имя сборки Да
    publicKeyToken Открытый ключ сборки, если она подписана строгим именем Нет
    Culture Культура, указанная в сборке Нет
    <bindingRedirect> Вложенный элемент dependedAssembly, содержит информацию об изменении версии сборки oldVersion Старая версия сборки, которую нужно заменить Да
    newVersion Новая версия сборки, на которую нужно заменить старую Да
    <codeBase> Вложенный элемент dependedAssembly, содержит путь до сборки со строгим именем Version Версия сборки Да
    Href Адрес подключаемой сборки Да
    <probing> Указывает вложенные папки, в которых могут находиться подключаемые сборки privatePath Содержит названия каталогов, в которых могут находиться подключаемые сборки. Все указанные каталоги должны быть вложенными Да
    <publisherPolicy> Указывает, использовать ли настройки издателя. Если этот элемент расположен в элементе dependedAssembly, то политика распространяется только на указанную сборку, в противном случае политика распространяется на все указанные в файле конфигурации сборки Apply Указывает, применять ли политику издателя к сборкам. Возможные значения — yes и no Да

    Выше мы использовали политику управления версиями сборок для указания применения в приложении более новой версии сборки. Сделаем то же самое, используя файл конфигурации.

    Скопируйте приложение AssVersion и назовите его AssVersionOne. Изменим строку, возвращаемую методом, на Version One:

    using System;
    
    namespace AssVersion
    {
      public class MyClass
      {
        
        public static string GetString()
        {
          return "Version One";
        }
      
    }
    
    }

    Устанавливаем следующие значения атрибутов файла AssemblyInfo.cs:

    [assembly: AssemblyVersion("1.0.0.0")]
    [assembly: AssemblyKeyFile("C:\\StrongKey.snk")]

    Компилируем сборку, закрываем проект, копируем всю его папку и называем ее AssVersionTwo. Снова меняем значение возвращаемой строки и значения атрибутов в AssemblyInfo.cs:

    using System;
    
    namespace AssVersion
    {
      
      public class MyClass
      {
        public static string GetString()
        {
          return "Version Two";
        }
      
    }
    
    [assembly: AssemblyVersion("2.0.0.0")]

    Компилируем это приложение и добавляем обе сборки в GAC при помощи консоли MMC, предварительно удалив из списка сборки, использованные нами в прошлом примере. Не забудьте также удалить политику управления версиями сборок! Теперь займемся приложением, которое будет использовать эти сборки. Скопируйте папку проекта UsingMyClassFromGAC и назовите ее UsingAssemblyConfig. Открываем проект, в окне Solution Explorer удаляем ссылку на сборку AssVersion и добавляем новую ссылку на сборку из проекта AssVersionOne. Запускаем проект из командной строки Visual Studio .NET (рис. 9.32).

    (рис 9.32) Результат запуска приложения UsingAssemblyConfig

    Приложение возвращает текстовую строку из первой сборки — Version One. Добавим теперь файл конфигурации приложения — щелкаем правой кнопкой мыши в окне Solution Explorer и в меню выбираем Add\Add New Item… . В появившемся окне прокручиваем список шаблонов до самого конца и выбираем шаблон Application configuration file, и не изменяя его названияПри этом мы добавляем рабочий файл конфигурации — в папке проекта появится файл App.config. Псоле компиляции проекта в папке bin\Debug появится файл конфигурации UsingMyClassFromGAC.exe.config, который будет использоваться в приложении. — App.config — нажимаем OK. Я привожу его содержимое для сборки, подписанной ключом StrongKey.snk:

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <runtime>
        <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
          <dependentAssembly>
            <assemblyIdentity name="AssVersion" publicKeyToken="b19037b107de741b"  
             culture="neutral" />
            <bindingRedirect oldVersion="1.0.0.0" newVersion="2.0.0.0" />  
          </dependentAssembly>
        </assemblyBinding>
      </runtime>
    </configuration>

    В этом коде мы указываем имя сборки — Ass Version, открытый ключ для приложения (publicKeyToken) — b19037b107de741b и культуру сборки — neutral. Если до этого момента вы воспроизводили все действия самостоятельно, то открытый ключ будет другим. Для просмотра сведений о сборке и открытого ключа, в частности, в консоли MMC, щелкните правой кнопкой на выбранной сборке, выберите ее свойства и в появившемся окне скопируйте значение publicKeyToken (рис. 9.33).

    (рис 9.33) Открытый ключ приложения publicKeyToken в окне свойств сборки

    Компилируем приложение и запускаем его в командной строке. Результатом выполнения программы будет текст VersionTwo (рис. 9.34).

    (рис 9.34) Результат запуска приложения с конфигурационным файлом

    Мы не указывали ссылку на сборку новой версии — среда CLR при запуске приложения считала данные о версиях сборок из файла конфигурации, нашла новую версию в GAC и вывела его содержимое в приложение. Этот прием используется для обновления программ через Интернет: пользователь скачивает пакет обновлений, содержащий одну или несколько новых сборок, которые установочный пакет помещает в GAC. В конфигурационном файле приложения заранее заданы названия новых версий сборок — и тогда среда CLR запускает обновленную версию программы без перезагрузки операционной системы. Если сборка не была помещена в GAC, то в конфигурационном файле следует указать путь к новой версии сборки при помощи тега <codeBase>.

    На диске, прилагаемом к книге, вы найдете приложения AssVersionOne, AssVersionTwo и UsingAssemblyConfig (Code\Glava9\AssVersionOne, AssVersionTwo, UsingAssemblyConfig).

    Создание пакетов установки

    Установка программы представляет собой копирование сборок и файлов, необходимых для работы приложения, в определенную папку на компьютере пользователя. При этом также происходит интеграция приложения в операционную систему Windows — добавление иконок на рабочий стол, в меню "Пуск", в контекстное меню правой кнопки мыши. Для слежения за лицензионным использованием программы или сохранением пользовательских настроек приложения следует предусмотреть возможность автоматического внесения изменений в реестр при установке. Если размер программы достаточно велик, файлы подлежат также архивации, и тогда установка программы сопровождается ее извлечением из архива. Первое знакомство пользователя с вашим приложением начинается именно с установки, и поэтому даже если сама программа очень хорошая, но ее трудно устанавливать, большинство пользователей откажутся от ее использования. Установка приложения должна отвечать следующим критериям:

  • Запуск программы установки происходит один раз.
  • Программа установки имеет название Setup.exe или Install.exe, и ее легко найти среди файлов установки.
  • Если программа распространяется на CD, то вставка диска в привод приводит к автоматическому запуску установки либо к появлению заставки, на которой при переходе по гиперссылке начинается установка.
  • Каждый шаг установки предполагает оптимальный вариант по умолчанию.
  • Информация, показанная при установке, необходима и достаточна, и обращение к файлу Readme не является обязательным.
  • Одна программа установки работает на всех поддерживаемых приложением версиях операционной системы.
  • Практически все крупные пакеты, такие как Microsoft Office или Adobe Photoshop, отвечают этим требованиям.

    Распространение приложений, написанных на языке C#, одном из языков платформы .NET, обладает важной особенностью: для работы программы необходимо наличие установленной в операционной системе библиотеки .NET Framework. Достаточно однократного включения в пакет установки этой библиотеки для последующей установки самих приложений платформы .NET в чистом виде, т. е. только файлов, созданных непосредственно вами. Проблема в том, что размер библиотеки .NET Framework и дополнительных утилит может достигать 50-70 Мб, что является одной из причин затруднительного распространения приложений через Интернет. На сегодняшний день .NET Framework 1.1 встроен только в операционную систему Windows 2003 Server family. Однако через несколько лет, с выходом и массовым распространением Windows Longhorn можно ожидать частичного решения этой проблемы — новая версия операционной системы будет содержать в себе библиотеку .NET Framework.

    Существует несколько способов переноса готового приложения на компьютер пользователя.

    Так называемая установка XCOPY – это простое копирование папки с приложением. Программа будет работать, если на компьютере установлен .NET Framework и ключи реестра не используются. Приложение может содержать только частные и подписанные строгим именем сборки. При подобной установке не происходит автоматической генерации иконок на рабочем столе или меню "Пуск". Для удаления приложения достаточно просто удалить его папку. Этот способ установки неприменим для распространения коммерческих приложений.

    Среда Visual Studio .NET предоставляет возможность создания пакетов дистрибутивов, позволяющих пользователю с минимумом усилий устанавливать приложение на свой компьютер. Получаемый в результате файл Windows Installer 2.0 позволяет установить, изменить или удалить приложение с компьютера пользователя. С помощью Windows Installer можно также управлять глобальным КЭШем сборок.

    Для распространения одной сборки используются файлы-кабинеты (.cab – files.). Cab-файл должен иметь то же самое имя, что и сборка, находящаяся в нем. Например, если cab-файл содержит сборку Assembly.dll, то он должен называться Assembly.cab. После того как вы создадите cab-файл, его можно будет загрузить используемым приложением, указав его адрес в теге codeBase файла конфигурации.

    Итак, существует три вида распространения сборок и приложений. С установкой XCOPY вы сталкивались при использовании готовых приложений с диска, прилагаемого к книге, — копировали их на свой компьютер и запускали exe-файл из папки bin\Debug. Распространение одной сборки — задача, встречаемая при создании патчей (дополнений) к программам и технически выполняемая достаточно просто. Наибольший интерес представляет создание полных пакетов установки, к рассмотрению которого мы и приступим.

    Создание простого пакета установки без библиотеки .NET Framework

    В качестве исходного приложения для распространения возьмем проект NotepadCSharp, c которым мы работали во второй лекции. На панели инструментов Standard среды Visual Studio .NET расположен список Solution Configurations, значения которого определяют режим компиляции приложения (рис. 9.35).

    (рис 9.35) Панель инструментов Standard и режим компиляции Debug

    Это режим компиляции, принятый по умолчанию, при его запуске появляется папка bin\Debug, которая содержит, кроме готового exe-файла, отладочную информацию. Приложение, подлежащее распространению, должно состоять только из рабочих файлов, поэтому в списке Solution Configurations выбираем режим Release и снова компилируем приложение. При этом в проекте появится папка bin\Release с готовым приложением.

    Пакеты установки можно создавать непосредственно в текущем проекте приложения, но мы сделаем отдельный пакет. Создайте папку и назовите ее NotepadCSharpSetup. Теперь запустите Visual Studio.NET и создайте новый проект в папке NotepadCSharpSetup, тип проекта Setup and Deployment Projects, шаблон — Setup Project, название — NotepadCSharpSetup (рис. 9.36).

    (рис 9.36) Создание проекта установки

    В окне Solution Explorer щелкаем на названии проекта — NotepadCSharp и затем переходим в окно его свойств, щелкая на вкладку Properties (или нажав клавишу F4) — именно так, а не по щелчку в пункте Properties контекстного меню! Дело в том, что в контекстном меню содержатся свойства самого проекта (рис. 9.37), а в окне Properties — свойства пакета установки (рис. 9.38), которые нам и нужно настроить.

    (рис 9.38) Свойства проекта установки(рис 9.37) Свойства пакета установки

    В свойствах самого проекта можно указать название выходного файла (Output file name), тип сжатия (Compression) — та самая архивация, которой подвергают все большие программы и даже цифровую подпись (Authenticode signature). В свойствах пакета установки следует указать имя автора и производителя, сайт продукта и его поддержки, телефоны, — примерный вариант заполнения этих свойств указан на рис. 9.38.

    Добавим файл NotepadCSharp.exe, который нам предстоит упаковать. Щелкаем правой кнопкой на папке Application Folder и выбираем пункт Add/File (рис. 9.39).

    (рис 9.39) Добавления файла приложения в проект установки

    Переходим в папку bin/Release и выбираем файл NotepadCSharp.exe. Добавим ярлыки приложения в пакет — они будут появляться при установке программы на Рабочем столе и в меню "Пуск". Щелкаем правой кнопкой на имени добавленной сборки и выбираем пункт Create Shortcut to Notepad CSharp.exe. Создадим два ярлыка и переименуем их (рис. 9.40).

    (рис 9.40) Добавление ярлыков к приложению

    Теперь "хватаем" мышью по очереди эти ярлыки и помещаем их в папки User's Desktop и User's Programs Menu (рис. 9.41).

    (рис 9.41) Перемещение ярлыков в папки User's Desktop и User's Programs Menu

    Переходим в папку User’s Desktop и, выделив ярлык, открываем окно его свойств. В поле свойства Icon щелкаем на значение Browse из выпадающего списка, в появившемся окне снова щелкаем на кнопку Browse. В окне Select Item in Project в выпадающем списке "Look in:" выбираем значение Application Folder и щелкаем на ставшую доступной кнопку Add File… . Иконка приложения расположена в каталоге NotepadCSharp\Icon\README.ICO, выбираем ее и закрываем окна Select Item in Project и Icon. Проделываем то же самое для изображения иконки папки User's Programs Menu.

    В процессе установки будет появляться несколько диалоговых окон, созданных по шаблону. Изменим немного интерфейс этих окон и текст на них. Для этого щелкаем в окне Solution Explorer на кнопке User Interface Editor (рис. 9.42).

    (рис 9.42) Кнопка User Interface Editor и деревья диалоговых окон

    Появляется два дерева диалоговых окон, мы будем редактировать формы дерева Install. Выделяем форму Welcome и переходим к его свойствам. Свойство BannerBitmap позволяет добавлять баннер размером 497х69 пикселей на диалоговое окно. В поле значения этого свойства выбираем Browse — и перед нами появляется уже знакомое окно Select Item in Project, добавляем в это окно баннер Bannersetup.bmp из папки NotepadCSharp\Icon. Переходим к надписям, которые будут располагаться на форме. В свойстве CopyrightWarning приводится текст предупреждения об авторских правах, оставим его без изменений — вы можете изменить его в своем проекте. В свойстве WelcomeText заменяем слова [ProductName] на NotepadC#. Текст надписей оставим на английском языке – кириллица отображается некорректно. В свойствах BannerBitmap следующих форм InstallationFolder, Confirm Installation и Progress также устанавливаем баннер Bannersetup.bmp. В последней форме изменяем текст свойства UpdateText на Thank you for your choice! и снова устанавливаем баннер. Устанавливаем режим Release и компилируем проект. Переходим в папку NotepadCSharpSetup\NotepadCSharp\Release и запускаем файл установки Setup.Exe (рис. 9.43).

    (рис 9.43) Форма Welcome пакета установки

    После выполнения всех шагов мастера программа устанавливается и становится доступной с рабочего стола (рис. 9.44), из меню "Пуск" (рис. 9.45) и рабочей папки приложения (рис. 9.46).

    (рис 9.45) Иконка приложения на Рабочем столе(рис 9.44) Иконка в меню пуск(рис 9.46) Иконка в рабочей папке

    Удалить программу можно с помощью стандартной утилиты "Установка и удаления программ" операционной системы Windows.

    На диске, прилагаемом к книге, вы найдете проект установки (Сode\Glava9\NotepadCSharpSetup\NotepadCSharp\NotepadCSharp.sln).

    Изменение каталога установки

    По умолчанию, программа устанавливается в каталог [ProgramFiles][Производитель (NotepadSoft)]\[ProductName (NotepadCSharp)] (см. рис. 9.46). Для изменения пути в проекте установки щелкаем правой кнопкой на папке Application Folder и меняем свойство DefaultLocation (рис. 9.47).

    (рис 9.47) Изменения каталога установки

    Добавление ключей реестра на компьютер пользователя

    Для добавления ключей реестра на компьютер пользователя при установке приложения их следует включить в пакет установки. В окне Solution Explorer нажимаем на кнопку Registry Editor (рис. 9.48).

    (рис 9.48) Добавление ключей реестра

    В появившемся окне Registry выбираем нужную ветвь реестра и создаем нужный параметр (рис. 9.49).

    (рис 9.49) Добавление ключа в выбранный раздел реестра

    При установке приложения созданный ключ будет добавлен в реестр компьютера пользователя.

    Добавление публичных сборок в GAC

    При создании нового проекта установки папка Global Assembly Cache скрыта по умолчанию. Для отображения этой папки в окне File System щелкаем правой кнопкой мыши на File System on Target Machine и выбираем Add Special Folder\Global Assembly Cache Folder. На появившейся папке снова щелкаем правой кнопкой и выбираем один из трех вариантов — конечный результат указанного проекта, файл или сборку из GAC данного компьютера (рис. 9.50).

    (рис 9.50) Выбор источника сборки

    При выборе сборки из GAC (Assembly) появляется список сборок, из которого следует выбрать нужные (рис. 9.51).

    (рис 9.51) Добавление сборки из GAC данного компьютера

    При установке программы выбранные сборки автоматически будут добавлены в GAC на компьютере пользователя.

    Добавление библиотеки .NET Framework

    Скорее всего, на компьютере пользователя не будет библиотеки .NET Framework, необходимой для работы приложения, которое написано на C#. Пакет установки .NET Framework — размеромРазмер может варьировать в зависимости от версии библиотеки и количества включенных в него компоненттов. Я имею в виду версию .NET Framework 1.1. около 23 Мб, называется dotnetfx.exe. В проекте в список зависимостей проекта автоматически включается файл dotnetfxredist_x86_enu.msm, который по умолчанию отмечен как исключенный (excluded) из результирующего пакета установки (рис. 9.52).

    (рис 9.52) В список зависимостей проекта установки входит файл библиотеки

    Однако при снятии галочки Exclude и попытке включения библиотеки в пакет установки возникает ошибка:

    dotNETFXRedist_x86_enu.msm must not be used to redistribute the .NET Framework.  
    Please exclude this merge module.

    Скорее всего, вначале предполагалось включать таким образом .NET Framework в состав инсталляций Но сейчас этот merge module используется только с одной целью: он предотвращает автоматическое включение в проект некоторых DLL, входящих в CLR.

    Итак, сейчас .NET Framework не может быть объединен с пакетом установки вашей программы непосредственно в среде Visual Studio .NET. Однако существует несколько способов включения библиотеки в состав дистрибутива.

    При компиляции пакета установки в папке Release проекта создается три файла – NameApplication.msi, Setup.exe и Setup.ini. NameApplication.msi — это основной файл Windows Installer 2.0, содержащий все необходимые для установки приложения файлы. Setup.exe — программа, предназначенная для запуска файла .msi. С помощью этого файла устанавливается дополнительное программное обеспечение, необходимое приложению. И, наконец, Setup.ini — это конфигурационный файл приложения Setup.exe.

    Установка приложения не начнется, пока Windows Installer не определитДля получения информации об установленных версиях .NET Framework используем реестр HKEY_LOCAL_MACHINE\Software\Microsoft\.NETFramework, ключ InstallRoot — директория, куда устанавливается .NET Framework — обычно это C:\WINDOWS\Microsoft.NET\Framework. Если такого каталога на диске нет, то .NET Framework не установлен. HKEY_LOCAL_MACHINE\Software\Microsoft\.NETFramework\Policy ключи вида \vX.X содержат информацию об установленных версиях .NET Framework на компьютере пользователя установленный .NET Framework. Этот порядок можно изменить с помощью утилиты bootstrapper.exe, заменяющей существующий setup.exe на новый, который позволяет устанавливать .NET Framework на компьютер пользователя. Свойству Bootstrap проекта установки устанавливаем значение None (см. рис. 9.37) — в результате при компиляции создастся только файл .msi. Теперь извлекаем из архива утилиту bootstrapper.exe в папку Release c файлом .msi. Также в эту папку помещаем пакет установки .NET Framework — dotnetfx.exe. В результате в папке будет четыре файла — .msi, setup.exe, setup.ini и dotnetfx.exe. Открываем файл setup.ini и меняем его содержимое следующим образом:

  • "Msi=FxCopSourceSetup.msi" изменяем на Msi=ВашMSIФайл.msi;
  • удаляем комментарий со строки 'FxInstallerPath=c: (нужно удалить символ ') и изменяем на расположение файла dotnetfx.exe. Например, если dotnetfx.exe расположен в том же каталоге, что и setup.exe, то вместо адреса нужно написать FxInstallerPath=.
  • После завершения этих действий пакет установки будет готов. Если Windows Installer обнаружит предыдущую версию .NET Framework или не обнаружит ее вообще на машине пользователя, то он ее обновит или установит.

    На диске, прилагаемом к книге, вы найдете архив утилиты bootstrapper.exe (Code\Glava9\ bootstrapper.exe).

    Я не привожу утилиту dotnetfx.exe из-за ее значительного размера, ее новую версию можно найти на официальном сайте MicrosoftЯ также не привожу ссылок — версии утилит быстро меняются и ссылки устаревают, воспользуйтесь поиском на сайте Microsoft..

    Другие библиотеки для работы приложения — MDAC, Jet и Crystal Reports

    К сожалению, библиотека .NET Framework представляет не исчерпывающий набор компонент для работы приложения. Если приложение использует доступ к базе данных (используется пространство имен System.Data), потребуется также установка Microsoft Data Access Components (MDAC). MDAC распространяется в виде файла установки mdac_typ.exe. Для работы отчетов Crystal Reports (CR) на машине клиента должен быть установлен Crystal Reports Free Runtime — набор библиотек и лицензия. Компоненты, так же как и сама библиотека .NET Framework, периодически обновляются, актуальные версии доступны на сайте Microsoft.

    Изменение пользовательского интерфейса установочного пакета

    При создании пакета установки для приложения NotepadC# мы изменяли пользовательский интерфейс форм, предложенных мастером. Среда Visual Studio .NET позволяет также добавлять отдельные формы в диалог установки. Добавим в этот пакет форму с лицензионным соглашением.

    Открываем проект NotepadCSharp и снова переходим на вкладку User Interface Editor, щелкнув на одноименной вкладке в окне Solution Explorer. Щелкаем правой кнопкой мыши на группе Start ветви Install и выбираем пункт меню Add Dialog. В появившемся окне шаблонов выделяем форму License Agreement и нажимаем ОК (рис. 9.53).

    (рис 9.53) Форма License Agreement

    Теоретически можно добавить любое диалоговое окно в любой раздел проекта установки, но добавление диалогового окна Finish в раздел Start приведет к ошибке компиляции. Лицензионное соглашение обычно появляется сразу после окна приветствия — управлять расположением формы можно, просто перетаскивая ее или используя контекстное меню (рис. 9.54).

    (рис 9.54) Расположение формы в списке

    В свойстве LicenseFile из выпадающего списка выбираем Browse и добавляем файл license.rtf из каталога Code\Glava9\NotepadCSharpSetup\ license.rtf. В этом файле содержится фрагмент стандартного определения прав между производителем и конечным пользователем. Добавим также баннер Bannersetup.bmp, который мы использовали также для оформления других форм. Компилируем проект. Теперь при установке программы появляется окно с лицензионным соглашением (рис. 9.55).

    (рис 9.55) Диалоговое окно с лицензионным соглашением. Попробуйте добавить файл лицензионного соглашения на русском языке

    Использование данных, получаемых при установке

    При установке некоторых программ требуется определять не только каталог установки, но и другие параметры, необходимые для работы приложения. Рассмотрим использование данных пользователя для пакета, устанавливающего базу данныхДля этого примера вам потребуется установленная СУБД SQL Server . Создайте новую библиотеку (тип проекта — Visual C# Projects, шаблон — Class Library) и назовите ее InstallerClass. В окне Solution Explorer щелкаем правой кнопкой на названии проекта и выбираем пункт меню Add New Item. В появившемся окне выбираем шаблон Installer Class и называем его CustomActionDB (рис. 9.56).

    (рис 9.56) Добавление шаблона Installer Class

    Удаляем из проекта Class1.cs. В окне Server Explorer на заголовке Data Connection щелкаем правой кнопкой мыши и выбираем пункт Add Connection. В открывшемся окне на вкладке "Подключение" выбираем или вводим название SQL-сервера (для подключения к локальному серверу вводим "(local)"), выбираем для входа в сеть учетные сведения Windows NT, а в выпадающем списке названий баз данных выбираем или вводим master. Завершив настройку соединения, проверяем подключение и нажимаем OK. В окне Solution Explorer щелкаем правой кнопкой на классе CustomActionDB и выбираем View Designer. Из окна Toolbox добавляем объект SqlConnection и в свойстве ConnectionString указываем только что созданное подключение. В окне Solution Explorer щелкаем правой кнопкой на названии проекта и добавляем к нему TextFile, который называем sqlScript.txt (рис. 9.57).

    (рис 9.57) Добавленный текстовый файл sqlScript.txt

    В этом текстовом файле вводим SQL-запрос на создание таблицы:

    CREATE TABLE [dbo].[Employees] (
    [Name] [char] (30) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
    [Rsvp] [int] NULL ,
    [Requests] [nvarchar] (4000) COLLATE SQL_Latin1_General_CP1_CI_AS NULL 
    ) ON [PRIMARY];
    
    ALTER TABLE [dbo].[Employees] WITH NOCHECK ADD 
    CONSTRAINT [PK_Employees] PRIMARY KEY CLUSTERED 
    (
    [Name]
    ) ON [PRIMARY];

    В окне Properties файла sqlScript.txt устанавливаем значение свойства Build Action на Embedded Resource (рис. 9.58):

    (рис 9.58) Свойство Build Action для файла sqlScript.txt

    Добавляем в класс CustomActionDB код, считывающий текстовый файл:

    /// <summary>
        /// Считывание  текста из файла.
        /// </summary>
        /// <param name="name">Название файла.</param>
        /// <returns></returns>
        private string GetSql(string name)
        {
          try
          {
            // Получаем текущий объект класса Assembly
            System.Reflection.Assembly asm = System.Reflection.Assembly.GetExecutingAssembly();
            // Получаем объект класса Stream к ресурсам текущей сборки.
            System.IO.Stream str = asm.GetManifestResourceStream(asm.GetName().Name + "." + name);
            // Считываем и возвращаем содержимое.
            System.IO.StreamReader reader = new System.IO.StreamReader(str);
            return reader.ReadToEnd();
          }
          catch(Exception ex)
          {
            // Отлавливаем возникшие исключения.
            System.Windows.Forms.MessageBox.Show("В методе GetSql возникла ошибка: "+ex.Message);
            throw ex;
          }    
        }
        /// <summary>
        /// Выполнение SQL-запроса.
        /// </summary>
        /// <param name="databaseName">Название базы данных.</param>
        /// <param name="sql">Текст команды.</param>
        private void ExecuteSql(string databaseName, string sql)
        {
          // Создаем объект класса SqlCommand.
          System.Data.SqlClient.SqlCommand comm = new System.Data.SqlClient.SqlCommand(sql, sqlConnection1);
          // Открываем соединение.
          comm.Connection.Open();
          // Изменяем используемую базу данных.
          comm.Connection.ChangeDatabase(databaseName);
          try
          {
            // Выполняем команду.
            comm.ExecuteNonQuery();
          }
          finally
          {
            // Закрываем соединение.
            comm.Connection.Close();
          }
        }
        /// <summary>
        /// Создание таблицы в базе данных.
        /// </summary>
        /// <param name="databaseName">Название базы данных.</param>
        protected void AddDBTable(string databaseName)
        {      
          try
          {
            // Создаем новую базу данных.
            this.ExecuteSql("master", "CREATE DATABASE " + databaseName);
            // Создаем таблицу в новой базе данных.
            this.ExecuteSql(databaseName, this.GetSql("sqlScript.txt"));
          }
          catch(Exception ex)
          {
            System.Windows.Forms.MessageBox.Show("В методе AddDBTable возникла ошибка: "+ex.Message);
          }
        }
        /// <summary>
        /// Перегружаем метод Install
        /// </summary>
        /// <param name="stateSaver">Параметр по умолчанию.</param>
        public override void Install(IDictionary stateSaver)
        {    
          base.Install (stateSaver);
          // В качестве названия БД передаем введенное значение пользователем.
          this.AddDBTable(this.Context.Parameters["dbname"]);
        }

    Компилируем библиотеку. При этом возникает исключение — класс библиотеки не содержит ссылки на пространство имен Windows:

    The type or namespace name 'Windows' does not exist in the class or namespace
     'System' (are you missing an assembly reference?)

    Для добавления ссылки на это пространство имен щелкаем правой кнопкой мыши на папке References в окне Solution Explorer и выбираем пункт Add References…(рис.рис. 9.59).

    (рис 9.59) Добавление ссылки на пространство имен

    В появившемся списке выбираем пространство имен System.Windows.Forms и добавляем его. Снова компилируем приложение. В окне Solution Explorer щелкаем правой кнопкой на заголовке Solution ‘Installer Class’(1 project) и выбираем Add\New Project. В появившемся окне добавляем проект установки (тип проекта — Setup And Deployment Projects, шаблон – Setup Project) и называем его CustomActionSetup.

    Открываем меню изменения пользовательского интерфейса. Добавьте в раздел Start новое диалоговое окно Textboxes (A) и нажмите ОК (рис. 9.60).

    (рис 9.60) Добавление диалогового окна

    Размещаем добавленное окно под диалоговым окном Installation Folder (рис. 9.61).

    (рис 9.61) Расположение добавленного окна

    Устанавливаем следующие свойства окна:

    Banner Text Add the data base name Укажите имя базы данных.
    Body Text We need this data to create the Data base, that used by our program Эти данные необходимы для создания новой базы данных приложения на вашем сервере баз данных
    Edit1Label Data Base Name Название базы данных
    Edit1Property CUSTOMTEXTA1 Текст, вводимый пользователем

    Свойствам Edit2Visible, Edit3Visible и Edit4Visible устанавливаем значение false.

    В окне Solution Explorer нажимаем на кнопку Custom Actions Editor. В открывшемся окне выделяем папку Install и в контекстном меню выбираем Add Custom Action (рис. 9.62):

    (рис 9.62) Добавление Custom Action

    В окне Select Item in Project в папке Application Folder нажимаем на кнопку Add Output. В Add Project output Group выбираем элемент Primary output и нажимаем OK (рис. 9.63).

    (рис 9.63) Выбор Custom Action

    Свойству CustomActionData созданного элемента Primary Output from InstallerClass (Active) устанавливаем значение /dbname=[CUSTOMTEXTA1] (рис. 9.64).

    (рис 9.64) Изменение свойств CustomActionData

    В результате у нас получилось приложение, состоящее из двух проектов. В окне Solution Explorer щелкаем правой кнопкой на названии проекта InstallerClass и выбираем пункт меню Build. Проделываем то же самое для проекта CustomActionSetup. В папке CustomActionSetup\Release появились файлы установки, запускаем Setup.exe. В процессе установки появляется окно для введения названия новой базы данных (рис. 9.65).

    (рис 9.65) Определение названия создаваемой базы данных

    После установки приложения появится новая база данных SQL — в этом можно будет убедиться, запустив программу Enterprise Manager из группы Microsoft SQL Server в меню "Пуск". В рассмотренном примере использовалась локальная база данных — для установки БД на компьютере пользователя необходимо указать сервер базы данных с помощью пользовательского интерфейса проекта.

    На диске, прилагаемом к книге, вы найдете проекты InstallerClass и CustomActionSetup (Code\Glava9\ InstallerClass и CustomActionSetup).

    Создание автозагрузочного диска

    Если программа распространяется на компакт-диске, лучше всего сделать этот диск автозагрузочным — при его вставке в лоток автоматически запустится программа установки. Для этого в файле autorun.inf, получаемом из обычного текстового файла, указываем иконку autorun.ico и файл setup.exe для запуска (рис. 9.66).

    (рис 9.66) Содержимое автозагрузочного диска

    Для предоставления пользователю выбора программ из списка можно сделать html-страницу, с которой будут даваться гиперссылки на файлы установки setup.exe. программ. При размещении файла index.htm и иконки autorun.ico в корневом каталоге диска содержимое autorun.inf примет слендующий вид:

    [autorun]
    OPEN=explorer.exe index.htm
    ICON=AUTORUN.ICO

    На диске, прилагаемом к книге, вы найдете папку AUTORUN со всем содержимым для автоматического запуска программы установки (Code\Glava9\ AUTORUN).

    Вернуться к учебному плану