C言語におけるC3136エラーの原因とCOMインターフェース継承の修正方法について解説
このエラーC3136は、COMインターフェイス用の属性が付いたインターフェイスが、正しいCOMインターフェイス(通常はIUnknown)から継承されていない場合に発生します。
たとえば、__interfaceを使用してインターフェイス宣言を行った際、継承元がCOMインターフェイスでないとC3136エラーが発生します。
正しい継承関係に修正することで解決できます。
エラーC3136の概要
このエラーは、COMインターフェースに対して正しい継承関係が構築されていない場合に発生します。
COMインターフェースは、すべて最終的に IUnknown
から継承される必要がありますが、これに反する継承方法をとると、コンパイラがエラーC3136を出力します。
エラー発生の背景
COMコンポーネントを利用する際、インターフェースはCOMの規約に則って定義されなければなりません。
具体的には、__interface
属性を使用して定義されたインターフェースは、自動的にCOMインターフェースとして扱われ、最終的に IUnknown
から継承する必要があります。
しかし、誤ってCOMインターフェース以外を継承した場合に、コンパイラは「COM インターフェースは他の COM インターフェースからのみ継承できます」というエラーを発生させます。
エラーメッセージの内容
エラーメッセージは次のような内容です。
「’interface’ : COM インターフェイスは他の COM インターフェイスからのみ継承できます、’interface’ は COM インターフェイスではありません。」
このメッセージは、COMインターフェース属性が指定されたインターフェースが、正しいCOM継承を行っていない場合に表示されます。
C3136エラーの原因詳細
COMインターフェースには、特有の属性や継承規則が存在します。
エラーC3136は、これらの規則に違反している際に発生します。
COMインターフェース属性の説明
__interface
属性は、インターフェースをCOMインターフェースとして定義するためのMicrosoft独自のキーワードです。
この属性を使用することで、インターフェースが自動的にCOMインターフェースとして認識され、IUnknown
から継承しているとみなされます。
そのため、継承先がCOMインターフェースでない場合、ルールに反してエラーが発生します。
継承階層の誤設定による問題
COMインターフェースのルールにおいて、すべてのCOMインターフェースは最終的に IUnknown
から継承される必要があります。
継承階層が正しく設定されていない場合、たとえばCOMインターフェース属性が付いたインターフェースが、COMインターフェースではないインターフェースを継承すると、エラーC3136が発生します。
__interfaceとIUnknownの関係
IUnknown
はCOMの基本インターフェースであり、ここから派生して各COMインターフェースが定義されます。
__interface
で定義されたインターフェースは、明示的に IUnknown
を継承するか、COMインターフェースとして定義された別のインターフェースから継承する必要があります。
もし、直接的または間接的に IUnknown
との関係が構築されていない場合、コンパイラは継承関係が正しくないと判断します。
例示コードから見る具体的原因
次のコードは、エラーC3136 が発生する例です。
#include "unknwn.h"
// COMインターフェース属性が付いたインターフェースがIUnknownから継承していないためエラーが発生する例
__interface A // エラーC3136が発生する
{
int a();
};
[object]
// インターフェースBがインターフェースAを継承しているが、AがCOMインターフェースではないためエラーとなる
__interface B : A {
int aa();
};
int main()
{
return 0;
}
このコードでは、__interface A
が IUnknown
から継承していない状態で定義されているため、エラーが発生します。
COMインターフェース継承の正しい方法
COMインターフェースを正しく定義するためには、すべてのインターフェースが IUnknown
から派生することを保証する必要があります。
ここでは正しい継承方法と、その書き方について説明します。
IUnknownからの継承の必要性
COMの設計において、IUnknown
は基本となるインターフェースであり、全てのCOMインターフェースは必ず IUnknown
を継承します。
これにより、COMインターフェースは共通のインターフェースQueryInterface
、AddRef
、Release
を持つことが保証され、COMオブジェクト間の相互運用性が確保されます。
したがって、インターフェース定義時には明示的に IUnknown
からの継承を指定する必要があります。
正しいインターフェース宣言の書き方
以下は、正しいCOMインターフェースの定義例です。
正しくは、_interface
キーワードを使用して IUnknown
から継承する必要があります。
#include <unknwn.h>
// 正しいCOMインターフェース定義の例:IUnknownから継承する
_interface A : IUnknown {
int a();
};
[object]
// インターフェースBは正しくAを継承している
__interface B : A {
int aa();
};
int main()
{
return 0;
}
この例では、インターフェース A
が明示的に IUnknown
から継承されているため、COMインターフェースとして適切に定義されています。
__interfaceと_interfaceの違い
__interface
と _interface
は、どちらもCOMインターフェースを定義する際に使用されるキーワードですが、以下の点で違いがあります。
__interface
COMインターフェース属性を前に付与することで、あたかもCOMインターフェースとして振る舞うように指定されます。
ただし、継承関係が正しく構築されない場合にエラーが発生するため、注意が必要です。
_interface
明示的に IUnknown
から継承する形式でインターフェースを定義します。
この方法を用いると、継承関係が明確になり、C3136エラーを回避できます。
修正方法の実践手順
正しい継承関係が構築されるようにコードを修正するための手順とポイントについて説明します。
コード修正のポイント
エラーC3136を解消するためには、COMインターフェースを定義する際に、必ず IUnknown
から継承するように修正します。
具体的には、__interface
を直接使用するのではなく、_interface
キーワードを用いて、明示的に IUnknown
を継承するようにします。
修正前後の比較例
以下は、修正前と修正後のコードの比較です。
修正前 | 修正後 |
---|---|
c | c | |
#include “unknwn.h” | #include <unknwn.h> |
// COMインターフェースがIUnknownを継承していない | // 正しくIUnknownから継承するCOMインターフェース定義例 |
__interface A { | _interface A : IUnknown { |
int a(); | int a(); |
}; | }; |
[object] | [object] |
__interface B : A { int aa(); }; | __interface B : A { int aa(); }; |
int main() { | int main() { |
return 0; | return 0; |
} | } |
| |
この比較表から分かるように、__interface A
の宣言を _interface A : IUnknown
と修正することで、COMインターフェースとしての継承関係が正しく構築されます。
テスト実施時の注意点
コード修正後は、以下の点に注意してテストを実施してください。
- 修正後のインターフェースが正しく定義されているか、コンパイルエラーが解消されているかを確認する。
- COMオブジェクト同士のインターフェース呼び出しが正しく動作するか、特に
QueryInterface
、AddRef
、Release
の動作を確認する。 - 既存のCOMコンポーネントとの互換性が保持されているかテストする。
このように、正しい継承関係を構築し、テストを通して動作確認を行うことで、安定したCOMインターフェースの実装が可能になります。
まとめ
この記事では、COMインターフェースにおけるエラーC3136の原因と対策について解説しています。
COMインターフェースは必ずIUnknownから継承する必要があり、属性の誤用や継承関係の不備によりエラーが発生することを説明しました。
また、正しいインターフェース宣言方法として_interfaceを使用し、具体例を用いて修正方法を示しました。
これにより、COM開発でのエラー解消と正しい設計が理解できる内容となっています。