Como usar o OLE em controles de edição avançada

Esta seção contém informações sobre como usar a vinculação e incorporação de objetos (OLE) em controles de edição avançada.

O que você precisa saber

Tecnologias

Pré-requisitos

  • C/C++
  • Programação da interface do usuário do Windows

Instruções

Usar uma interface de edição avançada

Os controles de edição avançada expõem algumas de suas funcionalidades por meio de interfaces COM (Component Object Model). Ao obter uma interface de um controle, você ganha a capacidade de trabalhar com outros objetos dentro do controle. Você pode obter essa interface enviando a mensagem EM_GETOLEINTERFACE. Na interface IRichEditOle, você pode obter interfaces usadas no modelo de objeto de texto.

Outra interface, IRichEditOleCallback, é implementada por aplicativos para definir o comportamento do controle quando ele interage com objetos.

Inserir um objeto em um controle de edição avançada

O exemplo de código a seguir insere um objeto File em um controle rich edit. Se um programa estiver associado ao tipo de arquivo na máquina do usuário (por exemplo, Microsoft Excel para um arquivo .xls), o conteúdo do arquivo será exibido no controle; caso contrário, um ícone será exibido.

  1. Obtenha a interface IRichEditOle.

    BOOL InsertObject(HWND hRichEdit, LPCTSTR pszFileName)
    {
        HRESULT hr;
    
        LPRICHEDITOLE pRichEditOle;
        SendMessage(hRichEdit, EM_GETOLEINTERFACE, 0, (LPARAM)&pRichEditOle);
    
        ...
    
  2. Criar armazenamento estruturado.

        LPLOCKBYTES pLockBytes = NULL;
        hr = CreateILockBytesOnHGlobal(NULL, TRUE, &pLockBytes);
    
        LPSTORAGE pStorage;
        hr = StgCreateDocfileOnILockBytes(pLockBytes, 
                                          STGM_SHARE_EXCLUSIVE | STGM_CREATE | STGM_READWRITE, 
                                          0, &pStorage);
        ...
    
  3. Configure o formato de dados.

        FORMATETC formatEtc;
    
        formatEtc.cfFormat = 0;
        formatEtc.ptd      = NULL;
        formatEtc.dwAspect = DVASPECT_CONTENT;
        formatEtc.lindex   = -1;
        formatEtc.tymed    = TYMED_NULL;
    
        ...
    
  4. Obtenha um ponteiro para o site de exibição.

        LPOLECLIENTSITE pClientSite;
        hr = pRichEditOle->GetClientSite(&pClientSite);
    
        ...
    
  5. Crie o objeto e recupere sua interface IUnknown .

        LPUNKNOWN pUnk;
        CLSID clsid = CLSID_NULL;
    
        hr = OleCreateFromFile(clsid, 
                               pszFileName, 
                               IID_IUnknown, 
                               OLERENDER_DRAW, 
                               &formatEtc, 
                               pClientSite, 
                               pStorage, 
                               (void**)&pUnk);
    
        pClientSite->Release();
    
        ...
    
  6. Obtenha a interface IOleObject para o objeto.

        LPOLEOBJECT pObject;
    
        hr = pUnk->QueryInterface(IID_IOleObject, (void**)&pObject);
    
        pUnk->Release();
    
        ...
    
  7. Para garantir que as referências sejam contadas corretamente, notifique o objeto de que ele está contido.

        OleSetContainedObject(pObject, TRUE);
    
        ...
    
  8. Configurar informações do objeto.

        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. Mova o cursor para o final do texto e adicione um retorno de carro.

        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. Insira o objeto.

        hr = pRichEditOle->InsertObject(&reobject);
    
        ...
    
  11. Limpar.

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

Usando IRichEditOleCallback

Os aplicativos implementam a interface IRichEditOleCallback para responder a consultas ou ações relacionadas ao OLE executadas por um controle de edição avançado. Você associa sua implementação da interface com o controle enviando uma mensagem EM_SETOLECALLBACK. Em seguida, o controle chama métodos em sua implementação da interface, conforme apropriado.

Por exemplo, QueryAcceptData é chamado quando o usuário tenta arrastar ou colar um objeto no controle. Se seu aplicativo puder aceitar os dados, sua implementação do método retornará S_OK; caso contrário, ele retornará um código de erro. O método também pode executar alguma outra ação, como avisar o usuário que arquivos desse tipo não podem ser colocados no controle.

Função de exemplo InsertObject completa

O exemplo de código a seguir demonstra os trechos de código anteriores combinados em uma função completa que inclui o tratamento de erros.

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;
}

Usando controles de edição avançada

Demonstração de controles comuns do Windows (CppWindowsCommonControls)