Архив за месяц: Август 2016

Работа с реестром в операционных системах Windows (часть 2)

Когда-то здесь я выкладывал инструменты по работе с реестром для .NET 3.5 SP1. Обнаружилось, что начиная с .NET 4.0 сигнатура нужных для обозначенного кода конструкторов класса RegistryKey была изменена. Как следствие - если наша сборка, скомпилированная под .NET 3.5 SP1 в дальнейшем окажется загруженной в .NET 4.0 (или любую более новую), то мы будем получать исключение времени выполнения при вызове некоторых методов опубликованного кода.


Я внёс некоторые правки в исходный код класса RegistryExtensions и написал несколько интеграционных тестов, проверяющих корректность работы кода в различных ситуациях (в т.ч. избавился от всех директив препроцессора - теперь они не нужны). Проверял в .NET 3.5 SP1, 4.0 и 4.6.1 для платформ x86|x64|AnyCPU:


Обозначенный код я поддерживаю в виду того, что у меня имеется в наработке некоторый объем кода, компилируемого под .NET 3.5 SP1 (т.к. AutoCAD 2009 не поддерживает более новые версии .Net Framework). Этот код должен без проблем компилироваться и успешно работать  не только в .NET 3.5 SP1, но и во всех более новых версиях .NET. Кроме того, необходимо, чтобы ранее скомпилированные мною под .NET 3.5 SP1 сборки успешно загружались и работали в .NET 4.0 - 4.6.1.

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

======================================================================
/* AcProducts
 * RegistryExtensions.cs
 * © Андрей Бушман, 2014
 *
 * В файле RegistryExtensions.cs определён дополнительный
 * функционал, расширяющий возможности работы с реестром из
 * .NET приложений, написанных на .NET 3.5 SP1.
 *
 * ИЗМЕНЕНИЯ:
 * 10-авг-2016
 *      В код внесены правки для того, чтобы он мог
 *      использоваться не только в .NET 3.5 SP1, но и во всех
 *      более новых версиях .NET Framework: например, когда
 *      сборка, скомпилированная под .NET 3.5 SP1 загружается в
 *      код .Net 4.6.1. Код не зависит от разрядности (x86|x64|
 *      AnyCPU).
 */
using System;
using Microsoft.Win32;
using System.Reflection;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;

namespace Bushman.AcProducts {

    /// <summary>
    /// Данный класс предназначен для предоставления 32-битным
    /// приложениям доступа к 64-битным разделам реестра. Класс
    /// так же может использоваться для предоставления
    /// 64-битным приложениям ветке реестра, предназначенной
    /// для 32-битных. За основу взят код, опубликованный в
    /// блоге http://clck.ru/96A9U
    /// </summary>

    public static class RegistryExtensions {

        /// <summary>
        /// Открытие ключа реестра, с указанием того, какую
        /// именно часть следует открывать: записи для
        /// 32-битных приложений, или же записи для 64-битных.
        ///
        /// ВНИМАНИЕ
        /// У данного метода имеется побочный эффект: свойство
        /// `Name` у возвращаемого объекта `RegistryKey` даёт
        /// пустую строку. Однако это не страшно, т.к. имя нам
        /// известно - первую часть можно получить из родителя,
        /// а вторую часть этого имени мы и так знаем,
        /// поскольку передаём её в виде параметра.
        /// </summary>
        /// <param name="parentKey">Родительский элемент
        /// RegistryKey, в котором следует выполнить открытие
        /// подраздера.</param>
        /// <param name="subKeyName">Name of the key to be
        /// opened</param>
        /// <param name="writable">true - открывать для чтения
        /// и записи; false - открывать только для чтения.
        /// </param>
        /// <param name="options">Какую именно часть реестра
        /// следует открывать: относящуюся к 32-битным
        /// приложениям или же относящуюся к 64-битным.
        /// </param>
        /// <returns>Возвращается RegistryKey или null, если по
        /// каким-либо причинам получить RegistryKey не
        /// удалось.</returns>
        public static RegistryKey OpenSubKey(this RegistryKey
            parentKey, String subKeyName, Boolean writable,
            RegWow64Options options) {

            // Проверка работоспособности
            if (parentKey == null || GetPtr(
                parentKey) == IntPtr.Zero) {

                return null;
            }

            // Назначение прав
            Int32 rights = (Int32) (writable ? RegistryRights
                .WriteKey : RegistryRights.ReadKey);

            // Вызов функций неуправляемого кода
            Int32 subKeyHandle, result = RegOpenKeyEx(
                GetPtr(parentKey), subKeyName, 0,
                rights | (Int32) options, out subKeyHandle);

            // Если мы ошиблись - возвращаем null
            if (result != 0) {

                return null;
            }

            /* Получаем ключ, представленный указателем,
             * возвращённым из RegOpenKeyEx */
            RegistryKey subKey = PtrToRegistryKey((IntPtr)
                subKeyHandle, writable, false, options);

            return subKey;
        }

