2009-12-26 15 views
5

Mam następujący odcinek kod, zaprojektowany, aby policzyć ile procesy Excel są obecnie otwarte:Jeśli "Process.HasExited" zgłasza wyjątek, czy mogę założyć, że proces już nie istnieje?

Func<int> OpenExcelProcessesCount = 
    () => System.Diagnostics.Process.GetProcessesByName("Excel") 
       .Where(p => !p.HasExited) 
       .Count(); 

A potem odzyskać licznik w różnych punktach, z kodem takich jak:

int excelAppCount = OpenExcelProcessesCount(); 

Ten kod od 100 miesięcy działa poprawnie w 100%. Potem nagle, dzisiaj jest konsekwentnie daje mi wyjątek, który odczytuje następujące:

Exception: ApplicationThreadException 

Message: Access is denied 

Stack Trace: 

    at System.Diagnostics.ProcessManager.OpenProcess(Int32 

ProcessID, Int32 dostępu, Boolean throwIfExited)

at System.Diagnostics.Process.GetProcessHandle(Int32 

dostępu, Boolean throwIfExited)

at System.Diagnostics.Process.get_HasExited() 

    etc... 

Zasadniczo połączenie z numerem Process.HasExited (który pojawia się jako System.Diagnostics.Process.get_HasExited() w śladzie stosu, powyżej) nie działa. Komunikat o błędzie "Odmowa dostępu" brzmi, jakbym nie miał uprawnień administratora do procesu, ale jedyne istniejące procesy Excela zostałyby utworzone przy moim bieżącym logowaniu użytkownika, a użytkownik zawsze może uzyskać dostęp do własnych procesów. Mój kod .NET również działa pod pełnym zaufaniem.

Linia, która ostatecznie zawodzi, to System.Diagnostics.ProcessManager.OpenProcess(Int32 processId, Int32 access, Boolean throwIfExited). Zastanawiam się, czy jest przekazywana w wartość "true" dla parametru "throwIfExited". W takim przypadku, przypuszczam, że mógłbym zabezpieczyć połączenie pod numerem Process.HasExited z blokiem try-catch i założyć, że jeśli to się nie powiedzie, to HasExited jest w rzeczywistości "prawdziwe". Ale czy to jest bezpieczne założenie?

Jestem nieswojo czyniąc takie założenie, zwłaszcza, że ​​komunikat o błędzie to "Odmowa dostępu". Czy ktoś ma jakieś pomysły na to, w jaki sposób mogę rozwiązać ten problem lub co mogę przetestować próbując dowiedzieć się, co się dzieje?

Jedyny podobny wątek jaki mogłem znaleźć na Stack Overflow był następujący: Why did hasExited throw ‘System.ComponentModel.Win32Exception’?. Odpowiedź udzielona było:

„Skoro robisz runas, tylko Ci SYNCHRONIZUJ dostęp na rączce, nie PROCESS_QUERY_INFORMATION dostępu stąd GetExitCodeProcess zawiedzie, które skutkuje hasEnded rzucanie Win32 wyjątek. "

Nie bardzo rozumiem tę odpowiedź i nie wiem, czy ma to zastosowanie w moim przypadku, ale pomyślałem, że powinienem o tym wspomnieć. Jeśli ktoś czuje, że jest prawdopodobne, że jest to sytuacja, w której się znajduję, to jeśli ktoś mógłby spróbować wyjaśnić mi tę odpowiedź, byłbym bardzo wdzięczny. (Jestem programista Excel, nie mam dużego doświadczenia w pracy z procesów.)

Much z góry dzięki ...

Aktualizacja:

najlepsze, co mogę powiedzieć, to jest było jednorazowa korupcja.Problemy, z którymi się zetknąłem zaczęły stawać się coraz bardziej dziwaczne, ponieważ to, co było doskonale funkcjonującym zestawem testów jednostkowych, zaczynało mieć awarie w innych "niemożliwych" lokalizacjach. Prosty restart spowodował naprawienie tego problemu i wszystkiego, z czym miałem do czynienia.

Przypuszczam, że miałem dziwne zepsucie. Być może ROT został skonfiskowany i/lub miałem wiszące wystąpienie Excela, które było tak zepsute, że nawet operacje "Process" niekoniecznie były stabilne. Nic ostatecznego, ale to wszystko, co mogę na razie wymyślić.

Do osób, które odpowiedziały, odpowiedziały i pomogły mi, dziękuję.

