如何:在通用 Windows 平台应用中使用现有 C++ 代码How to: Use Existing C++ Code in a Universal Windows Platform App

要在 UWP 环境中运行桌面程序,最简单的方法或许是使用桌面桥技术。Perhaps the easiest way to get your desktop program running in the UWP environment is to use the Desktop Bridge technologies. 这包括 Desktop App Converter,它能将现有应用程序打包为 UWP 应用,而无需更改代码。These include the Desktop App Converter, which will package your existing application as a UWP app with no code changes required. 有关详细信息,请参阅使用桌面桥将桌面应用引入通用 Windows 平台 (UWP)For more information, see Bring your desktop app to the Universal Windows Platform (UWP) with the Desktop Bridge.

本主题的剩余部分讨论如何将 C++ 库(DLL 和静态库)移植到通用 Windows 平台 (UWP)。The rest of this topic discusses how to port C++ libraries (DLLs and static libraries) to the Universal Windows Platform (UWP). 可能需要执行此操作,以便将核心 C++ 逻辑用于多个 UWP 应用。You might want to do this so that your core C++ logic can be used with multiple UWP apps.

UWP 应用在受保护的环境中运行,结果,很多可能危及平台安全的 Win32、COM 和 CRT API 调用都不被允许。UWP Apps run in a protected environment, and as a result, many Win32, COM, and CRT API calls that might compromise the security of the platform are not allowed. 如果使用 /ZW 选项,则编译器可以检测此类调用并生成错误。The compiler can detect such calls and generate an error, if the /ZW option is used. 你可以使用应用程序上的应用认证工具包检测调用禁止的 API 的代码。You can use the App Certification Kit on your application to detect code that calls forbidden APIs. 请参阅使用应用认证工具包See Using the App Certification Kit.

如果源代码可用于库,则你可能能够消除禁止的 API 调用。If source code is available for the library, you might be able to eliminate the forbidden API calls. 有关包括允许或禁止的 API 列表的详细信息,请参阅用于 Windows 运行时应用和通用 Windows 平台 (UWP) 应用的 Win32 和 COM,以及通用 Windows 平台应用中不支持的 CRT 函数For details including a list of APIs that are allowed or forbidden, see Win32 and COM for Windows Runtime Apps and Universal Windows platform (UWP) Apps and CRT functions not supported in Universal Windows Platform apps. 可通过 UWP 应用中的 Windows API 替代项,找到一些替代项。Some alternatives can be found at Alternatives to Windows APIs in UWP apps.

如果只是尝试从通用 Windows 项目添加引用到经典桌面库,你将得到一条显示库不兼容的错误消息。If you just try to add a reference from a Universal Windows Project to a classic desktop library, you get an error message that says the library is not compatible. 如果是静态库,你只需通过将库(.lib 文件)添加到链接器输入就可以链接到库,类似在经典 Win32 应用程序中的操作。In the case of a static library, you can link to your library simply by adding the library (.lib file) to your linker input, just as you would in a classic Win32 application. 对于仅二进制可用的库,这是唯一的选项。For libraries where only a binary is available, this is the only option. 静态库链接到应用的可执行文件中,但在 UWP 应用中使用的 Win32 DLL 必须通过将其包括在项目中并标记为“内容”来打包到应用中。A static library is linked into your app's executable, but a Win32 DLL that you consume in a UWP app must be packaged into the app by including it in the project and marking it as Content. 若要在 UWP 应用中加载 Win32 DLL,还需要调用 LoadPackagedLibrary,而不是 LoadLibrary 或 LoadLibraryEx。To load a Win32 DLL in a UWP app, you also have to call LoadPackagedLibrary instead of LoadLibrary or LoadLibraryEx.

如果你有 DLL 或静态库的源代码,则可以使用 /ZW 重新编译为 UWP 项目。If you have source code for the DLL or static library, you can recompile with /ZW as a UWP project. 如果要这样做,则可以使用解决方案资源管理器添加引用,并在 C++ UWP 应用中使用它。If you do that, you can add a reference using the Solution Explorer, and use it in C++ UWP apps. 在 DLL 的情况下,与导出库链接。In the case of a DLL, you link with the export library.

