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

вторник, 5 марта 2019 г.

Про перевод имен переменных

Вот есть разное программирование. И везде надо переменные называть. И правилом хорошего тона называть их на английском (нуу за несколькими исключениями, к примеру в виде 1С).

И вот тут можно использовать небольшой финт ушами.

Для примера возьмём слово "склад" и предположим, что мы не знаем как его нам забить. Казалось бы не проблема - идём в Google.Translate и переводим

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

среда, 27 февраля 2019 г.

Строки в компоненте DataGrid разного размера (Compact Framework)

Вводная: Есть проект для ТСД Windows Mobile 6.5 на .Net Compact Framework 3. И в нём есть DataGrid с некоторыми данным. Но проблема в том, что в данной версии фреймворка нельзя задать высоту для конкретной строки или авторасширение по контенту.

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



Решение: Напрямую мы не можем обращаться к высоте каждой строки. Но такой параметр ЕСТЬ, правда он с приватным модификатором доступа, поэтому придётся немного схитрить

Добавим после заполнения данными (dataGrid1.DataSource = dataTable;) 
такой код
//Здесь получаем все строки 
var allRows = (ArrayList)dataGrid1
   .GetType()
                        .GetField("m_rlrow", BindingFlags.NonPublic
                                           | BindingFlags.Static
                                           | BindingFlags.Instance)
                        .GetValue(dataGrid1);
 
//Здесь формируем массив строк для обработки с их индексами
foreach (var pair in dataTable.Rows.Cast<DataRow>()
                                   .Select((r, i) => new {Row = r, Index = i})
                                   //Указываем параметр по которому увеличиваем размер строки
                                   .Where(x => x.Row["Type"].ToString().Contains("\n")))
{
 int index = pair.Index;
        //Эдесь мы можем получить доступ к строке если надо
        //DataRow row = pair.Row;
        SetGridRowHeight(allRows[index], 60);
 
}

Далее сама функция изменения размера
public static void SetGridRowHeight(object row, int height)
{
    row.GetType().GetField("m_cy", BindingFlags.NonPublic
                                 | BindingFlags.Static
                                 | BindingFlags.Instance)
                 .SetValue(row, height);
}
 

И результат:




среда, 5 сентября 2018 г.

Доступ в интернет с эмулятора Windows Mobile 6 на Windows 10

Вводная: Есть ТСД, штука дорогая, защищённая, с мощными батареями и главное в наличии. "Покупать другие не предлагать". Разработка для них знакома и не представляет сложности. Все поставилось, но софт требует доступа к интернет-серверу (REST-api, все дела). А его нет! Проблема в том, что доступ к сети реализован через VirtualPC 2007, которая в Windows 10 не работают от слова вообще.

Но выход есть:
1. Ставим локальный прокси. Я рекомендую Fiddler https://www.telerik.com/fiddler

2. Запускать от админа, потом в меню Tools -> Options -> Connections 

3. Обязательно указываем "Allow remote computers to connect"


4. Запускаем Microsoft Device Emulator Manager 9 (входит в состав Microsoft Device Emulator 3.0 https://www.microsoft.com/ru-ru/download/details.aspx?id=5352 )

5. Выбираем наш эмулятор и в контекстном меню выбираем Cradle

6. Должен открыться "Центр устройств Windows Mobile" https://www.microsoft.com/ru-ru/download/details.aspx?id=3182

7. В нём выбираем "Подключение без настройки устройства"


8. На эмуляторе Settings -> Connections -> Connections -> Edit my proxy server

9. Указываем Ip адрес компьютера на котором запущен Fiddler и дважды нажимаем OK



10. Пробуем выходить в интернет

PS: Минус у этого решения есть и достаточно серъёзный - это всё надо делать каждый раз после перезапуска компьютера. Но автоматизируется легко. AutoIt или на том-же C#.

PS2: Кстати при наличии лицензионного ключа на 2008 Professional пришлось ставить пиратскую. Мой серийник, честно купленный в 2010 году, все найденные дистрибутивы просто отказались принимать :(

суббота, 30 декабря 2017 г.

Заполнить базу в MS SQL тестовыми данными

Вводная: сабж.

Решение:
USE [testBackup]
GO

DECLARE @count INT 
SET @count = 1

WHILE @count <= 100000
BEGIN
INSERT INTO [dbo].[Table_1]
    SELECT 
            CHAR((ABS(CHECKSUM(NEWID())) % 26) + 97) + CHAR((ABS(CHECKSUM(NEWID())) % 26) + 97) + 
            CHAR((ABS(CHECKSUM(NEWID())) % 26) + 97) + CHAR((ABS(CHECKSUM(NEWID())) % 26) + 97) + 
            CHAR((ABS(CHECKSUM(NEWID())) % 26) + 97) + CHAR((ABS(CHECKSUM(NEWID())) % 26) + 97) + 
            CHAR((ABS(CHECKSUM(NEWID())) % 26) + 97) + CHAR((ABS(CHECKSUM(NEWID())) % 26) + 97) + 
            CHAR((ABS(CHECKSUM(NEWID())) % 26) + 97) + CHAR((ABS(CHECKSUM(NEWID())) % 26) + 97) [Test]
    SET @count += 1
END
GO

Ну и удаление
USE [testBackup];
GO
DELETE FROM [dbo].[Table_1];
GO

вторник, 19 декабря 2017 г.

C# - отправить монитор в сон

Вводная: Есть телевизор, он используется исключительно как монитор и подключен к компьютеру. Настроено автовыключение при пропадании сигнала и соответственно включение при его появлении. Но есть несколько моментов:
1) Если выключаешь не с пульта, а с кнопки на телевизоре, то при появлении сигнала сам не включается - надо обязательно опять её нажать вручную.
2) На компьютере настроен таймаут 15 минут - его менять не хотелось. А иногда ждать эти пятнадцать минут не хочется. А вставать за пультом, также не хочется. (к примеру когда вечером ложимся спать) - ну и пульт получается только для включения-выключения.
3) Компьютер не выключается никогда.

