BluetoothDisplayDeviceProperty - функция выводит стандартное
окно свойств устройства Bluetooth.
Объявление функции:
function BluetoothEnableDiscovery(
hwndParent : HWND;
var pbtdi : PBLUETOOTH_DEVICE_INFO): BOOL; stdcall;
Важно: В оригинале (см. примечание выше) функция
выглядит вот так:
function BluetoothEnableDiscovery(
hwndParent : HWND;
pbtdi : PBLUETOOTH_DEVICE_INFO): BOOL; stdcall;
Это не верно, так как в документации Microsoft указано, что параметр pbtdi
должен передаваться как указатель (что подразумевает запись
PBLUETOOTH_DEVICE_INFO), но как я писал выше, этот тип ошибочен. Он не
является указателем. Я изменил функцию так, как показано выше (так она и должна
быть, если не менять определение типа). Параметры:
hwndParent |
Handle родительского окна, которому будет принадлежать диалог
свойств. Может быть 0, тогда родительским выбирается окно Desktop. |
pbtdi |
Указатель на структуру BLUETOOTH_DEVICE_INFO в которой
содержится адрес требуемого устройства. |
Возвращаемые значения:
- TRUE - если вызов успешен
- FALSE - в противном случае (код ошибки можно узнать вызовом
функции GetLastError).
Выбор устройства
Рассмотрим, как вызвать окно диалога выбора устройства.
Добавим в наш проект на Panel еще одну кнопку TButton и
установите ее свойства как в таблице:
Свойство |
Значение |
Caption |
Select |
Name |
btSelect |
Напишем вот такой обработчик события OnClick у этой кнопки:
procedure TfmMain.btSelectClick(Sender: TObject);
var
ASelParams: BLUETOOTH_SELECT_DEVICE_PARAMS;
ASelParamsSize: dword;
begin
ASelParamsSize := SizeOf(BLUETOOTH_SELECT_DEVICE_PARAMS);
FillChar(ASelParams, ASelParamsSize, 0);
with ASelParams do
begin
dwSize := ASelParamsSize;
hwndParent := Handle;
fShowRemembered := True;
fAddNewDeviceWizard := True;
end;
BluetoothSelectDevices(@ASelParams);
BluetoothSelectDevicesFree(@ASelParams);
end
В этой части кода две новые функции.
BluetoothSelectDevices - функция разрешает/запрещает
обнаружение локального радиомодуля Bluetooth.
Объявление функции:
function BluetoothSelectDevices(
pbtsdp : PBLUETOOTH_SELECT_DEVICE_PARAMS): BOOL; stdcall;
Параметры:
pbtsdp |
Описание смотрите ниже в описании структуры. |
Возвращаемые значения:
Если функция вернула TRUE, то пользователь выбрал устройства.
Pbtsdp^.pDevices будет указывать на корректные данные. После вызова
необходимо проверить флаги fAuthenticated и fRemembered, что бы
удостовериться в корректности данных. Для освобождения памяти используйте
функцию BluetoothSelectDevicesFree, только если функция вернет TRUE.
Вернет FALSE если вызов прошел не удачно. Используйте GetLastError
для получения дополнительных сведений. Возможные ошибки:
ERROR_CANCELLED |
Пользователь отменил выбор устройства. |
ERROR_INVALID_PARAMETER |
Параметр pbsdp равен nil. |
ERROR_REVISION_MISMATCH |
Структура, переданная в pbsdp неизвестного или неверного
размера. |
Другие ошибки Win32 |
|
BLUETOOTH_SELECT_DEVICE_PARAMS
Объявление:
BLUETOOTH_SELECT_DEVICE_PARAMS = record
dwSize : DWORD;
cNumOfClasses : ULONG;
prgClassOfDevices : PBlueToothCodPairs;
pszInfo : LPWSTR;
hwndParent : HWND;
fForceAuthentication : BOOL;
fShowAuthenticated : BOOL;
fShowRemembered : BOOL;
fShowUnknown : BOOL;
fAddNewDeviceWizard : BOOL;
fSkipServicesPage : BOOL;
pfnDeviceCallback : PFN_DEVICE_CALLBACK;
pvParam : Pointer;
cNumDevices : DWORD;
pDevices : __PBLUETOOTH_DEVICE_INFO;
end;
Члены:
dwSize |
Должен быть равен размеру структуры (dwSize :=
SizeOf(BLUETOOTH_RADIO_INFO)) |
cNumOfClasses |
Входной параметр. Количество записей в массиве
prgClassOfDevice. Если 0, то ищутся все устройства. |
prgClassOfDevices |
Входной параметр. Массив COD (классов устройств), которые
необходимо искать. |
pszInfo |
Входной параметр. Если не nil, то задает текст заголовка
окна выбора устройства. |
hwndParent |
Входной параметр. Handle родительского окна для диалога
выбора устройства. Если 0, то родителем будет Desktop. |
fForceAuthentication |
Входной параметр. Если TRUE, то требует принудительной
авторизации устройств. |
fShowAuthenticated |
Входной параметр. Если TRUE, то авторизованные устройства
будут доступны для выбора. |
fShowRemembered |
Входной параметр. Если TRUE, то запомненные устройства
будут доступны для выбора. |
fShowUnknown |
Входной параметр. Если TRUE, то неизвестные
(неавторизованные и не запомненные) устройства будут доступны для
выбора. |
fAddNewDeviceWizard |
Входной параметр. Если TRUE, то запускает мастер
добавления нового устройства. |
fSkipServicesPage |
Входной параметр. Если TRUE, то пропускает страницу
Сервисы в мастере. |
pfnDeviceCallback |
Входной параметр. Если не nil, то является указателем на функцию
обратного вызова, которая вызывается для каждого найденного
устройства. Если функция вернет TRUE, то устройства
добавляется в список, если нет, то устройство игнорируется. |
pvParam |
Входной параметр. Его значение будет передано функции
pfnDeviceCallback в качестве параметра pvParam. |
cNumDevices |
Как входной параметр – количество устройств, которое требуется
вернуть. Если 0, то нет ограничений. Как выходной параметр –
количество возвращенных устройств (выбранных). |
pDevices |
Выходной параметр. Указатель на массив структур
BLUETOOTH_DEVICE_INFO. Для его освобождения используйте функцию
BluetoothSelectDevicesFree.
Важно: В оригинале этот параметр
объявлен как PBLUETOOTH_DEVICE_INFO. По этому поводу здесь
много комментариев. |
BluetoothSelectDevicesFree - функция должна вызываться, только
если вызов BluetoothSelectDevices был успешен. Эта функция освобождает
память и ресурсы, задействованные функцией BluetoothSelectDevices в
структуре BLUETOOTH_SELECT_DEVICE_PARAMS.
Объявление функции:
function BluetoothSelectDevices(
pbtsdp : PBLUETOOTH_SELECT_DEVICE_PARAMS): BOOL; stdcall;
Параметры:
pbtsdp |
Описание смотрите выше в описании структуры. |
Возвращаемые значения:
- TRUE - если вызов успешен,
- FALSE - нечего освобождать.
Управление сервисами
Для управления сервисами Microsoft Bluetooth API предоставляет функцию:
BluetoothSetServiceState - включает или выключает указанный
сервис для устройства Bluetooth. Система проецирует сервис Bluetooth на
соответствующий драйвер. При отключении сервиса – драйвер удаляется. При его
включении – драйвер устанавливается. Если выполняется включение не
поддерживаемого сервиса, то драйвер не будет установлен.
Объявление функции:
function BluetoothSetServiceState(
hRadio : Thandle;
var pbtdi : PBLUETOOTH_DEVICE_INFO;
const pGuidService : TGUID;
dwServiceFlags : DWORD): DWORD; stdcall;
Параметры:
hRadio |
Описатель радиомодуля. |
pbtdi |
Указатель на структуру BLUETOOTH_DEVICE_INFO. |
pGuidService |
GUID сервиса, который необходимо включить/выключить. |
dwServiceFlags |
Флаги управления сервисом:
BLUETOOTH_SERVICE_DISABLE – отключает сервис;
BLUETOOTH_SERVICE_ENABLE – включает сервис. |
Возвращает ERROR_SUCCESS если вызов прошел успешно. Если вызов не удался вернет
один из следующих кодов:
ERROR_INVALID_PARAMETER |
Неверные флаги в dwServiceFlags |
ERROR_SERVICE_DOES_NOT_EXIST |
Указанный сервис не поддерживается |
Другие ошибки Win32 |
|
Важно: В оригинале (см. примечание выше) функция
выглядит вот так:
function BluetoothSetServiceState(
hRadio : Thandle;
pbtdi : PBLUETOOTH_DEVICE_INFO;
const pGuidService : TGUID;
dwServiceFlags : DWORD): DWORD; stdcall;
Это не верно, так как в документации Microsoft указано, что параметр pbtdi
должен передаваться как указатель (что подразумевает запись
PBLUETOOTH_DEVICE_INFO), но как я писал выше, этот тип ошибочен. Он не
является указателем. Я изменил функцию так, как показано выше (так она и должна
быть, если не менять определение типа).
Как использовать функцию? Давайте добавим к ActionList еще одну
TAction с такими свойствами:
Свойство |
Значение |
Caption |
Disable |
Name |
acEnable |
И добавим на Panel еще одну кнопку TButton, установив у нее
следующие свойства:
Свойство |
Значение |
Action |
acEnable |
Name |
btEnable |
В обработчике события OnUpdate для acEnable напишем вот такой код:
procedure TfmMain.acEnableUpdate(Sender: TObject);
var
SelectedNode: TTreeNode;
SelectedItem: TListItem;
begin
SelectedNode := TreeView.Selected;
SelectedItem := ListView.Selected;
TAction(Sender).Enabled := Assigned(SelectedNode) and
Assigned(SelectedItem) and
(SelectedNode.ImageIndex = -2);
end;
А в обработчике OnExecute для acEnable вот такой код:
procedure TfmMain.acEnableExecute(Sender: TObject);
var
GUID: TGUID;
begin
GUID := StringToGUID(ListView.Selected.Caption);
BluetoothSetServiceState(TreeView.Selected.Parent.ImageIndex,
BLUETOOTH_DEVICE_INFO(TreeView.Selected.Data^),
GUID,
BLUETOOTH_SERVICE_DISABLE);
end;
Важно: После нажатия на кнопку btEnable
сервис будет удален из системы. Включить его можно будет через окно свойств
устройства Bluetooth.
Как определять отключенные сервисы рассмотрим в серии про передачу данных
через Bluetooth.
Удаление устройств
Для удаления устройств используется функция:
BluetoothRemoveDevice - функция удаляет авторизацию между
компьютером и устройством Bluetooth. Так же очищает кэш-записи об этом
устройстве.
Объявление функции:
function BluetoothRemoveDevice(
var pAddress : BLUETOOTH_ADDRESS): DWORD; stdcall;
Параметры:
hAddress |
Адрес устройства, которое удаляется. |
Возвращаемые значения:
ERROR_SUCCESS |
устройство удалено |
ERROR_NOT_FOUND |
устройство не найдено |
Давайте попробуем. Добавим в ActionList TAction со следующими
свойствами:
Свойство |
Значение |
Caption |
Remove |
Name |
acRemove |
И на Panel кнопку TButton со свойствами:
Свойство |
Значение |
Action |
acRemove |
Name |
btRemove |
В обработчике OnUpdate для acRemove напишем следующий код:
procedure TfmMain.acRemoveUpdate(Sender: TObject);
begin
TAction(Sender).Enabled := acProperty.Enabled;
end;
А для события OnExecute вот такой код:
procedure TfmMain.acRemoveExecute(Sender: TObject);
var
Info: BLUETOOTH_DEVICE_INFO;
Res: dword;
begin
Info := BLUETOOTH_DEVICE_INFO(ListView.Selected.Data^);
Res := BluetoothRemoveDevice(Info.Address);
if Res <> ERROR_SUCCESS then
MessageDlg('Device not found', mtError, [mbOK], 0);
TreeViewChange(TreeView, TreeView.Selected);
end;
Процедура выполняется достаточно долго, так что не думайте, что программа
зависла.
Важно: Устройство удаляется из списка. Однако,
если уже иметь адрес устройства, то можно получить о нем информацию.
Есть еще одно функция, которая связана с BluetoothRemoveDevice. Это:
BluetoothUpdateDeviceRecord - функция обновляет данные об
устройстве в кэше.
Объявление функции:
function BluetoothUpdateDeviceRecord(
var pbtdi : BLUETOOTH_DEVICE_INFO): DWORD; stdcall;
Параметры:
pbtdu |
Указатель на структуру BLUETOOTH_DEVICE_INFO. В ней должны быть
заполнены поля:
dwSize – размер структуры;
Address – адрес устройства;
szName – новое имя устройства. |
Возвращаемые значения:
ERROR_SUCCESS |
Функция выполнена успешно |
ERROR_INVALID_PARAMETER |
Указатель pbtdi=nil. (Для варианта
в Delphi не реально, так как указатель мы получаем из структуры,
передавая ее как var-параметр). |
ERROR_REVISION_MISMATCH |
Размер структуры в dwSize не правильный |
Другие ошибки Win32 |
|
Попробуем использовать и ее. Схема стандартная: TAction к
ActionList, TButton на Panel:
Свойство |
Значение |
Caption |
Update |
Name |
acUpdate |
Свойство |
Значение |
Action |
acUpdate |
Name |
btUpdate |
Код:
procedure TfmMain.acUpdateUpdate(Sender: TObject);
begin
TAction(Sender).Enabled := acProperty.Enabled;
end;
procedure TfmMain.acUpdateExecute(Sender: TObject);
var
Info: BLUETOOTH_DEVICE_INFO;
Res: dword;
NewName: string;
begin
if InputQuery('Имя устройства', 'Новое имя', NewName) then begin
lstrcpyW(Info.szName, PWideChar(WideString(NewName)));
Res := BluetoothUpdateDeviceRecord(Info);
if Res <> ERROR_SUCCESS then RaiseLastOsError;
TreeViewChange(TreeView, TreeView.Selected);
end;
end;
Как видите, все просто.
И так, удалять устройства мы умеем. Давайте теперь научимся добавлять их. Для
этого Bluetooth API предоставляет две функции:
BluetoothAuthenticateDevice - отправляет запрос на авторизацию
удаленному устройству Bluetooth. Есть два режима авторизации: "Wizrd mode"
и "Blind Mode".
"Wizard Mode" запускается, когда параметр pszPasskey = nil. В
этом случае открывается окно "Мастера подключения". У пользователя будет
запрошен пароль, который будет отправлен в запросе на авторизацию удаленному
устройству. Пользователь будет оповещен системой об успешном или не успешном
выполнении авторизации и получит возможность попытаться авторизировать
устройства еще раз.
"Blind Mode" вызывается, когда pszPasskey <> nil. В этом случае
пользователь не увидит никакого мастера. Вам необходимо программно запросить код
авторизации (pszPasskey) и уведомить пользователя о результате.
Объявление функции:
function BluetoothAuthenticateDevice(
hwndParent : HWND;
hRadio : THandle;
pbtdi : BLUETOOTH_DEVICE_INFO;
pszPasskey : PWideChar;
ulPasskeyLength : ULONG): DWORD; stdcall;
Параметры:
hwndParent |
Handle родительского окна. Если 0, то родительским окном
станет окно Desktop. |
hRadio |
Handle локального радиомодуля. Если 0, то авторизация
будет проведена на всех радиомодулях. Если хотя бы один пройдет
авторизацию, функция выполнится успешно. |
pbdti |
Информация об устройстве, на котором необходимо
авторизироваться. |
pszPasskey |
PIN для авторизации. Если nil, то вызывается
мастер авторизации (описано выше). Важно: pszPasskey не
NULL-терминированная строка! |
ulPasskeyLength |
Длина строки в байтах. Должна быть меньше либо равна
BLUETOOTH_MAX_PASSKEY_SIZE * SizeOf(WCHAR). |
Возвращаемые значения:
ERROR_SUCCESS |
Функция выполнена успешно |
ERROR_CANCELLED |
Пользователь отменил процесс авторизации |
ERROR_INVALID_PARAMETER |
Структура pbtdi не верна |
ERROR_NO_MORE_ITEMS |
Устройство в pbtdi уже авторизированно |
Другие ошибки Win32 |
|
Для "Blind Mode" соответствие кодов ошибок Bluetooth кодам ошибок Win32
приведено в таблице:
Bluetooth |
Win32 |
BTH_ERROR_SUCCESS |
ERROR_SUCCESS |
BTH_ERROR_NO_CONNECTION |
ERROR_DEVICE_NOT_CONNECTED |
BTH_ERROR_PAGE_TIMEOUT |
WAIT_TIMEOUT |
BTH_ERROR_HARDWARE_FAILURE |
ERROR_GEN_FAILURE |
BTH_ERROR_AUTHENTICATION_FAILURE |
ERROR_NOT_AUTHENTICATED |
BTH_ERROR_MEMORY_FULL |
ERROR_NOT_ENOUGH_MEMORY |
BTH_ERROR_CONNECTION_TIMEOUT |
WAIT_TIMEOUT |
BTH_ERROR_LMP_RESPONSE_TIMEOUT |
WAIT_TIMEOUT |
BTH_ERROR_MAX_NUMBER_OF_CONNECTIONS |
ERROR_REQ_NOT_ACCEP |
BTH_ERROR_PAIRING_NOT_ALLOWED |
ERROR_ACCESS_DENIED |
BTH_ERROR_UNSPECIFIED_ERROR |
ERROR_NOT_READY |
BTH_ERROR_LOCAL_HOST_TERMINATED_CONNECTION |
ERROR_VC_DISCONNECTED |
Аналогичная функция:
BluetoothAuthenticateMultipleDevices - позволяет
авторизироваться сразу на нескольких устройствах при помощи одной копии "Мастера
авторизации".
Объявление функции:
function BluetoothAuthenticateMultipleDevices(
hwndParent : HWND;
hRadio : THandle;
cDevices : DWORD;
rgpbtdi : __PBLUETOOTH_DEVICE_INFO): DWORD; stdcall;
Параметры:
hwndParent |
Handle родительского окна. Если 0, то родительским окном
станет окно Desktop. |
hRadio |
Handle локального радиомодуля. Если 0, то авторизация
будет проведена на всех радиомодулях. Если хотя бы один пройдет
авторизацию, функция выполнится успешно. |
cDevices |
Количество элементов в массиве rgpbtdi. |
rgpbtdi |
Массив структур BLUETOOTH_DEVICE_INFO, в котором
представлены устройства для авторизации. |
Возвращаемые значения:
ERROR_SUCCESS |
Функция выполнена успешно. Проверьте флаг fAuthenticated
у каждого устройства, что бы знать, какие прошли авторизацию. |
ERROR_CANCELLED |
Пользователь отменил процесс авторизации. Проверьте флаг
fAuthenticated у каждого устройства, что бы знать, какие прошли
авторизацию. |
ERROR_INVALID_PARAMETER |
Один или несколько элементов массива rgpbtdi не верны. |
ERROR_NO_MORE_ITEMS |
Все устройства в массиве уже авторизированны. |
Другие ошибки Win32 |
|
Важно: В оригинале функция выглядит вот так:
function BluetoothAuthenticateMultipleDevices(
hwndParent : HWND;
hRadio : THandle;
cDevices : DWORD;
pbtdi : PBLUETOOTH_DEVICE_INFO): DWORD; stdcall;
Это не верно, так как в документации Microsoft указано, что параметр rgpbtdi
должен передаваться как указатель (что подразумевает запись
PBLUETOOTH_DEVICE_INFO), но как я писал выше, этот тип ошибочен. Он не
является указателем. Я изменил функцию так, как показано выше. По поводу типа
__PBLUETOOTH_DEVICE_INFO я писал выше.
Описывать с примером, как использовать эти функции не буду, так как они
тривиальны (если вы прочитали все вышеизложенное). Остались последние три
функции, которые мы не рассмотрели:
BluetoothRegisterForAuthentication - регистрирует функцию
обратного вызова, которая будет вызываться на запрос устройства об авторизации.
Если несколько приложений зарегистрировало такую функцию, то будет вызвана
функция в последнем приложении.
Объявление функции:
function BluetoothRegisterForAuthentication(
var pbtdi : PBLUETOOTH_DEVICE_INFO;
var phRegHandle : HBLUETOOTH_AUTHENTICATION_REGISTRATION;
pfnCallback : PFN_AUTHENTICATION_CALLBACK;
pvParam : Pointer): DWORD; stdcall;
Параметры:
pbtdi |
Указатель на BLUETOOTH_DEVICE_INFO. Используется адрес
устройства, для которого регистрируется функция.
Обратите внимание на параметр. В оригинале он
опять передается не как указатель. |
phRegHandle |
Указатель, куда будет возвращен Handle регистрации,
которой потом используется в BluetoothUnregisterAuthentication. |
pfnCallback |
Функция обратного вызова. |
pvParam |
Опциональный параметр, который без изменения передается в
функцию обратного вызова. |
Возвращаемые значения:
ERROR_SUCCESS |
Функция выполнена успешно. |
ERROR_OUTOFMEMORY |
Недостаточно памяти. |
Другие ошибки Win32 |
|
BluetoothUnregisterAuthentication - удаляет функцию обратного
вызова, зарегистрированную функцией BluetoothRegisterForAuthentication и
закрывает Handle.
Объявление функции:
function BluetoothUnregisterAuthentication(
hRegHandle : HBLUETOOTH_AUTHENTICATION_REGISTRATION): BOOL; stdcall;
Параметры:
hRegHandle |
Handle регистрации, полученный функцией
BluetoothRegisterForAuthentication. |
Возвращаемые значения:
Вернет TRUE, если вызов успешен и FALSE в случае неудачи.
Используйте GetLastError для получения дополнительной информации.
BluetoothSendAuthenticationResponse - эта функция должна
вызываться из функции обратного вызова при запросе авторизации удаленным
устройством для передачи PIN.
Объявление функции:
function BluetoothSendAuthenticationResponse(
hRadio : THandle;
pbtdi : PBLUETOOTH_DEVICE_INFO;
pszPasskey : LPWSTR): DWORD; stdcall;
Параметры:
hRadio |
Handle радиомодуля, для которого проводим авторизацию.
Если 0, то пытаемся на всех. |
pbtdi |
Указатель на BLUETOOTH_DEVICE_INFO с данными об
устройстве, от которого поступил запрос на авторизацию. Может быть
тот же указатель, который передан в функцию обратного вызова. |
pszPasskey |
Указатель на UNICODE строку, в которой содержится ключ
авторизации (PIN). |
Возвращаемые значения:
ERROR_SUCCESS |
Функция выполнена успешно. |
ERROR_CANCELLED |
Устройство отвергло авторизационный код (PIN). Так же,
возможно, имеются проблемы со связью |
E_FAIL |
Устройство вернуло ошибку авторизации. |
Другие ошибки Win32 |
|
И, наконец, функция обратного вызова:
PFN_AUTHENTICATION_CALLBACK
Описание этой функции дано выше. Здесь приведу лишь определеннее.
Объявление функции:
PFN_AUTHENTICATION_CALLBACK =
function(pvParam : Pointer;
pDevice : PBLUETOOTH_DEVICE_INFO): BOOL; stdcall;
Параметры:
pvParam |
Указатель на параметр, который мы передали в
BluetoothRegisterForAuthentication. |
pDevice |
Указатель на BLUETOOTH_DEVICE_INFO с данными об
устройстве, от которого поступил запрос на авторизацию. |
Заключение
На этот раз все. Мы рассмотрели все функции Bluetooth API от Microsoft. Также
мы научились управлять устройствами и радиомодулями Bluetooth, проводить
авторизацию и получать информацию об этих устройствах.
Но актуальным остается вопрос, который мне многие задают. Как же все-таки
передавать данные между устройствами Bluetooth?
Ответ на этот вопрос читайте в следующей серии статей "Передача данных через
Bluetooth".
Конечно, можно было бы всю эту информацию уместить в эти статьи, но объем ее
не сравним с предоставленным здесь. Так что наберитесь терпения. Я постараюсь
надолго не задерживать с выходом новой серии.
Я буду рад любым замечаниям и пожеланиям по данной теме.
P.S. Внимательно относитесь к сторонним библиотекам. Как видите, в JWALIB
оказалось много ошибок, которые порой загоняют в тупик. Я минут 20 смотрел на
Access Violation, пока не понял, в чем дело.
Внимание! Запрещается перепечатка данной статьи
или ее части без согласования с автором. Если вы хотите разместить эту статью на
своем сайте или издать в печатном виде, свяжитесь с автором.
|