        /// <summary>
        /// Получить указатель на ключ реестра.
        /// </summary>
        /// <param name="registryKey">Ключ реестра, указатель
        /// на который нужно получить.
        /// </param>
        /// <returns>Возвращается объект IntPtr. Если не
        /// удалось получить указатель на обозначенный объект
        /// RegistryKey, то возвращается IntPtr.Zero.</returns>
        public static IntPtr GetPtr(this RegistryKey
            registryKey) {

            if (registryKey == null)
                return IntPtr.Zero;

            /* The `RegistryKey.Handle` property appears since
             * .Net 4.0, therefore for .Net 3.5 I get it
             * through reflection. */
            Type registryKeyType = typeof(RegistryKey);

            FieldInfo fieldInfo = registryKeyType.GetField(
                "hkey", BindingFlags.NonPublic | BindingFlags
                .Instance);

            SafeHandle handle = (SafeHandle) fieldInfo.GetValue
                (registryKey);

            IntPtr unsafeHandle = handle.DangerousGetHandle(
                );

            return unsafeHandle;
        }

        /// <summary>
        /// Получить ключ реестра на основе его указателя.
        /// </summary>
        /// <param name="hKey">Указатель на ключ реестра
        /// </param>
        /// <param name="writable">true - открыть для записи;
        /// false - для чтения.</param>
        /// <param name="ownsHandle">Владеем ли мы
        /// дескриптором: true - да, false - нет.</param>
        /// <returns>Возвращается объект RegistryKey,
        /// соответствующий полученному указателю.</returns>
        public static RegistryKey PtrToRegistryKey(IntPtr
            hKey, Boolean writable, Boolean ownsHandle,
            RegWow64Options opt) {

            if (IntPtr.Zero == hKey) {
                return null;
            }

            Type safeRegistryHandleType =
                typeof(SafeHandleZeroOrMinusOneIsInvalid)
                .Assembly.GetType("Microsoft.Win32." +
                "SafeHandles.SafeRegistryHandle");

            /* Получаем массив типов, соответствующих
             * аргументом конструктора, который нам нужен. */
            Type[] argTypes = new Type[] { typeof(IntPtr),
                typeof(Boolean) };

            BindingFlags flags = default(BindingFlags);

            if (Environment.Version.Major < 4) {
                flags = BindingFlags.Instance | BindingFlags
                    .NonPublic;
            }
            else {
                flags = BindingFlags.Instance | BindingFlags
                    .Public;
            }

            // Получаем ConstructorInfo для нашего объекта
            ConstructorInfo safeRegistryHandleCtorInfo =
                safeRegistryHandleType.GetConstructor(flags,
                    null, argTypes, null);

            /* Вызываем конструктор для SafeRegistryHandle.
             * Класс SafeRegistryHandle появился начиная с .NET
             * 4.0. */
            Object safeHandle = safeRegistryHandleCtorInfo
                .Invoke(new Object[] { hKey, ownsHandle });

            Type registryKeyType = typeof(RegistryKey);
            Type registryViewType = null;

            /*Получаем массив типов, соответствующих аргументом
             * конструктора, который нам нужен */
            Type[] registryKeyConstructorTypes = null;

            if (Environment.Version.Major < 4) {
                registryKeyConstructorTypes = new Type[] {
                safeRegistryHandleType, typeof(bool) };
            }
            else {
                registryViewType = typeof(
                    SafeHandleZeroOrMinusOneIsInvalid).Assembly
                    .GetType("Microsoft.Win32.RegistryView");

                registryKeyConstructorTypes = new Type[] {
                    safeRegistryHandleType, typeof(bool),
                    registryViewType };

                flags = BindingFlags.Instance | BindingFlags
                    .NonPublic;
            }

            // Получаем ConstructorInfo для нашего объекта
            ConstructorInfo registryKeyCtorInfo =
                registryKeyType.GetConstructor(flags, null,
                registryKeyConstructorTypes, null);

            RegistryKey resultKey = null;

            if (Environment.Version.Major < 4) {
                // Вызываем конструктор для RegistryKey
                resultKey = (RegistryKey) registryKeyCtorInfo
                    .Invoke(new Object[] {
                    safeHandle, writable });
            }
            else {
                // Вызываем конструктор для RegistryKey
                resultKey = (RegistryKey) registryKeyCtorInfo
                    .Invoke(new Object[] {
                    safeHandle, writable, (int) opt});
            }

            // возвращаем полученный ключ реестра
            return resultKey;
        }

