2015-07-04 3 views
0

Я пытаюсь отсканировать соседнее устройство Bluetooth для их MAC-адреса с помощью интерфейса API Winsock2. Используя код ниже, я могу найти устройства. Но когда я пытаюсь получить их адрес, используя WSAAddressToString, получите сообщение об ошибке 10022 (WSAEINVAL): «Был указан недопустимый аргумент».Delphi: WSAAddressToString возвращает код ошибки 10022 (WSAEINVAL)

Код:

uses 
    winsock2, bt_helper; 

procedure test; 
var 
    ulFlags: u_long; 
    QuerySet: WSAQUERYSET; 
    QuerySize: u_long; 
    HLookup: THandle; 
    Result: Integer; 

    pCSAddr: pCSADDR_INFO; 
    pDeviceInfo: PBTH_DEVICE_INFO; 
    pResults: lpWSAQUERYSET; 
    Buffer: array [0..999] of Byte; 

    ProtocolInfo: WSAPROTOCOL_INFO; 
    ProtocolInfoSize: Integer; 

    BufferLength, AddressSize: LongWord; 
    addressAsString: array [0..1999] of Char; 
begin 

WSAStartup ($0202, Data); 

ulFlags:= 
    LUP_CONTAINERS or //device inquiry 
    LUP_RETURN_NAME or //Friendly device name (if available) will be returned in lpszServiceInstanceName 
    LUP_RETURN_ADDR or //BTH_ADDR will be returned in lpcsaBuffer member of WSAQUERYSET 
    LUP_FLUSHCACHE ; //Flush the device cache for all inquiries, except for the first inquiry 

QuerySize:= SizeOf(WSAQuerySet); 
ZeroMemory (@QuerySet, SizeOf(QuerySet)); 

QuerySet.dwNameSpace:= NS_BTH; 
QuerySet.dwSize:= QuerySize; 

Result:= WSALookupServiceBegin(@QuerySet, ulFlags, HLookup); 

if Result = 0 then 
begin 
    while true do 
    begin  
    bufferLength:= sizeof(buffer); 
    pResults:= lpWSAQUERYSET(@buffer); 
    Result:= WSALookupServiceNext (HLOOKUP, ulFlags, bufferLength, pResults); 

    if Result = 0 then 
    begin 
     // Get the device info, name, address, etc. 
     Memo1.Lines.Add(Format('The service instance name is %s', [pResults.lpszServiceInstanceName])); 
     //pCSAddr.LocalAddr.lpSockaddr.sa_family:= AF_INET; 
     pCSAddr:= PCSADDR_INFO(pResults.lpcsaBuffer); 
     pDeviceInfo:= PBTH_DEVICE_INFO(pResults.lpBlob); 

     // Print the local Bluetooth device address ... 
     AddressSize:= sizeof(addressAsString); 

     if WSAAddressToString(pCSAddr.LocalAddr.lpSockaddr^, pCSAddr.LocalAddr.iSockaddrLength, 
     @ProtocolInfo, @AddressAsString, AddressSize) = 0 
     then 
     Memo1.Lines.Add(Format ('The localAddress: %s', [AddressAsString])) 
     else 
     Memo1.Lines.Add(Format ('WSAAddressToString for localAddress failed with error code %d: %s', 
      [WSAGetLastError, SysErrorMessage (WSAGetLastError)])); 

     // Print the remote Bluetooth device address ... 
     AddressSize:= sizeof(addressAsString); 
     IF WSAAddressToString(pCSAddr.RemoteAddr.lpSockaddr^, pCSAddr.RemoteAddr.iSockaddrLength, 
     @ProtocolInfo, @AddressAsString, Addresssize) = 0 
     then 
     Memo1.Lines.Add (Format ('The remote device address: %s', [AddressAsString])) 
     else 
     Memo1.Lines.Add (Format ('WSAAddressToString for remoteAddress failed with error code %d: %s', 
      [WSAGetLastError, SysErrorMessage(WSAGetLastError)])); 
    end 
    else 
    begin 
     Memo1.Lines.Add(SysErrorMessage(WSAGetLastError)); 
     break; 
    end; 
    end; 
