Показаны сообщения с ярлыком C#. Показать все сообщения
Показаны сообщения с ярлыком C#. Показать все сообщения

среда, 13 февраля 2013 г.

WMI на C#

WMI (Windows Management Instrumentation) - это одна из базовых технологий для централизованного управления и слежения за работой различных частей компьютерной инфраструктуры под управлением платформы Windows. (Википедия)

Для работы с WMI Framework .NET предоставляет сборку System.Management.dll и одноименным неймспейсом.

Работа с WMI начинается с класса ManagementScope, который предназначен для подключению к серверу WMI, как локального компьютера, так и удаленного. Основной конструктор этого класса принимает 2 параметра:
  1. path - путь для подключения;
  2. options - параметры подключения.
Параметр path обычно: string.Format(@"\\{0}\root\cimv2", host). Пусть содержит хост компьютера к которому нужно подключиться, и путь неймспейса WMI (имеет иерархическую структуру). Имеется много нейсмпейсов, но наиболее используемый cimv2.
Параметр options содержит следующие поля:
  • Username - имя пользователя Windows.
  • Password/SecurePassword - пароль пользователя Windows.
  • Другия параметы - не использовал.
После создания объекта, для того чтобы подключения к WMI нужно вызвать метод Connect.
Исходный код подключения к WMI:
ConnectionOptions options = new ConnectionOptions();
options.Username = username;
options.Password = password;
scope = new ManagementScope(string.Format("\\\\{0}\\root\\cimv2", host),
    options);
scope.Connect();
Свойство IsConnected возвращает состояние подключения.
Важно: класс ManagementScope не имеет метода для разрыва связи, для того чтобы переподключиться, ножно повторно вызвать метод Connect.

После создания подключения, мы можем начать запрашивать различную информацию от WMI.
Для этого существует класс SelectQuery. В конструкторе ему передается строка с SQL-подобным запросом. После этого мы можем использовать объект класса SelectQuery для передачи его в конструктор класса ManagementObjectSearcher.

SelectQuery query = new SelectQuery(@"Select
    DeviceID, FreeSpace, Size, DriveType from Win32_LogicalDisk");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope,
    query);
ManagementObjectCollection queryCollection = searcher.Get();
foreach (ManagementObject mo in queryCollection) {
    Console.WriteLine("DeviceID: {0}", mo["DeviceID"]);
    Console.WriteLine("FreeSpace: {0}", mo["FreeSpace"]);
    Console.WriteLine("Size: {0}", mo["Size"]);
    Console.WriteLine("DriveType : {0}", mo["DriveType "]);
}

Таким вот нехитрым способом можно получить с компа очень много системной информации.

пятница, 8 февраля 2013 г.

OpenSource: JSIL - компилятор C# в JS

Нашел в инете 3 основный проека по компилированию C# в JS:
Script# я тестил давно, мне не понравился :-) Не доделанный какой-то.
Про SharpKit пишут хорошие отзывы, но он платный.
А вот с JSIL можно поэксперементоровать. Он OpenSource и генерит вполне читаемый и логичный JS. На сайте есть возможность в онлайне скомпилировать любой код и увадеть что получится.
Написано что JSIL позволяет компилировать XNA игры и приведено нескольно демок. Но это надо еще проверить... У меня есть одна простая игра на XNA, будет время попробую скомпилировать.

среда, 14 ноября 2012 г.

Компоненты Visual Studio. Создание собственного редактора свойства

При написании своих собственных компонентов для Visual Studio часто возникает необходимость создать специальный редактор для свойств, значениями которых являются например объекты, неизвестный системе. Сделать свой собственный редактор свойства довольно просто.
Любой редактор свойства является классом унаследованным от UITypeEditor. Настройка поведения своего редактора свойства осуществляется путем переопределения предоставляемых этим классом виртуальных методов. UITypeEditor содержит следующие методы, предназначенные для переопределения:
  • EditValue – этот метод вызывается при начале редактирования свойства, в нем должен вызываться редактор, в результате возвращает полученное от редактора значение;
  • GetEditStyle – должен возвращать значение enum'а. Допускаются следующие значения:
    • None – никакой кнопки выводиться не будет;
    • Modal – кнопка в виде многоточия (типа "Обзор"), указывающая на то что при нажатии на нее откроется диалог для редактирования значения свойства:
    • DropDown – кнопка в виде выпадающего списка, указывающая на то что при нажатии на нее появится небольшая формочка для редактирования:
  • GetPaintValueSupported – указывает, нужно ли будет рисовать маленький прямоугольник, перед значением свойства  в PropertyGird'е:
  • PaintValue – вызывается при необходимости перерисовки маленькой картинки перед значением свойства в PropertyGird'е.
