Опубликован: 05.08.2010 | Доступ: свободный | Студентов: 2009 / 47 | Оценка: 4.50 / 4.40 | Длительность: 60:26:00
Лекция 5:

Работа с файлами и каталогами

Упражнение 4. Получение метаданных из сборок

Иногда может возникнуть необходимость получить дополнительную информацию о файле, включающую в себя авторские права, номер версии, наименование компании-производителя, информацию о торговой марке и т.д. Эта информация вшивается в сборку при компиляции EXE - или DLL -файлов (если укажем). Данные отображаются в диалоговом окне свойств, вызванном в Windows Explorer при выделении исполнимого файла правой кнопкой мыши и выбора опции Свойства, например


Информация о сборке на этапе проектирования размещается в файле AssemblyInfo.cs, который автоматически создается оболочкой в новом проекте в каталоге Properties. Метаданные можно редактировать через этот файл. Такая необходимость чаще всего возникает в том случае, если программа (сборка или библиотека) делается для продажи или передачи другим людям.


  • Добавьте к решению командой File/Add/New Project новый проект консольного приложения с именем App4 и назначьте его стартовым
  • В панели Solution Explorer откройте на редактирование файл AssemblyInfo.cs и ознакомьтесь с его содержимым, автоматически сгенерированным оболочкой
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
    
// General Information about an assembly is controlled through the following 
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("App4")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("App4")]
[assembly: AssemblyCopyright("Copyright ©  2010")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
    
// Setting ComVisible to false makes the types in this assembly not visible 
// to COM components.  If you need to access a type in this assembly from 
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
    
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("749a9e12-8b91-41d5-942a-e174fe60800f")]
    
// Version information for an assembly consists of the following four values:
//
//      Major Version
//      Minor Version 
//      Build Number
//      Revision
//
// You can specify all the values or you can default the Build and Revision Numbers 
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

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

  • Выполните команду Project/App4 Properties меню оболочки и выделите вкладку Application страницы свойств проекта
  • Щелкните на кнопке Assembly Information, чтобы вызвать диалоговое окно редактирования метаданных сборки с текстовыми полями:
    • Title - название
    • Description - описание
    • Company - производитель
    • Product - наименование продукта
    • Copyright - авторское право
    • Trademark - торговая марка
    • Assembly Version - версия сборки
    • File Version - версия файла
    • Neutral Language - язык по умолчанию
  • Заполните диалоговое окно свойств как показано на рисунке

  • Вновь откройте файл AssemblyInfo.cs и убедитесь, что его содержимое изменилось

Извлечь информацию из сборки можно программно. Для этого предназначен класс System.Diagnostics. FileVersionInfo. Продемонстрируем его использование на примере.

  • Заполните файл Program.cs приложения App4 следующим кодом
using System;
using System.Collections.Generic;
using System.Text;
    
using System.IO;
using DEBUG = System.Diagnostics.Debug; // Псевдоним класса
using SD = System.Diagnostics;          // Создаем alias пространства имен (необязательно!)
using System.Diagnostics;               // Подключаем пространство имен напрямую
    
namespace App4
{
    class Program
    {
        static void Main(string[] args)
        {
            // Локальные (стековые) переменные инициализировать обязательно
            String currentDirectory = Directory.GetCurrentDirectory();  // Каталог сборки
            DirectoryInfo directory = new DirectoryInfo(currentDirectory);
            FileInfo[] files = directory.GetFiles("*.exe"); // Список файлов по шаблону
            // Создаем массив для информации обо всех файлах
            SD.FileVersionInfo[] info =
                new System.Diagnostics.FileVersionInfo[files.Length];
    
            // Извлекаем из всех файлов дополнительную информацию
            for (int i = 0; i < files.Length; i++)
            {
                info[i] = FileVersionInfo.GetVersionInfo(files[i].FullName);// Просто 'Name' мало!
            }
    
            // Накапливаем результат для печати
            String message = String.Empty;
            for (int i = 0; i < info.Length; i++)
            {
                // Используем отражение для сокращения кода (и куража!)
                System.Reflection.PropertyInfo[] props = // Общедоступные свойства
                    info[i].GetType().GetProperties();
                for (int j = 0; j < props.Length; j++)
                {
                    message += props[j].Name + ":\t";   // Имя свойства, ':' и отступ
                    // Выполняем свойство, чтобы извлечь его значение
                    Object prop = props[j].GetGetMethod().Invoke(info[i], null);
                    if (prop is String) // Динамическая идентификация типа (необязательно)
                        message += prop.ToString();
                    else if (prop != null)
                        message += String.Format("{0}", prop);
    
                    message += Environment.NewLine; // Новая строка
                }
    
                message += "\r\n";     // Новая строка
            }
    
            Console.Write(message + "\n");  // Печатаем на консоль (Write и новая строка)
            DEBUG.WriteLine(message);       // Печатаем в панель Output оболочки
    
            Console.ReadLine();         // Задержка консоли
        }
    }
}

