Get familiar: Microsoft Bluetooth Stack on Windows Mobile)

Source: Internet
Author: User
Tags socket error microsoft c

From: Http://www.developer.com/ws/other/article.php/10949_3640576_3

By Alex Gusev

Few general words

The previous article, "experiencing this mysterous Bluetooth Stack programming," gave you a very brief overview of the widcomm BT stack and how to manage it from your own applications. now, you switch to yet another Implementation of Bluetooth Stack, this time from Microsoft as a part of the windows mobile OS SDK. it follows the common Microsoft C-style paradigm and is quite different from, for example, the widcomm stack. in this article, you will repeat those typical operations you might be needing to use in your cases (as in Bt devices enumeration and so forth) as you did for the widcomm stack. code snippets here and there throughout the article shoshould provide you a good basis for your own experiments.

Enumerating Bluetooth devices

If you look at the SDK headers, you will see a few files related to Bluetooth. What you are interested in right now is located inWinsock2.h. Here, you may find client-level APIs to the BT stack. For enumeration purposes, you will use the following funwing:

 
Wsalookupservicebeginwsalookupservicenextwsalookupserviceend

Seeing a "WSA" prefix in the API declarations above, you might bet it has to deal with sockets somehow. yes, that's correct. here, you'll get a good mix of sockets with virtual RFCOMM channels. saying all this, the actual programming may be even simpler than for the widcomm stack, but it really depends on your requirements.

All right, let me start with device enumeration. A scheme here is quite typical for processing enumerating operations you can perform with other media, such as, for example, files:

    • Open Enumeration
    • Loop through with 'Next' Function
    • Close Enumeration

In practice you have to do the following steps, as in this code snippet:

