C# чайник — C#напишите пожалуйста код, не могу сделать вообще


Содержание

Можете объяснить суть invoke

Есть основной поток, в котором я создаю все Controls в winforms. И есть второй поток, который вызывается через срабатывание события. В результате этого события мне нужно изменить значение DataSource у DataGridView . В результате возникает ошибка, что доступ к контролу пытается получить не основной поток, в котором был создан контрол. Решением является использование методов Invoke\BeginInvoke . Но саму суть я не понимаю этих методов и как их реализовать в коде. В создаваемом втором потоке используется функция доступа к dgv

3 ответа 3

Суть метода Invoke довольно проста — он принимает делегат и выполняет его в том потоке, в котором был создан элемент управления, у которого вызывается Invoke . Как вы могли заметить, если обращаться к контролам в WinForms не из того потока, в котором они были созданы, будет выброшено исключение. Соответственно, метод Invoke полезен в случаях, когда необходимо работать с контролом из других потоков. Метод BeginInvoke делает то же самое, но асинхронно.

Небольшой пример использования Invoke :

Стоит также отметить, что async/await , добавленные в C# 5, позволяют обойтись без Invoke :

В оконных приложениях Windows существует так называемый поток пользовательского интерфейса (UI thread), по сути — основной поток приложения, создаваемый самым первым.

Он выполняет обработку оконных сообщений (Windows messages), вызывая в цикле функции GetMessage или PeekMessage . Если вы хотите что-то сделать с пользовательским интерфейсом, например, изменить строку в поле ввода, вы посылаете ему оконное сообщение.

В WinForms изменение текста в поле ввода выполняется с помощью присваивания:

но на низком уровне этот код приводит к отсылке оконного сообщения WM_SETTEXT окну с дескриптором textbox1.Handle при помощи функции SendMessage .

Тонкость заключается в том, что отправив сообщение, вы можете захотеть получить результат. Это неочевидно для WM_SETTEXT , но для WM_GETTEXT вы точно захотите узнать ответ.

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

Но что, если вы вызовете SendMessage из другого потока? Вопреки расхожему мнению, это не приведёт к ошибке. Вы можете это сделать, но вызывающий поток будет остановлен до тех пор, пока SendMessage не завершится. Если в программе работают несколько потоков, и они захотят что-то изменить в пользовательском интерфейсе, они будут приостановлены, и каждый их SendMessage будет выполняться основным потоком последовательно.

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

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

И всё бы хорошо, но часто такие небольшие функции что-то хотят сделать с вашим пользовательским интерфейсом. Например, вы обрабатываете большой файл и просите Windows вызывать вашу функцию, когда будут прочитаны очередные 64Кб. Блок прочитан, Windows будит поток и передаёт ему вашу функцию на выполнение. Функция делает полезную работу, а потом хочет увеличить индикатор процесса. Она вызывает SendMessage , который может конфликтовать с другими асинхронными функциями.

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

Это проблема, так что Windows запрещает вызывать SendMessage из других потоков при асинхронных вызовах.

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

Да, обновление интерфейса всё ещё происходит последовательно, но все остальные асинхронные функции совершенно не мешают друг другу.

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

Использовать их можно, например, так:

Здесь параметр Invoke это анонимный делегат, то есть в действительности функция, которая будет вызвана из потока пользовательского интерфейса.

Есть несколько способов упростить этот код (ищите на Stack Overflow). Отмечу основную идею: код располагается внутри одного из методов вашей формы, соответственно, InvokeRequired и Invoke это свойство и метод формы.

Вызывать изменение свойств через Invoke нужно только в том случае, когда свойство InvokeRequired истинно. Перед вызовом полезно подготовить все данные, которые вам потребуется использовать, чтобы не тормозить поток пользовательского интерфейса. Сначала готовите данные, а потом присваиваете их через свойства элементов управления внутри Invoke / BeginInvoke — таков основной паттерн асинхронного программирования десктопных приложений.

Напишите программу на c#, которая запрашивает с клавиатуры названия кинотеатра и фильма, время сеанса и стоимость билета и выводит сообщение (например, если введено название кинотеатра «Колизей», название фильма «Явление», время сеанса «18:00», цена билета «150»): «Приглашаем в наш кинотеатр «Колизей». У нас вы можете посмотреть фильм «Явление» в 18:00. Цена билета 150 р.».

Ответ

Console.WriteLine(«Введите название кинотеатра «);
string kino = Convert.ToString(Console.ReadLine());
Console.WriteLine(«Введите название фильма «);
string film = Convert.ToString(«Console.ReadLine());
Console.WriteLine(«Введите время сеанса «);
string time = Convert.ToString(Console.ReadLine());
Console.WriteLine(«Введите стоимость билета «);
int cena = Convert.ToInt32(Console.ReadLine());

Console.WriteLine(«Приглашаем в наш кинотеатр «» + kino + «». У нас вы можете посмотреть фильм «» + film + » » в » + time + «. Цена билета » + cena + «р.»);

Если и в дальнейшем будет нужна помощь с C#, то пиши в сообщения, дам контакты.

