次の方法で共有


方法: ユニバーサル Windows プラットフォーム アプリで既存の C++ コードを使用する

ユニバーサル Windows プラットフォーム (UWP) のプロジェクトで既存の C++ コードを使える方法は、いろいろあります。 コンポーネント拡張機能 (C++/CX) を有効にしてコードを再コンパイルする必要がない方法 (つまり、/ZW オプションを使用) やその必要がある方法があります。 コードを標準 C++ で保持するか、一部のコードではクラシック Win32 コンパイル環境を保持する必要がある場合があります。 適切なアーキテクチャの選択肢を使用して実行できます。 C#、Visual Basic、および JavaScript の呼び出し元に公開される UWP UI と型を含むすべてのコードについて考えます。 このコードは、Windows アプリ プロジェクトおよび Windows ランタイム コンポーネント プロジェクトに含まれる必要があります。 C++ (C++/CX を含む) から呼び出すだけのコードは、/ZW オプションを使用してコンパイルするプロジェクトまたは標準 C++ のプロジェクトに配置できます。 許可されていない API を使用しないバイナリ専用コードは、スタティック ライブラリとしてリンクすることで使用できます。 または、アプリをコンテンツとして使用してパッケージ化し、DLL に読み込むことができます。

UWP 環境でデスクトップ プログラムを実行できるようにする最も簡単な方法は、おそらく、デスクトップ ブリッジ テクノロジを使うことです。 この方法に含まれる Desktop App Converter は、既存のアプリケーションを UWP アプリとしてパッケージ化し、コードの変更は必要ありません。 詳細については、デスクトップ ブリッジに関するページをご覧ください。

この記事の残りの部分では、C++ ライブラリ (DLL とスタティック ライブラリ) をユニバーサル Windows プラットフォームに移植する方法を説明します。 C++ のコア ロジックを複数の UWP アプリで使用できるようにするには、コードを移植する必要があります。

UWP アプリは、保護された環境で実行されます。 その結果、プラットフォームのセキュリティを侵害する可能性がある Win32、COM、CRT API 呼び出しの多くは許可されません。 /ZW コンパイラ オプションは、そのような呼び出しを検出し、エラーを生成することができます。 アプリ認定キットをアプリケーションに対して使用して、許可されていない API を呼び出すコードを検出することができます。 詳細については、「Windows アプリ認定キット」をご覧ください。

ライブラリでソース コードを使用できる場合は、許可されていない API 呼び出しを排除してみてください。 許可されていない API の一覧については、「Win32 and COM APIs for UWP apps」 (UWP 用の Win32 API と COM API) と「ユニバーサル Windows プラットフォーム アプリでサポートされていない CRT 関数」をご覧ください。 UWP アプリでの Windows API の代替に関するページで、いくつかの代替を確認できます。

ユニバーサル Windows プロジェクトから従来のデスクトップ ライブラリへの参照を追加しようとすると、ライブラリに互換性がないことを示すエラー メッセージを受け取ります。 スタティック ライブラリの場合、従来の Win32 アプリケーションの場合と同様、ライブラリ (.lib ファイル) をリンカー入力に追加してライブラリにリンクできます。 バイナリ ライブラリのみを使用できる場合は、それが唯一のオプションです。 スタティック ライブラリは、アプリの実行可能ファイルにリンクされます。 ただし、UWP アプリで使用する Win32 DLL は、プロジェクトに含めてコンテンツとしてマークすることで、アプリにパッケージ化する必要があります。 UWP アプリで Win32 DLL を読み込むには、LoadLibraryLoadLibraryEx ではなく、LoadPackagedLibrary も呼び出す必要があります。

DLL またはスタティック ライブラリのソース コードがある場合は、/ZW コンパイラ オプションを使用して UWP プロジェクトとして再コンパイルできます。 次に、ソリューション エクスプローラーを使用して参照を追加し、その参照を C++ UWP アプリで使用することができます。 エクスポート ライブラリを使用して DLL をリンクします。

他の言語の呼び出し元に機能を公開するために、ライブラリを Windows ランタイム コンポーネントに変換することができます。 Windows ランタイム コンポーネントは、.NET および JavaScript のコンシューマーが必要とする方法でコンテンツを説明する .winmd ファイルの形式にメタデータが含まれているという点で通常の DLL とは異なります。 API 要素を他の言語に公開するには、ref クラスなどの C++/CX コンストラクトを追加し、それらをパブリックにできます。 Windows 10 以降では、C++/CX の代わりに C++/WinRT ライブラリ を使用することをお勧めします。

