서식 있는 편집 컨트롤에서 OLE를 사용하는 방법

이 섹션에는 서식 있는 편집 컨트롤에서 OLE(개체 연결 및 포함)를 사용하는 방법에 대한 정보가 포함되어 있습니다.

알아야 하는 작업

기술

필수 구성 요소

  • C/C++
  • Windows 사용자 인터페이스 프로그래밍

지침

서식 있는 편집 인터페이스 사용

서식 있는 편집 컨트롤은 COM(구성 요소 개체 모델) 인터페이스를 통해 일부 기능을 노출합니다. 컨트롤에서 인터페이스를 가져오면 컨트롤 내의 다른 개체와 함께 작업할 수 있습니다. EM_GETOLEINTERFACE 메시지를 전송하여 이 인터페이스를 가져올 수 있습니다. IRichEditOle 인터페이스에서 텍스트 개체 모델에 사용되는 인터페이스를 가져올 수 있습니다.

또 다른 인터페이스인 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;
    
    }
    

Using IRichEditOleCallback

애플리케이션은 IRichEditOleCallback 인터페이스를 구현하여 서식 있는 편집 컨트롤에서 수행하는 OLE 관련 쿼리 또는 작업에 응답합니다. EM_SETOLECALLBACK 메시지를 전송하여 인터페이스 구현을 컨트롤과 연결합니다. 그런 다음 컨트롤은 적절하게 인터페이스 구현에 대한 메서드를 호출합니다.

예를 들어, QueryAcceptData는 사용자가 개체를 컨트롤로 끌거나 붙여넣으려고 할 때 호출됩니다. 애플리케이션이 데이터를 수락할 수 있는 경우 메서드 구현은 S_OK를 반환합니다. 그렇지 않으면 오류 코드를 반환합니다. 메서드는 해당 형식의 파일을 컨트롤에 배치할 수 없음을 사용자에게 경고하는 것과 같은 다른 작업을 수행할 수도 있습니다.

완전한 InsertObject 함수 예

다음 코드 예는 오류 처리를 포함하는 하나의 완전한 함수로 결합된 이전 코드 조각을 보여 줍니다.

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)