Logo Море(!) аналитической информации!
IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware
Скидка до 20% на услуги дата-центра. Аренда серверной стойки. Colocation от 1U!

Миграция в облако #SotelCloud. Виртуальный сервер в облаке. Выбрать конфигурацию на сайте!

Виртуальная АТС для вашего бизнеса. Приветственные бонусы для новых клиентов!

Виртуальные VPS серверы в РФ и ЕС

Dedicated серверы в РФ и ЕС

По промокоду CITFORUM скидка 30% на заказ VPS\VDS

VPS/VDS серверы. 30 локаций на выбор

Серверы VPS/VDS с большим диском

Хорошие условия для реселлеров

4VPS.SU - VPS в 17-ти странах

2Gbit/s безлимит

Современное железо!

2006 г.

WinApi
Лекция из курса «Основы офисного программирования и язык VBA»

Биллиг Владимир Арнольдович
Интернет-Университет Информационных Технологий, INTUIT.ru

Назад Оглавление Вперёд

Вызов функций Win32 API, работающих в Unicode кодировке

Уже говорилось, что функции API, работающие со строками, вызываются в ANSI кодировке. Сейчас мы попытаемся объяснить причину этого факта, а, с другой стороны, покажем, как можно вызывать функции Win32 API, использующие Unicode кодировку. Заметим, что это может быть важным не столько для функций Win32 API, сколько для других внешних функций, которые могут существовать в кодировке Unicode и не иметь ANSI варианта. Начнем с объяснения ситуации, - почему в VBA внешние функции вызываются в кодировке ANSI. Следует понимать, что строки VBA хранятся в Unicode кодировке и передача строк при вызове внутренних функций внутри VBA происходит в кодировке Unicode. Однако VB и VBA предполагают, что внешний мир устроен по-другому и до сих пор использует кодировку ANSI. Поэтому всякий раз, когда вызываются внешние функции, при вызове происходит преобразование и строковая информация передается и возвращается в кодировке ANSI. По этой причине нельзя вызвать функцию в кодировке Unicode простым изменением псевдонима, задав у него окончание W. Покажем сейчас, как можно "обмануть" VBA, заставив его не выполнять указанных преобразований, что и позволит вызывать функции, корректно работающие в Unicode кодировке. Покажем также, что, как и всякий обман, не всегда все заканчивается благополучно. Тем не менее, с предлагаемым приемом полезно познакомиться. Решение задачи основывается на следующем:

  1. При вызове функции вместо строки используется массив байтов, хранящий копию строки. Напомним, что внутри VBA строка хранится в Unicode кодировке, поэтому и массив байтов будет хранить строку в этой кодировке.
  2. В операторе Declare необходимо тип String изменить на тип Any, что обеспечит отсутствие проверок и преобразований.
  3. Если в операторе Declare для строкового параметра указан спецификатор ByVal, то его необходимо удалить или изменить на ByRef, явно указав передачу параметра по ссылке.

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

  • FindWindow, которая позволяет найти окно по его заголовку, вернув описатель окна в качестве результата,
  • GetWindowText, SetWindowText, позволяющие получить и установить новый заголовок окна.

Заметим сразу же, что нам удалось успешно вызвать и корректно работать с двумя последними функциями в Unicode кодировке. Однако этот прием не работает при вызове функции FindWindowW. Несмотря на все попытки, переданная для поиска строка заголовка не приводила к успешному завершению поиска. Но обо всем по порядку. Приведем вначале раздел объявлений модуля с именем Unicode, созданного для работы с этим примером:

Option Explicit
'Объявление вызываемых функций в Unicode кодировке
 Public Declare Function FindWindowA Lib "user32" _
         (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
'Функции в Unicode кодировке
'Тип string заменен на Any. Передача аргумента по ссылке
 Public Declare Function FindWindowW Lib "user32" _
         (lpClassName As Any, lpWindowName As Any) As Long
 
 Public Declare Function GetWindowText Lib "user32" Alias "GetWindowTextW" _
         (ByVal hwnd As Long, lpString As Any, ByVal cch As Long) As Long
 
 Public Declare Function SetWindowText Lib "user32" Alias "SetWindowTextW" _
         (ByVal hwnd As Long, lpString As Any) As Long
 
 Public ArCapt() As Byte 'Объявление динамического массива

Все пояснения уже сделаны и поэтому приведем процедуру этого модуля, вызывающую функции API:

Пример 6: html, txt

Приведем результаты отладочной печати:

327894 
Document1 - Microsoft Word

Document1 - Microsoft Word
NewDoc

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

  • Работа процедуры начинается с вызова функции API FindWindowA, работающей в кодировке ANSI. Она успешно находит окно, заголовок которого задан переменной Capt. Функция возвращает его описатель.
  • На следующем шаге мы пытались решить эту же задачу, используя функцию API FindWindowW, работающую в кодировке Unicode. В тексте нашел отражение один из вариантов решения. К сожалению, поиск во всех случаях заканчивался неуспехом, хотя, как показал побайтный анализ в окне Watch и как показывает отладочная печать, массив байтов ArCapt содержит Unicode копию строки заголовка
  • Полученный описатель окна использовался при вызове Unicode варианта функции GetWindowTextW. Функция корректно работала, используя ссылку на переданный ей массив байтов ArCapt.
  • Затем, используя эту же технику, заголовок окна был изменен при вызове Unicode варианта функции SetWindowTextW.
  • Для контроля повторно была вызвана функция GetWindowTextW. Отладочная печать подтвердила корректность работы.

Неудача в вызове функции FindWindowW может быть вызвана разными причинами. Вероятнее всего, при выполнении поиска и проведения операций сравнения строк, применяемый способ не корректен, или, по крайней мере, требует дополнительных уточнений, возможно связанных с длиной строки. С другой стороны, сам прием является некоторой уловкой. Существует более честный способ, хотя, возможно, и более трудоемкий. Для решения задачи можно создать библиотеку типов TypeLib, содержащую описание функций Win32 API в Unicode кодировке, включить ссылку на эту библиотеку и вызывать функции без всяких уловок.

Назад Оглавление Вперёд

Бесплатный конструктор сайтов и Landing Page

Хостинг с DDoS защитой от 2.5$ + Бесплатный SSL и Домен

SSD VPS в Нидерландах под различные задачи от 2.6$

✅ Дешевый VPS-хостинг на AMD EPYC: 1vCore, 3GB DDR4, 15GB NVMe всего за €3,50!

🔥 Anti-DDoS защита 12 Тбит/с!

VPS в 21 локации

От 104 рублей в месяц

Безлимитный трафик. Защита от ДДоС.

🔥 VPS до 5.7 ГГц под любые задачи с AntiDDoS в 7 локациях

💸 Гифткод CITFORUM (250р на баланс) и попробуйте уже сейчас!

🛒 Скидка 15% на первый платеж (в течение 24ч)

Новости мира IT:

Архив новостей

IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware

Информация для рекламодателей PR-акции, размещение рекламы — adv@citforum.ru,
тел. +7 495 7861149
Пресс-релизы — pr@citforum.ru
Обратная связь
Информация для авторов
Rambler's Top100 TopList liveinternet.ru: показано число просмотров за 24 часа, посетителей за 24 часа и за сегодня This Web server launched on February 24, 1997
Copyright © 1997-2000 CIT, © 2001-2019 CIT Forum
Внимание! Любой из материалов, опубликованных на этом сервере, не может быть воспроизведен в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав. Подробнее...