Excel, lekib

Ma ei tea, kui paljud teist kunagi on pidanud tegema mingit Exceli automatiseerimise rakendust ning teavad sellest agooniast. Tõenäoselt mitte paljud, kuna kogenumad, arhitektiga meeskonnad oskavad sellisest lõksust hoiduda. Ma valgustan ülejäänuid. Jutt käib .NET 1.1-st. Kuulukse, et .NET 2.0 ja uus Visual Studio avavad Office'i automatiseerimisel uusi võimalusi.

Nimelt saab .NET 1.1 keskkonnas programmeerides üsna lihtsa vaevaga läbi MS Office'iga kaasatulevate COM wrapperite (Primary Interop Assemblies - PIA-s) kasutada Wordi, Exceli jm Office'i rakenduste võimalusi.

Kõlab hästi. Kahjuks kuni selle hetkeni, mil on vaja töö lõpetada ja kõik enese järelt ära koristada. Siis läheb raskeks. Osutub, et mingi COM pöördumiste jubin peab ise arvestust selle üle, kes ja kui mitme muutujaga tema peale viitab ning ei lase kord loodud COM objektil kaduda enne, kui tema arvab, et viiteid tema peale on järel 0tk. See tähendab, et kõik muutujad tuleb ka managed koodis explicitly deklareerida ja explicitly lahti lasta, s.t. kooditükk stiilis ((Microsoft.Office.Interop.Excel.Range)wSheet.Cells[offset_top + j,offset_left + k]) on saatanast ja peale selle käivitamist jääb ripakile üks Range objekt ning avatud Exceli rakendus ei sulgu.

Kasutaja masinas jooksvate rakenduste korral on mälulekked küll tõsine, ent mitte fataalne probleem, kuna enamus tavakasutajaid teeb aeg-ajalt (kasvõi sunnitult) restardi või lülitab oma masina välja ja sellega puhastab mälu igasugusest lekkinud saastast. Lisaks pole ühe kasutaja PC-s tõenäoselt kuigi suur päringute tihedus ja rakenduse crash segab korraga ainult ühte kasutajat. Omaette ja teenusena jooksvate serverirakenduste korral on lugu kole, kuna kui mäluleke juhtub 1% protsessi jooksmise kordadest, siis on poole päevaga serveri mälu täis, rakendus sigaaeglane ja telefoni otsas üpris mitu turris kasutajat.

Kujutame ette, et oleme deklareerinud kaks objekti, excelApp ja workBook. Nüüd tahaksime neist lahti saada:

//Close, Quit workBook.Close(false, Missing.Value, Missing.Value); excelApp.Quit();

//Release references System.Runtime.InteropServices.Marshal.ReleaseComObject (workBook); System.Runtime.InteropServices.Marshal.ReleaseComObject (excelApp);

//Null variables workBook = null; excelApp = null;

//Collect the garbage GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); GC.WaitForPendingFinalizers();

Üllatus! Task Manageri avades vaatab kõigest hoolimata vastu Excel.exe.

Osutus, et igasugune objektide koristamine ja lahtilaskmine ei pruugi aidata (vähe sellest, et suuremahulise rakenduse koodis on iga muutuja lahtilaskmist üpris keeruline taga ajada), seega lahendasin asja lihunikumeetodil - Excelit käivitades nuhkisin välja selle ProcessID ja hiljem sulgen selle protsessi läbi .NET võimaluste, puhastades niimoodi kogu väljakutsutud COM

//Fetch Excel process foreach (Process sProc in Process.GetProcesses()) { if (sProc.Id == ExcelProcessID) { sProc.Kill(); break; } }

Kõigele lisaks on Exceli kasutamine läbi Primary Interop Assembly'te ebameeldivalt aeglane ja töötab ainult LocaleID = 1033 (en-US) korral. Seega - hoiduge!

Microsofti ei kritiseeri, kuna selline käitumine on by design:

Leave a Reply


.pri.ee priiks!