From 37255dba1519450e3d5ef8dc32de56e4db7da9c8 Mon Sep 17 00:00:00 2001 From: Jared Henderson Date: Fri, 27 Jan 2017 11:26:03 -0800 Subject: [PATCH 1/6] Fixing leak in UIKit.Xaml controls, and a leak in UIButton. --- Frameworks/UIKit/UIButton.mm | 2 +- Frameworks/UIKit/XamlControls.mm | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Frameworks/UIKit/UIButton.mm b/Frameworks/UIKit/UIButton.mm index d2d9263c34..be10f0a748 100644 --- a/Frameworks/UIKit/UIButton.mm +++ b/Frameworks/UIKit/UIButton.mm @@ -184,7 +184,7 @@ - (void)_initUIButton { _contentVerticalAlignment = UIControlContentVerticalAlignmentCenter; _contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter; - __block UIButton* weakSelf = self; + __weak UIButton* weakSelf = self; XamlControls::HookButtonPointerEvents(_xamlButton, ^(RTObject* sender, WUXIPointerRoutedEventArgs* e) { // We mark the event as handled here. The method _processPointerPressedCallback diff --git a/Frameworks/UIKit/XamlControls.mm b/Frameworks/UIKit/XamlControls.mm index 5dd40bbdf7..9760eb9e74 100644 --- a/Frameworks/UIKit/XamlControls.mm +++ b/Frameworks/UIKit/XamlControls.mm @@ -27,7 +27,9 @@ // Button //////////////////////////////////////////////////////////////////////////////////// WXCButton* CreateButton() { - ComPtr inspectable(XamlCreateButton()); + ComPtr inspectable; + // Use Attach for transfer-ownership semantics, else we +1 and leak + inspectable.Attach(XamlCreateButton()); return _createRtProxy([WXCButton class], inspectable.Get()); } @@ -53,7 +55,9 @@ void HookLayoutEvent(WXCButton* button, WUXIPointerEventHandler layoutHook) { // ContentDialog //////////////////////////////////////////////////////////////////////////////////// WXCContentDialog* CreateContentDialog() { - ComPtr inspectable(XamlCreateContentDialog()); + ComPtr inspectable; + // Use Attach for transfer-ownership semantics, else we +1 and leak + inspectable.Attach(XamlCreateContentDialog()); return _createRtProxy([WXCContentDialog class], inspectable.Get()); } @@ -95,7 +99,9 @@ void XamlContentDialogSetDestructiveButtonIndex(WXCContentDialog* contentDialog, // Label //////////////////////////////////////////////////////////////////////////////////// WXCGrid* CreateLabel() { - Microsoft::WRL::ComPtr inspectable(XamlCreateLabel()); + Microsoft::WRL::ComPtr inspectable; + // Use Attach for transfer-ownership semantics, else we +1 and leak + inspectable.Attach(XamlCreateLabel()); return _createRtProxy([WXCGrid class], inspectable.Get()); } From 5e9999de89166960575b837c24c52f3d3e1fbe52 Mon Sep 17 00:00:00 2001 From: Jared Henderson Date: Fri, 27 Jan 2017 13:06:57 -0800 Subject: [PATCH 2/6] Adding UIButton memory leak tests. --- tests/functionaltests/FunctionalTests.cpp | 5 ++ .../Tests/UIKitTests/UIButtonTests.mm | 66 +++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/tests/functionaltests/FunctionalTests.cpp b/tests/functionaltests/FunctionalTests.cpp index 7ffff9b506..af68199a63 100644 --- a/tests/functionaltests/FunctionalTests.cpp +++ b/tests/functionaltests/FunctionalTests.cpp @@ -476,6 +476,7 @@ extern void UIActivityIndicatorViewGetXamlElement(); extern void UIButtonCreateXamlElement(); extern void UIButtonGetXamlElement(); +extern void UIButtonCheckForLeaks(); extern void UIButtonTitleColorChanged(); extern void UIButtonTextChanged(); @@ -606,6 +607,10 @@ class UIKitTests { FrameworkHelper::RunOnUIThread(&UIButtonGetXamlElement); } + TEST_METHOD(UIButton_CheckForLeaks) { + UIButtonCheckForLeaks(); + } + TEST_METHOD(UIButton_TitleColorChanged) { UIButtonTitleColorChanged(); } diff --git a/tests/functionaltests/Tests/UIKitTests/UIButtonTests.mm b/tests/functionaltests/Tests/UIKitTests/UIButtonTests.mm index 78094cbb91..e1b767b5e7 100644 --- a/tests/functionaltests/Tests/UIKitTests/UIButtonTests.mm +++ b/tests/functionaltests/Tests/UIKitTests/UIButtonTests.mm @@ -38,6 +38,72 @@ ASSERT_TRUE([backingElement isKindOfClass:[WXFrameworkElement class]]); } +@interface UIDeallocTestButton : UIButton { + NSCondition* _condition; + BOOL* _signaled; +} +@end + +@implementation UIDeallocTestButton + +- (void)setDeallocEvent:(NSCondition*)condition signaledFlag:(BOOL*)signaled { + _condition = condition; + _signaled = signaled; +} + +-(void)dealloc { + [_condition lock]; + *_signaled = YES; + [_condition signal]; + [_condition unlock]; + [super dealloc]; +} +@end + +TEST(UIButton, CheckForLeaks) { + Microsoft::WRL::WeakRef weakXamlElement; + { + __block UIButtonWithControlsViewController* buttonVC = [[UIButtonWithControlsViewController alloc] init]; + UXTestAPI::ViewControllerPresenter testHelper(buttonVC); + + __block UIDeallocTestButton* testButton = nil; + __block BOOL signaled = NO; + __block NSCondition* condition = [[NSCondition alloc] init]; + + // Create and render the button + dispatch_sync(dispatch_get_main_queue(), ^{ + testButton = [[UIDeallocTestButton alloc] initWithFrame:CGRectMake(100, 100, 100, 100)]; + testButton.backgroundColor = [UIColor redColor]; + [testButton setDeallocEvent:condition signaledFlag:&signaled]; + [buttonVC.view addSubview:testButton]; + }); + + // Grab a weak reference to the backing Xaml element + Microsoft::WRL::ComPtr xamlElement([[testButton xamlElement] comObj]); + ASSERT_TRUE_MSG(SUCCEEDED(xamlElement.AsWeak(&weakXamlElement)), "Failed to acquire a weak reference to the backing Xaml element."); + xamlElement = nullptr; + + // Free the button + dispatch_sync(dispatch_get_main_queue(), ^{ + // Nil out testButton and remove it from its superview + [testButton removeFromSuperview]; + [testButton release]; + testButton = nil; + }); + + // Validate that dealloc was called + [condition lock]; + ASSERT_TRUE_MSG(signaled || [condition waitUntilDate:[NSDate dateWithTimeIntervalSinceNow:c_testTimeoutInSec]], + "FAILED: Waiting for dealloc call failed!"); + [condition unlock]; + } + + // Validate that we can no longer acquire a strong reference to the UIButton's backing Xaml element + Microsoft::WRL::ComPtr xamlElement; + weakXamlElement.As(&xamlElement); + ASSERT_EQ_MSG(xamlElement.Get(), nullptr, "Unexpectedly able to reacquire a strong reference to the backing Xaml element."); +} + TEST(UIButton, TitleColorChanged) { __block auto uxEvent = UXEvent::CreateManual(); __block auto xamlSubscriber = std::make_shared(); From 157b9d6ad50912af599d86f7f2ca8d6cf832e7a9 Mon Sep 17 00:00:00 2001 From: Jared Henderson Date: Fri, 27 Jan 2017 14:29:07 -0800 Subject: [PATCH 3/6] Switching to fancy new event helper. --- .../Tests/UIKitTests/UIButtonTests.mm | 23 ++++++------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/tests/functionaltests/Tests/UIKitTests/UIButtonTests.mm b/tests/functionaltests/Tests/UIKitTests/UIButtonTests.mm index e1b767b5e7..d09a4bf281 100644 --- a/tests/functionaltests/Tests/UIKitTests/UIButtonTests.mm +++ b/tests/functionaltests/Tests/UIKitTests/UIButtonTests.mm @@ -39,23 +39,18 @@ } @interface UIDeallocTestButton : UIButton { - NSCondition* _condition; - BOOL* _signaled; + std::shared_ptr _event; } @end @implementation UIDeallocTestButton -- (void)setDeallocEvent:(NSCondition*)condition signaledFlag:(BOOL*)signaled { - _condition = condition; - _signaled = signaled; +- (void)setDeallocEvent:(std::shared_ptr)event { + _event = event; } -(void)dealloc { - [_condition lock]; - *_signaled = YES; - [_condition signal]; - [_condition unlock]; + _event->Set(); [super dealloc]; } @end @@ -67,14 +62,13 @@ -(void)dealloc { UXTestAPI::ViewControllerPresenter testHelper(buttonVC); __block UIDeallocTestButton* testButton = nil; - __block BOOL signaled = NO; - __block NSCondition* condition = [[NSCondition alloc] init]; + __block auto event = UXEvent::CreateAuto(); // Create and render the button dispatch_sync(dispatch_get_main_queue(), ^{ testButton = [[UIDeallocTestButton alloc] initWithFrame:CGRectMake(100, 100, 100, 100)]; testButton.backgroundColor = [UIColor redColor]; - [testButton setDeallocEvent:condition signaledFlag:&signaled]; + [testButton setDeallocEvent:event]; [buttonVC.view addSubview:testButton]; }); @@ -92,10 +86,7 @@ -(void)dealloc { }); // Validate that dealloc was called - [condition lock]; - ASSERT_TRUE_MSG(signaled || [condition waitUntilDate:[NSDate dateWithTimeIntervalSinceNow:c_testTimeoutInSec]], - "FAILED: Waiting for dealloc call failed!"); - [condition unlock]; + ASSERT_TRUE_MSG(event->Wait(c_testTimeoutInSec), "FAILED: Waiting for dealloc call failed!"); } // Validate that we can no longer acquire a strong reference to the UIButton's backing Xaml element From bfd4c1135dd0704e573658e332e9d4417f6ec538 Mon Sep 17 00:00:00 2001 From: Jared Henderson Date: Fri, 27 Jan 2017 14:58:14 -0800 Subject: [PATCH 4/6] Add a slight delay after freeing the UIBUtton to prevent a very intermittent test failure (failed twice out of 500 times). --- tests/functionaltests/Tests/UIKitTests/UIButtonTests.mm | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/functionaltests/Tests/UIKitTests/UIButtonTests.mm b/tests/functionaltests/Tests/UIKitTests/UIButtonTests.mm index d09a4bf281..0f59610a43 100644 --- a/tests/functionaltests/Tests/UIKitTests/UIButtonTests.mm +++ b/tests/functionaltests/Tests/UIKitTests/UIButtonTests.mm @@ -89,6 +89,9 @@ -(void)dealloc { ASSERT_TRUE_MSG(event->Wait(c_testTimeoutInSec), "FAILED: Waiting for dealloc call failed!"); } + // Unfortunately we have to wait a bit for the button to actually finish deallocation + [NSThread sleepForTimeInterval:.25]; + // Validate that we can no longer acquire a strong reference to the UIButton's backing Xaml element Microsoft::WRL::ComPtr xamlElement; weakXamlElement.As(&xamlElement); From 82d0fb89a789ba9cc1e3f7ce6c81dbd64aec2ff5 Mon Sep 17 00:00:00 2001 From: Jared Henderson Date: Fri, 27 Jan 2017 15:06:19 -0800 Subject: [PATCH 5/6] Switching to StrongId for VC. --- tests/functionaltests/Tests/UIKitTests/UIButtonTests.mm | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/functionaltests/Tests/UIKitTests/UIButtonTests.mm b/tests/functionaltests/Tests/UIKitTests/UIButtonTests.mm index 0f59610a43..10c59cde5f 100644 --- a/tests/functionaltests/Tests/UIKitTests/UIButtonTests.mm +++ b/tests/functionaltests/Tests/UIKitTests/UIButtonTests.mm @@ -58,7 +58,8 @@ -(void)dealloc { TEST(UIButton, CheckForLeaks) { Microsoft::WRL::WeakRef weakXamlElement; { - __block UIButtonWithControlsViewController* buttonVC = [[UIButtonWithControlsViewController alloc] init]; + StrongId buttonVC; + buttonVC.attach([[UIButtonWithControlsViewController alloc] init]); UXTestAPI::ViewControllerPresenter testHelper(buttonVC); __block UIDeallocTestButton* testButton = nil; @@ -69,7 +70,7 @@ -(void)dealloc { testButton = [[UIDeallocTestButton alloc] initWithFrame:CGRectMake(100, 100, 100, 100)]; testButton.backgroundColor = [UIColor redColor]; [testButton setDeallocEvent:event]; - [buttonVC.view addSubview:testButton]; + [[buttonVC view] addSubview:testButton]; }); // Grab a weak reference to the backing Xaml element From 8e376a5d626fdc20d654d43ba401dc116163825b Mon Sep 17 00:00:00 2001 From: Jared Henderson Date: Fri, 27 Jan 2017 17:05:32 -0800 Subject: [PATCH 6/6] Incorporating CR feedback. --- Frameworks/UIKit.Xaml/Button.xaml.cpp | 6 +++--- Frameworks/UIKit.Xaml/ContentDialog.xaml.cpp | 5 +++-- Frameworks/UIKit.Xaml/Label.xaml.cpp | 5 +++-- Frameworks/UIKit.Xaml/ObjCXamlControls.h | 14 +++++++------- Frameworks/UIKit.Xaml/ProgressRing.xaml.cpp | 5 +++-- Frameworks/UIKit.Xaml/ScrollViewer.xaml.cpp | 5 +++-- Frameworks/UIKit.Xaml/Slider.xaml.cpp | 5 +++-- Frameworks/UIKit.Xaml/TextBox.xaml.cpp | 5 +++-- Frameworks/UIKit/XamlControls.mm | 9 +++------ .../Tests/UIKitTests/UIActionSheetTests.mm | 3 ++- .../Tests/UIKitTests/UIActivityIndicatorTests.mm | 3 ++- .../Tests/UIKitTests/UIButtonTests.mm | 3 ++- .../Tests/UIKitTests/UIScrollViewTests.mm | 3 ++- .../Tests/UIKitTests/UISliderTests.mm | 3 ++- .../Tests/UIKitTests/UITextFieldTests.mm | 3 ++- 15 files changed, 43 insertions(+), 34 deletions(-) diff --git a/Frameworks/UIKit.Xaml/Button.xaml.cpp b/Frameworks/UIKit.Xaml/Button.xaml.cpp index 0a1f41fb1b..b47a1dc2f4 100644 --- a/Frameworks/UIKit.Xaml/Button.xaml.cpp +++ b/Frameworks/UIKit.Xaml/Button.xaml.cpp @@ -189,9 +189,9 @@ void Button::OnApplyTemplate() { //////////////////////////////////////////////////////////////////////////////////// // ObjectiveC Interop //////////////////////////////////////////////////////////////////////////////////// -UIKIT_XAML_EXPORT IInspectable* XamlCreateButton() { - auto button = ref new UIKit::Xaml::Button(); - return InspectableFromObject(button).Detach(); +UIKIT_XAML_EXPORT void XamlCreateButton(IInspectable** created) { + ComPtr inspectable = InspectableFromObject(ref new UIKit::Xaml::Button()); + *created = inspectable.Detach(); } UIKIT_XAML_EXPORT void XamlRemovePointerEvents(const ComPtr& inspectableButton) { diff --git a/Frameworks/UIKit.Xaml/ContentDialog.xaml.cpp b/Frameworks/UIKit.Xaml/ContentDialog.xaml.cpp index 13b54d21b1..efaea4560c 100644 --- a/Frameworks/UIKit.Xaml/ContentDialog.xaml.cpp +++ b/Frameworks/UIKit.Xaml/ContentDialog.xaml.cpp @@ -60,8 +60,9 @@ void ContentDialog::OnSelectionChanged(Platform::Object ^sender, SelectionChange // ObjectiveC Interop //////////////////////////////////////////////////////////////////////////////////// -UIKIT_XAML_EXPORT IInspectable* XamlCreateContentDialog() { - return InspectableFromObject(ref new UIKit::Xaml::ContentDialog()).Detach(); +UIKIT_XAML_EXPORT void XamlCreateContentDialog(IInspectable** created) { + ComPtr inspectable = InspectableFromObject(ref new UIKit::Xaml::ContentDialog()); + *created = inspectable.Detach(); } UIKIT_XAML_EXPORT int XamlContentDialogPressedIndex(const ComPtr& inspectableContentDialog) { diff --git a/Frameworks/UIKit.Xaml/Label.xaml.cpp b/Frameworks/UIKit.Xaml/Label.xaml.cpp index ce44885b1d..a53527047f 100644 --- a/Frameworks/UIKit.Xaml/Label.xaml.cpp +++ b/Frameworks/UIKit.Xaml/Label.xaml.cpp @@ -83,8 +83,9 @@ TextBlock^ Label::TextBlock::get() { //////////////////////////////////////////////////////////////////////////////////// // Returns a UIKit::Label as an IInspectable -UIKIT_XAML_EXPORT IInspectable* XamlCreateLabel() { - return InspectableFromObject(ref new UIKit::Xaml::Label()).Detach(); +UIKIT_XAML_EXPORT void XamlCreateLabel(IInspectable** created) { + ComPtr inspectable = InspectableFromObject(ref new UIKit::Xaml::Label()); + *created = inspectable.Detach(); } // Retrieves the UIKit::Label's backing TextBlock as an IInspectable diff --git a/Frameworks/UIKit.Xaml/ObjCXamlControls.h b/Frameworks/UIKit.Xaml/ObjCXamlControls.h index c690101b4b..36c5c72d16 100644 --- a/Frameworks/UIKit.Xaml/ObjCXamlControls.h +++ b/Frameworks/UIKit.Xaml/ObjCXamlControls.h @@ -29,7 +29,7 @@ enum ControlStates { ControlStateNormal = 0, ControlStateHighlighted = 1 << 0, C //////////////////////////////////////////////////////////////////////////////////// // Returns a UIKit::Button as an IInspectable -UIKIT_XAML_EXPORT IInspectable* XamlCreateButton(); +UIKIT_XAML_EXPORT void XamlCreateButton(IInspectable** created); UIKIT_XAML_EXPORT void XamlButtonApplyVisuals(const Microsoft::WRL::ComPtr& inspectableButton, const Microsoft::WRL::ComPtr& inspectableText, @@ -57,7 +57,7 @@ UIKIT_XAML_EXPORT void XamlRemoveLayoutEvent(const Microsoft::WRL::ComPtr& label); @@ -82,35 +82,35 @@ UIKIT_XAML_EXPORT IInspectable* XamlGetFrameworkElementSublayerCanvasProperty(co //////////////////////////////////////////////////////////////////////////////////// // Returns a UIKit::ProgressRing as an IInspectable -UIKIT_XAML_EXPORT IInspectable* XamlCreateProgressRing(); +UIKIT_XAML_EXPORT void XamlCreateProgressRing(IInspectable** created); //////////////////////////////////////////////////////////////////////////////////// // ScrollViewer.xaml.cpp //////////////////////////////////////////////////////////////////////////////////// // Returns a UIKit::ScrollViewer as an IInspectable -UIKIT_XAML_EXPORT IInspectable* XamlCreateScrollViewer(); +UIKIT_XAML_EXPORT void XamlCreateScrollViewer(IInspectable** created); //////////////////////////////////////////////////////////////////////////////////// // Slider.xaml.cpp //////////////////////////////////////////////////////////////////////////////////// // Returns a UIKit::Slider as an IInspectable -UIKIT_XAML_EXPORT IInspectable* XamlCreateSlider(); +UIKIT_XAML_EXPORT void XamlCreateSlider(IInspectable** created); //////////////////////////////////////////////////////////////////////////////////// // TextBox.xaml.cpp //////////////////////////////////////////////////////////////////////////////////// // Returns a UIKit::TextBox as an IInspectable -UIKIT_XAML_EXPORT IInspectable* XamlCreateTextBox(); +UIKIT_XAML_EXPORT void XamlCreateTextBox(IInspectable** created); //////////////////////////////////////////////////////////////////////////////////// // ContentDialog.xaml.cpp //////////////////////////////////////////////////////////////////////////////////// // Returns a UIKit::ContentDialog as an IInspectable -UIKIT_XAML_EXPORT IInspectable* XamlCreateContentDialog(); +UIKIT_XAML_EXPORT void XamlCreateContentDialog(IInspectable** created); // Get the index of the button pressed UIKIT_XAML_EXPORT int XamlContentDialogPressedIndex(const Microsoft::WRL::ComPtr& inspectableContentDialog); diff --git a/Frameworks/UIKit.Xaml/ProgressRing.xaml.cpp b/Frameworks/UIKit.Xaml/ProgressRing.xaml.cpp index b9b723e8fe..13596297c8 100644 --- a/Frameworks/UIKit.Xaml/ProgressRing.xaml.cpp +++ b/Frameworks/UIKit.Xaml/ProgressRing.xaml.cpp @@ -31,8 +31,9 @@ ProgressRing::ProgressRing() { //////////////////////////////////////////////////////////////////////////////////// // ObjectiveC Interop //////////////////////////////////////////////////////////////////////////////////// -UIKIT_XAML_EXPORT IInspectable* XamlCreateProgressRing() { - return InspectableFromObject(ref new UIKit::Xaml::ProgressRing()).Detach(); +UIKIT_XAML_EXPORT void XamlCreateProgressRing(IInspectable** created) { + Microsoft::WRL::ComPtr inspectable = InspectableFromObject(ref new UIKit::Xaml::ProgressRing()); + *created = inspectable.Detach(); } // clang-format on \ No newline at end of file diff --git a/Frameworks/UIKit.Xaml/ScrollViewer.xaml.cpp b/Frameworks/UIKit.Xaml/ScrollViewer.xaml.cpp index 7f5c41f091..ab841a74be 100644 --- a/Frameworks/UIKit.Xaml/ScrollViewer.xaml.cpp +++ b/Frameworks/UIKit.Xaml/ScrollViewer.xaml.cpp @@ -31,8 +31,9 @@ ScrollViewer::ScrollViewer() { //////////////////////////////////////////////////////////////////////////////////// // ObjectiveC Interop //////////////////////////////////////////////////////////////////////////////////// -UIKIT_XAML_EXPORT IInspectable* XamlCreateScrollViewer() { - return InspectableFromObject(ref new UIKit::Xaml::ScrollViewer()).Detach(); +UIKIT_XAML_EXPORT void XamlCreateScrollViewer(IInspectable** created) { + Microsoft::WRL::ComPtr inspectable = InspectableFromObject(ref new UIKit::Xaml::ScrollViewer()); + *created = inspectable.Detach(); } // clang-format on \ No newline at end of file diff --git a/Frameworks/UIKit.Xaml/Slider.xaml.cpp b/Frameworks/UIKit.Xaml/Slider.xaml.cpp index ccfc31e784..1559c57e1d 100644 --- a/Frameworks/UIKit.Xaml/Slider.xaml.cpp +++ b/Frameworks/UIKit.Xaml/Slider.xaml.cpp @@ -36,8 +36,9 @@ void Slider::OnApplyTemplate() { //////////////////////////////////////////////////////////////////////////////////// // ObjectiveC Interop //////////////////////////////////////////////////////////////////////////////////// -UIKIT_XAML_EXPORT IInspectable* XamlCreateSlider() { - return InspectableFromObject(ref new UIKit::Xaml::Slider()).Detach(); +UIKIT_XAML_EXPORT void XamlCreateSlider(IInspectable** created) { + Microsoft::WRL::ComPtr inspectable = InspectableFromObject(ref new UIKit::Xaml::Slider()); + *created = inspectable.Detach(); } // clang-format on \ No newline at end of file diff --git a/Frameworks/UIKit.Xaml/TextBox.xaml.cpp b/Frameworks/UIKit.Xaml/TextBox.xaml.cpp index bd2117cafe..d56720ecc1 100644 --- a/Frameworks/UIKit.Xaml/TextBox.xaml.cpp +++ b/Frameworks/UIKit.Xaml/TextBox.xaml.cpp @@ -36,8 +36,9 @@ void TextBox::OnApplyTemplate() { //////////////////////////////////////////////////////////////////////////////////// // ObjectiveC Interop //////////////////////////////////////////////////////////////////////////////////// -UIKIT_XAML_EXPORT IInspectable* XamlCreateTextBox() { - return InspectableFromObject(ref new UIKit::Xaml::TextBox()).Detach(); +UIKIT_XAML_EXPORT void XamlCreateTextBox(IInspectable** created) { + Microsoft::WRL::ComPtr inspectable = InspectableFromObject(ref new UIKit::Xaml::TextBox()); + *created = inspectable.Detach(); } // clang-format on \ No newline at end of file diff --git a/Frameworks/UIKit/XamlControls.mm b/Frameworks/UIKit/XamlControls.mm index 9760eb9e74..92da5708c4 100644 --- a/Frameworks/UIKit/XamlControls.mm +++ b/Frameworks/UIKit/XamlControls.mm @@ -28,8 +28,7 @@ //////////////////////////////////////////////////////////////////////////////////// WXCButton* CreateButton() { ComPtr inspectable; - // Use Attach for transfer-ownership semantics, else we +1 and leak - inspectable.Attach(XamlCreateButton()); + XamlCreateButton(&inspectable); return _createRtProxy([WXCButton class], inspectable.Get()); } @@ -56,8 +55,7 @@ void HookLayoutEvent(WXCButton* button, WUXIPointerEventHandler layoutHook) { //////////////////////////////////////////////////////////////////////////////////// WXCContentDialog* CreateContentDialog() { ComPtr inspectable; - // Use Attach for transfer-ownership semantics, else we +1 and leak - inspectable.Attach(XamlCreateContentDialog()); + XamlCreateContentDialog(&inspectable); return _createRtProxy([WXCContentDialog class], inspectable.Get()); } @@ -100,8 +98,7 @@ void XamlContentDialogSetDestructiveButtonIndex(WXCContentDialog* contentDialog, //////////////////////////////////////////////////////////////////////////////////// WXCGrid* CreateLabel() { Microsoft::WRL::ComPtr inspectable; - // Use Attach for transfer-ownership semantics, else we +1 and leak - inspectable.Attach(XamlCreateLabel()); + XamlCreateLabel(&inspectable); return _createRtProxy([WXCGrid class], inspectable.Get()); } diff --git a/tests/functionaltests/Tests/UIKitTests/UIActionSheetTests.mm b/tests/functionaltests/Tests/UIKitTests/UIActionSheetTests.mm index 51cd88369d..ff5cb04dfe 100644 --- a/tests/functionaltests/Tests/UIKitTests/UIActionSheetTests.mm +++ b/tests/functionaltests/Tests/UIKitTests/UIActionSheetTests.mm @@ -32,7 +32,8 @@ TEST(UIActionSheet, CreateXamlElement) { // TODO: Switch to UIKit.Xaml projections when they're available. - Microsoft::WRL::ComPtr xamlElement(XamlCreateContentDialog()); + Microsoft::WRL::ComPtr xamlElement; + XamlCreateContentDialog(&xamlElement); ASSERT_TRUE(xamlElement); } diff --git a/tests/functionaltests/Tests/UIKitTests/UIActivityIndicatorTests.mm b/tests/functionaltests/Tests/UIKitTests/UIActivityIndicatorTests.mm index 8a7de09be4..ddfb7ae7c3 100644 --- a/tests/functionaltests/Tests/UIKitTests/UIActivityIndicatorTests.mm +++ b/tests/functionaltests/Tests/UIKitTests/UIActivityIndicatorTests.mm @@ -32,7 +32,8 @@ TEST(UIActivityIndicatorView, CreateXamlElement) { // TODO: Switch to UIKit.Xaml projections when they're available. - Microsoft::WRL::ComPtr xamlElement(XamlCreateProgressRing()); + Microsoft::WRL::ComPtr xamlElement; + XamlCreateProgressRing(&xamlElement); ASSERT_TRUE(xamlElement); } diff --git a/tests/functionaltests/Tests/UIKitTests/UIButtonTests.mm b/tests/functionaltests/Tests/UIKitTests/UIButtonTests.mm index 10c59cde5f..d73e2e185d 100644 --- a/tests/functionaltests/Tests/UIKitTests/UIButtonTests.mm +++ b/tests/functionaltests/Tests/UIKitTests/UIButtonTests.mm @@ -25,7 +25,8 @@ TEST(UIButton, CreateXamlElement) { // TODO: Switch to UIKit.Xaml projections when they're available. - Microsoft::WRL::ComPtr xamlElement(XamlCreateButton()); + Microsoft::WRL::ComPtr xamlElement; + XamlCreateButton(&xamlElement); ASSERT_TRUE(xamlElement); } diff --git a/tests/functionaltests/Tests/UIKitTests/UIScrollViewTests.mm b/tests/functionaltests/Tests/UIKitTests/UIScrollViewTests.mm index cc14678db0..0cacf75e1a 100644 --- a/tests/functionaltests/Tests/UIKitTests/UIScrollViewTests.mm +++ b/tests/functionaltests/Tests/UIKitTests/UIScrollViewTests.mm @@ -32,7 +32,8 @@ TEST(UIScrollView, CreateXamlElement) { // TODO: Switch to UIKit.Xaml projections when they're available. - Microsoft::WRL::ComPtr xamlElement(XamlCreateScrollViewer()); + Microsoft::WRL::ComPtr xamlElement; + XamlCreateScrollViewer(&xamlElement); ASSERT_TRUE(xamlElement); } diff --git a/tests/functionaltests/Tests/UIKitTests/UISliderTests.mm b/tests/functionaltests/Tests/UIKitTests/UISliderTests.mm index e9e2c60612..d83ae52947 100644 --- a/tests/functionaltests/Tests/UIKitTests/UISliderTests.mm +++ b/tests/functionaltests/Tests/UIKitTests/UISliderTests.mm @@ -32,7 +32,8 @@ TEST(UISlider, CreateXamlElement) { // TODO: Switch to UIKit.Xaml projections when they're available. - Microsoft::WRL::ComPtr xamlElement(XamlCreateSlider()); + Microsoft::WRL::ComPtr xamlElement; + XamlCreateSlider(&xamlElement); ASSERT_TRUE(xamlElement); } diff --git a/tests/functionaltests/Tests/UIKitTests/UITextFieldTests.mm b/tests/functionaltests/Tests/UIKitTests/UITextFieldTests.mm index aae4eeebb5..fa2211179f 100644 --- a/tests/functionaltests/Tests/UIKitTests/UITextFieldTests.mm +++ b/tests/functionaltests/Tests/UIKitTests/UITextFieldTests.mm @@ -32,7 +32,8 @@ TEST(UITextField, CreateXamlElement) { // TODO: Switch to UIKit.Xaml projections when they're available. - Microsoft::WRL::ComPtr xamlElement(XamlCreateTextBox()); + Microsoft::WRL::ComPtr xamlElement; + XamlCreateTextBox(&xamlElement); ASSERT_TRUE(xamlElement); }