これまでの説明は、COM コンポーネントには当てはまりません。COM コンポーネントは、異なる方法で行う必要があります。 EXE または DLL に COM サーバーがある場合は、ユニバーサル Windows サーバー プロジェクトで使用できます。 これを、登録を必要としない COM コンポーネントとしてパッケージ化し、コンテンツ ファイルとしてプロジェクトに追加し、CoCreateInstanceFromApp を使用してインスタンス化します。 詳細については、「Using Free-COM DLL in Windows Store C++ Project」 (Windows ストア C++ プロジェクトでの Free-COM DLL の使用) をご覧ください。

既存の COM ライブラリを UWP に移植する場合は、それを Windows ランタイム コンポーネントに変換することもできます。 このようなポートには C++/WinRT ライブラリをお勧めしますが、Windows ランタイム C++ テンプレート ライブラリ (WRL) を使用することもできます。 WRL は非推奨とされており、ATL と OLE のすべての機能をサポートしていません。 このようなポートが実現可能かどうかは、コンポーネントに必要な COM、ATL、OLE の機能によって異なります。

どの開発シナリオを選択する場合でも、多くのマクロ定義に注意する必要があります。 これらのマクロをコードで使用して、クラシック デスクトップ Win32 と UWP の両方で条件付きでコードをコンパイルできます。

#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PC_APP)
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)

これらのステートメントは、それぞれ、UWP アプリ、Windows Phone ストア アプリ、両方のアプリ、どちらでもないアプリ (クラシック Win32 デスクトップのみ) の順に適用されます。 これらのマクロは、Windows SDK 8.1 以降でのみ使用できます。

この記事には、次のプロシージャが含まれています。

UWP アプリで Win32 の DLL を使用する

セキュリティと信頼性を向上するために、ユニバーサル Windows アプリは制限付きのランタイム環境で実行されます。 従来の Windows デスクトップ アプリケーションと同じ方法でネイティブ DLL を使用することはできません。 DLL のソース コードがある場合、コードが UWP 上で実行されるように、コードを移植することができます。 まず、いくつかのプロジェクト設定とプロジェクト ファイル メタデータを変更し、プロジェクトを UWP プロジェクトとして識別させます。 /ZW オプションを使用してライブラリ コードを再コンパイルします。これにより、C++/CX が使用可能になります。 特定の API 呼び出しは、環境と関連付けられているより厳密な制御のため、UWP アプリでは許可されていません。 詳細については、「Win32 and COM APIs for UWP apps」(UWP 用の Win32 API と COM API) をご覧ください。

__declspec(dllexport) を使用して関数をエクスポートするネイティブ DLL がある場合は、DLL を UWP プロジェクトとして再コンパイルすることで UWP アプリからこれらの関数を呼び出すことができます。 たとえば、いくつかのクラスとそのメソッドをエクスポートする Giraffe という名前の Win32 DLL プロジェクトがあり、次のヘッダー ファイルのようなコードを使用するとします。

// giraffe.h
// Define GIRAFFE_EXPORTS when building this DLL
#pragma once

#ifdef GIRAFFE_EXPORTS
#define GIRAFFE_API __declspec(dllexport)
#else
#define GIRAFFE_API
#endif

GIRAFFE_API int giraffeFunction();

class Giraffe
{
    int id;
        Giraffe(int id_in);
    friend class GiraffeFactory;

public:
    GIRAFFE_API int GetID();
};

class GiraffeFactory
{
    static int nextID;

public:
    GIRAFFE_API GiraffeFactory();
    GIRAFFE_API static int GetNextID();
    GIRAFFE_API static Giraffe* Create();
};

コード ファイルは以下のようになります。

// giraffe.cpp
#include "pch.h"
#include "giraffe.h"

Giraffe::Giraffe(int id_in) : id(id_in)
{
}

int Giraffe::GetID()
{
    return id;
}

int GiraffeFactory::nextID = 0;

GiraffeFactory::GiraffeFactory()
{
    nextID = 0;
}

int GiraffeFactory::GetNextID()
{
    return nextID;
}

Giraffe* GiraffeFactory::Create()
{
    return new Giraffe(nextID++);
}

int giraffeFunction();

プロジェクト内の他のすべてのもの (pch.hdllmain.cpp) は、標準の Win32 プロジェクト テンプレートの一部です。 このコードでは、マクロ GIRAFFE_API を定義します。このマクロは、GIRAFFE_EXPORTS が定義されている場合 __declspec(dllexport) に解決されます。 つまり、プロジェクトが DLL としてビルドされる場合は定義されますが、クライアントが giraffe.h ヘッダーを使用する場合は定義されません。 この DLL は、ソース コードを変更せずに UWP プロジェクトで使用できます。 一部のプロジェクト設定とプロパティのみを変更する必要があります。

次の手順は、__declspec(dllexport) を使用して関数を公開するネイティブ DLL がある場合に適用されます。