若要向其他语言中的调用方公开功能,则可以将库转换为 Windows 运行时组件。To expose functionality to callers in other languages, you can convert the library into a Windows Runtime Component. Windows 运行时组件与普通的 DLL 的不同之处在于它们包括 .winmd 文件格式的元数据,这些元数据以 .NET 和 JavaScript 的使用者需要的方式介绍内容。Windows Runtime Components differ from ordinary DLLs in that they include metadata in the form of .winmd files which describe the contents in a way that .NET and JavaScript consumers require. 若要向其他语言公开 API 元素,你可以添加 C++/CX 构造(如 ref 类)并将其设置为公共,或使用 Windows 运行时 C++ 模板库 (WRL)To expose API elements to other languages, you can add C++/CX constructs, such as ref classes, and make them public, or use the Windows Runtime C++ Template Library (WRL). 在 Windows 10 以及更高版本中,可使用 C++/WinRT 库,而不是 C++/CX。In Windows 10 and later, you can use the C++/WinRT library instead of C++/CX.

前面的讨论不适用于 COM 组件案例,COM 组件必须以不同方式处理。The preceding discussion doesn't apply to the case of COM components, which must be handled differently. 如果在 EXE 或 DLL 中具有 COM 服务器,只要将其作为免注册 COM 组件打包,将其作为内容文件添加到你的项目,并使用 CoCreateInstanceFromApp 将其实例化,就可以在通用 Windows 项目中使用它。If you have a COM server in an EXE or DLL, you can use it in a Universal Windows Project as long as you package it as a registration-free COM component, add it to your project as a Content file, and instantiate it using CoCreateInstanceFromApp. 请参阅在 Windows 应用商店 C++ 项目中使用 Free-COM DLLSee Using Free-COM DLL in Windows Store C++ Project.

如果想要将现有 COM 库移植到 UWP,可通过使用 Windows 运行时 C++ 模板库 (WRL) 将其转换为 Windows 运行时组件。If you have an existing COM library that you want to port to the UWP, you might be able to convert it into a Windows Runtime Component by using the Windows Runtime C++ Template Library (WRL). WRL 不支持 ATL 和 OLE的所有功能,因此这种端口是否可行取决于 COM 代码多少,取决于你的组件需要 COM、ATL 以及 OLE 的哪些功能。The WRL does not support all the features of ATL and OLE, so whether such a port is feasible depends on how much your COM code depends on what features of COM, ATL, and OLE your component requires.

这些是你可以在 UWP 项目中使用现有的 C++ 代码的各种方法。These are the various ways that you can use existing C++ code in UWP projects. 某些方法不需要在组件扩展 (C++/CX) 启用(即,使用 /ZW 选项)的情况下对代码重新编译,而某些方法需要。因此如果你需要在标准 C++ 中保存代码,或者为某些代码保留经典 Win32 编译环境,你可以进行重新编译并选择相应的体系结构。Some ways do not require code to be recompiled with the component extensions (C++/CX) enabled (that is, with the /ZW option), and some do, so if you need to keep code in standard C++, or preserve a classic Win32 compilation environment for some code, you can do so, with appropriate architecture choices. 例如,所有包含 UWP 用户界面的代码和要向 C#、Visual Basic 和 JavaScript 调用方公开的类型都应存在于 Windows 应用项目和 Windows 运行时组件项目中。For example, all your code that contains UWP UI and types that are to be exposed to C#, Visual Basic, and JavaScript callers should be in Windows App projects and Windows Runtime Component projects. 仅在 C++(包括 C++/CX)代码中需要使用的代码可以存在于使用 /WX 选项编译的项目中或标准 C++ 项目中。Code that needs to be consumed only in C++ (including C++/CX) code can either be in a project that compiles with the /WX option or a standard C++ project. 仅当仅二进制代码不使用禁止的 API 时,可通过将其作为静态库链接,或作为内容与应用一起打包并在 DLL 中加载来使用。Binary-only code can be used by linking it in as a static library, or packaged with the app as content and loaded in a DLL only if it doesn't use forbidden APIs.

