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, пока не понял, в чем дело.
Внимание! Запрещается перепечатка данной статьи или ее части без согласования с автором. Если вы хотите разместить эту статью на своем сайте или издать в печатном виде, свяжитесь с автором.