+3

„Zastanawiam się, czy jest ono przekazywane w wartości«true»dla parametru«throwIfExited»... jest to bezpieczne założenie? ? " Nie. Według Reflector, HasExited przekazuje wartość false dla throwIfExited. Ponadto, jeśli throwIfExited byłyby prawdziwe, wyjątek byłby wyjątkiem InvalidOperationException z komunikatem wskazującym, że proces został zakończony. (Niestety, nie mam odpowiedzi na twoje pytanie, ale pomyślałem, że warto o tym wspomnieć, aby nie tracić czasu na bezowocną teorię.) – itowlson

+0

Dzięki, itowlson, naprawdę doceniam informacje, to zdecydowanie pomaga. –

Odpowiedz

4

Podana przez Ciebie odpowiedź może dotyczyć Twojej sprawy. Jak rozumiem, zasadniczo mówi się, że jeśli proces, na który patrzysz, działa pod innym kontem użytkownika, wówczas HasExited nie może uzyskać uprawnień wymaganych do ustalenia, czy proces został zakończony.

Teraz mówisz, że "tylko istniejące procesy Excel zostałyby utworzone przy moim bieżącym logowaniu użytkownika". Ale załóżmy, że tak nie jest. Załóżmy, że istnieje inny proces Excel działający w tym samym polu, pod innym kontem użytkownika? (Może ktoś zaczął pracę z procesem innej osoby, używając Automatyzacji OLE, i nie został poprawnie oczyszczony lub zawiesił się). Wtedy GetProcessesByName podniosłoby to, ale HasExited zakończyłoby się niepowodzeniem.

Tak więc przed wywołaniem metody OpenExcelProcessesCount() należy dodać trochę rejestrowania, aby zrzucić identyfikatory procesów wszystkich procesów zwróconych przez GetProcessesByName ("Excel"). Następnie sprawdź je w Menedżerze zadań lub liczbie procesów programu Excel, które spodziewasz się uruchomić na swoim koncie. Jeśli istnieje taki identyfikator, który nie odpowiada "oczekiwanemu" procesowi programu Excel, możesz mieć winowajcę.

+0

Wielkie dzięki, naprawdę doceniam twoje myśli i wysiłki tutaj. Dam to spojrzenie. Nie widzę sposobu, w jaki może to być proces utworzony przy innym logowaniu, ponieważ jestem jedynym na tym komputerze i nie ma innych kont. Jednak myślę, że uszkodzona/uszkodzona instancja programu Excel * mogła * spowodować to. Wrócę po kolejnych testach ... –

+0

Domyślam się, że miałem jakieś dziwaczne zepsucie. Ponowne uruchomienie rozwiązało wszystko.Domyślam się, że ROT był zniekształcony i/lub miałem wiszącą instancję Excela, która była tak zepsuta, że ​​nawet operacje "Process" niekoniecznie były stabilne. Nic ostatecznego, ale to wszystko, na co mogę sobie teraz wyobrazić ... Doceniam pomoc. –

1

Po przeczytaniu the documentation:

użyć tej metody do utworzenia tablicy nowych elementów procesu i skojarzyć im wszystkich zasobów procesowych uruchomionych ten sam plik wykonywalny na komputerze lokalnym.

Wygląda na to, że nie trzeba sprawdzać HasExited, ponieważ zwraca on tylko uruchomione procesy.

+0

Dobra uwaga. Mój kod jest w najlepszym przypadku nadmiarowy i odpowiada warunkowi wyścigowemu, w którym "Process.HasExited" może zwrócić tylko "false", jeśli proces zwrócony przez "Process.GetProcessesByName" zakończył się w mikrosekundach między otrzymaniem instancji "Process" i przetestowaniem jej pod kątem "HasExited". Więc usunąłem teraz wezwanie do "HasExited". Poprzednia tajemnica pozostaje jednak, ale dzięki za pomoc! –

6

Process.HasExited może rzucić wyjątek odmowy dostępu, jeśli proces docelowy jest uruchomiony, a proces nie jest wykonywany. To samo dzieje się z własnością StartTime.

Oto blogu na ten temat, z możliwością rozwiązania: Bugs in System.Diagnostics.Process Class

+1

Dzięki Giorgi, to naprawdę dobra informacja. –

+0

@MikeRosenblum: Stacktrace również wygląda podobnie do tego, który mam na blogu. – Giorgi

Powiązane problemy