2009-05-08 35 views
9

Có thể chụp quá trình kết thúc trình quản lý tác vụ của một ứng dụng cửa sổ trong chính ứng dụng cửa sổ đó không? Tôi đang sử dụng một ứng dụng giành chiến thắng C# 2.0 và tôi muốn làm một số xử lý cơ sở dữ liệu (thay đổi một lá cờ từ 'Y' thành 'N' trong DB) khi một quá trình kết thúc xảy ra.Xử lý quá trình kết thúc của một ứng dụng cửa sổ

Trả lời

10

Không, không thể kết thúc quyết định của hệ điều hành để kết thúc quá trình. Lưu ý, điều này không được thực hiện bởi trình quản lý tác vụ, kết thúc quá trình là trách nhiệm của hạt nhân.

Bạn sẽ cần phải làm hai việc ở đây:

  1. Connect xử lý sự kiện để các thông điệp giao diện người dùng bình thường mà nói với một ứng dụng để thoát. Sử dụng các sự kiện này để lưu trữ dữ liệu, tài nguyên miễn phí và thoát ra một cách rõ ràng.
  2. Xử lý ngoại lệ phù hợp để phát hiện lỗi và dọn dẹp và lưu dữ liệu nếu có thể.

Dưới đây là ba liên kết tới blog của Raymond giải thích lý do bạn không thể làm những gì bạn đang yêu cầu.

Ngoài ra, tôi giải quyết một câu hỏi tương tự StackOverflow here.

+0

Có, tôi có thể xử lý sự kiện. Tuy nhiên, nếu người dùng thực hiện một quá trình kết thúc từ trình quản lý tác vụ, anh ta sẽ vẫn bị gắn cờ là "đăng nhập" trong cơ sở dữ liệu và khi anh ta cố đăng nhập lại, anh ta sẽ không được phép. Bây giờ tôi biết lý do tại sao thông báo kết thúc nói rằng 'Bạn không thể lưu bất kỳ dữ liệu chưa được lưu ... v.v. " –

+0

Phải - điều này là do thiết kế. Hãy tưởng tượng nếu Windows cho phép ứng dụng móc cuộc gọi đến TerminateProcess(). Task scheduler không được thiết kế để được sử dụng để bình thường kết thúc một quá trình - một khẩu súng của nó - nó được thiết kế để tiêu diệt các quá trình, không phải là kết thúc chúng theo một cách có trật tự. lưu trữ dữ liệu bền vững, nhưng nếu người dùng muốn quá trình của bạn dừng lại, TerminateProcess() sẽ làm điều đó ngay tại đó và – Foredecker

+0

Tất cả những âm thanh này giống như Rashmi P. không thấy rừng từ cây. Quá trình mới sẽ tạo ra kết nối mới, không có vấn đề gì cả, – GregC

1

Điều bạn có thể làm là lấy ID tiến trình và theo dõi quy trình và bạn có thể sử dụng thuộc tính HasExited để kiểm tra xem quá trình có kết thúc hay không. Dưới đây là một mã VB nhanh (Xin lỗi tôi không có VS bây giờ. Điều này đã được viết bởi tôi ở diễn đàn khác)

Public Class Form1 
    Dim p As ProcessStartInfo 
    Dim process As Process 
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click 
     p = New ProcessStartInfo("iexplore.exe") 
     process = process.Start(p) 
    End Sub 

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click 
     MsgBox(process.Id) 
     If process.HasExited Then 
      MsgBox("yes") 
     Else 
      MsgBox("no") 
     End If 
    End Sub 
End Class 

Trên đang bắt đầu InternetExplorer và kiểm tra nút cho dù quá trình này có chấm dứt hay không. Bạn có thể sử dụng một quá trình tương tự để có được tất cả quá trình đang chạy và sử dụng processID.

+0

hey Shoban, tôi có thể nắm bắt được một quá trình bên ngoài cuối ứng dụng (notepad iexplorem, vv) sử dụng ma cua ban.Nhưng tôi nên làm gì để nắm bắt nhiệm vụ kết thúc trên cùng một ứng dụng (một trong đó có chứa Form1 trong mã ur ở trên) –

+0

Ông nói, "trong cùng một ứng dụng cửa sổ chính nó". –

+1

Bạn không thể làm điều đó trong cùng một ứng dụng, vì vậy ý ​​tưởng của Shoban gần như bạn có thể nhận được. – RichieHindle

1

Tôi không nghĩ rằng điều này có thể thực hiện được từ bên trong ứng dụng. Mục đích của End Task là ngay lập tức dừng quá trình. Điều này không cho phép bất kỳ mã làm sạch nào để thực thi.

Shoban đã chỉ ra một cách khác để đạt được mục tiêu của bạn. Một ứng dụng hoặc dịch vụ khác sẽ cần tìm quy trình chính. Khi quá trình khác không thể tìm thấy quy trình chính, bạn có thể thực hiện xử lý cơ sở dữ liệu tại thời điểm đó.

3

Cách tiếp cận hơi khác:

Ứng dụng của bạn cập nhật trường thời gian ngày, ví dụ: LastPollDate thường xuyên như vậy trong khi nó đang chạy và có một trường riêng biệt, ví dụ: "AppTerminatedNormally" mà bạn đặt thành N và đổi thành Y nếu bạn nhận được sự kiện đóng biểu mẫu.