Решение: Была написана небольшая программа на C#, которая при запуске просто отправляет монитор в сон. Код -

    class Program
    {
        [DllImport("user32.dll")]
        static extern IntPtr SendMessage(IntPtr hWnd, 
                                         int msg, 
                                         IntPtr wParam, 
                                         IntPtr lParam);
 
        static void Main()
        {
            var hwndBroadcast  = (IntPtr)0xFFFF;
            var scMonitorpower = (IntPtr)0xF170;
            var wmSyscommand   = 0x0112;
 
            SendMessage(hwndBroadcast, wmSyscommand, scMonitorpower, (IntPtr)2);
        }
    }

Несколько примечаний -
1) Проект консольный, но "Output type" windows application - по этому никаких окон не появляется при запуске
2) Админских прав не требует
3) Никаких дополнительных библиотек не требует

четверг, 1 декабря 2016 г.

Тестовая задача C# - создание самораспаковывающегося архива

Реализовать программу, которая создаёт самораспаковывающийся архив.

  1. Тип результирующего файла - exe.
  2. Одного файла должно быть достаточно, чтобы передать его для извлечения в другом месте.
  3. При старте спрашивает папку в которую распаковать.
  4. Сжатие любое, но должно присутствовать.
  5. Программа должна уметь создавать архив из произвольного количества папок и файлов, произвольного типа.

Сторонние библиотеки использовать нелья, только Net.Framework (любая версия на ваш выбор).


четверг, 23 июня 2016 г.

Небольшой FAQ про локализацию текста в приложениях при разработке в C# Mono на Linux

1. Текущий язык зависит от языка MonoDevelop, если у вас настроен анлгийский, то и язык приложений будет по умолчанию английским. Даже если сама система на русском (как и наоборот).

2. По умолчанию тип проекта "Translation Project" в списке не отображается, чтобы он появился надо включить его в Tools - Add-in Manager - Gettext Translation Support.

3. То что указано в Mono.Unix.Catalog.GetString("Hello World!") является одновременно и именем, и значением по умолчанию (которое используется, если в переводе не найдено)

4. При разработке в GTK# и использовании графической разработки, дизайнер автоматически подставляет GetString, вместо отображаемого значения.

5. По умолчанию имя ВСЕХ проектов переводов - "i8n1", можете поменять в свойствах Translation Project. Также в опциях можно указать в какой католог кидать переводы + увидеть строку для инициализации

6. Для указания где брать переводы используется команда
Mono.Unix.Catalog.Init ("i8n1", "./locale");

7. Чтобы указать в приложении конкретный язык нужно до инициализации (и назначения значений переменных) выполнить
Environment.SetEnvironmentVariable ("LANGUAGE", "ru");

8. Можно сменить язык во время работы приложения. Но для этого нужно заново указать все компоненты (для примера у нас есть три элемента label)


protected void OnButtonRUClicked (object sender, EventArgs e)
{
 Environment.SetEnvironmentVariable ("LANGUAGE", "ru");
 Mono.Unix.Catalog.Init ("i8n1", "./locale");
 nameUpdate ();
}