        /// <summary>
        /// Получение числового значения указателя на искомый
        /// подраздел реестра.
        /// </summary>
        /// <param name="hKey">Указатель на родительский раздел
        /// реестра.</param>
        /// <param name="subKey">Имя искомого подраздела.
        /// </param>
        /// <param name="ulOptions">Этот параметр
        /// зарезервирован и всегда должен быть равным 0.
        /// </param>
        /// <param name="samDesired">Права доступа (чтение\
        /// запись) и указание того, как именно следует
        /// открывать реестр. Значение этого параметра
        /// формируется путём применения операции логического
        /// "И" для объектов перечислений RegistryRights и
        /// RegWow64Options.</param>
        /// <param name="phkResult">Ссылка на переменную, в
        /// которую следует сохранить полученное числовое
        /// значение указателя на искомый подраздел.</param>
        /// <returns>В случае успеха возвращается 0.</returns>
        [DllImport("advapi32.dll", CharSet = CharSet.Auto)]
        static extern Int32 RegOpenKeyEx(IntPtr hKey,
            String subKey, Int32 ulOptions, Int32 samDesired,
            out Int32 phkResult);
    }

    /// <summary>
    /// Перечисление указывает, какую именно часть реестра
    /// следует открывать: относящуюся к 32-битным приложениям
    /// или же относящуюся к 64-битным.
    /// </summary>
    public enum RegWow64Options {

        /// <summary>
        /// Открывать ту часть реестра, которая хранит
        /// информацию приложений, разрядность которых
        /// соответствует разрядности текущего приложения
        /// (x86\x64).</summary>
        None = 0,
        /// <summary>
        /// Открывать часть реестра, относящуюся к 64-битным
        /// приложениям.
        /// </summary>
        KEY_WOW64_64KEY = 0x0100,
        /// <summary>
        /// Открывать часть реестра, относящуюся к 32-битным
        /// приложениям.
        /// </summary>
        KEY_WOW64_32KEY = 0x0200
    }

    /// <summary>
    /// Перечисление, указывающее на то, с каким уровнем
    /// доступа следует открывать ветку реестра: для чтения,
    /// или же для чтения\записи.
    /// </summary>
    public enum RegistryRights {

        /// <summary>
        /// Открыть только для чтения.
        /// </summary>
        ReadKey = 131097,
        /// <summary>
        /// Открыть для чтения и записи.
        /// </summary>
        WriteKey = 131078
    }
}
==================================================================

Интеграционные тесты:

==================================================================
/* AcProducts.IntegrationTests
 * RegistryExtensionsTests.cs
 * © Andrey Bushman, 2016
 *
 * Integration tests of Bushman.AcProducts.RegistryExtensions
 * class.
 */
using System;
using Microsoft.Win32;
using NUnit.Framework;

namespace Bushman.AcProducts.IntegrationTests {

    [TestFixture]
    public class RegistryExtensionsTests {

        [Test]
        public void GetPtr_Returns_ValidPtr() {

            // `Registry.LocalMachine` key always exists.
            RegistryKey rk = Registry.LocalMachine;
            IntPtr rkPtr = rk.Handle.DangerousGetHandle();

            /* The `RegistryKey.Handle` property appears since
             * .Net 4.0, therefore for .Net 3.5 in the code
             * under test I get it through reflection. */
            IntPtr rkPtr2 = RegistryExtensions.GetPtr(rk);

            Assert.AreEqual(rkPtr, rkPtr2);
        }

        [Test]
        public void GetPtr_ReturnsZero_ForNull() {

            /* The `RegistryKey.Handle` property appears since
             * .Net 4.0, therefore for .Net 3.5 in the code
             * under test I get it through reflection. */
            IntPtr ptr = RegistryExtensions.GetPtr(null);

            Assert.AreEqual(IntPtr.Zero, ptr);
        }

        [TestCase(@"SOFTWARE\7-Zip", RegWow64Options
            .KEY_WOW64_64KEY, false)]

        [TestCase(@"SOFTWARE\7-Zip", RegWow64Options
            .KEY_WOW64_32KEY, true)]

        [TestCase(@"SOFTWARE\Notepad++",
            RegWow64Options.KEY_WOW64_64KEY, true)]

        [TestCase(@"SOFTWARE\Notepad++",
            RegWow64Options.KEY_WOW64_32KEY, false)]

        [Description("7-Zip and Notepad++ are to be installed"
            )]
        public void OpenSubKey_ReturnsValidValue(string subkey,
            RegWow64Options opt, bool isNull) {

            RegistryKey rk = Registry.LocalMachine;

            RegistryKey rk2 = RegistryExtensions.OpenSubKey(rk,
                subkey, false, opt);

            if (isNull) {
                Assert.IsNull(rk2);
            }
            else {
                Assert.IsNotNull(rk2);
            }
        }

