C言語・C++で発生するコンパイラエラー C3138 の原因と対処法を解説
この記事では、C言語およびC++環境で発生するコンパイラエラー C3138について解説します。
COMのインターフェース継承において、dualやdispinterface属性を持つインターフェースにIDispatchが正しく継承されていない場合にエラーが起こります。
具体例を交えながら原因や対処法を分かりやすく紹介します。
エラー発生の背景
COMインターフェース継承の基本ルール
dualおよびdispinterface属性の概要
COMインターフェースには、dual属性やdispinterface属性が指定でき、これらはインターフェースの利用方法を決定する重要な属性です。
・dual属性は、インターフェースが早期バインディング(コンパイル時に決定される呼び出し)と後期バインディング(実行時に決定される呼び出し)の両方に対応することを意味します。
・dispinterface属性は、主にOLEオートメーションにおいて利用され、IDispatchを基盤とする動的なメソッド呼び出しの仕組みを提供します。
IDispatchの継承条件
COMにおいて、dual属性やdispinterface属性を持つインターフェースは、直接または間接的にIDispatchから継承する必要があります。
つまり、インターフェース宣言でIDispatchが基底インターフェースに含まれていないとエラーが発生する可能性があります。
このルールは、COMオブジェクトが正しいメソッド呼び出しやプロパティアクセスを実現するための基本条件となります。
エラー発生の具体例
サンプルコードによるエラー原因
以下は、エラー C3138 が発生するサンプルコードの例です。
IMyDualInterface が IMyCustomInterface を基底インターフェースとして継承しているため、IDispatchが継承チェーンに含まれておらず、エラーが発生します。
#include <unknwn.h>
// カスタムインターフェース
[ object, uuid("77ac9240-6e9a-11d2-97de-0000f805d73b") ]
__interface IMyCustomInterface
{
    // サンプルメソッド
    HRESULT mf1(void);
};
// dispinterface属性を持つインターフェース
[ dispinterface, uuid("3536f8a0-6e9a-11d2-97de-0000f805d73b") ]
__interface IMyDispInterface : IUnknown
{
    // ID指定されたメソッド
    [id(1)] HRESULT mf2(void);
};
// dual属性を持つインターフェースですが、IDispatchを継承していないためエラー発生
[ object, dual, uuid("34e90a10-6e9a-11d2-97de-0000f805d73b") ]
__interface IMyDualInterface : IMyCustomInterface  // ここでエラー C3138 が発生する
{
    HRESULT mf3(void);
};
int main(void)
{
    // COM呼び出しのテストはここに記述する
    return 0;
}// コンパイル時に以下のようなエラーメッセージが表示される:
// C3138: 'interface': 'attribute' インターフェイスは IDispatch、また IDispatch から継承したインターフェイスから継承する必要がありますコード例の詳細解説
エラーを含むサンプルコードの構成
各インターフェースの役割
このコード例には、3つの主要なインターフェースが含まれています。
・IMyCustomInterface はユーザー定義の基本インターフェースで、通常のメソッド呼び出しを提供します。
・IMyDispInterface は dispinterface 属性を持ち、OLEオートメーションのために利用されるインターフェースです。
・IMyDualInterface は dual 属性を持ち、動的および静的呼び出し双方に対応できるよう設計されていますが、正しく IDispatch を継承していません。
IMyCustomInterfaceの説明
IMyCustomInterface は、COMオブジェクトが実装すべきメソッドを定義する基本的なインターフェースです。
このインターフェースは、単一のメソッド mf1 を提供しており、ユーザー定義機能などの追加が可能です。
IMyDispInterfaceの説明
IMyDispInterface は、dispinterface 属性によって宣言され、OLEオートメーションで利用されるためのインターフェースです。
IDispatch を継承している仕様が期待されますが、ここでは基底クラスとして IUnknown を指定しているため、OLEオートメーション環境での使用に制約が生じます。
IMyDualInterfaceでのエラー箇所
IMyDualInterface は dual 属性が指定されていますが、継承チェーンに IDispatch が含まれません。
正しくは、dual 属性を持つインターフェースは、直接もしくは間接的に IDispatch を継承しなければなりません。
この不整合が原因で、C3138 エラーが発生してしまいます。
エラーメッセージの解析
‘interface’と’attribute’に関する情報
エラーメッセージには「’interface’: ‘attribute’ インターフェイスは IDispatch、また IDispatch から継承したインターフェースから継承する必要があります」と記載されています。
これは、dual または dispinterface 属性を付与されたインターフェースが、IDispatch に依存するというCOMの設計ルールに基づいています。
そのため、継承関係において IDispatch を含めない構成は許容されません。
また、エラーメッセージは直接的にどのインターフェースに問題があるかを示しており、問題箇所を迅速に特定できる情報となります。
対処方法の提示
正しいインターフェース継承の記述方法
IDispatchを正しく継承する方法
dual 属性を持つインターフェースでは、IDispatch を継承することで正しいコンパイルを実現できます。
例えば、以下のようにIMyDualInterfaceが直接 IDispatch 又は IUnknown 経由で IDispatch を含む形に修正する必要があります。
修正方法としては、IMyCustomInterface を継承する場合でも、IMyCustomInterface 自体が IDispatch から継承するように変更する方法が考えられます。
修正コードのポイント
修正版コードの注意点
修正版コード例では、IMyCustomInterface にも dual を指定し、IDispatch を正しく継承するように書き換えます。
これにより、IMyDualInterface は正しい継承チェーンを持つことになり、C3138 エラーが解消されます。
以下は修正版コードの例です。
#include <unknwn.h>
// dual属性を追加し、IDispatchを基底インターフェースに含むことで修正
[ object, dual, uuid("77ac9240-6e9a-11d2-97de-0000f805d73b") ]
__interface IMyCustomInterface : IDispatch
{
    // カスタムメソッド
    HRESULT mf1(void);
};
[ dispinterface, uuid("3536f8a0-6e9a-11d2-97de-0000f805d73b") ]
__interface IMyDispInterface : IDispatch
{
    // dispinterface用のメソッド
    [id(1)] HRESULT mf2(void);
};
// IMyCustomInterface がIDispatchを継承するため、こちらは問題なく継承可能
[ object, dual, uuid("34e90a10-6e9a-11d2-97de-0000f805d73b") ]
__interface IMyDualInterface : IMyCustomInterface
{
    // 追加のカスタムメソッド
    HRESULT mf3(void);
};
int main(void)
{
    // COMオブジェクト生成やメソッド呼び出しのテストコードを記述可能
    return 0;
}// このコードはコンパイルエラー C3138 を発生させずにコンパイル可能です。開発環境での注意事項
環境依存の設定確認
開発環境によっては、COMコンパイラの設定や利用するSDKのバージョンにより、エラーの発生条件や挙動が異なる場合があります。
環境設定において以下の点を確認してください。
- 利用しているWindows SDKのバージョンが最新かどうか
- COM関連のプロジェクト設定が正しく構成されているか
- コンパイラのオプションにより、属性の取り扱いについてのオーバーライドが行われていないか
これらの設定が正しく行われていない場合、想定外のエラーが発生する可能性があります。
エラー再発防止のチェック事項
エラー再発防止のために、以下の項目についてチェックすることをお勧めします。
- インターフェース継承チェーンに IDispatchが含まれているか確認する
- dualや- dispinterface属性の用途に合わせた正しい継承関係が維持されているかを定期的に見直す
- COM実装の変更時に、サンプルコードやテストコードを用いて各インターフェースの動作確認を行う
これらのチェックを行うことで、同様のエラーが再び発生するリスクを下げることが可能です。
まとめ
本記事では、COMインターフェースのdualおよびdispinterface属性の役割と、IDispatch継承の必須条件について解説しました。
エラーC3138が発生する具体例と、その原因となる継承不備を説明し、修正例を通じて正しい継承関係の構築方法を示しました。
読者は、COMインターフェースの正しい設計方法とエラー防止のポイントを理解できます。
