Delphi і Bluetooth. Частина 3 (исходники), Різне, Програмування, статті

Частина 1 :: Частина 2

Вступ


Отже, в попередніх частинах ми навчилися отримувати список локальних радіомодулів Bluetooth і віддалених пристроїв Bluetooth. Нам залишилося навчитися отримувати список сервісів, що надаються віддаленою пристроєм і управляти локальними радіомодулями. Так само, необхідно розібратися, як же все-таки передаються дані між різними пристроями Bluetooth.


В цій частині, а вона буде найдовшою та інформативною, ми створимо програму, яка допоможе нам узагальнити отриману інформацію і покаже, як використовувати нові функції, які тут будуть описані.


Перш, ніж ми приступимо, давайте визначимося в термінах. Microsoft у своїй документації вводить два терміни: Radio і Device. Radio – Це локальний радіомодуль Bluetooth (USB-брелок, інтегроване рішення, загалом те, що встановлено на вашому комп’ютері). Device – Це те пристрій Bluetooth з яким ви хочете обмінюватися інформацією. Будь то телефон, КПК, гарнітура або ще щось. Важливо розуміти, що якщо ми пишемо програму для PDA, то коли вона працює на PDA – його модуль Bluetooth буде Radio, А комп’ютер – Device. Якщо ж вона працює на комп’ютері, то комп’ютерний модуль – Radio, А PDA – Device.


Що ми знаємо


На жаль, документація Microsoft по Bluetooth API і роботі з Bluetooth настільки мізерна (у мене вийшло 50 сторінок в Word з оформленням), а прикладів вони взагалі не надають, що з неї дуже важко зрозуміти, як же все-таки працює ця технологія.


Коли я тільки починав вивчати цей предмет, я перерив весь Internet, але так нічого зрозумілого не знайшов.


По-цьому, тут мені хочеться дати найбільш повну і детальну інформацію про це питання, що б ви не зіткнулися з тією ж проблемою відсутності інформації.


Отже, приступимо.


Створення проекту


Давайте створимо в Delphi новий проект і збережемо його під ім’ям BTWork, А модуль – під ім’ям Main.


Головну і поки єдину форму, назвемо fmMain. Заголовок BTWork.


Тепер нам знадобляться файл JwaBluetoothAPI.pas, JwaBtHDef.pas і JwaBthSdpDef.pas. Їх можна знайти в прикладах з попередніх частин або в бібліотеці BTClasses.


Для того, щоб не тягнути з собою всі інші файли з JWA, давайте ці трохи виправимо. Знайдіть у них рядок uses
JwaWindows і замініть JwaWindows на Windows.

Далі видалити з них рядки {$ WEAKPACKAGEUNIT}