end;  
WSALookupServiceEnd(HLookup); 

Вот результат в памятке:

The service instance name is BTDevice1 
WSAAddressToString for localAddress failed with error code 10022: An invalid argument was supplied 
WSAAddressToString for remoteAddress failed with error code 10022: An invalid argument was supplied 
--------------------------------- 
No more results can be returned by WSALookupServiceNext 

Используйте следующий блок для компиляции:

unit bt_helper; 

interface 

uses 
    winsock2, Winapi.Windows; 

const 
    BTH_MAX_NAME_SIZE = 248; 
    BTHPROTO_RFCOMM= 3; 
    BT_PORT_ANY = -1; 

type 
    BTH_ADDR = int64; 

    SOCKADDR_BTH = packed record 
    addressFamily  :word;   // Always AF_BTH 
    btAddr    :BTH_ADDR;  // Bluetooth device address 
    serviceClassId  :TGUID;   // [OPTIONAL] system will query SDP for port 
    port    :dword;   // RFCOMM channel or L2CAP PSM 
    end; 

    BTH_COD = ULONG; 

    _BTH_DEVICE_INFO = record 
    flags: ULONG;      // Combination BDIF_Xxx flags 
    address: BTH_ADDR;     // Address of remote device. 
    classOfDevice: BTH_COD;   // Class Of Device. 
    name: array [0..BTH_MAX_NAME_SIZE - 1] of CHAR; // name of the device 
    end; 
    {$EXTERNALSYM _BTH_DEVICE_INFO} 
    BTH_DEVICE_INFO = _BTH_DEVICE_INFO; 
    {$EXTERNALSYM BTH_DEVICE_INFO} 
    PBTH_DEVICE_INFO = ^BTH_DEVICE_INFO; 
    {$EXTERNALSYM PBTH_DEVICE_INFO} 
    TBthDeviceInfo = BTH_DEVICE_INFO; 
    PBthDeviceInfo = PBTH_DEVICE_INFO;  

implementation 

end. 
+0

использовать длину() вместо SizeOf() – whosrdaddy

+0

и пожалуйста включите компилируемый пример? – whosrdaddy

+0

Документация для 'WSAEINVAL' говорит * Неверный параметр был передан. Эта ошибка возвращается, если параметр lpsaAddress, dwAddressLength или lpdwAddressStringLength равен NULL. Эта ошибка также возвращается, если указанный адрес не является допустимым адресом сокета, или поставщик транспорта не поддерживает указанное семейство адресов. * Вы проверили эти условия? –

ответ

2

Если вы читаете documentation of WSAAddressToString близко вы бы заметили этот пункт:

lpProtocolInfo [in, optional] Указатель на структуру WSAPROTOCOL_INFO для конкретного поставщика. Если этот параметр равен NULL, вызов направляется провайдеру первого протокола, поддерживающего семейство адресов , указанное в параметре lpsaAddress.

поэтому вместо того, чтобы снабжать фальшивую структуру информации WSA_PROTOCOL, вы должны пройти в нуле. Вторая проблема заключается в том, что вы используете SizeOf(), чтобы определить длину буфера Струнный, это неправильно, и вы должны использовать Length():

AddressSize:= Length(addressAsString); 

if WSAAddressToString(pCSAddr.LocalAddr.lpSockaddr^, pCSAddr.LocalAddr.iSockaddrLength, 
    nil, @AddressAsString, AddressSize) = 0 then 
begin 
    SetLength(AddressAsString, AddressSize-1);// resize to returned length minus last null character 
    ... 
+0

Ваше решение сработало. Большое спасибо. Я могу получить удаленный MAC-адрес Bluetooth, используя 'pCSAddr.RemoteAddr.lpSockaddr'. Это то, что я хочу. Но первая часть LocalAddr возвращает ошибку 10022. – SAMPro

+0

@SAMPro, да почему-то локальный адрес пустой строки, я думаю, что это нормально для bluetooth. – whosrdaddy

Смежные вопросы