Skip to content

Commit 154d969

Browse files
authored
Clarify C++/WinRT namespace header file rules (#4182)
It is not true that including a namespace header automatically includes all parent namespace headers. Do not confuse the issue with declarations and implementations. Just say that you need to include the header for any class you use.
1 parent 7a4d53b commit 154d969

File tree

3 files changed

+12
-22
lines changed

3 files changed

+12
-22
lines changed

uwp/cpp-and-winrt-apis/consume-apis.md

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -52,31 +52,21 @@ In fact, that projected value is a proxy; it's essentially just a smart pointer
5252
When the `contosoUri` value falls out of scope, it destructs, and releases its reference to the default interface. If that reference is the last reference to the backing Windows Runtime **Windows.Foundation.Uri** object, the backing object destructs as well.
5353

5454
> [!TIP]
55-
> A *projected type* is a wrapper over a runtime class for purposes of consuming its APIs. A *projected interface* is a wrapper over a Windows Runtime interface.
55+
> A *projected type* is a wrapper over a Windows Runtime type for purposes of consuming its APIs. For example, a *projected interface* is a wrapper over a Windows Runtime interface.
5656
5757
## C++/WinRT projection headers
58-
To consume Windows namespace APIs from C++/WinRT, you include headers from the `%WindowsSdkDir%Include<WindowsTargetPlatformVersion>\cppwinrt\winrt` folder. It's common for a type in a subordinate namespace to reference types in its immediate parent namespace. Consequently, each C++/WinRT projection header automatically includes its parent namespace header file; so you don't *need* to explicitly include it. Although, if you do, there will be no error.
58+
To consume Windows namespace APIs from C++/WinRT, you include headers from the `%WindowsSdkDir%Include<WindowsTargetPlatformVersion>\cppwinrt\winrt` folder. You must include the headers corresponding to each namespace you use.
5959

60-
For example, for the [**Windows::Security::Cryptography::Certificates**](/uwp/api/windows.security.cryptography.certificates) namespace, the equivalent C++/WinRT type definitions reside in `winrt/Windows.Security.Cryptography.Certificates.h`. Types in **Windows::Security::Cryptography::Certificates** require types in the parent **Windows::Security::Cryptography** namespace; and types in that namespace could require types in its own parent, **Windows::Security**.
60+
For example, for the [**Windows::Security::Cryptography::Certificates**](/uwp/api/windows.security.cryptography.certificates) namespace, the equivalent C++/WinRT type definitions reside in `winrt/Windows.Security.Cryptography.Certificates.h`. Including that header gives you access to all the types in the [**Windows::Security::Cryptography::Certificates**](/uwp/api/windows.security.cryptography.certificates) namespace.
6161

62-
So, when you include `winrt/Windows.Security.Cryptography.Certificates.h`, that file in turn includes `winrt/Windows.Security.Cryptography.h`; and `winrt/Windows.Security.Cryptography.h` includes `winrt/Windows.Security.h`. That's where the trail stops, since there is no `winrt/Windows.h`. This transitive inclusion process stops at the second-level namespace.
62+
Sometimes, one namespace header will include portions of related namespace headers, but you shouldn't rely on this implementation detail. Explicitly include the headers for the namespaces you use.
6363

64-
This process transitively includes the header files that provide the necessary *declarations* and *implementations* for the classes defined in parent namespaces.
64+
For example, the [**Certificate::GetCertificateBlob**](/uwp/api/windows.security.cryptography.certificates.certificate.getcertificateblob) method returns an
65+
[**Windows::Storage::Streams::IBuffer**](/uwp/api/windows.storage.streams.ibuffer) interface.
66+
Before calling the [**Certificate::GetCertificateBlob**](/uwp/api/windows.security.cryptography.certificates.certificate.getcertificateblob) method,
67+
you must include the `winrt/Windows.Storage.Streams.h` namespace header file to ensure that you can receive and operate on the returned [**Windows::Storage::Streams::IBuffer**](/uwp/api/windows.storage.streams.ibuffer).
6568

66-
A member of a type in one namespace can reference one or more types in other, unrelated, namespaces. In order for the compiler to compile these member definitions successfully, the compiler needs to see the type declarations for the closure of all these types. Consequently, each C++/WinRT projection header includes the namespace headers it needs to *declare* any dependent types. Unlike for parent namespaces, this process does *not* pull in the *implementations* for referenced types.
67-
68-
> [!IMPORTANT]
69-
> When you want to actually *use* a type (instantiate, call methods, etc.) declared in an unrelated namespace, you must include the appropriate namespace header file for that type. Only *declarations*, not *implementations*, are automatically included.
70-
71-
For example, if you only include `winrt/Windows.Security.Cryptography.Certificates.h`, then that causes declarations to be pulled in from these namespaces (and so on, transitively).
72-
73-
- Windows.Foundation
74-
- Windows.Foundation.Collections
75-
- Windows.Networking
76-
- Windows.Storage.Streams
77-
- Windows.Security.Cryptography
78-
79-
In other words, some APIs are forward-declared in a header that you've included. But their definitions are in a header that you haven't yet included. So, if you then call [**Windows::Foundation::Uri::RawUri**](/uwp/api/windows.foundation.uri.rawuri), then you'll receive a linker error indicating that the member is undefined. The solution is to explicitly `#include <winrt/Windows.Foundation.h>`. In general, when you see a linker error such as this, include the header named for the API's namespace, and rebuild.
69+
Forgetting to include the required namespace headers before using types in that namespace is a common source of build errors.
8070

8171
## Accessing members via the object, via an interface, or via the ABI
8272
With the C++/WinRT projection, the runtime representation of a Windows Runtime class is no more than the underlying ABI interfaces. But, for your convenience, you can code against classes in the way that their author intended. For example, you can call the **ToString** method of a [**Uri**](/uwp/api/windows.foundation.uri) as if that were a method of the class (in fact, under the covers, it's a method on the separate **IStringable** interface).

uwp/cpp-and-winrt-apis/faq.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ sections:
7474
- question: |
7575
Why is the compiler giving me a "C3779: consume_Something: function that returns 'auto' cannot be used before it is defined" error?
7676
answer: |
77-
You're consuming an API from the Windows namespace headers for the C++/WinRT projection (in the **winrt** namespace), and the API is forward-declared in a header that you've included, but its definition is in a header that you haven't yet included. Include the header named for the API's namespace, and rebuild. For more info, see [C++/WinRT projection headers](consume-apis.md#cwinrt-projection-headers).
77+
You're using a Windows Runtime object without having first included the corresponding namespace header file. Include the header named for the API's namespace, and rebuild. For more info, see [C++/WinRT projection headers](consume-apis.md#cwinrt-projection-headers).
7878
7979
- question: |
8080
Why is the linker giving me a "LNK2019: Unresolved external symbol" error?
@@ -87,7 +87,7 @@ sections:
8787
8888
It's important that you resolve any linker errors that you can by linking **WindowsApp.lib** instead of an alternative static-link library, otherwise your application won't pass the [Windows App Certification Kit](../debug-test-perf/windows-app-certification-kit.md) tests used by Visual Studio and by the Microsoft Store to validate submissions (meaning that it consequently won't be possible for your application to be successfully ingested into the Microsoft Store).
8989
90-
**Relatively rare**: if the unresolved symbol is an API from the Windows namespace headers for the C++/WinRT projection (in the **winrt** namespace), then the API is forward-declared in a header that you've included, but its definition is in a header that you haven't yet included. Include the header named for the API's namespace, and rebuild. For more info, see [C++/WinRT projection headers](consume-apis.md#cwinrt-projection-headers).
90+
If the unresolved symbol is a constructor, you may have forgotten to include the namespace header file for the class being constructed. Include the header named for the class's namespace, and rebuild. For more info, see [C++/WinRT projection headers](consume-apis.md#cwinrt-projection-headers).
9191
9292
- question: |
9393
Why am I getting a "class not registered" exception?

uwp/cpp-and-winrt-apis/get-started.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ The headers contain Windows APIs projected into C++/WinRT. In other words, for e
7575
> [!IMPORTANT]
7676
> Whenever you want to use a type from a Windows namespaces, you must `#include` the corresponding C++/WinRT Windows namespace header file, as shown above. The *corresponding* header is the one with the same name as the type's namespace. For example, to use the C++/WinRT projection for the [**Windows::Foundation::Collections::PropertySet**](/uwp/api/windows.foundation.collections.propertyset) runtime class, include the `winrt/Windows.Foundation.Collections.h` header.
7777
>
78-
> It's usual for a C++/WinRT projection header to automatically include its parent namespace header file. So, for example, `winrt/Windows.Foundation.Collections.h` includes `winrt/Windows.Foundation.h`. But you shouldn't rely on this behavior, since it's an implementation detail that changes over time. You must explicitly include any headers that you need.
78+
> It is common for a C++/WinRT projection header to automatically include related namespace header files. For example, `winrt/Windows.Foundation.Collections.h` includes `winrt/Windows.Foundation.h`. But you shouldn't rely on this behavior, since it's an implementation detail that changes over time. You must explicitly include any headers that you need.
7979
8080
```cppwinrt
8181
using namespace winrt;

0 commit comments

Comments
 (0)