C言語のコンパイラ エラー C3719の原因と対処方法について解説
本解説では、コンパイラ エラー C3719 について説明します。
C3719 は、COM イベント以外のコンテキストでインターフェイスベースのイベントソースを宣言した際に発生するエラーです。
正しい動作を実現するために、object、coclass、event_source、event_receiver などの属性を適切に適用する必要があります。
エラー C3719の発生理由
このエラーは、COMイベントをサポートするためのインターフェイス宣言が不適切な属性とともに使用された場合に発生します。
COMイベントは特定の属性セット(例えば、[object]、[coclass]、[event_source]、[event_receiver])を必要とするため、これらの属性が正しく適用されていないとコンパイラがエラーを報告します。
COMイベントとインターフェイスの関係
COMイベントでは、イベントの通知を行うためにイベントソースインターフェイスが利用されます。
これらのインターフェイスは、COMの仕組みに則って定義されている必要があります。
具体的には、以下の点が重要です。
- COMイベントには特定の属性が必要となる。
- イベントを定義するインターフェイスは、通常のインターフェイス宣言とは異なる方法で記述される。
- イベントソースの定義は、イベントのフックや呼び出しのために必要な構造を持っていることが求められる。
インターフェイス宣言の制約
インターフェイスを宣言する際には、必ずCOM仕様に準拠した属性を付与する必要があります。
例えば、[object]属性はCOMオブジェクトであることを示すために使用され、[coclass]属性はCOMクラスを示す際に必要となります。
これらの属性が間違った場所に付与された場合、または必要な属性が漏れている場合、コンパイラはエラー C3719 を発生させるため注意が必要です。
不正なコード例の検証
誤った属性の適用方法が原因でエラーが発生する場合、どの部分が問題であるかを特定することが必要です。
以下に、実際にエラーが再現できるコード例を示します。
再現可能なコード例
下記のコードは、誤った属性の適用によってエラー C3719 を発生させるサンプルです。
問題のある属性の適用状況
// FlawedCode.cpp
#define _ATL_ATTRIBUTES 1
#include <atlbase.h>
#include <atlcom.h>
// モジュール定義(COMライブラリ内で利用)
[module(name="MyLibrary", version="1.2", helpfile="MyHelpFile")];
// COMオブジェクトとしての属性が適切に定義されていない状態
[object]
__interface I
{
    HRESULT func1();
};
[event_source(native), coclass]
struct A
{
    // エラーを引き起こす記述例
    __event __interface I; // C3719: イベントソースはCOMイベントでのみ使用可能です
};
int main()
{
    return 0;
}上記のコードでは、struct Aにおける__event __interface Iの宣言が正しくないため、コンパイラエラーが発生します。
正しい対処方法の提示
エラーを解決するためには、属性を正しく適用する必要があります。
次の項目で、各属性の利用方法とその正しい使い方について詳しく説明します。
属性の適正な適用方法
属性を正しく使うことで、COMイベント用のインターフェイスが正しく定義され、エラーが発生しなくなります。
以下では、それぞれの属性の使用方法について説明します。
object属性の利用方法
[object]属性は、そのインターフェイスがCOMオブジェクトに対して定義されていることを明示するために使われます。
正しい宣言例は次の通りです。
#define _ATL_ATTRIBUTES 1
#include <atlbase.h>
#include <atlcom.h>
// モジュール定義
[module(name="MyLibrary", version="1.2")];
// COMオブジェクトとしてのインターフェイスに適用
[object, uuid("00000000-0000-0000-0000-000000000001")]
__interface I
{
    HRESULT func1(); // イベント通知用関数
};coclass属性の利用方法
[coclass]属性は、COMクラスとして利用される構造体に付与されます。
また、[event_source]などの属性と組み合わせることで、COMイベントのソースとして機能させることができます。
[coclass, event_source(com), uuid("00000000-0000-0000-0000-000000000002")]
struct MyStruct
{
    __event __interface I; // 正しいCOMイベントインターフェイスの適用
};event_sourceおよびevent_receiver属性の使用方法
[event_source]属性を用いることで、構造体やクラスがCOMイベントの発信源であることを示します。
また、[event_receiver]属性は、イベントを受信するクラスなどに適用します。
これらの属性を正しく使用することで、イベントの通知と処理がスムーズに実行されます。
[event_receiver(com)]
struct MyStruct2
{
    // イベント通知を受け取るための関数
    void func1()
    {
        // イベント処理の内容
    }
    // コンストラクタでイベントのフックを設定
    MyStruct2(I* pEventSource)
    {
        __hook(&I::func1, pEventSource, &MyStruct2::func1);
    }
};
int main()
{
    // COMオブジェクトの生成例(詳細な生成処理は省略)
    return 0;
}修正コード例の解説
正しい属性設定を用いることで、先ほどのエラーを回避するコード例が下記になります。
ここでは、object、coclass、event_source、およびevent_receiverの各属性が適切に適用されています。
#define _ATL_ATTRIBUTES 1
#include <atlbase.h>
#include <atlcom.h>
// モジュール定義
[module(name="MyLibrary", version="1.2")];
// COMインターフェイスの定義
[object, uuid("00000000-0000-0000-0000-000000000001")]
__interface I
{
    HRESULT func1();
};
// COMクラスとイベントソースの定義
[coclass, event_source(com), uuid("00000000-0000-0000-0000-000000000002")]
struct MyStruct
{
    __event __interface I;
};
// イベント受信側の定義
[event_receiver(com)]
struct MyStruct2
{
    // 受信したイベントを処理する関数
    void func1()
    {
        // イベント受信時の処理
    }
    // コンストラクタでイベントフックを実施
    MyStruct2(I* pEventSource)
    {
        __hook(&I::func1, pEventSource, &MyStruct2::func1);
    }
};
int main()
{
    // COMオブジェクト生成やイベント設定のテストを行う
    return 0;
}// このコードはコンパイルエラーが発生しない状態で、正しく属性が適用されています。上記のコード例では、各属性が適所に配置されているため、エラー C3719 は発生しません。
また、イベントのフックも正しく設定され、COMイベントの起動と受信が可能な構造となっています。
修正による動作確認
正しく修正されたコードと、不正なコードの挙動を比較し、エラーが解消されたことを検証することが重要です。
修正前後の動作比較
修正前のコードでは、誤った属性の適用によりコンパイラエラーが発生していました。
以下は、不正なコードと正しいコードの違いを簡単に比較した表です。
| 項目 | 不正なコード | 修正後のコード | 
|---|---|---|
| インターフェイス宣言 | [object]のみの適用で、必要なuuid属性やその他属性が不足 | [object, uuid("...")]として、必要な属性が全て適用 | 
| COMクラスの定義 | [coclass, event_source(native)]で属性が正しく設定されず | [coclass, event_source(com)]と正しい属性を設定 | 
| イベント受信の設定 | 設定が行われず、イベントのフックが実施されない | [event_receiver(com)]を用い、イベント受信側の処理を明記 | 
この比較から、正しい属性の適用により、コンパイラエラーが解消され、COMイベント機能が正しく動作することが確認できます。
エラー解消の検証ポイント
- コンパイル時にエラー C3719 が報告されないことを確認する。
- 正しい属性適用により、COMインターフェイスとクラスが期待された通りに定義されていることを確認する。
- 実行時にイベントのフック処理が正常に行われ、関数呼び出しが期待どおりに行われることをテストで検証する。
- サンプルコードの出力内容やコンパイル結果で、エラー解消が明確に示されることを確認する。
まとめ
この記事では、エラー C3719 の原因として、COMイベントに必要な属性が正しく適用されないことがある点を解説しました。
COMイベント用のインターフェイスとクラスには、[object]、[coclass]、[event_source]、および [event_receiver] の各属性を適切に適用する必要があること、また不正なコード例と改善例を具体的なサンプルコードで示すことで、修正方法と動作確認の手順が理解できる内容となっています。
