Browse Source
* Bump MicroCOM to 0.11.4, add workaround for WinRT bug * menu.h - use ComPtr for COM stored references * Replaced raw COM pointers with smart ones * fixes * Use weak com ref from AvnMenuItem * Better smart pointer handling * Avalonia native readme update * review * missing dif * Just call the ctor like a normal personrelease/12.0.0-rc2
committed by
GitHub
30 changed files with 305 additions and 115 deletions
@ -0,0 +1,3 @@ |
|||
|
|||
When running code review, please refer to the following documents if they are relevant to the changed parts of the codebase: |
|||
- `native/Avalonia.Native/**` -> `native/Avalonia.Native/README.md` |
|||
@ -0,0 +1,26 @@ |
|||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
|||
<PropertyGroup> |
|||
<!-- Uncomment to use local MicroCOM build --> |
|||
<!--<UseLocalMicroComBuild>true</UseLocalMicroComBuild>--> |
|||
|
|||
<LocalMicroComPath Condition="'$(LocalMicroComPath)' == ''">$(MSBuildThisFileDirectory)/../../MicroCom</LocalMicroComPath> |
|||
</PropertyGroup> |
|||
|
|||
<!-- Local build: delegate to MicroCom's own targets --> |
|||
<Import Condition="'$(UseLocalMicroComBuild)' == 'true'" |
|||
Project="$(LocalMicroComPath)/UseLocalBuild.targets" /> |
|||
|
|||
<!-- NuGet packages: include based on property flags --> |
|||
<ItemGroup Condition="'$(UseLocalMicroComBuild)' != 'true'"> |
|||
<PackageReference Condition="'$(UseMicroCom)' == 'true'" |
|||
Include="MicroCom.Runtime" /> |
|||
<PackageReference Condition="'$(UseMicroComGenerator)' == 'true'" |
|||
Include="MicroCom.CodeGenerator" /> |
|||
<PackageReference Condition="'$(UseMicroComGeneratorMSBuild)' == 'true'" |
|||
Include="MicroCom.CodeGenerator.MSBuild" |
|||
PrivateAssets="all" /> |
|||
<PackageReference Condition="'$(UseMicroComGeneratorRoslyn)' == 'true'" |
|||
Include="MicroCom.CodeGenerator.Roslyn" |
|||
PrivateAssets="all" /> |
|||
</ItemGroup> |
|||
</Project> |
|||
@ -0,0 +1,87 @@ |
|||
# Avalonia.Native |
|||
|
|||
This project implements the macOS native platform backend for Avalonia using Objective-C++ and COM (Component Object Model) interfaces. |
|||
|
|||
|
|||
## COM Reference Management |
|||
|
|||
This codebase uses COM for cross-boundary object lifetime management. COM types are typically prefixed with `IAvn` (interfaces) or `Avn` (implementations). All COM objects ultimately derive from `IUnknown` and use reference counting (`AddRef`/`Release`). |
|||
|
|||
**No raw COM pointer should ever be stored in class fields, instance variables, closures, or containers.** Raw COM pointers are only acceptable as function parameters and local variables with the lifetime of the current function call. |
|||
|
|||
### COM Return Value Convention |
|||
|
|||
By convention, any COM interface reference returned from a COM call has its reference counter incremented — it is the caller's responsibility to release it. With the `IFoo* GetFoo()` pattern it is hard to track this correctly, so all methods in `avn.idl` should use the out-parameter pattern instead: |
|||
|
|||
```cpp |
|||
// WRONG — easy to leak or forget Release: |
|||
IFoo* GetFoo(); |
|||
|
|||
// CORRECT — use HRESULT + out-parameter: |
|||
HRESULT GetFoo(IFoo** ppv); |
|||
``` |
|||
# Smart pointer types |
|||
|
|||
### Objective-C Objects |
|||
|
|||
For Objective-C objects, reference counting is provided by the compiler. Objective-C pointers _look_ like raw pointers, however every `NSObject*` reference is properly ref-counted by ARC (Automatic Reference Counting). No manual wrapping is needed for `NSObject*` fields. |
|||
|
|||
### COM Smart Pointer Types |
|||
|
|||
All retained COM references must use one of the following wrappers defined in `inc/comimpl.h`: |
|||
|
|||
#### `ComPtr<T>` — Owning Reference |
|||
|
|||
Use for any COM pointer that the holder needs to keep alive. |
|||
|
|||
```cpp |
|||
ComPtr<IAvnWindow> _window; // correct |
|||
IAvnWindow* _window; // WRONG — raw COM pointer in a field |
|||
``` |
|||
|
|||
#### `ComObjectWeakPtr<T>` — Non-Owning Weak Reference |
|||
|
|||
Use for intentional non-owning references to `ComObject`-derived objects (internal implementations). Allows safely referencing COM objects without extending their lifetime. |
|||
|
|||
```cpp |
|||
ComObjectWeakPtr<WindowBaseImpl> _parent; // correct |
|||
WindowBaseImpl* _parent; // WRONG |
|||
``` |
|||
|
|||
Access weak references with `tryGet()`, which returns a `ComPtr<T>` (null if the object was destroyed): |
|||
|
|||
```cpp |
|||
auto parent = _parent.tryGet(); |
|||
if (parent) { |
|||
parent->DoSomething(); |
|||
} |
|||
``` |
|||
|
|||
#### `ComStaticPtr<T>` — Process-Lifetime Static Reference |
|||
|
|||
Use for static/global COM singletons that must live for the entire process lifetime. Intentionally does **not** Release in its destructor to avoid crashes during app teardown. |
|||
|
|||
```cpp |
|||
static ComStaticPtr<IAvnGlDisplay> GlDisplay; // correct |
|||
static IAvnGlDisplay* GlDisplay; // WRONG |
|||
``` |
|||
|
|||
Assign via `set()`: |
|||
|
|||
```cpp |
|||
GlDisplay.set(comnew<AvnGlDisplay>()); |
|||
``` |
|||
|
|||
### `comnew<T>(args...)` — COM Object Factory |
|||
|
|||
A convenience template similar to `std::make_shared`. Creates a new COM object and returns it wrapped in a `ComPtr<T>` with correct ownership (no double-AddRef): |
|||
|
|||
```cpp |
|||
// Instead of: |
|||
ComPtr<Cursor> cursor(new Cursor(nsCursor), true); |
|||
|
|||
// Write: |
|||
ComPtr<Cursor> cursor = comnew<Cursor>(nsCursor); |
|||
``` |
|||
|
|||
This works because `new T()` on a `ComObject`-derived type starts with refcount=1, and `comnew` wraps it in a `ComPtr` that takes ownership without an additional `AddRef`. |
|||
Loading…
Reference in new issue