Программирование на C, C# и Java

Уроки программирования, алгоритмы, статьи, исходники, примеры программ и полезные советы

ОСТОРОЖНО МОШЕННИКИ! В последнее время в социальных сетях участились случаи предложения помощи в написании программ от лиц, прикрывающихся сайтом vscode.ru. Мы никогда не пишем первыми и не размещаем никакие материалы в посторонних группах ВК. Для связи с нами используйте исключительно эти контакты: vscoderu@yandex.ru, https://vk.com/vscode

Ввод в TextBox только цифр и необходимых символов C#

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

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

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

Затем следует найти в правой стороне рабочей области Visual Studio окно “Свойства” и перейти в нём на вкладку событий (значок в виде молнии):

Примечание: если вы не нашли “Свойства”, то просто кликните правой кнопкой мыши по текстбоксу и выберете в появившемся меню соответствующую вкладку.

Далее мы ищем событие KeyPress и дважды нажимаем на него левой кнопкой мыши. Нас перенесет к коду этого события. Далее мы рассмотрим несколько вариантов решения проблемы с вводом определенных символов в TextBox. Сначала будут идти варианты только с выводом цифр, а затем и другие (с Backspace, пробелом, запятой и проч.)

Использование в TextBox только цифр.

Способ первый – самый быстрый.

Внутри этой области кода мы запишем всего несколько строк:


Вот и всё решение нашей проблемы! Теперь если запустить проект и попробовать что-нибудь написать в нашем TextBox’e, то в него не попадёт ни один другой символ кроме цифр.

Так что же мы тут сделали?

В самой первой строке мы объявили символьную переменную, назвав её number.Благодаря параметру e.KeyChar программа заносит в нашу переменную символ введенной клавиши. Нажали на клавишу “+”, в переменную запишется “+”, нажали на клавишу “в”, в переменную запишется “в” и т.д.

Далее идёт условие !Char.IsDigit(number), которое можно словесно интерпретировать как “если символ из переменной number не относится к категории десятичных цифр” (а нам как раз такие и нужны). А вывод из условия e.Handled = true интерпретируется как “тогда не обрабатывать введенный символ (и, следовательно, не выводить его в TextBox). Иными словами, мы проверяем, является ли любой символ, введенный пользователем десятичной цифрой. Если нет – отбрасываем его, если является – обрабатываем и выводим в TextBox. Легко, просто, быстро!

Способ второй – с кодировкой ASCII.

Однако далеко не всегда можно обойтись только способом, описанным выше. Нам в TextBox’e могут понадобиться и другие символы и клавиши, например, клавиша удаления Backspace, запятая или пробел. В таком случае нам придётся пользоваться помощью таблицей ASCII-кодов. Это совсем несложно. Но для начала разберемся,что вообще такое ASCII.

ASCII – это специальная кодировка, которая присваивает всем используемым в компьютере символам соответствующий числовой код.

Таблицу большинства ASCII-кодов можно просмотреть ниже (кликабельно).

Теперь попробуем написать аналогичный код для вывода только цифр используя коды ASCII. Итак, ищем в таблице, под какими номерами расположены наши цифры. Видимо, что нам необходимы коды с 48 по 57 – цифры от 0 до 9. Значит наш код в событии KeyPress будет таким:

Кейлоггер по-домашнему. Пишем на C# кейлоггер, который не палится антивирусами

Содержание статьи

Ставим задачу

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

  • мы не беспокоим жертву лишними окнами, иконками в таскбаре, сообщениями об ошибках и подобным;
  • мы имеем доступ к целевому компьютеру только однократно и на очень короткий срок;
  • мы сможем забирать логи, находясь в той же локальной сети;
  • антивирус должен молчать;
  • файрвол не учитываем и предполагаем, что мы дадим ему разрешение вручную при подсадке кейлоггера;
  • мы не будем пытаться скрывать процесс и только дадим ему неприметное название.
Цукерберг рекомендует:  Создание Peel Away объявлений

Еще жертва может пользоваться парольным менеджером, тогда в логе мы получим только Ctrl-C и Ctrl-V. На этот случай будем мониторить еще и содержимое буфера обмена.

Подробнее об атаках на парольные менеджеры читай в статье «Ищем слабые места современных менеджеров паролей».

Писать будем на C# в Visual Studio. Забегая вперед, скажу, что в результате у меня получилось две версии программы — одна работает через перехват WinAPI, другую я про себя называю «костыльной». Но эта менее красивая версия дает другие результаты при проверке антивирусами, поэтому расскажу и о ней.

Теория

Когда ты нажимаешь на кнопку, операционка посылает уведомления тем программам, которые хотят об этом узнать. Поэтому самый простой способ перехватить ввод с клавиатуры — это принимать сообщения о нажатиях клавиш. Если мы этого сделать не можем (например, функция SetWindowsHookEx запрещена антивирусом или еще чем-либо), можно тянуть сырой ввод и без нее. Есть такая функция — GetAsyncKeyState, которая принимает номер клавиши и позволяет узнать, зажата она или отжата в момент вызова. Собственно, алгоритм действий будет такой: раз в N мс опрашиваем все кнопки и узнаем их состояние, занося нажатые в специальный список. Затем список обрабатываем, учитывая состояние клавиши Caps Lock, Num Lock, Shift, Ctrl и так далее. Полученные данные будем записывать в файл.

