The api itself is c based, but the upcoming beta has the winrt apis:
namespace ConsoleApplication625;
uses
rtl.winrt;
type
HSTR = public record
private
fValue: HSTRING;
public
constructor; empty;
constructor(aValue: String);
begin
WindowsCreateString(aValue.FirstChar, aValue.Length, @fValue);
end;
constructor(aValue: ^rtl.WCHAR);
begin
WindowsCreateString(aValue, ExternalCalls.wcslen(aValue), @fValue);
end;
finalizer;
begin
if fvalue <> nil then
WindowsDeleteString(fValue);
end;
method ToString: String; override;
begin
if fValue = nil then exit nil;
var lLen: UInt32;
exit String.FromPChar(WindowsGetStringRawBuffer(fValue, @lLen), lLen);
end;
property Ptr: ^HSTRING read @fValue;
property Value: HSTRING read fValue;
end;
Program = class
public
class method Main(args: array of String): Int32;
begin
var si: ^__x_ABI_CWindows_CSystem_CProfile_CSystemManufacturers_CISmbiosInformationStatics;
var g := Guid.Parse('080CCA7C-637C-48C4-B728-F9273812DB8E');
RoInitialize(RO_INIT_TYPE.MULTITHREADED);
RoGetActivationFactory(new HSTR(RuntimeClass_Windows_System_Profile_SystemManufacturers_SmbiosInformation).Value, ^rtl.Guid(@g), ^^Void(@si));
var lRes: HSTR;
si^.lpVtbl^.get_SerialNumber(si, lRes.Ptr);
si^.lpVtbl^.Release(si);
writeLn(lRes.ToString);
RoUninitialize();
end;
end;
end.
There is no like button on this post, but I do like it!
There is so much potential here.
Can we expect an aspect to map the c-like interface to an island object/interface? So there is no need for …(si,…) or to call Release?
This should allow us to use XAML with Island. I need to try it.
Let’s just say that stuff is quite verbose. It’s ok though - the stuff I need to use it for isn’t too complex. I guess it will be a crash course in COM for me…
Yeah. I’m still looking for ways to make it more manageable; using the IWebBrowser* interfaces myself in a project and finding it way too verbose too. But at least it should get you going.
Is there a way to look at the winrt.fx file? Seeing the actual definitions would be quite helpful as Fire’s “go to definition” feature doesn’t always work and the COM stuff is pretty verbose.
How would one hook up a TypedEventHandler to, say, a BluetoothLEAdvertisementWatcher?
var stoppedHandlerToken: EventRegistrationToken?
// hstr: HSTRING built from RuntimeClass_Windows_Devices_Bluetooth_Advertisement_BluetoothLEAdvertisementWatcher
var guid = RemObjects.Elements.System.Guid.Parse("A6AC336F-F3D3-4297-8D6C-C81EA6623F40")
var obj: UnsafePointer<Void>
if RoGetActivationFactory(hstr, (&guid as! UnsafePointer<GUID>), &obj != S_OK {
return nil
}
let object = obj as! UnsafePointer<__x_ABI_CWindows_CDevices_CBluetooth_CAdvertisement_CIBluetoothLEAdvertisementWatcher>
// Need to instantiate TypedEventHandler<BluetoothLEAdvertisementWatcher, BluetoothLEAdvertisementWatcherStoppedEventArgs>
// this is: __FITypedEventHandler_2_Windows__CDevices__CBluetooth__CAdvertisement__CBluetoothLEAdvertisementWatcher_Windows__CDevices__CBluetooth__CAdvertisement__CBluetoothLEAdvertisementWatcherStoppedEventArgs
var handlerObj: UnsafePointer<__FITypedEventHandler_2_Windows__CDevices__CBluetooth__CAdvertisement__CBluetoothLEAdvertisementWatcher_Windows__CDevices__CBluetooth__CAdvertisement__CBluetoothLEAdvertisementWatcherStoppedEventArgs>
// should I be using RoGetActivationFactory again? I've coded this in C++/CX but it was somewhat straightforward:
// _watcher->Stopped += ref new TypedEventHandler<BluetoothLEAdvertisementWatcher ^, BluetoothLEAdvertisementWatcherStoppedEventArgs ^>(classInstance, &MyClass::OnAdvertisementWatcherStopped);
// ... missing code ...
var token = EventRegistrationToken()
if (*(*object).lpVtbl).add_Stopped(object, handlerObj, &token) == S_OK {
stoppedEventHandler = token
}
// ...
(*(*object).lpVtbl).remove_Stopped(object, stoppedEventHandlerToken)
import rtl.winrt;
@COMImport(typeOf(rtl.winrt.__FITypedEventHandler_2_Windows__CDevices__CBluetooth__CAdvertisement__CBluetoothLEAdvertisementWatcher_Windows__CDevices__CBluetooth__CAdvertisement__CBluetoothLEAdvertisementWatcherStoppedEventArgs), Guid = "9936a4db-dc99-55c3-9e9b-bf4854bd9eab")
public protocol CBluetoothLEAdvertisementWatcherStoppedEventArgs
{
}
public struct CBluetoothLEAdvertisementWatcherStoppedEventArgsPtr
{
}
@COMObject
class Impl: CBluetoothLEAdvertisementWatcherStoppedEventArgs
{
}
writeLn("The magic happens here.")
Impl now fails to compile because it doesn’t implement “invoke” (which is the point of this exercise)
How this works: @COMImport is an aspect that “fills” the protocol and matching *Ptr type. @COMObject creates QueryInterface, AddRef, Release etc to be com usable.
To use it as a com object, you can do something like:
I’m struggling to use the AsyncOperation obtained from BluetoothLEDevice::FromAsync. I have made some simple wrapper classes for the WinRT classes I’m using. Here is my code:
import rtl
import rtl.winrt
@COMImport(typeOf(__FIAsyncOperationCompletedHandler_1_Windows__CDevices__CBluetooth__CBluetoothLEDevice), Guid = "9156b79f-c54a-5277-8f8b-d2cc43c7e004")
public protocol IAsyncOperationCompletedHandler_CBluetoothLEDevice {
}
public struct IAsyncOperationCompletedHandler_CBluetoothLEDevicePtr {
}
@COMObject
public class AsyncOperationCompletedHandler_BluetoothLEDevice : IAsyncOperationCompletedHandler_CBluetoothLEDevice {
private weak var completion: (UnsafePointer<__x_ABI_CWindows_CDevices_CBluetooth_CIBluetoothLEDevice>?) -> Void
init(completion: (UnsafePointer<__x_ABI_CWindows_CDevices_CBluetooth_CIBluetoothLEDevice>?) -> Void) {
self.completion = completion
}
public func Invoke(_ asyncInfo: UnsafePointer<__FIAsyncOperation_1_Windows__CDevices__CBluetooth__CBluetoothLEDevice>, _ status: AsyncStatus) -> HRESULT {
var device: UnsafePointer<__x_ABI_CWindows_CDevices_CBluetooth_CIBluetoothLEDevice>?
(*(*asyncInfo).lpVtbl).GetResults(asyncInfo, &device)
completion(device)
return S_OK
}
}
public class BluetoothLEDevice {
private static __field IID___x_ABI_CWindows_CDevices_CBluetooth_CIBluetoothLEDeviceStatics = RemObjects.Elements.System.Guid.Parse("C8CF1A19-F0B6-4BF0-8689-41303DE2D9F4")
class func FromIdAsync(deviceId: String, completion: (BluetoothLEDevice?) -> Void) {
let basid = HStringWrapper(wstr: RuntimeClass_Windows_Devices_Bluetooth_BluetoothLEDevice)
var obj: UnsafePointer<Void>
guard RoGetActivationFactory(basid.value, (&IID___x_ABI_CWindows_CDevices_CBluetooth_CIBluetoothLEDeviceStatics as! UnsafePointer<GUID>), &obj) == S_OK else {
completion(nil)
return
}
guard let bas = obj as? UnsafePointer<__x_ABI_CWindows_CDevices_CBluetooth_CIBluetoothLEDeviceStatics> else {
completion(nil)
return
}
defer {
(*(*bas).lpVtbl).Release(bas)
}
var asyncOperation: UnsafePointer<__FIAsyncOperation_1_Windows__CDevices__CBluetooth__CBluetoothLEDevice>
guard (*(*bas).lpVtbl).FromIdAsync(bas, HStringWrapper(string: deviceId).value, &asyncOperation) == S_OK else {
completion(nil)
return
}
var completedHandler: IAsyncOperationCompletedHandler_CBluetoothLEDevice = AsyncOperationCompletedHandler_BluetoothLEDevice { asyncInfo in
guard let asyncInfo = asyncInfo else {
completion(nil)
return
}
completion(BluetoothLEDevice(object: asyncInfo))
}
let res = (*(*asyncOperation).lpVtbl).put_Completed(asyncOperation, (&completedHandler as! UnsafePointer<__FIAsyncOperationCompletedHandler_1_Windows__CDevices__CBluetooth__CBluetoothLEDevice>))
guard res == S_OK else {
completion(nil)
return
}
}
}
It seems to work fine until I call put_Completed (bottom part of the source code). At that point, the app just poofs, I get no exception, no HRESULT to check, nothing. This is code I’m calling directly from a console application. Note: asyncOperation is not nil and if I pass nil as the second parameter to put_Completed I get no crash.