        [Test]
        public void OpenSubKey_ReturnsNull_ForInvalidSubkey() {

            string subkey =
                "{F28A3464-0A5D-48FB-AFF6-B07F058D3EFC}";

            RegistryKey rk = RegistryExtensions.OpenSubKey(
                Registry.LocalMachine, subkey, false,
                RegWow64Options.None);

            Assert.IsNull(rk);
        }

        [Test]
        public void PtrToRegistryKey_Returns_ValidValie() {

            RegistryKey rk = Registry.LocalMachine;
            IntPtr rkPtr = rk.Handle.DangerousGetHandle();

            RegistryKey rk2 = RegistryExtensions
                .PtrToRegistryKey(rkPtr, false, false,
                RegWow64Options.None);
            IntPtr rkPtr2 = rk2.Handle.DangerousGetHandle();

            Assert.AreEqual(rkPtr, rkPtr2);
        }

        [Test]
        public void PtrToRegistryKey_ReturnsNull_ForZero() {

            RegistryKey rk = RegistryExtensions
                .PtrToRegistryKey(IntPtr.Zero, false, false,
                RegWow64Options.None);

            Assert.IsNull(rk);
        }
    }
}
==================================================================

4 важные причины заказать принадлежности в интернет магазине канцтоваров office-land.com.ua

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

Сегодня в сети можно купить все что угодно – товары и услуги различных типов и характеров. И канцелярские принадлежности не являются исключением.

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

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

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

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

Наша команда рада предложить свои услуги всем, кто ценит внимательный сервис и лучшее качество! Работать с нами – это отличная идея, так как здесь вас никогда не подведут и не разочаруют.

Интернет магазин канцтоваров office-land.com.ua – это ваш надежный друг и партнер.

В каталогах представлены товары для детей и взрослых, бизнесменов и учеников, для досуга и ведения активной деятельности.

Обратиться к нашему сайту следует по ряду причин. Перечислим основные:

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

2.       Наша команда предлагает индивидуальные скидки каждому клиенту. Будьте уверены в том, что независимо от количества приобретенных товаров, вы платите минимальную цену за максимально качественную продукцию.

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

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

Использование преобразователей частоты. Экономическая эффективность и срок окупаемости.

Использование преобразователей частоты в электроприводах насосов, компрессоров, вентиляторов и дымососов имеет следующие преимущества:

  • плавный пуск и остановка приводных механизмов, уменьшает пусковой ток электродвигателя и возрастает срок безаварийной эксплуатации объекта в целом;
  • отсутствуют гидроудары в системе;
  • экономия электроэнергии.

Расчет экономии электроэнергии

Потребляемая мощность является функцией от производительности насоса (компрессора, вентилятора, дымососа):

S = F (Q),

где S — потребляемая электрическая мощность, Вт;
Q — производительность механизма, м3 / час.

Производительность механизма зависит от частоты вращения приводного электродвигателя:

Образ ,

где n — частота вращения приводного электродвигателя, об / мин.

Итак, потребляемая электрическая мощность зависит от куба частоты вращения приводного электродвигателя:

S = F (п 3 ).

Сравним два способа регулирования подачи: регулирование заслонкой и частотное регулирование. меншення подачи до 70% от номинальной, при регулировании заслонкой потребляемая мощность составит как и при 100%, так как электродвигатель вращается с той же частотой. При частотном регулировании частота вращения уменьшится в 1,43 раза, а потребляемая мощность уменьшится в 2,92 раза. При уменьшении подачи до 50% от номинальной, при регулировании заслонкой потребляемая мощность составит как и при 100% .При частотном — частота вращения уменьшится в 2 раза, а потребляемая мощность уменьшится в 8 раз.

срок окупаемости

Образ,

где Т — срок окупаемости, ч;
С — затраты на модернизацию (стоимость преобразователя частоты), руб .;
Р1 — потребляемая мощность до модернизации, кВт;
Р2 — потребляемая мощность после модернизации, кВт;
Ц — цена электроэнергии, руб. / КВт · ч.

пример

Модернизация котельной. Замена дроссельного регулирования подачи воздуха в топку котла на частотное регулирование. Мощность приводного двигателя 11,0 кВт. Положение заслонки подачи воздуха составляет 63%. Стоимость преобразователя частоты E82EV113K4C с сетевой дросселем ELN30150H024 — 11520,00 грн. Цена электроэнергии 0,30 руб. / КВт · ч.

При использовании частотного регулирования — частота вращения приводного двигателя уменьшится в

100%: 63% (положения заслонки) = 1,59 раза,

потребляемая мощность уменьшится в

(1,59) 3 = 4 раза

и составит

11,0 : 4 = 2,75 кВт.

Срок окупаемости:

Образ год,

или

Т = 4654,54 / (24 · 30) = 6,46 месяца.

Итак, срок окупаемости от внедрения частотный преобразователь цена украина составляет 6,5 месяцев, а дальше чистая прибыль.

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