Пишем код

Для начала откроем Visual Studio и создадим новый проект Windows Forms (.NET Framework). Почему именно Windows Forms? Если мы выберем обычное консольное приложение, то при каждом запуске будет создаваться некрасивое черное окошко, а ведь юзера мы договорились не беспокоить. Также, пока мы не создали форму (а создавать ее мы и не будем), никаких значков в таскбаре не появится — важная часть скрытой работы. Теперь удаляй автоматически созданный файл Form1.cs со всеми потрохами и открывай Program.cs.

Здесь нас уже поджидает шаблон программы, но он не будет работать просто так. Первым делом надо убрать строчки 10–12 и 16–18. Теперь меняем объявление метода со static void Main() на static void Main(String[] args) . Нужно это для того, чтобы мы могли определить свои аргументы при перезапуске.

Теперь добавим using System.IO; для работы с файлами, System.Runtime.InteropServices для работы с WinAPI и System.Threading для приостановки потока. Если ты не хочешь писать костыльный вариант, лучше пропусти этот раздел и сразу переходи к следующему.

Импортируем GetAsyncKeyState из user32.dll:

И добавляем собственно логирование нажатий, собирая их по десять штук, чтобы не делать слишком много дисковых операций:

Расшифровывать такой лог будет неудобно

Выглядит не очень красиво, а про читабельность вообще можно забыть. Во-первых, наш код тянет ввод не только с клавиатуры, но и с мыши (всякие LButton и RButton). Поэтому давай не будем записывать нажатие, если это не символьная клавиша. Заменим содержимое if в цикле на это:

После такого редактирования лог стал намного чище (см. рисунок).

Продолжение доступно только участникам

Вариант 1. Присоединись к сообществу «Xakep.ru», чтобы читать все материалы на сайте

Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», увеличит личную накопительную скидку и позволит накапливать профессиональный рейтинг Xakep Score! Подробнее

Диалоговое окно сообщений для пользователя c#

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

Для начало создадим обычное приложение WinForm и разместим на нем кнопку при нажатии на которое будем выводить сообщения.

Для того что бы вывести обычно сообщения достаточно вписать в метод нажатия кнопки строку:

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

В следующем примере нам придется использовать MessageBoxButtons в качестве передаваемого аргумента. Однако он имеет несколько параметров:

  • MessageBoxButtons.AbortRetryIgnore – Прервать | Повтор | Пропустить
  • MessageBoxButtons.OK— ОК
  • MessageBoxButtons.OKCancel — ОК | Отмена
  • MessageBoxButtons.RetryCancel — Повтор | Отмена
  • MessageBoxButtons.YesNo — Да | Нет
  • MessageBoxButtons.YesNoCancel — Да | Нет | Отмена

Это нам позволит разместить в диалоговом окне сообщение кнопку или кнопки, в зависимости от параметров.

Рассмотрим все примеры с использованием кнопок:

Вариант AbortRetryIgnore


C#: Как эмулировать нажатие клавиш?

Здравствуйте, товарищи программисты!

Я начинающий программист, начал осваивать C# несколько месяцев назад (до этого программированием не занимался). Пишу для себя программу и столкнулся с проблемой. Суть следующая: программа должна работать в фоновом режиме, параллельно с игрой. Ее задача отлавливать клавиатурный ввод и соответствующим образом реагировать. Хук написанный на C#, отлавливающий клавиатурный ввод я нашел (ниже я его выложу), правда, я в нем мало что понял, но нашел фильтрующюю функцию. Реагировать на нажатия определенных клавишь на клавитуре, я тоже разобрался как. Но мне еще нужно модифицировать и послать обратно в систему это сообщение. Т.е. я например нажимаю на клаве одну клавишу, программа должна «нажать» ее несколько раз, или нажать какую-то последовательность клавишь. Функция SendKeys.Send() не помогает, игра не реагирует на нее.

У меня к вам две прозьбы:
1) Напишите мне пояснения к коду который я приложу ниже. Я прочитал пару статей про хуки, но толком ниче не понял. Вы мне просто напишите нормальным языком, какая строка что делает. Но это конечно по желанию)))

2) А главное, скажите что дописать к этому коду, чтоб эмулировать клавиатурный ввод? И тоже если можно с коментариями.

Заранее благодарю за внимание! Да, и это, не отсылайте меня на англоязычные ресурсы и к MSDN, я англ. не понимаю, а переводчик не особо помогает.

using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace myHook
<
static class Program
<
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private static LowLevelKeyboardProc _proc = HookCallback;
private static IntPtr _hook >
[STAThread]
static void Main()
<
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
_hook > Application.Run(new Form1());
UnhookWindowsHookEx(_hookID);
>