Теперь подробнее о том как работает этот механизм. В самом простом случае нужно переопределить два метода:
1) GetEditStyle – для задания вида редактора. Например если нужно получить выпадающую форму для редактирования, нужно сделать так:
public override UITypeEditorEditStyle GetEditStyle(
    ITypeDescriptorContext context)
{
    return UITypeEditorEditStyle.DropDown;
}
2) EditValue – для открытия редактора. Метод имеет следующую сигнатуру:
public Object EditValue(
 ITypeDescriptorContext context,
 IServiceProvider provider,
 object value)
где
  • context – не знаю для чего используется:-);
  • provider – обеспечивает объект интерфейса IWindowsFormsEditorService (путем вызова метода GetService(typeof(IWindowsFormsEditorService))). Этот объект предоставляет методы для отображения (DropDownControl) и закрытия (CloseDropDown) всплывающей формы редактора и метод ShowDialog для отображения диалога редактора.
  • value – текущее значение свойства.
Возвращает новое значение свойства, после изменения его в редакторе. Таким образом, переопределение метода EditValue должно выглядеть примерно так:
public override object EditValue(ITypeDescriptorContext context,
    IServiceProvider provider, object value)
{
    IWindowsFormsEditorService edSvc = (IWindowsFormsEditorService)
             provider.GetService(typeof(IWindowsFormsEditorService));
    if (edSvc != null)
    {
        MyEditorControl control = new MyEditorControl();
        control.Value = (MyEditableType)value;
        edSvc.DropDownControl(control);
        value = control.Value;
    }
    return value;
}
В коде можно увидеть использование неизвестного класса MyEditorControl. Этот класс и есть форма нашего редактора. Он является наследником класса UserControl (но может быть унаследован и от другого контрола). Реализация класса MyEditorControl должна иметь примерно следующий вид:
class MyEditorControl : UserControl {
    public MyEditableType Value {
        get; set;
    }
    //
}
Так как MyEditorControl является обычным контролом, вы можете пользоваться всеми средствами предоставляемыми Windows.Forms: создавать на нем кнопки, выпадающие списки, переопределять виртуальные методы (OnPaint, OnMouseDown, ...) и др.
Но это еще не все. В приведенном выше коде в качестве типа редактируемого свойства используется класс (или структура) MyEditableType. Этот тип является пользовательским и компонентная модель ничего не знает о нем. Для того чтобы объяснить компонентной модели как обращаться с этим типом, для него необходимо задать атрибут TypeConverterAttribute. В качестве параметра этот атрибут принимает тип класса, унаследованного от TypeConverter.

Исходный код в котором вы сможете увидеть применение редакторов свойств на практике можно найти здесь.

четверг, 17 мая 2012 г.

Двойная буферизация в .NET

Существует два способа двойной буферизации для отрисовки WinForms контролов: автоматический и ручной.

Для того чтобы включить автоматическую двойную буферизацию, нужно всего лишь для контрола установить свойство DoubleBuffered = true или вызвать SetStyle(ControlStyles.OptimizedDoubleBuffer, true).

Для ручного же управления двойной буферизацией Framework .NET включает 3 класса:
BufferedGraphicsManager содержит одно статическое свойство Current, которое возвращает объект BufferedGraphicsContext для текущего домена приложения.* Для приложений активно использующих анимацию может быть эффективнее создать новый экземпляр BufferedGraphicsContext вместо того чтобы использовать BufferedGraphicsManager.Current. В этом случае по завершению работы с объектом, его необходимо уничтожить явным образом:
BufferedGraphicsContext myContext = new BufferedGraphicsContext();
// использование
myContext.Dispose();
или
using(BufferedGraphicsContext myContext = 
    new BufferedGraphicsContext()) {
// использование
}
BufferedGraphicsContext имеет один метод Allocate и одно свойство MaximumBuffer
Allocate(Graphics targetGraphics, Rectangle targetRectangle) -- создает новый BufferedGraphics на основе переданного через параметр targetGraphics размером targetRectangle.

Как работает метод Allocate

Исходный код метода:
    public BufferedGraphics Allocate(Graphics targetGraphics, Rectangle targetRectangle)
    {
      if (this.ShouldUseTempManager(targetRectangle))
        return this.AllocBufferInTempManager(targetGraphics, IntPtr.Zero, targetRectangle);
      else
        return this.AllocBuffer(targetGraphics, IntPtr.Zero, targetRectangle);
    }