Nếu ứng dụng bị giết thông qua Trình quản lý tác vụ, ngày đó sẽ không được cập nhật nữa và ngày AppTerminated của bạn sẽ vẫn không có.

Bằng cách này bạn có thể chạy truy vấn tìm thấy tất cả các hàng mà LastPollDate cũ hơn 10 phút và AppTerminatedNormally là N và bạn sẽ có tất cả các phiên bị kết thúc bất thường.

+0

Đây là cách tốt để đi. Cảm ơn – Sakthivel

2

Bạn đang chuẩn bị nhổ bài đăng này, nhưng ở đây ...

Bạn đang cố giải quyết sự cố ở cấp độ sai (tức là đang chạy mã trong ứng dụng của bạn khi kernal đang giết ứng dụng). Vấn đề thực sự là đảm bảo rằng cơ sở dữ liệu phản ánh chính xác sự hiện diện (hoặc vắng mặt) của ứng dụng khách của nó/s.

Để giải quyết vấn đề này, tránh cho phép ứng dụng ở trạng thái "không tương thích" giữa các tương tác của người dùng. Nói cách khác, không bắt đầu các giao dịch mà bạn không thể cam kết nhanh chóng, không ghi dữ liệu vào các tệp để tệp ở trạng thái được viết một nửa hoặc không đọc được và không giữ tài nguyên ở bên ngoài ứng dụng của bạn một cách không phù hợp trạng thái bên ngoài tương tác của người dùng. Đặt một cách khác, nếu ứng dụng của bạn không bận rộn trả lời một trình xử lý sự kiện, nó sẽ sẵn sàng đóng ngay lập tức.

Nếu bạn thực hiện theo phương pháp trên, bạn sẽ thấy rất ít trường hợp mà bạn cần "dọn dẹp nhanh" trước khi chấm dứt. Bên ngoài các tương tác mà người dùng nhấp vào "OK" hoặc "Lưu", v.v. một ứng dụng được viết tốt sẽ có thể tồn tại ngay lập tức chấm dứt mà không có bất kỳ thiệt hại lâu dài hoặc tham nhũng của các cửa hàng dữ liệu của nó.

Nếu bạn hoàn toàn phải thiết lập một lá cờ trong cơ sở dữ liệu khi xuất cảnh (mà âm thanh đặc trưng của một mô hình sử dụng để phát hiện xem một người dùng đang đăng nhập hay không), sau đó xem xét một trong các phương thức sau:

  1. Định kỳ (có lẽ sau mỗi 30 giây) chèn/cập nhật trường thời gian giống như dấu thời gian trong cơ sở dữ liệu, để cho biết gần đây một ứng dụng đã trực tuyến như thế nào. Các ứng dụng khác có thể kiểm tra các dấu thời gian này để xác định mức độ gần đây của một ứng dụng khác đang trực tuyến ... nếu giá trị nằm trong 30 giây cuối cùng, ứng dụng kia vẫn là opnline.

  2. Như Woodhenge đã đề xuất đúng, tạo một quy trình riêng biệt (lý tưởng là dịch vụ) để theo dõi trạng thái của ứng dụng chính. Các dịch vụ Windows có thể được cấu hình để tự động khởi động lại trong trường hợp không có dịch vụ. Quá trình giám sát này sau đó sẽ phát hành các dấu thời gian cho cơ sở dữ liệu.

Chú ý rằng cả các đề nghị trên giải quyết vấn đề thực tế (phát hiện xem các ứng dụng đang truy cập vào cơ sở dữ liệu) mà không bao giờ rời khỏi cơ sở dữ liệu trong một "nhà nước không thích hợp" (cờ nói trên là "Y" khi ứng dụng là thực tế đã chết và cờ phải là "N").

2

Nếu bạn đang nhắm mục tiêu Windows Vista (hoặc cao hơn), bạn có thể quan tâm trong API RegisterApplicationRecoveryCallback ...

http://msdn.microsoft.com/en-us/library/aa373345.aspx

Nó cho phép bạn chỉ định một thói quen gọi lại trong ứng dụng của bạn mà sẽ được gọi khi quá trình sắp sửa sụp đổ. N.B. nó chỉ dành cho các sự cố, và sẽ không tự động được gọi nếu quá trình này bị giết một cách có chủ ý.

Bạn có thể p/gọi API này từ C# (tôi đã làm), nhưng hãy nhớ rằng khi gọi lại của bạn được gọi ứng dụng của bạn đã ở trạng thái rất xấu và bạn có thể đưa ra rất ít giả định về trạng thái bộ nhớ của bạn. Nếu bạn có bất kỳ dữ liệu nào trong bộ nhớ mà bạn muốn sử dụng trong thường trình này, tôi sẽ đặt nó trong một vùng tĩnh ở một phạm vi rất chung để bạn có cơ hội tốt nhất mà không bị "dọn dẹp" khi thường xuyên gọi lại của bạn chạy.

Có một số API khác thú vị, liên quan đến thế này, cho phép bạn tự động khởi động lại ứng dụng của bạn sau một thất bại vv

+0

xin cảm ơn Martin ... tôi sẽ xem xét điều này :) –

Các vấn đề liên quan