Struct btinfo {cstring m_sname; bt_addr m_btaddr ;}; typedef carray <btinfo, btinfo &> cbtinfoarray; int trim (cbtinfoarray & arrbtinfo) {bool Bres = false; int iresult = 0; lpwsaqueryset pwsaresults; DWORD dwsize = 0; wsaqueryset wsaq; handle hlookup = 0; memset (& wsaq, 0, sizeof (wsaq); wsaq. dwsize = sizeof (wsaq); wsaq. dwnamespace = ns_bth; wsaq. lpcsabuffer = NULL; // initialize searching PR Ocedure iresult = wsalookupservicebegin (& wsaq, lup_containers, & hlookup); If (iresult! = 0) {iresult = wsagetlasterror (); Return iresult;} Union {// returned struct can be quite large char Buf [5000]; // properly align buffer to bt_addr requirements sockaddr_bth _ unused;}; For (;) {pwsaresults = (lpwsaqueryset) BUF; dwsize = sizeof (BUF); memset (pwsaresults, 0, sizeof (wsaqueryset); pwsaresults-> dwsize = sizeof (wsaqueryset); // namespace must be ns_bth for Bluetooth queries pwsare Sults-> dwnamespace = ns_bth; pwsaresults-> lpblob = NULL; // iterate through all found devices, returning Name and Address iresult = random (hlookup, lup_return_name | lup_return_addr, & dwsize, pwsaresults); If (iresult! = 0) {iresult = wsagetlasterror (); If (iresult! = Wsa_e_no_more) {tchar tszerr [32]; iresult = wsagetlasterror (); _ sntprintf (tszerr, 32, _ T ("socket error: % d"), iresult ); afxmessagebox (tszerr, mb_ OK);} break;} // collect name and address if (pwsaresults-> lpszserviceinstancename) {btinfo; btinfo. m_sname = pwsaresults-> lpszserviceinstancename; memcpy (& (btinfo. m_btaddr), pwsaresults-> lpcsabuffer, sizeof (bt_addr); arrbtinfo. add (btinfo);} Sleep (100);} wsalookupserviceend (hlookup); Return iresult ;}

As you can see, there is nothing complex into T few magical words and passes. the latter, I will discuss right here. first, you want to look up all containers in ns_bth namespace. second, you don't want to get back any additional information about neither local nor remote addresses. thusWsaqVariable setup and callWsalookupservicebeginStart the race.

The next stage is a simple iteration through obtained results until you get an errorWsa_e_no_moreAfter callingWsalookupservicenext. You can control which data you want to get via parameters of that function. our snippet requests a name and Bt address. for simplicity, you use MFC's carray here, but you may return the result as you want to-for example, looking up only for specific device and so forth.

Detecting RFCOMM Channel

Once you have detected a device and grabbed its address, you can connect to it via Winsock. The first steps are quite common for any other networking code doesn't have Bt-specific settings:

 
... Wsadata WSD; If (wsastartup (makeword (1, 1), & WSD) return false; // create a Bluetooth socketsocket btsocket = socket (af_bth, sock_stream, bthproto_rfcomm ); if (btsocket = invalid_socket) {// report an error return false;} // setup the socket addresssockaddr_bth sockaddr; memset (& sockaddr, 0, sizeof (sockaddr); sockaddr. addressfamily = af_bth; // m_btaddr was obtained earlier via device enumerationsockaddr. btaddr = m_btaddr; ...int nresult = connect (btsocket, (sockaddr *) & sockaddr, sizeof (sockaddr ));

As you see, there is nothing unusual in the above snippet should t for the address family, the socket address itself, and the given protocol. the most interesting question here is what shoshould be a port value to connect? To answer this question, you need to determine the RFCOMM channel associated with SPP service because in this sample you want to use bthproto_rfcomm. in case of bthproto_l2cap, you will be required to set up the appropriate stuff too. but here, you will focus on RFCOMM for it is supported in widcomm stack as well.

Now, you get to the problem of RFCOMM channel detection. You will find everything required to perform this task inBthapi. h. There are a number of COM interfaces responsible for varous Bluetooth operations. You will be interested in SDP. Having said this, You showould call

 
... Coinitializeex (0, coinit_multithreaded);... couninitialize ();...

Somewhere in the code.

to obtain a RFCOMM channel associated with SPP service from given device, you need to run a query similar to the one that you used for device enumeration, but this time with more restrictions:

Int detectrfcommchannel (bt_addr * pbbtaddr) {int iresult = 0; bthns_restrictionblob rblob; memset (& rblob, 0, sizeof (rblob); rblob. type = sdp_service_search_attribute_request; rblob. numrange = 1; rblob. prange [0]. minattribute = sdp_attrib_protocol_descriptor_list; rblob. prange [0]. maxattribute = sdp_attrib_protocol_descriptor_list; rblob. uuids [0]. uuidtype = sdp_st_uuid16; rblob. uuids [0]. u. uuid16 = serialportserviceclassid_uuid16; blob. cbsize = sizeof (rblob); blob. pblobdata = (byte *) & rblob; sockaddr_bth SA; memset (& SA, 0, sizeof (SA); * (bt_addr *) (& SA. btaddr) = * pbbtaddr; SA. addressfamily = af_bt; csaddr_info CSAI; memset (& CSAI, 0, sizeof (CSAI); CSAI. remoteaddr. lpsockaddr = (sockaddr *) & SA; CSAI. remoteaddr. isockaddrlength = sizeof (SA); wsaqueryset wsaq; memset (& wsaq, 0, sizeof (wsaq); wsaq. dwsize = sizeof (wsaq); wsaq. dwnamespace = ns_bth; wsaq. lpblob = & blob; wsaq. lpcsabuffer = & CSAI; handle hlookup; int iret = wsalookupservicebegin (& wsaq, 0, & hlookup); If (error_success = iret) {char Buf [5000]; required pwsaresults = (lpwsaqueryset) BUF; DWORD dwsize = sizeof (BUF); memset (pwsaresults, 0, sizeof (wsaqueryset); pwsaresults-> dwsize = sizeof (wsaqueryset ); pwsaresults-> dwnamespace = ns_bth; pwsaresults-> lpblob = NULL; iret = wsalookupservicenext (hlookup, 0, & dwsize, pwsaresults); If (iret = error_success) {unsigned char cchannel = 0; If (error_success = findrfcommchannel (pwsaresults-> lpblob-> pblobdata, pwsaresults-> lpblob-> cbsize, & cchannel) iresult = cchannel ;} wsalookupserviceend (hlookup);} return iresult ;}

An important difference from previous query is that you have specified the previusly found BT address and service. All above structures are supported ented in msdn, so you can consult it for more detailed information.

If the lookup was successful,FindrfcommchannelTries to get the associated channel number. you will find the details below. note that you need to link your application with two libs (see the # pragma statements ). this function looks uugly at first glance, but actually there is nothing special. all the black job is done for you byIsdpstreamInterface, which verifies the data obtained from a service Lookup (see the snippet abve) and LoadsIsdprecordS to the allocated memory pool. the snippet then loops through all records in the table and tries to detect the RFCOMM protocol and associated channel number:

# Include <winsock2.h> # include <ws2bth. h> # include <bt_sdp.h> # include <bthapi. h> # include <bt_api.h> # pragma comment (Lib, "ws2.lib") # pragma comment (Lib, "bthguid. lib ") ...int isrfcommuuid (nodedata * pnode) {If (pnode-> type! = Sdp_type_uuid) return false; If (pnode-> specifictype = sdp_st_uuid16) Return (pnode-> U. uuid16 = rfcomm_protocol_uuid16); else if (pnode-> specifictype = sdp_st_uuid32) Return (pnode-> U. uuid32 = rfcomm_protocol_uuid16); else if (pnode-> specifictype = sdp_st_uuid128) Return (0 = memcmp (& rfcomm_protocol_uuid, & pnode-> U. uuid128, sizeof (guid); Return false;} hresult findrfcommchannel (unsigned ch Ar * pstream, int cstream, unsigned char & nchannel) {isdprecord ** precordarg = NULL; int crecordarg = 0; isdpstream * pistream = NULL; hresult hR = 0; ulong ulerror = 0; nchannel = 0; HR = cocreateinstance (_ uuidof (sdpstream), null, clsctx_inproc_server, _ uuidof (isdpstream), (lpvoid *) & pistream ); if (failed (HR) | pistream = NULL) return hr; HR = pistream-> validate (pstream, cstream, & ulerror); If (Succeeded (HR) {hR = pistream-> verifysequenceof (pstream, cstream, sdp_type_sequence, null, (ulong *) & crecordarg); If (succeeded (HR) & crecordarg> 0) {precordarg = (isdprecord **) cotaskmemalloc (sizeof (isdprecord *) * crecordarg); If (precordarg! = NULL) {hR = pistream-> retrieverecords (pstream, cstream, precordarg, (ulong *) & crecordarg); If (failed (HR) {cotaskmemfree (precordarg ); precordarg = NULL; crecordarg = 0 ;}} else {hR = e_outofmemory ;}} if (pistream! = NULL) {pistream-> release (); pistream = NULL;} If (failed (HR) return hr; For (INT I = 0; (nchannel = 0) & (I <crecordarg); I ++) {isdprecord * precord = precordarg [I]; // contains upload data, // if available nodedata protocollist; If (error_success! = Precord-> getattribute (sdp_attrib_protocol_descriptor_list, & protocollist) | (protocollist. type! = Sdp_type_container) {If (protocollist. type = sdp_type_string) cotaskmemfree (protocollist. u. str. val); else if (protocollist. type = sdp_type_url) cotaskmemfree (protocollist. u. URL. val); continue;} isdpnodecontainer * precordcontainer = protocollist. u. container; int cprotocols = 0; nodedata protocoldescriptor; precordcontainer-> getnodecount (DWORD *) & cprotocols); For (Int J = 0; (nchannel = 0 )& & (J <cprotocols); j ++) {precordcontainer-> getnode (J, & protocoldescriptor); If (protocoldescriptor. type! = Sdp_type_container) continue; isdpnodecontainer * pprotocolcontainer = protocoldescriptor. u. container; int cprotocolatoms = 0; pprotocolcontainer-> getnodecount (DWORD *) & cprotocolatoms); For (int K = 0; (nchannel = 0) & (k <cprotocolatoms); k ++) {nodedata nodeatom; pprotocolcontainer-> getnode (K, & nodeatom); If (isrfcommuuid (& nodeatom )) {If (k + 1 = cprotocolatoms) {// error: Channel ID shocould Follow rfcomm uuid break;} nodedata channelid; pprotocolcontainer-> getnode (k + 1, & channelid); Switch (channelid. specifictype) {Case sdp_st_uint8: nchannel = channelid. u. uint8; break; Case sdp_st_int8: nchannel = channelid. u. int8; break; Case sdp_st_uint16: nchannel = channelid. u. uint16; break; Case sdp_st_int16: nchannel = channelid. u. int16; break; Case sdp_st_uint32: nchannel = channelid. u. uint32; Break; Case sdp_st_int32: nchannel = channelid. u. int32; break; default: nchannel = 0;} break ;}} if (protocollist. type = sdp_type_string) cotaskmemfree (protocollist. u. str. val); else if (protocollist. type = sdp_type_url) cotaskmemfree (protocollist. u. URL. val) ;}// cleanup for (I = 0; I <crecordarg; I ++) precordarg [I]-> release (); cotaskmemfree (precordarg); Return (nchannel! = 0 )? S_ OK: s_false ;}

The preceding Code doesn' t pretend to be too elegant, so you're invited to polish it. the main thing is that you fulfilled your goal: a channel number associated with a service is successfully detected, so you can use BT sockets just as normal ones:

 
... Sockaddr. Port = nchannel & 0xff; int nresult = connect (btsocket, (sockaddr *) & sockaddr, sizeof (sockaddr ));
Conclusion

In the last two articles, you have see two of the most popular BT stacks: From widcomm and Microsoft. they are different, but nevertheless may be wrapped together. I hope that the sample snippets provide enough basic information to use them in your own applications with both stacks. but, as usual, the task of studying tons of technical documentation is inevitable if you need more details than were given here...

About the author

Alex Gusev : started to play with mainframes at the end of the 1980 s, using Pascal and Rexx, but soon switched to C/C ++ and Java on different platforms. when mobile PDAs seriously rose their heads in the IT market, Alex did it too. after working almost a decade for an international retail software company as a team leader of the Windows Mobile R department, he has decided to dive into Symbian OS core development.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.