Внутри метода происходит проверка MaximumBuffer и targetRectangle (методом ShouldUseTempManager**). Если требуемый размер полотна превышает заданный полем MaximumBuffer , то вызывается метод AllocBufferInTempManager. Этот метод внутри себя создает новый экземпляр класса BufferedGraphicsContext, вызывает у него метод AllocBuffer и возвращает полученный от него объект класса BufferedGraphics.***
Если же targetRectangle не превышает MaximumBuffer, то тогда временный объект не создаётся, а метод AllocBuffer вызывается непосредственно у текущего объекта (т.е. у самого себя).
Метод AllocBuffer внутри себя вызывает метод CreateBuffer, для создания нового экземпляра Graphics, оборачивает его в BufferedGraphics и сохраняет в переменную объекта buffer. Эта переменная используется для того, чтобы в дальнейшем при уничтожении экземпляра BufferedGraphicsContext (методом Dispose), уничтожить связанный с ним экземпляр BufferedGraphics.

Стоит заметить что объект BufferedGraphics также хранит в себе ссылку на создавший его BufferedGraphicsContext в закрытой переменной.

---------------------------------------------------------------


*  Код класса BufferedGraphicsManager выглядит следующим образом:
  public sealed class BufferedGraphicsManager
  {
    private static BufferedGraphicsContext bufferedGraphicsContext;
    public static BufferedGraphicsContext Current
    {
      get
      {
        return BufferedGraphicsManager.bufferedGraphicsContext;
      }
    }

    static BufferedGraphicsManager()
    {
      AppDomain.CurrentDomain.ProcessExit += 
          new EventHandler(BufferedGraphicsManager.OnShutdown);

      AppDomain.CurrentDomain.DomainUnload +=
          new EventHandler(BufferedGraphicsManager.OnShutdown);
 
      // В СТАТИЧЕСКОМ КОНСТРУКТОРЕ ПРОСТО СОЗДАЕТСЯ НОВЫЙ
      // НОВЫЙ ОБЪЕКТ BufferedGraphicsContext
      BufferedGraphicsManager.bufferedGraphicsContext = 
          new BufferedGraphicsContext();
    }

    private BufferedGraphicsManager()
    {
    }

    [PrePrepareMethod]
    private static void OnShutdown(object sender, EventArgs e)
    {
      BufferedGraphicsManager.Current.Invalidate();
    }
  }

** Исходный код метода ShouldUseTempManager():
    private bool ShouldUseTempManager(Rectangle targetBounds)
    {
      return targetBounds.Width * targetBounds.Height > this.MaximumBuffer.Width * this.MaximumBuffer.Height;
    }
*** При этом созданный внутри метода AllocBufferInTempManager экземпляр BufferedGraphicsContext не уничтожается, ответственность за его уничтожение ложится на пользователя получившего объект BufferedGraphics, который хранит обратную ссылку, при уничтожении которого и уничтожается породиший его объект BufferedGraphicsContext. Как это работает? Исходный код метода AllocBufferInTempManager:
    private BufferedGraphics AllocBufferInTempManager(Graphics targetGraphics, IntPtr targetDC, Rectangle targetRectangle)
    {
      BufferedGraphicsContext bufferedGraphicsContext = (BufferedGraphicsContext) null;
      BufferedGraphics bufferedGraphics = (BufferedGraphics) null;
      try
      {
        // Создаем новый "временный" контент
        bufferedGraphicsContext = new BufferedGraphicsContext();
        if (bufferedGraphicsContext != null) //  Всегда ДА
        {
          // Создаем в нем буферизированное полотно, которое внутри себя (переменная context) хранит 
          // ссылку на него же
          bufferedGraphics = bufferedGraphicsContext.AllocBuffer(targetGraphics, targetDC, targetRectangle);

          // ВОТ, этот флаг указывает, что объект bufferedGraphics 
          // при своем уничтожении должен уничтожить породившего его
          // bufferedGraphicsContext:
          bufferedGraphics.DisposeContext = true; 
        }
      }
      finally
      {
        // В нормальной ситуации это условие не выполняется
        if (bufferedGraphicsContext != null 
            && (bufferedGraphics == null 
                || bufferedGraphics != null && !bufferedGraphics.DisposeContext))
          bufferedGraphicsContext.Dispose();
      }
      return bufferedGraphics;
    }

вторник, 15 мая 2012 г.

Выход из .NET программы

