Windows api window functions

Вызов функций Windows API

Из книги C#. Советы программистам (в сокращении)

Программный код, который выполняется под управлением CLR (Common Language Runtime, т. е. общая среда выполнения языков), называется управляемым (managed) кодом. Программный код, выполняющийся вне среды выполнения CLR, называется неуправляемым (unmanaged) кодом. Примером неуправляемого программного кода служат функции Win32 API, компоненты COM, интерфейсы ActiveX. Несмотря на большое количество классов .NET Framework, содержащих множество методов, программисту все равно приходится иногда прибегать к неуправляемому коду. Надо сказать, что число вызовов неуправляемого кода уменьшается с выходом каждой новой версии .NET Framework. Microsoft надеется, что наступит такое время, когда весь код можно будет сделать управляемым и безопасным. Но пока реальность такова, что без вызовов функций Windows API нам пока не обойтись. Но сначала немного теории.

Управляемый код .NET Framework может вызывать неуправляемую функцию из DLL (функцию Windows API) при помощи специального механизма Platform Invoke (сокр. P/Invoke). Для того чтобы обратиться к какой-нибудь неуправлямойнеуправляемой библиотеке DLL, вы должны преобразовать .NET-объекты в наборы struct, char* и указателей на функции, как того требует язык C. Как сказали бы программисты на своем жаргоне — вам нужно маршалировать параметры. Более подробно о маршалинге (Marshalling) вам следует почитать в документации. Чтобы вызвать DLL-функцию из C#, сначала ее необходимо объявить (программисты, имеющие опыт работы с Visual Basic 6.0, уже знакомы с этим способом). Для этого используется атрибут DllImport:

Иногда в примерах вы можете также встретить такой способ (длинный и неудобный): [System.Runtime.InteropServices.DllImport(«User32.Dll»)]. , но это на любителя.

Атрибут DllImport сообщает компилятору, где находится точка входа, что позволяет далее вызывать функцию из нужного места. Вы должны всегда использовать тип IntPtr для HWND, HMENU и любых других описателей. Для LPCTSTR используйте String, а сервисы взаимодействия (interop services) выполнят автоматический маршаллинг System.String в LPCTSTR до передачи в Windows. Компилятор ищет указанную выше функцию SetWindowText в файле User32.dll и перед ее вызовом автоматически преобразует вашу строку в LPTSTR (TCHAR*). Почему это происходит? Для каждого типа в C# определен свой тип, используемый при маршалинге по умолчанию (default marshaling type) . Для строк это LPTSTR.

Вызов функций Windows API, имеющих выходной строковый параметр char*

Предположим, нам необходимо вызвать функцию GetWindowText, у которой имеется строковый выходной параметр char*. По умолчанию, для строк используется LPTSTR, но если мы будем использовать System.String, как было сказано выше, то ничего не произойдет, так как класс System.String не позволяет модифицировать строку. Вам необходимо использовать класс StringBuilder, который позволяет изменять строки.

Тип, используемый для маршашлинга StringBuilder по умолчанию, — тоже LPTSTR, зато теперь GetWindowText может модифицировать саму вашу строку:

Таким образом, ответом на вопрос, как вызывать функцию, у которой есть выходной строковый параметр, будет — используйте класс StringBuilder.

Изменение типа, применяемого для маршалинга по умолчанию

Например, мы хотим вызвать функцию GetClassName, который принимает параметр LPSTR (char*) даже в Unicode-версиях. Если вы передадите строку, общеязыковая исполняющая среда (CLR) преобразует ее в серию TCHAR. Но с помощью атрибута MarshalAs можно переопределить то, что предлагается по умолчанию:

Теперь, когда вы вызовете GetClassName, .NET передаст вашу строку в виде символов ANSI, а не «широких символов».

Вызов функций, требующих struct

Возьмем для примера функцию GetWindowRect, которая записывает в структуру RECT экранные координаты окна. Чтобы вызвать функцию GetWindowRect и передать ей структуру RECT нужно использовать тип struct в сочетании с атрибутом StructLayout:

Важно использовать ref, чтобы CLR передала параметр типа RECT как ссылку. В этом случае функция сможет модифицировать ваш объект, а не его безымянную копию в стеке. После такого объявления функции можно ее вызвать в коде:

Читайте также:  Как перезапустить сервер печати windows 10

Обратите внимание, что ref используется и в объявлении, и при вызове функции. Тип, по умолчанию применяемый для маршалинга типов struct — по умолчанию LPStruct, поэтому необходимости в атрибуте MarshalAs нет. Но если вы хотите использовать RECT в виде класса, а не struct, вам необходимо реализовать оболочку:

Работа с функциями обратного вызова в C#

Для использования функций, написанных на C#, в качестве функций обратного вызова Windows, нужно использовать делегаты (delegate).

Объявив свой тип делегата, можно написать оболочку для функции Windows API:

Так как в строке с delegate просто объявляется тип делегата (delegate type), сам делегат нужно предоставить в классе:

а затем передать оболочке:

