Gere uma pasta de trabalho a partir do Delphi, anote uma célula com a API clássica de comentários e o Excel 365 arquiva o seu texto em Anotações: uma caixa amarela à moda antiga, sem campo de resposta, sem avatar de autor, sem botão de resolver. O HotXLS escreve comentários encadeados genuínos do Excel 365 por meio de AddThreadedComment e AddThreadedReply no motor XLSX, emitindo a parte dedicada xl/threadedComments/threadedCommentN.xml por planilha e registrando cada autor na parte person, de nível de pasta de trabalho, de modo que a conversa que o seu código escreve é o mesmo objeto ao qual um revisor responde no Excel
A distinção importa porque os dois recursos só parecem iguais. Uma anotação é uma caixa de texto flutuante; um comentário encadeado é um registro de conversa com identificadores estáveis, uma árvore de respostas, um cadastro de autores e uma marca de resolvido — as coisas sobre as quais um fluxo de revisão de fato roda. Este artigo percorre primeiro a estrutura OOXML, porque, uma vez que você vê os dois modelos de armazenamento lado a lado, toda diferença de comportamento no Excel deixa de ser misteriosa
Por que meus comentários aparecem como anotações no Excel 365?
A resposta curta: duas gerações de comentário compartilham uma mesma grade e vivem em partes completamente diferentes do pacote. O modelo antigo — aquele que AddComment tem como alvo — guarda o texto em xl/comments1.xml (tipo de conteúdo application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml) e posiciona o balão por meio de uma parte de desenho VML companheira, xl/drawings/vmlDrawing1.vml. Esse par é anterior à faixa de opções; o Excel 365 ainda o lê fielmente, mas renderiza o resultado como uma "anotação" e não oferece interface de encadeamento nele, porque não há nada no armazenamento para encadear. O autor é uma string de exibição, a posição é uma forma VML, e esse é o modelo inteiro
Os comentários encadeados, introduzidos com o Excel 365, ignoram por completo a camada VML. Cada planilha com uma conversa carrega a própria parte xl/threadedComments/threadedCommentN.xml sob o tipo de conteúdo application/vnd.openxmlformats-officedocument.spreadsheetml.threadedComments+xml, e a pasta de trabalho carrega uma única parte xl/person/person.xml (tipo de conteúdo ...spreadsheetml.people+xml) listando cada participante uma vez. O HotXLS expõe os dois modelos na mesma planilha: AddComment continua escrevendo o par antigo, AddThreadedComment escreve as partes novas. Se a sua saída aparece como anotações, você chamou a primeira API e queria a segunda. O modelo antigo ainda é a ferramenta certa para alguns trabalhos — o artigo anterior sobre comentários de célula e hyperlinks em fluxos de revisão o cobre a fundo, inclusive do lado do XLS —, mas nada nele evolui para uma conversa
O que o HotXLS escreve dentro do pacote
O HotXLS modela cada resposta como um objeto TXLSXThreadedComment que carrega uma âncora de célula (Ref), um identificador em estilo GUID (Id), um ParentId opcional, um AuthorId que resolve pela lista de pessoas, um espelho DisplayName, o corpo do texto, uma marca Done e um DateTime em ISO-8601. Ao salvar, cada entrada vira um elemento <threadedComment> cujo atributo t guarda o identificador, cujo atributo dT guarda o carimbo de tempo e cujo atributo parentT — presente apenas em respostas filhas — nomeia o identificador do pai. O Excel reconstrói a árvore da conversa casando parentT com t; não há aninhamento no XML, apenas uma lista plana mais referências
A parte person é a peça que a maioria das implementações feitas à mão esquece. Todo authorId em um comentário encadeado precisa resolver para uma entrada <person> em xl/person/person.xml, ligada às relações da pasta de trabalho e com a própria substituição de tipo de conteúdo — do contrário o Excel não tem nome de exibição para mostrar. O HotXLS cuida do registro automaticamente: AddThreadedComment procura o autor na lista Persons da pasta pelo nome de exibição e cria uma entrada com um GUID novo quando nenhuma existe, de modo que comentários consecutivos do mesmo autor compartilhem uma identidade. As relações da planilha ganham a relação threadedComments, as relações da pasta ganham a relação de person, e o manifesto de tipos de conteúdo ganha as duas substituições, sem que nada disso apareça no seu código
Montando uma cadeia de respostas com AddThreadedComment e AddThreadedReply
AddThreadedComment cria a raiz da conversa: o ParentId dela fica vazio, e é isso que a marca como topo da conversa. AddThreadedReply recebe um parâmetro ParentRef — a referência de célula onde a raiz vive —, encontra a raiz naquela âncora e carimba o ParentId da nova resposta com o Id da raiz. As duas devolvem o novo TXLSXThreadedComment, então você pode definir o carimbo de tempo ou o estado de resolvido no objeto que acabou de criar:
var
Book: TXLSXWorkbook;
Sheet: TXLSXWorksheet;
Root: TXLSXThreadedComment;
begin
Book := TXLSXWorkbook.Create;
try
Book.Open('forecast.xlsx');
Sheet := Book.Sheets[0];
// Raiz da conversa; ParentId fica vazio
Root := Sheet.AddThreadedComment(8, 3,
'Q3 figure looks low against the pipeline export', 'Maria Ortiz');
Root.DateTime := '2026-07-06T09:12:00Z';
// As respostas ancoram na mesma célula; ParentRef nomeia a célula da raiz
Sheet.AddThreadedReply(8, 3, Root.Ref,
'Pipeline export missed the EMEA renewals, re-running', 'Jan Kowalski');
Sheet.AddThreadedReply(8, 3, Root.Ref,
'Confirmed, refreshed figure lands tomorrow', 'Maria Ortiz');
Book.SaveAs('forecast-reviewed.xlsx');
finally
Book.Free;
end;
end;
Dois detalhes dessa listagem compensam atenção. Primeiro, Root.Ref é passado em vez de uma string montada à mão: a referência que a biblioteca gerou tem garantia de casar com o que AddThreadedReply vai procurar, o que elimina toda uma classe de bugs de âncora deslocada por um. Segundo, os dois autores foram passados como simples nomes de exibição — o cadastro de pessoas, as identidades GUID e a ligação de authorId aconteceram todos por trás das chamadas. Abra o arquivo salvo no Excel 365 e a ancoragem na célula, a ordem das respostas e os dois participantes distintos estão todos vivos: clique em Responder e o Excel acrescenta à mesma conversa que o seu código começou
Lendo uma conversa de volta: comportamento de ida e volta
O HotXLS faz o percurso de ida e volta dos comentários encadeados desde a versão 2.122.0: reabrir um pacote salvo reconstrói a lista de conversas de cada planilha e a lista de participantes da pasta a partir das partes, de modo que identificadores, vínculos de resposta e nomes de exibição sobrevivem a um ciclo completo de leitura→escrita. O leitor analisa o person.xml antes de qualquer conteúdo de planilha, que é o que permite a todo authorId resolver para um nome de exibição na hora da carga; os identificadores de pessoa analisados são preservados como estão, e não regenerados, então uma pasta que vai e volta entre o seu código e o Excel mantém identidades de autor estáveis por quantos percursos você quiser
var
i: Integer;
Cmt: TXLSXThreadedComment;
begin
Book.Open('forecast-reviewed.xlsx');
Sheet := Book.Sheets[0];
for i := 0 to Sheet.ThreadedComments.Count - 1 do
begin
Cmt := Sheet.ThreadedComments[i];
if Cmt.ParentId = '' then
Writeln('Root at ', Cmt.Ref, ' by ', Cmt.DisplayName, ': ', Cmt.Text)
else
Writeln(' reply by ', Cmt.DisplayName, ': ', Cmt.Text);
end;
Writeln('Participants: ', Book.Persons.Count);
end;
O armazenamento em lista plana mais referências transparece aqui de propósito: ThreadedComments enumera as respostas na ordem da parte, e um ParentId vazio identifica cada raiz. Se você precisa do formato de árvore — digamos, para exportar um registro de revisão —, agrupe primeiro por Ref e depois encadeie ParentId a Id dentro do grupo de cada célula. Esse comportamento de preservar o que foi analisado é uma instância de uma política mais ampla da biblioteca; o artigo sobre percurso sem perdas de temas, listas de extensão e cadeia de cálculo cobre como o mesmo princípio se aplica ao resto do pacote
Estado de resolvido, carimbos de tempo e identidade de autor
Três atributos carregam a semântica de revisão, e os três são graváveis nos objetos devolvidos. Done mapeia para o atributo done — o Excel mostra uma conversa resolvida recolhida, com um link Reabrir. DateTime é o carimbo de criação em ISO-8601 UTC (dT); o HotXLS substitui por um espaço reservado fixo quando você o deixa vazio, para que a parte sempre valide, mas é um carimbo real que torna o histórico da conversa legível, então defina-o. Do lado da identidade, cada TXLSXPerson expõe ProviderId — em geral None para entradas criadas localmente — e um UserId que você pode preencher com um UPN ou e-mail quando a sua aplicação o conhece:
var
Root: TXLSXThreadedComment;
Person: TXLSXPerson;
begin
Root := Sheet.ThreadedComments.FindAt('D9');
if Root <> nil then
Root.Done := True; // salvo como done="1"; o Excel mostra a conversa resolvida
Person := Book.Persons.FindByDisplayName('Maria Ortiz');
if Person <> nil then
Person.UserId := '[email protected]';
end;
Um limite a enunciar com clareza: o HotXLS escreve o elemento <mentions> vazio. Os registros de menção com @ — a maquinaria que acende o nome de um colega dentro do texto do comentário e dispara uma notificação no Microsoft 365 — não são modelados, então um texto contendo um arroba é guardado como texto puro. Para uma pasta de revisão gerada isso raramente é uma perda, mas se o seu fluxo depende de notificações de menção, planeje para que uma pessoa as acrescente dentro do Excel. A identidade de autor na parte person combina naturalmente com os campos de procedência de nível de pasta tratados em metadados de pasta de trabalho e propriedades de documento, que é onde vive o resto da trilha de auditoria de um arquivo gerado
O que versões mais antigas do Excel fazem com comentários encadeados?
O Excel 2016 e anteriores são anteriores ao modelo encadeado, e simplesmente ignoram partes que não entendem. Quando o próprio Excel 365 salva uma conversa encadeada, ele também escreve uma sombra de comentário antigo — uma anotação de espaço reservado com o texto "[Threaded comment]…" — justamente para que versões mais antigas mostrem algo na célula ancorada. O HotXLS emite apenas as partes encadeadas, sem sombra antiga, então um arquivo escrito pelo seu código não mostra indicador de comentário nenhum quando aberto no Excel 2016. Se o seu público inclui instalações anteriores ao 365 e a anotação precisa ser visível lá, a API antiga AddComment continua sendo o canal compatível; só evite empilhar os dois modelos na mesma célula sem testar em todas as versões do Excel para as quais você distribui, porque como um leitor concilia uma anotação e uma conversa em uma célula é decisão do leitor, não sua
O outro limite duro é o próprio formato de arquivo. Comentários encadeados são uma estrutura OOXML sem contrapartida no BIFF8, então o lado .xls do HotXLS não tem API encadeada — uma pasta que precisa permanecer no formato binário antigo fica limitada às anotações clássicas. Na prática a tabela de decisão é curta: escrevendo .xlsx para o Excel 365 ou para leitores web e móveis do Excel, use AddThreadedComment e tenha conversas de verdade; mirando o Excel 2016 ou .xls, use AddComment e aceite o modelo de anotação; auditando um arquivo que você recebeu, cheque tanto ThreadedComments quanto Comments, porque uma pasta que viveu nos dois mundos pode legitimamente carregar os dois. A superfície completa de API das duas gerações está documentada na página do produto HotXLS Delphi Excel Component