В приведенном коде мы применили методику отражения типов ( Reflection - рефлексию), чтобы не перебирать все свойства явно. Кроме того, использовали разные способы новой строки, для разнообразия.

  • Запустите приложение - вывод информации для файлов каталога исполнимой сборки данного проекта будет таким
Comments:	Читает метаданные (Description)
CompanyName:	Рога и копыта (Company)
FileBuildPart:	0
FileDescription:	Приложение App4 (Title)
FileMajorPart:	1
FileMinorPart:	0
FileName:	E:\Tmp\FilesAndDirectory\App4\bin\Debug\App4.exe
FilePrivatePart:	5678
FileVersion:	1.0.0.5678
InternalName:	App4.exe
IsDebug:	False
IsPatched:	False
IsPrivateBuild:	False
IsPreRelease:	False
IsSpecialBuild:	False
Language:	Независимо от языка
LegalCopyright:	Copyright ©  2010 (Copyright)
LegalTrademarks:	Ни-Бэ-Ни-Мэ (Trademark)
OriginalFilename:	App4.exe
PrivateBuild:	
ProductBuildPart:	0
ProductMajorPart:	1
ProductMinorPart:	0
ProductName:	Суперприложение (Product)
ProductPrivatePart:	5678
ProductVersion:	1.0.0.5678
SpecialBuild:	
	
Comments:	vshost.exe
CompanyName:	Microsoft Corporation
FileBuildPart:	21022
FileDescription:	vshost.exe
FileMajorPart:	9
FileMinorPart:	0
FileName:	E:\Tmp\FilesAndDirectory\App4\bin\Debug\App4.vshost.exe
FilePrivatePart:	8
FileVersion:	9.0.21022.8
InternalName:	vshost.exe
IsDebug:	False
IsPatched:	False
IsPrivateBuild:	False
IsPreRelease:	False
IsSpecialBuild:	False
Language:	Независимо от языка
LegalCopyright:	© Microsoft Corporation. All rights reserved.
LegalTrademarks:	
OriginalFilename:	vshost.exe
PrivateBuild:	
ProductBuildPart:	21022
ProductMajorPart:	9
ProductMinorPart:	0
ProductName:	Microsoft (R) Visual Studio (R) 2008
ProductPrivatePart:	8
ProductVersion:	9.0.21022.8
SpecialBuild:

Здесь, на первый взгляд, казалось бы, наблюдается парадокс - исполнимая сборка проверяет саму себя! Ну и что, порядок ее создания таков: компилятор транслирует код и записывает его в файл. Затем оболочка загружает файл в память и запускает процесс CLR, который анализирует указанный нами файл на диске в соответствии с заложенным алгоритмом. Указали бы другой исполнимый или библиотечный файл, процесс проверял бы его. Конечно, можно было бы сделать и диалог для выбора файла, но не в этом суть данного упражнения.

Алексей Бабушкин
Алексей Бабушкин

При выполнении в лабораторной работе упражнения №1 , а именно при выполнении нижеследующего кода:

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

using System.Windows.Forms;

using Microsoft.Xna.Framework.Graphics;

   

namespace Application1

{

    public partial class MainForm : Form

    {

        // Объявим поле графического устройства для видимости в методах

        GraphicsDevice device;

   

        public MainForm()

        {

            InitializeComponent();

   

            // Подпишемся на событие Load формы

            this.Load += new EventHandler(MainForm_Load);

   

            // Попишемся на событие FormClosed формы

            this.FormClosed += new FormClosedEventHandler(MainForm_FormClosed);

        }

   

        void MainForm_FormClosed(object sender, FormClosedEventArgs e)

        {

            //  Удаляем (освобождаем) устройство

            device.Dispose();

            // На всякий случай присваиваем ссылке на устройство значение null

            device = null;       

        }

   

        void MainForm_Load(object sender, EventArgs e)

        {

            // Создаем объект представления для настройки графического устройства

            PresentationParameters presentParams = new PresentationParameters();

            // Настраиваем объект представления через его свойства

            presentParams.IsFullScreen = false; // Включаем оконный режим

            presentParams.BackBufferCount = 1;  // Включаем задний буфер

                                                // для двойной буферизации

            // Переключение переднего и заднего буферов

            // должно осуществляться с максимальной эффективностью

            presentParams.SwapEffect = SwapEffect.Discard;

            // Устанавливаем размеры заднего буфера по клиентской области окна формы

            presentParams.BackBufferWidth = this.ClientSize.Width;

            presentParams.BackBufferHeight = this.ClientSize.Height;

   

            // Создадим графическое устройство с заданными настройками

            device = new GraphicsDevice(GraphicsAdapter.DefaultAdapter, DeviceType.Hardware,

                this.Handle, presentParams);

        }

   

        protected override void OnPaint(PaintEventArgs e)

        {

            device.Clear(Microsoft.Xna.Framework.Graphics.Color.CornflowerBlue);

   

            base.OnPaint(e);

        }

    }

}

Выбрасывается исключение:

Невозможно загрузить файл или сборку "Microsoft.Xna.Framework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=6d5c3888ef60e27d" или один из зависимых от них компонентов. Не удается найти указанный файл.

Делаю все пунктуально. В чем может быть проблема?