locked
How to use Windows.Devices.Bluetooth.Rfcomm APIs to connect to a bluetooth device (SPP) in WinRT DLL?

    Question

  • I have build a Win8.1 store app demo to  connect to a BT device ,using the Windows.Devices.Bluetooth.Rfcomm APIs, and it works.

    But my question is can i move those code into a WinRT DLL (c++ language), still using Windows.Devices.Bluetooth.Rfcomm APIs, can still communication with BT device?  So , the customer can wrap my WinRT DLL to a WinRT Component or simply make a Win8.1 store app himself. 

    Because in Store app, i can declare DeviceCapability in Package.appxmanifest, like:

        <m2:DeviceCapability Name="bluetooth.rfcomm">
          <m2:Device Id = "any">
            <m2:Function Type="name:serialPort" />
          </m2:Device>
        </m2:DeviceCapability> 

    but, in a WinRT DLL using C++,  how can i declare it ?

    My Scenario is:  a surface RT(8.1) connected to a bluetooth card reader using bluetooth, i need write a WinRT DLL to : write some interface function to communicate with BT card reader, then the customer write a windows store app to invoke my WinRT DLL or WinRT component to wrap my WinRT DLL. 

    Is it possible and how to do ?

    thanks,


    nio

    Wednesday, November 27, 2013 7:28 AM

Answers

  • Hi nio Pan,

    Welcome here!

    Because Package.appxmanifest is a XML file, so you could access it just as you access XML file.

    Note: Please make sure you have been faimiliar with what you want to add or modify first.

    You could use Win32 bluetooth APIs and socket APIs in WinRT DLL, but please make sure you could use the type which WINRT doesn't support only internally. When transfer data to invoker, you must convert the type to WINRT type first.

    If not, you couldn't pass The Windows App Certification Kit.

    Here are all Win32 and Com APIs you could use and could pass Windows App Certification Kit:

    http://msdn.microsoft.com/en-us/library/windows/apps/br205757.aspx

    Regards!


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Thursday, November 28, 2013 7:07 AM
    Moderator

