You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: windows-apps-src/cpp-and-winrt-apis/author-apis.md
+48-1Lines changed: 48 additions & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -22,6 +22,7 @@ In both cases, the type that implements your C++/WinRT APIs is called the *imple
22
22
> It's important to distinguish the concept of an implementation type from that of a projected type. The projected type is described in [Consume APIs with C++/WinRT](consume-apis.md).
23
23
24
24
## If you're *not* authoring a runtime class
25
+
25
26
The simplest scenario is where you're implementing a Windows Runtime interface for local consumption. You don't need a runtime class; just an ordinary C++ class. For example, you might be writing an app based around [**CoreApplication**](/uwp/api/windows.applicationmodel.core.coreapplication).
26
27
27
28
> [!NOTE]
@@ -118,6 +119,7 @@ int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int)
118
119
```
119
120
120
121
## If you're authoring a runtime class in a Windows Runtime Component
122
+
121
123
If your type is packaged in a Windows Runtime Component for consumption from an application, then it needs to be a runtime class.
122
124
123
125
> [!TIP]
@@ -174,6 +176,7 @@ So, in this scenario, at the root of the inheritance hierarchy is the [**winrt::
174
176
For more details, code, and a walkthrough of authoring APIs in a Windows Runtime component, see [Author events in C++/WinRT](author-events.md#create-a-core-app-bankaccountcoreapp-to-test-the-windows-runtime-component).
175
177
176
178
## If you're authoring a runtime class to be referenced in your XAML UI
179
+
177
180
If your type is referenced by your XAML UI, then it needs to be a runtime class, even though it's in the same project as the XAML. Although they are typically activated across executable boundaries, a runtime class can instead be used within the compilation unit that implements it.
178
181
179
182
In this scenario, you're both authoring *and* consuming the APIs. The procedure for implementing your runtime class is essentially the same as that for a Windows Runtime Component. So, see the previous section—[If you're authoring a runtime class in a Windows Runtime Component](#if-youre-authoring-a-runtime-class-in-a-windows-runtime-component). The only detail that differs is that, from the IDL, the C++/WinRT toolchain generates not only an implementation type but also a projected type. It's important to appreciate that saying only "**MyRuntimeClass**" in this scenario may be ambiguous; there are several entities with that name, of different kinds.
@@ -204,6 +207,7 @@ For an example walkthrough of implementing the **INotifyPropertyChanged** interf
204
207
The procedure for consuming your runtime class in this scenario is described in [Consume APIs with C++/WinRT](consume-apis.md#if-the-api-is-implemented-in-the-consuming-project).
205
208
206
209
## Runtime class constructors
210
+
207
211
Here are some points to take away from the listings we've seen above.
208
212
209
213
- Each constructor you declare in your IDL causes a constructor to be generated on both your implementation type and on your projected type. IDL-declared constructors are used to consume the runtime class from *a different* compilation unit.
@@ -230,6 +234,7 @@ Here are some examples.
230
234
The last two are very useful when you're writing an asynchronous event handler.
231
235
232
236
## Instantiating and returning implementation types and interfaces
237
+
233
238
For this section, let's take as an example an implementation type named **MyType**, which implements the [**IStringable**](/uwp/api/windows.foundation.istringable) and [**IClosable**](/uwp/api/windows.foundation.iclosable) interfaces.
234
239
235
240
You can derive **MyType** directly from [**winrt::implements**](/uwp/cpp-ref-for-winrt/implements) (it's not a runtime class).
@@ -260,7 +265,7 @@ namespace MyProject
260
265
}
261
266
```
262
267
263
-
To go from **MyType** to an **IStringable** or **IClosable** object that you can use or return as part of your projection, you can call the [**winrt::make**](/uwp/cpp-ref-for-winrt/make) function template. **make** returns the implementation type's default interface.
268
+
To go from **MyType** to an **IStringable** or **IClosable** object that you can use or return as part of your projection, you should call the [**winrt::make**](/uwp/cpp-ref-for-winrt/make) function template. **make** returns the implementation type's default interface.
## Deriving from a type that has a non-default constructor
354
+
349
355
[**ToggleButtonAutomationPeer::ToggleButtonAutomationPeer(ToggleButton)**](/uwp/api/windows.ui.xaml.automation.peers.togglebuttonautomationpeer.-ctor#Windows_UI_Xaml_Automation_Peers_ToggleButtonAutomationPeer__ctor_Windows_UI_Xaml_Controls_Primitives_ToggleButton_) is an example of a non-default constructor. There's no default constructor so, to construct a **ToggleButtonAutomationPeer**, you need to pass an *owner*. Consequently, if you derive from **ToggleButtonAutomationPeer**, then you need to provide a constructor that takes an *owner* and passes it to the base. Let's see what that looks like in practice.
350
356
351
357
```idl
@@ -403,6 +409,47 @@ The base class constructor expects a **ToggleButton**. And **MySpecializedToggle
403
409
404
410
Until you make the edit described above (to pass that constructor parameter on to the base class), the compiler will flag your constructor and point out that there's no appropriate default constructor available on a type called (in this case) **MySpecializedToggleButtonAutomationPeer_base<MySpecializedToggleButtonAutomationPeer>**. That's actually the base class of the bass class of your implementation type.
405
411
412
+
## Namespaces: projected types, implementation types, and factories
413
+
414
+
As you've seen previously in this topic, a C++/WinRT runtime class exists in the form of more than one C++ class in more than one namespace. So, the name **MyRuntimeClass** has one meaning in the **winrt::MyProject** namespace, and a different meaning in the **winrt::MyProject::implementation** namespace. Be aware of which namespace you currently have in context, and then use namespace prefixes if you need a name from a different namespace. Let's look more closely at the namespaces in question.
415
+
416
+
-**winrt::MyProject**. This namespace contains projected types. An object of a projected type is a proxy; it's essentially a smart pointer to a backing object, where that backing object might be implemented here in your project, or it might be implemented in another compilation unit.
417
+
-**winrt::MyProject::implementation**. This namespace contains implementation types. An object of an implementation type is not a pointer; it's a value—a full C++ stack object. Don't construct an implementation type directly; instead, call [**winrt::make**](/uwp/cpp-ref-for-winrt/make), passing your implementation type as the template parameter. We've shown examples of **winrt::make** in action previously in this topic, and there's another example in [XAML controls; bind to a C++/WinRT property](binding-property.md#add-a-property-of-type-bookstoreviewmodel-to-mainpage).
418
+
-**winrt::MyProject::factory_implementation**. This namespace contains factories. An object in this namespace supports [**IActivationFactory**](/windows/win32/api/activation/nn-activation-iactivationfactory).
419
+
420
+
This table shows the minimum namespace qualification you need to use in different contexts.
421
+
422
+
|The namespace that's in context|To specify the projected type|To specify the projected type|
> When you want to return a projected type from your implementation, be careful not to instantiate the implementation type by writing `MyRuntimeClass myRuntimeClass;`. The correct techniques and code for that scenario are shown previously in this topic in the section [Instantiating and returning implementation types and interfaces](#instantiating-and-returning-implementation-types-and-interfaces).
429
+
>
430
+
> The problem with `MyRuntimeClass myRuntimeClass;` in that scenario is that it creates a **winrt::MyProject::implementation::MyRuntimeClass** object on the stack. That object (of implementation type) behaves like the projected type in some ways—you can invoke methods on it in the same way; and it even converts to a projected type. But the object destructs, as per normal C++ rules, when the scope exits. So, if you returned a projected type (a smart pointer) to that object, then that pointer is now dangling.
431
+
>
432
+
> This memory corruption type of bug is difficult to diagnose. So, for debug builds, a C++/WinRT assertion helps you catch this mistake, using a stack-detector. But coroutines are allocated on the heap, so you won't get help with this mistake if you make it inside a coroutine.
433
+
434
+
## Using projected types and implementation types with various C++/WinRT features
435
+
436
+
Here are various places where a C++/WinRT features expects a type, and what kind of type it expects (projected type, implementation type, or both).
437
+
438
+
|Feature|Accepts|Notes|
439
+
|-|-|-|
440
+
|`T` (representing a smart pointer)|Projected|See the caution in [Namespaces: projected types, implementation types, and factories](#namespaces-projected-types-implementation-types-and-factories) about using the implementation type by mistake.|
441
+
|`agile_ref<T>`|Both|If you use the implementation type, then the constructor argument must be `com_ptr<T>`.|
442
+
|`com_ptr<T>`|Implementation|Using the projected type generates the error: `'Release' is not a member of 'T'`.|
443
+
|`default_interface<T>`|Both|If you use the implementation type, then the first implemented interface is returned.|
444
+
|`get_self<T>`|Implementation|Using the projected type generates the error: `'_abi_TrustLevel': is not a member of 'T'`.|
445
+
|`guid_of<T>()`|Both|Returns the GUID of the default interface.|
446
+
|`IWinRTTemplateInterface<T>`<br>|Projected|Using the implementation type compiles, but it's a mistake—see the caution in [Namespaces: projected types, implementation types, and factories](#namespaces-projected-types-implementation-types-and-factories).|
447
+
|`make<T>`|Implementation|Using the projected type generates the error: `'implements_type': is not a member of any direct or indirect base class of 'T'`|
448
+
|`make_agile(T const&)`|Both|If you use the implementation type, then the argument must be `com_ptr<T>`.|
449
+
|`make_self<T>`|Implementation|Using the projected type generates the error: `'Release': is not a member of any direct or indirect base class of 'T'`|
450
+
|`name_of<T>`|Projected|If you use the implementation type, then you get the stringified GUID of the default interface.|
451
+
|`weak_ref<T>`|Both|If you use the implementation type, then the constructor argument must be `com_ptr<T>`.|
0 commit comments