В WinForms приложениях для завершения работы программы существует метод Application.Exit(). Для того чтобы немедленно завершить работу консольного приложения, нужно выполнить следующую команду:
Environment.Exit(0);
Метод Environment.Exit(int exitCode) является аналого сишной функции exit(int code).

воскресенье, 6 мая 2012 г.

Запрос .NET программой прав администратора при запуске

Для того чтобы при запуске программы на C# выводился запрос на получение прав администратора нужно:
Добавить в проект Visual Studio файл монифеста Project->New Item->Application Manifest File
В добавившемся файле заменить строку:
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
на следующую:
<requestedExecutionLevel level="requireAdministrator" uiaccess="false" />
После этого рядом с иконкой программы появится картинка щита, указывающая что запуск программы требует прав администратора.

вторник, 10 апреля 2012 г.

C#: Чтение файла без блокировки

Для того чтобы прочиталь файл без блокировки его на запись и удаление другими процессами, нужно открыть его следующим образом:
FileStream stream = new FileStream(pathName, FileMode.Open, 
FileAccess.Read, FileShare.ReadWrite | FileShare.Delete);

суббота, 6 августа 2011 г.

Форматирование даты и времени на C#


В C# для работы с датами и временем используется тип DateTime. Существует еще тип DateTimeOffset. Для преобразования даты/времени в строку у типа DateTime есть 4 переопределения метода ToString:
ToString(string format, IFormatProvider provider);
ToString(IFormatProvider provider);
ToString(string format);
ToString(),
где format -- строка форматирования даты/времени. Строка format может состоять из 1 символа, тогда она считается стандартным форматом даты времени, или из нескольких, тогда она считается строкой настраиваемого формата даты и времени.
Существуют следующие стандартные форматы даты и времени:
d -- Короткий шаблон даты.
D -- Полный шаблон даты.
f -- Полный шаблон даты и времени (короткий шаблон времени).
F -- Полный шаблон даты и времени (полный шаблон времени).
g -- Общий шаблон даты и времени (короткий шаблон времени).
G -- Общий шаблон даты и времени (полный шаблон времени).
M, m -- Шаблон дней месяца.
O, o -- Шаблон обратного преобразования даты и времени.
R, r -- Шаблон RFC1123.
s -- Сортируемый шаблон времени и даты.
t -- Короткий шаблон времени.
T -- Полный шаблон времени.
u -- Универсальный сортируемый шаблон времени и даты.
U -- Универсальный полный шаблон даты и времени.
Y, y -- Шаблон месяца года.
Для того чтобы получить нестандартную строку времени, например в таком виде 07:27:15, параметр format должен быть строкой настраиваемого формата даты и времени, и иметь значение "hh:mm:ss". В параметре format допустимы следующие спецификаторы:
d -- день месяца от 1 до 31;
dd -- день месяца от 01 до 31;
ddd -- день недели, сокращенно (Пн, Вт и т. д.);
dddd -- день недели, полностью (понедельник и т. д.);
h -- часы от 1 до 12;
hh -- часы от 01 до 12;
H -- часы от 0 до 23;
HH -- часы от 00 до 23;
m -- минуты от 0 до 59;
mm -- минуты от 00 до 59;
M -- месяц от 1 до 12;
MM -- месяц от 01 до 12;
MMM -- месяц, сокращенно;
MMMM -- месяц, полностью;
s -- секунды от 0 до 59;
ss -- секунды от 00 до 59;
y -- год от 0 до 99;
yy -- год от 00 до 99;
yyy -- год от 000 до 999;
yyyy -- год от 0000 до 9999;
yyyyy -- год от 00000 до 99999;
t -- первый символ от AM/PM;
tt -- AM/PM;
z -- смещение в часах от UTC (всемирного координатного времени, приближенно совпадает со временем по Гринвичу);
zz -- смещение в часах от UTC,с нулями в начале для значений из одной цифры;
zzz -- смещение в часах и минутах от UTC, например 6/15/2009 1:45:30 PM -07:00 -> -07:00;
g или gg -- эпоха или эра;
f, ff, fff, ffff, fffff, ffffff, fffffff -- доли секунды;
F, FF, FFF, FFFF, FFFFF, FFFFFF, FFFFFFF -- доли секунды с нулями в начале;
: -- разделитель компонентов времени;
/ -- разделитель компонентов даты;
"string" или 'string' -- любая строка, копируется в результат как есть;
% -- отделяет символ спецификатора, от символа стоящего перед ним. Например "dd" для 8 марта возвратит "08", а "d%d" возвратит 88;
\ -- escape-символ, отменяет действие спецификатора;
др. символы -- копируется в результирующую строку без изменений.
provider -- обычно задается объектом класса CultureInfo - представляет язык и региональные параметры. Если provider не задан или равен null, то за него принимается CultureInfo.CurrentCulture.

