데이터 액세스 후 C#에서 Excel 응용 프로그램 프로세스 닫기
저는 읽기/쓰기 작업을 위해 엑셀 템플릿 파일을 여는 애플리케이션을 C#로 작성하고 있습니다.사용자가 앱을 닫을 때 엑셀 파일을 저장하지 않고 엑셀 신청 절차가 종료되었으면 합니다.앱을 여러 번 실행한 후 내 작업 관리자를 확인합니다.
이 코드를 사용하여 Excel 파일을 엽니다.
public Excel.Application excelApp = new Excel.Application();
public Excel.Workbook excelBook;
excelBook = excelApp.Workbooks.Add(@"C:/pape.xltx");
데이터 액세스를 위해 다음 코드를 사용합니다.
Excel.Worksheet excelSheet = (Worksheet)(excelBook.Worksheets[1]);
excelSheet.DisplayRightToLeft = true;
Range rng;
rng = excelSheet.get_Range("C2");
rng.Value2 = txtName.Text;
스택 오버플로에서 이 질문과 이 질문, 테스트 답변과 같은 유사한 질문이 표시되지만 작동하지 않습니다.
사용해 보십시오.
excelBook.Close(0);
excelApp.Quit();
워크북을 닫을 때 다음과 같은 세 가지 선택적 매개 변수가 있습니다.
Workbook.close SaveChanges, filename, routeworkbook
Workbook.Close(false)
binding을 할는 0을 이 더 쉬울 때도 있어요.Workbook.Close(0)
이것이 제가 워크북을 자동으로 닫을 때 수행한 방법입니다.
또한 문서를 찾아보니 Excel Workbook 닫기
xlBook.Save();
xlBook.Close(true);
xlApp.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp);
이것을 시도해 보세요.저한테는 효과가 있었어요프로세스를 중지하려면 xl 응용 프로그램 개체를 해제해야 합니다.
참조: https://stackoverflow.com/a/17367570/132599
다음과 같은 이중 점 호출 식을 사용하지 않도록 합니다.
var workbook = excel.Workbooks.Open(/*params*/)
...이렇게 하면 워크북뿐만 아니라 워크북에도 RCW 개체를 생성할 수 있으므로 릴리스해야 합니다(개체에 대한 참조가 유지되지 않는 경우에는 불가능).
이것으로 저는 그 문제를 해결했습니다.코드는 다음과 같습니다.
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;
그런 다음 모든 개체를 해제합니다.
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);
으로 합니다.try {} finally {}
예를 들어, 문제가 발생하더라도 모든 것이 해결되도록 보장합니다(무엇이 잘못될 수 있습니까?).
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);
}
이것을 생각해 보세요, 그것은 과정을 죽입니다.
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 { }
}
}
그리고 그냥 정상적으로 닫으려고 하셨습니까?
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
Excel을 죽이는 것이 항상 쉬운 것은 아닙니다. 이 기사를 참조하십시오. Excel을 죽이는 50가지 방법
이 기사는 Excel을 멋지게 그만두게 하는 방법에 대한 Microsoft(MS 기술 자료 문서)의 최고의 조언을 받지만, 필요한 경우 프로세스를 종료하여 이를 확인합니다.저는 두 번째 낙하산을 가지고 있는 것을 좋아합니다.
열려 있는 모든 워크북을 닫고 애플리케이션을 종료한 후 xlApp 개체를 릴리스하십시오.마지막으로 프로세스가 아직 활성화되어 있는지 확인하고 활성화되어 있으면 종료합니다.
이 문서는 또한 우리가 모든 엑셀 프로세스를 죽이는 것이 아니라 시작된 정확한 프로세스만 죽이는 것을 확실히 합니다.
제가 사용하는 코드는 다음과 같습니다. (매번 작동)
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
저는 같은 문제를 만나 여러 가지 방법으로 해결해 보았지만 잘 되지 않습니다.마침내, 저는 길을 따라 길을 찾았습니다.일부 참조는 여기에 링크 설명을 입력합니다.
내 코드가 미래의 누군가를 도울 수 있기를 바랍니다.저는 그것을 해결하기 위해 이틀 이상을 보냈습니다.내 코드는 다음과 같습니다.
//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();
}
}
}
나는 그것을 갖는 것이 중요하다는 것을 발견했습니다.Marshal.ReleaseComObject
에.While
루프하고 가비지 컬렉션으로 끝냅니다.
static void Main(string[] args)
{
Excel.Application xApp = new Excel.Application();
Excel.Workbooks xWbs = xApp.Workbooks;
Excel.Workbook xWb = xWbs.Open("file.xlsx");
Console.WriteLine(xWb.Sheets.Count);
xWb.Close();
xApp.Quit();
while (Marshal.ReleaseComObject(xWb) != 0);
while (Marshal.ReleaseComObject(xWbs) != 0);
while (Marshal.ReleaseComObject(xApp) != 0);
GC.Collect();
GC.WaitForPendingFinalizers();
}
당신은 당신 자신의 프로세스를 죽일 수 있습니다.COM
excel pid 어우함수적
dll 가져오기 코드 아래에 추가
[DllImport("user32.dll", SetLastError = true)]
private static extern int GetWindowThreadProcessId(IntPtr hwnd, ref int lpdwProcessId);
및 사용
if (excelApp != null)
{
int excelProcessId = -1;
GetWindowThreadProcessId(new IntPtr(excelApp.Hwnd), ref excelProcessId);
Process ExcelProc = Process.GetProcessById(excelProcessId);
if (ExcelProc != null)
{
ExcelProc.Kill();
}
}
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 { }
}
}
이름이 "Excel"인 마지막 10초 프로세스를 닫습니다.
하여 반드시 .Marshal.ReleaseComObject >0
루프가 없으면 Excel 프로세스는 여전히 활성 상태를 유지합니다.
public class test{
private dynamic ExcelObject;
protected dynamic ExcelBook;
protected dynamic ExcelBooks;
protected dynamic ExcelSheet;
public void LoadExcel(string FileName)
{
Type t = Type.GetTypeFromProgID("Excel.Application");
if (t == null) throw new Exception("Excel non installato");
ExcelObject = System.Activator.CreateInstance(t);
ExcelObject.Visible = false;
ExcelObject.DisplayAlerts = false;
ExcelObject.AskToUpdateLinks = false;
ExcelBooks = ExcelObject.Workbooks;
ExcelBook = ExcelBooks.Open(FileName,0,true);
System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application");
ExcelSheet = ExcelBook.Sheets[1];
}
private void ReleaseObj(object obj)
{
try
{
int i = 0;
while( System.Runtime.InteropServices.Marshal.ReleaseComObject(obj) > 0)
{
i++;
if (i > 1000) break;
}
obj = null;
}
catch
{
obj = null;
}
finally
{
GC.Collect();
}
}
public void ChiudiExcel() {
System.Threading.Thread.CurrentThread.CurrentCulture = ci;
ReleaseObj(ExcelSheet);
try { ExcelBook.Close(); } catch { }
try { ExcelBooks.Close(); } catch { }
ReleaseObj(ExcelBooks);
try { ExcelObject.Quit(); } catch { }
ReleaseObj(ExcelObject);
}
}
대부분의 메소드는 작동하지만 Excel 프로세스는 항상 응용프로그램을 닫을 때까지 유지됩니다.
Excel 프로세스를 한 번 종료하면 동일한 스레드에서 다시 실행할 수 없습니다. 이유를 알 수 없습니다.
모든 Excel 프로세스를 종료하는 올바른 방법
var _excel = new Application();
foreach (Workbook _workbook in _excel.Workbooks) {
_workbook.Close(0);
}
_excel.Quit();
_excel = null;
프로세스 예제를 사용하면 이와 관계없이 모든 Excel 프로세스가 종료될 수 있습니다.
var process = System.Diagnostics.Process.GetProcessesByName("Excel");
foreach (var p in process) {
if (!string.IsNullOrEmpty(p.ProcessName)) {
try {
p.Kill();
} catch { }
}
}
workbook.Close(0);
excelApp.Quit();
나를 위해 일했습니다.
excelBook.Close();
excelApp.Quit();
코드 끝을 추가하면 충분할 수 있습니다.그것은 내 코드에서 작동하고 있습니다.
using System;
using Excel = Microsoft.Office.Interop.Excel;
private Excel.Worksheet excelSheet;
private Excel.Workbook wb;
private Excel.Application excel;
public void Close()
{
wb.Close(true);
excel.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(excel);
System.Runtime.InteropServices.Marshal.ReleaseComObject(wb);
if(excelSheet!=null)
System.Runtime.InteropServices.Marshal.ReleaseComObject(excelSheet);
GC.Collect();
}
응용 프로그램 및 워크북을 닫은 후 GC collect를 호출하여 가비지 컬렉션을 강제로 수집합니다.
저는 많은 사용 사례에서 작동하는 이 문제에 대한 좋은 해결책을 생각해냈습니다.
코드 및 설명은 이전 게시물을 확인하십시오. https://stackoverflow.com/a/75414974/10391983
코드는 다음과 같습니다.
using System;
using System.Runtime.InteropServices;
using Microsoft.Office.Interop.Excel;
namespace YourNameSpace
{
public class MicrosoftApplications
{
[DllImport("user32.dll")]
static extern int GetWindowThreadProcessId(int hWnd, out int lpdwProcessId);
public class Excel
{
public Excel()
{
Application = new Microsoft.Office.Interop.Excel.Application();
RegisterExitEvent();
}
public Microsoft.Office.Interop.Excel.Application Application;
private void RegisterExitEvent()
{
Application.WindowDeactivate -= XlApp_WindowDeactivate;
Application.WindowDeactivate += XlApp_WindowDeactivate;
}
private void XlApp_WindowDeactivate(Workbook Wb, Window Wn)
{
Kill();
}
public void Kill()
{
int pid = 0;
GetWindowThreadProcessId(Application.Hwnd, out pid);
if (pid > 0)
{
System.Diagnostics.Process p = System.Diagnostics.Process.GetProcessById(pid);
p.Kill();
}
Application = null;
GC.Collect();
GC.WaitForPendingFinalizers();
}
}
}
}
다음과 같이 부를 수 있습니다.YourNameSpace.MicrosoftApplications.Excel xlApp = new YourNameSpace.MicrosoftApplications.Excel();
를 호출하면 됩니다.xlApp.Kill();
다른 솔루션을 기반으로 합니다.사용한 적이 있습니다.
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 { }
}
}
"주 창 핸들"을 사용하여 프로세스를 식별하고 프로세스를 닫습니다.
excelObj:이것은 나의 Application Interop excel 목표입니다.
우리는 아래 코드를 사용하여 xls를 xlsx로 변환하는 동안 엑셀 어플리케이션을 닫을 수 있습니다.이러한 종류의 작업을 수행할 때 Excel 응용 프로그램이 작업 관리자에서 실행되고 있습니다. 백그라운드에서 실행 중인 이 Excel을 닫아야 합니다.Interop은 Marshal이 사용한 com 구성 요소를 해제하기 위한 Com 구성 요소입니다.FinalReleaseComObject입니다.
private void button1_Click(object sender, EventArgs e)
{
Excel03to07("D:\\TestExls\\TestExcelApp.XLS");
}
private void Excel03to07(string fileName)
{
string svfileName = Path.ChangeExtension(fileName, ".xlsx");
object oMissing = Type.Missing;
var app = new Microsoft.Office.Interop.Excel.Application();
var wb = app.Workbooks.Open(fileName, oMissing, oMissing,
oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing);
wb.SaveAs(svfileName, XlFileFormat.xlOpenXMLWorkbook, Type.Missing, Type.Missing, Type.Missing, Type.Missing, XlSaveAsAccessMode.xlNoChange, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
wb.Close(false, Type.Missing, Type.Missing);
app.Quit();
GC.Collect();
Marshal.FinalReleaseComObject(wb);
Marshal.FinalReleaseComObject(app);
}
이 문제에 대한 또 다른 해결책은 프로세스를 저장하는 것입니다.작업 중인 Excel 프로그램의 ID입니다.그런 다음 프로그램을 마치면 다른 엑셀 프로세스를 대상으로 하지 않고 해당 엑셀 프로세스를 특별히 종료할 수 있습니다.
저는 이 답변에서 해결책을 얻었습니다.여기서 공유하려고 생각했습니다.
먼저 클래스 메소드 외부에 코드 줄을 추가합니다.
// The DllImport requires -- Using System.Runtime.InteropServices;
[DllImport("user32.dll", SetLastError = true)]
private static extern int GetWindowThreadProcessId(IntPtr hwnd, ref int lpdwProcessId);
그 이후로
이제 선택한 방법으로 이 행을 추가합니다.이 라인들은 작업 중인 특정 Excel 프로세스를 폐기합니다.
필요에 따라 수정하지만 논리는 동일합니다.
if (ExcelApp != null)
{
int excelProcessId = 0;
//your Excel Application variable has access to its Hwnd property
GetWindowThreadProcessId(new IntPtr(ExcelApp.Hwnd), ref excelProcessId);
// you need System.Diagnostics to use Process Class
Process ExcelProc = Process.GetProcessById(excelProcessId);
if (ExcelProc != null)
{
ExcelProc.Kill();
}
}
따라서 전체적으로 당신의 프로그램은 다음과 같아야 합니다.
class Program
{
[DllImport("user32.dll", SetLastError = true)]
private static extern int GetWindowThreadProcessId(IntPtr hwnd, ref int lpdwProcessId);
static void Main(string[] args)
{
Application ExcelApp = new Application();
_Workbook ExcelWrkBook = ExcelApp.Workbooks.Open(filePath);
_Worksheet ExcelWrkSht = ExcelWrkBook.ActiveSheet;
ExcelWrkSht.Cells[1, 2] = "70";
if (ExcelApp != null)
{
int excelProcessId = 0; // simple declare, zero is merely a place holder
GetWindowThreadProcessId(new IntPtr(ExcelApp.Hwnd), ref excelProcessId);
Process ExcelProc = Process.GetProcessById(excelProcessId);
if (ExcelProc != null)
{
ExcelProc.Kill();
}
}
}
}
작업 관리자에 표시된 것처럼 Excel 프로세스가 제거됩니다.
저는 미래에 누군가에게 도움이 될 수 있도록 저에게 효과가 있었던 것을 쓸 것입니다.
저장, 저장 및 종료 전에 이 작업을 수행하여 문제를 해결했습니다.제가 사용하지 않는 다른 방법에 필요할 수도 있습니다.
m_pXLApp->PutDisplayAlerts( VARIANT_FALSE );
더 이상 매달리지 않는 EXCEL.EXE
Microsoft 설명서에서 이해한 바로는 이 기능은 사용자에게 작업을 저장하라는 메시지를 표시하지 않도록 설계되었지만 호환성 문제와 같은 다른 메시지에 대해서도 작동합니다.
그 메시지들은 저에게 나타나지 않았지만 뭔가가 Excel이 나가는 것을 방해하고 있었습니다.COM 개체에 대한 환불을 추적하려고 시도한 후, 이것이 제가 시도할 수 있는 유일한 "롱샷"이었습니다.
이것이 누군가에게 도움이 되기를 바랍니다.
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;
이 GetWindowThreadProcessId는 올바른 ProcessId를 찾습니다...죽인 후에...즐기세요!!!
private void releaseObject(object obj)
{
try
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
obj = null;
}
catch (Exception ex)
{
obj = null;
MessageBox.Show("Unable to release the Object " + ex.ToString());
}
finally
{
GC.Collect();
}
}
언급URL : https://stackoverflow.com/questions/17777545/closing-excel-application-process-in-c-sharp-after-data-access
'programing' 카테고리의 다른 글
<...>라는 이름> 네임스페이스 clr-message <...> (0) | 2023.05.02 |
---|---|
Xcode 프로젝트에 대한 Git ignore 파일 (0) | 2023.05.02 |
에레독 배관을 위한 다중 라인 구문; 이것은 휴대 가능합니까? (0) | 2023.05.02 |
구분 문자열을 목록으로 분할()하는 방법 (0) | 2023.05.02 |
데이터 입력 후 문자열을 트리밍하는 가장 좋은 방법입니다.사용자 정의 모델 바인더를 작성해야 합니까? (0) | 2023.05.02 |