📄 sdptest.cxx
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
/**
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
Abstract:
Windows CE Bluetooth application sample
**/
#if ! defined (UNDER_CE)
// Needed to get CoInitializeEx()
#define _WIN32_DCOM
#include <stdio.h>
#endif
#include <winsock2.h>
#include <windows.h>
#include <svsutil.hxx>
#include "bt_api.h"
#include "bt_sdp.h"
#include "bt_buffer.h"
#include "bt_ddi.h"
#include "btdc.h"
#include "bthapi.h"
#define BUFFER_SIZE 1500
// CE values
const CLSID CLSID_SdpRecord = {0xACD02BA7,0x9667,0x4085,{0xA1,0x00,0xCC,0x6A,0xCA,0x96,0x21,0xD6}};
const CLSID CLSID_SdpNodeContainer = {0xD5CA76C5,0x0DEE,0x4453,{0x96,0xA1,0xE6,0x03,0xC2,0x40,0x17,0x66}};
#define GUID_FORMAT "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x\n"
#define GUID_ELEMENTS(p) \
&p->Data1, &p->Data2, &p->Data3,\
&p->Data4[0], &p->Data4[1], &p->Data4[2], &p->Data4[3],\
&p->Data4[4], &p->Data4[5], &p->Data4[6], &p->Data4[7]
BOOL CreateSdpRecord(WCHAR *szFile, UCHAR **ppStream, ULONG *pSize);
#define ADD_ENTRY() if (pRecord) pRecord->SetAttribute(attribVal, &ndw); \
else pCont->AppendNode(&ndw);
#define MAX_HANDLES 50
#define MAX_ATTRIBUTES 50
#define SKIP_WHITESPACE(p) while (*(p) && iswspace(*(p))) ++(p);
void PrintStream(PUCHAR Stream, ULONG Size)
{
for (ULONG i = 0; i < Size; i++) {
printf("%02x, ", (ULONG) Stream[i]);
}
}
FILE *SdpOpenFile(WCHAR *szFileName) {
FILE *pFile;
pFile = _wfopen(szFileName, L"r");
if (!pFile)
wprintf(L"Cannot open file: %s\n",szFileName);
return pFile;
}
#define SDP_RECORD_COMMENT_CHAR ';'
void SdpReadString(FILE *pf, CHAR *buffer, int iSizeofBuffer) {
int i;
for (i = 0; i < iSizeofBuffer; i++) {
if (EOF == fscanf(pf, "%c", &buffer[i])) {
buffer[i] = 0;
break;
}
if (buffer[i] == '\r' || buffer[i] == '\n') {
if (buffer[i] == '\r')
fscanf(pf, "%c", &buffer[i]);
buffer[i] = 0;
break;
}
}
}
// Handles comments in stream.
BOOL ParseHandleComment(FILE *pf, PSTR szBuffer, DWORD cbBuffer) {
if (szBuffer[0] != SDP_RECORD_COMMENT_CHAR)
return FALSE;
int iLen = strlen(szBuffer);
SdpReadString(pf,szBuffer+iLen,cbBuffer-iLen);
return TRUE;
}
const BD_ADDR zeroAddr = {0};
void InitWSAQuerySet(WSAQUERYSET *pw, BT_ADDR *pba=NULL, CSADDR_INFO *pcsaBuffer=NULL, SOCKADDR_BTH *psockBT=NULL, LPBLOB pBlob=NULL) {
memset(pw,0,sizeof(WSAQUERYSET));
pw->dwSize = sizeof(WSAQUERYSET);
pw->dwNameSpace = NS_BTH;
pw->lpBlob = pBlob;
if (pba) {
pw->lpcsaBuffer = pcsaBuffer;
memset(pcsaBuffer,0,sizeof(CSADDR_INFO));
memset(psockBT,0,sizeof(SOCKADDR_BTH));
memcpy(&psockBT->btAddr,pba,sizeof(BT_ADDR));
pcsaBuffer->RemoteAddr.lpSockaddr = (LPSOCKADDR) psockBT;
pcsaBuffer->RemoteAddr.iSockaddrLength = sizeof(SOCKADDR_BTH);
}
}
BOOL ReadUUIDs(FILE *pFile, SdpQueryUuid* pUUIDs, unsigned short *pcUUIDs, BOOL fEOF) {
char buffer[2048];
int i;
GUID guid[2];
*pcUUIDs = 0;
while (EOF != fscanf(pFile, "%s", buffer)) {
if (ParseHandleComment(pFile,buffer,sizeof(buffer)))
continue;
// When we read in GUIDS + Attrib (fEOF=FALSE) then stop reading GUID at "END"
if (!fEOF && (_stricmp(buffer,"END") == 0)) {
if (0 == *pcUUIDs) {
wprintf(L"Syntax: No UUIDS specified\n");
return FALSE;
}
return TRUE;
}
if (*pcUUIDs == MAX_UUIDS_IN_QUERY) {
wprintf(L"Cannot have > %d UUIDs in ServiceSearch\n",MAX_UUIDS_IN_QUERY);
return FALSE;
}
if (_stricmp(buffer,"UUID16") == 0) {
fscanf(pFile, "%x\n", &i);
pUUIDs[*pcUUIDs].u.uuid16 = (unsigned short) i;
pUUIDs[*pcUUIDs].uuidType = SDP_ST_UUID16;
}
else if (_stricmp(buffer,"UUID32") == 0) {
fscanf(pFile, "%x\n", &i);
pUUIDs[*pcUUIDs].u.uuid32 = i;
pUUIDs[*pcUUIDs].uuidType = SDP_ST_UUID32;
}
else if (_stricmp(buffer,"UUID128") == 0) {
memset(&guid,0,sizeof(guid));
fscanf(pFile,GUID_FORMAT,GUID_ELEMENTS((&guid[0])));
pUUIDs[*pcUUIDs].uuidType = SDP_ST_UUID128;
memcpy(&pUUIDs[*pcUUIDs].u.uuid128,&guid[0],sizeof(guid[0]));
}
else {
wprintf(L"GUID must be prefaced by UUID16, UUID32, or UUID128\n");
return FALSE;
}
*pcUUIDs += 1;
}
if (0 == *pcUUIDs) {
wprintf(L"Syntax: No UUIDS specified\n");
return FALSE;
}
return TRUE;
}
BOOL ReadAttributes(FILE *pFile, unsigned long *pulHandle, SdpAttributeRange *pRange, unsigned long *pcAttributes) {
CHAR buffer[2048];
*pcAttributes = 0;
if (pulHandle) {
do {
if (EOF == fscanf(pFile,"%s",buffer)) {
wprintf(L"syntax: Handle syntax in file\r\n");
return FALSE;
}
if (ParseHandleComment(pFile,buffer,sizeof(buffer)))
continue;
if (! sscanf(buffer,"%x",pulHandle)) {
wprintf(L"syntax: Handle syntax in file\r\n");
return FALSE;
}
break;
} while(1);
}
while (EOF != fscanf(pFile,"%s",buffer)) {
if (ParseHandleComment(pFile,buffer,sizeof(buffer)))
continue;
if (! sscanf(buffer,"%x",(unsigned long*)&pRange[*pcAttributes].minAttribute)) {
wprintf(L"syntax: Min Attrib ID syntax, element #=%d\r\n",*pcAttributes);
return FALSE;
}
if (EOF == fscanf(pFile,"%s",buffer)) {
wprintf(L"syntax: Max Attrib ID syntax, element #=%d\r\n",*pcAttributes);
return FALSE;
}
if (! sscanf(buffer,"%x",(unsigned long*)&pRange[*pcAttributes].maxAttribute)) {
wprintf(L"syntax: Max Attrib ID syntax, element #=%d\r\n",*pcAttributes);
return FALSE;
}
*pcAttributes = *pcAttributes+1;
}
return TRUE;
}
/************************************************************
void TestSdpInquiry(void)
Performs a device inquiry using the exposed BTH NS Api.
************************************************************/
void TestSdpInquiry(WCHAR *szCmd) {
WSAQUERYSET wsaQuery;
DWORD dwGetNextFlags = LUP_RETURN_ADDR;
if (0 == wcsnicmp(szCmd,L"-name ",6)) {
szCmd += 6;
dwGetNextFlags |= LUP_RETURN_NAME;
}
if (0 == wcsnicmp(szCmd,L"-blob",5)) {
dwGetNextFlags |= LUP_RETURN_BLOB;
}
DWORD dwFlags = LUP_CONTAINERS;
InitWSAQuerySet(&wsaQuery);
BTHNS_INQUIRYBLOB inquiryRestrictions;
#define INQUIRY_GIAC_LAP 0x9e8b33 // unlimited inquiry access mode (GIAC)
inquiryRestrictions.LAP = INQUIRY_GIAC_LAP;
inquiryRestrictions.length = 5;
inquiryRestrictions.num_responses = 3;
BLOB blob;
blob.cbSize = sizeof (inquiryRestrictions);
blob.pBlobData = (BYTE*) &inquiryRestrictions;
wsaQuery.lpBlob = &blob;
HANDLE hLookup;
SetLastError(0);
int iRet = BthNsLookupServiceBegin(&wsaQuery,dwFlags,&hLookup);
wprintf(L"BthNsLookupServiceBegin returned 0x%08x,GLE=0x%08x\r\n",iRet,GetLastError());
if (ERROR_SUCCESS != iRet) {
return;
}
union {
CHAR szBuf[BUFFER_SIZE];
SOCKADDR_BTH __unused; // properly align buffer to BT_ADDR requirements
};
LPWSAQUERYSET pResults = (LPWSAQUERYSET) szBuf;
DWORD dwLen = sizeof(szBuf);
DWORD i = 0;
#if defined (UNDER_CE)
SetLastError(0);
while (ERROR_SUCCESS == (iRet = BthNsLookupServiceNext(hLookup,dwGetNextFlags,&dwLen,pResults))) {
WCHAR *szName;
PSOCKADDR_BTH pSockAddr;
BT_ADDR *pba;
if (! (dwGetNextFlags & LUP_RETURN_NAME)) {
szName = NULL;
}
else {
szName = pResults->lpszServiceInstanceName;
}
pSockAddr = (PSOCKADDR_BTH) pResults->lpcsaBuffer->RemoteAddr.lpSockaddr;
pba = (BT_ADDR*)&pSockAddr->btAddr;
wprintf(L"BthNsLookupServiceNext (i=%d, retVal=0x%08x) name = %s, pba=%04x%08x\r\n",i,iRet,szName ? szName : L"",GET_NAP((*pba)), GET_SAP((*pba)));
if (dwGetNextFlags & LUP_RETURN_BLOB) {
BthInquiryResult *pInquiry = (BthInquiryResult *) pResults->lpBlob->pBlobData;
if (GET_NAP((pInquiry->ba)) != GET_NAP((*pba)) ||
GET_SAP((pInquiry->ba)) != GET_SAP((*pba)) || pResults->lpBlob->cbSize != sizeof(BthInquiryResult)) {
ASSERT(0); // if these don't match up then it's a bug.
}
wprintf(L"-->cod=0x%08x,clkofst=0x%04x,PgScanMode=0x%02x,PgScanPeriodMode=0x%02x,PgScanRepMode=0x%02x\r\n",pInquiry->cod,pInquiry->clock_offset,pInquiry->page_scan_mode,pInquiry->page_scan_period_mode, pInquiry->page_scan_repetition_mode);
}
dwLen = sizeof(szBuf);
i++;
}
wprintf(L"Final BthNsLookupServiceNext returns 0x%08x,GLE=0x%08x\r\n",iRet,GetLastError());
#endif // UNDER_CE
SetLastError(0);
iRet = BthNsLookupServiceEnd(hLookup);
wprintf(L"BthNsLookupServiceEnd returned 0x%08x,GLE=0x%08x\r\n",iRet,GetLastError());
}
/************************************************************
TestSdpAddRecord
File format is [ATTRIB Id] [Data Type] [Data]
Only required AttribID is 1, Seq of UUIDs
All AttribIDs and numeric values are in hexidecimal.
Example file:
1 SEQUENCE
UUID16 FFF
UUID16 3000
UUID32 4000000
END
999 UUID128 12345678-ABCD-AF12-8800-12345678EF12
1001 UINT8 10
1002 UINT16 100
1003 UINT32 40000000
1004 UINT64 4000000000000
1005 UINT128 100 1000
1006 INT8 -10
1007 INT16 -100
1008 INT32 -40000000
1009 INT64 -4000000000000
1010 INT128 -100 1000
1011 UUID16 100
1012 UUID32 40000000
1014 BOOLEAN 1
1015 BOOLEAN 0
1016 STRING Where do you want to go today?
1017 URL http://www.microsoft.com/
1018 Nil
************************************************************/
void TestSdpAddRecord(WCHAR *szCmd) {
UCHAR *pStream = NULL;
ULONG ulSize = 0;
WSAQUERYSET Service;
CHAR buf[BUFFER_SIZE];
BLOB blob;
PBTHNS_SETBLOB addBlob = (PBTHNS_SETBLOB) buf;
ULONG recordHandle = 0;
ULONG ulSdpVersion = BTH_SDP_VERSION;
if (! CreateSdpRecord(szCmd,&pStream,&ulSize))
return;
memset(&Service,0,sizeof(Service));
blob.cbSize = sizeof(BTHNS_SETBLOB) + ulSize - 1;
blob.pBlobData = (PBYTE) addBlob;
addBlob->pRecordHandle = &recordHandle;
addBlob->pSdpVersion = &ulSdpVersion;
addBlob->fSecurity = 0;
addBlob->fOptions = 0;
addBlob->ulRecordLength = ulSize;
memcpy(addBlob->pRecord,pStream,ulSize);
Service.dwSize = sizeof(Service);
Service.lpBlob = &blob;
Service.dwNameSpace = NS_BTH;
SetLastError(0);
int iErr = BthNsSetService(&Service,RNRSERVICE_REGISTER,0);
wprintf(L"BthNsSetService returns 0x%08x, record handle = 0x%08x,GLE=0x%08x\r\n",iErr,recordHandle,GetLastError());
}
void TestSdpDelRecord(WCHAR *szCmd) {
BLOB blob;
BTHNS_SETBLOB delBlob;
unsigned long hRec;
ULONG ulSdpVersion = BTH_SDP_VERSION;
WSAQUERYSET Service;
if (!GetUI(&szCmd,&hRec)) {
wprintf(L"Syntax: handle\n");
return;
}
blob.cbSize = sizeof(BTHNS_SETBLOB);
blob.pBlobData = (PBYTE) &delBlob;
memset(&delBlob,0,sizeof(delBlob));
delBlob.pRecordHandle = &hRec;
delBlob.pSdpVersion = &ulSdpVersion;
memset(&Service,0,sizeof(Service));
Service.dwSize = sizeof(Service);
Service.lpBlob = &blob;
Service.dwNameSpace = NS_BTH;
SetLastError(0);
int iErr = BthNsSetService(&Service,RNRSERVICE_DELETE,0);
wprintf(L"BthNsSetService returns 0x%08x,GLE=0x%08x\r\n",iErr,GetLastError());
}
/************************************************************
TestSdpServiceSearch
File format is [Data Type] [Guid] Data Type must be UUID16, UUID32, or UUID128
Must be at least 1 entry, no more than 12.
All entries are in hex.
Example file:
UUID16 FFF
UUID32 4000000
************************************************************/
void TestSdpServiceSearch(WCHAR *szCmd) {
FILE *pFile;
SdpQueryUuid UUIDs[MAX_UUIDS_IN_QUERY];
unsigned short cUUIDs;
unsigned short cMaxHandles = MAX_HANDLES;
BT_ADDR bt;
DWORD dwFlags = 0;
// Read Input
SKIP_WHITESPACE(szCmd);
if (! GetBA(&szCmd, &bt)) {
wprintf (L"Syntax: bd_addr\n");
return;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -