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インターフェースの正しい設計方法とエラー防止のポイントを理解できます。