Saya menggunakan interop Excel di C # ( ApplicationClass
) dan telah menempatkan kode berikut di klausa saya yang terakhir:
while (System.Runtime.InteropServices.Marshal.ReleaseComObject(excelSheet) != 0) { }
excelSheet = null;
GC.Collect();
GC.WaitForPendingFinalizers();
Meskipun ini berfungsi, Excel.exe
prosesnya masih di latar belakang bahkan setelah saya menutup Excel. Ini hanya dirilis setelah aplikasi saya ditutup secara manual.
Apa yang saya lakukan salah, atau apakah ada alternatif untuk memastikan objek interop dibuang dengan benar?
c#
excel
interop
com-interop
Neraka
sumber
sumber
Jawaban:
Excel tidak berhenti karena aplikasi Anda masih memegang referensi ke objek COM.
Saya kira Anda memohon setidaknya satu anggota objek COM tanpa menugaskannya ke variabel.
Bagi saya itu adalah objek excelApp.Worksheets yang langsung saya gunakan tanpa menugaskannya ke variabel:
Saya tidak tahu bahwa secara internal C # membuat pembungkus untuk objek COM lembar kerja yang tidak dirilis oleh kode saya (karena saya tidak menyadarinya) dan merupakan alasan mengapa Excel tidak diturunkan.
Saya menemukan solusi untuk masalah saya di halaman ini , yang juga memiliki aturan yang bagus untuk penggunaan objek COM di C #:
Jadi dengan pengetahuan ini cara yang tepat untuk melakukan hal di atas adalah:
PEMBARUAN POST MORTEM:
Saya ingin setiap pembaca membaca jawaban ini oleh Hans Passant dengan sangat hati-hati karena ini menjelaskan jebakan yang saya dan banyak pengembang lain temukan. Ketika saya menulis jawaban ini bertahun-tahun yang lalu saya tidak tahu tentang efek debugger terhadap pemulung dan menarik kesimpulan yang salah. Saya menjaga jawaban saya tidak berubah demi sejarah tetapi tolong baca tautan ini dan jangan mengikuti "dua titik": Memahami pengumpulan sampah di .NET dan Bersihkan Objek Excel Interop dengan IDisposable
sumber
Anda benar-benar dapat melepaskan objek Aplikasi Excel Anda dengan bersih, tetapi Anda harus berhati-hati.
Saran untuk mempertahankan referensi bernama untuk benar-benar setiap objek COM yang Anda akses dan kemudian secara eksplisit melepaskannya melalui
Marshal.FinalReleaseComObject()
teori, tetapi, sayangnya, sangat sulit untuk dikelola dalam praktiknya. Jika seseorang pernah tergelincir di mana saja dan menggunakan "dua titik", atau mengulangi sel melaluifor each
loop, atau perintah sejenis lainnya, maka Anda akan memiliki objek COM yang tidak direferensikan dan berisiko hang. Dalam hal ini, tidak akan ada cara untuk menemukan penyebabnya dalam kode; Anda harus meninjau semua kode Anda dengan mata dan mudah-mudahan menemukan penyebabnya, tugas yang hampir mustahil untuk proyek besar.Berita baiknya adalah Anda tidak harus mempertahankan referensi variabel bernama untuk setiap objek COM yang Anda gunakan. Sebaliknya, panggil
GC.Collect()
dan kemudianGC.WaitForPendingFinalizers()
untuk melepaskan semua objek (biasanya minor) yang tidak Anda pegang referensi, dan kemudian secara eksplisit melepaskan objek yang Anda pegang referensi variabel bernama.Anda juga harus merilis referensi nama Anda dalam urutan terbalik kepentingan: objek rentang pertama, lalu lembar kerja, buku kerja, dan akhirnya objek Aplikasi Excel Anda.
Misalnya, dengan asumsi bahwa Anda memiliki variabel objek Range bernama
xlRng
, variabel Worksheet bernamaxlSheet
, variabel Workbook bernamaxlBook
dan variabel Aplikasi Excel bernamaxlApp
, maka kode pembersihan Anda bisa terlihat seperti berikut:Dalam sebagian besar contoh kode Anda akan melihat untuk membersihkan objek COM dari .NET,
GC.Collect()
danGC.WaitForPendingFinalizers()
panggilan dibuat DUA KALI seperti pada:Namun, ini tidak diperlukan, kecuali jika Anda menggunakan Visual Studio Tools for Office (VSTO), yang menggunakan finalizers yang menyebabkan seluruh grafik objek dipromosikan dalam antrian finalisasi. Benda-benda seperti itu tidak akan dirilis sampai pengumpulan sampah berikutnya . Namun, jika Anda tidak menggunakan VSTO, Anda harus dapat menelepon
GC.Collect()
danGC.WaitForPendingFinalizers()
sekali saja.Saya tahu bahwa menelepon secara eksplisit
GC.Collect()
adalah tidak-tidak (dan tentu saja melakukannya dua kali terdengar sangat menyakitkan), tetapi tidak ada jalan lain, jujur saja. Melalui operasi normal, Anda akan menghasilkan objek tersembunyi yang tidak Anda pegang referensi sehingga tidak dapat dilepaskan melalui cara lain selain meneleponGC.Collect()
.Ini adalah topik yang kompleks, tetapi ini adalah segalanya. Setelah Anda membuat templat ini untuk prosedur pembersihan, Anda dapat membuat kode secara normal, tanpa perlu pembungkus, dll. :-)
Saya punya tutorial tentang ini di sini:
Mengotomatiskan Program Office dengan VB.Net / COM Interop
Ini ditulis untuk VB.NET, tetapi jangan ditunda karena itu, prinsip-prinsipnya persis sama seperti ketika menggunakan C #.
sumber
Kata pengantar: jawaban saya mengandung dua solusi, jadi berhati-hatilah saat membaca dan jangan lewatkan apa pun.
Ada berbagai cara dan saran tentang cara membuat Excel misalnya diturunkan, seperti:
Melepaskan SETIAP objek com secara eksplisit dengan Marshal.FinalReleaseComObject () (tidak lupa tentang objek com yang dibuat secara implisit). Untuk melepaskan setiap objek com yang dibuat, Anda dapat menggunakan aturan 2 titik yang disebutkan di sini:
Bagaimana cara membersihkan objek interop Excel dengan benar?
Memanggil GC.Collect () dan GC.WaitForPendingFinalizers () untuk membuat CLR melepaskan objek-com yang tidak terpakai * (Sebenarnya, itu berfungsi, lihat solusi kedua saya untuk detail)
Memeriksa apakah aplikasi-server-com mungkin memperlihatkan kotak pesan menunggu pengguna untuk menjawab (meskipun saya tidak yakin itu dapat mencegah Excel menutup, tetapi saya mendengarnya beberapa kali)
Mengirim pesan WM_CLOSE ke jendela Excel utama
Menjalankan fungsi yang berfungsi dengan Excel di AppDomain yang terpisah. Beberapa orang percaya contoh Excel akan ditutup, ketika AppDomain diturunkan.
Membunuh semua instance excel yang dipakai setelah kode interoping excel kami dimulai.
TAPI! Terkadang semua opsi ini tidak membantu atau tidak sesuai!
Sebagai contoh, kemarin saya menemukan bahwa di salah satu fungsi saya (yang berfungsi dengan excel) Excel terus berjalan setelah fungsi berakhir. Saya mencoba semuanya! Saya benar-benar memeriksa seluruh fungsi 10 kali dan menambahkan Marshal.FinalReleaseComObject () untuk semuanya! Saya juga punya GC.Collect () dan GC.WaitForPendingFinalizers (). Saya memeriksa kotak pesan tersembunyi. Saya mencoba mengirim pesan WM_CLOSE ke jendela Excel utama. Saya menjalankan fungsi saya di AppDomain terpisah dan membongkar domain itu. Tidak ada yang membantu! Opsi dengan menutup semua instance excel tidak tepat, karena jika pengguna memulai instance Excel lain secara manual, selama eksekusi fungsi saya yang juga berfungsi dengan Excel, maka instance itu juga akan ditutup oleh fungsi saya. Saya yakin pengguna tidak akan senang! Jadi, jujur, ini opsi yang lemah (jangan tersinggung kawan).solusi : Bunuh proses excel dengan hWnd dari jendela utamanya (ini solusi pertama).
Ini adalah kode sederhana:
Seperti yang Anda lihat saya menyediakan dua metode, sesuai dengan pola Try-Parse (saya pikir itu tepat di sini): satu metode tidak membuang pengecualian jika Proses tidak dapat dibunuh (misalnya proses tidak ada lagi) , dan metode lain melempar pengecualian jika Proses tidak terbunuh. Satu-satunya tempat yang lemah dalam kode ini adalah izin keamanan. Secara teoritis, pengguna mungkin tidak memiliki izin untuk mematikan proses, tetapi dalam 99,99% dari semua kasus, pengguna memiliki izin tersebut. Saya juga mengujinya dengan akun tamu - itu berfungsi dengan baik.
Jadi, kode Anda, bekerja dengan Excel, dapat terlihat seperti ini:
Voila! Excel dihentikan! :)
Ok, mari kita kembali ke solusi kedua, seperti yang saya janjikan di awal posting. Solusi kedua adalah dengan memanggil GC.Collect () dan GC.WaitForPendingFinalizers (). Ya, mereka benar-benar berfungsi, tetapi Anda harus berhati-hati di sini!
Banyak orang mengatakan (dan saya katakan) bahwa memanggil GC.Collect () tidak membantu. Tetapi alasan itu tidak membantu adalah jika masih ada referensi ke objek COM! Salah satu alasan paling populer untuk GC.Collect () tidak membantu adalah menjalankan proyek dalam mode Debug. Dalam mode debug-objek yang tidak benar-benar direferensikan lagi tidak akan menjadi sampah yang dikumpulkan sampai akhir metode.
Jadi, jika Anda mencoba GC.Collect () dan GC.WaitForPendingFinalizers () dan itu tidak membantu, coba lakukan hal berikut:
1) Cobalah untuk menjalankan proyek Anda dalam mode Rilis dan periksa apakah Excel ditutup dengan benar
2) Bungkus metode bekerja dengan Excel dalam metode terpisah. Jadi, bukannya sesuatu seperti ini:
Anda menulis:
Sekarang, Excel akan menutup =)
sumber
UPDATE : Menambahkan kode C #, dan menautkan ke Windows Jobs
Saya menghabiskan beberapa waktu untuk mencari tahu masalah ini, dan pada saat itu XtremeVBTalk adalah yang paling aktif dan responsif. Berikut ini tautan ke posting asli saya, Menutup proses Excel Interop dengan bersih, bahkan jika aplikasi Anda macet . Di bawah ini adalah ringkasan posting, dan kode yang disalin ke posting ini.
Application.Quit()
danProcess.Kill()
berfungsi sebagian besar, tetapi gagal jika aplikasi crash secara katastropis. Yaitu jika aplikasi macet, proses Excel masih akan berjalan longgar.Saya menemukan ini menjadi solusi bersih karena OS melakukan pekerjaan nyata membersihkan. Yang harus Anda lakukan adalah mendaftarkan proses Excel.
Kode Pekerjaan Windows
Membungkus Panggilan API Win32 untuk mendaftarkan proses Interop.
Catatan tentang kode konstruktor
info.LimitFlags = 0x2000;
disebut.0x2000
adalah nilaiJOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
enum, dan nilai ini didefinisikan oleh MSDN sebagai:Extra Win32 API Call untuk mendapatkan ID Proses (PID)
Menggunakan kodenya
sumber
Ini berhasil untuk proyek yang saya kerjakan:
Kami belajar bahwa penting untuk menetapkan setiap referensi ke objek Excel COM ke nol ketika Anda selesai menggunakannya. Ini termasuk Sel, Lembar, dan semuanya.
sumber
Apa pun yang ada di dalam namespace Excel perlu dirilis. Titik
Anda tidak dapat melakukan:
Anda harus melakukannya
diikuti oleh pelepasan benda-benda.
sumber
Pertama - Anda tidak perlu menelepon
Marshal.ReleaseComObject(...)
atauMarshal.FinalReleaseComObject(...)
ketika melakukan interop Excel. Ini adalah anti-pola yang membingungkan, tetapi informasi apa pun tentang ini, termasuk dari Microsoft, yang menunjukkan Anda harus melepaskan referensi COM secara manual dari .NET tidak benar. Faktanya adalah bahwa .NET runtime dan pengumpul sampah dengan benar melacak dan membersihkan referensi COM. Untuk kode Anda, ini berarti Anda dapat menghapus seluruh loop `while (...) di bagian atas.Kedua, jika Anda ingin memastikan bahwa referensi COM ke objek COM out-of-proses dibersihkan ketika proses Anda berakhir (sehingga proses Excel akan menutup), Anda perlu memastikan bahwa pengumpul sampah berjalan. Anda melakukan ini dengan benar dengan panggilan ke
GC.Collect()
danGC.WaitForPendingFinalizers()
. Memanggil ini dua kali aman, dan memastikan bahwa siklus pasti dibersihkan juga (meskipun saya tidak yakin itu diperlukan, dan akan menghargai contoh yang menunjukkan ini).Ketiga, ketika berjalan di bawah debugger, referensi lokal akan tetap hidup sampai akhir metode (sehingga pemeriksaan variabel lokal bekerja). Jadi
GC.Collect()
panggilan tidak efektif untuk membersihkan objek sepertirng.Cells
dari metode yang sama. Anda harus membagi kode melakukan COM interop dari pembersihan GC menjadi metode terpisah. (Ini adalah penemuan kunci bagi saya, dari satu bagian dari jawaban yang diposting di sini oleh @nightcoder.)Jadi, pola umumnya adalah:
Ada banyak informasi palsu dan kebingungan tentang masalah ini, termasuk banyak posting di MSDN dan Stack Overflow (dan terutama pertanyaan ini!).
Apa yang akhirnya meyakinkan saya untuk melihat lebih dekat dan mencari tahu saran yang tepat adalah posting blog Marshal.ReleaseComObject Dianggap Berbahaya bersama-sama dengan menemukan masalah dengan referensi tetap hidup di bawah debugger yang membingungkan pengujian saya sebelumnya.
sumber
Saya menemukan templat generik yang berguna yang dapat membantu menerapkan pola pembuangan yang benar untuk objek COM, yang membutuhkan Marshal.ReleaseComObject dipanggil ketika mereka keluar dari ruang lingkup:
Pemakaian:
Templat:
Referensi:
http://www.deez.info/sengelha/2005/02/11/useful-idisposable-class-3-autoreleasecomobject/
sumber
Saya tidak percaya masalah ini telah menghantui dunia selama 5 tahun .... Jika Anda telah membuat aplikasi, Anda harus mematikannya terlebih dahulu sebelum menghapus tautan.
saat menutup
Ketika Anda baru aplikasi excel, itu membuka program excel di latar belakang. Anda perlu memerintahkan program excel untuk berhenti sebelum Anda melepaskan tautan karena program excel itu bukan bagian dari kontrol langsung Anda. Karena itu, ia akan tetap terbuka jika tautannya dirilis!
Pemrograman yang bagus, semuanya ~~
sumber
Pengembang umum, tidak ada solusi yang bekerja untuk saya, jadi saya memutuskan untuk menerapkan trik baru .
Pertama mari kita tentukan "Apa tujuan kita?" => "Tidak melihat objek excel setelah pekerjaan kami di task manager"
Baik. Biarkan tidak untuk menantang dan mulai menghancurkannya, tetapi pertimbangkan untuk tidak menghancurkan contoh lain os Excel yang berjalan secara paralel.
Jadi, dapatkan daftar prosesor saat ini dan ambil PID dari proses EXCEL, maka setelah pekerjaan Anda selesai, kami memiliki tamu baru dalam daftar proses dengan PID unik, temukan dan hancurkan yang itu.
<perlu diingat setiap proses excel baru selama pekerjaan excel Anda akan terdeteksi sebagai baru dan dihancurkan> <Solusi yang lebih baik adalah dengan menangkap PID objek excel yang baru dibuat dan menghancurkannya>
Ini menyelesaikan masalah saya, harap Anda juga.
sumber
Ini sepertinya terlalu rumit. Dari pengalaman saya, hanya ada tiga hal utama untuk membuat Excel menutup dengan benar:
1: pastikan tidak ada referensi yang tersisa untuk aplikasi excel yang Anda buat (Anda seharusnya hanya punya satu; setel ke
null
)2: panggilan
GC.Collect()
3: Excel harus ditutup, baik oleh pengguna secara manual menutup program, atau dengan Anda memanggil
Quit
objek Excel. (Catatan yangQuit
akan berfungsi sama seperti jika pengguna mencoba untuk menutup program, dan akan menyajikan dialog konfirmasi jika ada perubahan yang belum disimpan, bahkan jika Excel tidak terlihat. Pengguna dapat menekan membatalkan, dan kemudian Excel tidak akan ditutup. )1 harus terjadi sebelum 2, tetapi 3 bisa terjadi kapan saja.
Salah satu cara untuk mengimplementasikan ini adalah dengan membungkus objek Excel interop dengan kelas Anda sendiri, membuat instance interop di konstruktor, dan mengimplementasikan IDisposable dengan Buang terlihat seperti
Itu akan membersihkan excel dari sisi program Anda. Setelah Excel ditutup (secara manual oleh pengguna atau dengan Anda menelepon
Quit
) proses akan hilang. Jika program sudah ditutup, maka prosesnya akan hilang padaGC.Collect()
panggilan.(Saya tidak yakin seberapa penting hal itu, tetapi Anda mungkin ingin
GC.WaitForPendingFinalizers()
panggilan setelahGC.Collect()
panggilan tetapi tidak sepenuhnya diperlukan untuk menyingkirkan proses Excel.)Ini berhasil bagi saya tanpa masalah selama bertahun-tahun. Perlu diingat bahwa meskipun ini berfungsi, Anda benar-benar harus menutup dengan anggun agar bisa berfungsi. Anda masih akan mendapatkan akumulasi proses excel.exe jika Anda menghentikan program Anda sebelum Excel dibersihkan (biasanya dengan menekan "stop" saat program Anda sedang di-debug).
sumber
Marshal
.Untuk menambah alasan mengapa Excel tidak menutup, bahkan ketika Anda membuat refrences langsung ke setiap objek setelah dibaca, kreasi, adalah loop 'Untuk'.
sumber
Saya secara tradisional mengikuti saran yang ditemukan dalam jawaban VVS . Namun, dalam upaya untuk menjaga jawaban ini tetap terkini dengan opsi terbaru, saya pikir semua proyek masa depan saya akan menggunakan perpustakaan "NetOffice".
NetOffice adalah pengganti lengkap untuk PIA Office dan sepenuhnya versi-agnostik. Ini adalah kumpulan pembungkus Managed COM yang dapat menangani pembersihan yang sering menyebabkan sakit kepala saat bekerja dengan Microsoft Office di .NET.
Beberapa fitur utama adalah:
Saya sama sekali tidak berafiliasi dengan proyek; Saya benar-benar menghargai pengurangan tajam pada sakit kepala.
sumber
Jawaban yang diterima di sini benar, tetapi juga perhatikan bahwa tidak hanya referensi "dua titik" perlu dihindari, tetapi juga objek yang diambil melalui indeks. Anda juga tidak perlu menunggu sampai Anda selesai dengan program untuk membersihkan objek-objek ini, yang terbaik adalah membuat fungsi yang akan membersihkannya segera setelah Anda selesai menggunakannya, jika memungkinkan. Berikut adalah fungsi yang saya buat yang memberikan beberapa properti objek Style yang disebut
xlStyleHeader
:Perhatikan bahwa saya harus mengatur
xlBorders[Excel.XlBordersIndex.xlEdgeBottom]
ke variabel untuk membersihkannya (Bukan karena dua titik, yang merujuk pada enumerasi yang tidak perlu dilepaskan, tetapi karena objek yang saya maksud sebenarnya adalah objek Border yang perlu dirilis).Hal semacam ini tidak benar-benar diperlukan dalam aplikasi standar, yang melakukan pekerjaan besar membersihkan setelah diri mereka sendiri, tetapi dalam aplikasi ASP.NET, jika Anda melewatkan salah satu dari ini, tidak peduli seberapa sering Anda memanggil pengumpul sampah, Excel akan masih berjalan di server Anda.
Dibutuhkan banyak perhatian terhadap detail dan banyak pelaksanaan pengujian saat memantau Manajer Tugas saat menulis kode ini, tetapi hal itu menghemat kerumitan mencari halaman kode untuk menemukan satu contoh yang Anda lewatkan. Ini sangat penting saat bekerja dalam loop, di mana Anda perlu melepaskan SETIAP INSTAN objek, meskipun menggunakan nama variabel yang sama setiap kali loop.
sumber
Setelah mencoba
GC.Collect()
danGC.WaitForPendingFinalizers()
dua kali di akhirsolusi terakhir yang bekerja untuk saya adalah memindahkan satu set
yang kami tambahkan di akhir fungsi ke pembungkus, sebagai berikut:
sumber
Saya mengikuti ini persis ... Tapi saya masih mengalami masalah 1 dari 1000 kali. Siapa yang tahu kenapa. Saatnya mengeluarkan palu ...
Tepat setelah kelas Aplikasi Excel yang dipakai saya mendapatkan proses Excel yang baru saja dibuat.
Kemudian setelah saya melakukan semua pembersihan COM di atas, saya memastikan bahwa prosesnya tidak berjalan. Jika masih berjalan, bunuh saja!
sumber
¨ ° º¤ø „¸ Tembak Excel proc dan kunyah permen karet ¸„ ø¤º ° ¨
sumber
Anda harus menyadari bahwa Excel sangat sensitif terhadap budaya yang Anda jalankan juga.
Anda mungkin menemukan bahwa Anda perlu mengatur budaya ke EN-US sebelum memanggil fungsi Excel. Ini tidak berlaku untuk semua fungsi - tetapi beberapa di antaranya.
Ini berlaku bahkan jika Anda menggunakan VSTO.
Untuk detail: http://support.microsoft.com/default.aspx?scid=kb;en-us;Q320369
sumber
"Jangan pernah menggunakan dua titik dengan objek COM" adalah aturan praktis yang bagus untuk menghindari kebocoran referensi COM, tetapi Excel PIA dapat menyebabkan kebocoran dalam lebih banyak cara daripada yang terlihat pada pandangan pertama.
Salah satu cara ini adalah berlangganan ke setiap peristiwa yang diekspos oleh salah satu objek COM model objek Excel.
Misalnya, berlangganan acara WorkbookOpen kelas Aplikasi.
Beberapa teori tentang peristiwa COM
Kelas COM mengekspos sekelompok acara melalui antarmuka panggilan balik. Untuk berlangganan acara, kode klien dapat dengan mudah mendaftarkan objek yang mengimplementasikan antarmuka panggilan balik dan kelas COM akan memanggil metode-metodenya dalam menanggapi peristiwa tertentu. Karena antarmuka panggilan balik adalah antarmuka COM, itu adalah tugas dari objek pelaksana untuk mengurangi jumlah referensi dari objek COM yang diterimanya (sebagai parameter) untuk salah satu penangan acara.
Bagaimana Excel PIA mengekspos Acara COM
Excel PIA memperlihatkan peristiwa COM dari kelas Aplikasi Excel sebagai peristiwa .NET konvensional. Setiap kali berlangganan kode klien untuk acara NET (penekanan pada 'a'), PIA menciptakan sebuah instance dari kelas yang mengimplementasikan interface panggilan kembali dan register dengan Excel.
Oleh karena itu, sejumlah objek panggilan kembali didaftarkan dengan Excel sebagai tanggapan atas permintaan berlangganan yang berbeda dari kode .NET. Satu objek panggilan balik per langganan acara.
Antarmuka panggilan balik untuk penanganan acara berarti bahwa, PIA harus berlangganan ke semua acara antarmuka untuk setiap permintaan berlangganan .NET event. Itu tidak bisa memilih. Saat menerima panggilan balik acara, objek panggilan balik akan memeriksa apakah penangan peristiwa .NET terkait tertarik dengan peristiwa saat ini atau tidak dan kemudian memanggil penangan atau secara diam-diam mengabaikan panggilan balik.
Efek pada jumlah referensi instance COM
Semua objek panggilan balik ini tidak mengurangi jumlah referensi dari objek COM yang mereka terima (sebagai parameter) untuk salah satu metode panggilan balik (bahkan untuk yang diabaikan secara diam-diam). Mereka hanya mengandalkan pengumpul sampah CLR untuk membebaskan objek COM.
Karena GC run bersifat non-deterministik, ini dapat menyebabkan penangguhan proses Excel untuk durasi yang lebih lama dari yang diinginkan dan menciptakan kesan 'kebocoran memori'.
Larutan
Satu-satunya solusi pada saat ini adalah dengan menghindari penyedia acara PIA untuk kelas COM dan menulis penyedia acara Anda sendiri yang secara pasti melepaskan objek COM.
Untuk kelas Aplikasi, ini bisa dilakukan dengan mengimplementasikan antarmuka AppEvents dan kemudian mendaftarkan implementasi dengan Excel dengan menggunakan antarmuka IConnectionPointContainer . Kelas Aplikasi (dan dalam hal ini semua objek COM yang mengekspos peristiwa menggunakan mekanisme panggilan balik) mengimplementasikan antarmuka IConnectionPointContainer.
sumber
Seperti yang telah ditunjukkan orang lain, Anda perlu membuat referensi eksplisit untuk setiap objek Excel yang Anda gunakan, dan memanggil Marshal.ReleaseComObject pada referensi itu, seperti yang dijelaskan dalam artikel KB ini . Anda juga perlu menggunakan try / akhirnya untuk memastikan ReleaseComObject selalu dipanggil, bahkan ketika ada pengecualian. Yaitu alih-alih:
Anda perlu melakukan sesuatu seperti:
Anda juga perlu memanggil Application.Quit sebelum melepaskan objek Aplikasi jika Anda ingin Excel ditutup.
Seperti yang Anda lihat, ini dengan cepat menjadi sangat sulit segera setelah Anda mencoba melakukan sesuatu yang bahkan cukup kompleks. Saya telah berhasil mengembangkan aplikasi .NET dengan kelas pembungkus sederhana yang membungkus beberapa manipulasi sederhana dari model objek Excel (buka buku kerja, tulis ke Range, simpan / tutup buku kerja dll). Kelas wrapper mengimplementasikan IDisposable, mengimplementasikan Marshal dengan hati-hati. ReleaseComObject pada setiap objek yang digunakannya, dan tidak secara terbuka mengekspos objek Excel apa pun ke seluruh aplikasi.
Tetapi pendekatan ini tidak sesuai untuk persyaratan yang lebih kompleks.
Ini adalah kekurangan besar .NET COM Interop. Untuk skenario yang lebih kompleks, saya serius mempertimbangkan untuk menulis ActiveX DLL di VB6 atau bahasa tidak terkelola lainnya di mana Anda dapat mendelegasikan semua interaksi dengan objek COM out-proc seperti Office. Anda kemudian dapat mereferensikan ActiveX DLL ini dari aplikasi .NET Anda, dan segalanya akan jauh lebih mudah karena Anda hanya perlu merilis referensi yang satu ini.
sumber
Ketika semua hal di atas tidak berhasil, coba beri Excel waktu untuk menutup lembarannya:
sumber
Pastikan Anda melepaskan semua objek yang terkait dengan Excel!
Saya menghabiskan beberapa jam dengan mencoba beberapa cara. Semua adalah ide-ide bagus tetapi saya akhirnya menemukan kesalahan saya: Jika Anda tidak melepaskan semua objek, tidak ada cara di atas yang dapat membantu Anda seperti dalam kasus saya. Pastikan Anda melepaskan semua objek termasuk rentang satu!
Pilihannya adalah bersama di sini .
sumber
Artikel hebat tentang pelepasan objek COM adalah 2.5 Melepaskan Objek COM (MSDN).
Metode yang saya sarankan adalah untuk membatalkan referensi Excel.Interop Anda jika mereka adalah variabel non-lokal, dan kemudian memanggil
GC.Collect()
danGC.WaitForPendingFinalizers()
dua kali. Variabel Interop yang dicakup secara lokal akan dijaga secara otomatis.Ini menghilangkan kebutuhan untuk menyimpan referensi bernama untuk setiap objek COM.
Berikut ini contoh yang diambil dari artikel:
Kata-kata ini langsung dari artikel:
sumber
Aturan dua titik tidak bekerja untuk saya. Dalam kasus saya, saya membuat metode untuk membersihkan sumber daya saya sebagai berikut:
sumber
Solusi saya
sumber
Anda harus sangat berhati-hati menggunakan aplikasi interop Word / Excel. Setelah mencoba semua solusi, kami masih memiliki banyak proses "WinWord" yang dibiarkan terbuka di server (dengan lebih dari 2000 pengguna).
Setelah mengatasi masalah selama berjam-jam, saya menyadari bahwa jika saya membuka lebih dari beberapa dokumen menggunakan
Word.ApplicationClass.Document.Open()
pada utas yang berbeda secara bersamaan, proses pekerja IIS (w3wp.exe) akan macet meninggalkan semua proses WinWord terbuka!Jadi saya kira tidak ada solusi absolut untuk masalah ini, tetapi beralih ke metode lain seperti pengembangan Office Open XML .
sumber
Jawaban yang diterima tidak berhasil untuk saya. Kode berikut dalam destructor melakukan pekerjaan.
sumber
Saat ini saya sedang mengerjakan otomatisasi Office dan menemukan solusi untuk ini yang berfungsi setiap saat untuk saya. Ini sederhana dan tidak melibatkan pembunuhan proses apa pun.
Tampaknya dengan hanya mengulang-ulang proses aktif saat ini, dan dengan cara apa pun 'mengakses' proses Excel terbuka, setiap instance Excel yang tersesat akan dihapus. Kode di bawah ini hanya memeriksa proses di mana namanya 'Excel', lalu menulis properti MainWindowTitle dari proses tersebut ke string. 'Interaksi' ini dengan proses tampaknya membuat Windows mengejar dan membatalkan contoh Excel yang beku.
Saya menjalankan metode di bawah ini tepat sebelum add-in di mana saya sedang mengembangkan berhenti, karena itu menyalakannya acara bongkar. Ini menghapus setiap contoh Excel yang menggantung setiap saat. Dalam semua kejujuran saya tidak sepenuhnya yakin mengapa ini bekerja, tetapi itu bekerja dengan baik bagi saya dan dapat ditempatkan di akhir setiap aplikasi Excel tanpa harus khawatir tentang titik ganda, Marshal.ReleaseComObject, atau proses pembunuhan. Saya akan sangat tertarik dengan saran mengapa ini efektif.
sumber
Saya berpikir bahwa beberapa di antaranya adalah cara framework menangani aplikasi Office, tapi saya bisa saja salah. Pada beberapa hari, beberapa aplikasi segera membersihkan prosesnya, dan beberapa hari lainnya sepertinya menunggu sampai aplikasi ditutup. Secara umum, saya berhenti memperhatikan detail dan hanya memastikan bahwa tidak ada proses tambahan yang beredar di akhir hari.
Juga, dan mungkin saya terlalu menyederhanakan hal, tapi saya pikir Anda bisa ...
Seperti yang saya katakan sebelumnya, saya tidak cenderung memperhatikan detail kapan proses Excel muncul atau menghilang, tetapi itu biasanya bekerja untuk saya. Saya juga tidak suka menjaga proses Excel sekitar untuk apa pun selain jumlah waktu minimal, tapi saya mungkin hanya paranoid karenanya.
sumber
Seperti beberapa mungkin sudah ditulis, bukan hanya penting bagaimana Anda menutup Excel (objek); itu juga penting bagaimana Anda membuka dan juga berdasarkan jenis proyeknya.
Dalam aplikasi WPF, pada dasarnya kode yang sama berfungsi tanpa atau dengan sedikit masalah.
Saya punya proyek di mana file Excel yang sama sedang diproses beberapa kali untuk nilai parameter yang berbeda - misalnya menguraikannya berdasarkan nilai-nilai di dalam daftar generik.
Saya meletakkan semua fungsi yang berhubungan dengan Excel ke dalam kelas dasar, dan parser ke dalam subkelas (parser yang berbeda menggunakan fungsi Excel yang umum). Saya tidak ingin Excel dibuka dan ditutup lagi untuk setiap item dalam daftar generik, jadi saya hanya membukanya sekali di kelas dasar dan menutupnya di subkelas. Saya mengalami masalah saat memindahkan kode ke aplikasi desktop. Saya sudah mencoba banyak solusi yang disebutkan di atas.
GC.Collect()
sudah diterapkan sebelumnya, dua kali seperti yang disarankan.Kemudian saya telah memutuskan bahwa saya akan memindahkan kode untuk membuka Excel ke subclass. Alih-alih membuka hanya sekali, sekarang saya membuat objek baru (kelas dasar) dan membuka Excel untuk setiap item dan menutupnya di akhir. Ada beberapa penalti kinerja, tetapi berdasarkan beberapa tes, proses Excel ditutup tanpa masalah (dalam mode debug), demikian juga file sementara dihapus. Saya akan melanjutkan pengujian dan menulis lebih banyak jika saya akan mendapatkan beberapa pembaruan.
Intinya adalah: Anda juga harus memeriksa kode inisialisasi, terutama jika Anda memiliki banyak kelas, dll.
sumber