GithubHelp home page GithubHelp logo

travisspomer / apicheck Goto Github PK

View Code? Open in Web Editor NEW
1.0 2.0 0.0 20 KB

Easy, high-performance checks for WinRT APIs from C++.

License: MIT License

C++ 100.00%
windows-runtime winrt winrt-uwp cpp cpp-library api

apicheck's Introduction

ApiCheck

Writing Windows Runtime (WinRT) code in C++ that needs to run on older, downlevel versions of Windows, while still taking advantage of new system APIs if present, is a pain. This library makes it easy to check for APIs in the supported fashion with high performance. I've used code in production apps that have shipped to millions of users that's based on this library.

Building and integrating

  1. Copy ApiCheck.cpp, ApiCheck.h, and ApiCheckCore.h into your project.
  2. (Optional) In ApiCheckCore.h, set RequiredVersion to the minimum version of Windows that your app supports.
  3. Use the ApiCheck:: functions accordingly.

This library is in standard C++ and requires no additional frameworks beyond the Windows SDK. Your project can use standard C++ (with WRL, for example), C++/CX, or C++/WinRT. As long as it links to the Windows Runtime and calls RoInitialize, it should work.

ApiCheck.cpp is only needed if you want the specific helper functions in that file. If you don't need those, delete ApiCheck.cpp and remove the corresponding function declarations from ApiCheck.h. Boom—header-only library!

Usage

Add the following to each of your source files that need it, or to your precompiled header:

#include "ApiCheck.h"

Checking for a Windows version

There are convenient helper functions for many versions of Windows:

if (ApiCheck::IsAtLeastRS3()) { /* ... */ }

Alternately, you can use this more general form:

if (ApiCheck::IsAtLeast<ApiCheck::WindowsVersion::RS3>()) { /* ... */ }

The supported values for WindowsVersion are in ApiCheckCore.h:

WindowsVersion means...
TH1 Threshold 1 = version 1507 = build 10240
TH2 Threshold 2 = version 1511 = build 10586
RS1 Redstone 1 = Anniversary Update = version 1607 = build 14393
RS2 Redstone 2 = Creators Update = version 1703 = build 15063 (or 15254 for final feature2 build of Windows 10 Mobile)
RS3 Redstone 3 = Fall Creators Update = version 1709 = build 16299
RS4 Redstone 4 = April 2018 Update = version 1803 = build 17134
RS5 Redstone 5 = October 2018 Update = version 1809 = build 17763
CY19H1 May 2019 Update = version 1903 = build 18362
CY20H1 May 2020 Update = version 2004 = build 19041
None default value

Hey, don't blame me for the absolute insanity of Windows version naming.

Checking for a specific type

Instead of calling Windows.Foundation.Metadata.ApiInformation.IsTypePresent directly, call ApiCheck::IsTypePresent. See ApiCheck.cpp for a few examples of this.

if (ApiCheck::IsTypePresent<RuntimeClass_Windows_UI_Xaml_Media_RevealBrush,
    ApiCheck::WindowsVersion::RS3>())
{
    /* ... */
}

IsTypePresent takes two type parameters:

  1. RuntimeClass: The RuntimeClass (full API name) of the API.
  2. IntroducedIn: Optionally, the version of Windows that the API was introduced in, if it's in the universal contract.

The example above checks to see if the RevealBrush type is available. But, if the user is running a version of Windows after RS3 (aka Fall Creators Update, aka Version 1709, aka build 16299), then it knows that that check can be skipped. (If the type is part of an extension SDK and not the universal contract, don't include IntroducedIn. That's the case for APIs that are available only on, say, Windows Phone or HoloLens, such as Windows.UI.ViewManagement.StatusBar, which is not present on any desktop version of Windows.)

Checking for a property, method, event, or enum value

ApiCheck also provides wrappers for IsPropertyPresent, IsMethodPresent, IsEventPresent, and IsEnumNamedValuePresent. These work the same as IsTypePresent except they take an additional type parameter.

extern const wchar_t PreviewKeyDown[] = L"PreviewKeyDown";

if (ApiCheck::IsPropertyPresent<RuntimeClass_Windows_UI_Xaml_UIElement,
    PreviewKeyDown,
    ApiCheck::WindowsVersion::RS3>())
{
    /* ... */
}

These wrappers take three type parameters:

  1. RuntimeClass: The RuntimeClass (full API name) of the type.
  2. Property / Method / Event / NamedValue : The member of the type to look for.
  3. IntroducedIn: Optionally, the version of Windows that the member was introduced in, if it's in the universal contract.

Why is it fast? (Why is it normally slow?)

The supported way to check for the existence of an API is to use the Windows.Foundation.Metadata.ApiInformation API. Under the hood, that requires looking up and instantiating the activation factory for IApiInformationStatics by name, and then calling the API, which does a string lookup of the API which requires loading metadata (.winmd) files.

This library:

  • Is faster to code for, since it's just simple standard C++ function calls that just "do the right thing"
  • Caches the activation factory for you
  • Caches API existence checks for you so that they're only performed once
  • Can often avoid checking for the API entirely, if:
    • The user is running a version of Windows that is guaranteed to always have the API
    • Your app's manifest dictates that the minimum version of Windows required to install the app already has the API

Under the hood, it uses magic statics and function templates. Each unique API checked adds about 83 bytes to your executable, and the cached checks only take about 1 μs on my machine. (In comparison, the small metadata file that Windows loads for an API check would easily be 500× that size or more.)


© 2021 Travis Spomer. MIT license.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.