Проницательные читатели заметят, что я умолчал о проблеме с lparam.

В языке C, если в EnumWindows дается LPARAM, Windows будет уведомлять вашу функцию обратного вызова этим LPARAM. Обычно lparam — указатель на некую структуру или класс, который содержит контекстную информацию, нужную вам для выполнения своих операций. Но запомните: в .NET слово «указатель» произносить нельзя! Так что же делать? Можно объявить ваш lparam как IntPtr и использовать GCHandle в качестве его оболочки:

Не забудьте вызвать Free, когда закончите свои дела! Иногда в C# приходится самому освобождать память. Чтобы получить доступ к «указателю» lparam внутри перечислителя, используйте GCHandle.Target.

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

Небольшая программа ListWin (Приложение ListWin.cs), которую я написал для перечисления окон верхнего уровня, позволяет просматривать списки HWND, имен классов, заголовков и/или прямоугольников окон, используя RECT или Rectangle. Исходный код ListWin показан не полностью; весь исходный код можно скачать по ссылке, приведенной в конце статьи.

Создание собственной управляемой библиотеки

Можно создать собственную управляемую библиотеку, из которой можно будет вызывать функции Windows API. Для этого в Visual Studio предусмотрены специальные опции. Новый проект создается как библиотека классов (Class Library). Сборка при этом автоматически получает расширение dll. Использовать управляемую библиотеку в управляемом коде просто. Для этого надо добавить ссылку (используя меню Project | Add Reference…) на библиотечную сборку, указав месторасположение сборки в соответствующем диалоговом окне. После этого Visual Studio копирует сборку в директорию, в которой располагается разрабатываемый код. Далее в коде программы используется либо оператор using, либо полное имя библиотечного модуля с точечной нотацией. Все библиотечные классы и методы готовы к использованию в коде программы.

Также можно воспользоваться командной строкой. Чтобы скомпилировать класс Win32API.cs, введите:

В результате у вас будет создан файл Win32API.dll, доступный для любого проекта на C#.

Пример создания библиотеки и использования функций Windows API находится в папке Win32 на прилагаемом к книге диске.

Примеры использования функций API

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

  • Блокировка компьютера — Если вам необходимо блокировать компьютер, то вызовите функцию LockWorkStation. Результат работы примера будет аналогичен нажатию комбинации клавиш Win+L или клавиш Ctrl+Alt+Del с последующим выбором кнопки (или команды меню) Блокировка.
  • Является ли текущий пользователь администратором? — Если необходимо удостовериться, что текущий пользователь имеет права администратора, то можно вызвать функцию IsUserAnAdmin.
  • Мигание заголовка формы — Наверное, вам приходилось видеть, что заголовок окна вдруг начинал мигать, привлекая ваше внимание. Подобный эффект реализуется вызовом функций FlashWindow или FlashWindowsEx.
  • Форматирование дисков — Чтобы вызвать стандартное диалоговое окно форматирования дисков нужно воспользоваться функцией SHFormatDrive
  • Открытие и закрытие лотка привода компакт-дисков — Наверное, при работе с утилитами, прожигающими компакт-диски CD-R и CD-RW, вы замечали, что у них имеется возможность извлекать компакт-диск из привода программным путем. Неплохо бы научиться делать то же самое при помощи C#. Для этого используем функцию mciSendString в связке с специальными командами, которые и позволят нам открывать и закрывать лоток привода компакт-дисков
  • Создание собственного пункта в системном меню — У большинства окон в Windows имеется так называемое системное меню. Внешний вид, как правило, у всех меню одинаков, но иногда попадаются программы, у которых в системном меню имеются свои собственные пункты. Естественно, любого программиста разбирает любопытство — а как реализовать эту функциональность в своей программе. На данный момент .NET Framework не предоставляет такого полезного свойства как Form.SystemMenu или что-то в этом роде. Поэтому придется прибегать к помощи механизма P/Invoke для вызовов функций Windows API. Опытные программисты (особенно имеющие опыт работы с языком С++) знают, что для модификации системного меню используется функция GetSystemMenu, а также вспомогательная функция AppendMenu, которая позволяет добавлять в меню разделители, картинки, галочки и сам текст.
  • Извлечение значков из файлов — Функция ExtractIcon позволяет извлекать значки из ресурсов, которые зашиты в файлах EXE, DLL, CPL и др. Кроме того, функция позволяет подсчитать количество значков, находящихся в файле. В качестве испытуемого файла возьмем динамическую библиотеку shell32.dll, которая имеется в любой версии Windows.
  • Вызов диалогового окна Смена значка — Существует такая функция Windows API как PickIconDlg. Долгое время она была официально не документирована, но, начиная, с Windows 2000 компания Microsoft все-таки выложила описание этой функции на сайте MSDN. Функция PickIconDlg вызывает стандартное диалоговое окно «Смена значка», позволяющее выбрать значок из модуля. Тем самым, мы можем предоставить пользователю возможность самому выбирать нужный значок, после чего и вывести его на форму (или произвести другие операции).
  • Панель задач, кнопка Пуск и часы в области уведомлений — Очень часто программисты хотят получить доступ к стандартным элементам интерфейса Рабочего стола Windows. Например, разработчики хотят получить координаты панели задач, программно нажать на кнопку Пуск, спрятать и показать эту кнопку Пуск и многое другое.
  • Смена обоев Рабочего стола — Если вы хотите периодически менять картинку на своем Рабочем столе, то можете это сделать программным способом прямо из своего приложения. Для смены обоев Рабочего стола вызывается одна функция Windows API SystemParametersInfo.
