Тверской государственный университет
Опубликован: 13.09.2006 | Доступ: свободный | Студентов: 3491 / 369 | Оценка: 4.65 / 4.29 | Длительность: 30:37:00
Специальности: Программист, Менеджер
Лекция 7:

WinApi

Примеры работы с Win32 API функциями

Разговор об особенностях вызова Win32 API функций еще не закончен. Тем не менее, пора прервать общее изложение и обратиться к примерам. Многое из того, что было сказано, целесообразно проиллюстрировать примерами работы с конкретными функциями Win 32 API. Каждый из наших примеров будет посвящен работе с некоторой группой функций.

Работа с окнами

Как мы уже говорили, окна - это один из основных объектов операционной системы. Функции для работы с ними находятся, в основном, в библиотеке User32. Из большого множества функций мы отобрали несколько функций, позволяющих продемонстрировать, как можно получать описатели окон, как, зная описатель, можно получать характеристики окон и как можно изменять характеристики окон. Начнем с приведения программного текста, а уж потом подробно прокомментируем его. Заметим, что для получения корректного описания операторов Declare, используемых типов данных и констант мы использовали API Viewer и описание функций, которое можно найти на уже упоминавшемся сервере Microsoft.

В проекте нашего тестового документа был создан модуль "Окна" и в разделе его объявлений помещен следующий текст:

Option Explicit
'Константы
Public Const SW_HIDE = 0
Public Const SW_SHOWNORMAL = 1
Public Const SW_SHOWMINIMIZED = 2
Public Const SW_SHOWMAXIMIZED = 3

'Типы
Public Type RECT
			Left As Long
			Top As Long
			Right As Long
			Bottom As Long
End Type

'Функции
Public Declare Function GetActiveWindow Lib "user32" () As Long

Public Declare Function GetWindowRect Lib "user32" (ByVal hwnd As Long, _
			lpRect As RECT) As Long

