Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ output, runtime behavior, and the `@microsoft/dynwinrt` root API.
- Method call: `method_handle.invoke(obj, [args])` → returns single `DynWinRTValue`
- `IReference<T>` values project as native values plus `None`; generated `IReference_*` wrappers remain accepted for input compatibility
- Generated `Object` positions stay raw `DynWinRTValue`s; `unbox_object(raw, preserve_type=False)` and `to_winrt_object(value, property_type=None)` convert boxed values explicitly, with tags, typed arrays, `Point`/`Size`/`Rect` and `PropertyType` in `dynwinrt.values` (never guess a WinRT type)
- `dynwinrt.values.object_value_view(map, preserve_type=False)` is the opt-in, live converting view of a generated map that QueryInterface confirms as `IMap`/`IMapView<String or Guid, Object>`; reads unbox, writes use `to_winrt_object`, and `view.raw` stays native

### Common Issues
- `test_initialize` is `#[ignore]` — requires `WINAPPSDK_BOOTSTRAP_DLL_PATH` env var
Expand Down
53 changes: 53 additions & 0 deletions bindings/py/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,59 @@ wrapper to an interface view. Use `InterfaceClass.from_value(raw)` for a raw
passing a runtime class raises `TypeError` that points to `project_as()`. Do not
call the internal `_from_native()` method from application code.

### Views of `Object`-valued maps

`dynwinrt.values.object_value_view(mapping, *, preserve_type=False)` is an
opt-in view that applies these conversions to the values of a generated map
whose values are `Object`: `PropertySet`, `ValueSet`,
`DeviceInformation.properties`, the map returned by
`StorageItemContentProperties.retrieve_properties_async()`, and other
`IMap<K, Object>` or `IMapView<K, Object>` maps with `str` or `uuid.UUID`
keys:

```python
from dynwinrt.values import UInt32, object_value_view

view = object_value_view(properties)
view["count"] = 5 # to_winrt_object(5): Int32
view["port"] = UInt32(8080) # UInt32
count = view["count"] # 5
box = view.raw["count"] # the native DynWinRTValue box
```

- The view is live: every operation goes to the map, and the view holds no
WinRT reference of its own. An `IMap` gets a `MutableObjectValueView`, a
`collections.abc.MutableMapping`; an `IMapView` gets a read-only
`ObjectValueView`, a `Mapping`. Releasing the underlying generated wrapper
makes native reads and writes through the view raise the usual released-object
error; a live WinRT null entry still reads as `None`.
- Reads return `None` for WinRT null, a runtime object that is not a box as
its `DynWinRTValue`, and `unbox_object(value, preserve_type=preserve_type)`
for a box. Where `unbox_object` raises for a box without a Python form, the
view returns the box's `DynWinRTValue`, so `dict(view)` does not fail on one
odd entry: an unsupported `PropertyType` such as `OtherType` anywhere inside
the box, or a `DateTime` outside the range of `datetime`. Other errors
propagate, including the same HRESULT from a failing getter for an otherwise
supported `PropertyType`. Each read returns a new `DynWinRTValue` for a
runtime object, so compare those with `identity_raw()`.
- Writes store `to_winrt_object(value)` and raise its errors unchanged: a
plain `int` boxes as `Int32` only, and an empty or mixed list needs a typed
array or an explicit `property_type`.
- `view.raw` is the generated map, which keeps returning native
`DynWinRTValue` objects. Use it to keep a box's COM identity: with
`preserve_type=True`, a value that is read and written back keeps its
`PropertyType`, but it is a new box.
- The generated wrapper declares the exact `IMap`/`IMapView` interface used by
its mapping methods, and `QueryInterface` confirms support for that IID. A
wrapper for another map on the same COM identity is rejected rather than
dispatching through the wrong vtable. Other maps, such as `StringMap` or
`JsonObject`, raise `TypeError`; the type stubs reject them too. Runtime-class
wrappers generated without this declaration fail closed; reproject them with
`value.as_interface(IMap_String_Object)` (or the Guid/read-only equivalent).
- Generated `IPropertySet` wrappers, such as `ApplicationDataContainer.values`,
are not Python mappings. Pass
`container.values.as_interface(IMap_String_Object)` instead.

## COM apartments and cleanup

Use `RoApartment` to initialize COM for a thread and balance every successful
Expand Down
Loading
Loading