Ler em inglês

Compartilhar via


IPaper::Save

O foco principal neste código de exemplo é como o COPaper pode carregar e salvar seus dados de papel em arquivos compostos. As implementações do método IPaper, Load e Save são discutidas detalhadamente.

Veja a seguir o método IPaper::Save de Paper.cpp.

STDMETHODIMP COPaper::CImpIPaper::Save(
                 SHORT nLockKey,
                 IStorage* pIStorage)
  {
    HRESULT hr = E_FAIL;
    IStream* pIStream;
    ULONG ulToWrite, ulWritten;

    if (OwnThis())
    {
      if (m_bLocked && m_cLockKey == nLockKey && NULL != pIStorage)
      {
        // Use the COM service to mark this compound file as one 
        // that is handled by our server component, DllPaper.
        WriteClassStg(pIStorage, CLSID_DllPaper);

        // Use the COM Service to write user-readable clipboard 
        // format into the compound file.
        WriteFmtUserTypeStg(pIStorage, m_ClipBdFmt, 
                            TEXT(CLIPBDFMT_STR));

        // Create the stream to be used for the actual paper data.
        // Call it "PAPERDATA".
        hr = pIStorage->CreateStream(
               STREAM_PAPERDATA_USTR,
        STGM_CREATE | STGM_WRITE | STGM_DIRECT | STGM_SHARE_EXCLUSIVE,
               0,
               0,
               &pIStream);
        if (SUCCEEDED(hr))
        {
          // Obtained a stream. Write data to it.
          // First, write PAPER_PROPERTIES structure.
          m_PaperProperties.lInkArraySize = m_lInkDataEnd+1;
          m_PaperProperties.crWinColor = m_crWinColor;
          m_PaperProperties.WinRect.right = m_WinRect.right;
          m_PaperProperties.WinRect.bottom = m_WinRect.bottom;
          ulToWrite = sizeof(PAPER_PROPERTIES);
          hr = pIStream->Write(&m_Paper_Properties, ulToWrite, 
                               &ulWritten);
          if (SUCCEEDED(hr) && ulToWrite != ulWritten)
            hr = STG_E_CANTSAVE;
          if (SUCCEEDED(hr))
          {
            // Now, write the complete array of Ink Data.
            ulToWrite = m_PaperProperties.lInkArraySize * 
                                                     sizeof(INKDATA);
            hr = pIStream->Write(m_paInkData, ulToWrite, &ulWritten);
            if (SUCCEEDED(hr) && ulToWrite != ulWritten)
              hr = STG_E_CANTSAVE;
          }

          // Release the stream.
          pIStream->Release();
        }
      }

      UnOwnThis();
    }

    // Notify all other connected clients that Paper is now saved.
    if (SUCCEEDED(hr))
      m_pBackObj->NotifySinks(PAPER_EVENT_SAVED, 0, 0, 0, 0);

    return hr;
  }

Nessa relação de cliente e servidor, o COPaper não cria o arquivo composto usado para armazenar dados de papel. Para os métodos Salvar e Carregar , o cliente passa um ponteiro de interface IStorage para um arquivo composto existente. Em seguida, ele usa o IStorage para gravar e ler dados nesse arquivo composto. Em IPaper::Save acima, vários tipos de dados são armazenados.

O CLSID para DllPaper, CLSID_DllPaper, é serializado e armazenado em um fluxo especial controlado por COM dentro do objeto de armazenamento chamado "\001CompObj". A função de serviço WriteClassStg executa esse armazenamento. Esses dados CLSID armazenados podem ser usados para associar o conteúdo de armazenamento ao componente DllPaper que criou e pode interpretá-lo. Neste exemplo, o armazenamento raiz é passado por StoClien e, portanto, todo o arquivo composto está associado ao componente DllPaper. Esses dados CLSID podem ser recuperados posteriormente com uma chamada para a função de serviço ReadClassStg .

Como o DllPaper lida com dados editáveis, também é apropriado registrar um formato de área de transferência no armazenamento. A função de serviço WriteFmtUserTypeStg é chamada para armazenar uma designação de formato de área de transferência e um nome legível pelo usuário para o formato. O nome legível pelo usuário destina-se à exibição de GUI em listas de seleção. O nome passado acima usa uma macro, CLIPBDFMT_STR, que é definida como "DllPaper 1.0" em Paper.h. Esses dados armazenados da área de transferência podem ser recuperados posteriormente com uma chamada para a função de serviço ReadFmtUserTypeStg. Essa função retorna um valor de cadeia de caracteres alocado usando o alocador de memória da tarefa. O chamador é responsável por liberar a cadeia de caracteres.

Salvar em seguida cria um fluxo no armazenamento para os dados de papel COPaper. O fluxo é chamado de "PAPERDATA" e é passado usando a macro STREAM_PAPERDATA_USTR. O método IStorage::CreateStream exige que essa cadeia de caracteres esteja em Unicode. Como a cadeia de caracteres é corrigida em tempo de compilação, a macro é definida como Unicode em Paper.h.

#define STREAM_PAPERDATA_USTR L"PAPERDATA"

O 'L' antes da cadeia de caracteres, indicando LONG, consegue isso.

O método CreateStream cria e abre um fluxo dentro do armazenamento especificado. Um ponteiro de interface IStream para o novo fluxo é passado em uma variável de ponteiro de interface do chamador. AddRef é chamado nesse ponteiro de interface no CreateStream e o chamador deve liberar esse ponteiro depois de usá-lo. O método CreateStream é passado por vários sinalizadores de modo de acesso, da seguinte maneira.

STGM_CREATE | STGM_WRITE | STGM_DIRECT | STGM_SHARE_EXCLUSIVE

STGM_CREATE cria um novo fluxo ou substitui um existente com o mesmo nome. STGM_WRITE abre o fluxo com permissão de gravação. STGM_DIRECT abre o fluxo para acesso direto, em vez de acesso transacionado. STGM_SHARE_EXCLUSIVE abre o arquivo para uso exclusivo e não compartilhado pelo chamador.

Depois que o fluxo PAPERDATA for criado com êxito, a interface IStream será usada para gravar no fluxo. O método IStream::Write é usado para primeiro armazenar o conteúdo da estrutura PAPER_PROPERTIES. Esse é essencialmente um cabeçalho de propriedades na frente do fluxo. Como o número de versão é a primeira coisa no arquivo, ele pode ser lido independentemente para determinar como lidar com os dados a seguir. Se a quantidade de dados realmente gravada não for igual ao valor solicitado, o método Save será anulado e retornará STG_E_CANTSAVE.

Salvar toda a matriz de dados de tinta no fluxo é simples.

// Now write the complete array of Ink Data.
  ulToWrite = m_PaperProperties.lInkArraySize * sizeof(INKDATA);
  hr = pIStream->Write(m_paInkData, ulToWrite, &ulWritten);
  if (SUCCEEDED(hr) && ulToWrite != ulWritten)
    hr = STG_E_CANTSAVE;

Como o método IStream::Write opera em uma matriz de bytes, o número de bytes de dados de tinta armazenados na matriz é calculado e a operação de gravação começa no início da matriz. Se a quantidade de dados realmente gravados não for igual ao valor solicitado, o método Save retornará STG_E_CANTSAVE.

Depois que o fluxo é gravado, o método IPaper::Save libera o ponteiro IStream que estava usando.

O método Save também chama o cliente IPaperSink (no método NotifySinks interno do COPaper) para notificar o cliente de que a operação de salvamento está concluída. Neste ponto, o método Save retorna ao cliente de chamada, que normalmente libera o ponteiro IStorage .