こんにちは、Japan Developer Support Core チームの上原です。
今回は、Microsoft Visual C++ 2015 以降のバージョン(2015, 2017, 2019, 2022)における互換性について、Microsoft 公式ドキュメントをもとに解説します。
はじめに
Visual C++ ランタイムでは、システムにランタイムをインストールする再頒布可能パッケージや、ビルドツールとしての MSVC など、各バージョンごとにソフトウェアが提供されています。
例えば、ビルドツール MSVC v140 を用いてビルドしたアプリケーションは、Visual C++ 2015 ランタイム上で動作することを想定しており、Visual C++ ランタイムのバージョン 14.0 として表記される場合もあります。
- Visual C++ 2015 / MSVC v140 / バージョン 14.0
- Visual C++ 2017(Microsoft Visual C++ 2015-2017) / MSVC v141 / バージョン 14.1x
- Visual C++ 2019(Microsoft Visual C++ 2015-2019) / MSVC v142 / バージョン 14.2x
- Visual C++ 2022(Microsoft Visual C++ 2015-2022) / MSVC v143 / バージョン 14.3x, 14.4x
なお、Visual C++ ランタイムは、32bit 版である x86、64bit 版である x64、ARM 版である ARM64 が、それぞれ独立したソフトウェアとして提供されておりますが、本記事では特定のアーキテクチャに依存しない Visual C++ の互換性についてご説明します。
バイナリの互換性
Visual C++ 2015 以降のランタイム(MSVC)は、バイナリの互換性(後方互換性)が保証されています。
これは、特定の Visual C++ バージョンをターゲットに開発されたアプリケーションは、再ビルドすることなく、ターゲットより新しいバージョンの Visual C++ ランタイム上で互換性を維持して動作することを意味しています。
例えば、 MSVC v142 を用いて開発したアプリケーションは、対応する Visual C++ 2019 以降のランタイム上では互換性を維持し動作しますが、Visual C++ 2017 や 2015 ランタイム上では動作が保証されません。
そのため、アプリケーションをビルドする開発者と、ビルドされたアプリケーションを実行する利用者は、それぞれの観点でバージョン間の互換性を適切に認識する必要があります。
アプリケーション実行時に考慮すべき互換性
バイナリの後方互換性が保証されておりますので、リリースされたアプリケーションを実行する環境では、可能な限り 最新の Visual C++ 再頒布可能パッケージ の利用が推奨されております。
Visual C++ ランタイムや再頒布可能パッケージは、Windows Update にてインストール・アップデートされるソフトウェアではありませんので、Visual Studio などの Visual C++ を含む親製品と共にインストールする、あるいは、手動でインストールする必要があります。
一方で、Visual C++ 再頒布可能パッケージはシステム共通で利用されるソフトウェアとなっているため、特定のバージョンに固定し、アップデートを抑制するといった方法はございません。
システムにインストールされている Visual C++ 再頒布可能パッケージが、あるアプリケーションのアップデートやインストールに伴ってアップデートされた場合であっても、バイナリ互換性が保証されていることで既存のアプリケーションは従来通り動作することが想定されていますので、通常はバージョンを固定する必要はありません。
開発時に考慮すべき互換性
Visual Studio などを用い Visual C++ アプリケーションを開発する場合には、ビルドツール(プラットフォーム ツール) として、任意の MSVC バージョンを指定することが可能です。
そのため、アプリケーション開発においていずれのバージョンの MSVC をターゲットとするかを決定する必要があります。
過去バージョンをターゲットとする場合には、より広範囲の Visual C++ ランタイムバージョンにおいて動作することが期待されますが、ターゲットバージョン以降に導入された機能改善や不具合修正の恩恵を受けられない可能性があります。
弊社としては可能な限り最新バージョンをターゲットとして開発することを推奨しておりますが、後述いたします Visual C++ ランタイム自体のサポート状況や、上記のような互換性に関する制約なども鑑み、総合的にご判断いただければと存じます。
アプリケーションが複数のバイナリ(EXE、DLL、LIB、OBJ) から構成されており、それぞれのバイナリごとにビルド環境や、依存する MSVC のバージョンが異なるといった場合には、 バイナリ互換性に関する制限事項 に注意する必要があります。
私たちサポート窓口にお問い合わせいただく事例の中でも、上記制限事項を満たしていない構成であったことで、予期しないタイミングで問題が顕在化するといった報告もありますので、問題を未然に防ぐためにも、各バイナリが依存する Visual C++ バージョンや構成に問題がないかご確認ください。
[参考情報 1] Visual C++ のサポートライフサイクル
Visual C++ の各バージョンは、原則として対応する Visual Studio のライフサイクルに沿って サポートされます。
各 Visual C++ バージョンのライフサイクルについては、こちらのドキュメント をご確認ください。
なお、サポートライフサイクルにおける Visual C++ バージョンは、開発時にターゲットとしたバージョンではなく、システムで実際に動作するランタイムのバージョンに依存します。
そのため、既存のアプリケーションをそのまま利用する場合であっても、可能な限り定期的にアップデートを実施いただき、最新の Visual C++ ランタイム(再頒布可能パッケージ) の利用することで、より長期にわたりアプリケーションをご利用いただくことが可能です。
[参考情報 2] Visual C++ ランタイムの配置
Visual C++ アプリケーションを開発する場合には、Visual C++ ランタイムの配置について、以下の 3種類のいずれかを選択することが可能です。
- Visual C++ 再頒布可能パッケージを用いてシステムにインストールする集中配置
- アプリケーション内にランタイム ファイル群を含めて配布するローカル デプロイ
- ビルド時にアプリのバイナリに直接ランタイムを含める スタティック リンク
一般的に 集中配置
が推奨されておりますので、本記事では集中配置を前提に説明しておりますが、何かしらの要件や制約によりローカル デプロイやスタティック リンクを選択する場合には、アプリケーションのリリース時にランタイムが固定されますため、ランタイムの更新にはアプリケーションの再リリースが必要になります。
[参考情報 3] DLL の境界を越えて CRT オブジェクトを渡す場合に発生するエラー
よく弊社にお問い合わせいただく事例として、DLL の境界を越えて CRT オブジェクトを渡す場合に発生する可能性のあるエラー を紹介させていただきます。
Visual C++ ランタイム(CRT) で定義されている CRT オブジェクトを、バイナリ(EXE や DLL) の境界を越えて受け渡しすることで、予期せぬエラーが発生する可能性がございます。
具体的には、CRT オブジェクトを受け渡すバイナリ間において、それぞれのバイナリが異なる Visual C++ ランタイムに依存(リンク)している場合に、ヒープの破損などの問題を引き起こす可能性があります。
本エラーが懸念される場合には、CRT オブジェクトを受け渡すそれぞれのバイナリを同一の Visual C++ ランタイムにリンクしていただく、あるいは、バイナリ境界を越えた CRT オブジェクトの受け渡しを避けていただく、といった対応をご検討ください。
本ブログの内容は弊社の公式見解として保証されるものではなく、開発・運用時の参考情報としてご活用いただくことを目的としています。もし公式な見解が必要な場合は、弊社ドキュメント (https://learn.microsoft.com や https://support.microsoft.com) をご参照いただくか、もしくは私共サポートまでお問い合わせください。