リッチ エディット コントロールで OLE を使用する方法

このセクションでは、リッチ エディット コントロールでオブジェクトのリンクと埋め込み (OLE) を使用する方法について説明します。

知っておくべきこと

テクノロジ

前提条件

  • C/C++
  • Windows ユーザー インターフェイス プログラミング

手順

リッチ エディット インターフェイスの使用

リッチ エディット コントロールは、コンポーネント オブジェクト モデル (COM) インターフェイスを通じて機能の一部を公開します。 コントロールからインターフェイスを取得することにより、コントロール内の他のオブジェクトを操作可能になります。 このインターフェイスは、EM_GETOLEINTERFACE メッセージを送信することにより取得できます。 IRichEditOle インターフェイスから、テキスト オブジェクト モデルで使用されているインターフェイスを取得できます。

もう 1 つのインターフェイス IRichEditOleCallback は、オブジェクトと対話するときのコントロールの動作を定義するため、アプリケーションによって実装されます。

リッチ エディット コントロールへのオブジェクトの挿入

次のコード例では、ファイル オブジェクトをリッチ エディット コントロールに挿入します。 プログラムがユーザーのコンピューター上のファイルの種類に関連付けられている場合 (たとえば、.xls ファイルの場合は Microsoft Excel)、ファイルの内容がコントロールに表示されます。それ以外の場合、アイコンが表示されます。

  1. IRichEditOle インターフェイスを取得します。

    BOOL InsertObject(HWND hRichEdit, LPCTSTR pszFileName)
    {
        HRESULT hr;
    
        LPRICHEDITOLE pRichEditOle;
        SendMessage(hRichEdit, EM_GETOLEINTERFACE, 0, (LPARAM)&pRichEditOle);
    
        ...
    
  2. 構造化ストレージを作成します。

        LPLOCKBYTES pLockBytes = NULL;
        hr = CreateILockBytesOnHGlobal(NULL, TRUE, &pLockBytes);
    
        LPSTORAGE pStorage;
        hr = StgCreateDocfileOnILockBytes(pLockBytes, 
                                          STGM_SHARE_EXCLUSIVE | STGM_CREATE | STGM_READWRITE, 
                                          0, &pStorage);
        ...
    
  3. データ形式を設定します。

        FORMATETC formatEtc;
    
        formatEtc.cfFormat = 0;
        formatEtc.ptd      = NULL;
        formatEtc.dwAspect = DVASPECT_CONTENT;
        formatEtc.lindex   = -1;
        formatEtc.tymed    = TYMED_NULL;
    
        ...
    
  4. 表示サイトへのポインターを取得します。

        LPOLECLIENTSITE pClientSite;
        hr = pRichEditOle->GetClientSite(&pClientSite);
    
        ...
    
  5. オブジェクトを作成し、その IUnknown インターフェイスを取得します。

        LPUNKNOWN pUnk;
        CLSID clsid = CLSID_NULL;
    
        hr = OleCreateFromFile(clsid, 
                               pszFileName, 
                               IID_IUnknown, 
                               OLERENDER_DRAW, 
                               &formatEtc, 
                               pClientSite, 
                               pStorage, 
                               (void**)&pUnk);
    
        pClientSite->Release();
    
        ...
    
  6. オブジェクトへの IOleObject インターフェイスを取得します。

        LPOLEOBJECT pObject;
    
        hr = pUnk->QueryInterface(IID_IOleObject, (void**)&pObject);
    
        pUnk->Release();
    
        ...
    
  7. 参照が正しくカウントされるようにするため、参照が含まれていることをオブジェクトに通知します。

        OleSetContainedObject(pObject, TRUE);
    
        ...
    
  8. オブジェクト情報を設定します。

        REOBJECT reobject = { sizeof(REOBJECT)};
    
        hr = pObject->GetUserClassID(&clsid);
    
        reobject.clsid    = clsid;
        reobject.cp       = REO_CP_SELECTION;
        reobject.dvaspect = DVASPECT_CONTENT;
        reobject.dwFlags  = REO_RESIZABLE | REO_BELOWBASELINE;
        reobject.dwUser   = 0;
        reobject.poleobj  = pObject;
        reobject.polesite = pClientSite;
        reobject.pstg     = pStorage;
    
        SIZEL sizel       = { 0 };
        reobject.sizel    = sizel;
    
        ...
    
  9. キャレットをテキストの末尾に移動し、キャリッジ リターンを追加します。

        SendMessage(hRichEdit, EM_SETSEL, 0, -1);
    
        DWORD dwStart, dwEnd;
    
        SendMessage(hRichEdit, EM_GETSEL, (WPARAM)&dwStart, (LPARAM)&dwEnd);
        SendMessage(hRichEdit, EM_SETSEL, dwEnd+1, dwEnd+1);
        SendMessage(hRichEdit, EM_REPLACESEL, TRUE, (WPARAM)L"\n"); 
    
        ...
    
  10. オブジェクトを挿入します。

        hr = pRichEditOle->InsertObject(&reobject);
    
        ...
    
  11. クリーンアップします。

        pObject->Release();
    
        pRichEditOle->Release();
    
        return TRUE;
    
    }
    