protected void OnButtonENClicked (object sender, EventArgs e)
{
 Environment.SetEnvironmentVariable ("LANGUAGE", "en");
 Mono.Unix.Catalog.Init ("i8n1", "./locale");
 nameUpdate ();
}

void nameUpdate()
{
 label1.LabelProp = global::Mono.Unix.Catalog.GetString ("label1");
 label2.LabelProp = global::Mono.Unix.Catalog.GetString ("label2");
 label3.LabelProp = global::Mono.Unix.Catalog.GetString ("label3");
}

9. Если после создания проекта перевода в основном проекте были добавлены компоненты которые нужно переводить, то чтобы они появились в ранее созданом проекте перевода нужно просто щелкнуть правой кнопкой на нём и выбрать "Update Translations"

10. На текст перевода распространяются ограничения обычного текста в коде. То есть спецсимволы, такие как "\" или сами кавычки нужно экранировть.

11. Вы можете в любом месте проекта сделать
string str = global::Mono.Unix.Catalog.GetString ("TestMessage");
затем сделать Update Translations и новое сообщение появится для перевода

12. В переводах допустима подстановка -
string str = global::Mono.Unix.Catalog.GetString ("Hello {0}!");
string str2 = string.Format (str, "World");

пятница, 10 июня 2016 г.

Тестовая задача на программиста C# №2

Что выведет этот код. Почему? Есть ли здесь ошибка? Если есть то какая и как исправить?

void Main()
{   
   var Ref1 = new SomeClass { Val = 111 };
   var Ref2 = Ref1;

   Ref2.Val += 1;
   
   Console.WriteLine(Ref1.Val);
   Console.WriteLine(Ref2.Val);
}

public class SomeClass { public int Val; }

понедельник, 11 апреля 2016 г.

Тестовая задача на программиста C#

Периодически прохожу разные собеседования на программиста C#. Буду выкладывать тестовые задание и/или вопросы с собеседования. 

Задача: Пусть есть БД с 2 таблицами
В таблице 1 находится информация по номерам:

  • ID - идентификатор строки таблицы, 
  • номер
  • цена за час
  • его описание 

В таблицу 2 заносятся операции по бронированию:

  • ссылка на ID номера
  • дата начала бронирование
  • дата окончания бронирования

Реализовать автоматический расчёт стоимости при создании брони.

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

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

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

Срок - 3 дня.

понедельник, 21 декабря 2015 г.

Использование ВК для логгирования через C#

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

Решение: Для начала нужна зарегистрированная страница в VK. Переходим по ссылке https://vk.com/apps?act=manage и нажимаем "Создать приложение". Название пусть будет "vkLogSend", тип "Standalone-приложение".

Придёт смс с кодом, который нужно указать. Далее переходим во вкладку "Настройки" и сохраняем куда-нибудь "ID приложения", в нашем случае 1111111.



На этом работа с сайтом закончена и можем переходить непосредственно к программированию.

Открываем Visual Studio и создаём консольный проект vkLogSend. Далее сразу можно перейти в NuGet и установить два пакета - VkNet (реализация ВКонтакте API для .NET) и NLog (библиотека логгирования для C#).

Далее создаём класс с именем "vkTarget.cs" и содержанием -

using System;

using NLog;
using NLog.Targets;

using VkNet;
using VkNet.Enums.Filters;

namespace vkLogSend
{
    [Target("vk")]
    public sealed class VKTarget : TargetWithLayout
    {
        public VKTarget() { }

        protected override void Write(LogEventInfo logEvent)
        {
            var logMessage = this.Layout.Render(logEvent);

            SendTheMessageToRemoteHost(logMessage);
        }

        [STAThread]
        private void SendTheMessageToRemoteHost(string message)
        {
            var appId = 111111; // указываем id приложения
            var email = "user@mail.com"; // email для авторизации
            var password = "Pa$$w00rd"; // пароль
            var settings = Settings.Messages; // уровень доступа к данным

            var api = new VkApi();

            api.Authorize(appId, email, password, settings); // авторизуемся

            api.Messages.Send(1111111, false, message); // посылаем сообщение пользователю
        }
    }
}

Теперь нужно создать правила для NLog, это делается через создание файла NLog.config, в нашем примере пусть будет два правила: вывод на консоль и отправка в ВК -

<?xml version="1.0" encoding="utf-8" ?>

<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

  <extensions>
    <add assembly="vkLogSend"/>
  </extensions>

  <targets>
    <target name="console" xsi:type="Console" layout="${date:format=HH\:mm\:ss} | ${level} | ${message}" />
    <target name="vk" type="vk" layout="${date:format=HH\:mm\:ss} | ${level} | ${message}"/>
  </targets>

  <rules>
    <logger name="*" minlevel="Trace" writeTo="console" />
    <logger name="*" minlevel="Trace" writeTo="vk" />
  </rules>

</nlog>

По сути стандартный файл NLog с добавленной секцией <extensions> и прописывание правила для таргета "vk"

И напоследок использование -


using System;
using NLog;

namespace vkLogSend
{
    class Program
    {
        static Logger logger = LogManager.GetCurrentClassLogger();

        static void Main()
        {
            logger.Trace("vkLogSend test message. Error on machine: " + Environment.MachineName);
            Console.WriteLine("Press any key..."); Console.ReadKey();
        }
    }
}

И у нас ничего не работает :) В библиотеке VkNet, при установке через NuGet есть ошибка - устанавливаются библиотеки Newtonsoft.Json и HtmlAgilityPack неверных версий. Решение простое - через NuGet обновляем их до последних и всё должно заработать.