新しいプロジェクトを作成せずに UWP にネイティブ DLL を移植するには

  1. Visual Studio で DLL プロジェクトを開きます。

  2. DLL プロジェクトの [プロジェクトのプロパティ] を開き、構成[すべての構成] に設定します。

  3. [プロジェクトのプロパティ] にある [C/C++][全般] タブで、[Windows ランタイム拡張機能の使用][はい (/ZW)] に設定します。 このプロパティにより、コンポーネントの拡張機能 (C++/CX) が使用可能になります。

  4. ソリューション エクスプローラーで、プロジェクト ノードを選び、ショートカット メニューを開いて [プロジェクトのアンロード] を選びます。 次に、アンロードしたプロジェクト ノードのショートカット メニューを開き、プロジェクト ファイルの編集を選択します。 WindowsTargetPlatformVersion 要素を検索し、次の要素に置き換えます。

    <AppContainerApplication>true</AppContainerApplication>
    <ApplicationType>Windows Store</ApplicationType>
    <WindowsTargetPlatformVersion>10.0.10156.0</WindowsTargetPlatformVersion>
    <WindowsTargetPlatformMinVersion>10.0.10156.0</WindowsTargetPlatformMinVersion>
    <ApplicationTypeRevision>10.0</ApplicationTypeRevision>
    

    .vcxproj ファイルを閉じて、ショートカット メニューを再度開き、[プロジェクトの再読み込み] を選びます。

    これで、ソリューション エクスプ ローラーがプロジェクトをユニバーサル Windows プロジェクトとして識別するようになります。

  5. プリコンパイル済みヘッダー ファイル名が正しいことを確認します。 [プリコンパイル済みヘッダー] セクションで、次のようなエラーが表示される場合は、プリコンパイル済みヘッダー ファイルpch.h から stdafx.h に、または逆の方法で変更する必要があります。

    エラー C2857: /Ycpch.h コマンド ライン オプションで指定した ' #include ' ステートメントがソース ファイル内に見つかりませんでした

    問題は、以前のプロジェクト テンプレートでプリコンパイル済みヘッダー ファイルに対して別の名前付け規則が使用されていることです。 Visual Studio 2019 以降のプロジェクトでは、pch.h を使用します。

  6. プロジェクトをビルドします。 互換性のないコマンド ライン オプションに関するエラーが発生する場合があります。 たとえば、現在非推奨になっているが頻繁に使用されるオプション [最小リビルドを有効にする (/Gm)] は多くの古い C++ プロジェクトで既定で設定され、/ZW と互換性がありません。

    ユニバーサル Windows プラットフォーム用にコンパイルする場合、一部の関数は使用できません。 問題があるとそれに関するコンパイラ エラーが表示されます。 ビルドがクリーンになるまでこれらのエラーを解決します。

  7. 同じソリューションで UWP アプリの DLL を使用するには、UWP プロジェクト ノードのショートカット メニューを開き、[追加][参照] の順に選びます。

    [プロジェクト][ソリューション] の順に選び、DLL プロジェクトの横にあるチェック ボックスをオンにして、[OK] ボタンを選びます。

  8. UWP アプリの pch.h ファイルに、ライブラリのヘッダー ファイルを含めます。

    #include "..\Giraffe\giraffe.h"
    
  9. 通常通り UWP プロジェクトにコードを追加し、関数を呼び出して、DLL から型を生成します。

    MainPage::MainPage()
    {
        InitializeComponent();
        GiraffeFactory gf;
        Giraffe* g = gf.Create();
        int id = g->GetID();
    }
    

UWP アプリでネイティブ C++ スタティック ライブラリを使用する

UWP プロジェクトでネイティブ C++ スタティック ライブラリを使用することはできますが、理解しておくべき制約と制限があります。 最初に C++/CX でのスタティック ライブラリについてご覧ください。 UWP アプリからスタティック ライブラリのネイティブ コードにアクセスすることはできますが、このようなスタティック ライブラリにパブリックな参照型を作成することは推奨されていません。 /ZW オプションを使用してスタティック ライブラリをコンパイルすると、ライブラリアン (実際にはリンカー) により次の警告が表示されます。

LNK4264: は /ZW でコンパイルされたオブジェクト ファイルをスタティック ライブラリにアーカイブしています。Windows Runtime 型を作成する場合、Windows Runtime メタデータを含むスタティック ライブラリとのリンクはお勧めできません。

ただし、/ZW を使用して再コンパイルするのでなければ、UWP アプリでスタティック ライブラリを使用することができます。 ライブラリでは、ref 型を宣言したり、C++/CX コンストラクトを使用したりすることはできません。 ただし、ネイティブ コードのライブラリを使用することだけが目的である場合は、次の手順に従って実行できます。