All replies

  • Can i use Win32 bluetooth APIs and socket APIs in WinRT DLL ? 

    nio

    Wednesday, November 27, 2013 8:46 AM
  • Hi nio Pan,

    Welcome here!

    Because Package.appxmanifest is a XML file, so you could access it just as you access XML file.

    Note: Please make sure you have been faimiliar with what you want to add or modify first.

    You could use Win32 bluetooth APIs and socket APIs in WinRT DLL, but please make sure you could use the type which WINRT doesn't support only internally. When transfer data to invoker, you must convert the type to WINRT type first.

    If not, you couldn't pass The Windows App Certification Kit.

    Here are all Win32 and Com APIs you could use and could pass Windows App Certification Kit:

    http://msdn.microsoft.com/en-us/library/windows/apps/br205757.aspx

    Regards!


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Thursday, November 28, 2013 7:07 AM
    Moderator
  • Hi nio,

    Can you please refer me and guide me how to build Win 8.1 app to communicate with Bluetooth devices? e.g Data transfer etc.

     I'm working on it but couldn't found any solution.

    Friday, November 29, 2013 8:50 PM
  • hi, Abdul , here are some code snippet of my project,  it was a  c# demo version , and i am researching  how to convert it to WinRT DLL.

    MainPage.xaml.cs:    

        private Windows.Devices.Bluetooth.Rfcomm.RfcommDeviceService _service;
        private StreamSocket _socket;
        private DataWriter _writer;

        ObservableCollection<PairedDeviceInfo> _pairedDevices;

    async void InitializeRfcommDeviceService()

     {
                try
                {
                    DeviceInformationCollection DeviceInfoCollection = await DeviceInformation.FindAllAsync(RfcommDeviceService.GetDeviceSelector(RfcommServiceId.SerialPort));

                    var numDevices = DeviceInfoCollection.Count();

                    // By clearing the backing data, we are effectively clearing the ListBox
                    _pairedDevices.Clear();

                    if (numDevices == 0)
                    {
                        MessageDialog md = new MessageDialog("No paired devices found", "Title");
                        await md.ShowAsync();
                    }
                    else
                    {
                        // Found paired devices.
                        foreach (var deviceInfo in DeviceInfoCollection)
                        {
                            _pairedDevices.Add(new PairedDeviceInfo(deviceInfo));
                        }
                    }
                }
                catch (Exception ex)
                {

                }
            }

     async private void ConnectDevice_Click(object sender, RoutedEventArgs e)
     {
                DeviceInformation DeviceInfo =  await DeviceInformation.CreateFromIdAsync(this.TxtBlock_SelectedID.Text);

                try
                {
                    _service = await RfcommDeviceService.FromIdAsync(DeviceInfo.Id);

                    if (_socket != null)
                    {
                        // Disposing the socket with close it and release all resources associated with the socket
                        _socket.Dispose();
                    }

                    _socket = new StreamSocket();

                    // Note: If either parameter is null or empty, the call will throw an exception
                    await _socket.ConnectAsync(_service.ConnectionHostName, _service.ConnectionServiceName);

                    // If the connection was successful, the RemoteAddress field will be populated
                    MessageDialog md = new MessageDialog(String.Format("Connected to {0}!", _socket.Information.RemoteAddress.DisplayName), "Title");
                    await md.ShowAsync();
                }
                catch (Exception ex)
                {
                    _socket.Dispose();
                    _socket = null;
                }
            }

                

        /// <summary>
        ///  Class to hold all paired device information
        /// </summary>
        public class PairedDeviceInfo
        {
            internal PairedDeviceInfo(DeviceInformation deviceInfo)
            {
                this.DeviceInfo = deviceInfo;

                this.ID = this.DeviceInfo.Id;
                this.Name = this.DeviceInfo.Name;

            }

            public string Name { get; private set; }
            public string ID { get; private set; }
            public DeviceInformation DeviceInfo { get; private set; }
        }

    Package.appxmanifest:

          <Capabilities>
        <Capability Name="internetClient" />
        <m2:DeviceCapability Name="bluetooth.rfcomm">
          <m2:Device Id="any">
            <m2:Function Type="name:serialPort" />
          </m2:Device>
        </m2:DeviceCapability>
      </Capabilities>     


    nio

    Thursday, December 05, 2013 5:32 AM
  • Thanks Xiaoliang,

    I have created a  WinRT DLL project with CPP,  which used the windows runtime support (/ZW),  and i have created another windows store app with CPP as well . The WinRT DLL has a function which i want it could find the paired bluetooth devices and save them into a vector, then transfer them back to the win store app. So the store app has a button to invoke the DLL's find function.  But i don't know how to transfer the DeviceInformation vector object back to the invoker, because i don't faimiliar with C++/CX talk, so could you help me and take a look my code ? thank you!

    BTWinRTDLL.h :

    #pragma once
    
    #ifdef BTWinRTDLL_EXPORTS
    #define BTWinRTDLL_API  __declspec(dllexport)
    #else
    #define BTWinRTDLL_API __declspec(dllimport)
    #endif
    
    class BTWinRTDLL_API CBTWinRTDLL
    {
    	public:
    		CBTWinRTDLL(void);
    		Platform::Collections::Vector<Windows::Devices::Enumeration::DeviceInformation^>^  FindPairedDevices();
    };


    BTWinRTDLL.cpp:

    #include "pch.h"
    #include "BTWinRTDLL.h"
    #include <ppltasks.h>
    
    using namespace Platform;
    using namespace Platform::Collections; 
    using namespace Windows::Foundation;
    using namespace concurrency;
    using namespace Windows::Devices::Bluetooth;
    using namespace Windows::Devices::Bluetooth::Rfcomm;
    using namespace Windows::Devices::Enumeration;
    using namespace Windows::Networking::Sockets;
    
    Platform::Collections::Vector<Windows::Devices::Enumeration::DeviceInformation^>^ deviceInfoVector;
    
    CBTWinRTDLL::CBTWinRTDLL()
    {
    }
    
    Vector<DeviceInformation^>^  CBTWinRTDLL::FindPairedDevices()
    {
    	IAsyncOperation<DeviceInformationCollection^>^ deviceOp = DeviceInformation::FindAllAsync(RfcommDeviceService::GetDeviceSelector(RfcommServiceId::SerialPort));
    	auto deviceEnumTask = create_task(deviceOp);
    	deviceEnumTask.then([this](DeviceInformationCollection^ devices)
    	{
    		deviceInfoVector = ref new Platform::Collections::Vector<Windows::Devices::Enumeration::DeviceInformation^>();
    
    		for (int i = 0; i < devices->Size; i++)
    		{
    			DeviceInformation^ di = devices->GetAt(i);
    			deviceInfoVector->Append(di);
    		}
    		//return deviceInfoVector;
    	});
    	return deviceInfoVector;  //is here for return?
    }


    MainPage.xaml.h:(store app)

    #pragma once
    
    #include "MainPage.g.h"
    
    namespace BTApp_CPP
    {
    	public ref class MainPage sealed
    	{
    
    	public:
    		MainPage();
    
    	protected:
    		virtual void OnNavigatedTo(Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) override;
    
    	private:
    		Platform::Collections::Vector<Windows::Devices::Enumeration::DeviceInformation^>^ deviceInfoVector;
    		void Btn_FindPairedDevices_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
    		void Btn_ConnectDevice_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
    		void PairedDevicesList_SelectionChanged(Platform::Object^ sender, Windows::UI::Xaml::Controls::SelectionChangedEventArgs^ e);
    	};
    }


    MainPage.xaml.cpp:

    #include "pch.h"
    #include "MainPage.xaml.h"
    #include "..\BTWinRTDLL\BTWinRTDLL.h"
    
    using namespace BTApp_CPP;
    
    using namespace Platform;
    using namespace Windows::Foundation;
    using namespace Windows::Foundation::Collections;
    using namespace Windows::UI::Xaml;
    using namespace Windows::UI::Xaml::Controls;
    using namespace Windows::UI::Xaml::Controls::Primitives;
    using namespace Windows::UI::Xaml::Data;
    using namespace Windows::UI::Xaml::Input;
    using namespace Windows::UI::Xaml::Media;
    using namespace Windows::UI::Xaml::Navigation;
    
    CBTWinRTDLL btDLL;
    
    MainPage::MainPage()
    {
    	InitializeComponent();
    }
    
    void MainPage::OnNavigatedTo(NavigationEventArgs^ e)
    {
    	(void)e;	// Unused parameter
    }
    
    
    void BTApp_CPP::MainPage::Btn_FindPairedDevices_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
    {
    	deviceInfoVector = ref new Platform::Collections::Vector<Windows::Devices::Enumeration::DeviceInformation^>();
    
    	deviceInfoVector =	btDLL.FindPairedDevices();
    	
    	for each(Windows::Devices::Enumeration::DeviceInformation^ devInfo in deviceInfoVector)
    	{
    		this->PairedDevicesList->Items->Append(devInfo->Name + "-AND-" + devInfo->Id);
    
    	}
    }

    I want get the deviceInfoVector back from DLL , but it doesn't get anything.

     



    nio


    • Edited by nio Pan Thursday, December 05, 2013 8:01 AM
    Thursday, December 05, 2013 7:57 AM
  • After study the lambda syntax , i have added another function ConnectToDevice(), the code is below, it can enumration my BT device and automatically connect to the first device(for demo reason. And i have only one BT device), but it seems like cannot keep the connection if i do not use the socket immediately , which is different from the C# version demo,  the C# version demo will keep the BT connection after connected, until the user click the Disconnect button which will close the socket object.

    So , how do i keep a BT Connection for a long time  in CPP version demo?  Just like a serial port,  when i open a port, i will always keep alive, even if i don't transfer anything, until i close the port. 

    void  CBTWinRTDLL::ConnectToDevice()
    {
    	auto deviceEnumTask = create_task(DeviceInformation::FindAllAsync(RfcommDeviceService::GetDeviceSelector(RfcommServiceId::SerialPort)));
    
    	deviceEnumTask.then([](DeviceInformationCollection^ devices)->DeviceInformation^
    	{
    		DeviceInformation^ di;
    		for (int i = 0; i < devices->Size; i++)
    		{
    			di = devices->GetAt(i);
    		}
    		return di;
    	}).then([](DeviceInformation^ deviceInfo)
    	{
    		auto RfServiceTask = create_task(RfcommDeviceService::FromIdAsync(deviceInfo->Id));
    		RfServiceTask.then([](RfcommDeviceService^ deviceService)
    		{
    			StreamSocket^ socket = ref new StreamSocket();
    			auto SocketTask = create_task(socket->ConnectAsync(deviceService->ConnectionHostName, deviceService->ConnectionServiceName));
    			SocketTask.then([&socket](void)  //->IAsyncAction^
    			{
    				INT32 count = 0;
    				for (int loop = 0; loop < 2; loop++)
    				{
    					for (int i = 0; i < INT16_MAX; i++)
    					{
    						count += i;
    					}
             		}
    			});
    
    		});
    	});
    }

    Here's  the C# code:

            async private void ConnectDevice_Click(object sender, RoutedEventArgs e)
            {
                DeviceInformation DeviceInfo =  await DeviceInformation.CreateFromIdAsync(this.TxtBlock_SelectedID.Text);
                try
                {
                    _service = await RfcommDeviceService.FromIdAsync(DeviceInfo.Id);
    
                    if (_socket != null)
                    {
                        // Disposing the socket with close it and release all resources associated with the socket
                        _socket.Dispose();
                    }
    
                    _socket = new StreamSocket();
    
                    // Note: If either parameter is null or empty, the call will throw an exception
                    await _socket.ConnectAsync(_service.ConnectionHostName, _service.ConnectionServiceName);
    
                    // If the connection was successful, the RemoteAddress field will be populated
                    MessageDialog md = new MessageDialog(String.Format("Connected to {0}!", _socket.Information.RemoteAddress.DisplayName), "Title");
                    await md.ShowAsync();
                }
                catch (Exception ex)
                {
                    _socket.Dispose();
                    _socket = null;
                }
            }
    

    • Edited by nio Pan Friday, December 06, 2013 5:46 AM add c# code snippet
    Friday, December 06, 2013 5:36 AM
  • Ok, i solved the problem, simply define the socket object in .h  file can make it work.

    Windows::Networking::Sockets::StreamSocket^ _socket;
    Windows::Storage::Streams::DataWriter^ _writer;
    Windows::Storage::Streams::DataReader^ _reader;


    nio

    Friday, December 06, 2013 9:50 AM
  • I have some code based on this sample pairing and connecting with an HC-05 module on an Arduino device. However, I can't seem to get any data sending or receiving.

    Are there any samples using the input and output streams based on this code?

    Thanks

    Tuesday, January 21, 2014 4:31 AM
  • Just happened to run into a situation where in a LOB app they call win32 legacy BluetoothFindFirstRadio() and it returns 256 - no devices found. Even after I got permission from the user, created a test socket stream to the device (using SPP). So the manifest is ok, permissions granted.

    You state here that was can use the Win32 BT API, but how?

    Tuesday, July 08, 2014 3:42 PM