Работа с Bluetooth в Delphi
Falk0ner, вс, 06/07/2008 - 15:34.
При отключении сервиса – драйвер удаляется. При его включении – драйвер устанавливается. Если выполняется включение не поддерживаемого сервиса, то драйвер не будет установлен. Объявление функции:
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 напишем вот такой код:
hRadio : Thandle;
var pbtdi : PBLUETOOTH_DEVICE_INFO;
const pGuidService : TGUID;
dwServiceFlags : DWORD): DWORD; stdcall;
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 вот такой код:
<code>
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. Так же очищает кэш-записи об этом устройстве.
Объявление функции:
<code>
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 напишем следующий код:
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 вот такой код:
<code>
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. Так же очищает кэш-записи об этом устройстве.
Объявление функции:
<code>
function BluetoothRemoveDevice(
var pAddress : BLUETOOTH_ADDRESS): DWORD; stdcall;
procedure TfmMain.acRemoveUpdate(Sender: TObject);
begin
TAction(Sender).Enabled := acProperty.Enabled;
end;
А для события OnExecute вот такой код:
begin
TAction(Sender).Enabled := acProperty.Enabled;
end;
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 - функция обновляет данные об устройстве в кэше.
Объявление функции:
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;
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
Код:
var pbtdi : BLUETOOTH_DEVICE_INFO): DWORD; stdcall;
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) и уведомить пользователя о результате.
Объявление функции:
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;
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 - позволяет авторизироваться сразу на нескольких устройствах при помощи одной копии "Мастера авторизации".
Объявление функции:
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).
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
Важно: В оригинале функция выглядит вот так:
hwndParent : HWND;
hRadio : THandle;
cDevices : DWORD;
rgpbtdi : __PBLUETOOTH_DEVICE_INFO): DWORD; stdcall;
function BluetoothAuthenticateMultipleDevices(
hwndParent : HWND;
hRadio : THandle;
cDevices : DWORD;
pbtdi : PBLUETOOTH_DEVICE_INFO): DWORD; stdcall;
Это не верно, так как в документации Microsoft указано, что параметр rgpbtdi должен передаваться как указатель (что подразумевает запись PBLUETOOTH_DEVICE_INFO), но как я писал выше, этот тип ошибочен. Он не является указателем. Я изменил функцию так, как показано выше. По поводу типа __PBLUETOOTH_DEVICE_INFO я писал выше.
Описывать с примером, как использовать эти функции не буду, так как они тривиальны (если вы прочитали все вышеизложенное). Остались последние три функции, которые мы не рассмотрели:
BluetoothRegisterForAuthentication - регистрирует функцию обратного вызова, которая будет вызываться на запрос устройства об авторизации. Если несколько приложений зарегистрировало такую функцию, то будет вызвана функция в последнем приложении.
Объявление функции:
hwndParent : HWND;
hRadio : THandle;
cDevices : DWORD;
pbtdi : PBLUETOOTH_DEVICE_INFO): DWORD; stdcall;
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.
Объявление функции:
var pbtdi : PBLUETOOTH_DEVICE_INFO;
var phRegHandle : HBLUETOOTH_AUTHENTICATION_REGISTRATION;
pfnCallback : PFN_AUTHENTICATION_CALLBACK;
pvParam : Pointer): DWORD; stdcall;
function BluetoothUnregisterAuthentication(
hRegHandle : HBLUETOOTH_AUTHENTICATION_REGISTRATION): BOOL; stdcall;
Параметры:
hRegHandle
Handle регистрации, полученный функцией BluetoothRegisterForAuthentication.
Возвращаемые значения:
Вернет TRUE, если вызов успешен и FALSE в случае неудачи. Используйте GetLastError для получения дополнительной информации.
BluetoothSendAuthenticationResponse - эта функция должна вызываться из функции обратного вызова при запросе авторизации удаленным устройством для передачи PIN.
Объявление функции:
hRegHandle : HBLUETOOTH_AUTHENTICATION_REGISTRATION): BOOL; stdcall;
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
Описание этой функции дано выше. Здесь приведу лишь определеннее.
Объявление функции:
hRadio : THandle;
pbtdi : PBLUETOOTH_DEVICE_INFO;
pszPasskey : LPWSTR): DWORD; stdcall;
PFN_AUTHENTICATION_CALLBACK =
function(pvParam : Pointer;
pDevice : PBLUETOOTH_DEVICE_INFO): BOOL; stdcall;
Параметры:
pvParam
Указатель на параметр, который мы передали в BluetoothRegisterForAuthentication.
pDevice
Указатель на BLUETOOTH_DEVICE_INFO с данными об устройстве, от которого поступил запрос на авторизацию.
Заключение
На этот раз все. Мы рассмотрели все функции Bluetooth API от Microsoft. Также мы научились управлять устройствами и радиомодулями Bluetooth, проводить авторизацию и получать информацию об этих устройствах.
Но актуальным остается вопрос, который мне многие задают. Как же все-таки передавать данные между устройствами Bluetooth?
Ответ на этот вопрос читайте в следующей серии статей "Передача данных через Bluetooth".
Конечно, можно было бы всю эту информацию уместить в эти статьи, но объем ее не сравним с предоставленным здесь. Так что наберитесь терпения. Я постараюсь надолго не задерживать с выходом новой серии.
Полностью рабочий пример, рассмотренный в этой статье, вы можете скачать здесь (300K).
Я буду рад любым замечаниям и пожеланиям по данной теме.function(pvParam : Pointer;
pDevice : PBLUETOOTH_DEVICE_INFO): BOOL; stdcall;
Отправить комментарий