После обновления библиотек можем тестировать и отправлять себе логи через Вконтакт.

\



PS: Есть нюанс при работе - если у вас настроено подтверждение входа (через смс или другим способом), то данный код работать не будет. Имейте это в виду.

среда, 14 октября 2015 г.

Неверное отображение WPF программы в классической теме оформления Windows

Иногда при разработке на C# использованием WPF возникает проблема с отображением окон, особенно если используются не стандартные компоненты, а какие нибудь свои, либо измененные стандартные. Для примера создадим окно с одним TabControl`ом и парой TabItem`ов. Добавим кнопки и пару элементов. Окно при использовании стандартной темы Windows 7

При использовании темы Aero все будет выглядеть вполне нормально, но если мы запустим программу при использовании темы Classic (к примеру на почти всех серверных ОC тема по умолчанию именно классическая), то отображение будет не очень корректным -

Для исправления данной проблемы сделаем следующее -
В References добавим ссылку на PresentationFramework.Aero и добавим следующий код -

    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="/PresentationFramework.Aero;V3.0.0.0;31bf3856ad364e35;component/themes/aero.normalcolor.xaml" />
    </ResourceDictionary.MergedDictionaries>

Обычно этого достаточно, но если у вас используется директива Style и вы забыли (или не стали определять директиву BasedOn) то будет выглядеть в классической вот так -

У вас в таком случае два выхода -
1. В файле где у вас определены стили нужно немного их переписать -
если было - <Style x:Key="TabItemStyle" TargetType="TabItem">
Надо добавить директиву BasedOn
 <Style x:Key="TabItemStyle" TargetType="TabItem" BasedOn="{StaticResource {x:Type TabItem}}">
2. Либо полностью прописать нужный стиль, как должны выглядить элементы.

Теперь программа выглядит корректно при любой теме.

суббота, 26 сентября 2015 г.

Немного мыслей про логгирование в приложениях на C#

Предположим вы решили писать какую-то программу, небольшую утилиту. И даже прикрутили к ней лог. И даже не стали писать свой велосипед, а взяли какую-нибудь отлаженную и хорошую библиотеку (в моём случае NLog http://nlog-project.org ). Так вот в первые строчки лога после запуска вбивайте "ВРЕМЯ-Название-ВЕРСИЮ-ОСНОВНЫЕ НАСТРОЙКИ".

Объясню почему -

  • Название - чтобы когда вам просто тупо скинули файл лога (ещё и переименовав его как-нибудь "Лог.ткст", то вы из первой строчки могли вытащить хоть какую то инфу от чего этот лог )))
  • Время - чтобы понимать, что лог актуальный, а то бывает вообще программа не работает и лог от старой версии. А вы смотрите в него и в нём всё нормально.
  • Версию - похоже на предыдущий пункт, но немного другое. Бывает, что человек, которому вы делаете программу и выкатили новый релиз, на вас ругается, что новый функционал не работает. А в логах чисто. И пользователь утверждает, что таки да - "ОБНОВИЛ, Мамой клянусь". Так вот. Бывает, что не обновляет. Бывает сам закосячишь и в апдейторе забудешь предварительно закрыть предварительно программу если открыта (а винда не даст вам просто взять и перезаписать, запущенный файл). А косяки прут. Дополнительно можно вставлять версию операционнки, особенно если есть "зависимый" функционал (то есть работает только выше 7, XP мимо и прочее такое). Сюда же можно всякое про браузеры, антивирусы и прочее что влияет на работу программы. 
  • Основные настройки - все особо смысла нет (разве что при дотошной отладке, обычно если место хранение настроек едино и прочиталась одна, то и все остальные тоже. Но не факт) А для чего? Чтобы убедиться, что программа считывает настройки и не пытается работать с настройками по умолчанию. И не подключается к удалённому серверу БД не потому, что "файрволл, нет клиенсткой библиотеки и прочее блядство", а просто потому, что пробует подключиться на дефолтный локалхост

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