无论选择哪种开发方案,都应注意可以在代码中使用一些宏定义,以便可以在经典桌面 Win32 和 UWP 下有条件地编译代码。Regardless of which of these development scenarios you choose, you should be aware of a number of macro definitions that you can use in your code so that you can compile code conditionally under both classic desktop Win32 and UWP.


这些语句分别适用于 UWP 应用、Windows Phone 应用商店应用、都适用或都不适用(仅针对经典 Win32 桌面)。These statements respectively apply to UWP apps, Windows Phone Store apps, both, or neither (classic Win32 desktop only). 这些宏仅在 Windows SDK 8.1 及更高版本中才可用,因此如果你的代码需要使用早期版本的 Windows SDK 或除 Windows 以外的其他平台进行编译,则还应考虑未定义它们中任何一个这种情况。These macros are only available in Windows SDK 8.1 and later, so if your code needs to compile with earlier versions of the Windows SDK or for other platforms besides Windows, then you should also consider the case that none of them are defined.

本主题包含以下过程。This topic contains the following procedures.

  1. 在 UWP 应用中使用 Win32 DLLUsing a Win32 DLL in a UWP App

  2. 在 UWP 应用中使用本机 C++ 静态库Using a native C++ static library in a UWP App

  3. 将 C++ 库移植到 Windows 运行时组件Porting a C++ Library to a Windows Runtime Component

在 UWP 应用中使用 Win32 DLLUsing a Win32 DLL in a UWP App

为了获得更好的安全性和可靠性,通用 Windows 应用在受限的运行时环境中运行,因此不能像在经典 Windows 桌面应用程序中那样使用任何本机 DLL。For better security and reliability, Universal Windows Apps run in a restricted runtime environment, so you can't just use any native DLL the way you would in a classic Windows desktop application. 如果你有 DLL 的源代码,则可以移植此代码,以便使其在 UWP 上运行。If you have source code for a DLL, you can port the code so that it runs on the UWP. 你首先更改几个项目设置和项目文件元数据,以将此项目标识为 UWP 项目。You start by changing a few project settings and project file metadata to identify the project as a UWP project. 你需要使用 /ZW 选项编译库代码,从而启用 C++/CX。You need to compile the library code using the /ZW option, which enables C++/CX. 由于与该环境相关的控制更严格,在 UWP 应用中,某些 API 调用是不被允许的。Certain API calls are not allowed in UWP apps due to stricter controls associated with that environment. 请参阅适用于 Windows 运行时应用和通用 Windows 平台 (UWP) 应用的 Win32 和 COMSee Win32 and COM for Windows Runtime apps and Universal Windows Platform (UWP) apps.

以下过程应用于该情况:你的本机 DLL 使用 __declspec(dllexport) 公开函数。The following procedure applies to the case where you have a native DLL that exposes functions using __declspec(dllexport).

