From: Vibhav Pant <vibhavp@gmail.com> --- .../bluetoothdevice.c | 278 +++++++++++++++++- dlls/windows.devices.bluetooth/private.h | 2 + .../tests/bluetooth.c | 25 +- 3 files changed, 285 insertions(+), 20 deletions(-) diff --git a/dlls/windows.devices.bluetooth/bluetoothdevice.c b/dlls/windows.devices.bluetooth/bluetoothdevice.c index 1c1a13c381c..5cd66fada2d 100644 --- a/dlls/windows.devices.bluetooth/bluetoothdevice.c +++ b/dlls/windows.devices.bluetooth/bluetoothdevice.c @@ -18,6 +18,13 @@ */ #include "private.h" +#include "roapi.h" +#include "setupapi.h" +#include "initguid.h" +#include "devpkey.h" +#include "bthledef.h" +#include "ddk/bthguid.h" + #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL( bluetooth ); @@ -155,6 +162,251 @@ static const IBluetoothDeviceStaticsVtbl bluetoothdevice_statics_vtbl = bluetoothdevice_statics_GetDeviceSelector, }; +struct ble_device +{ + IBluetoothLEDevice IBluetoothLEDevice_iface; + HSTRING id; + UINT64 addr; + LONG ref; +}; + +static inline struct ble_device *impl_from_IBluetoothLEDevice( IBluetoothLEDevice *iface ) +{ + return CONTAINING_RECORD( iface, struct ble_device, IBluetoothLEDevice_iface ); +} + +static HRESULT WINAPI ble_device_QueryInterface( IBluetoothLEDevice *iface, REFIID iid, void **out ) +{ + struct ble_device *impl = impl_from_IBluetoothLEDevice( iface ); + + TRACE( "(%p, %s, %p)\n", iface, debugstr_guid( iid ), out ); + + if (IsEqualGUID( iid, &IID_IUnknown ) || + IsEqualGUID( iid, &IID_IInspectable ) || + IsEqualGUID( iid, &IID_IAgileObject ) || + IsEqualGUID( iid, &IID_IBluetoothLEDevice )) + { + IBluetoothLEDevice_AddRef( (*out = &impl->IBluetoothLEDevice_iface) ); + return S_OK; + } + + *out = NULL; + FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); + return E_NOINTERFACE; +} + +static ULONG WINAPI ble_device_AddRef( IBluetoothLEDevice *iface ) +{ + struct ble_device *impl = impl_from_IBluetoothLEDevice( iface ); + TRACE( "(%p)\n", iface ); + return InterlockedIncrement( &impl->ref ); +} + +static ULONG WINAPI ble_device_Release( IBluetoothLEDevice *iface ) +{ + struct ble_device *impl = impl_from_IBluetoothLEDevice( iface ); + ULONG ref = InterlockedDecrement( &impl->ref ); + TRACE( "(%p)\n", iface ); + + if (!ref) + { + WindowsDeleteString( impl->id ); + free( impl ); + } + return ref; +} + +static HRESULT WINAPI ble_device_GetIids( IBluetoothLEDevice *iface, ULONG *iid_count, IID **iids ) +{ + FIXME( "(%p, %p, %p): stub!\n", iface, iid_count, iids ); + return E_NOTIMPL; +} + +static HRESULT WINAPI ble_device_GetRuntimeClassName( IBluetoothLEDevice *iface, HSTRING *class_name ) +{ + FIXME( "(%p, %p): stub!\n", iface, class_name ); + return E_NOTIMPL; +} + +static HRESULT WINAPI ble_device_GetTrustLevel( IBluetoothLEDevice *iface, TrustLevel *level ) +{ + FIXME( "(%p, %p): stub!\n", iface, level ); + return E_NOTIMPL; +} + +static HRESULT WINAPI ble_device_get_DeviceId( IBluetoothLEDevice *iface, HSTRING *value ) +{ + FIXME( "(%p, %p): stub!\n", iface, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI ble_device_get_Name( IBluetoothLEDevice *iface, HSTRING *value ) +{ + FIXME( "(%p, %p): stub!\n", iface, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI ble_device_get_GattServices( IBluetoothLEDevice *iface, IVectorView_GattDeviceService **services ) +{ + FIXME( "(%p, %p): stub!\n", iface, services ); + return E_NOTIMPL; +} + +static HRESULT WINAPI ble_device_get_ConnectionStatus( IBluetoothLEDevice *iface, BluetoothConnectionStatus *value ) +{ + FIXME( "(%p, %p): stub!\n", iface, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI ble_device_get_BluetoothAddress( IBluetoothLEDevice *iface, UINT64 *value ) +{ + struct ble_device *impl = impl_from_IBluetoothLEDevice( iface ); + TRACE( "(%p, %p)\n", iface, value ); + *value = impl->addr; + return S_OK; +} + +static HRESULT WINAPI ble_device_GetGattService( IBluetoothLEDevice *iface, GUID uuid, IGattDeviceService **service ) +{ + FIXME( "(%p, %s, %p): stub!\n", iface, debugstr_guid( &uuid ), service ); + return E_NOTIMPL; +} + +static HRESULT WINAPI ble_device_add_NameChanged( IBluetoothLEDevice *iface, ITypedEventHandler_BluetoothLEDevice_IInspectable *handler, + EventRegistrationToken *token ) +{ + FIXME( "(%p, %p, %p): stub!\n", iface, handler, token ); + return E_NOTIMPL; +} + +static HRESULT WINAPI ble_device_remove_NameChanged( IBluetoothLEDevice *iface, EventRegistrationToken token ) +{ + FIXME( "(%p, %I64d): stub!\n", iface, token.value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI ble_device_add_GattServicesChanged( IBluetoothLEDevice *iface, ITypedEventHandler_BluetoothLEDevice_IInspectable *handler, + EventRegistrationToken *token ) +{ + FIXME( "(%p, %p, %p): stub!\n", iface, handler, token ); + return E_NOTIMPL; +} + +static HRESULT WINAPI ble_device_remove_GattServicesChanged( IBluetoothLEDevice *iface, EventRegistrationToken token ) +{ + FIXME( "(%p, %I64d): stub!\n", iface, token.value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI ble_device_add_ConnectionStatusChanged( IBluetoothLEDevice *iface, ITypedEventHandler_BluetoothLEDevice_IInspectable *handler, + EventRegistrationToken *token ) +{ + FIXME( "(%p, %p, %p): stub!\n", iface, handler, token ); + return E_NOTIMPL; +} + +static HRESULT WINAPI ble_device_remove_ConnectionStatusChanged( IBluetoothLEDevice *iface, EventRegistrationToken token ) +{ + FIXME( "(%p, %I64d): stub!\n", iface, token.value ); + return E_NOTIMPL; +} + +static const IBluetoothLEDeviceVtbl ble_device_vtbl = { + /* IUnknown */ + ble_device_QueryInterface, + ble_device_AddRef, + ble_device_Release, + /* IInspectable */ + ble_device_GetIids, + ble_device_GetRuntimeClassName, + ble_device_GetTrustLevel, + /* IBluetoothLEDevice */ + ble_device_get_DeviceId, + ble_device_get_Name, + ble_device_get_GattServices, + ble_device_get_ConnectionStatus, + ble_device_get_BluetoothAddress, + ble_device_GetGattService, + ble_device_add_NameChanged, + ble_device_remove_NameChanged, + ble_device_add_GattServicesChanged, + ble_device_remove_GattServicesChanged, + ble_device_add_ConnectionStatusChanged, + ble_device_remove_ConnectionStatusChanged, +}; + +static HRESULT ble_device_create( IBluetoothLEDevice **device, const WCHAR *id, UINT64 addr ) +{ + struct ble_device *impl; + HRESULT hr; + + TRACE( "(%p, %s, %I64x)\n", device, debugstr_w( id ), addr ); + + if (!(impl = calloc( 1, sizeof( *impl )))) + return E_OUTOFMEMORY; + if (FAILED(hr = WindowsCreateString( id, wcslen( id ), &impl->id ))) + { + free( impl ); + return hr; + } + impl->ref = 1; + impl->addr = addr; + impl->IBluetoothLEDevice_iface.lpVtbl = &ble_device_vtbl; + *device = &impl->IBluetoothLEDevice_iface; + return S_OK; +} + +static HRESULT bluetoothledevice_get_device_async( IUnknown *invoker, IUnknown *param, PROPVARIANT *result, BOOL called_async ) +{ + char buffer[sizeof( SP_DEVICE_INTERFACE_DETAIL_DATA_W ) + MAX_PATH * sizeof( WCHAR )]; + SP_DEVICE_INTERFACE_DETAIL_DATA_W *iface_detail = (SP_DEVICE_INTERFACE_DETAIL_DATA_W *)buffer; + SP_DEVICE_INTERFACE_DATA iface_data = { .cbSize = sizeof( iface_data ) }; + IBluetoothLEDevice *device; + BOOL found = FALSE; + HDEVINFO devinfo; + DWORD idx = 0; + UINT64 addr; + HRESULT hr; + + if (!called_async) return STATUS_PENDING; + if (FAILED(hr = IPropertyValue_GetUInt64( (IPropertyValue *)param, &addr ))) + return hr; + + devinfo = SetupDiGetClassDevsW( &GUID_BLUETOOTHLE_DEVICE_INTERFACE, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE ); + if (devinfo == INVALID_HANDLE_VALUE) + return HRESULT_FROM_WIN32( GetLastError() ); + iface_detail->cbSize = sizeof( *iface_detail ); + result->vt = VT_NULL; + while (SetupDiEnumDeviceInterfaces( devinfo, NULL, &GUID_BLUETOOTHLE_DEVICE_INTERFACE, idx++, &iface_data )) + { + SP_DEVINFO_DATA devinfo_data = { .cbSize = sizeof( devinfo_data ) }; + WCHAR addr_str[13]; + DEVPROPTYPE type; + UINT64 addr2 = 0; + + if (!SetupDiGetDeviceInterfaceDetailW( devinfo, &iface_data, iface_detail, sizeof( buffer ), NULL, &devinfo_data )) + continue; + if (!SetupDiGetDevicePropertyW( devinfo, &devinfo_data, &DEVPKEY_Bluetooth_DeviceAddress, &type, (BYTE *)addr_str, sizeof( addr_str ), NULL, 0 )) + continue; + if (swscanf( addr_str, L"%I64x", &addr2 ) != 1) + continue; + if (addr == addr2) + { + found = TRUE; + break; + } + } + + SetupDiDestroyDeviceInfoList( devinfo ); + if (!found) + return S_OK; + if (FAILED(hr = ble_device_create( &device, iface_detail->DevicePath, addr ))) + return hr; + result->vt = VT_UNKNOWN; + result->punkVal = (IUnknown *)device; + return S_OK; +} + struct bluetoothledevice_statics { IActivationFactory IActivationFactory_iface; @@ -251,10 +503,30 @@ static HRESULT WINAPI bluetoothledevice_statics_FromIdAsync( IBluetoothLEDeviceS return E_NOTIMPL; } -static HRESULT WINAPI bluetoothledevice_statics_FromBluetoothAddressAsync( IBluetoothLEDeviceStatics *iface, UINT64 addr, IAsyncOperation_BluetoothLEDevice **async_op ) +static HRESULT WINAPI bluetoothledevice_statics_FromBluetoothAddressAsync( IBluetoothLEDeviceStatics *iface, + UINT64 addr, + IAsyncOperation_BluetoothLEDevice **async_op ) { - FIXME( "(%p, %#I64x, %p): stub!\n", iface, addr, async_op ); - return E_NOTIMPL; + static const WCHAR *class_name = RuntimeClass_Windows_Foundation_PropertyValue; + IPropertyValueStatics *statics; + IPropertyValue *addr_val; + HSTRING_HEADER hdr; + HSTRING str; + HRESULT hr; + + TRACE( "(%p, %#I64x, %p)\n", iface, addr, async_op ); + + if (FAILED(hr = WindowsCreateStringReference( class_name, wcslen( class_name ), &hdr, &str ))) return hr; + if (FAILED(hr = RoGetActivationFactory( str, &IID_IPropertyValueStatics, (void **)&statics ))) return hr; + if (FAILED(hr = IPropertyValueStatics_CreateUInt64( statics, addr, (IInspectable **)&addr_val ))) + { + IPropertyValueStatics_Release( statics ); + return hr; + } + IPropertyValueStatics_Release( statics ); + + return async_operation_inspectable_create( &IID_IAsyncOperation_BluetoothLEDevice, (IUnknown *)iface, (IUnknown *)addr_val, bluetoothledevice_get_device_async, + (IAsyncOperation_IInspectable **)async_op ); } static HRESULT WINAPI bluetoothledevice_statics_GetDeviceSelector( IBluetoothLEDeviceStatics *iface, HSTRING *result ) diff --git a/dlls/windows.devices.bluetooth/private.h b/dlls/windows.devices.bluetooth/private.h index 48cc5c04447..3882558de37 100644 --- a/dlls/windows.devices.bluetooth/private.h +++ b/dlls/windows.devices.bluetooth/private.h @@ -41,6 +41,8 @@ #define WIDL_using_Windows_Devices_Radios #include "windows.devices.radios.h" #define WIDL_using_Windows_Devices_Bluetooth +#define WIDL_using_Windows_Devices_Bluetooth_GenericAttributeProfile +#include "windows.devices.bluetooth.genericattributeprofile.h" #include "windows.devices.bluetooth.rfcomm.h" #include "windows.devices.bluetooth.h" #define WIDL_using_Windows_Devices_Bluetooth_Advertisement diff --git a/dlls/windows.devices.bluetooth/tests/bluetooth.c b/dlls/windows.devices.bluetooth/tests/bluetooth.c index c1bb8f9939d..0c189f1def6 100644 --- a/dlls/windows.devices.bluetooth/tests/bluetooth.c +++ b/dlls/windows.devices.bluetooth/tests/bluetooth.c @@ -544,8 +544,8 @@ static void test_IBluetoothLEDevice( int line, IBluetoothLEDevice *device, UINT6 WindowsDeleteString( str ); hr = IBluetoothLEDevice_get_BluetoothAddress( device, &addr2 ); - todo_wine ok_( __FILE__, line )( hr == S_OK, "got hr %#lx.\n", hr ); - todo_wine ok_( __FILE__, line )( addr == addr2, "%I64x != %I64x\n", addr, addr2 ); + ok_( __FILE__, line )( hr == S_OK, "got hr %#lx.\n", hr ); + ok_( __FILE__, line )( addr == addr2, "%I64x != %I64x\n", addr, addr2 ); hr = IBluetoothLEDevice_get_Name( device, &str ); todo_wine ok_( __FILE__, line )( hr == S_OK, "got hr %#lx.\n", hr ); @@ -597,15 +597,12 @@ static void test_BluetoothLEDeviceStatics( void ) /* Use an invalid Bluetooth address. */ hr = IBluetoothLEDeviceStatics_FromBluetoothAddressAsync( statics, 0, &async_op ); - todo_wine ok( hr == S_OK, "got hr %#lx.\n", hr ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); - if (hr == S_OK) - { - await_bluetoothledevice( __LINE__, async_op ); - check_bluetoothledevice_async( __LINE__, async_op, 1, Completed, S_OK, TRUE, &device ); - ok( !device, "got device %p != NULL\n", device ); - if (device) IBluetoothLEDevice_Release( device ); - } + await_bluetoothledevice( __LINE__, async_op ); + check_bluetoothledevice_async( __LINE__, async_op, 1, Completed, S_OK, TRUE, &device ); + ok( !device, "got device %p != NULL\n", device ); + IBluetoothLEDevice_Release( device ); /* Enumerate through all known LE devices on this system. */ devinfo = SetupDiGetClassDevsW( &GUID_BLUETOOTHLE_DEVICE_INTERFACE, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE ); @@ -632,13 +629,7 @@ static void test_BluetoothLEDeviceStatics( void ) winetest_push_context( "device %lu (%s)", idx - 1, debugstr_w( addr_str ) ); hr = IBluetoothLEDeviceStatics_FromBluetoothAddressAsync( statics, addr, &async_op ); - todo_wine ok( hr == S_OK, "got hr %#lx.\n", hr ); - if (hr != S_OK) - { - skip( "FromBluetoothAddressAsync failed.\n" ); - winetest_pop_context(); - continue; - } + ok( hr == S_OK, "got hr %#lx.\n", hr ); await_bluetoothledevice( __LINE__, async_op ); check_bluetoothledevice_async( __LINE__, async_op, 1, Completed, S_OK, FALSE, &device ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10865