C言語コールCOMコンポーネント


Cのやり方をよりよく理解するために、C++呼び出しCOMコンポーネントがどのようにしているかを見てみましょう.
一、C++方式
Windows 7からタスクバーに進捗バーが表示されるので、このインタフェースを例にとりましょう.
ITaskbarList4 *pTaskbar = nullptr;
HRESULT hResult = ::CoCreateInstance(CLSID_TaskbarList, nullptr, CLSCTX_INPROC_SERVER, __uuidof(ITaskbarList4), reinterpret_cast<void**>(&pTaskbar));

上記のコードでは、ITaskbarList 4は1つのインタフェース(純虚関数のみのクラス)であり、CoCreateInstanceの役割はITaskbarList 4インタフェースのインスタンスを作成することである.作成に成功すれば、pTaskbarを使用することができる.
hResult = pTaskbar->HrInit();

二、C方式
C++コードではインタフェース(クラス)を使用していますが、C言語にはクラスがありません.では、どうすればいいのでしょうか.
COMコンポーネントはバイナリ互換性の模範であることを知っています.CでITaskbarList 4インタフェースを使用するには、ITaskbarList 4のメモリモデルと同じC変数を指定する必要があります.
#define STDMETHODCALLTYPE __stdcall

typedef struct ITaskbarList4Vtbl
{
    HRESULT(STDMETHODCALLTYPE *QueryInterface)(ITaskbarList4 *This, const IID *riid, void **ppvObject);
    ULONG(STDMETHODCALLTYPE *AddRef)(ITaskbarList4 *This);
    ULONG(STDMETHODCALLTYPE *Release)(ITaskbarList4 *This);
    HRESULT(STDMETHODCALLTYPE *HrInit)(ITaskbarList4 *This);
    HRESULT(STDMETHODCALLTYPE *AddTab)(ITaskbarList4 *This, HWND hwnd);
    HRESULT(STDMETHODCALLTYPE *DeleteTab)(ITaskbarList4 *This, HWND hwnd);

    //       

} ITaskbarList4Vtbl;

typedef struct ITaskbarList4
{
    ITaskbarList4Vtbl *pVtbl;
} ITaskbarList4;

上のCコードのITaskbarList 4はC++コードのITaskbarList 4のメモリモデルと同じ(有名な図書「C++オブジェクトモデルを深く探求する」を参照)であり、pVtblはC++のITaskbarList 4の虚関数テーブルであり、ITaskbarList 4*ThisはC++のthisポインタである.
クラスITaskbarList 4のダミー関数テーブルをすべてCで書くと、CでCOMコンポーネントを呼び出すことができます.もちろん、このやり方の優雅さはC++方式に及ばない.
ITaskbarList4* pTaskbar = NULL;
HRESULT hr = 0L;

hr = CoCreateInstance(&CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, &IID_ITaskbarList4, (void**)&pTaskbar);

hr = pTaskbar->lpVtbl->HrInit(pTaskbar);

hr = pTaskbar->lpVtbl->SetProgressValue(pTaskbar, hWnd, 20ui64, 100ui64);

CコードはC++コードよりも1つのパラメータが多いが,このパラメータはインタフェース自体を伝達する.このパラメータは実はC++のthisポインタで、C言語では表示して提供しなければなりませんが、C++ではthisポインタが非表示なので、Cコードにパラメータが1つ増えているのが見えます.
三、一般規則
一般的に、C++版のCOMインタフェースが
class IFunc
{
public:
    virtual R_1 Func_1(   1)= 0;
    virtual R_2 Func_2(   2) = 0;
    // ......
    virtual R_n Func_3(   n) = 0;
};

では、対応するC構造は、
struct Func;
typedef struct Func Func;

typedef struct FuncVtbl //     
{
    R_1(__stdcall Func_1)(Func *This,    1);
    R_2(__stdcall Func_2)(Func *This,    2);
    // ......
    R_n(__stdcall Func_n)(Func *This,    n);
} FuncVtbl;

struct Func
{
    FuncVtbl *pVtbl;
};