Máy bơm tin nhắn là gì?


104

Trong chủ đề này (được đăng khoảng một năm trước), có một cuộc thảo luận về các vấn đề có thể xảy ra khi chạy Word trong một phiên không tương tác. Lời khuyên (khá mạnh mẽ) được đưa ra là không nên làm như vậy. Trong một bài đăng, nó được nêu "Tất cả các API Office đều giả định rằng bạn đang chạy Office trong một phiên tương tác trên máy tính để bàn, với màn hình, bàn phím và chuột và quan trọng nhất là máy bơm thông báo." Tôi không chắc đó là gì. (Tôi mới lập trình bằng C # được khoảng một năm; kinh nghiệm lập trình khác của tôi chủ yếu là với ColdFusion.)

Cập nhật:

Chương trình của tôi chạy qua một số lượng lớn các tệp RTF để trích xuất hai phần thông tin được sử dụng để xây dựng một số báo cáo y tế. Thay vì thử và tìm ra cách hoạt động của các hướng dẫn định dạng trong RTF, tôi quyết định chỉ mở chúng trong Word và kéo văn bản ra từ đó (mà không thực sự khởi động GUI). Đôi khi, chương trình bị trục trặc khi đang xử lý một tệp và để mở một chuỗi Word được đính kèm với tài liệu đó (tôi vẫn phải tìm cách tắt luồng đó). Khi tôi chạy lại chương trình, tất nhiên tôi nhận được thông báo rằng có một chuỗi sử dụng tệp đó và tôi có muốn mở một bản sao chỉ đọc không? Khi tôi nói Có, Word GUI đột nhiên xuất hiện từ đâu và bắt đầu xử lý tệp. Tôi đã tự hỏi tại sao điều đó lại xảy ra;


3
Tại sao cái này được gắn thẻ là win32? - Hệ thống thông báo trong Windows V1 (Theo tôi nhớ là 8 bit.)
Hogan

Câu trả lời:


187

Vòng lặp thông báo là một đoạn mã nhỏ tồn tại trong bất kỳ chương trình Windows gốc nào. Đại khái là như thế này:

MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{ 
   TranslateMessage(&msg); 
   DispatchMessage(&msg); 
} 

API GetMessage () Win32 truy xuất thông báo từ Windows. Chương trình của bạn thường dành 99,9% thời gian ở đó, đợi Windows cho biết điều gì đó thú vị đã xảy ra. TranslateMessage () là một hàm trợ giúp dịch các tin nhắn trên bàn phím. DispatchMessage () đảm bảo rằng thủ tục cửa sổ được gọi với thông báo.

Mỗi chương trình .NET được kích hoạt GUI đều có một vòng lặp thông báo, nó được khởi động bởi Application.Run ().

Sự liên quan của vòng lặp thông báo với Office có liên quan đến COM. Các chương trình Office là các chương trình hỗ trợ COM, đó là cách hoạt động của các lớp Microsoft.Office.Interop. COM đảm nhận việc phân luồng thay cho lớp COM, nó đảm bảo rằng các cuộc gọi được thực hiện trên giao diện COM luôn được thực hiện từ đúng luồng. Hầu hết các lớp COM có một khóa đăng ký trong sổ đăng ký khai báo ThreadingModel của chúng, cho đến nay các lớp phổ biến nhất (bao gồm cả Office) sử dụng "Căn hộ". Có nghĩa là cách an toàn duy nhất để gọi một phương thức giao diện là thực hiện cuộc gọi từ cùng một luồng đã tạo đối tượng lớp. Hay nói một cách khác: cho đến nay hầu hết các lớp COM đều không an toàn cho luồng.

Mỗi chuỗi được kích hoạt COM thuộc về một căn hộ COM. Có hai loại, Căn hộ đơn luồng (STA) và Căn hộ đa luồng (MTA). Một lớp COM theo luồng căn hộ phải được tạo trên một luồng STA. Bạn có thể thấy điều này trong các chương trình .NET, điểm nhập của chuỗi giao diện người dùng của chương trình Windows Forms hoặc WPF có thuộc tính [STAThread]. Mô hình căn hộ cho các luồng khác được đặt bởi phương thức Thread.SetApartmentState ().

Các phần lớn của hệ thống ống nước Windows sẽ không hoạt động chính xác nếu chuỗi giao diện người dùng không phải là STA. Đáng chú ý là Kéo + Thả, khay nhớ tạm, hộp thoại Windows như OpenFileDialog, các điều khiển như WebBrowser, ứng dụng UI Automation như trình đọc màn hình. Và nhiều máy chủ COM, như Office.

Một yêu cầu khó đối với một luồng STA là nó không bao giờ được chặn và phải bơm một vòng lặp bản tin. Vòng lặp thông báo rất quan trọng vì đó là những gì COM sử dụng để điều khiển một cuộc gọi phương thức giao diện từ một luồng này sang một luồng khác. Mặc dù .NET làm cho các cuộc gọi sắp xếp sao chép dễ dàng (ví dụ: Control.BeginInvoke hoặc Dispatcher.BeginInvoke), nó thực sự là một việc rất khó thực hiện. Luồng thực hiện cuộc gọi phải ở trạng thái nổi tiếng. Bạn không thể chỉ tùy tiện ngắt một luồng và buộc nó thực hiện một cuộc gọi phương thức, điều đó sẽ gây ra các vấn đề về sự hấp dẫn lại khủng khiếp. Một luồng phải ở trạng thái "nhàn rỗi", không bận thực thi bất kỳ mã nào làm thay đổi trạng thái của chương trình.

Có lẽ bạn có thể thấy điều đó dẫn đến đâu: vâng, khi một chương trình đang thực hiện vòng lặp thông báo, nó sẽ không hoạt động. Việc sắp xếp thực sự diễn ra thông qua một cửa sổ ẩn mà COM tạo ra, nó sử dụng PostMessage để thủ tục cửa sổ của cửa sổ đó thực thi mã. Trên chuỗi STA. Vòng lặp thông báo đảm bảo rằng mã này chạy.


Câu trả lời rất hay và chi tiết. Chỉ cần nói thêm - cũng có một STA đặc biệt được gọi là STA chính, là STA đầu tiên được tạo ra. Lý tưởng nhất phải là cái được tạo bởi chuỗi giao diện người dùng của bạn. STA chính là nơi các thành phần có mô hình luồng = none được tạo. Nếu STA chính của bạn không phải là phần được tạo bởi luồng giao diện người dùng của bạn - bạn có thể gặp phải các vấn đề thú vị khi sử dụng các điều khiển activex cũ hơn không có mô hình luồng.
quixver

12

"Máy bơm thông báo" là một phần cốt lõi của bất kỳ chương trình Windows nào chịu trách nhiệm gửi thông báo chuyển cửa sổ tới các phần khác nhau của ứng dụng. Đây là cốt lõi của lập trình Win32 UI. Do tính phổ biến của nó, nhiều ứng dụng sử dụng máy bơm thông báo để chuyển thông báo giữa các mô-đun khác nhau, đó là lý do tại sao các ứng dụng Office sẽ bị hỏng nếu chúng được chạy mà không có bất kỳ giao diện người dùng nào.

Wikipedia có một mô tả cơ bản .


Tôi tin rằng không thể viết ứng dụng windows mà không có vòng lặp thông báo, do đó tất cả các ứng dụng đều sử dụng máy bơm thông báo.
Hogan

2
Bạn cũng có thể viết các ứng dụng GUI đơn giản mà không có - ví dụ: bạn có thể bật lên các hộp tin nhắn mà không cần ứng dụng của riêng bạn có vòng lặp thông báo trong ứng dụng của bạn.

Nếu bạn tạo một hộp thoại thông qua DialogBox hoặc DialogBox gián tiếp - bạn không cần vòng lặp thông báo, bạn chỉ cần cung cấp một hàm (dlgproc) sẽ được cửa sổ gọi đến. (và một hộp thông báo chỉ là một hộp thoại đơn giản)
quixver

6

John đang nói về cách hệ thống Windows (và các hệ thống dựa trên cửa sổ khác - X Window , Mac OS gốc ....) thực hiện giao diện người dùng không đồng bộ bằng cách sử dụng các sự kiện thông qua hệ thống tin nhắn.

Đằng sau mỗi ứng dụng có một hệ thống nhắn tin nơi mỗi cửa sổ có thể gửi sự kiện đến các cửa sổ khác hoặc trình nghe sự kiện - điều này được thực hiện bằng cách thêm một tin nhắn vào hàng đợi tin nhắn. Có một vòng lặp chính luôn chạy xem hàng đợi thông báo này và sau đó gửi các thông điệp (hoặc sự kiện) đến người nghe.

Bài viết Wikipedia Vòng lặp thông báo trong Microsoft Windows hiển thị mã ví dụ của một chương trình Windows cơ bản - và như bạn có thể thấy ở cấp độ cơ bản nhất, một chương trình Windows chỉ là "máy bơm thông báo".

Vì vậy, để kéo tất cả lại với nhau. Lý do chương trình windows được thiết kế để hỗ trợ giao diện người dùng không thể hoạt động như một dịch vụ là vì chương trình này cần vòng lặp thông báo luôn chạy để kích hoạt hỗ trợ giao diện người dùng. Nếu bạn triển khai nó dưới dạng một dịch vụ như được mô tả, nó sẽ không thể xử lý việc xử lý sự kiện không đồng bộ nội bộ.


6

Trong COM , một máy bơm thông báo nối tiếp và thông báo ngắt nối tiếp được gửi giữa các căn hộ. Căn hộ là một quy trình nhỏ trong đó các thành phần COM có thể được chạy. Căn hộ có các chế độ luồng đơn và luồng tự do. Các căn hộ đơn luồng chủ yếu là một hệ thống kế thừa cho các ứng dụng của các thành phần COM không hỗ trợ đa luồng. Chúng thường được sử dụng với Visual BASIC (vì điều này không hỗ trợ mã đa luồng) và các ứng dụng kế thừa.

Tôi đoán rằng yêu cầu bơm thông báo cho Word bắt nguồn từ API COM hoặc các phần của ứng dụng không an toàn cho chuỗi. Hãy nhớ rằng các mô hình phân luồng .NET và thu thập rác không hoạt động tốt với COM ra khỏi hộp. COM có một cơ chế thu gom rác rất đơn giản và mô hình phân luồng yêu cầu bạn thực hiện mọi thứ theo cách COM. Việc sử dụng Office PIA tiêu chuẩn vẫn yêu cầu bạn tắt rõ ràng các tham chiếu đối tượng COM, vì vậy bạn cần theo dõi mọi xử lý COM được tạo. PIA cũng sẽ tạo ra những thứ đằng sau hậu trường nếu bạn không cẩn thận.

Tích hợp .NET-COM tự nó là một chủ đề toàn bộ, và thậm chí còn có những cuốn sách viết về chủ đề này. Ngay cả khi sử dụng các API COM cho Office từ một ứng dụng tương tác trên máy tính để bàn cũng yêu cầu bạn chuyển qua các vòng và đảm bảo rằng các tham chiếu được phát hành một cách rõ ràng.

Office có thể được coi là không an toàn cho chuỗi, vì vậy bạn sẽ cần một phiên bản Word, Excel hoặc các ứng dụng Office khác cho mỗi chuỗi. Bạn sẽ phải chịu phí khởi đầu hoặc duy trì một nhóm chủ đề. Nhóm luồng sẽ phải được kiểm tra tỉ mỉ để đảm bảo tất cả các tham chiếu COM được phát hành chính xác. Ngay cả khi khởi động và tắt các phiên bản yêu cầu bạn phải đảm bảo tất cả các tham chiếu được phát hành chính xác. Việc không đánh dấu i của bạn và vượt qua chữ t của bạn ở đây sẽ dẫn đến một số lượng lớn các đối tượng COM đã chết và thậm chí toàn bộ phiên bản Word đang chạy bị rò rỉ.


1
Có một vài điểm không chính xác trong câu trả lời của bạn. Có 3 loại khoang - STA (Đơn ren), MTA (Đa luồng) và NTA (Trung tính). Luồng tự do được sử dụng để mô tả một thành phần tập hợp bộ điều phối luồng tự do, không có cái gọi là ngăn chứa luồng tự do. COM sử dụng các thông điệp để giao tiếp với các STA. Đối với các thành phần sống trong MTA (hoặc tổng hợp bộ điều phối luồng miễn phí) thì không cần vòng lặp thông báo. AFAIK - lpc được sử dụng để sắp xếp dữ liệu từ việc gọi luồng đến một luồng từ nhóm luồng RPC mà sau đó thực sự gọi phương thức.
quixver


0

Tôi nghĩ rằng cuộc thảo luận Kênh 9 này có một lời giải thích ngắn gọn thú vị:

Quá trình giao tiếp cửa sổ này được thực hiện nhờ cái gọi là Windows Message Pump. Hãy nghĩ về Message Pump như một thực thể cho phép hợp tác giữa các cửa sổ ứng dụng và màn hình nền.


2
wow ... đó là một trích dẫn khủng khiếp và gây hiểu lầm. (Một "thực thể"? Ơ .. không.)
Hogan

4
entity - object: thứ gì đó tồn tại dưới dạng hoặc được coi là một đối tượng riêng biệt encarta.msn.com/dictionary_1861608661/entity.html
Matthew Whited
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.