[PATCH v3 0/6] MR10865: windows.devices.bluetooth: Add an initial implementation for IBluetoothLEDevice, IGattService.
-- v3: windows.devices.bluetooth: Implement IGattDeviceService::get_AttributeHandle. windows.devices.bluetooth: Implement IGattDeviceService::get_Uuid. windows.devices.bluetooth: Implement IBluetoothLEDevice::get_GattServices. windows.devices.bluetooth: Implement IBluetoothLEDevice::get_DeviceId. windows.devices.bluetooth: Implement BluetoothLEDeviceStatics::FromBluetoothAddressAsync. https://gitlab.winehq.org/wine/wine/-/merge_requests/10865
From: Vibhav Pant <vibhavp@gmail.com> --- .../tests/Makefile.in | 2 +- .../tests/bluetooth.c | 81 +++++++++++++++++++ 2 files changed, 82 insertions(+), 1 deletion(-) diff --git a/dlls/windows.devices.bluetooth/tests/Makefile.in b/dlls/windows.devices.bluetooth/tests/Makefile.in index c04dafe56d1..2fef3f491ed 100644 --- a/dlls/windows.devices.bluetooth/tests/Makefile.in +++ b/dlls/windows.devices.bluetooth/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = windows.devices.bluetooth.dll -IMPORTS = combase bluetoothapis +IMPORTS = combase setupapi bluetoothapis SOURCES = \ bluetooth.c diff --git a/dlls/windows.devices.bluetooth/tests/bluetooth.c b/dlls/windows.devices.bluetooth/tests/bluetooth.c index 24ead71caa4..c1bb8f9939d 100644 --- a/dlls/windows.devices.bluetooth/tests/bluetooth.c +++ b/dlls/windows.devices.bluetooth/tests/bluetooth.c @@ -24,8 +24,12 @@ #include "windef.h" #include "winbase.h" #include "winstring.h" +#include "setupapi.h" #include "bthsdpdef.h" #include "bluetoothapis.h" +#include "bthledef.h" +#include "devpkey.h" +#include "ddk/bthguid.h" #include "roapi.h" @@ -37,6 +41,7 @@ #include "windows.networking.h" #define WIDL_using_Windows_Devices_Bluetooth_Advertisement #define WIDL_using_Windows_Devices_Bluetooth +#define WIDL_using_Windows_Devices_Bluetooth_GenericAttributeProfile #include "windows.devices.bluetooth.advertisement.h" #include "windows.devices.bluetooth.rfcomm.h" #include "windows.devices.bluetooth.h" @@ -524,15 +529,48 @@ static void test_BluetoothDeviceStatics( void ) IBluetoothDeviceStatics_Release( statics ); } +static void test_IBluetoothLEDevice( int line, IBluetoothLEDevice *device, UINT64 addr ) +{ + BluetoothConnectionStatus status; + HSTRING str = NULL; + UINT64 addr2 = 0; + HRESULT hr; + + hr = IBluetoothLEDevice_get_DeviceId( device, &str ); + todo_wine ok_( __FILE__, line )( hr == S_OK, "got hr %#lx.\n", hr ); + todo_wine ok_( __FILE__, line )( !WindowsIsStringEmpty( str ), "got empty DeviceId value.\n" ); + if (hr == S_OK) + trace( "DeviceId: %s\n", debugstr_hstring( str ) ); + 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 ); + + hr = IBluetoothLEDevice_get_Name( device, &str ); + todo_wine ok_( __FILE__, line )( hr == S_OK, "got hr %#lx.\n", hr ); + if (hr == S_OK) + trace( "Name: %s\n", debugstr_hstring( str ) ); + WindowsDeleteString( str ); + + hr = IBluetoothLEDevice_get_ConnectionStatus( device, &status ); + todo_wine ok_( __FILE__, line )( hr == S_OK, "got hr %#lx.\n", hr ); + if (hr == S_OK) + trace( "ConnectionStatus: %d\n", status ); +} + static void test_BluetoothLEDeviceStatics( void ) { static const WCHAR *class_name = RuntimeClass_Windows_Devices_Bluetooth_BluetoothLEDevice; IAsyncOperation_BluetoothLEDevice *async_op; + SP_DEVICE_INTERFACE_DATA iface_data; IBluetoothLEDeviceStatics *statics; IActivationFactory *factory; IBluetoothLEDevice *device = NULL; + HDEVINFO devinfo; HSTRING str; HRESULT hr; + DWORD err, idx = 0; WindowsCreateString( class_name, wcslen( class_name ), &str ); hr = RoGetActivationFactory( str, &IID_IActivationFactory, (void *)&factory ); @@ -569,6 +607,49 @@ static void test_BluetoothLEDeviceStatics( void ) if (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 ); + err = GetLastError(); + ok( devinfo != INVALID_HANDLE_VALUE, "SetupDiGetClassDevsW failed: %lu\n", err ); + iface_data.cbSize = sizeof( iface_data ); + while (SetupDiEnumDeviceInterfaces( devinfo, NULL, &GUID_BLUETOOTHLE_DEVICE_INTERFACE, idx++, &iface_data )) + { + SP_DEVINFO_DATA devinfo_data; + WCHAR addr_str[13]; + DEVPROPTYPE type; + UINT64 addr = 0; + BOOL success; + + devinfo_data.cbSize = sizeof( devinfo_data ); + success = SetupDiGetDeviceInterfaceDetailW( devinfo, &iface_data, NULL, 0, NULL, &devinfo_data ); + err = GetLastError(); + ok( !success && err == ERROR_INSUFFICIENT_BUFFER, "SetupDiGetDeviceInterfaceDetailW failed: %lu\n", err ); + addr_str[0] = '\0'; + success = SetupDiGetDevicePropertyW( devinfo, &devinfo_data, &DEVPKEY_Bluetooth_DeviceAddress, &type, (BYTE *)addr_str, sizeof( addr_str ), NULL, 0 ); + err = GetLastError(); + ok( success, "SetupDiGetDevicePropertyW failed: %lu\n", err ); + swscanf( addr_str, L"%I64x", &addr ); + + 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; + } + + await_bluetoothledevice( __LINE__, async_op ); + check_bluetoothledevice_async( __LINE__, async_op, 1, Completed, S_OK, FALSE, &device ); + IAsyncOperation_BluetoothLEDevice_Release( async_op ); + + test_IBluetoothLEDevice( __LINE__, device, addr ); + IBluetoothLEDevice_Release( device ); + winetest_pop_context(); + } + + SetupDiDestroyDeviceInfoList( devinfo ); IBluetoothLEDeviceStatics_Release( statics ); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10865
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
From: Vibhav Pant <vibhavp@gmail.com> --- dlls/windows.devices.bluetooth/bluetoothdevice.c | 5 +++-- dlls/windows.devices.bluetooth/tests/bluetooth.c | 7 +++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dlls/windows.devices.bluetooth/bluetoothdevice.c b/dlls/windows.devices.bluetooth/bluetoothdevice.c index 5cd66fada2d..9806f4c495d 100644 --- a/dlls/windows.devices.bluetooth/bluetoothdevice.c +++ b/dlls/windows.devices.bluetooth/bluetoothdevice.c @@ -236,8 +236,9 @@ static HRESULT WINAPI ble_device_GetTrustLevel( IBluetoothLEDevice *iface, Trust static HRESULT WINAPI ble_device_get_DeviceId( IBluetoothLEDevice *iface, HSTRING *value ) { - FIXME( "(%p, %p): stub!\n", iface, value ); - return E_NOTIMPL; + struct ble_device *impl = impl_from_IBluetoothLEDevice( iface ); + TRACE( "(%p, %p)\n", iface, value ); + return WindowsDuplicateString( impl->id, value ); } static HRESULT WINAPI ble_device_get_Name( IBluetoothLEDevice *iface, HSTRING *value ) diff --git a/dlls/windows.devices.bluetooth/tests/bluetooth.c b/dlls/windows.devices.bluetooth/tests/bluetooth.c index 0c189f1def6..07e5e2f905d 100644 --- a/dlls/windows.devices.bluetooth/tests/bluetooth.c +++ b/dlls/windows.devices.bluetooth/tests/bluetooth.c @@ -537,10 +537,9 @@ static void test_IBluetoothLEDevice( int line, IBluetoothLEDevice *device, UINT6 HRESULT hr; hr = IBluetoothLEDevice_get_DeviceId( device, &str ); - todo_wine ok_( __FILE__, line )( hr == S_OK, "got hr %#lx.\n", hr ); - todo_wine ok_( __FILE__, line )( !WindowsIsStringEmpty( str ), "got empty DeviceId value.\n" ); - if (hr == S_OK) - trace( "DeviceId: %s\n", debugstr_hstring( str ) ); + ok_( __FILE__, line )( hr == S_OK, "got hr %#lx.\n", hr ); + ok_( __FILE__, line )( !WindowsIsStringEmpty( str ), "got empty DeviceId value.\n" ); + trace( "DeviceId: %s\n", debugstr_hstring( str ) ); WindowsDeleteString( str ); hr = IBluetoothLEDevice_get_BluetoothAddress( device, &addr2 ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10865
From: Vibhav Pant <vibhavp@gmail.com> --- dlls/windows.devices.bluetooth/Makefile.in | 4 +- .../bluetoothdevice.c | 64 +- dlls/windows.devices.bluetooth/gatt.c | 154 ++++ dlls/windows.devices.bluetooth/private.h | 12 + .../tests/bluetooth.c | 41 ++ dlls/windows.devices.bluetooth/vector.c | 675 ++++++++++++++++++ 6 files changed, 947 insertions(+), 3 deletions(-) create mode 100644 dlls/windows.devices.bluetooth/gatt.c create mode 100644 dlls/windows.devices.bluetooth/vector.c diff --git a/dlls/windows.devices.bluetooth/Makefile.in b/dlls/windows.devices.bluetooth/Makefile.in index 0e0364f2a3f..a3823f49023 100644 --- a/dlls/windows.devices.bluetooth/Makefile.in +++ b/dlls/windows.devices.bluetooth/Makefile.in @@ -8,4 +8,6 @@ SOURCES = \ bluetoothadapter.c \ bluetoothdevice.c \ classes.idl \ - main.c + gatt.c \ + main.c \ + vector.c diff --git a/dlls/windows.devices.bluetooth/bluetoothdevice.c b/dlls/windows.devices.bluetooth/bluetoothdevice.c index 9806f4c495d..adc3fddb18d 100644 --- a/dlls/windows.devices.bluetooth/bluetoothdevice.c +++ b/dlls/windows.devices.bluetooth/bluetoothdevice.c @@ -24,6 +24,7 @@ #include "devpkey.h" #include "bthledef.h" #include "ddk/bthguid.h" +#include "bluetoothleapis.h" #include "wine/debug.h" @@ -167,6 +168,7 @@ struct ble_device IBluetoothLEDevice IBluetoothLEDevice_iface; HSTRING id; UINT64 addr; + HANDLE device; LONG ref; }; @@ -211,6 +213,7 @@ static ULONG WINAPI ble_device_Release( IBluetoothLEDevice *iface ) if (!ref) { WindowsDeleteString( impl->id ); + CloseHandle( impl->device ); free( impl ); } return ref; @@ -249,8 +252,58 @@ static HRESULT WINAPI ble_device_get_Name( IBluetoothLEDevice *iface, HSTRING *v static HRESULT WINAPI ble_device_get_GattServices( IBluetoothLEDevice *iface, IVectorView_GattDeviceService **services ) { - FIXME( "(%p, %p): stub!\n", iface, services ); - return E_NOTIMPL; + static const struct vector_iids iids = { + .vector = &IID_IVector_IInspectable, + .view = &IID_IVectorView_GattDeviceService, + .iterable = &IID_IIterable_GattDeviceService, + .iterator = &IID_IIterator_GattDeviceService, + }; + struct ble_device *impl = impl_from_IBluetoothLEDevice( iface ); + BTH_LE_GATT_SERVICE *buf = NULL; + IVector_IInspectable *vector; + USHORT actual = 0, i; + HRESULT hr; + + TRACE( "(%p, %p)\n", iface, services ); + + *services = NULL; + if (FAILED(hr = vector_create( &iids, (void **)&vector ))) return hr; + hr = BluetoothGATTGetServices( impl->device, 0, NULL, &actual, 0 ); + if (SUCCEEDED( hr ) || hr != HRESULT_FROM_WIN32( ERROR_MORE_DATA )) goto done; + + for (;;) + { + UINT32 size = actual; + void *tmp; + + if (!(tmp = realloc( buf, sizeof( *buf ) * size ))) + { + hr = E_OUTOFMEMORY; + goto done; + } + buf = tmp; + if (SUCCEEDED(hr = BluetoothGATTGetServices( impl->device, size, buf, &actual, 0 ))) break; + if (hr != HRESULT_FROM_WIN32( ERROR_INVALID_USER_BUFFER )) goto done; + } + for (i = 0; i < actual; i++) + { + IGattDeviceService *service; + + if (FAILED(hr = gatt_service_create( &buf[i], &service ))) goto done; + hr = IVector_IInspectable_Append( vector, (IInspectable *)service ); + IGattDeviceService_Release( service ); + if (FAILED( hr )) goto done; + } +done: + free( buf ); + if (FAILED( hr )) + { + IVector_IInspectable_Release( vector ); + return hr; + } + hr = IVector_IInspectable_GetView( vector, (IVectorView_IInspectable **)services ); + IVector_IInspectable_Release( vector ); + return hr; } static HRESULT WINAPI ble_device_get_ConnectionStatus( IBluetoothLEDevice *iface, BluetoothConnectionStatus *value ) @@ -350,6 +403,13 @@ static HRESULT ble_device_create( IBluetoothLEDevice **device, const WCHAR *id, free( impl ); return hr; } + impl->device = CreateFileW( id, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL ); + if (impl->device == INVALID_HANDLE_VALUE) + { + WindowsDeleteString( impl->id ); + free( impl ); + return HRESULT_FROM_WIN32( GetLastError() ); + } impl->ref = 1; impl->addr = addr; impl->IBluetoothLEDevice_iface.lpVtbl = &ble_device_vtbl; diff --git a/dlls/windows.devices.bluetooth/gatt.c b/dlls/windows.devices.bluetooth/gatt.c new file mode 100644 index 00000000000..43b968f844d --- /dev/null +++ b/dlls/windows.devices.bluetooth/gatt.c @@ -0,0 +1,154 @@ +/* IGatt* Implementation + * + * Copyright 2026 Vibhav Pant + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "private.h" +#include "bthledef.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL( bluetooth ); + +struct gatt_service +{ + IGattDeviceService IGattDeviceService_iface; + LONG ref; + + BTH_LE_GATT_SERVICE service; +}; + +static inline struct gatt_service *impl_from_IGattDeviceService( IGattDeviceService *iface ) +{ + return CONTAINING_RECORD( iface, struct gatt_service, IGattDeviceService_iface ); +} + +static HRESULT WINAPI gatt_service_QueryInterface( IGattDeviceService *iface, REFIID iid, void **out ) +{ + struct gatt_service *impl = impl_from_IGattDeviceService( 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_IGattDeviceService )) + { + IGattDeviceService_AddRef(( *out = &impl->IGattDeviceService_iface )); + return S_OK; + } + *out = NULL; + FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); + return E_NOINTERFACE; +} + +static ULONG WINAPI gatt_service_AddRef( IGattDeviceService *iface ) +{ + struct gatt_service *impl = impl_from_IGattDeviceService( iface ); + TRACE( "(%p)\n", iface ); + return InterlockedIncrement( &impl->ref ); +} + +static ULONG WINAPI gatt_service_Release( IGattDeviceService *iface ) +{ + struct gatt_service *impl = impl_from_IGattDeviceService( iface ); + ULONG ref = InterlockedDecrement( &impl->ref ); + TRACE( "(%p)\n", iface ); + if (!ref) + free( impl ); + return ref; +} + +static HRESULT WINAPI gatt_service_GetIids( IGattDeviceService *iface, ULONG *iid_count, IID **iids ) +{ + FIXME( "(%p, %p, %p): stub!\n", iface, iid_count, iids ); + return E_NOTIMPL; +} + +static HRESULT WINAPI gatt_service_GetRuntimeClassName( IGattDeviceService *iface, HSTRING *class_name ) +{ + FIXME( "(%p, %p): stub!\n", iface, class_name ); + return E_NOTIMPL; +} + +static HRESULT WINAPI gatt_service_GetTrustLevel( IGattDeviceService *iface, TrustLevel *level ) +{ + FIXME( "(%p, %p): stub!\n", iface, level ); + return E_NOTIMPL; +} + +static HRESULT WINAPI gatt_service_GetCharacteristics( IGattDeviceService *iface, GUID uuid, IVectorView_GattCharacteristic **chars ) +{ + FIXME( "(%p, %s, %p): stub!\n", iface, debugstr_guid( &uuid ), chars ); + return E_NOTIMPL; +} + +static HRESULT WINAPI gatt_service_GetIncludedServices( IGattDeviceService *iface, GUID uuid, IVectorView_GattDeviceService **services ) +{ + FIXME( "(%p, %s, %p): stub!\n", iface, debugstr_guid( &uuid ), services ); + return E_NOTIMPL; +} + +static HRESULT WINAPI gatt_service_get_DeviceId( IGattDeviceService *iface, HSTRING *value ) +{ + FIXME( "(%p, %p): stub!\n", iface, value ); + *value = NULL; + return E_NOTIMPL; +} + +static HRESULT WINAPI gatt_service_get_Uuid( IGattDeviceService *iface, GUID *value ) +{ + FIXME( "(%p, %p): stub!\n", iface, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI gatt_service_get_AttributeHandle( IGattDeviceService *iface, UINT16 *value ) +{ + FIXME( "(%p, %p): stub!\n", iface, value ); + return E_NOTIMPL; +} + +static const IGattDeviceServiceVtbl gatt_service_vtbl = +{ + /* IUnknown */ + gatt_service_QueryInterface, + gatt_service_AddRef, + gatt_service_Release, + /* IInspectable */ + gatt_service_GetIids, + gatt_service_GetRuntimeClassName, + gatt_service_GetTrustLevel, + /* IGattDeviceService */ + gatt_service_GetCharacteristics, + gatt_service_GetIncludedServices, + gatt_service_get_DeviceId, + gatt_service_get_Uuid, + gatt_service_get_AttributeHandle +}; + +HRESULT gatt_service_create( const BTH_LE_GATT_SERVICE *svc, IGattDeviceService **service ) +{ + struct gatt_service *impl; + + if (!(impl = calloc( 1, sizeof( *impl ) ))) + return E_OUTOFMEMORY; + impl->IGattDeviceService_iface.lpVtbl = &gatt_service_vtbl; + impl->ref = 1; + impl->service = *svc; + *service = &impl->IGattDeviceService_iface; + return S_OK; +} diff --git a/dlls/windows.devices.bluetooth/private.h b/dlls/windows.devices.bluetooth/private.h index 3882558de37..b0d86775b75 100644 --- a/dlls/windows.devices.bluetooth/private.h +++ b/dlls/windows.devices.bluetooth/private.h @@ -26,6 +26,7 @@ #include "windef.h" #include "winbase.h" #include "winstring.h" +#include "bthledef.h" #include "activation.h" #include "bthdef.h" @@ -58,6 +59,17 @@ extern IActivationFactory *advertisement_watcher_factory; HRESULT async_operation_inspectable_create( const GUID *iid, IUnknown *invoker, IUnknown *param, async_operation_callback callback, IAsyncOperation_IInspectable **out ); +struct vector_iids +{ + const GUID *iterable; + const GUID *iterator; + const GUID *vector; + const GUID *view; +}; +HRESULT vector_create( const struct vector_iids *iids, void **out ); + +HRESULT gatt_service_create( const BTH_LE_GATT_SERVICE *svc, IGattDeviceService **service ); + #define DEFINE_IINSPECTABLE_( pfx, iface_type, impl_type, impl_from, iface_mem, expr ) \ static inline impl_type *impl_from( iface_type *iface ) \ { \ diff --git a/dlls/windows.devices.bluetooth/tests/bluetooth.c b/dlls/windows.devices.bluetooth/tests/bluetooth.c index 07e5e2f905d..3b300234d52 100644 --- a/dlls/windows.devices.bluetooth/tests/bluetooth.c +++ b/dlls/windows.devices.bluetooth/tests/bluetooth.c @@ -529,6 +529,31 @@ static void test_BluetoothDeviceStatics( void ) IBluetoothDeviceStatics_Release( statics ); } +static void test_IGattDeviceService( int line, IGattDeviceService *service ) +{ + HSTRING str = NULL; + UINT16 handle; + HRESULT hr; + GUID uuid; + + hr = IGattDeviceService_get_DeviceId( service, &str ); + todo_wine ok_( __FILE__, line )( hr == S_OK, "got hr %#lx.\n", hr ); + todo_wine ok_( __FILE__, line )( !WindowsIsStringEmpty( str ), "got empty DeviceId value.\n" ); + if (hr == S_OK) + trace( "DeviceId: %s\n", debugstr_hstring( str ) ); + WindowsDeleteString( str ); + + hr = IGattDeviceService_get_Uuid( service, &uuid ); + todo_wine ok_( __FILE__, line )( hr == S_OK, "got hr %#lx.\n", hr ); + if (hr == S_OK) + trace( "UUID: %s\n", debugstr_guid( &uuid ) ); + + hr = IGattDeviceService_get_AttributeHandle( service, &handle ); + todo_wine ok_( __FILE__, line )( hr == S_OK, "got hr %#lx.\n", hr ); + if (hr == S_OK) + trace( "Attribute handle: %#x\n", handle ); +} + static void test_IBluetoothLEDevice( int line, IBluetoothLEDevice *device, UINT64 addr ) { BluetoothConnectionStatus status; @@ -610,8 +635,10 @@ static void test_BluetoothLEDeviceStatics( void ) iface_data.cbSize = sizeof( iface_data ); while (SetupDiEnumDeviceInterfaces( devinfo, NULL, &GUID_BLUETOOTHLE_DEVICE_INTERFACE, idx++, &iface_data )) { + IVectorView_GattDeviceService *services; SP_DEVINFO_DATA devinfo_data; WCHAR addr_str[13]; + UINT32 i, len = 0; DEVPROPTYPE type; UINT64 addr = 0; BOOL success; @@ -635,6 +662,20 @@ static void test_BluetoothLEDeviceStatics( void ) IAsyncOperation_BluetoothLEDevice_Release( async_op ); test_IBluetoothLEDevice( __LINE__, device, addr ); + hr = IBluetoothLEDevice_get_GattServices( device, &services ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + IVectorView_GattDeviceService_get_Size( services, &len ); + for (i = 0; i < len; i++) + { + IGattDeviceService *service; + + winetest_push_context( "GATT service %u", i ); + IVectorView_GattDeviceService_GetAt( services, i, &service ); + test_IGattDeviceService( __LINE__, service ); + winetest_pop_context(); + IGattDeviceService_Release( service ); + } + IBluetoothLEDevice_Release( device ); winetest_pop_context(); } diff --git a/dlls/windows.devices.bluetooth/vector.c b/dlls/windows.devices.bluetooth/vector.c new file mode 100644 index 00000000000..f0aa937995b --- /dev/null +++ b/dlls/windows.devices.bluetooth/vector.c @@ -0,0 +1,675 @@ +/* WinRT IVector<IInspectable *> implementation + * + * Copyright 2021 Rémi Bernon for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "private.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(combase); + +struct iterator +{ + IIterator_IInspectable IIterator_IInspectable_iface; + const GUID *iid; + LONG ref; + + IVectorView_IInspectable *view; + UINT32 index; + UINT32 size; +}; + +static inline struct iterator *impl_from_IIterator_IInspectable( IIterator_IInspectable *iface ) +{ + return CONTAINING_RECORD( iface, struct iterator, IIterator_IInspectable_iface ); +} + +static HRESULT WINAPI iterator_QueryInterface( IIterator_IInspectable *iface, REFIID iid, void **out ) +{ + struct iterator *impl = impl_from_IIterator_IInspectable( iface ); + + TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid( iid ), out ); + + if (IsEqualGUID( iid, &IID_IUnknown ) || + IsEqualGUID( iid, &IID_IInspectable ) || + IsEqualGUID( iid, &IID_IAgileObject ) || + IsEqualGUID( iid, impl->iid )) + { + IInspectable_AddRef( (*out = &impl->IIterator_IInspectable_iface) ); + return S_OK; + } + + FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI iterator_AddRef( IIterator_IInspectable *iface ) +{ + struct iterator *impl = impl_from_IIterator_IInspectable( iface ); + ULONG ref = InterlockedIncrement( &impl->ref ); + TRACE( "iface %p increasing refcount to %lu.\n", iface, ref ); + return ref; +} + +static ULONG WINAPI iterator_Release( IIterator_IInspectable *iface ) +{ + struct iterator *impl = impl_from_IIterator_IInspectable( iface ); + ULONG ref = InterlockedDecrement( &impl->ref ); + + TRACE( "iface %p decreasing refcount to %lu.\n", iface, ref ); + + if (!ref) + { + IVectorView_IInspectable_Release( impl->view ); + free( impl ); + } + + return ref; +} + +static HRESULT WINAPI iterator_GetIids( IIterator_IInspectable *iface, ULONG *iid_count, IID **iids ) +{ + FIXME( "iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids ); + return E_NOTIMPL; +} + +static HRESULT WINAPI iterator_GetRuntimeClassName( IIterator_IInspectable *iface, HSTRING *class_name ) +{ + FIXME( "iface %p, class_name %p stub!\n", iface, class_name ); + return E_NOTIMPL; +} + +static HRESULT WINAPI iterator_GetTrustLevel( IIterator_IInspectable *iface, TrustLevel *trust_level ) +{ + FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level ); + return E_NOTIMPL; +} + +static HRESULT WINAPI iterator_get_Current( IIterator_IInspectable *iface, IInspectable **value ) +{ + struct iterator *impl = impl_from_IIterator_IInspectable( iface ); + TRACE( "iface %p, value %p.\n", iface, value ); + return IVectorView_IInspectable_GetAt( impl->view, impl->index, value ); +} + +static HRESULT WINAPI iterator_get_HasCurrent( IIterator_IInspectable *iface, boolean *value ) +{ + struct iterator *impl = impl_from_IIterator_IInspectable( iface ); + + TRACE( "iface %p, value %p.\n", iface, value ); + + *value = impl->index < impl->size; + return S_OK; +} + +static HRESULT WINAPI iterator_MoveNext( IIterator_IInspectable *iface, boolean *value ) +{ + struct iterator *impl = impl_from_IIterator_IInspectable( iface ); + + TRACE( "iface %p, value %p.\n", iface, value ); + + if (impl->index < impl->size) impl->index++; + return IIterator_IInspectable_get_HasCurrent( iface, value ); +} + +static HRESULT WINAPI iterator_GetMany( IIterator_IInspectable *iface, UINT32 items_size, + IInspectable **items, UINT *count ) +{ + struct iterator *impl = impl_from_IIterator_IInspectable( iface ); + TRACE( "iface %p, items_size %u, items %p, count %p.\n", iface, items_size, items, count ); + return IVectorView_IInspectable_GetMany( impl->view, impl->index, items_size, items, count ); +} + +static const IIterator_IInspectableVtbl iterator_vtbl = +{ + iterator_QueryInterface, + iterator_AddRef, + iterator_Release, + /* IInspectable methods */ + iterator_GetIids, + iterator_GetRuntimeClassName, + iterator_GetTrustLevel, + /* IIterator<IInspectable*> methods */ + iterator_get_Current, + iterator_get_HasCurrent, + iterator_MoveNext, + iterator_GetMany, +}; + +struct vector_view +{ + IVectorView_IInspectable IVectorView_IInspectable_iface; + IIterable_IInspectable IIterable_IInspectable_iface; + struct vector_iids iids; + LONG ref; + + UINT32 size; + IInspectable *elements[1]; +}; + +static inline struct vector_view *impl_from_IVectorView_IInspectable( IVectorView_IInspectable *iface ) +{ + return CONTAINING_RECORD( iface, struct vector_view, IVectorView_IInspectable_iface ); +} + +static HRESULT WINAPI vector_view_QueryInterface( IVectorView_IInspectable *iface, REFIID iid, void **out ) +{ + struct vector_view *impl = impl_from_IVectorView_IInspectable( iface ); + + TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid( iid ), out ); + + if (IsEqualGUID( iid, &IID_IUnknown ) || + IsEqualGUID( iid, &IID_IInspectable ) || + IsEqualGUID( iid, &IID_IAgileObject ) || + IsEqualGUID( iid, impl->iids.view )) + { + IInspectable_AddRef( (*out = &impl->IVectorView_IInspectable_iface) ); + return S_OK; + } + + if (IsEqualGUID( iid, impl->iids.iterable )) + { + IInspectable_AddRef( (*out = &impl->IIterable_IInspectable_iface) ); + return S_OK; + } + + FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI vector_view_AddRef( IVectorView_IInspectable *iface ) +{ + struct vector_view *impl = impl_from_IVectorView_IInspectable( iface ); + ULONG ref = InterlockedIncrement( &impl->ref ); + TRACE( "iface %p increasing refcount to %lu.\n", iface, ref ); + return ref; +} + +static ULONG WINAPI vector_view_Release( IVectorView_IInspectable *iface ) +{ + struct vector_view *impl = impl_from_IVectorView_IInspectable( iface ); + ULONG i, ref = InterlockedDecrement( &impl->ref ); + + TRACE( "iface %p decreasing refcount to %lu.\n", iface, ref ); + + if (!ref) + { + for (i = 0; i < impl->size; ++i) IInspectable_Release( impl->elements[i] ); + free( impl ); + } + + return ref; +} + +static HRESULT WINAPI vector_view_GetIids( IVectorView_IInspectable *iface, ULONG *iid_count, IID **iids ) +{ + FIXME( "iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids ); + return E_NOTIMPL; +} + +static HRESULT WINAPI vector_view_GetRuntimeClassName( IVectorView_IInspectable *iface, HSTRING *class_name ) +{ + FIXME( "iface %p, class_name %p stub!\n", iface, class_name ); + return E_NOTIMPL; +} + +static HRESULT WINAPI vector_view_GetTrustLevel( IVectorView_IInspectable *iface, TrustLevel *trust_level ) +{ + FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level ); + return E_NOTIMPL; +} + +static HRESULT WINAPI vector_view_GetAt( IVectorView_IInspectable *iface, UINT32 index, IInspectable **value ) +{ + struct vector_view *impl = impl_from_IVectorView_IInspectable( iface ); + + TRACE( "iface %p, index %u, value %p.\n", iface, index, value ); + + *value = NULL; + if (index >= impl->size) return E_BOUNDS; + + IInspectable_AddRef( (*value = impl->elements[index]) ); + return S_OK; +} + +static HRESULT WINAPI vector_view_get_Size( IVectorView_IInspectable *iface, UINT32 *value ) +{ + struct vector_view *impl = impl_from_IVectorView_IInspectable( iface ); + + TRACE( "iface %p, value %p.\n", iface, value ); + + *value = impl->size; + return S_OK; +} + +static HRESULT WINAPI vector_view_IndexOf( IVectorView_IInspectable *iface, IInspectable *element, + UINT32 *index, BOOLEAN *found ) +{ + struct vector_view *impl = impl_from_IVectorView_IInspectable( iface ); + ULONG i; + + TRACE( "iface %p, element %p, index %p, found %p.\n", iface, element, index, found ); + + for (i = 0; i < impl->size; ++i) if (impl->elements[i] == element) break; + if ((*found = (i < impl->size))) *index = i; + else *index = 0; + + return S_OK; +} + +static HRESULT WINAPI vector_view_GetMany( IVectorView_IInspectable *iface, UINT32 start_index, + UINT32 items_size, IInspectable **items, UINT *count ) +{ + struct vector_view *impl = impl_from_IVectorView_IInspectable( iface ); + UINT32 i; + + TRACE( "iface %p, start_index %u, items_size %u, items %p, count %p.\n", + iface, start_index, items_size, items, count ); + + if (start_index >= impl->size) return E_BOUNDS; + + for (i = start_index; i < impl->size; ++i) + { + if (i - start_index >= items_size) break; + IInspectable_AddRef( (items[i - start_index] = impl->elements[i]) ); + } + *count = i - start_index; + + return S_OK; +} + +static const struct IVectorView_IInspectableVtbl vector_view_vtbl = +{ + vector_view_QueryInterface, + vector_view_AddRef, + vector_view_Release, + /* IInspectable methods */ + vector_view_GetIids, + vector_view_GetRuntimeClassName, + vector_view_GetTrustLevel, + /* IVectorView<IInspectable*> methods */ + vector_view_GetAt, + vector_view_get_Size, + vector_view_IndexOf, + vector_view_GetMany, +}; + +DEFINE_IINSPECTABLE_( iterable_view, IIterable_IInspectable, struct vector_view, view_impl_from_IIterable_IInspectable, + IIterable_IInspectable_iface, &impl->IVectorView_IInspectable_iface ) + +static HRESULT WINAPI iterable_view_First( IIterable_IInspectable *iface, IIterator_IInspectable **value ) +{ + struct vector_view *impl = view_impl_from_IIterable_IInspectable( iface ); + struct iterator *iter; + + TRACE( "iface %p, value %p.\n", iface, value ); + + if (!(iter = calloc( 1, sizeof(struct iterator) ))) return E_OUTOFMEMORY; + iter->IIterator_IInspectable_iface.lpVtbl = &iterator_vtbl; + iter->iid = impl->iids.iterator; + iter->ref = 1; + + IVectorView_IInspectable_AddRef( (iter->view = &impl->IVectorView_IInspectable_iface) ); + iter->size = impl->size; + + *value = &iter->IIterator_IInspectable_iface; + return S_OK; +} + +static const struct IIterable_IInspectableVtbl iterable_view_vtbl = +{ + iterable_view_QueryInterface, + iterable_view_AddRef, + iterable_view_Release, + /* IInspectable methods */ + iterable_view_GetIids, + iterable_view_GetRuntimeClassName, + iterable_view_GetTrustLevel, + /* IIterable<T> methods */ + iterable_view_First, +}; + +struct vector +{ + IVector_IInspectable IVector_IInspectable_iface; + IIterable_IInspectable IIterable_IInspectable_iface; + struct vector_iids iids; + LONG ref; + + UINT32 size; + UINT32 capacity; + IInspectable **elements; +}; + +static inline struct vector *impl_from_IVector_IInspectable( IVector_IInspectable *iface ) +{ + return CONTAINING_RECORD( iface, struct vector, IVector_IInspectable_iface ); +} + +static HRESULT WINAPI vector_QueryInterface( IVector_IInspectable *iface, REFIID iid, void **out ) +{ + struct vector *impl = impl_from_IVector_IInspectable( iface ); + + TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid( iid ), out ); + + if (IsEqualGUID( iid, &IID_IUnknown ) || + IsEqualGUID( iid, &IID_IInspectable ) || + IsEqualGUID( iid, &IID_IAgileObject ) || + IsEqualGUID( iid, impl->iids.vector )) + { + IInspectable_AddRef( (*out = &impl->IVector_IInspectable_iface) ); + return S_OK; + } + + if (IsEqualGUID( iid, impl->iids.iterable )) + { + IInspectable_AddRef( (*out = &impl->IIterable_IInspectable_iface) ); + return S_OK; + } + + FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI vector_AddRef( IVector_IInspectable *iface ) +{ + struct vector *impl = impl_from_IVector_IInspectable( iface ); + ULONG ref = InterlockedIncrement( &impl->ref ); + TRACE( "iface %p increasing refcount to %lu.\n", iface, ref ); + return ref; +} + +static ULONG WINAPI vector_Release( IVector_IInspectable *iface ) +{ + struct vector *impl = impl_from_IVector_IInspectable( iface ); + ULONG ref = InterlockedDecrement( &impl->ref ); + + TRACE( "iface %p decreasing refcount to %lu.\n", iface, ref ); + + if (!ref) + { + IVector_IInspectable_Clear( iface ); + free( impl ); + } + + return ref; +} + +static HRESULT WINAPI vector_GetIids( IVector_IInspectable *iface, ULONG *iid_count, IID **iids ) +{ + FIXME( "iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids ); + return E_NOTIMPL; +} + +static HRESULT WINAPI vector_GetRuntimeClassName( IVector_IInspectable *iface, HSTRING *class_name ) +{ + FIXME( "iface %p, class_name %p stub!\n", iface, class_name ); + return E_NOTIMPL; +} + +static HRESULT WINAPI vector_GetTrustLevel( IVector_IInspectable *iface, TrustLevel *trust_level ) +{ + FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level ); + return E_NOTIMPL; +} + +static HRESULT WINAPI vector_GetAt( IVector_IInspectable *iface, UINT32 index, IInspectable **value ) +{ + struct vector *impl = impl_from_IVector_IInspectable( iface ); + + TRACE( "iface %p, index %u, value %p.\n", iface, index, value ); + + *value = NULL; + if (index >= impl->size) return E_BOUNDS; + + IInspectable_AddRef( (*value = impl->elements[index]) ); + return S_OK; +} + +static HRESULT WINAPI vector_get_Size( IVector_IInspectable *iface, UINT32 *value ) +{ + struct vector *impl = impl_from_IVector_IInspectable( iface ); + TRACE( "iface %p, value %p.\n", iface, value ); + *value = impl->size; + return S_OK; +} + +static HRESULT WINAPI vector_GetView( IVector_IInspectable *iface, IVectorView_IInspectable **value ) +{ + struct vector *impl = impl_from_IVector_IInspectable( iface ); + struct vector_view *view; + ULONG i; + + TRACE( "iface %p, value %p.\n", iface, value ); + + if (!(view = calloc( 1, offsetof( struct vector_view, elements[impl->size] ) ))) return E_OUTOFMEMORY; + view->IVectorView_IInspectable_iface.lpVtbl = &vector_view_vtbl; + view->IIterable_IInspectable_iface.lpVtbl = &iterable_view_vtbl; + view->iids = impl->iids; + view->ref = 1; + + for (i = 0; i < impl->size; ++i) IInspectable_AddRef( (view->elements[view->size++] = impl->elements[i]) ); + + *value = &view->IVectorView_IInspectable_iface; + return S_OK; +} + +static HRESULT WINAPI vector_IndexOf( IVector_IInspectable *iface, IInspectable *element, UINT32 *index, BOOLEAN *found ) +{ + struct vector *impl = impl_from_IVector_IInspectable( iface ); + ULONG i; + + TRACE( "iface %p, element %p, index %p, found %p.\n", iface, element, index, found ); + + for (i = 0; i < impl->size; ++i) if (impl->elements[i] == element) break; + if ((*found = (i < impl->size))) *index = i; + else *index = 0; + + return S_OK; +} + +static HRESULT WINAPI vector_SetAt( IVector_IInspectable *iface, UINT32 index, IInspectable *value ) +{ + struct vector *impl = impl_from_IVector_IInspectable( iface ); + + TRACE( "iface %p, index %u, value %p.\n", iface, index, value ); + + if (index >= impl->size) return E_BOUNDS; + IInspectable_Release( impl->elements[index] ); + IInspectable_AddRef( (impl->elements[index] = value) ); + return S_OK; +} + +static HRESULT WINAPI vector_InsertAt( IVector_IInspectable *iface, UINT32 index, IInspectable *value ) +{ + struct vector *impl = impl_from_IVector_IInspectable( iface ); + IInspectable **tmp = impl->elements; + + TRACE( "iface %p, index %u, value %p.\n", iface, index, value ); + + if (impl->size == impl->capacity) + { + impl->capacity = max( 32, impl->capacity * 3 / 2 ); + if (!(impl->elements = realloc( impl->elements, impl->capacity * sizeof(*impl->elements) ))) + { + impl->elements = tmp; + return E_OUTOFMEMORY; + } + } + + memmove( impl->elements + index + 1, impl->elements + index, (impl->size++ - index) * sizeof(*impl->elements) ); + IInspectable_AddRef( (impl->elements[index] = value) ); + return S_OK; +} + +static HRESULT WINAPI vector_RemoveAt( IVector_IInspectable *iface, UINT32 index ) +{ + struct vector *impl = impl_from_IVector_IInspectable( iface ); + + TRACE( "iface %p, index %u.\n", iface, index ); + + if (index >= impl->size) return E_BOUNDS; + IInspectable_Release( impl->elements[index] ); + memmove( impl->elements + index, impl->elements + index + 1, (--impl->size - index) * sizeof(*impl->elements) ); + return S_OK; +} + +static HRESULT WINAPI vector_Append( IVector_IInspectable *iface, IInspectable *value ) +{ + struct vector *impl = impl_from_IVector_IInspectable( iface ); + + TRACE( "iface %p, value %p.\n", iface, value ); + + return IVector_IInspectable_InsertAt( iface, impl->size, value ); +} + +static HRESULT WINAPI vector_RemoveAtEnd( IVector_IInspectable *iface ) +{ + struct vector *impl = impl_from_IVector_IInspectable( iface ); + + TRACE( "iface %p.\n", iface ); + + if (impl->size) IInspectable_Release( impl->elements[--impl->size] ); + return S_OK; +} + +static HRESULT WINAPI vector_Clear( IVector_IInspectable *iface ) +{ + struct vector *impl = impl_from_IVector_IInspectable( iface ); + + TRACE( "iface %p.\n", iface ); + + while (impl->size) IVector_IInspectable_RemoveAtEnd( iface ); + free( impl->elements ); + impl->capacity = 0; + impl->elements = NULL; + + return S_OK; +} + +static HRESULT WINAPI vector_GetMany( IVector_IInspectable *iface, UINT32 start_index, + UINT32 items_size, IInspectable **items, UINT *count ) +{ + struct vector *impl = impl_from_IVector_IInspectable( iface ); + UINT32 i; + + TRACE( "iface %p, start_index %u, items_size %u, items %p, count %p.\n", + iface, start_index, items_size, items, count ); + + if (start_index >= impl->size) return E_BOUNDS; + + for (i = start_index; i < impl->size; ++i) + { + if (i - start_index >= items_size) break; + IInspectable_AddRef( (items[i - start_index] = impl->elements[i]) ); + } + *count = i - start_index; + + return S_OK; +} + +static HRESULT WINAPI vector_ReplaceAll( IVector_IInspectable *iface, UINT32 count, IInspectable **items ) +{ + HRESULT hr; + ULONG i; + + TRACE( "iface %p, count %u, items %p.\n", iface, count, items ); + + hr = IVector_IInspectable_Clear( iface ); + for (i = 0; i < count && SUCCEEDED(hr); ++i) hr = IVector_IInspectable_Append( iface, items[i] ); + return hr; +} + +static const struct IVector_IInspectableVtbl vector_vtbl = +{ + vector_QueryInterface, + vector_AddRef, + vector_Release, + /* IInspectable methods */ + vector_GetIids, + vector_GetRuntimeClassName, + vector_GetTrustLevel, + /* IVector<IInspectable*> methods */ + vector_GetAt, + vector_get_Size, + vector_GetView, + vector_IndexOf, + vector_SetAt, + vector_InsertAt, + vector_RemoveAt, + vector_Append, + vector_RemoveAtEnd, + vector_Clear, + vector_GetMany, + vector_ReplaceAll, +}; + +DEFINE_IINSPECTABLE( iterable, IIterable_IInspectable, struct vector, IVector_IInspectable_iface ) + +static HRESULT WINAPI iterable_First( IIterable_IInspectable *iface, IIterator_IInspectable **value ) +{ + struct vector *impl = impl_from_IIterable_IInspectable( iface ); + IIterable_IInspectable *iterable; + IVectorView_IInspectable *view; + HRESULT hr; + + TRACE( "iface %p, value %p.\n", iface, value ); + + if (FAILED(hr = IVector_IInspectable_GetView( &impl->IVector_IInspectable_iface, &view ))) return hr; + + hr = IVectorView_IInspectable_QueryInterface( view, impl->iids.iterable, (void **)&iterable ); + IVectorView_IInspectable_Release( view ); + if (FAILED(hr)) return hr; + + hr = IIterable_IInspectable_First( iterable, value ); + IIterable_IInspectable_Release( iterable ); + return hr; +} + +static const struct IIterable_IInspectableVtbl iterable_vtbl = +{ + iterable_QueryInterface, + iterable_AddRef, + iterable_Release, + /* IInspectable methods */ + iterable_GetIids, + iterable_GetRuntimeClassName, + iterable_GetTrustLevel, + /* IIterable<T> methods */ + iterable_First, +}; + +HRESULT vector_create( const struct vector_iids *iids, void **out ) +{ + struct vector *impl; + + TRACE( "iid %s, out %p.\n", debugstr_guid( iids->vector ), out ); + + if (!(impl = calloc( 1, sizeof(*impl) ))) return E_OUTOFMEMORY; + impl->IVector_IInspectable_iface.lpVtbl = &vector_vtbl; + impl->IIterable_IInspectable_iface.lpVtbl = &iterable_vtbl; + impl->iids = *iids; + impl->ref = 1; + + *out = &impl->IVector_IInspectable_iface; + TRACE( "created %p\n", *out ); + return S_OK; +} -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10865
From: Vibhav Pant <vibhavp@gmail.com> --- dlls/windows.devices.bluetooth/gatt.c | 13 +++++++++++-- dlls/windows.devices.bluetooth/tests/bluetooth.c | 5 ++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/dlls/windows.devices.bluetooth/gatt.c b/dlls/windows.devices.bluetooth/gatt.c index 43b968f844d..ac541bfc180 100644 --- a/dlls/windows.devices.bluetooth/gatt.c +++ b/dlls/windows.devices.bluetooth/gatt.c @@ -112,8 +112,17 @@ static HRESULT WINAPI gatt_service_get_DeviceId( IGattDeviceService *iface, HSTR static HRESULT WINAPI gatt_service_get_Uuid( IGattDeviceService *iface, GUID *value ) { - FIXME( "(%p, %p): stub!\n", iface, value ); - return E_NOTIMPL; + struct gatt_service *impl = impl_from_IGattDeviceService( iface ); + TRACE( "(%p, %p)\n", iface, value ); + + if (impl->service.ServiceUuid.IsShortUuid) + { + *value = BTH_LE_ATT_BLUETOOTH_BASE_GUID; + value->Data1 = impl->service.ServiceUuid.Value.ShortUuid; + } + else + *value = impl->service.ServiceUuid.Value.LongUuid; + return S_OK; } static HRESULT WINAPI gatt_service_get_AttributeHandle( IGattDeviceService *iface, UINT16 *value ) diff --git a/dlls/windows.devices.bluetooth/tests/bluetooth.c b/dlls/windows.devices.bluetooth/tests/bluetooth.c index 3b300234d52..ac32b9f8520 100644 --- a/dlls/windows.devices.bluetooth/tests/bluetooth.c +++ b/dlls/windows.devices.bluetooth/tests/bluetooth.c @@ -544,9 +544,8 @@ static void test_IGattDeviceService( int line, IGattDeviceService *service ) WindowsDeleteString( str ); hr = IGattDeviceService_get_Uuid( service, &uuid ); - todo_wine ok_( __FILE__, line )( hr == S_OK, "got hr %#lx.\n", hr ); - if (hr == S_OK) - trace( "UUID: %s\n", debugstr_guid( &uuid ) ); + ok_( __FILE__, line )( hr == S_OK, "got hr %#lx.\n", hr ); + trace( "UUID: %s\n", debugstr_guid( &uuid ) ); hr = IGattDeviceService_get_AttributeHandle( service, &handle ); todo_wine ok_( __FILE__, line )( hr == S_OK, "got hr %#lx.\n", hr ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10865
From: Vibhav Pant <vibhavp@gmail.com> --- dlls/windows.devices.bluetooth/gatt.c | 6 ++++-- dlls/windows.devices.bluetooth/tests/bluetooth.c | 5 ++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/dlls/windows.devices.bluetooth/gatt.c b/dlls/windows.devices.bluetooth/gatt.c index ac541bfc180..84b8ee84d5e 100644 --- a/dlls/windows.devices.bluetooth/gatt.c +++ b/dlls/windows.devices.bluetooth/gatt.c @@ -127,8 +127,10 @@ static HRESULT WINAPI gatt_service_get_Uuid( IGattDeviceService *iface, GUID *va static HRESULT WINAPI gatt_service_get_AttributeHandle( IGattDeviceService *iface, UINT16 *value ) { - FIXME( "(%p, %p): stub!\n", iface, value ); - return E_NOTIMPL; + struct gatt_service *impl = impl_from_IGattDeviceService( iface ); + TRACE( "(%p, %p)\n", iface, value ); + *value = impl->service.AttributeHandle; + return S_OK; } static const IGattDeviceServiceVtbl gatt_service_vtbl = diff --git a/dlls/windows.devices.bluetooth/tests/bluetooth.c b/dlls/windows.devices.bluetooth/tests/bluetooth.c index ac32b9f8520..b2ff49f454e 100644 --- a/dlls/windows.devices.bluetooth/tests/bluetooth.c +++ b/dlls/windows.devices.bluetooth/tests/bluetooth.c @@ -548,9 +548,8 @@ static void test_IGattDeviceService( int line, IGattDeviceService *service ) trace( "UUID: %s\n", debugstr_guid( &uuid ) ); hr = IGattDeviceService_get_AttributeHandle( service, &handle ); - todo_wine ok_( __FILE__, line )( hr == S_OK, "got hr %#lx.\n", hr ); - if (hr == S_OK) - trace( "Attribute handle: %#x\n", handle ); + ok_( __FILE__, line )( hr == S_OK, "got hr %#lx.\n", hr ); + trace( "Attribute handle: %#x\n", handle ); } static void test_IBluetoothLEDevice( int line, IBluetoothLEDevice *device, UINT64 addr ) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10865
participants (2)
-
Vibhav Pant -
Vibhav Pant (@vibhavp)