IRichEditOleCallback の使用

アプリケーションは、OLE 関連のクエリ、またはリッチ エディット コントロールによって実行されるアクションに応答する IRichEditOleCallback インターフェイスを実装します。 インターフェイスの実装をコントロールに関連付けるには、EM_SETOLECALLBACK メッセージを送信します。 コントロールは、必要に応じてインターフェイスの実装でメソッドを呼び出します。

たとえば、ユーザーがオブジェクトをコントロールにドラッグまたは貼り付けようとすると、QueryAcceptData が呼び出されます。 アプリケーションがデータを受け入れる場合、メソッドの実装によって S_OK が返されます。それ以外の場合はエラー コードが返されます。 メソッドは、その種類のファイルをコントロールに配置できないことをユーザーに警告するなど、他のアクションを実行することもあります。

完全な InsertObject サンプル関数

次のコード例は、エラー処理を含む、1 つの完全な関数に結合された前のコード スニペットを示しています。

BOOL InsertObject(HWND hRichEdit, LPCTSTR pszFileName)
{
    HRESULT hr;

    LPRICHEDITOLE pRichEditOle;
    SendMessage(hRichEdit, EM_GETOLEINTERFACE, 0, (LPARAM)&pRichEditOle);

    if (pRichEditOle == NULL)
    {
        return FALSE;
    }

    LPLOCKBYTES pLockBytes = NULL;
    hr = CreateILockBytesOnHGlobal(NULL, TRUE, &pLockBytes);

    if (FAILED(hr))
    {
        return FALSE;
    }

    LPSTORAGE pStorage;
    hr = StgCreateDocfileOnILockBytes(pLockBytes, 
           STGM_SHARE_EXCLUSIVE | STGM_CREATE | STGM_READWRITE, 
           0, &pStorage);

    if (FAILED(hr))
    {
        return FALSE;
    }

    FORMATETC formatEtc;
    formatEtc.cfFormat = 0;
    formatEtc.ptd = NULL;
    formatEtc.dwAspect = DVASPECT_CONTENT;
    formatEtc.lindex = -1;
    formatEtc.tymed = TYMED_NULL;

    LPOLECLIENTSITE pClientSite;
    hr = pRichEditOle->GetClientSite(&pClientSite);

    if (FAILED(hr))
    {
        return FALSE;
    }

    LPUNKNOWN pUnk;
    CLSID clsid = CLSID_NULL;

    hr = OleCreateFromFile(clsid, pszFileName, IID_IUnknown, OLERENDER_DRAW, 
           &formatEtc, pClientSite, pStorage, (void**)&pUnk);

    pClientSite->Release();

    if (FAILED(hr))
    {
        return FALSE;
    }

    LPOLEOBJECT pObject;
    hr = pUnk->QueryInterface(IID_IOleObject, (void**)&pObject);
    pUnk->Release();

    if (FAILED(hr))
    {
        return FALSE;
    }

    OleSetContainedObject(pObject, TRUE);
    REOBJECT reobject = { sizeof(REOBJECT)};
    hr = pObject->GetUserClassID(&clsid);

    if (FAILED(hr))
    {
        pObject->Release();
        return FALSE;
    }

    reobject.clsid = clsid;
    reobject.cp = REO_CP_SELECTION;
    reobject.dvaspect = DVASPECT_CONTENT;
    reobject.dwFlags = REO_RESIZABLE | REO_BELOWBASELINE;
    reobject.dwUser = 0;
    reobject.poleobj = pObject;
    reobject.polesite = pClientSite;
    reobject.pstg = pStorage;
    SIZEL sizel = { 0 };
    reobject.sizel = sizel;

    SendMessage(hRichEdit, EM_SETSEL, 0, -1);
    DWORD dwStart, dwEnd;
    SendMessage(hRichEdit, EM_GETSEL, (WPARAM)&dwStart, (LPARAM)&dwEnd);
    SendMessage(hRichEdit, EM_SETSEL, dwEnd+1, dwEnd+1);
    SendMessage(hRichEdit, EM_REPLACESEL, TRUE, (WPARAM)L"\n"); 

    hr = pRichEditOle->InsertObject(&reobject);
    pObject->Release();
    pRichEditOle->Release();

    if (FAILED(hr))
    {
        return FALSE;
    }
    
    return TRUE;
}

リッチ エディット コントロールの使用

Windows コモン コントロールのデモ (CppWindowsCommonControls)