Public Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" _
			(ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long

Public Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
			(ByVal lpClassName As String, ByVal lpWindowName As String) As Long

Public Declare Function ShowWindow Lib "user32" (ByVal hwnd As Long, _
			ByVal nCmdShow As Long) As Long

Public Declare Function SetWindowText Lib "user32" Alias "SetWindowTextA" _
			(ByVal hwnd As Long, ByVal lpString As String) As Long
6.1.

Дадим краткую характеристику используемых функций:

  1. GetActiveWindow возвращает описатель активного окна.
  2. GetWindowRect получает в качестве входного параметра описатель окна hwnd и возвращает значения полей структуры Rect, переданной функции в качестве второго параметра lpRect. Заметьте, тип Rect должен быть предварительно определен. Обратите внимание, первый параметр передается по значению, а второй по ссылке. Передача по ссылке позволяет функции заполнить значениями поля переданной ей структуры. Значения этих полей задают координаты прямоугольника, определяющего положение окна на экране дисплея. Возвращаемый функцией результат будет равен нулю, если выполнение функции закончится неуспехом, например, при некорректном задании описателя.
  3. GetWindowText по описателю окна возвращает его заголовок. Поскольку функция должна вернуть строку, то, как мы говорили ранее, ей передаются два параметра - lpString и cch, задающие строку и число символов, доступных для заполнения. Обратите внимание, здесь используется псевдоним с окончанием A, указывающим на использование кодировки ANSI. Опять-таки, результат, возвращаемый функцией, зависит от успеха операции.
  4. FindWindow возвращает описатель окна. Функция ищет окно и возвращает в случае успеха описатель этого окна. Окно ищется либо по имени класса, заданного параметром lpClassName, либо по заголовку, заданному параметром lpWindowName. При вызове может быть задан только один из этих параметров, второй может быть указателем с неопределенным значением.. Поскольку параметр может быть либо указателем, имеющим тип Long, либо строкой, то в предыдущих версиях по этой причине для обоих параметров следовало указывать тип Any. Теперь указывается тип String, поскольку введена специальная константа vbNullString, формально имеющая тип String, но позволяющая передать указатель со значением Null.
  5. ShowWindow позволяет сделать видимым или невидимым окно, заданное описателем, может также минимизировать, максимизировать или нормализовать его размеры. Соответствующее действие определяется вторым параметром, значения которого задаются соответствующей константой. В разделе объявлений модуля мы определили возможные значения этих констант, которые будут использованы в процессе вызова этой функции.
  6. SetWindowText позволяет установить новый заголовок окна. Является функцией, парной к функции GetWindowText, но, поскольку здесь строка заголовка передается функции, то функция устроена проще, имеет два, а не три параметра и передавать ей можно константу, что и будет продемонстрировано в нашем примере.

Приведем теперь процедуру, в которой поочередно запускаются описанные здесь функции (В примерах используются документы: DocOne6, DocTwo6

Public Sub WorkWithWindows()
		Dim Res As Long 'Результат выполнения функции
		Dim HandleAW As Long		'Описатель активного окна
		Dim RectAW As RECT	'Структура, задающая прямоугольник окна
		Dim TextAW As String 'Заголовок активного окна
		Dim LenTextAW As Long 'Длина строки
		Dim HandleW As Long		'Описатель окна
		Dim TextW As String 'Заголовок окна
		
		'Получить описатель активного окна
		HandleAW = GetActiveWindow
		Debug.Print HandleAW
		
		'Получить прямоугольник, задающий положение активного окна
		Res = GetWindowRect(HandleAW, RectAW)
		Debug.Print Res
		If Res > 0 Then 'OK
			Debug.Print "Размеры окна: Left = ", RectAW.Left, " Top = ", _
			RectAW.Top, " Right = ", RectAW.Right, " Bottom = ", RectAW.Bottom
		Else:
		MsgBox ("Не удалось получить размеры активного окна")
		End If
		'Получить заголовок окна
		'Предварительная набивка результирующей строки	нулевыми символами
		TextAW = VBA.String$(255, vbNullChar)
		LenTextAW = VBA.Len(TextAW)
		Res = GetWindowText(HandleAW, TextAW, LenTextAW)
		Debug.Print Res
		If Res > 0 Then 'OK
			TextAW = VBA.Left(TextAW, VBA.InStr(1, TextAW, vbNullChar) - 1)
			Debug.Print TextAW
		Else:
		MsgBox ("Не удалось получить заголовок активного окна")
		End If
		
		'Поиск окна документа по его заголовку
		'Возвращается описатель окна
		TextW = "DocOne6 - Microsoft Word"
		HandleW = FindWindow(vbNullString, TextW)
		If HandleW > 0 Then 'OK
			Debug.Print HandleW
		Else:
		MsgBox ("Не удалось найти окно с указанным заголовком" _
		& vbCrLf & TextW)
		End If
		
		'Минимизация и нормализация окна документа
		Res = ShowWindow(HandleW, SW_SHOWMINIMIZED)
		If Res > 0 Then Debug.Print "Окно минимизировано"
		Res = ShowWindow(HandleW, SW_SHOWNORMAL)
		If Res > 0 Then Debug.Print "Окно	в нормальном состоянии"
		
 	'Изменение заголовка окна
		TextW = "Document1 - Microsoft Word"
		HandleW = FindWindow(vbNullString, TextW)
		If HandleW > 0 Then 'OK
			Debug.Print HandleW
		Else:
		MsgBox ("Не удалось найти окно с указанным заголовком" _
		& vbCrLf & TextW)
		End If
		Res = SetWindowText(HandleW, "DocTwo6 - Microsoft Word")
End Sub
6.2.

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

655706 
 1 
Размеры окна:      Left = 8      Top = 73      Right = 769      Bottom = 580 
 58 
Microsoft Visual Basic - DocOne6 [running] - [Окна (Code)]
 6684884 
Окно минимизировано
Окно	в нормальном состоянии
 191103490

Дадим комментарии к работе этой процедуры:

  • Вначале, при вызове функции API GetActiveWindow был получен описатель активного окна. Заметим, что это было окно кода выполняемой процедуры. Значение этого описателя равно 655706.
  • Затем, при вызове функции GetWindowRect, был получен прямоугольник, определяющий положение окна на экране. Функция успешно завершила работу и вернула результат, равный 1 (истина). Как и в остальных случаях, по окончании выполнения функции мы проверили результат на успешность завершения.
  • На следующем шаге был получен заголовок активного окна. Как видно из распечатки заголовка, активным являлось выполняемое окно кода. Результат 58, который вернула функция GetWindowText, задает число символов результирующей строки. Обратите внимание, перед вызовом функции передаваемая ей строка была инициализирована нулевыми символами. После успешного завершения из строки был выделен результат, задающий заголовок. Его печать показывает, что активным в момент запуска функции было выполняемое окно кода. Для выделения заголовка из строки использовался нулевой символ, как признак окончания заголовка. Для решения этой задачи можно было использовать и число возвращаемых символов - значение, возвращаемое функцией.
  • Следующим шагом было получение описателя окна по заданному заголовку. В качестве такового был использован заголовок окна с тестовым документом. Функция FindWindow нашла такое окно и вернула его описатель, равный 6684884. Обратите внимание, первый параметр был задан константой vbNullString.
  • Окно, описатель которого был получен в последнем вызове, дважды перестраивалось, - вначале минимизировалось, затем нормализовалось, - при двух вызовах функции ShowWindow с различными значениями констант.
  • На последнем этапе снова вызывалась функция FindWindow для нахождения описателя вновь открытого документа. Затем при вызове функции SetWindowText был изменен заголовок этого окна. Заметьте, новое значение заголовка передавалось функции в виде обычной строковой константы.
Характеристики окружения

Наш следующий пример показывает, как получить, используя вызов Win32 API функций, следующие характеристики окружения:

  • Версию используемой операционной системы.
  • Тип процессора.
  • Общий и используемый объем физической и виртуальной памяти.

Функции, используемые в этом примере, принадлежат библиотеке Kernel32. Заметьте, что в отличие от большинства случаев в данном примере будут вызываться не только функции, но и процедуры, хранящиеся в библиотеке Kernel32. Начнем с описания констант, типов и операторов Declare, предшествующих вызову API функций:

Option Explicit
 'Константы
		Public Const PROCESSOR_INTEL_386 = 386
		Public Const PROCESSOR_INTEL_486 = 486
		Public Const PROCESSOR_INTEL_PENTIUM = 586
		Public Const PROCESSOR_MIPS_R4000 = 4000
		Public Const PROCESSOR_ALPHA_21064 = 21064
'Типы
		Type SYSTEM_INFO
				dwOemID As Long
				dwPageSize As Long
				lpMinimumApplicationAddress As Long
				lpMaximumApplicationAddress As Long
				dwActiveProcessorMask As Long
				dwNumberOrfProcessors As Long
				dwProcessorType As Long
				dwAllocationGranularity As Long
				dwReserved As Long
		End Type
		Type OSVERSIONINFO
				dwOSVersionInfoSize As Long
				dwMajorVersion As Long
				dwMinorVersion As Long
				dwBuildNumber As Long
				dwPlatformId As Long
				szCSDVersion As String * 128
		End Type
		Type MEMORYSTATUS
				dwLength As Long
				dwMemoryLoad As Long
				dwTotalPhys As Long
				dwAvailPhys As Long
				dwTotalPageFile As Long
				dwAvailPageFile As Long
				dwTotalVirtual As Long
				dwAvailVirtual As Long
		End Type
'Операторы Declare
		Declare Function GetVersionEx Lib "kernel32" Alias "GetVersionExA" _
			(LpVersionInformation As OSVERSIONINFO) As Long
		Declare Sub GlobalMemoryStatus Lib "kernel32" (lpBuffer As _
			MEMORYSTATUS)
		Declare Sub GetSystemInfo Lib "kernel32" (lpSystemInfo As _
			SYSTEM_INFO)
6.3.

Для сбора информации об окружении - используемом процессоре, операционной системе, имеющейся памяти и других характеристиках компьютера используем три следующие функции (процедуры) Win32 API:

  1. Функция GetVersionEx имеет в качестве единственного параметра, передаваемого по ссылке, структуру типа OSVERSIONINFO. В результате выполнения функции будут заполнены поля этой структуры, содержащие всю необходимую информацию об используемой версии операционной системы. Конечно, необходимо в раздел объявлений включить и объявление типа OSVERSIONINFO. Возвращаемый функцией результат позволяет проанализировать успешность ее выполнения.
  2. Процедура GlobalMemoryStatus имеет единственный, передаваемый по ссылке параметр типа MEMORYSTATUS. В результате выполнения процедуры поля структуры заполняются собранной информацией об объеме физической и виртуальной памяти, общей и доступной для использования в текущий момент, размере слова и некоторых других характеристиках памяти.
  3. Процедура GetSystemInfo имеет единственный, передаваемый по ссылке параметр типа SYSTEM_INFO. В результате выполнения процедуры поля структуры заполняются собранной системной информацией о типе процессора, числе процессоров, используемом размере страницы и других характеристиках компьютера. Нужно ли говорить, что для корректного вызова функции требуется объявление типа SYSTEM_INFO и констант, необходимых для анализа значений поля dwProcessorType, определяющего тип центрального процессора.

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

Public Sub WorkWithStatus()
		Dim res As Long		'Результат выполнения функции
		Dim msg As String			' Формируемое сообщение
		Dim verinfo As OSVERSIONINFO		'Информация об ОС и ее версиях
		Dim sysinfo As SYSTEM_INFO	'Системная информация
		Dim memstatus As MEMORYSTATUS 'Информация о статусе памяти

		verinfo.dwOSVersionInfoSize = Len(verinfo)
		res = GetVersionEx(verinfo)
		If res > 0 Then
			Select Case verinfo.dwPlatformId
				Case 0
						msg = "Windows 32s "
				Case 1
						msg = "Windows 95/98 "
				Case 2
						msg = "Windows NT "
			End Select
			msg = msg & verinfo.dwMajorVersion & "." & verinfo.dwMinorVersion
			msg = msg & " (Build " & verinfo.dwBuildNumber & ")" & vbCrLf
		Debug.Print msg
		Else
			MsgBox ("Не могу получить версию операционной системы")
		End If
		
		' определение типа процессора
		GetSystemInfo sysinfo
		msg = "Процессор: "
		Select Case sysinfo.dwProcessorType
			Case PROCESSOR_INTEL_386
				msg = msg & "Intel 386" & vbCrLf
			Case PROCESSOR_INTEL_486
				msg = msg & "Intel 486" & vbCrLf
			Case PROCESSOR_INTEL_PENTIUM
				msg = msg & "Intel Pentium" & vbCrLf
			Case PROCESSOR_MIPS_R4000
				msg = msg & "MIPS R4000" & vbCrLf
			Case PROCESSOR_ALPHA_21064
				msg = msg & "DEC Alpha 21064" & vbCrLf
			Case Else
				msg = msg & "(unknown)" & vbCrLf

		End Select
		Debug.Print msg
		msg = "Число процессоров: " & sysinfo.dwNumberOrfProcessors & vbCrLf
		Debug.Print msg
		msg = "Размер страницы: " & sysinfo.dwPageSize & vbCrLf
		Debug.Print msg
		msg = "Минимальный адрес приложения: " & sysinfo.lpMinimumApplicationAddress & vbCrLf
		Debug.Print msg
		msg = "Максимальный адрес приложения: " & sysinfo.lpMaximumApplicationAddress & vbCrLf
		Debug.Print msg

		' Получение характеристик памяти
		GlobalMemoryStatus memstatus
		msg = "Физическая память. Всего: " & _
			VBA.Format$(memstatus.dwTotalPhys \ 1024, "###,###,###") & "K" & vbCrLf
		Debug.Print msg
	
 	msg = "Физическая память. Доступно: " & _
			VBA.Format$(memstatus.dwAvailPhys \ 1024, "###,###,###") & "K" & vbCrLf
		Debug.Print msg

		msg = "Виртуальная память. Всего: " & _
			VBA.Format$(memstatus.dwTotalVirtual \ 1024, "###,###,###") & "K" & vbCrLf
		Debug.Print msg
		msg = "Виртуальная память. Доступно: " & _
			VBA.Format$(memstatus.dwAvailVirtual \ 1024, "###,###,###") & "K" & vbCrLf
		Debug.Print msg
		msg = "Длина слова: " & memstatus.dwLength & vbCrLf
		Debug.Print msg
		msg = "Загрузка памяти: " & memstatus.dwMemoryLoad & vbCrLf
		Debug.Print msg

End Sub
6.4.

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

Windows NT 4.0 (Build 1381)

Процессор: Intel Pentium

Число процессоров: 1

Размер страницы: 4096

Минимальный адрес приложения: 65536

Максимальный адрес приложения: 2147418111

Физическая память. Всего: 32 180K

Физическая память. Доступно: 4 772K

Виртуальная память. Всего: 2 097 024K

Виртуальная память. Доступно: 1 982 872K

Длина слова: 32

Загрузка памяти: 0
полина есенкова
полина есенкова
Дмитрий Вологжин
Дмитрий Вологжин
Добрый день, прошел тесты с 1 по 9, 10 не сдал, стал читать лекцию и всё пройденные тесты с 1 по 9 сбросились, когда захотел пересдать 10 тест.