若要在无需创建新项目的情况下将本机 DLL 移植到 UWPTo port a native DLL to the UWP without creating a new project

  1. 如果你的本机 DLL 使用 __declspec(dllexport) 导出函数,则可以通过将 DLL 重新编译为 UWP 项目,从 UWP 应用中调用这些函数。If you have a native DLL that exports functions by using __declspec(dllexport), you can call those functions from a UWP app by recompiling the DLL as a UWP project. 例如,假设我们有一个 DLL,它使用类似于以下标头文件的代码,可导出几个类及其方法:For example, suppose we have a DLL that exports a couple of classes and their methods, with code like the following header file:

    // giraffe.h  
    #pragma once  
    #ifdef _DLL  
    #define GIRAFFE_API __declspec(dllexport)  
    #define GIRAFFE_API   
    GIRAFFE_API int giraffeFunction();  
    class Giraffe  
        int id;  
            Giraffe(int id_in);  
        friend class GiraffeFactory;  
        GIRAFFE_API int GetID();  
    class GiraffeFactory  
        static int nextID;  
        GIRAFFE_API GiraffeFactory();  
        GIRAFFE_API static int GetNextID();  
        GIRAFFE_API static Giraffe* Create();  

    以下代码文件:And the following code file:

    // giraffe.cpp  
    #include "stdafx.h"  
    #include "giraffe.h"  
    Giraffe::Giraffe(int id_in) : id(id_in)  
    int Giraffe::GetID()  
      return id;  
    int GiraffeFactory::nextID = 0;  
        nextID = 0;  
    int GiraffeFactory::GetNextID()  
        return nextID;  
    Giraffe* GiraffeFactory::Create()  
        return new Giraffe(nextID++);  
    int giraffeFunction();  

    项目(stdafx.h、dllmain.cpp)中的其他所有内容都属于标准 Win32 项目模板。Everything else in the project (stdafx.h, dllmain.cpp) is part of the standard Win32 project template. 如果想要遵循这些步骤,但又不想将自己的 DLL 用于这些步骤,请尝试创建 Win32 项目,在项目向导中选择 DLL,然后添加标头文件 giraffe.h 和代码文件 giraffe.cpp,并在此步骤中,将代码中的内容复制到相应的文件中。If you want to follow along, but don't want to use your own DLL yet with these steps, try creating a Win32 project, select DLL in the project wizard, and then add a header file giraffe.h and code file giraffe.cpp, and copy the contents from the code in this step into the appropriate files.

    该代码将在定义 _DLL 时(即,当项目生成为 DLL 时),定义解析为 __declspec(dllexport) 的宏 GIRAFFE_API。The code defines the macro GIRAFFE_API which resolves to __declspec(dllexport) when _DLL is defined (that is, when the project is built as a DLL).

  2. 打开 DLL 项目中的“项目属性”,并将“配置”设置为“所有配置”。Open the Project Properties for the DLL project, and set the Configuration to All Configurations.

  3. 在“项目属性”中,在“C/C++”、“常规”选项卡上,将“使用 Windows 运行时扩展”设置为“是 (/ZW)”。In the Project Properties, under C/C++, General tab, set Consume Windows Runtime Extension to Yes (/ZW). 这将启用组件扩展 (C++/CX)。This enables component extensions (C++/CX).

  4. 在“解决方案资源管理器”中,选择项目节点,打开快捷菜单,然后选择“卸载项目”。In Solution Explorer, select the project node, open the shortcut menu and choose Unload Project. 然后,在卸载的项目节点上打开快捷菜单,然后选择编辑项目文件。Then, open the shortcut menu on the unloaded project node, and choose to edit the project file. 找到 WindowsTargetPlatformVersion 元素并将其替换为以下元素。Locate the WindowsTargetPlatformVersion element and replace it with the following elements.

    <ApplicationType>Windows Store</ApplicationType>  

    关闭 .vcxproj 文件,再次打开快捷菜单,然后选择“重新加载项目”。Close the .vcxproj file, open the shortcut menu again and choose Reload Project.

    现在,解决方案资源管理器会将该项目标识为通用 Windows 项目。Solution Explorer now identifies the project as a Universal Windows project.

  5. 请确保预编译的头文件的名称正确。Make sure your precompiled header file name is correct. 在“预编译标头”部分中,将预编译头文件从 pch.h 更改为 stdafx.h。In the Precompiled Headers section, change Precompiled Header File from pch.h to stdafx.h. 如果没有这样操作,将出现以下错误。If you don't do this, you see the following error.

    error C2857: '#include' statement specified with the /Ycpch.h command-line option was not found in the source file  

    问题在于通用 Windows 项目对预编译标头文件使用不同的命名约定。The issue is that the Universal Windows projects use a different naming convention for the precompiled header file.

  6. 生成项目。Build the project. 可能会收到一些有关不兼容的命令行选项的错误。You might get some errors about incompatible command line options. 例如,频繁使用的选项“启用最小重新生成 (/Gm)”在许多 C++ 项目中默认进行设置,并且与 /ZW 不兼容。For example, the frequently used option Enable Minimal Rebuild (/Gm) is set by default in many C++ projects, and is incompatible with /ZW.

    当为通用 Windows 平台编译时,某些功能不可用。Some functions are not available when you compile for the Universal Windows Platform. 将看到有关任何问题的编译器错误。You will see compiler errors about any problems. 解决这些问题,直到有一个干净的生成。Address these until you have a clean build.

  7. 若要在相同的解决方案中的 UWP 应用中使用该 DLL,请打开 UWP 项目节点的快捷菜单,然后选择“添加、引用”。To use the DLL in a UWP app in the same solution, open the shortcut menu for the UWP project node, and choose Add, Reference.

    在“项目、解决方案”下,选择 DLL 项目旁边的复选框,然后选择“确定”按钮。Under Projects, Solution, select the checkbox next to the DLL project, and choose the OK button.

  8. 将库的标头文件包含在 UWP 应用的 pch.h 文件中。Include the library's header file(s) in your UWP app's pch.h file.

    #include "..\MyNativeDLL\giraffe.h"  
  9. 照常将代码添加到 UWP 项目中,以从 DLL 中调用函数并创建类型。Add code as usual in the UWP project to invoke functions and create types from the DLL.

        GiraffeFactory gf;  
        Giraffe* g = gf.Create();  
        int id = g->GetID();  