Для форматирования дат и времени также может быть использован метод string.Format(string format, params object args).


* Про форматирование даты и времени в C# можно еще почитать в MSDN.

пятница, 5 августа 2011 г.

Сериализация на C#

Сериализацию (и десериализацию) объекта в .NET можно осуществить двумя способами. Один более универсальный, другой более удобный.

Сначала рассмотрим более удобный способ. С помощью него объект можно сериализовать только в XML.

Первое что нужно для этого сделать -- добавить в References ссылки на System.Xml.dll и (только в Silverlight приложениях) System.Xml.Serialization.dll. В первой, в неймспейсе System.Xml.Serialization содержатся атрибуты, необходимые для указания какому элементу XML соответствует какой-либо класс или свойство:
  • XmlRootAttribute -- указывает на то, что класс к которому он (атрибут) применен, является корнем XML-файла. Он может принимать аргумент ElementName, который задает как будет называться соответствующий тег в XML'е. Если ElementName не задан, то за название тега принимается имя класса, к которому был применен атрибут.
  • XmlAttributeAttribute -- указывает сериализатору на то, что свойство к которому применен атрибут, является атрибутом XML. В качестве аргумента может принимать название атрибута в XML.
  • XmlElementAttribute -- указывает сериализатору на то, что свойство к которому применен атрибут, является элементом XML. Также как и предыдущий может принимать имя в XML в качестве аргумента.
  • XmlArrayAttribute -- применяется к свойству, имеющему перечислимый тип (массив), в случае если необходимо чтобы входящие в соответствующий ему элементы XML дочерние элементы, были представлены как элементы массива этого свойства.
  • XmlArrayItemAttribute -- также применяется к свойству, имеющему перечислимый тип, вместе с атрибутом XmlArrayAttribute, чтобы указать параметры соответствующего элементу массива, элемента XML (например тип или имя).

Пример разметки классов для сериализации приведен в листинге:
using System;
using System.Xml.Serialization;
using System.IO;
namespace SerializationTest1
{
    public class Product
    {
        private string name;
        private int price;
        [XmlElement("price")]
        public int Price
        {
            get { return price; }
            set { price = value; }
        }
        [XmlAttribute("name")]
        public string Name
        {
            get { return name; }
            set { name = value; }
        }

    }
    [XmlRoot("shop")]
    public class Shop
    {
        private string owner;
        private string name;
        private Product[] products;
        [XmlAttribute("name")]
        public string Name
        {
            get { return name; }
            set { name = value; }
        }
        [XmlAttribute("owner")]
        public string Owner
        {
            get { return owner; }
            set { owner = value; }
        }
        [XmlArray("products"), XmlArrayItem("product")]
        public Product[] Products
        {
            get { return products; }
            set { products = value; }
        }

    }
}
После разметки сериализуемых классов атрибутами (чтобы сериализатор знал что во что сериализировать), переходим непосредственно к самой сериализации.
Для этого в неймспейсе System.Xml.Serialization существует класс XmlSerializer. Его конструктор принимает в качестве параметра тип класса, который соответствует корневому элементу XML.
Класс содержит 3 нужные нам метода:
CanDeserialize(XmlReader xmlReader) -- проверяет, получится ли получить из переданного в параметре XML, указанный при инстанцировании тип.
Deserialize(XmlReader xmlReader) -- возвращает объект, полученный в результате десериализачии XML считанного из xmlReader.
Serialize(XmlWriter xmlWriter, object o) -- сериализует объект o и записывает полученный XML в xmlWriter.
Пример получения из XML объекта описанного выше класса, приведен в листинге ниже:
using System;
using System.Xml.Serialization;
using System.IO;
namespace SerializationTest1
{
    class Program
    {
        static void Main(string[] args)
        {
            string xml = @"<shop name=""Supershop"" 
                owner=""Fedya Pupkin"">
    <products>
        <product name=""phone"">
            <price>10000</price>
        </product>
        <product name=""book"">
            <price>500</price>
        </product>
    </products>
</shop>";
            XmlSerializer serializer = 
                new XmlSerializer(typeof(Shop));
            object obj = serializer.Deserialize(
                new StringReader(xml));
            Shop shop = (Shop)obj;
        }
    }
}