Cierre del proceso de solicitud de Excel en C#después del acceso a los datos
visual-studio-2012 excel-interop (12)
Basado en otras soluciones Lo he usado:
IntPtr xAsIntPtr = new IntPtr(excelObj.Application.Hwnd);
excelObj.ActiveWorkbook.Close();
System.Diagnostics.Process[] process = System.Diagnostics.Process.GetProcessesByName("Excel");
foreach (System.Diagnostics.Process p in process)
{
if (p.MainWindowHandle == xAsIntPtr)
{
try
{
p.Kill();
}
catch { }
}
}
Usando el "MainWindowHandle" para identificar el proceso y cerrarlo.
excelObj: esta es mi aplicación Interop excel objecto
Estoy escribiendo una aplicación en C # que abre un archivo de plantilla de Excel para operaciones de lectura / escritura. Quiero cuando el usuario cierra la aplicación, el proceso de solicitud de Excel se ha cerrado, sin guardar el archivo de Excel. Ver mi Administrador de tareas después de varias ejecuciones de la aplicación.
Uso este código para abrir el archivo de Excel:
public Excel.Application excelApp = new Excel.Application();
public Excel.Workbook excelBook;
excelBook = excelApp.Workbooks.Add(@"C:/pape.xltx");
y para el acceso a los datos, uso este código:
Excel.Worksheet excelSheet = (Worksheet)(excelBook.Worksheets[1]);
excelSheet.DisplayRightToLeft = true;
Range rng;
rng = excelSheet.get_Range("C2");
rng.Value2 = txtName.Text;
Veo preguntas similares en stackoverflow como esta pregunta y this , y pruebo las respuestas, pero no funciona.
Encontré los mismos problemas e intenté muchos métodos para resolverlo, pero no funciona. Finalmente, encontré el por cierto. Algunas referencias ingresan la descripción del enlace aquí
Espero que mi código pueda ayudar a alguien en el futuro. He pasado más de dos días para resolverlo. A continuación está mi Código:
//get current in useing excel
Process[] excelProcsOld = Process.GetProcessesByName("EXCEL");
Excel.Application myExcelApp = null;
Excel.Workbooks excelWorkbookTemplate = null;
Excel.Workbook excelWorkbook = null;
try{
//DO sth using myExcelApp , excelWorkbookTemplate, excelWorkbook
}
catch (Exception ex ){
}
finally
{
//Compare the EXCEL ID and Kill it
Process[] excelProcsNew = Process.GetProcessesByName("EXCEL");
foreach (Process procNew in excelProcsNew)
{
int exist = 0;
foreach (Process procOld in excelProcsOld)
{
if (procNew.Id == procOld.Id)
{
exist++;
}
}
if (exist == 0)
{
procNew.Kill();
}
}
}
Killing Excel no siempre es fácil; vea este artículo: 50 formas de matar a Excel
Este artículo toma el mejor consejo de Microsoft ( MS Knowledge Base Article ) sobre cómo hacer que Excel salga bien, pero también se asegura de ello matando el proceso si es necesario. Me gusta tener un segundo paracaídas.
Asegúrese de cerrar todos los libros abiertos, salir de la aplicación y liberar el objeto xlApp. Por último, compruebe si el proceso todavía está activo y, en caso afirmativo, mátalo.
Este artículo también se asegura de que no matemos todos los procesos de Excel, sino que solo elimine el proceso exacto que se inició.
Consulte también Obtener proceso desde la manija de la ventana
Aquí está el código que uso: (funciona todo el tiempo)
Sub UsingExcel()
''declare process; will be used later to attach the Excel process
Dim XLProc As Process
''call the sub that will do some work with Excel
''calling Excel in a separate routine will ensure that it is
''out of scope when calling GC.Collect
''this works better especially in debug mode
DoOfficeWork(XLProc)
''Do garbage collection to release the COM pointers
''http://support.microsoft.com/kb/317109
GC.Collect()
GC.WaitForPendingFinalizers()
''I prefer to have two parachutes when dealing with the Excel process
''this is the last answer if garbage collection were to fail
If Not XLProc Is Nothing AndAlso Not XLProc.HasExited Then
XLProc.Kill()
End If
End Sub
''http://msdn.microsoft.com/en-us/library/ms633522%28v=vs.85%29.aspx
<System.Runtime.InteropServices.DllImport("user32.dll", SetLastError:=True)> _
Private Shared Function GetWindowThreadProcessId(ByVal hWnd As IntPtr, _
ByRef lpdwProcessId As Integer) As Integer
End Function
Private Sub ExcelWork(ByRef XLProc As Process)
''start the application using late binding
Dim xlApp As Object = CreateObject("Excel.Application")
''or use early binding
''Dim xlApp As Microsoft.Office.Interop.Excel
''get the window handle
Dim xlHWND As Integer = xlApp.hwnd
''this will have the process ID after call to GetWindowThreadProcessId
Dim ProcIdXL As Integer = 0
''get the process ID
GetWindowThreadProcessId(xlHWND, ProcIdXL)
''get the process
XLProc = Process.GetProcessById(ProcIdXL)
''do some work with Excel here using xlApp
''be sure to save and close all workbooks when done
''release all objects used (except xlApp) using NAR(x)
''Quit Excel
xlApp.quit()
''Release
NAR(xlApp)
End Sub
Private Sub NAR(ByVal o As Object)
''http://support.microsoft.com/kb/317109
Try
While (System.Runtime.InteropServices.Marshal.ReleaseComObject(o) > 0)
End While
Catch
Finally
o = Nothing
End Try
End Sub
La forma correcta de cerrar todo el proceso de Excel
var _excel = new Application();
foreach (Workbook _workbook in _excel.Workbooks) {
_workbook.Close(0);
}
_excel.Quit();
_excel = null;
var process = System.Diagnostics.Process.GetProcessesByName("Excel");
foreach (var p in process) {
if (!string.IsNullOrEmpty(p.ProcessName)) {
try {
p.Kill();
} catch { }
}
}
Piense en esto, mata el proceso:
System.Diagnostics.Process[] process=System.Diagnostics.Process.GetProcessesByName("Excel");
foreach (System.Diagnostics.Process p in process)
{
if (!string.IsNullOrEmpty(p.ProcessName))
{
try
{
p.Kill();
}
catch { }
}
}
Además, ¿trataste de cerrarlo normalmente?
myWorkbook.SaveAs(@"C:/pape.xltx", missing, missing, missing, missing, missing, Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlNoChange, missing, missing, missing, missing, missing);
excelBook.Close(null, null, null); // close your workbook
excelApp.Quit(); // exit excel application
excel = null; // set to NULL
Prueba esto:
excelBook.Close(0);
excelApp.Quit();
Al cerrar el libro de trabajo, tiene tres parámetros opcionales:
Workbook.close SaveChanges, filename, routeworkbook
Workbook.Close(false)
o si está haciendo binding tarde, a veces es más fácil utilizar zero Workbook.Close(0)
Así es como lo hice al automatizar el cierre de libros de trabajo.
También fui y busqué la documentación para encontrarla aquí: Libro de Excel Cerrar
Gracias,
Puede matar el proceso con su propio objeto COM
excel pid
agregar en algún lugar debajo del código de importación dll
[DllImport("user32.dll", SetLastError = true)]
private static extern int GetWindowThreadProcessId(IntPtr hwnd, ref int lpdwProcessId);
y use
if (excelApp != null)
{
int excelProcessId = -1;
GetWindowThreadProcessId(new IntPtr(excelApp.Hwnd), ref excelProcessId);
Process ExcelProc = Process.GetProcessById(excelProcessId);
if (ExcelProc != null)
{
ExcelProc.Kill();
}
}
Ref: https://.com/a/17367570/132599
Evite el uso de expresiones de llamadas dobles, como esta:
var workbook = excel.Workbooks.Open(/*params*/)
... porque de esta manera creas objetos RCW no solo para el libro de trabajo, sino para los libros de trabajo, y también debes liberarlo (lo cual no es posible si no se mantiene una referencia al objeto).
Esto resolvió el problema para mí. Tu código se convierte en:
public Excel.Application excelApp = new Excel.Application();
public Excel.Workbooks workbooks;
public Excel.Workbook excelBook;
workbooks = excelApp.Workbooks;
excelBook = workbooks.Add(@"C:/pape.xltx");
...
Excel.Sheets sheets = excelBook.Worksheets;
Excel.Worksheet excelSheet = (Worksheet)(sheets[1]);
excelSheet.DisplayRightToLeft = true;
Range rng;
rng = excelSheet.get_Range("C2");
rng.Value2 = txtName.Text;
Y luego libera todos esos objetos:
System.Runtime.InteropServices.Marshal.ReleaseComObject(rng);
System.Runtime.InteropServices.Marshal.ReleaseComObject(excelSheet);
System.Runtime.InteropServices.Marshal.ReleaseComObject(sheets);
excelBook .Save();
excelBook .Close(true);
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlBook);
System.Runtime.InteropServices.Marshal.ReleaseComObject(workbooks);
excelApp.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp);
Envuelvo esto en una try {} finally {}
para asegurar que todo se libere incluso si algo sale mal (¿qué podría salir mal?), Por ej.
public Excel.Application excelApp = null;
public Excel.Workbooks workbooks = null;
...
try
{
excelApp = new Excel.Application();
workbooks = excelApp.Workbooks;
...
}
finally
{
...
if (workbooks != null) System.Runtime.InteropServices.Marshal.ReleaseComObject(workbooks);
excelApp.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp);
}
excelBook.Close (); excelApp.Quit (); agregue el final del código, podría ser suficiente. está trabajando en mi código
wb.Close();
app.Quit();
System.Diagnostics.Process[] process = System.Diagnostics.Process.GetProcessesByName("Excel");
foreach (System.Diagnostics.Process p in process)
{
if (!string.IsNullOrEmpty(p.ProcessName) && p.StartTime.AddSeconds(+10) > DateTime.Now)
{
try
{
p.Kill();
}
catch { }
}
}
Cierra el último proceso de 10 segundos con el nombre "Excel"
GetWindowThreadProcessId((IntPtr)app.Hwnd, out iProcessId);
wb.Close(true,Missing.Value,Missing.Value);
app.Quit();
System.Diagnostics.Process[] process = System.Diagnostics.Process.GetProcessesByName("Excel");
foreach (System.Diagnostics.Process p in process)
{
if (p.Id == iProcessId)
{
try
{
p.Kill();
}
catch { }
}
}
}
[DllImport("user32.dll")]
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
uint iProcessId = 0;
este GetWindowThreadProcessId encuentra el ID de proceso correcto o excell .... Después de matarlo ... ¡Disfrútalo!
xlBook.Save();
xlBook.Close(true);
xlApp.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp);
intenta esto ... funcionó para mí ... deberías liberar ese objeto de aplicación xl para detener el proceso.