Estou usando a interoperabilidade do Excel em C # ( ApplicationClass
) e coloquei o seguinte código na minha cláusula finally:
while (System.Runtime.InteropServices.Marshal.ReleaseComObject(excelSheet) != 0) { }
excelSheet = null;
GC.Collect();
GC.WaitForPendingFinalizers();
Apesar desse tipo de trabalho, o Excel.exe
processo ainda está em segundo plano, mesmo depois que eu fecho o Excel. Ele é liberado apenas quando meu aplicativo é fechado manualmente.
O que estou fazendo de errado ou existe uma alternativa para garantir que os objetos de interoperabilidade sejam descartados corretamente?
c#
excel
interop
com-interop
HAdes
fonte
fonte
Respostas:
O Excel não fecha porque seu aplicativo ainda mantém referências a objetos COM.
Eu acho que você está invocando pelo menos um membro de um objeto COM sem atribuí-lo a uma variável.
Para mim, foi o objeto excelApp.Worksheets que eu usei diretamente sem atribuí-lo a uma variável:
Eu não sabia que internamente o C # criava um invólucro para o objeto COM de planilhas que não era liberado pelo meu código (porque eu não sabia disso) e era a causa pela qual o Excel não era descarregado.
Encontrei a solução para o meu problema nesta página , que também possui uma boa regra para o uso de objetos COM em C #:
Portanto, com esse conhecimento, a maneira correta de fazer o acima é:
ATUALIZAÇÃO PÓS-MORTEM:
Quero que todos os leitores leiam essa resposta de Hans Passant com muito cuidado, pois explica a armadilha em que eu e muitos outros desenvolvedores nos deparamos. Quando escrevi essa resposta anos atrás, não sabia o efeito que o depurador causava no coletor de lixo e tirei conclusões erradas. Eu mantenho minha resposta inalterada para o bem da história, mas por favor leia este link e não siga o caminho dos "dois pontos": Entendendo a coleta de lixo no .NET e Limpar objetos de interoperabilidade do Excel com IDisposable
fonte
Você pode realmente liberar seu objeto Aplicativo do Excel de maneira limpa, mas é necessário ter cuidado.
O conselho para manter uma referência nomeada para absolutamente todos os objetos COM que você acessa e depois liberá-lo explicitamente
Marshal.FinalReleaseComObject()
é correto em teoria, mas, infelizmente, é muito difícil de gerenciar na prática. Se alguém deslizar para algum lugar e usar "dois pontos" ou iterar células por meio de umfor each
iterar loop ou qualquer outro tipo de comando semelhante, você terá objetos COM não referenciados e corre o risco de travar. Nesse caso, não haveria maneira de encontrar a causa no código; você precisaria revisar todo o seu código a olho nu e, esperançosamente, encontrar a causa, uma tarefa que poderia ser quase impossível para um projeto grande.A boa notícia é que você realmente não precisa manter uma referência de variável nomeada para todos os objetos COM que você usa. Em vez disso, chame
GC.Collect()
e, em seguida,GC.WaitForPendingFinalizers()
libere todos os objetos (geralmente menores) aos quais você não mantém uma referência e libere explicitamente os objetos aos quais você mantém uma referência de variável nomeada.Você também deve liberar suas referências nomeadas em ordem inversa de importância: alcance primeiro os objetos, depois as planilhas, as pastas de trabalho e, finalmente, o objeto Aplicativo do Excel.
Por exemplo, supondo que você tenha uma variável de objeto Range denominada
xlRng
, uma variável de planilha denominadaxlSheet
, uma variável de pasta de trabalho denominadaxlBook
e uma variável de aplicativo do Excel denominadaxlApp
, seu código de limpeza poderá ter a seguinte aparência:Na maioria dos exemplos de código que você verá para limpar objetos COM do .NET, as chamadas
GC.Collect()
eGC.WaitForPendingFinalizers()
são feitas DUAS VEZES como em:Entretanto, isso não deve ser necessário, a menos que você esteja usando o VSTO (Visual Studio Tools for Office), que usa finalizadores que fazem com que um gráfico inteiro de objetos seja promovido na fila de finalização. Esses objetos não seriam liberados até a próxima coleta de lixo. No entanto, se você não estiver usando o VSTO, poderá ligar
GC.Collect()
eGC.WaitForPendingFinalizers()
apenas uma vez.Eu sei que ligar explicitamente
GC.Collect()
é um não-não (e certamente fazê-lo duas vezes parece muito doloroso), mas não há como contornar isso, para ser honesto. Por meio de operações normais, você gerará objetos ocultos aos quais não mantém nenhuma referência que, portanto, não pode liberar por qualquer outro meio que não seja a chamadaGC.Collect()
.Este é um tópico complexo, mas isso realmente é tudo o que existe. Depois de estabelecer esse modelo para o procedimento de limpeza, você pode codificar normalmente, sem a necessidade de invólucros, etc. :-)
Eu tenho um tutorial sobre isso aqui:
Automatizando programas do Office com interoperabilidade VB.Net / COM
Ele foi escrito para o VB.NET, mas não se deixe levar por isso, os princípios são exatamente os mesmos que quando se usa C #.
fonte
Prefácio: minha resposta contém duas soluções; portanto, tenha cuidado ao ler e não perca nada.
Existem diferentes maneiras e conselhos de como descarregar a instância do Excel, como:
Liberando TODOS os objetos com explicitamente com Marshal.FinalReleaseComObject () (sem esquecer os objetos com implicitamente criados). Para liberar todos os objetos com criados, você pode usar a regra de 2 pontos mencionados aqui:
Como faço para limpar corretamente os objetos de interoperabilidade do Excel?
Chamando GC.Collect () e GC.WaitForPendingFinalizers () para fazer com que o CLR libere objetos-com não utilizados * (Na verdade, ele funciona, consulte minha segunda solução para obter detalhes)
Verificando se o aplicativo com-servidor talvez mostre uma caixa de mensagem aguardando a resposta do usuário (embora não tenha certeza de que ele possa impedir o Excel de fechar, mas ouvi falar algumas vezes)
Enviando mensagem WM_CLOSE para a janela principal do Excel
Executando a função que funciona com o Excel em um AppDomain separado. Algumas pessoas acreditam que a instância do Excel será fechada quando o AppDomain for descarregado.
Matar todas as instâncias do Excel que foram instanciadas após o início do código de interoperabilidade do Excel.
MAS!Às vezes, todas essas opções simplesmente não ajudam ou não podem ser apropriadas!
Por exemplo, ontem descobri que em uma das minhas funções (que funciona com o Excel) o Excel continua em execução após o término da função. Eu tentei de tudo! Eu verifiquei minuciosamente toda a função 10 vezes e adicionei Marshal.FinalReleaseComObject () para tudo! Eu também tinha GC.Collect () e GC.WaitForPendingFinalizers (). Eu verifiquei as caixas de mensagens ocultas. Tentei enviar a mensagem WM_CLOSE para a janela principal do Excel. Eu executei minha função em um AppDomain separado e descarreguei esse domínio. Nada ajudou! A opção de fechar todas as instâncias do Excel é inadequada, pois se o usuário iniciar outra instância do Excel manualmente, durante a execução da minha função que também funciona com o Excel, essa instância também será fechada pela minha função. Aposto que o usuário não será feliz! Então, honestamente, essa é uma opção esfarrapada (sem ofensas).solução : Mate o processo do excel por hWnd de sua janela principal (é a primeira solução).
Aqui está o código simples:
Como você pode ver, forneci dois métodos, de acordo com o padrão Try-Parse (acho que é apropriado aqui): um método não lança a exceção se o Processo não puder ser eliminado (por exemplo, o processo não existe mais) , e outro método lança a exceção se o Processo não foi morto. O único ponto fraco desse código são as permissões de segurança. Teoricamente, o usuário pode não ter permissões para interromper o processo, mas em 99,99% de todos os casos, o usuário tem essas permissões. Também testei com uma conta de convidado - funciona perfeitamente.
Portanto, seu código, trabalhando com o Excel, pode ficar assim:
Voila! Excel é encerrado! :)
Ok, vamos voltar para a segunda solução, como prometi no início do post. A segunda solução é chamar GC.Collect () e GC.WaitForPendingFinalizers (). Sim, eles realmente funcionam, mas você precisa ter cuidado aqui!
Muitas pessoas dizem (e eu disse) que ligar para GC.Collect () não ajuda. Mas a razão pela qual não ajudaria é se ainda houver referências a objetos COM! Um dos motivos mais populares para o GC.Collect () não ser útil é executar o projeto no modo Debug. No modo de depuração, os objetos que realmente não são mais referenciados não serão coletados como lixo até o final do método.
Portanto, se você tentou GC.Collect () e GC.WaitForPendingFinalizers () e não ajudou, tente fazer o seguinte:
1) Tente executar seu projeto no modo Release e verifique se o Excel foi fechado corretamente
2) Enrole o método de trabalho com o Excel em um método separado. Então, em vez de algo como isto:
você escreve:
Agora, o Excel fechará =)
fonte
UPDATE : Adicionado código C # e link para trabalhos do Windows
Passei algum tempo tentando descobrir esse problema e, na época, o XtremeVBTalk era o mais ativo e responsivo. Aqui está um link para minha postagem original, Fechando um processo de interoperabilidade do Excel de maneira limpa, mesmo se o aplicativo falhar . Abaixo está um resumo da postagem e o código copiado para esta postagem.
Application.Quit()
eProcess.Kill()
funciona para a maior parte, mas não consegue se os aplicativos falhar catastroficamente. Ou seja, se o aplicativo falhar, o processo do Excel ainda estará solto.Eu achei que essa era uma solução limpa porque o sistema operacional está realizando um trabalho real de limpeza. Tudo que você precisa fazer é registrar o processo do Excel.
Código de tarefa do Windows
Quebra as chamadas de API do Win32 para registrar processos de interoperabilidade.
Nota sobre o código do construtor
info.LimitFlags = 0x2000;
é chamado.0x2000
é oJOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
valor da enumeração e esse valor é definido pelo MSDN como:Chamada extra da API do Win32 para obter o ID do processo (PID)
Usando o código
fonte
Isso funcionou para um projeto no qual eu estava trabalhando:
Aprendemos que era importante definir todas as referências a um objeto COM do Excel como nulo quando você terminasse. Isso incluía células, folhas e tudo mais.
fonte
Qualquer coisa que esteja no espaço para nome do Excel precisa ser liberada. Período
Você não pode estar fazendo:
Você tem que estar fazendo
seguido pela liberação dos objetos.
fonte
Primeiro - você nunca precisa ligar
Marshal.ReleaseComObject(...)
ouMarshal.FinalReleaseComObject(...)
fazer interoperabilidade no Excel. É um anti-padrão confuso, mas qualquer informação sobre isso, inclusive da Microsoft, que indique que você deve liberar manualmente as referências COM do .NET está incorreta. O fato é que o tempo de execução .NET e o coletor de lixo controlam e limpam corretamente as referências COM. Para o seu código, isso significa que você pode remover todo o loop `while (...) na parte superior.Segundo, se você deseja garantir que as referências COM a um objeto COM fora de processo sejam limpas quando o processo terminar (para que o processo do Excel seja fechado), você deverá garantir que o coletor de lixo seja executado. Você faz isso corretamente com chamadas para
GC.Collect()
eGC.WaitForPendingFinalizers()
. Chamar isso duas vezes é seguro e garante que os ciclos também sejam definitivamente limpos (embora eu não tenha certeza de que seja necessário e que aprecie um exemplo que mostre isso).Terceiro, quando executadas no depurador, as referências locais serão artificialmente mantidas ativas até o final do método (para que a inspeção de variáveis locais funcione). Portanto, as
GC.Collect()
chamadas não são eficazes para limpar objetos comorng.Cells
no mesmo método. Você deve dividir o código que está fazendo a interoperabilidade COM da limpeza do GC em métodos separados. (Esta foi uma descoberta importante para mim, de uma parte da resposta postada aqui por @nightcoder.)O padrão geral seria assim:
Há muitas informações falsas e confusão sobre esse problema, incluindo muitas postagens no MSDN e no Stack Overflow (e especialmente nesta pergunta!).
O que finalmente me convenceu a olhar mais de perto e descobrir o conselho certo foi o post no blog Marshal.ReleaseComObject Considered Dangerous, além de encontrar o problema com referências mantidas vivas no depurador que estava confundindo meus testes anteriores.
fonte
Eu encontrei um modelo genérico úteis que podem ajudar a implementar o padrão de descarte correto para objetos COM, essa necessidade Marshal.ReleaseComObject chamado quando eles saem de escopo:
Uso:
Modelo:
Referência:
http://www.deez.info/sengelha/2005/02/11/useful-idisposable-class-3-autoreleasecomobject/
fonte
Não acredito que esse problema assombre o mundo há cinco anos ... Se você criou um aplicativo, é necessário desligá-lo primeiro antes de remover o link.
ao fechar
Quando você cria um aplicativo Excel, ele abre um programa Excel em segundo plano. Você precisa comandar o encerramento do programa do Excel antes de liberar o link, porque esse programa do Excel não faz parte do seu controle direto. Portanto, ele permanecerá aberto se o link for lançado!
Boa programação a todos ~~
fonte
Desenvolvedores comuns, nenhuma de suas soluções funcionou para mim, então eu decido implementar um novo truque .
Primeiro vamos especificar "Qual é o nosso objetivo?" => "Não ver o objeto do Excel após nosso trabalho no gerenciador de tarefas"
Está bem. Não deixe de desafiar e comece a destruí-lo, mas considere não destruir outra instância do Excel que esteja sendo executada em paralelo.
Portanto, obtenha a lista de processadores atuais e obtenha o PID dos processos EXCEL; depois que seu trabalho estiver concluído, teremos um novo convidado na lista de processos com um PID exclusivo, localize e destrua apenas esse.
<lembre-se de que qualquer novo processo do Excel durante o seu trabalho do Excel será detectado como novo e destruído> <Uma solução melhor é capturar o PID do novo objeto criado do Excel e apenas destruí-lo>
Isso resolve o meu problema, espero que o seu também.
fonte
Isso com certeza parece ter sido muito complicado. De acordo com minha experiência, existem apenas três itens principais para que o Excel seja fechado corretamente:
1: verifique se não há referências restantes para o aplicativo excel que você criou (você só deve ter um de qualquer maneira; defina-o como
null
)2: ligar
GC.Collect()
3: O Excel deve ser fechado, pelo usuário que fecha o programa manualmente ou por você chamar
Quit
o objeto do Excel. (Observe queQuit
funcionará como se o usuário tentasse fechar o programa e apresentará uma caixa de diálogo de confirmação se houver alterações não salvas, mesmo que o Excel não esteja visível. O usuário pode pressionar cancelar e o Excel não será fechado. )1 precisa acontecer antes de 2, mas 3 pode acontecer a qualquer momento.
Uma maneira de implementar isso é agrupar o objeto de interoperabilidade do Excel com sua própria classe, criar a instância de interoperabilidade no construtor e implementar IDisposable com Dispose parecido com
Isso limpará o Excel do lado das coisas do seu programa. Depois que o Excel for fechado (manualmente pelo usuário ou por você ligando
Quit
), o processo desaparecerá. Se o programa já foi fechado, o processo desaparecerá naGC.Collect()
chamada.(Não tenho certeza do quanto é importante, mas você pode querer uma
GC.WaitForPendingFinalizers()
ligação após aGC.Collect()
ligação, mas não é estritamente necessário se livrar do processo do Excel.)Isso funcionou para mim sem problemas por anos. Lembre-se de que, enquanto isso funciona, você realmente precisa fechar normalmente para que funcione. Você ainda acumulará processos excel.exe se interromper o programa antes da limpeza do Excel (geralmente pressionando "stop" enquanto o programa está sendo depurado).
fonte
Marshal
.Para adicionar aos motivos pelos quais o Excel não fecha, mesmo quando você cria referências diretas para cada objeto na leitura, criação, é o loop 'For'.
fonte
Tradicionalmente, segui os conselhos encontrados na resposta do VVS . No entanto, em um esforço para manter essa resposta atualizada com as opções mais recentes, acho que todos os meus projetos futuros usarão a biblioteca "NetOffice".
O NetOffice é um substituto completo para as PIAs do Office e é totalmente independente da versão. É uma coleção de wrappers COM gerenciados que podem lidar com a limpeza que geralmente causa essas dores de cabeça ao trabalhar com o Microsoft Office no .NET.
Alguns recursos principais são:
Eu não sou de forma alguma afiliado ao projeto; Eu realmente aprecio genuinamente a redução gritante de dores de cabeça.
fonte
A resposta aceita aqui está correta, mas também observe que não apenas as referências de "dois pontos" precisam ser evitadas, mas também objetos recuperados por meio do índice. Você também não precisa esperar até terminar o programa para limpar esses objetos; é melhor criar funções que os limpem assim que possível, quando possível. Aqui está uma função que eu criei que atribui algumas propriedades de um objeto Style chamado
xlStyleHeader
:Observe que eu precisei definir
xlBorders[Excel.XlBordersIndex.xlEdgeBottom]
uma variável para limpar isso (não por causa dos dois pontos, que se referem a uma enumeração que não precisa ser liberada, mas porque o objeto ao qual estou me referindo é realmente um objeto Border isso precisa ser liberado).Esse tipo de coisa não é realmente necessário em aplicativos padrão, que fazem um ótimo trabalho de limpeza após eles mesmos, mas nos aplicativos ASP.NET, se você perder um deles, não importa quantas vezes você chame o coletor de lixo, o Excel irá ainda está sendo executado no seu servidor.
Ele requer muita atenção aos detalhes e muitas execuções de teste enquanto monitora o Gerenciador de Tarefas ao escrever esse código, mas evita o incômodo de procurar desesperadamente pelas páginas de código para encontrar a instância que você perdeu. Isso é especialmente importante ao trabalhar em loops, onde você precisa liberar CADA INSTÂNCIA de um objeto, mesmo que ele use o mesmo nome de variável cada vez que fizer um loop.
fonte
Depois de tentar
GC.Collect()
eGC.WaitForPendingFinalizers()
duas vezes no finala solução final que funciona para mim é mover um conjunto de
que adicionamos ao final da função em um wrapper, da seguinte maneira:
fonte
Eu segui exatamente isso ... Mas ainda enfrentei os problemas 1 em cada 1000 vezes. Quem sabe o porquê. Hora de trazer o martelo ...
Logo depois que a classe Aplicativo do Excel é instanciada, recebo o processo do Excel que acabou de ser criado.
Depois de concluir toda a limpeza COM acima, verifique se o processo não está em execução. Se ainda estiver em execução, mate-o!
fonte
¨ º º¤ø „¸ Atire no Excel e mastigue chiclete ¸„ ø¤º ° ¨
fonte
Você precisa estar ciente de que o Excel também é muito sensível à cultura em que você está executando.
Você pode achar que precisa definir a cultura como EN-US antes de chamar as funções do Excel. Isso não se aplica a todas as funções - mas a algumas delas.
Isso se aplica mesmo se você estiver usando o VSTO.
Para detalhes: http://support.microsoft.com/default.aspx?scid=kb;en-us;Q320369
fonte
"Nunca use dois pontos com objetos COM" é uma ótima regra geral para evitar vazamentos de referências COM, mas o Excel PIA pode causar vazamentos de mais maneiras do que aparentes à primeira vista.
Uma dessas maneiras é inscrever-se em qualquer evento exposto por qualquer um dos objetos COM do modelo de objeto do Excel.
Por exemplo, assinando o evento WorkbookOpen da classe Application.
Alguma teoria sobre eventos COM
As classes COM expõem um grupo de eventos por meio de interfaces de retorno de chamada. Para se inscrever em eventos, o código do cliente pode simplesmente registrar um objeto implementando a interface de retorno de chamada e a classe COM invocará seus métodos em resposta a eventos específicos. Como a interface de retorno de chamada é uma interface COM, é dever do objeto de implementação diminuir a contagem de referência de qualquer objeto COM que ele recebe (como parâmetro) para qualquer manipulador de eventos.
Como o Excel PIA expõe eventos COM
O Excel PIA expõe eventos COM da classe Aplicativo Excel como eventos .NET convencionais. Sempre que o código do cliente se inscreve em um evento .NET (ênfase em 'a'), o PIA cria uma instância de uma classe implementando a interface de retorno de chamada e a registra no Excel.
Portanto, vários objetos de retorno de chamada são registrados no Excel em resposta a diferentes solicitações de assinatura do código .NET. Um objeto de retorno de chamada por assinatura de evento.
Uma interface de retorno de chamada para manipulação de eventos significa que, o PIA precisa se inscrever em todos os eventos da interface para cada solicitação de inscrição de evento .NET. Não pode escolher e escolher. Ao receber um retorno de chamada de evento, o objeto de retorno de chamada verifica se o manipulador de eventos .NET associado está interessado no evento atual ou não e, em seguida, invoca o manipulador ou ignora silenciosamente o retorno de chamada.
Efeito nas contagens de referência da instância COM
Todos esses objetos de retorno de chamada não diminuem a contagem de referência de nenhum dos objetos COM que eles recebem (como parâmetros) para qualquer um dos métodos de retorno de chamada (mesmo para os que são ignorados silenciosamente). Eles contam exclusivamente com o coletor de lixo CLR para liberar os objetos COM.
Como a execução do GC é não determinística, isso pode levar à suspensão do processo do Excel por um período maior que o desejado e criar uma impressão de um 'vazamento de memória'.
Solução
A única solução a partir de agora é evitar o provedor de eventos da PIA para a classe COM e escrever seu próprio provedor de eventos, que libera deterministicamente objetos COM.
Para a classe Application, isso pode ser feito implementando a interface AppEvents e registrando a implementação no Excel usando a interface IConnectionPointContainer . A classe Application (e todos os objetos COM que expõem eventos usando o mecanismo de retorno de chamada) implementa a interface IConnectionPointContainer.
fonte
Como outros já apontaram, você precisa criar uma referência explícita para cada objeto do Excel que você usa e chamar Marshal.ReleaseComObject nessa referência, conforme descrito neste artigo da Base de Dados de Conhecimento . Você também precisa usar o try / finalmente para garantir que o ReleaseComObject seja sempre chamado, mesmo quando uma exceção é lançada. Ou seja, em vez de:
você precisa fazer algo como:
Você também precisa chamar Application.Quit antes de liberar o objeto Application se desejar que o Excel feche.
Como você pode ver, isso rapidamente se torna extremamente pesado assim que você tenta fazer algo que seja moderadamente complexo. Desenvolvi aplicativos .NET com êxito com uma classe de wrapper simples que envolve algumas manipulações simples do modelo de objeto do Excel (abra uma pasta de trabalho, grave em um Range, salve / feche a pasta de trabalho etc.). A classe de wrapper implementa IDisposable, implementa cuidadosamente Marshal.ReleaseComObject em todos os objetos que usa e não expõe pubicamente nenhum objeto do Excel para o restante do aplicativo.
Mas essa abordagem não é adequada para requisitos mais complexos.
Essa é uma grande deficiência do .NET COM Interop. Para cenários mais complexos, eu consideraria seriamente escrever uma DLL ActiveX no VB6 ou outra linguagem não gerenciada na qual você possa delegar toda a interação com objetos COM de processo externo, como o Office. Em seguida, você pode fazer referência a esta DLL ActiveX do seu aplicativo .NET e as coisas ficarão muito mais fáceis, pois você precisará liberar apenas essa referência.
fonte
Quando todo o material acima não funcionou, tente dar ao Excel algum tempo para fechar suas folhas:
fonte
Certifique-se de liberar todos os objetos relacionados ao Excel!
Passei algumas horas tentando de várias maneiras. Todas são ótimas idéias, mas finalmente encontrei meu erro: se você não liberar todos os objetos, nenhuma das maneiras acima poderá ajudá-lo no meu caso. Certifique-se de liberar todos os objetos, incluindo o alcance um!
As opções estão juntas aqui .
fonte
Um ótimo artigo sobre a liberação de objetos COM é o 2.5 Liberando Objetos COM (MSDN).
O método que eu defenderia é anular as referências do Excel.Interop se elas forem variáveis não locais e, em seguida, chamar
GC.Collect()
eGC.WaitForPendingFinalizers()
duas vezes. As variáveis de interoperabilidade com escopo local serão tratadas automaticamente.Isso elimina a necessidade de manter uma referência nomeada para cada objeto COM.
Aqui está um exemplo retirado do artigo:
Estas palavras são diretas do artigo:
fonte
A regra dos dois pontos não funcionou para mim. No meu caso, criei um método para limpar meus recursos da seguinte maneira:
fonte
Minha solução
fonte
Você deve ter muito cuidado ao usar aplicativos de interoperabilidade Word / Excel. Depois de experimentar todas as soluções, ainda tínhamos muito processo "WinWord" aberto no servidor (com mais de 2000 usuários).
Depois de trabalhar no problema por horas, percebi que, se eu abrir mais do que alguns documentos usando
Word.ApplicationClass.Document.Open()
segmentos diferentes simultaneamente, o processo de trabalho do IIS (w3wp.exe) trava, deixando todos os processos do WinWord abertos!Portanto, acho que não há solução absoluta para esse problema, mas a mudança para outros métodos, como o desenvolvimento do Office Open XML .
fonte
A resposta aceita não funcionou para mim. O código a seguir no destruidor fez o trabalho.
fonte
Atualmente, estou trabalhando na automação do Office e encontrei uma solução para isso que funciona sempre para mim. É simples e não envolve matar nenhum processo.
Parece que apenas percorrendo os processos ativos atuais e de alguma forma 'acessando' um processo aberto do Excel, qualquer instância suspensa perdida do Excel será removida. O código abaixo simplesmente verifica processos onde o nome é 'Excel' e, em seguida, grava a propriedade MainWindowTitle do processo em uma cadeia de caracteres. Essa 'interação' com o processo parece fazer o Windows recuperar e abortar a instância congelada do Excel.
Eu executo o método abaixo pouco antes do encerramento do suplemento que estou desenvolvendo, pois ele dispara o evento de descarregamento. Ele remove todas as instâncias suspensas do Excel sempre. Com toda a honestidade, não sei ao certo por que isso funciona, mas funciona bem para mim e pode ser colocado no final de qualquer aplicativo do Excel sem ter que se preocupar com pontos duplos, Marshal.ReleaseComObject, nem processos de extermínio. Eu ficaria muito interessado em alguma sugestão sobre por que isso é eficaz.
fonte
Eu acho que isso é apenas o modo como a estrutura lida com aplicativos do Office, mas eu posso estar errado. Em alguns dias, alguns aplicativos limpam os processos imediatamente e outros dias parecem esperar até que o aplicativo seja fechado. Em geral, parei de prestar atenção aos detalhes e apenas certifique-se de que não haja nenhum processo extra flutuando no final do dia.
Além disso, e talvez eu esteja simplificando demais as coisas, mas acho que você pode ...
Como eu disse anteriormente, não costumo prestar atenção nos detalhes de quando o processo do Excel aparece ou desaparece, mas isso geralmente funciona para mim. Também não gosto de manter os processos do Excel por mais tempo do que o mínimo, mas provavelmente estou paranóico nisso.
fonte
Como alguns provavelmente já escreveram, não é importante apenas como você fecha o Excel (objeto); também é importante como você o abre e também pelo tipo de projeto.
Em um aplicativo WPF, basicamente o mesmo código está funcionando sem ou com muito poucos problemas.
Eu tenho um projeto no qual o mesmo arquivo do Excel está sendo processado várias vezes para diferentes valores de parâmetros - por exemplo, analisando-os com base em valores dentro de uma lista genérica.
Coloquei todas as funções relacionadas ao Excel na classe base e o analisamos em uma subclasse (diferentes analisadores usam funções comuns do Excel). Eu não queria que o Excel fosse aberto e fechado novamente para cada item em uma lista genérica; portanto, eu o abri apenas uma vez na classe base e o fechei na subclasse. Tive problemas ao mover o código para um aplicativo de desktop. Eu tentei muitas das soluções mencionadas acima.
GC.Collect()
já foi implementado antes, o dobro do sugerido.Decidi então mover o código para abrir o Excel em uma subclasse. Em vez de abrir apenas uma vez, agora crio um novo objeto (classe base) e abro o Excel para cada item e o fecho no final. Há alguma penalidade no desempenho, mas com base em vários testes, os processos do Excel estão fechando sem problemas (no modo de depuração), portanto, os arquivos temporários são removidos. Continuarei com os testes e escreverei um pouco mais se receber algumas atualizações.
A linha inferior é: Você também deve verificar o código de inicialização, especialmente se você tiver muitas classes, etc.
fonte