在 UWP 应用中使用本机 C++ 静态库Using a native C++ static library in a UWP App

你可以在 UWP 项目中使用本机 C++ 静态库,但有一些限制和局限需要注意。You can use a native C++ static library in a UWP project, but there are some restrictions and limitations to be aware of. 请首先阅读关于 C++/CX 中静态库的此主题Start by reading this topic about static libraries in C++/CX. 你可以从 UWP 应用访问静态库中的本机代码,但不建议在此类静态库中创建公共 ref 类型。You can access the native code in your static library from your UWP app, but it's not recommended to create public ref types in such a static library. 如果使用 /ZW 选项编译静态库,则管理员(实际是经过伪装的链接器)会发出警告:If you compile a static library with the /ZW option, the librarian (actually the linker in disguise) warns:

LNK4264: archiving object file compiled with /ZW into a static library; note that when authoring Windows Runtime types it is not recommended to link with a static library that contains Windows Runtime metadata  

但是,你可以无需使用 /ZW 重新编译 UWP 中的静态库,便可使用该静态库。However, you can use a static library in a UWP without recompiling it with /ZW. 你将无法声明任何 ref 类型或使用 C++/CX 构造,但如果你的目的仅仅是使用本机代码的库,则可以通过执行以下步骤来执行此操作。You won't be able to declare any ref types or use C++/CX constructs, but if your purpose is to simply use library of native code, then you can do so by following these steps.

若要在 UWP 项目中使用本机 C++ 静态库To use a native C++ static library in a UWP project

  1. 在 UWP 项目的项目属性中,在“链接器”部分,在输入属性中将路径添加到库。In the project properties for the UWP project, in the Linker section, add the path to the library in the Input property. 例如,对于将其输出放置在 SolutionFolder\Debug\MyNativeLibrary\MyNativeLibrary.lib 中的项目中的库,则添加相对路径 Debug\MyNativeLibrary\MyNativeLibrary.libFor example, for a library in the project that places its output in SolutionFolder\Debug\MyNativeLibrary\MyNativeLibrary.lib, add the relative path Debug\MyNativeLibrary\MyNativeLibrary.lib.

  2. 添加一个 include 语句以对 UWP 项目中的 pch.h 引用头文件,并开始添加使用库的代码。Add an include statement to reference the header file to your pch.h in the UWP project and start adding code that uses the library.

    #include "..\MyNativeLibrary\giraffe.h"  

    不要在“解决方案资源管理器”的“引用”节点中添加引用 。Do not add a reference in the References node in Solution Explorer. 该机制仅适用于 Windows 运行时组件。That mechanism only works for Windows Runtime Components.

将 C++ 库移植到 Windows 运行时组件Porting a C++ Library to a Windows Runtime Component

如果你想要从 UWP 应用使用静态库中的本机 API,并且你具有本机库的源代码,则你可以将代码移植到 Windows 运行时组件。If you want to consume native APIs in a static library from a UWP app, and you have the source code for the native library, you can port the code to a Windows Runtime Component. 它将不再是静态库,而将是 DLL。It won't be a static library anymore, it will be a DLL. 你可以在任何 C++ UWP 应用中使用它,但与静态库不同,你可以无论何种语言,都能够添加 ref 类型和可用于 UWP 应用代码中的客户端的其他 C++/CX 构造。You can use it in any C++ UWP app, but unlike the case of static library, you can add ref types and other C++/CX constructs which are available to clients in any UWP app code, regardless of language. 因此,你可以从 C#、Visual Basic 或 JavaScript 来访问这些类型。Therefore, you can access these types from C#, Visual Basic, or JavaScript. 基本过程是创建 Windows 运行时组件项目,将静态库的代码复制到其中,并解决将代码从标准的 C++ 编译移至 /ZW 编译而引发的任何错误。The basic procedure is to create a Windows Runtime Component project, copy the code for your static library into it, and address any errors that arise from moving the code from a standard C++ compilation to a /ZW compilation.