private static IntPtr SetHook(LowLevelKeyboardProc proc)
<
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
<
return SetWindowsHookEx(WH_KEYBOARD_LL, proc,
GetModuleHandle(curModule.ModuleName), 0);
>
>

private delegate IntPtr LowLevelKeyboardProc(
int nCode, IntPtr wParam, IntPtr lParam);

[DllImport(«user32.dll», CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);

[DllImport(«user32.dll», CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);

[DllImport(«user32.dll», CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, IntPtr lParam);

[DllImport(«kernel32.dll», CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
>
>

7 ответов

Прототип на C# будет выглядеть примерно так:

[DllImport(«user32.dll»)]
public static extern void keybd_event(Keys bVk, byte bScan, UInt32 dwFlags, IntPtr dwExtraInfo);

public const UInt32 KEYEVENTF_EXTENDEDKEY = 1;
public const UInt32 KEYEVENTF_KEYUP = 2;

Пример на С иллюстрирует использование (переводить было лениво ;) для симуляции нажатия НумЛока.

void SetNumLock( BOOL bState )
<
BYTE keyState[256];

// Simulate a key release
keybd_event( VK_NUMLOCK,
0x45,
KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP,
0);
>
>

hardcase, огромное спасибо. Сработало, правда пример на С пришлось чуть модернизировать, но там я сразу понял что надо переписать. И че я раньше не обратился за помощью, 3 недели потерял.

using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace Primer_keybdEvent
<
static class Program
<
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private static LowLevelKeyboardProc _proc = HookCallback;
private static IntPtr _hook > public const UInt32 KEYEVENTF_EXTENDEDKEY = 1;
public const UInt32 KEYEVENTF_KEYUP = 2;

[STAThread]
static void Main()
<
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
_hook > Application.Run(new Form1());
UnhookWindowsHookEx(_hookID);
>

private static IntPtr SetHook(LowLevelKeyboardProc proc)
<
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
<
return SetWindowsHookEx(WH_KEYBOARD_LL, proc,
GetModuleHandle(curModule.ModuleName), 0);
>
>

private delegate IntPtr LowLevelKeyboardProc(
int nCode, IntPtr wParam, IntPtr lParam);

private static IntPtr HookCallback(int nCode, IntPtr wParam,
IntPtr lParam)
<
int vcCode = Marshal.ReadInt32(lParam);
if ((nCode >= 0) && (wParam == (IntPtr)WM_KEYDOWN)
&& ((Keys)vcCode == Keys.Return))
<
keybd_event(Keys.CapsLock, 0x45, KEYEVENTF_EXTENDEDKEY | 0, (IntPtr)0);
keybd_event(Keys.CapsLock, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, (IntPtr)0);
return (IntPtr)1;
>
return (IntPtr)0;
>

[DllImport(«user32.dll», CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);

[DllImport(«user32.dll», CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);

[DllImport(«user32.dll», CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, IntPtr lParam);

[DllImport(«kernel32.dll», CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);

[DllImport(«user32.dll», EntryPoint = «keybd_event», CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern void keybd_event(Keys bVk, byte bScan, UInt32 dwFlags, IntPtr dwExtraInfo);
>
>

Кстати, функция keybd_event во многих играх не катит, т.к. ввод в играх осуществляется через InputDirect. так что прийдется ковыряться дальше.

Уроки C#

Уроки C# (C sharp) | #1 — Что такое C# и зачем он нужен?

Видеоурок

Благодаря незаурядной мощности языка, на него пал выбор разработчиков движка Unity . Сегодня является одним из топовых движков для игр на Windows. Выпуск и активное использование движка пошли на руку C#, который стал ещё популярнее.

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

Если сравнить С# с прочими языками, его можно назвать довольно молодым, хотя за плечами уже пройден немалый путь. Впервые полноценная версия языка появилось после выхода Microsoft Visual Studio .NET, событие датируется февралём 2002 года. На сегодня актуальная версия — C# 7.0, выпущенная 7.03.2020 параллельно с Visual Studio 2020.

В C Sharp используется синтаксис, сильно напоминающий Си и приближённый к С++ , Java . Если есть познания в одном их перечисленных языков, изучить C# станет значительно легче. Это объектно-ориентированный язык, который немало позаимствовал из С++ и Java. Для примера, С# обладает поддержкой наследственности, полиморфизма, повторную загрузку операторов, статической типизации. Такой подходит помогает в решении распространённых задач в сфере разработки крупных приложений, сохраняющих гибкость, расширяемость и масштабируемость. C# всё ещё развивается, после каждого дополнения в языке появляются новые функции, преимущественно довольно полезные. Среди них: асинхронная работа, переменное связывание, лямбды и т. п.

Какова роль .NET?


Если речь заходит о C#, часто подразумеваются технологии, связанные с платформой .NET (WPF, ASP.NET). То же самое справедливо в обратном направлении, говоря про .NET, думают про C#. Безусловно, понятия имеют жёсткую взаимосвязь, но не являются синонимами. C# — это язык, созданный для взаимодействия с фреймворком .NET. Тем не менее .NET – это довольно широкое понятие.

Сейчас вспоминаются слова Билла Гейтса, не дословно, но смысл таков: « Платформа .NET – лучшее творение Microsoft ». Может так и есть, ведь фреймворком очень мощный и постоянно используется в разработке приложений.

Ключевые черты платформы:

  • Работает параллельно с разными языками. Популярностью С# во многом обязан общеязыковой среде CLR. Сейчас платформа способна работать с С#, VB.NET, C++, F#, но и на этом список не заканчивается, ведь она работает с диалектами, что привязаны к .NET (наподобие Delphi.NET). После компиляции кода с любого из перечисленных языков, вся интерпретируется в общий язык CIL – это своеобразный ассемблер для .NET. Такой подход позволяет использовать несколько языков для создания подключаемых модулей программы;
  • Кроссплатформенность. Данную платформу реально переносить, хоть и есть отдельные ограничения. Сегодня актуальная версия фреймворка работает на всех поддерживаемых Виндовс: от Windows Vista до «десятки». За счёт проекта Mono появилась возможность разрабатывать программы под Linux (различные дистрибутивы), Android и iOS;
  • Обширная библиотека классов. .NET Framework обладает единой, унифицированной библиотекой классов, с которой работают все поддерживаемые языки. Библиотека классов пригодится при создании любых программ: от блокнота до огромного веб-сайта;
  • Масса встроенных технологий. Среда CLR в сочетании с библиотекой классов – это основа для большого пакета вспомогательных технологий. Их могут использовать все программисты во время разработки приложений. В качестве примера, при взаимодействии с базами данных можно использовать технологию ADO.NET. Во время создания графических редакторов с многочисленными функциями удобно использовать WPF. Во время веб-разработки наверняка используют ASP.NET.
Цукерберг рекомендует:  Основы построения ссылок

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

Управляемый и неуправляемый код

Некоторые читатели уже слышали, когда о приложении, построенном на С#, говорят – управляемый код. Какой смысл этого выражения? Это означает, что программа базируется на .NET и поддерживает управление общеязыковой средой CLR. Вы же помните, как CLR самостоятельно очищает память. Существуют и другие приложения, разрабатываемые на C++, они не преображаются в унифицированный CIL-язык (свойственный для С#, VB.NET). На выходе – это стандартный машинный код. Таким приложением .NET не может управлять.

При этом платформа .NET позаботилась о том, чтобы была возможность работать даже с неуправляемым кодом. Помимо обычных классов, предоставляемых библиотекой .NET, есть возможность применять сборки COM.

JIT-компиляция

Исходный код C# компилируется в программы или отдельные сборки на CIL с расширениями dll, exe. В процессе запуска готового приложения выполняется JIT-компиляция – это сокращение от Just-In-Time (Просто сейчас). На выходе получается машинный код, который передаётся на исполнение.

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

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

Это все базовые знания, которые нужно иметь в отношении платформы .NET

Дополнительные курсы

На нашем сайте вы можете найти дополнительные курсы по языку C#. Все курсы представлены на этой странице .

C# для чайников

В ступление

Платформа .NET позволяет создавать распределенные приложения.

Преимуществами распределенных приложений являются:

  • возможность сконцентрировать в подходящих местах программный код, выполняющий специализированные задачи.
    Т.е. становится не нужно на каждой машине поддерживать программное обеспечение, выполняющее все функции
  • разные платформы могут использовать один и тот же код за счет того, что это специализированное программное обеспечение имеет общеизвестный интерфейс.
    Например сотовые телефоны с их специализированным программно-аппаратным обеспечением могут использовать код web-серверов реализованных по-другому.
  • Становится возможным предоставление платных услуг, например, вычислительных мощностей или информации.
    Здесь фирма предоставляющие услуги владеет одной частью системы, а пользователи — другой.
  • С точки зрения разработчика, платформа .NET это совокупность Common Language Runtime (CLR), .NET Framework Classes и высокоуровневых средств, таких как WinForms и Active Server Pages (ASP .NET)

    Common Language Runtime управляет выполнением кода, написанного для платформы .NET, Framework Classes позволяют работать с операционной системой, WinForms нужны для создания пользовательского интерфейса, а ASP для формирования web-страниц.

    Код для платформы может быть скомпилирован из исходных текстов, написанных на разных языках. Один из таких языков — C#.

    Шаг 2. Синтаксис C#

    Принято начинать описание языка с примера Hello World. Можете посмотреть этот

    Прежде всего, нужно сказать, что C# учитывает регистр идентификаторов. Компилятор выдаст ошибку, если, к примеру, написть слово Console с маленькой буквы.

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

    менее читабельно, чем

    В C# не бывает операторов вне функций, а функций вне классов. Поэтому в примере описан класс World и функция Main. Выполнение программы начинается с метода Main одного из классов программы. Стоит обратить внимание на то, что Main пишется с заглавной (большой) буквы. Имя класса может отличаться от имени того файла, в котором класс находится.

    Директивы using позволяют сократить имена идентификаторов из используемых библиотек. Так, например, объект Console на самом деле называется System.Console, но так как используется директива using, можно писать просто Console.

    Комментарии в C# бывают нескольких видов:

    • до конца строки — //
    • многострочные — /* */
    • для документации — ///

    Строки

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

    В C# есть два вида такой замены.

    1. Использование замен при помощи символа


    Символ, который надо заменить Цепочка
    «
    \\
    Звонок \a
    Забой \b
    Перевод страницы \f
    Новая строка \n
    Возврат каретки \r
    Табуляция \t
    Вертикальная табуляция \v
    Символ Unicode, заданный своим номером, например u200 \u
    Символ Unicode, заданный своим номером в 16-ричной системе счисления, например xc8 \x
    Символ с кодом ноль \0

    2. Строки с удвоенными кавычками (как в ZX Spectrum)
    Здесь нужно поставить перед строкой символ @ а затем удваивать кавычки внутри строки. Если такая строка занимает несколько строк программы, то будут сохранены символы перевода на новую строку и пробелы.

    Пример: если нужно записать строку

    то можно писать так:

    Переменные

    переменные в C# обязательно имеют тип и могут содержать только объекты этого типа (и производных).

    Есть три вида переменных

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

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

    Переменные-значения

    Ключевые слова языка C# отображаются (отображаются — являются сокращениями для имен) на типы пакета System, поэтому во второй колонке приведены названия этих типов

    тип C# тип из .Net Framework Знаковый бит Сколько байтов Граничне значения
    sbyte System.Sbyte есть 1 от -128 до 127
    short System.Int16 есть 2 от -32768 до 32767
    int System.Int32 есть 4 от -2147483648 до 2147483647
    long System.Int64 есть 8 от -9223372036854775808 до 9223372036854775807
    byte System.Byte нет 1 от 0 до 255
    ushort System.Uint16 нет 2 от 0 до 65535
    uint System.UInt32 нет 4 от 0 до 4294967295
    ulong System.Uint64 нет 8 от 0 до 18446744073709551615
    float System.Single есть 4 Примерно от ±1.5 x 10 -45 до ±3.4 x 10 38 , 7 значащих цифр
    double System.Double есть 8 Примерно от ±5.0 x 10 -324 до ±1.7 x 10 308 , 15 или 16 значащих цифр
    decimal System.Decimal есть 12 Примерно от ±1.0 x 10 -28 до ±7.9 x 10 28 , 28 или 29 значащих цифр
    char System.Char не применимо 2 любой символ Unicode (16-ти битный)
    bool System.Boolean не применимо 1 / 2 true и false

    Есть еще (immutable) класс string , объекты которого обязаны всегда создаваться заново, поэтому после выполнения кода

    строка s1 будет равна «goodbye», а s2 — «hello»

    Переменные — ссылки

    Переменные этого вида на самом деле хранят адрес начала памяти, в которой находятся данные, на которые эти переменные ссылаются.

    Новые типы могут быть определены при помощи конструкций ‘class’, ‘interface’ и ‘delegate’.

    Boxing

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

    Перечисления

    Перечисление — это тип, объекты которого могут иметь значения только из заданного набора. При определении типа можно указать значения, которые будут образовывать такой набор. Например это могут быть дни недели, месяцы года, виды валют, поддерживаемые системой, или что-то еще (что?).

    По умолчанию базовым типом для перечисления является тип integer. Первому значению сопоставляется число ноль, следующему 1 и т.д. (поэтому Sunday == 6). После последнего значения можно ставить запятую, а можно и не ставить

    Можно изменить базовый тип для перечисления

    Кроме того, можно задать значения первому элементу перечисления (последующие будут пронумерованы автоматически) или даже каждому элементу

    Можно распечатать символьное название константы (используя ToString())

    Здесь функция WriteLine заменяет на n-ый аргумент функции после строки

    Операторы

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

    Создание и генерация исключений (Руководство по программированию C#) Creating and Throwing Exceptions (C# Programming Guide)

    Исключения позволяют обозначить, что во время выполнения программы произошла ошибка. Exceptions are used to indicate that an error has occurred while running the program. Объекты исключений, описывающие ошибку, создаются и затем вызываются с помощью ключевого слова throw. Exception objects that describe an error are created and then thrown with the throw keyword. Далее среда выполнения ищет наиболее совместимый обработчик исключений. The runtime then searches for the most compatible exception handler.

    Программисты должны вызывать исключения при выполнении одного или нескольких из перечисленных ниже условий. Programmers should throw exceptions when one or more of the following conditions are true:

    Метод не способен выполнить свои функции. The method cannot complete its defined functionality.

    Например, если значение параметра метода является недопустимым: For example, if a parameter to a method has an invalid value:

    На основе состояния объекта выполнен неправильный вызов объекта. An inappropriate call to an object is made, based on the object state.

    В качестве примера можно привести попытку записи в файл, доступный только для чтения. One example might be trying to write to a read-only file. В случаях, когда состояние объекта не допускает выполнения операции, вызывается экземпляр InvalidOperationException или объекта на основе наследования этого класса. In cases where an object state does not allow an operation, throw an instance of InvalidOperationException or an object based on a derivation of this class. Ниже приведен пример метода, который вызывает объект InvalidOperationException: This is an example of a method that throws an InvalidOperationException object:

    Когда аргумент метода вызывает исключение. When an argument to a method causes an exception.


    В этом случае должно быть перехвачено исходное исключение и создан экземпляр ArgumentException. In this case, the original exception should be caught and an ArgumentException instance should be created. Исходное исключение должно передаваться конструктору ArgumentException в качестве параметра InnerException: The original exception should be passed to the constructor of the ArgumentException as the InnerException parameter:

    Исключения содержат свойство с именем StackTrace. Exceptions contain a property named StackTrace. Строка содержит имена методов в текущем стеке вызовов вместе с именем файла и номером строки, в которой было вызвано исключение для каждого метода. This string contains the name of the methods on the current call stack, together with the file name and line number where the exception was thrown for each method. Объект StackTrace создается автоматически средой CLR из точки оператора throw , так что исключения должны вызываться из той точки, где должна начинаться трассировка стека. A StackTrace object is created automatically by the common language runtime (CLR) from the point of the throw statement, so that exceptions must be thrown from the point where the stack trace should begin.

    Цукерберг рекомендует:  Как быстро обучиться программированию

    Все исключения содержат свойство с именем Message. All exceptions contain a property named Message. Эта строка должна содержать сообщение с объяснением причины исключения. This string should be set to explain the reason for the exception. Обратите внимание, что важные с точки зрения безопасности сведения не следует помещать в текст сообщения. Note that information that is sensitive to security should not be put in the message text. Помимо Message, ArgumentException содержит свойство с именем ParamName, которому должно присваиваться имя аргумента, ставшего причиной возникновения исключения. In addition to Message, ArgumentException contains a property named ParamName that should be set to the name of the argument that caused the exception to be thrown. Для метода задания свойства ParamName должно получать значение value . In the case of a property setter, ParamName should be set to value .

    Открытые и защищенные методы должны вызывать исключения каждый раз, когда не удается выполнить назначенные им функции. Public and protected methods should throw exceptions whenever they cannot complete their intended functions. Вызываемый класс исключения должен быть самым конкретным доступным исключением, удовлетворяющим условиям ошибки. The exception class that is thrown should be the most specific exception available that fits the error conditions. Эти исключения должны документироваться в составе функций класса, а производные классы или обновления исходного класса должны сохранять то же поведение для обеспечения обратной совместимости. These exceptions should be documented as part of the class functionality, and derived classes or updates to the original class should retain the same behavior for backward compatibility.

    Чего следует избегать при вызове исключений Things to Avoid When Throwing Exceptions

    Ниже приводятся рекомендации по тому, чего следует избегать при вызове исключений. The following list identifies practices to avoid when throwing exceptions:

    Исключения не рекомендуется использовать для изменения потока программы в рамках обычного выполнения. Exceptions should not be used to change the flow of a program as part of ordinary execution. Исключения следует использовать только для сообщения о состояниях ошибки и их обработки. Exceptions should only be used to report and handle error conditions.

    Исключения должны генерироваться, а не возвращаться в качестве возвращаемого значения или параметра. Exceptions should not be returned as a return value or parameter instead of being thrown.

    Не рекомендуется создавать исключения, которые могут вызываться в режиме отладки, а не в режиме выпуска. Do not create exceptions that can be thrown in debug mode but not release mode. Чтобы определить ошибки времени выполнения на этапе разработки, используйте Debug Assert. To identify run-time errors during the development phase, use Debug Assert instead.

    Определение классов исключений Defining Exception Classes

    Программы могут вызывать предопределенный класс исключений в пространстве имен System (кроме указанных ранее случаев) или создавать собственные классы исключений путем наследования от Exception. Programs can throw a predefined exception class in the System namespace (except where previously noted), or create their own exception classes by deriving from Exception. Производные классы должны определять по крайней мере четыре конструктора: один конструктор без параметров, один конструктор, задающий свойство сообщения, и еще один, задающий свойства Message и InnerException. The derived classes should define at least four constructors: one parameterless constructor, one that sets the message property, and one that sets both the Message and InnerException properties. Четвертый конструктор служит для сериализации исключения. The fourth constructor is used to serialize the exception. Новые классы исключений должны быть сериализуемыми. New exception classes should be serializable. Например: For example:

    Новые свойства следует добавлять к классу исключений только в том случае, если данные в них могут помочь в разрешении исключения. New properties should only be added to the exception class when the data they provide is useful to resolving the exception. При добавлении новых свойств в производный класс исключений метод ToString() необходимо переопределить так, чтобы он возвращал добавленные сведения. If new properties are added to the derived exception class, ToString() should be overridden to return the added information.

    Спецификация языка C# C# Language Specification

    Дополнительные сведения см. в разделах Исключения и Оператор throw в Спецификации языка C#. For more information, see Exceptions and The throw statement in the C# Language Specification. Спецификация языка является предписывающим источником информации о синтаксисе и использовании языка C#. The language specification is the definitive source for C# syntax and usage.

    Защищаем приложение, написанное на C#

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

    К сожалению, дотнетовские программы, равно как джавовские, довольно-таки просто «вскрыть». Виной всему байт-код, позволяющий специальными программами легко дизассемблировать и воссоздать первоначальный код. Далеко ходить не нужно за примерами, так как даже VS поставляется с дизассемблером ILDasm.

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

    Методы защиты C# приложения

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

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

    Как я уже писал, главная проблема дотнетовских программ, равно как джавашных – легкий способ получения исходников. Да, получить исходный код сейчас просто плевое дело. Например, можно воспользоваться бесплатным dotPeek от JetBrains. Фактически, основанный на базе известного Resharper от этой же студии, данный инструмент позволяет легко и непринужденно вскрыть внутренности исследуемой программы, если незадачливый программист не позаботился о ее своевременной защите.

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

    • Декомпиляция сборок .NET версий в исходный код C# и IL-код

    Для отображения декомпилированного кода dotPeek использует большинство функций, привычных пользователям Microsoft Visual Studio: открытие декомпилированных файлов в отдельных вкладках, подсветка синтаксиса, сворачивание блоков кода, нумерация строк и многое другое.

    2) Преобразование и экспорт сборок .NET в проекты Microsoft Visual Studio

    Если вы хотите не только исследовать сборку, но и внести в нее изменения, dotPeek позволит вам преобразовать и сохранить ее в проект Microsoft Visual Studio и, таким образом, продолжить работу уже с исходным кодом сборки.

    Занятная тулза, не так ли? Но самое главное – dotPeek абсолютно бесплатный, в отличие от «дедушки» .NET Reflector, который раньше был едва ли не стандартом де-факто для декомпиляции дотнетовских приложений. Так как вам все равно нужно будет смотреть то, насколько хорошо вы защитили свое приложение, то dotPeek должен быть у вас всегда. Скачать его можно на сайте https://jetbrains.ru/products/dotpeek/

    Естественно, что когда все знают о том, что программу на C# может «взломать» любой, способный крякнуть игру, начинается шевеление и волнение. В итоге, нужно устранить очевидные проблемы в защите.

    • Как бы это банально не звучало, но для начала сделаем обфускациюприложения. Иными словами, мы максимально запутаем исходный код, но сохраним функциональность. Достаточно действенный способ, если бы не одно «но» — на публичные обфускаторы есть масса деобфускаторов. Кроме того, основная масса обфускаторов платные. Вы без труда найдете обзоры наиболее «распиаренных». Могу лишь сказать, что часто их функционал оставляет желать лучшего. Иногда после такой обфускации программа может даже перестать нормально работать, особенно, если вы прошлись по ней взломанным обфускатором. Конечно, Майкрософт в свои студии разработки вставляла бесплатный Dotfuscator Software Services.
    • Вернее, он бесплатный только для личного использования, для бизнеса он стоит ну очень много убитых енотов. Он уже интегрирован в Visual Studio. Честно, помню недовольные отзывы о нем в плане неочевидности и прочего, но как по мне, пользоваться им достаточно просто. Да, есть хромые места, но идеальных обфускаторов, думаю вообще не существует. В любом случае, начните хотя бы с него. По крайней мере, у него есть также и защита от отладки. Для новичков он будет весьма и весьма кстати.

    Еще один обфускатор, который лично мне нравится – это пресловутый ConfuserEx. Он опенсорсный и дает весьма сильную защиту. Например, можете увидеть то, как он «путает» код и не дает прочитать его с помощью еще одного исследователя ILSpy.

    Скачать его можете на https://yck1509.github.io/ConfuserEx/. Тем не менее, его можно все же снять небезызвестным De4dot, при условии, что реверсер его правильно определит, имейте это в виду.

    2 ) Крипторы и пакеры. На самом деле, хотя и дают сильную защиту, но большинство проектов попросту брошены или они стоят безумно больших денег. Поэтому на них я останавливаться не стану.

    3) Новые студии разработки (начиная с 2015) меня больше радуют. Майкрософт разработала технологию .NET Native, позволяющую скомпилировать дотнетовское приложение в нативный код.

    А вот этот момент весьма и весьма интересен, так как для реверсера предстанет весьма любопытный плюсовский код, «приправленный» автоматическим кодом AOT-компилятором .NET. Это очень усложнит задачу по взлому и реверсингу приложения. Фактически, я бы посоветовал его. Но проблема есть и у этого способа – все будет только работать на майкрософтовской платформе.

    Резюме

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

    C# приложения были изначально уязвимы для реверсинга. В этом плане, они не сильно далеко ушли даже от того же JS, хотя там вообще все очевидно. Обфускация запутает код и инструменты типа dotPeek или ILSpy. Но важно понимать, что все они обрасли дополнительными плагинами, которые позволяют определить защиту и всячески ее снять. Тем не менее, пренебрегать ими не стоит.

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

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

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