Ну и пункт выходящий из предыдущего пункт - пусть логгирование дебаг уровня будет вместо комментариев :) Тоже достаточно интересный финт ИМХО.

Дополнительно нужно не забывать про права записи для логов. И пробовать запускать программу от ограниченного (в правах) пользователя. Так как если программа ставится в Program Files и логи пишутся в папку с программой, то можно поймать трабл когда логи не будут писаться. А учитывая, что вывод в лог часто в самом начале программы, то может получится, что будет ошибка на запись и программа просто будет вылетать при запуске не оставляя логов. Но при этом во время разработки глюков не будет никаких.

Добавлено 12.10.2015:
Ещё нужно давать возможность совсем отключать логи. Это может потребоваться в разных ситуациях, начиная от запрета на запись из соображений безопасности, кончая увеличением ресурса SSD или увеличением скорости работы.

Про скорость работы программы - некоторые программисты делают избыточные логи (каюсь, порой грешен) и забывают делать замеры производительности. Для примера приведу одну из ситуаций: была программа, задача которой было очень много считать, причём очень тяжелые формулы, так вот - запись на медленный хард во время процесса выполняемого быстрым процессором, давала постоянные задержки выполнения (грубо говоря 5мс считает, 30мс пишет лог), что в реальной работе совершенно лишнее.

Ограничение размера логов - ОЧЕНЬ желательно реализовывать систему "обрезки" логов, либо по размеру, либо по дате. Иначе рано или поздно вы просто забьёте пользователю всё свободное место на диске. Да и работать с лог-файлами размером в пару десятков-сотен гигабайт очень неудобно





среда, 23 сентября 2015 г.

Получение внешнего IP-адреса на C#

Вводная: В одной программе было необходимо получить внешний адрес компьютера. Для решения предварительно погуглил и выяснил, что достаточно известная функция и реализуется просто. Если что искать по запросу в гугл - "C# get public ip external". Первые же ссылки ведут на http://www.codeproject.com/Tips/452024/Getting-the-External-IP-Address и http://stackoverflow.com/questions/3253701/get-public-external-ip-address где и показывается как это можно сделать. В данных примерах получение адреса делается через сервисы checkip.dyndns.org и whatismyip.com. Первоначально с ними и начал работать, но возникло куча осложнений - порой дикие задержки и проблемы с соединением. Постоянная ошибка "System.Net.WebException: Время ожидания операции истекло   в System.Net.HttpWebRequest.GetResponse()"

Решил сделать тоже самое, но с оглядкой на Российскую действительность. Первоначально рассматривал https://2ip.ru но там достаточно тяжелая страница и в итоге выбор пал на Яндекс, а конкретно - http://yandex.ru/internet

Решение:
public class PublicIP
{
  public string Get()
  {
    try
    {
      using (var client = new WebClient())
      {
        var uri = new Uri("http://yandex.ru/internet/");
 
        client.Encoding = Encoding.UTF8;
        client.Proxy = null;
 
        var downloadString = client.DownloadString(uri);
        var first = downloadString.IndexOf("<strong>IP-адрес</strong>: ", StringComparison.Ordinal) + 27;
        var last = downloadString.IndexOf("<strong>Регион по IP-адресу</strong>", StringComparison.Ordinal);
 
        downloadString = downloadString.Substring(first, last - first);
 
        return downloadString;
      }
    }
    catch (Exception msg)
    {
      Console.WriteLine(msg);
      return "";
    }
  }
}

PS: Используется простой разбор строк не потому, что я не знаю о парсерах HTML (Html Agility Pack, Fizzler и тп), а просто потому, что

  • а) в данном случае они избыточны 
  • б) удлиняют выполнение функции примерно на 1-2 секунды
  • в) Ради одного единственного места в программе тащить ещё мегабайт библиотекой ИМХО не корректно
  • г) в итоге кода получается больше :)


PS2: Замеры по сравнению с точно такой же функцией, только которая обращается к CheckIP.dyndns.org

Stopwatch stopWatch = new Stopwatch();
 
stopWatch.Start();
 
var gip = new PublicIP();
Console.WriteLine(gip.Get());
 
stopWatch.Stop();
 
Console.WriteLine("Checkip:  " + stopWatch2.Elapsed);