若要将 C++ 库移植到 Windows 运行时组件To port a C++ library to a Windows Runtime Component

  1. 创建 Windows 运行时组件项目。Create a Windows Runtime Component project.

  2. 关闭该项目。Close the project.

  3. 在 Windows 文件资源管理器中,找到该项目。In the Windows File Explorer, locate the project. 默认情况下,Visual Studio 将使用“文档”文件夹中的“Visual Studio 2017”\“项目”文件夹。By default, Visual Studio uses the Visual Studio 2017\Projects folder in your Documents folder. 找到 C++ 库项目,该项目包含你想要移植的代码。Locate the C++ library project that contains the code you want to port. 从 C++ 库项目复制源文件(头文件、代码文件和包括在子目录中的任何其他资源),并将它们粘贴到项目文件夹,同时确保保留相同的文件夹结构。Copy the source files (header files, code files, and any other resources, including in subdirectories) from your C++ library project, and paste them into the project folder, making sure to preserve the same folder structure.

  4. 重新打开 Windows 运行时组件项目,并在“解决方案资源管理器”中打开项目节点的快捷菜单,然后选择“添加、现有项”。Reopen the Windows Runtime Component project, and open the shortcut menu for the project node in Solution Explorer, and choose Add, Existing Item.

  5. 从原始项目中选择要添加的所有文件,然后选择“确定”。Select all the files to add from your original project, and choose OK. 如果子文件夹需要,则重复。Repeat if necessary for subfolders.

  6. 你现在可能有一些重复代码。You might now have some duplicated code. 如果你有多个预编译的标头(假设 stdafx.h 和 pch.h),选择一个保留。If you have more than one precompiled header (say stdafx.h and pch.h), choose one to keep. 将任何所需的代码(比如 include 语句)复制到你要保留的标头中。Copy any required code, such as include statements, into the one you're keeping. 然后,删除另一个,并在“预编译标头”下的项目属性中,请确保头文件的名称正确。Then, delete the other, and in the project properties, under Precompiled Headers, make sure that the name of the header file is correct.

    如果更改了要用作预编译标头的文件,请确保预编译标头选项适用于每个文件。If you changed the file to use as the precompiled header, make sure that the precompiled header options are correct for each file. 依次选择每个 .cpp 文件,打开其属性窗口,并确保所有项都设置为“使用 (/Yu)”(所需的预编译标头除外,其应设置为“创建 (/Yc)”)。Select each .cpp file in turn, open its properties window, and make sure that all are set to Use (/Yu), except for the desired precompiled header, which should be set to Create (/Yc).

  7. 生成项目并解决任何错误。Build the project and resolve any errors. 这些错误可能由使用 /ZW 选项导致,或可能由新版本的 Windows SDK 导致,或者它们可能反映依赖项(例如,你的库依赖的头文件或旧项目和新项目之间的项目设置的差异)。These errors could be caused by using the /ZW option, or they could be caused by a new version of the Windows SDK, or they might reflect dependencies such as header files that your library depends on, or differences in project settings between your old project and the new one.

  8. 将公共 ref 类型添加到你的项目,或将普通类型转换为 ref 类型,以便于在想要从 UWP 应用调用的功能中公开入口点。Add public ref types to your project, or convert ordinary types to ref types, to expose entry points into the functionality you want to call from UWP apps.

  9. 通过从 UWP 应用项目添加对组件的引用来测试该组件,然后添加某些代码来调用你创建的公共 API。Test the component by adding a reference to it from a UWP app project, and add some code to call the public APIs you created.

请参阅See Also

移植到通用 Windows 平台Porting to the Universal Windows Platform