Работа с Bluetooth в Delphi

Правее 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 BluetoothFindDevice(hDevFind, DevInfo^);
// Поиск устройств закончен
BluetoothFindDeviceClose(hDevFind);
end;
// Находим следующее радио
until not BluetoothFindRadio(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;
&#1047;&#1076;&#1077;&#1089;&#1100; &#1093;&#1086;&#1095;&#1091; &#1087;&#1088;&#1080;&#1074;&#1077;&#1089;&#1090;&#1080; &#1086;&#1087;&#1080;&#1089;&#1072;&#1085;&#1080;&#1077; &#1080;&#1089;&#1087;&#1086;&#1083;&#1100;&#1079;&#1091;&#1077;&#1084;&#1099;&#1093; &#1089;&#1090;&#1088;&#1091;&#1082;&#1090;&#1091;&#1088;, &#1090;&#1072;&#1082; &#1082;&#1072;&#1082; &#1088;&#1072;&#1085;&#1077;&#1077; &#1103; &#1080;&#1093; &#1085;&#1077; &#1086;&#1087;&#1080;&#1089;&#1099;&#1074;&#1072;&#1083;:
BLUETOOTH_DEVICE_SEARCH_PARAMS
&#1054;&#1073;&#1098;&#1103;&#1074;&#1083;&#1077;&#1085;&#1080;&#1077;:
<code>
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;
&#1063;&#1083;&#1077;&#1085;&#1099;:
dwSize
&#1044;&#1086;&#1083;&#1078;&#1077;&#1085; &#1073;&#1099;&#1090;&#1100; &#1088;&#1072;&#1074;&#1077;&#1085; &#1088;&#1072;&#1079;&#1084;&#1077;&#1088;&#1091; &#1089;&#1090;&#1088;&#1091;&#1082;&#1090;&#1091;&#1088;&#1099; (dwSize := SizeOf(BLUETOOTH_RADIO_INFO))
Address
&#1040;&#1076;&#1088;&#1077;&#1089; &#1088;&#1072;&#1076;&#1080;&#1086;&#1084;&#1086;&#1076;&#1091;&#1083;&#1103; Bluetooth
szName
&#1048;&#1084;&#1103; &#1088;&#1072;&#1076;&#1080;&#1086;&#1084;&#1086;&#1076;&#1091;&#1083;&#1103;
ulClassofDevice
&#1050;&#1083;&#1072;&#1089;&#1089; &#1091;&#1089;&#1090;&#1088;&#1086;&#1081;&#1089;&#1090;&#1074;&#1072; (&#1089;&#1084;. &#1074;&#1099;&#1096;&#1077;)
lmpSubversion
&#1047;&#1072;&#1074;&#1080;&#1089;&#1080;&#1090; &#1086;&#1090; &#1087;&#1088;&#1086;&#1080;&#1079;&#1074;&#1086;&#1076;&#1080;&#1090;&#1077;&#1083;&#1103;
Manufacturer
&#1050;&#1086;&#1076; &#1087;&#1088;&#1086;&#1080;&#1079;&#1074;&#1086;&#1076;&#1080;&#1090;&#1077;&#1083;&#1103;. &#1054;&#1087;&#1088;&#1077;&#1076;&#1077;&#1083;&#1103;&#1077;&#1090;&#1089;&#1103; &#1082;&#1086;&#1085;&#1089;&#1090;&#1072;&#1085;&#1090;&#1072;&#1084;&#1080; BTH_MFG_Xxx. &#1041;&#1086;&#1083;&#1077;&#1077; &#1087;&#1086;&#1083;&#1085;&#1091;&#1102; &#1080;&#1085;&#1092;&#1086;&#1088;&#1084;&#1072;&#1094;&#1080;&#1102; &#1086; &#1087;&#1088;&#1086;&#1080;&#1079;&#1074;&#1086;&#1076;&#1080;&#1090;&#1077;&#1083;&#1103;&#1093; &#1084;&#1086;&#1078;&#1085;&#1086; &#1087;&#1086;&#1083;&#1091;&#1095;&#1080;&#1090;&#1100; &#1085;&#1072; &#1089;&#1072;&#1081;&#1090;&#1077; &#1087;&#1086;&#1076;&#1076;&#1077;&#1088;&#1078;&#1082;&#1080; 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.GetChild(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.GetChild(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, то проверяются все радиомодули. Возвращаемые значения: ·Вернет TRUE, если указанный радиомодуль разрешает входящие подключения. Если hRadio=0, то вернет TRUE, если хотя бы один радиомодуль разрешает входящие подключения. ·Если входящие подключения запрещены, то вернет FALSE. BluetoothIsDiscoverable - определяет, будет ли виден указанный радиомодуль другим при поиске. Если просматриваются все радиомодули, то вернет TRUE если хотя бы один разрешает обнаружение. Объявление функции:
function BluetoothIsDiscoverable(const hRadio : THandle): BOOL; stdcall;
Параметры: hRadio Handle радиомодуля, который мы проверяем. Если 0, то проверяются все радиомодули. Возвращаемые значения: ·Вернет TRUE, если указанный радиомодуль разрешает обнаружение. Если hRadio=0, то вернет TRUE, если хотя бы один радиомодуль разрешает обнаружение. ·Если обнаружение запрещено, то вернет FALSE. 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). Возвращаемые значения: ·Вернет ERROR_SUCCESS, если вызов успешен и количество сервисов в pcServices соответствует реальности. ·Вернет ERROR_MORE_DATA, если вызов успешен, но выделенное количество памяти (pcServices при вызове) меньше, чем количество предоставляемых сервисов. ·В случае ошибки – другие коды ошибок Win32. Примечания: Посмотрите на код получения списка сервисов:
// Получаем размер массива сервисов
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))

Отправить комментарий

Проверка
Антиспам проверка
Image CAPTCHA
...