Методика тестирования - запускается программа. Значение записывается отдельно и так по 5 раз для каждого варианта (CheckIP и Yandex)
checkIP
00:00:01.9662763
00:00:02.1180682
00:00:03.0694474
00:00:02.0939421
00:00:02.1191459
Yandex
00:00:00.3286215
00:00:00.3752536
00:00:00.3639731
00:00:00.3458052
00:00:00.3535228

Комментарии излишни.

PS3: Если вам требуется получать в пределах одного города или провайдера, то проще поднять у себя web-сервер и отдавать от себя. Скорость может быть ещё выше.

вторник, 15 сентября 2015 г.

Среда программирования и используемые плагины.

На одном из собеседований задали вопрос - какими средствами (IDE, плагины, другие средства) пользуетесь при программировании. Мой ответ -

IDE - 
Visual Studio 2015 Community

Графическая схема -
http://studiostyl.es/ Son of Obsidian

Плагины - 
Refactoring Essentials
Productivity Power Tools 2015
Code Cracker for C#
C# outline
Trailing Whitespace Visualizer
Microsoft CodeLens Code Health Indicator
CommentsPlus
Supercharger

Дополнительные программы - 
LINQPad
dotPeek
inno setup + Inno Script Studio
Paint.Net с дополнительными плагинами

