WinAPI из C#
Язык программирования C# был создан как язык, который можно использовать для простого программирования в ОС Windows. Позже этот язык получил возможность создавать приложения и на других операционных системах, но в этой статье мы будем говорить только об ОС Windows.
Для работы с операционной системой С# использует платформу .Net — по сути, высокоуровневую обертку для WinAPI функций. Для того чтобы выполнить элементарные операции нужно просто найти нужный класс/функцию и передать необходимый набор параметров.
Но всё становится сложнее, если нужно работать с функциями, которые не имеют оберток для .Net или когда требуется низкоуровневый доступ к структурам данных или нативному коду. Статья расскажет о нескольких способах использования функций WinAPI из C#.
managed и unmanaged код
С# используется для разработки программного беспечения поверх платформы .NET. Эта платформа различает несколько версий работы приложения:
managed code
unmanaged code
В первом случае это среда выполнения программ, где есть жествие правила взаимодействия с ресурсами и операционной системой. Тоесть там сущесутвуют механизмы, которые отлавливают ошибки, неверное образение к памяти и помогают программисту сосредоточиться именно на написании алгоритма.
Второй же пример включает в себя традиционное окружение, которое присуще языкам программирования вроде Assembly, C, C++. Там все операции с данными и алгоритмы должны быть четко определены программистом и все неверные действия он должен предусмотреть самостоятельно.
Большое количество библиотек, которые позволяют работать с операционной системой уже переведены на .NET, но есть и те, которые не переведены или не могут быть переписаны в силу особенностей работы алгоритма или наличия команды, которая могла бы портировать код. При разработке ПО может потребоваться использовать такие библиотеки. И в этом случае нужно как-то запускать unmanaged код. Специально для этого в C# существует фича, которая позволяет просто ссылаться на уже собранный файл и зная название и параметры функций просто их вызывать напрямую из библиотек. Фича называется P/Invoke
или Platform Invoke.
С помощью Platform Invoke можно работать с любыми функциями, но необходимо учитывать некоторые особенности. Основная особенность — различие типов. Безопасность C# и платформы .NET в первую очередь строится на введение специальных типов, с которыми работает платформа. Типы, которые применяются в документациях и уже готовых библиотеках могут отличаться и поэтому чтобы была возможность работать со сторонним кодом корректно, нужно определять в коде C# функции специальным образом и проводить маршаллинг
типов данных. Если по-простому это сопоставление аналогичных типов данных между типами данных языка на которм была написана бибилиотека и типами данных, которые есть в C#. Попробуем провести простые эксперименты.
Пример использования PInvoke
Для того чтобы создать приложение, которое будет использовать P/Invoke, создадим новый проект в Visual Studio. Для этого выберем консольное приложение для платформы Windows:
Для работы с P/Invoke нужно добавить using System.Runtime.InteropServices.
И сами функции, так как они будут вызываться за пределами платформы .NET, то их нужно описать с помощью класса DllImportAttribute.
Но класс так же может быть использован для описания дополнительных характеристик, например, можно с помощью атрибута CharSet = CharSet.Unicode явно указать какая кодировка используется для работы функции в приложении. По факту такое описание WinAPI дает возможность .Net платформе задавать статические адреса для вызова алгоритмов функций. Попробуем нарисовать MessageBox и показать его на экране:
И результат выполнения:
Вроде бы ничего сложного, описание метода→сопоставление типов данных→profit. Но это в маленьком проекте, а что делать, если таких функции десятки и больше? Постоянно совмещать типы данных может стать нетривиальной задачей. Специально для этого, ну и для того чтобы помочь комьюнити MS сделали проект, который должен помочь реализовывать все описанные выше действия намного проще.
win32metadata
Уже сейчас существует пререлизная версия проекта, который позволяет в автоматическом режиме генерировать код, который будет создавать определения для функций WinAPI и транслировать типы данных. Этот проект можно найти здесь. Проект официально поддерживается MS и призван упростить использование WinAPI для С#. Вообще проект имеет еще несколько параллельных версий, которые для языков отличных от C# так же предоставляют возможность с помощью нативным методов и типов данных для яхыка программирования использовать WinAPI.
Для того чтобы использовать проект, нужно выполнить ряд рекомендаций:
Visual Studio не ниже 2019
Тип Проекта, который включает в себя либо 5, либо 6 версию .Net. Последняя предпочтительнее
Заходим в директорию проекта и одбавляем packadge:
dotnet add package Microsoft.Windows.CsWin32 --prerelease
Создаем в проекте файл с именем NativeMethods.txt
в этом файле нужно указать название функций. На каждой строке должно быть 1 имя, можно использовать знак *
.
После этого пишем код, который будет его использовать. Несмотря на официальный Readme, нужно использовать namespace Microsoft.Windows.Sdk. Кстати, с новым типом проекта это будет выглядеть вот так:
Результат работы:
Таким образом можно упростить использование WinAPI функций в своем проекте. Это позволит не записывать функции вручную и долго мучаться над транслированием типов данных и сосредоточиться на алгоритме приложения. Кстати, проект обещают развивать и дальше, чтобы можно было пистать более сложные приложения.
В последние рабочие дни хотим анонсировать запуск нового потока курса C# Developer. Professional, который стартует уже в январе.
Узнать подробнее о курсе можно тут.