Читайте также:  Пробный период для windows server 2012

Заключение

Несмотря на огромное число имеющихся классов .NET Framework, программисту по-прежнему приходится прибегать к вызовам системных функций Windows API. В папке Win32Help на прилагаемом к книге компакт-диске вы найдете демо-версию справочника по функциям Windows API для .NET Framework. Если вам понравится этот справочник, то вы можете приобрести его полную версию на моем сайте.

Windows API main functions

last modified July 16, 2020

In this part of the Windows API tutorial, we will talk about main functions.

The main function prototypes

The main() function is an entry point to a C program. However, it is not the first program to run. When the entry point is main() , the program execution actually begins in a function called mainCRTStartup() . This function is located in the C runtime library. It initialises things like the memory manager, file I/O support, and the argv parameter. After that, the mainCRTStartup() function will call the main() function.

These are the function prototypes for the main() function for the classic console program.

The above source code presents an example of a classic console C program.

This is the output of the ClassicConsole.exe program.

The wmain function prototypes

The previous main function prototypes could receive only ASCII characters. If we want a program that could receive wide characters from the command line, we will use the wmain() function prototypes.

The above wmain() function prototypes receive wchar_t characters on the command line. When we use these prototypes, the execution begins in a function called wmainCRTStartup() which will later call the wmain() function.

We have a wmain() function which can receive wide characters. The example prints the first argument of the console program. To insert command line arguments in Pelles C, we go to Project options and select the General tab. There is an edit box called Command line arguments.

Читайте также:  Сетевой адаптер не имеет доступных параметров настройки ip windows 10 ethernet

The wchar_t type of the second parameter of the wmain() function tells us that the program input is in wide characters.

The GetStdHandle() function returns a handle to the standard output.

In case of an error, we receive the INVALID_HANDLE_VALUE return code. For this situation we print an error message. The GetLastError() function retrieves last error code value.

We use the WriteConsoleW() function to write to the console in wide characters.

The CloseHandle() function closes the opened handle to the standard output.

We pass a Russian word (compiler) as a parameter to our program. The program simply prints the parameter back to the console. Note that in order to see correct characters, we need to change the default font of the console to Lucida Console. We need a true type font to display wide characters correctly.

The _tmain function prototypes

The _tmain() function is a Microsoft extension. It enables programmers to easily create both ANSI and UNICODE builds of their programs. It is a C macro that translates to wmain() or main() functions, depending whether the _UNICODE constant is defined or not. It was common in the past to create both ANSI and UNICODE builds. Nowadays, many programmers recommend to create only Unicode programs. This is also what we will do in this tutorial. We will create mostly Unicode programs.

These are the _tmain function prototypes. The TCHAR macro translates either to char or to wchar_t . It is controlled by the UNICODE constant.

The example prints its first argument if available.

Here we define two constants. These definitions mean that we are going to build a Unicode program. They translate C macros in C runtime and Windows header files. The _UNICODE constant translates macros in the C runtime. (These macros start with an underscore.) The UNICODE constant translates macros in the Windows header files.

We include the definition of the TCHAR macro. The macro is affected by the UNICODE constant.

We must include this header file for the _tmain and _tcslen macros. They are translated depending on the _UNICODE constant.

The _tmain() function translates in our case to wmain() and the TCHAR macro to wchar_t .

The WriteConsole() macro is transleted to the WriteConsoleW() function. The WriteConsoleW() writes output to the console. The _tcslen macro is translated to wcslen() function; it returns the lenght of the wide string.

The program takes another Russian word (operating system) as a parameter and prints it to the console.

The WinMain function prototypes

So far we had console main functions. For graphical user interface development, we use one of the WinMain function prototypes.

These three function prototypes are used for entry points for Windows GUI applications. The wWinMain() function’s pCmdLine parameter contains the command-line arguments as a Unicode string. The WinMain() function’s pCmdLine parameter contains the command-line arguments as an ANSI string. The _tWinMain is a C macro that translates to other two function prototypes, depending whether the _UNICODE constant is defined.

When the entry point is WinMain() , the execution of the program begins in WinMainCRTStartup() . In case of wWinMain() , the execution begins in wWinMainCRTStartup() .

This code shows a small message box on the screen. It displays the first command line argument.

The third parameter of the wWinMain() function is a PWSTR (pointer to wide string). It accepts wide characters.

Figure: A message box

In this part of the Windows API tutorial, we have mentioned main functions.

Оцените статью