PS: Да я знаю про решарпер ((( Но нужно, чтобы было всё бесплатное

воскресенье, 13 сентября 2015 г.

Как приостановить выполнение программы на X секунд

Спросили меня, вроде бы простой вопрос - "Как приостановить выполнение программы на X секунд". Естественно в C#. Первый (и очень часто единственный) вариант это Thread.Sleep(1000); Но для порядка решил погуглить и покопаться на stackoverflow.

И вот к чему я пришел -
Используйте

  1. System.Timers.Timer
  2. System.Windows.Forms.Timer
  3. System.Threading.Timer
Лучше не использовать Thread.Sleep, так как это полностью заблокирует нить и предотвратит её от обработки других сообщений.

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

Для контроля (сколько времени реально выполнялось) можно использовать System.Diagnostics.Stopwatcth
Пример кода -

using System;
using System.Diagnostics;

namespace TimerTest
{
    class Program
    {
        static System.Timers.Timer aTimer;
        static Stopwatch stopwatch = System.Diagnostics.Stopwatch.StartNew();

        static void Main(string[] args)
        {
            aTimer = new System.Timers.Timer(2000);
            aTimer.Elapsed += OnTimedEvent;
            //Разовое выполнение таймера
            aTimer.AutoReset = false;
            aTimer.Enabled = true;

            Console.WriteLine("Press the Enter key to continue the program at any time... ");
            Console.ReadLine();            

            TimeSpan ts = stopwatch.Elapsed;

            string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
                ts.Hours, ts.Minutes, ts.Seconds,
                ts.Milliseconds / 10);
            Console.WriteLine("RunTime " + elapsedTime);
            Console.ReadLine();
        }

        private static void OnTimedEvent(Object source, System.Timers.ElapsedEventArgs e)
        {
            Console.WriteLine("The Elapsed event was raised at {0}", e.SignalTime);
            stopwatch.Stop();
        }
    }
}

воскресенье, 2 августа 2015 г.

Перевод на русский SambaPOS v4

Вводная: Есть такая программа для автоматизации общепита (кафе, столовых, ресторанов, фастфудов и прочего) SambaPOS. Она бесплатная, версии 2 и 3 в опенсорсе, лежат себе спокойно на гитхабе и прочее. В своё время для одного заведения мы переводили вторую версию (и до сих пор именно наш перевод там используется, хоть и корявый). Но в четвёртой версии почему-то вообще нет поддержки многоязычности и соответственно русского языка. Официальное мнение на этот счёт - "Only English is supported at the moment". Но ко мне обратились с вопросом - "Можно ли как-нибудь получить четвёртую версию на русский?"

Решение: Для начала я решил действовать "в лоб", зашел в MultiCommander (бесплатный аналог TotalCommander`a и ИМХО более для меня удобный и быстрый) и сделал поиск подстроки по папке - "Admin PIN". Данное сообщение выходит на первом экране, и решено было тестирование возможности перевода начать с него.

Искомая подстрока была найдена в библиотеке - Samba.Localization.dll и уже обрадовавшись, попробовал просто её поправить в обычном редакторе. И естественно у меня ничего не получилось. Если количество символов совпадало, то программа запускалась и даже работала, но так как отличие русского и английского языка весьма существенно и большинство слов и фраз по количеству не попадают, то пришлось думать дальше.

Для дальнейшей работы нам потребуется две вещи - Visual Studio (я использовал Visual Studio Community 2015, но можно использовать любую в которой есть поддержка 4 версии) и программу Resource.NET (взять можно по адресу - http://fishcodelib.com/Resource.htm ).

Теперь копируем Samba.Localization.dll в какую-либо папку (в моём случае X:\POS\) и открываем "Командную строку разработчика" 

Выполняем команду ildasm https://msdn.microsoft.com/ru-ru/library/f7dy01k1(v=vs.110).aspx

C:\Program Files (x86)\Microsoft Visual Studio 14.0>ildasm /out=x:\pos\sambaloc.il x:\POS\Samba.Localization.dll

Выполнив данную команду мы получим несколько файлов и среди них будет Samba.Localization.Properties.Resources.resources (имя будет таким вне зависимости от того, что вы указали в параметре out команды ildasm). Теперь открывает Resource.NET и выбираем данный файл. Открыв, мы увидим строки для редактирования, которые можно перевести самому или отдать фрилансерам на перевод. Переводим только раздел DATA и ни в коем случае не трогаем раздел Name!!!

После изменения, не забываем нажать кнопки "Update" и "Save".


После этого возвращаемся в Командную строку разработчика и вводим уже другую команду ilasm https://msdn.microsoft.com/ru-ru/library/496e4ekx(v=vs.110).aspx

C:\Program Files (x86)\Microsoft Visual Studio 14.0>ilasm x:\pos\sambaloc.il /output:x:\pos\Samba.Localization.dll /dll


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



PS: Также некоторые кнопки НЕ БУДУТ переведены данным способом, их нужно переводить в разделе - Manage-Automation-Automatiom Commands. Выбираем нужную для перевода команду и переводим секцию "Button Header"

пятница, 13 марта 2015 г.

Генерация списка MAC адресов в C#

Вводная: Необходимо генерировать определённое количество MAC адресов, начиная с заданного.

Решение: Была написана функция alMacList(string first, decimal count, string separatorChar, bool up). Данная функция получает в качестве параметра первый MAC в диапозоне, получает количество нужных адресов, символ разделитель (MAC может быть как цельным числом, так и разделяться. К примеру - "AABBCCDDEEFF" и "AA:BB:CC:DD:EE:FF"). Нужно ли отдавать в верхнем или нижнем регистре. Возвращает ArrayList. Проверок на корректность входных параметров НЕТ!

Собственно сама функция -

private ArrayList alMacList(string first, decimal count, string separatorChar, bool up)
        {
            ArrayList mac = new ArrayList();
 
            long value = long.Parse(first, NumberStyles.HexNumber, CultureInfo.CurrentCulture.NumberFormat);
 
            for (int i = 0; i < count; i++)
            {
                string s = (value + i).ToString("X12");
                s = String.Format("{0}{6}{1}{6}{2}{6}{3}{6}{4}{6}{5}", s.Substring(0,2), 
                                                                       s.Substring(2,2), 
                                                                       s.Substring(4,2), 
                                                                       s.Substring(6,2), 
                                                                       s.Substring(8,2), 
                                                                       s.Substring(10,2), 
                                                                       separatorChar);
 
                if (up) {s = s.ToUpper(); }
                else s = s.ToLower();
 
                mac.Add(s);
            }
 
            return mac;
        }

вторник, 19 августа 2014 г.

Использование карт 2GIS в программе на C# через API

Вводная: Необходимо отображение карты 2GIS в приложении Windows Forms.

Решение:
1. Создаём форму

2. Добавляем компонет WebBrowser

3. Добавляем HTML страницу. В неё нужный нам код (для примера возьмём результирующий код с http://api.2gis.ru/doc/maps/quickstart/ )
В свойствах созданного файла нужно выбрать - "Всегда копировать"

4. Создаём событие Load на форме где наш компонент WebBrowser

        private void Form1_Load(object sender, EventArgs e)
        {
            var curDir = Directory.GetCurrentDirectory();
            webBrowser1.Url = new Uri(String.Format("file:///{0}/2GIS.html", curDir));
        }

5. Компилируем.


PS: Можно использовать установленный 2GIS, он может выступать как COM-сервер, но в моём случае было достаточно и допустимо использования webAPI. Если вам нужны работать оффлайн, то - http://plugins.2gis.ru/wiki/Практика:_.NET


пятница, 6 июня 2014 г.

Простейший бот-кликер для игры

Есть такая игра http://armorgames.com/play/15760/gemcraft-chasing-shadows . Игра очень хорошая и вставляющая - качественный Tower Defense. С кучей миссий и прочим кайфом. Есть там также такая вещь, как талисман - и прокачивается за счёт так называемых "Shadom cores". Прикол в чём - игра построена по модели free-to-play поэтому играть можно и бесплатно, но если хочешь качаться быстрее плати. И тут возникает вопрос - "Откуда деньги у старого евреямолодого архонта?".

Думал я, думал и решил написать тупого простейшего бота. Чтобы он сам фармил это всё. Ситуацию облегчило две вещи - 1) Первый уровень - типа демонстрационный, с разными уже построенными камнями. 2) то что уже был достаточно прокачен и не требовалось ничего улучшать, строить дополнительно и прочее.

После пары ручных прогонов стало понятно, что от бота будет нужно 4 действия -
1. Выбрать миссию
2. Нажать кнопку "Start the Battle!"
3. Нажать кнопку "9х" (служить для ускорения в 9 раз игры)
4. После прохождения вернуться обратно на карту
И ПОВТОРЯТЬ, ПОВТОРЯТЬ, ПОВТОРЯТЬ

Решено было писать на C#. По сути всё свелось к одной единственной процедуре, которая "щелкала" мыщъ по переданным координатам.

        #region Send mouse click
        [DllImport("user32.dll")]
        static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint dwData, IntPtr dwExtraInfo);
 
        public const int MOUSEEVENTF_LEFTDOWN = 0x02;
        public const int MOUSEEVENTF_LEFTUP = 0x04;
 
        public static void SendClick(Point location)
        {
            Cursor.Position = location;
            mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, new IntPtr());
            mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, new IntPtr());
        }
        #endregion


        private void botAction()
        {
            Thread.Sleep(2000);
            SendClick(new Point(500, 660)); // Select mission
            Thread.Sleep(2000);
 
            SendClick(new Point(615, 875)); // Start the Battle!
            Thread.Sleep(6000);
 
            SendClick(new Point(141, 388)); // 9x speed
            Thread.Sleep(18000);
 
            SendClick(new Point(836, 928)); // Back to the Map
            Thread.Sleep(2000);
 
            Count++;
            labelCount.Text = Count.ToString();
        }

Данная процедура была засунута в таймер и оставлена на ночное выполнение. За ночь я набрал около 20к этих хреновин, что СЭКОНОМИЛО МНЕ ЦЕЛЫХ ПЯТЬ ДОЛЛАРОВ!!!



PS: Чтобы знать какие координаты прописывать ещё одна небольшая процедура.

        #region Get Cursor Location
        [DllImport("user32.dll")]
        static extern bool GetCursorPos(ref Point lpPoint);
 
        private void timer1_Tick(object sender, EventArgs e)
        {
            Point ptCoords = new Point();
            GetCursorPos(ref ptCoords);
 
            uint x = (uint)ptCoords.X;
            uint y = (uint)ptCoords.Y;
 
            labelX.Text = x.ToString();
            labelY.Text = y.ToString();
        }
        #endregion

четверг, 10 октября 2013 г.

Mikrotik SSH Backup - собственное исполнение

Вводная: Необходимо было реализовать бэкап конфигураций Mikrotik. Но с несколькими ограничениями -
1) Средство должно было быть под Windows
2) Средство не должно было вызывать запись на внутреннюю флеш-память микротика (ограниченное число циклов записи)
3) Средство должно было иметь возможность автоматического выполнения и отсылки отчёта в случае неудачи.

Решение: Реализовал с помощью C# .Net. Программа подключается через SSH к Mikrotik. И сохраняет вывод команды export compact. При запуске через командную строку с параметром Backup ("MikrotikSSHBackup.exe Backup"), просто выполняется, создавая резервные копии.


Для работы программы необходимо сделать следующее -

  1. Включить пакет Security (System - Packages - Security)
  2. Проверить, что ssh не отключен в IP - Services (порт 22). Рекомендуется также проставить Available From и только нужную нам подсеть, чтобы не было доступа из вне, если конечно доступ не требуется)
  3. Необязательно, но настоятельно рекомендую создать группу которая может работать только с ssh (можно и из-под админа, но не совсем правильно)
  4. user group add name=SSH policy="ssh, read" 
  5. user add name=userSSH group=SSH password=TestPaSSword
  6. Добавить в программу необходимые роутеры.
  7. Добавить (если необходимо) параметры для отправки email
  8. Проверить работу программы нажав на "Start Backup"


Ссылки: Скачать саму программу - https://dl.dropboxusercontent.com/u/10168286/Programmers/MikrotikSSHBackup.zip
GitHub - https://github.com/psionika/MikrotikSSHBackup (здесь вы можете посмотреть исходный код и всегда скачать самую последнюю версию)
"Резервное копирование Mikrotik в Subversion посредством SSH/SFTP" - http://habrahabr.ru/post/143320/ (на основании данной статьи сделал и я)