{$HPPEMIT “”}
{$HPPEMIT “#include “bluetoothapis.h””}
{$HPPEMIT “”}

{$I jediapilib.inc}

І у файлі JwaBluetoothAPI видаліть все, що знаходиться між {$IFDEF DYNAMIC_LINK} і {$ELSE} разом з цими DEF. І в кінці цього файлі видаліть {$ENDIF}.


Далі, в JwaBluetoothAPI.pas після implementation

uses
JwaWinDLLNames; Напишіть const
   btapi = “irprops.cpl”;

Хай вибачать нас хлопці, які цю бібліотеку писали!


Всі ці дії я робив для того, щоб зменшити архів прикладу. Та й не потрібно тягнути за собою багато зайвого. Хоча сама бібліотека вельми корисна. Один модуль JwaWindows чого вартий. Там дуже багато цікавого є. Ну да ладно – щось я відволікся.


Після того, як ми кастрували ці модулі, давайте додамо їх в наш проект. Готово?


У цьому додатку ми будемо отримувати список локальних радіомодулів, пристроїв, до них приєднаних, список сервісів, що надаються пристроями. Також ми повинні управляти радіомодулями і навчитися проходити авторизацію.


Приступаємо.


Оформлення головної форми


На головну форму помістимо компонент TPanel і встановіть наступні властивості:















Властивість  Значення 
Align alTop
Caption  
Name Panel


Далі помістимо компонент TTreeView і встановіть властивості як в таблиці:
























Властивість  Значення 
Align alLeft
Cursor crHandPoint
HideSelection False
HotTrack True
Name TreeView
ReadOnly True


Правіше TTreeView помістимо TSplitter і встановимо такі його властивості:












Властивість  Значення 
Name Splitter
Width 5


І, нарешті, поміщаємо компонент TListView ще правіше TSplitter. Встановлюємо його властивості як в таблиці:







































Властивість  Значення 
Align alClient
ColumnClick False
Cursor crHandPoint
GridLines True
HideSelection False
HotTrack True
Name ListView
ReadOnly True
RowSelect True
ShowWorkAreas True
ViewStyle vsReport


На TPanel помістимо кнопку TButton.












Властивість  Значення 
Caption Refresh
Name btRefresh


Тепер ми готові писати програму.


Пишемо код


При старті нашої програми, бажано щоб відразу заповнювався TreeView. У ньому будуть показані модулі Bluetooth і пристрої, які до них підключені.


Для цього в обробнику OnCreate форми fmMain напишемо такий код: procedure TfmMain.FormCreate (Sender: TObject);
begin
   btRefresh.Click;
end; А в обробнику OnClick кнопки btRefresh напишемо наступне: procedure TfmMain.btRefreshClick (Sender: TObject);
var
   RootNode: TTreeNode;
   hFind: HBLUETOOTH_RADIO_FIND;
   hDevFind: HBLUETOOTH_DEVICE_FIND;
   FindParams: BLUETOOTH_FIND_RADIO_PARAMS;
   SearchParams: BLUETOOTH_DEVICE_SEARCH_PARAMS;
   SearchParamsSize: dword;
   DevInfo: ^PBLUETOOTH_DEVICE_INFO;
   DevInfoSize: dword;
   hRadio: THandle;
   RadioInfo: PBLUETOOTH_RADIO_INFO;
   RadioInfoSize: dword;
   RadioNode: TTreeNode;
   Loop: integer;
   DevNode: TTreeNode;
begin
   with TreeView.Items do
     begin
       BeginUpdate;

/ / Очищаємо дерево
       for Loop := 0 to Count – 1 do
         begin
           if TreeView.Items[Loop].ImageIndex > 0 then
             CloseHandle(TreeView.Items[Loop].ImageIndex);
           if Assigned(TreeView.Items[Loop].Data) then
             Dispose(TreeView.Items[Loop].Data);
         end;
       Clear;

/ / Коренева гілку в дереві
       RootNode := Add(nil, “Bluetooth Radios”);
       with RootNode do
         begin
           Data := nil;
           ImageIndex := -1;
         end;

/ / Починаємо пошук локальних модулів Bluetooth
       FindParams.dwSize := SizeOf(BLUETOOTH_FIND_RADIO_PARAMS);
       hFind := BluetoothFindFirstRadio(@FindParams, hRadio);
       if hFind <> 0 then begin
         repeat
/ / Отримати інформацію про радіомодуля
           New(RadioInfo);
           RadioInfoSize := SizeOf(BLUETOOTH_RADIO_INFO);
           FillChar(RadioInfo^, RadioInfoSize, 0);
           RadioInfo^.dwSize := RadioInfoSize;
/ / Помилки не обробляємо!
           BluetoothGetRadioInfo(hRadio, RadioInfo^);

/ / Додаємо радіо в дерево
           RadioNode := AddChild(RootNode,
             string(RadioInfo^.szName) + ” [” +
             BTAdrToStr(RadioInfo^.address) + “]”);
           with RadioNode do
             begin
/ / Так як ми зберігаємо Handle, то не закриваємо його!
               ImageIndex := hRadio;
               Data := RadioInfo;
             end;

/ / Починаємо пошук пристроїв для знайденого радіомодуля.
      SearchParamsSize := SizeOf(BLUETOOTH_DEVICE_SEARCH_PARAMS);
           FillChar(SearchParams, SearchParamsSize, 0);
           SearchParams.dwSize := SearchParamsSize;
           SearchParams.fReturnRemembered := True;
           SearchParams.hRadio := hRadio;

           New(DevInfo);
           DevInfoSize := SizeOf(BLUETOOTH_DEVICE_INFO);
           FillChar(DevInfo^, DevInfoSize, 0);
           DevInfo^.dwSize := DevInfoSize;

/ / Шукаємо перший
           hDevFind := BluetoothFindFirstDevice(SearchParams, DevInfo^);
           if hDevFind <> 0 then begin
             repeat
/ / Додаємо в дерево
               DevNode := AddChild(RadioNode,
                 string(DevInfo^.szName) + ” [” +
                 BTAdrToStr(DevInfo^.Address) + “]”);
               with DevNode do
                 begin
                   Data := DevInfo;
                   ImageIndex := -2;
                 end;

/ / Шукаємо наступне пристрій
               New(DevInfo);
               DevInfoSize := SizeOf(BLUETOOTH_DEVICE_INFO);
               FillChar(DevInfo^, DevInfoSize, 0);
               DevInfo^.dwSize := DevInfoSize;
             until not BluetoothFindNextDevice(hDevFind, DevInfo^);

/ / Пошук пристроїв закінчено
           BluetoothFindDeviceClose(hDevFind);
         end;

/ / Знаходимо наступне радіо
       until not BluetoothFindNextRadio(hFind, hRadio);

/ / Пошук радіомодулів закінчено
       BluetoothFindRadioClose(hFind);
     end;

     EndUpdate;
   end;

   with TreeView do
     begin
       Selected := RootNode;
       Items[0].Expand(True);
     end;
end; В uses нашого модуля, який відноситься до головної формі, допишемо: implementation / / Вже написано!

uses / / Дописати!
JwaBluetoothAPIs, Windows, SysUtils, Dialogs; Нижче додамо функцію: / / Перетворює адресу з внутрішнього формату (dword) в рядок,
/ / Прийняту для подання адрес пристроїв Bluetooth.
function BTAdrToStr(const Adr: BLUETOOTH_ADDRESS): string;
var
   Loop: byte;
begin
   Result := IntToHex(Adr.rgBytes[0], 2);
   for Loop := 1 to 5 do
     Result := IntToHex(Adr.rgBytes[Loop], 2) + ‘:’ + Result;
end;

Тут хочу привести опис використовуваних структур, так як раніше я їх не описував:


BLUETOOTH_DEVICE_SEARCH_PARAMS


Оголошення: BLUETOOTH_DEVICE_SEARCH_PARAMS = record
   dwSize : DWORD;
   fReturnAuthenticated : BOOL;
   fReturnRemembered : BOOL;
   fReturnUnknown : BOOL;
   fReturnConnected : BOOL;
   fIssueInquiry : BOOL;
   cTimeoutMultiplier : UCHAR;
   hRadio : THandle;
end;

Члени:



























dwSize

Вхідний параметр. Повинен бути дорівнює розміру структури (dwSize := SizeOf(BLUETOOTH_DEVICE


_SEARCH_PARAMS))

fReturnAuthenticated Вхідний параметр. Функція буде повертати пристрої, що пройшли авторизацію.
fReturnRemembered Вхідний параметр. Функція буде повертати пристрою, вже запомненние раннє.
fReturnUnknown Вхідний параметр. Функція буде повертати нові або невідомі пристрої.
fReturnConnected Вхідний параметр. Функція буде повертати підключені пристрої.
fIssueInquiry Вхідний параметр. Змушує функцію перевіряти пристрою.
cTimeoutMultiplier Вхідний параметр. Тайм-аут для перевірки пристрою.
hRadio Handle радіомодуля, для якого проводиться пошук пристроїв. Якщо 0, то перевіряються всі радіомодулі.

BLUETOOTH_DEVICE_INFO


Оголошення: BLUETOOTH_DEVICE_INFO = record
   dwSize : DWORD;
   Address : BLUETOOTH_ADDRESS;
   ulClassofDevice : ULONG;
   fConnected : BOOL;
   fRemembered : BOOL;
   fAuthenticated : BOOL;
   stLastSeen : SYSTEMTIME;
   stLastUsed : SYSTEMTIME;
   szName : array [0..BLUETOOTH_MAX_NAME_SIZE – 1] of WideChar;
end;

Члени:






























dwSize Вхідний параметр. Повинен бути дорівнює розміру структури (dwSize := SizeOf(BLUETOOTH_DEVICE_INFO))
Address Адреса пристрою Bluetooth.
ulClassofDevice Клас пристрою. Детальніше за класами дивіться в JwaBluetoothAPIs. Константи з префіксом COD_xxx.
fConnected Якщо TRUE, То пристрій підключено / використовується
fRemembered Якщо TRUE, То пристрій раніше вже було знайдено (запомнено)
fAuthenticated Якщо TRUE, То пристрій пройшло авторизацію (Авторизуватися)
stLastSeen Дата і час останнього виявлення пристрою
stLastUsed Дата і час останнього використання пристрою
szName Назва пристрою (ім’я)

BLUETOOTH_RADIO_INFO


Оголошення: BLUETOOTH_RADIO_INFO = record
   dwSize : DWORD;
   address : BLUETOOTH_ADDRESS;
   szName : array [0..BLUETOOTH_MAX_NAME_SIZE – 1] of WideChar;
   ulClassofDevice : ULONG;
   lmpSubversion : Word;
   manufacturer : Word;
end;

Члени:





















dwSize Повинен бути дорівнює розміру структури (dwSize := SizeOf(BLUETOOTH_RADIO_INFO))
Address Адреса радіомодуля Bluetooth
szName Ім’я радіомодуля
ulClassofDevice Клас пристрою (див. вище)
lmpSubversion Залежить від виробника
Manufacturer Код виробника. Визначається константами BTH_MFG_Xxx. Більш повну інформацію про виробників можна отримати на сайті підтримки Bluetooth.

Далі напишемо ось такий обробник події OnChange для TreeView: procedure TfmMain.TreeViewChange(Sender: TObject; Node: TTreeNode);
var
   ASelected: TTreeNode;

procedure ShowRadios;
   var
     Info: PBLUETOOTH_RADIO_INFO;
     CurNode: TTreeNode;
begin
/ / Будуємо стовпці
   with ListView.Columns do
     begin
       BeginUpdate;
       with Add do Caption := “Address”;
       with Add do Caption := “Name”;
       with Add do Caption := “Class Of Device”;
       with Add do Caption := “Manufacturer”;
       with Add do Caption := “Subversion”;
       with Add do Caption := “Connectable”;
       with Add do Caption := “Discoverable”;
       EndUpdate;
     end;

/ / Заповнюємо список
   with ListView.Items do
     begin
       BeginUpdate;

       CurNode := ASelected.GetFirstChild;

       while Assigned(CurNode) do          begin
           Info := PBLUETOOTH_RADIO_INFO(CurNode.Data);

/ / Перечитати інформацію про радіомодуля
           BluetoothGetRadioInfo(CurNode.ImageIndex, Info^);

           with Add do
             begin
               Data := Pointer(CurNode.ImageIndex);
               Caption := BTAdrToStr(Info.address);
               with SubItems do
                 begin
                   Add(string(Info.szName));
                   Add(IntToStr(Info.ulClassofDevice));
                   Add(IntToStr(Info.manufacturer));
                   Add(IntToStr(Info.lmpSubversion));
                   // NEW FUNCTIONS!!!
                   Add(BoolToStr(BluetoothIsConnectable(CurNode.ImageIndex), True));
                   Add(BoolToStr(BluetoothIsDiscoverable(CurNode.ImageIndex), True));
                 end;
             end;

           CurNode := ASelected.GetNextChild(CurNode);
         end;

       EndUpdate;
     end;
   end;

procedure ShowDevices;
   var
     Info: ^PBLUETOOTH_DEVICE_INFO;
     CurNode: TTreeNode;
begin
/ / Будуємо стовпці
   with ListView.Columns do
     begin
       BeginUpdate;
       with Add do Caption := “Address”;
       with Add do Caption := “Name”;
       with Add do Caption := “Class Of Device”;
       with Add do Caption := “Connected”;
       with Add do Caption := “Remembered”;
       with Add do Caption := “Authenticated”;
       with Add do Caption := “Last Seen”;
       with Add do Caption := “Last Used”;
       EndUpdate;
     end;

/ / Заповнюємо список
   with ListView.Items do
     begin
       BeginUpdate;

       CurNode := ASelected.GetFirstChild;

       while Assigned(CurNode) do
         begin
           Info := CurNode.Data;

/ / Перечитуємо інформацію про пристрій
/ / Так як передаємо покажчик, то вона автоматом
/ / Оновиться і в тому місці, де ми її зберігали
           BluetoothGetDeviceInfo(ASelected.ImageIndex, Info^);

           with Add do
             begin
               Data := Info;
               Caption := BTAdrToStr(Info^.Address);
               with SubItems do
                 begin
                   Add(string(Info^.szName));
                   Add(IntToStr(Info^.ulClassofDevice));
                   Add(BoolToStr(Info^.fConnected, True));
                   Add(BoolToStr(Info^.fRemembered, True));
                   Add(BoolToStr(Info^.fAuthenticated, True));
try / / stLastSeen може бути 0 і тоді тут помилка буде
                     Add(DateTimeToStr(SystemTimeToDateTime(Info^.stLastSeen)));
                   except
                     Add(‘’);
                   end;
try / / stLastUsed може бути 0 і тоді тут помилка буде
                     Add(DateTimeToStr(SystemTimeToDateTime(Info^.stLastUsed)));
                   except
                     Add(‘’);
                   end;
                 end;
               end;

             CurNode := ASelected.GetNextChild(CurNode);
         end;

       EndUpdate;
     end;
end;

procedure ShowServices;
   var
     Info: __PBLUETOOTH_DEVICE_INFO;
     ServiceCount: dword;
     Services: array of TGUID;
     hRadio: THandle;
     Loop: integer;
begin
/ / Будуємо стовпці
   with ListView.Columns do
     begin
       BeginUpdate;
       with Add do Caption := “GUID”;
       EndUpdate;
     end;

/ / Заповнюємо список
   with ListView.Items do
     begin
       BeginUpdate;

/ / Отримуємо розмір масиву сервісів
       ServiceCount := 0;
       Services := nil;
       hRadio := ASelected.Parent.ImageIndex;
       Info := ASelected.Data;
       // NEW FUNCTION
       BluetoothEnumerateInstalledServices

(hRadio, Info, ServiceCount, nil);

/ / Виділяємо пам’ять.
SetLength(Services, ServiceCount);

/ / Отримуємо список сервісів
BluetoothEnumerateInstalledServices

(hRadio, Info, ServiceCount, PGUID(Services));

/ / Малюємо їх
for Loop := 0 to ServiceCount – 1 do
with Add do
Caption := GUIDToString(Services[Loop]);

/ / Очищаємо пам’ять
Services := nil;

EndUpdate;
end;
end;

begin
ASelected := TreeView.Selected;

/ / Очищаємо ListView
with ListView do
begin
with Columns do
begin
BeginUpdate;
Clear;
EndUpdate;
end;

with Items do
begin
BeginUpdate;
Clear;
EndUpdate;
end;
end;

/ / Заповнюємо інформацією
if Assigned(ASelected) then
case ASelected.ImageIndex of
-2: ShowServices;
-1: ShowRadios;
else
if ASelected.ImageIndex > 0 then ShowDevices;
end;
end;

У цьому коді з’явилося три нові функції, які виділені жирним шрифтом. Ось вони


BluetoothIsConnectable – Визначає, чи можливе підключення до зазначеного радіомодуля.


Оголошення функції: function BluetoothIsConnectable (
   const hRadio : THandle): BOOL; stdcall;

Параметри:






hRadio Handle радіомодуля, який ми перевіряємо. Якщо 0, то перевіряються всі радіомодулі.

Значення, що повертаються:

BluetoothIsDiscoverable – Визначає, чи буде видно вказаний радіомодуль іншим при пошуку. Якщо проглядаються всі радіомодулі, то поверне TRUE якщо хоча б один дозволяє виявлення.


Оголошення функції: function BluetoothIsDiscoverable (
   const hRadio : THandle): BOOL; stdcall;

Параметри:






hRadio Handle радіомодуля, який ми перевіряємо. Якщо 0, то перевіряються всі радіомодулі.

Значення, що повертаються:

BluetoothEnumerateInstalledServices – Отримує список GUID сервісів, що надаються пристроєм. Якщо параметр hRadio=0, То переглядає всі радіомодулі.


Оголошення функції: function BluetoothEnumerateInstalledServices (
   hRadio : THandle;
   pbtdi : __PBLUETOOTH_DEVICE_INFO;
   var pcServices : dword;
   pGuidServices : PGUID): dword; stdcall;

Параметри:















hRadio Handle радіомодуля, який ми перевіряємо. Якщо 0, то перевіряються всі радіомодулі.
pbtdi Покажчик на структуру BLUETOOTH_DEVICE_INFO, В якій описано проверяемое пристрій. Необхідно заповнити поля dwSize і Address.
pcServices При виклику – кількість записів в масиві pGuidServices, Повертає в цьому параметрі реальна кількість сервісів, що надаються пристроєм.
pGuidServices Покажчик на масив TGUID, В який будуть записані GUID надаються пристроєм сервісом. Якщо nil і pcServices=0, То в pcServices буде записано кількість сервісів. Необхідно виділити для pGuidServices пам’ять розміром не менше pcServices*SizeOf(TGUID).

Значення, що повертаються:

Примітки:


Подивіться на код отримання списку сервісів: / / Отримуємо розмір масиву сервісів
ServiceCount := 0;
Services := nil;
hRadio := ASelected.Parent.ImageIndex;
Info := ASelected.Data;
// NEW FUNCTION
BluetoothEnumerateInstalledServices(hRadio, Info, ServiceCount, nil);

/ / Виділяємо пам’ять.
SetLength(Services, ServiceCount);

/ / Отримуємо список сервісів
BluetoothEnumerateInstalledServices(hRadio, Info, ServiceCount, PGUID(Services))

Спочатку ми викликаємо функцію з pcServices=0 і pGuidServices=nil для того, щоб отримати кількість сервісів, що надаються пристроєм.


Потім виділяємо пам’ять (SetLength()) І тільки потім викликаємо функцію з реальними параметрами і отримуємо список сервісів.


Ще важливе зауваження. У файлі JwaBluetoothAPIs.pas параметр pbtdi має тип PBLUETOOTH_DEVICE_INFO, Який розкривається в BLUETOOTH_DEVICE_INFO. Зауважте, що це НЕ ПОКАЖЧИК. Це не вірно, тому що в початковому вигляді функція вимагає саме покажчик. По-цьому, я ввів тип type
   __PBLUETOOTH_DEVICE_INFO = ^PBLUETOOTH_DEVICE_INFO

Так що ВИКОРИСТОВУЙТЕ файл з прикладу, а не з вихідної бібліотеки. Інакше отримаєте порушення доступу до пам’яті.


Коментар до коду: Ми перечитуємо інформацію про пристрій, так як за час, поки ми милуємося програмою, могли відбутися різні події: пристрій відключили, скасували авторизацію і т. п. А ми хочемо мати найсвіжішу інформацію про пристрій.


В принципі те, що описано вище, ми вже знали, окрім двох зазначених функцій.


Давайте розширимо можливості нашого застосування. Додамо функції заборони / дозволу виявлення радіомодуля і заборони / дозволу підключення до нього.


BluetoothEnableIncomingConnections і BluetoothEnableDiscoverable


Помістимо на форму компонент TactionList і змінимо його властивості як показано в таблиці.









Властивість  Значення 
Name ActionList


Тепер два рази клацнемо по ActionList і у вікні редактора властивостей додавши дві TAction з наступними властивостями:












Властивість  Значення 
Caption Connectable
Name acConnectable













Властивість  Значення 
Caption Discoverable
Name acDiscoverable

На панель Panel додав дві TButton і встановимо властивості:












Властивість  Значення 
Action acConnectable
Name btConnectable













Властивість  Значення 
Action acDiscoverable
Name btDiscoverable

Напишемо ось такий обробник події OnUpdate у acConnectable: procedure TfmMain.acConnectableUpdate(Sender: TObject);
var
   SelectedItem: TListItem;
   SelectedNode: TTreeNode;
begin
   SelectedNode := TreeView.Selected;
   SelectedItem := ListView.Selected;

   with TAction(Sender) do
     begin
     Enabled := Assigned(SelectedNode) and Assigned(SelectedItem) and (SelectedNode.ImageIndex = -1);

     if Enabled then
       if StrToBool(SelectedItem.SubItems[4])
         then Caption := “Not conn.”
         else Caption := “Connectable”;
     end;
end; І те ж саме напишемо для обробника події OnUpdateacDiscoverable: procedure TfmMain.acDiscoverableUpdate(Sender: TObject);
var
   SelectedItem: TListItem;
   SelectedNode: TTreeNode;
begin
   SelectedNode := TreeView.Selected;
   SelectedItem := ListView.Selected;

   with TAction(Sender) do
     begin
       Enabled := Assigned(SelectedNode) and Assigned(SelectedItem) and (SelectedNode.ImageIndex = -1);

       if Enabled then
         if StrToBool(SelectedItem.SubItems[5])
           then Caption := “Not disc.”
           else Caption := “Discoverable”;
       end;
end; Тепер обробник події OnExecute для acConnectable: procedure TfmMain.acConnectableExecute(Sender: TObject);
var
   SelectedItem: TListItem;
begin
   SelectedItem := ListView.Selected;

   if Assigned(SelectedItem) then
     if not BluetoothEnableIncomingConnections(Integer(SelectedItem.Data), TAction(Sender).Caption = “Not conn.”)
       then MessageDlg(“Unable to change Radio state”, mtError, [mbOK], 0)
       else TreeViewChange(TreeView, TreeView.Selected);
end; Такий же обробник напишемо і для OnExecuteacDiscoverable: procedure TfmMain.acConnectableExecute(Sender: TObject);
var
   SelectedItem: TListItem;
begin
   SelectedItem := ListView.Selected;

   if Assigned(SelectedItem) then
     if not BluetoothEnableDiscovery(Integer(SelectedItem.Data), TAction(Sender).Caption = “Not disc.”)
       then MessageDlg(“Unable to change Radio state”, mtError, [mbOK], 0)
       else TreeViewChange(TreeView, TreeView.Selected);
end;

Висновок вікна властивостей пристрою


Важливо: Якщо Windows сам використовує радіомодуль, то він не дасть поміняти статус, хоч і функція виконається без помилок!


Тут ми ввели дві нові функції (виділені жирним):


BluetoothEnableInfomingConnection – Функція дозволяє / забороняє підключення до локального радіомодуля Bluetooth.


Оголошення функції: function BluetoothEnableIncomingConnections (
   hRadio : THandle;
   fEnabled : BOOL): BOOL; stdcall;

Параметри:









hRadio Handle радіомодуля, статус якого ми хочемо змінити. Якщо 0, то міняємо у всіх.
fEnabled TRUE – Дозволяємо підключення; FALSE – Забороняємо.

Значення, що повертаються:

BluetoothEnableDiscovery – Функція дозволяє / забороняє виявлення локального радіомодуля Bluetooth


Оголошення функції: function BluetoothEnableDiscovery (
   hRadio : THandle;
   fEnabled : BOOL): BOOL; stdcall;

Параметри:









hRadio Handle радіомодуля, статус якого ми хочемо змінити. Якщо 0, то міняємо у всіх.
fEnabled TRUE – Дозволяємо виявлення; FALSE – Забороняємо.

Значення, що повертаються:

Тепер давайте навчимося виводити системне вікно властивостей пристрою Bluetooth. Для цього додамо до ActionList ще один TAction от з такими властивостями:












Властивість  Значення 
Caption Property
Name acProperty


Додамо на Panel кнопку TButton з такими властивостями:












Властивість  Значення 
Action acProperty
Name btProperty


Тепер напишемо такий обробник подій OnUpdate у acProperty: procedure TfmMain.acPropertyUpdate(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 > 0);
end; І обробник OnExecute для неї ж: procedure TfmMain.acPropertyExecute (Sender: TObject);
var
   Info: BLUETOOTH_DEVICE_INFO;
begin
   Info := BLUETOOTH_DEVICE_INFO(ListView.Selected.Data^);
   BluetoothDisplayDeviceProperties(Handle, Info);
end;

Важливо: В початковому вигляді у файлі JwaBluetoothAPIs функція BluetoothDisplayDeviceProperties оголошена не вірно. Другий параметр повинен бути дороговказом, а там він передається як структура. Я виправив функцію так, щоб він передавався як var-параметр (за посиланням). Використовуйте модуль JwaBluetoothAPIs з цього прикладу, щоб не виникало помилок доступу до пам’яті.


Важливо: Ні в цій процедурі, ні раніше, ні далі я не проводжу перевірку помилок, щоб не захаращувати код зайвими подробицями. В реальному додатку НЕОБХІДНО перевіряти повертаються функціями значення і покажчики.


І так, в цьому коді є нова функція, виділена жирним шрифтом.


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 в якій міститься адресу потрібного пристрою.

Значення, що повертаються:

Вибір пристрою


Розглянемо, як викликати вікно діалогу вибору пристрою.


Додамо в наш проект на 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 Опис дивіться вище в описі структури.

Значення, що повертаються:

Управління сервісами

Для управління сервісами 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


Опис цієї функції дано вище. Тут

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*