UWP プロジェクトでネイティブ C++ スタティック ライブラリを使用するには

  1. UWP プロジェクトのプロジェクト プロパティで、左側のウィンドウの [構成プロパティ]>[リンカー]>[入力] を選択します。 右側のウィンドウで、[追加の依存関係] プロパティのライブラリにパスを追加します。 たとえば、出力を <SolutionFolder>\Debug\MyNativeLibrary\MyNativeLibrary.lib に配置するプロジェクトのライブラリの場合、相対パス Debug\MyNativeLibrary\MyNativeLibrary.lib を追加します。

  2. ヘッダー ファイルを参照する include ステートメントを pch.h ファイル (ある場合)、または必要に応じて任意の .cpp ファイルに追加して、そのライブラリを使用するコードの追加を開始します。

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

    ソリューション エクスプローラー[参照] ノードには参照を追加しないでください。 このメカニズムは、Windows ランタイム コンポーネントの場合のみ機能します。

C++ ライブラリを Windows ランタイム コンポーネントに移植する

UWP アプリからスタティック ライブラリのネイティブ API を使用するとします。 ネイティブ ライブラリのソース コードがある場合は、Windows ランタイム コンポーネントにコードを移植できます。 これは、スタティック ライブラリではなくなります。これを、任意の C++ UWP アプリで使用できる DLL に変換します。 この手順では、C++/CX 拡張機能を使用する新しい Windows ランタイム コンポーネントを作成する方法について説明します。 代わりに C++/WinRT を使用するコンポーネントを作成する方法については、「C++/WinRT を使用する Windows ランタイム コンポーネント」をご覧ください。

C++/CX を使用する場合、参照型およびその他の C++/CX コンストラクトを追加できます。これは、任意の UWP アプリ コードでクライアントが使用できます。 C#、Visual Basic、または JavaScript からこれらの型にアクセスできます。 基本手順は次のとおりです。

  • Windows ランタイム コンポーネント (ユニバーサル Windows) プロジェクトを作成し、
  • スタティック ライブラリのコードをそのプロジェクトにコピーして、
  • /ZW オプションによって発生したコンパイラのエラーに対処します。

C++ ライブラリを Windows ランタイム コンポーネントに移植するには

  1. Windows ランタイム コンポーネント (ユニバーサル Windows) プロジェクトを作成します。

  2. プロジェクトを閉じます。

  3. Windows ファイル エクスプローラー で、新しいプロジェクトを検索します。 次に、移植するコードを含む C++ ライブラリ プロジェクトを見つけます。 C++ ライブラリ プロジェクトから、ソース ファイル (サブディレクトリ内のヘッダー ファイル、コード ファイル、その他のリソースなど) をコピーします。 新しいプロジェクト フォルダーに貼り付け、同じフォルダー構造を保持します。

  4. Windows ランタイム コンポーネント プロジェクトを再度開きます。 ソリューション エクスプローラー でプロジェクト ノードのショートカット メニューを開き、追加>既存アイテム を選択します。

  5. 元のプロジェクトから追加するすべてのファイルを選択し、[OK] を選択します。 サブフォルダーについても必要に応じてこの操作を繰り返します。

  6. 一部のコードが重複している可能性があります。 プリコンパイル済みヘッダーが複数ある場合 (stdafx.hpch.h の両方) は、保持するものを 1 つ選択します。 include ステートメントなどの必要なコードはすべて、保持する方にコピーしておきます。 次に、プロジェクト プロパティの [プリコンパイル済みヘッダー] でもう一方を削除します。このとき、ヘッダー ファイルの名前が正しいことを確認してください。

    プリコンパイル済みヘッダーとして使用するファイルを変更した場合、プリコンパイル済みヘッダー オプションが各ファイルに対して正しいことを確認します。 今度は各 ..cpp ファイルを選び、そのプロパティ ウィンドウを開いて、[作成する (/Yc)] に設定されている目的のプリコンパイル済みヘッダー以外は、すべて [使用する (/Yu)] に設定されていることを確認します。

  7. プロジェクトをビルドし、エラーを解決します。 これらのエラーは、/ZW オプションを使用した場合、または新しいバージョンの Windows SDK が原因で発生した可能性があります。 また、ライブラリが依存するヘッダー ファイルなどの依存関係や、古いプロジェクトと新しいプロジェクトの間のプロジェクト設定の違いが反映されている場合もあります。

  8. パブリック参照型をプロジェクトに追加するか、通常の型を参照型に変換します。 これらの型を使用して、UWP アプリから呼び出す機能にエントリ ポイントを公開します。

  9. UWP アプリ プロジェクトからコンポーネントへの参照を追加してコンポーネントをテストし、作成したパブリック API を呼び出すコードを追加します。

関連項目

ユニバーサル Windows プラットフォームへの移植