2008-12-11 16 views
10

tôi là có một ứng dụng đa luồng (MIDAS) mà làm cho sử dụng các cửa sổ thông điệp để giao tiếp với chính nó.Tìm kiếm một sự thay thế cho cửa sổ thông điệp được sử dụng trong liên quá trình giao tiếp

MẪU TRANG CHỦ

Hình thức chính nhận được cửa sổ tin nhắn được gửi bởi RDM LogData ('DataToLog')

Bởi vì cửa sổ thông điệp được sử dụng họ có các thuộc tính sau đây

  1. thông điệp nhận được Không thể chia tách
  2. Thư đã nhận được xếp hàng theo thứ tự được gửi

HỎI:

bạn có thể đề nghị một cách tốt hơn làm điều này mà không sử dụng cửa sổ tin nhắn?

CHỦ MẪU MÃ

const 
    UM_LOGDATA  = WM_USER+1002; 

type 

    TLogData = Record 
     Msg  : TMsgNum; 
     Src  : Integer; 
     Data  : String; 
    end; 
    PLogData = ^TLogData; 


    TfrmMain = class(TForm) 
    // 
    private 
    procedure LogData(var Message: TMessage);  message UM_LOGDATA; 
    public 
    //   
    end; 


procedure TfrmMain.LogData(var Message: TMessage); 
var LData : PLogData; 
begin 
    LData := PLogData(Message.LParam); 
    SaveData(LData.Msg,LData.Src,LData.Data); 
    Dispose(LData); 
end; 

RDM MÃ

procedure TPostBoxRdm.LogData(DataToLog : String); 
var 
    WMsg : TMessage; 
    LData : PLogData; 
    Msg : TMsgNum; 
begin 
    Msg := MSG_POSTBOX_RDM; 
    WMsg.LParamLo := Integer(Msg); 
    WMsg.LParamHi := Length(DataToLog); 
    new(LData); 
    LData.Msg := Msg; 
    LData.Src := 255; 
    LData.Data := DataToLog; 
    WMsg.LParam := Integer(LData); 
    PostMessage(frmMain.Handle, UM_LOGDATA, Integer(Msg), WMsg.LParam); 
end; 

EDIT:

Tại sao tôi muốn thoát khỏi các cửa sổ thông điệp:

  • Tôi muốn chuyển đổi các ứng dụng vào một dịch vụ windows
  • Khi hệ thống đang bận - bộ đệm cửa sổ nhắn được đầy đủ và những thứ chậm
+0

Những loại vấn đề làm Thông báo Windows gây ra? IOW, bạn đang cố gắng giải quyết vấn đề gì? – gabr

+0

Bạn có thể sử dụng các tin nhắn cửa sổ trong dịch vụ Windows được Delphi viết. – gabr

Trả lời

10

Sử dụng Named Pipes. Nếu bạn không biết cách sử dụng chúng, thì bây giờ là lúc để học.

Với các đường ống được đặt tên, bạn có thể gửi bất kỳ loại cấu trúc dữ liệu nào (miễn là cả máy chủ lẫn máy khách đều biết cấu trúc dữ liệu đó là gì). Tôi thường sử dụng một loạt các bản ghi để gửi các bộ sưu tập thông tin lớn qua lại. Rất tiện dụng.

Tôi sử dụng các thành phần ống miễn phí (và mã nguồn mở) của Russell Libby. Đi kèm với một TPipeServer và một thành phần hình ảnh TPipeClient. Họ làm cho việc sử dụng các đường ống được đặt tên vô cùng dễ dàng và các đường ống có tên là rất tốt cho giao tiếp liên ngành (IPC).

You can get the component here. Mô tả từ nguồn là: // Mô tả: Thiết lập máy khách và máy chủ có tên là các thành phần đường ống cho Delphi, như là // cũng là một thành phần chuyển hướng ống điều khiển.

Ngoài ra, Russell đã giúp tôi trên Chuyên gia trao đổi với việc sử dụng phiên bản cũ hơn của thành phần này để làm việc trong ứng dụng bảng điều khiển để gửi/nhận tin nhắn trên các đường ống có tên. Điều này có thể giúp làm hướng dẫn giúp bạn và vận hành bằng cách sử dụng các thành phần của mình. Xin lưu ý rằng trong ứng dụng hoặc dịch vụ VCL, bạn không cần phải viết vòng lặp tin nhắn của riêng mình như tôi đã làm trong ứng dụng giao diện điều khiển này.

program CmdClient; 
{$APPTYPE CONSOLE} 

uses 
    Windows, Messages, SysUtils, Pipes; 

type 
    TPipeEventHandler = class(TObject) 
    public 
    procedure OnPipeSent(Sender: TObject; Pipe: HPIPE; Size: DWORD); 
    end; 

procedure TPipeEventHandler.OnPipeSent(Sender: TObject; Pipe: HPIPE; Size: DWORD); 
begin 
    WriteLn('On Pipe Sent has executed!'); 
end; 

var 
    lpMsg:   TMsg; 
    WideChars:  Array [0..255] of WideChar; 
    myString:  String; 
    iLength:  Integer; 
    pcHandler:  TPipeClient; 
    peHandler:  TPipeEventHandler; 

begin 

    // Create message queue for application 
    PeekMessage(lpMsg, 0, WM_USER, WM_USER, PM_NOREMOVE); 

    // Create client pipe handler 
    pcHandler:=TPipeClient.CreateUnowned; 
    // Resource protection 
    try 
    // Create event handler 
    peHandler:=TPipeEventHandler.Create; 
    // Resource protection 
    try 
     // Setup clien pipe 
     pcHandler.PipeName:='myNamedPipe'; 
     pcHandler.ServerName:='.'; 
     pcHandler.OnPipeSent:=peHandler.OnPipeSent; 
     // Resource protection 
     try 
      // Connect 
      if pcHandler.Connect(5000) then 
      begin 
       // Dispatch messages for pipe client 
       while PeekMessage(lpMsg, 0, 0, 0, PM_REMOVE) do DispatchMessage(lpMsg); 
       // Setup for send 
       myString:='the message I am sending'; 
       iLength:=Length(myString) + 1; 
       StringToWideChar(myString, wideChars, iLength); 
       // Send pipe message 
       if pcHandler.Write(wideChars, iLength * 2) then 
       begin 
       // Flush the pipe buffers 
       pcHandler.FlushPipeBuffers; 
       // Get the message 
       if GetMessage(lpMsg, pcHandler.WindowHandle, 0, 0) then DispatchMessage(lpMsg); 
       end; 
      end 
      else 
       // Failed to connect 
       WriteLn('Failed to connect to ', pcHandler.PipeName); 
     finally 
      // Show complete 
      Write('Complete...'); 
      // Delay 
      ReadLn; 
     end; 
    finally 
     // Disconnect event handler 
     pcHandler.OnPipeSent:=nil; 
     // Free event handler 
     peHandler.Free; 
    end; 
    finally 
    // Free pipe client 
    pcHandler.Free; 
    end; 

end. 
2

Lựa chọn 1: Tuỳ chỉnh Message Queue

Bạn có thể xây dựng một hàng đợi thông điệp tùy chỉnh, và đẩy các thông điệp vào hàng đợi, sắp xếp hàng đợi dựa trên các quy tắc kinh doanh, và tin nhắn pop từ hàng đợi từ các chủ đề chính để xử lý. Sử dụng một phần quan trọng để đồng bộ hóa.

Tùy chọn 2: Gọi lại

Sử dụng gọi lại để gửi dữ liệu qua lại từ chủ đề. Một lần nữa, sử dụng một phần quan trọng để đồng bộ hóa.

2

OmniThreadLibrary chứa hàng đợi tin nhắn rất hiệu quả trong đơn vị OtlComm.pas.

Tài liệu không phải lúc nào cũng tốt (start here) nhưng bạn luôn có thể sử dụng forum.

+1

Tôi sẽ không đề xuất thêm toàn bộ thư viện luồng mới chỉ đơn giản cho hàng đợi thư của nó. Sử dụng OmniThreadLibrary nếu bạn đang tìm kiếm một thư viện luồng khác nhau (và nó có chất lượng rất cao). – Mick

+1

Tôi đồng ý. Nhưng bạn không phải sử dụng thư viện luồng OTL để sử dụng hệ thống con truyền thông. Đơn vị OtlComm là khá độc lập và có thể được sử dụng với bất kỳ mô hình luồng nào cũng như trong các ứng dụng đơn luồng. – gabr

+0

Tôi không biết điều đó. Tốt để biết! – Mick

2

Có - Gabr bạn có thể sử dụng tin nhắn cửa sổ trong một dịch vụ.

==============================

Trước khi Windows Vista, bạn có thể cấu hình dịch vụ của bạn tương tác với máy tính để bàn.Điều đó làm cho dịch vụ chạy trên cùng một máy tính để bàn với tư cách người dùng đã đăng nhập, vì vậy một chương trình đang chạy khi người dùng đó có thể gửi tin nhắn đến các cửa sổ của dịch vụ của bạn. Tuy nhiên, Windows Vista vẫn cách ly các dịch vụ; họ không thể tương tác với bất kỳ máy tính để bàn của người dùng nữa.

=============================

Một Trích từ Rob Kennedy trả lời cho ‘TService won’t process messages’

Nhưng tôi sẽ không thể sử dụng 'frmMain.Handle' để đăng thông báo từ RDM lên biểu mẫu chính trong Windows Vista.

Tất cả tôi cần làm là tìm một cách khác nhau của đăng & nhận được thông báo

+0

Không biết điều đó - cảm ơn thông tin! – gabr

0

Tin nhắn Windows vẫn có thể được sử dụng trong Windows Vista! Vấn đề ở chỗ là một công nghệ có tên là User Interface Privilege Isolation (UIPI) ngăn chặn các tiến trình có mức độ toàn vẹn thấp hơn (IL) từ việc gửi tin nhắn đến một proccess với một IL cao (ví dụ: dịch vụ windows có IL và user cao) ứng dụng chế độ có IL trung bình).

Tuy nhiên, điều này có thể bị bỏ qua và các ứng dụng IL trung bình có thể được phép gửi các quy trình IL cao.

Wikipedia says it best:

UIPI không phải là một ranh giới an ninh, và không nhằm mục đích để bảo vệ chống lại tất cả các cuộc tấn công vỡ. UI Accessibility Ứng dụng có thể bỏ qua UIPI bằng cách đặt giá trị "uiAccess" của chúng thành TRUE như một phần của tệp kê khai. Yêu cầu yêu cầu ứng dụng nằm trong thư mục Tệp chương trình hoặc Windows, như cũng như được ký bởi mã hợp lệ quyền ký, nhưng các yêu cầu này sẽ không nhất thiết phải dừng lại phần mềm độc hại khỏi việc tôn trọng chúng.

Thêm vào đó, một số tin nhắn được vẫn được phép thông qua, chẳng hạn như WM_KEYDOWN, cho phép thấp hơn quá trình IL lái xe đầu vào cho một dấu nhắc lệnh cao.

Cuối cùng, hàm ChangeWindowMessageFilter cho phép một vừa IL quá trình (tất cả không cao quá trình trừ Internet Explorer Protected Mode) để thay đổi các thông điệp rằng một quá trình IL cao có thể nhận từ IL thấp quá trình. hiệu quả này cho phép bỏ qua UIPI, trừ khi chạy từ Internet Explorer hoặc một trong các quy trình con của nó.

Ai đó ở tại Delphi-PRAXIS (liên kết bằng tiếng Đức. Sử dụng Google để dịch trang) đã giải quyết vấn đề này và đăng mã của họ bằng ChangeWindowMessageFilter. Tôi tin rằng vấn đề của họ là WM_COPYDATA sẽ không hoạt động trên Vista cho đến khi họ sửa đổi mã của họ để bỏ qua UIPI cho WM_COPYDATA.

Original Link (German)

unit uMain; 

interface 

uses 
    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 
    Dialogs, ExtCtrls, StdCtrls, uallHook, uallProcess, uallUtil, uallKernel; 

type 
    TfrmMain = class(TForm) 
    lbl1: TLabel; 
    tmrSearchCondor: TTimer; 
    mmo1: TMemo; 
    procedure FormCreate(Sender: TObject); 
    procedure tmrSearchCondorTimer(Sender: TObject); 
    procedure FormDestroy(Sender: TObject); 
    private 
    { Private-Deklarationen } 
    fCondorPID : DWord; 
    fInjected : Boolean; 
    fDontWork : Boolean; 
    procedure SearchCondor; 
    procedure InjectMyFunctions; 
    procedure UnloadMyFunctions; 
    function GetDebugPrivileges : Boolean; 
    procedure WriteText(s : string); 
    procedure WMNOTIFYCD(var Msg: TWMCopyData); message WM_COPYDATA; 
    public 
    { Public-Deklarationen } 
    end; 

var 
    frmMain: TfrmMain; 
    ChangeWindowMessageFilter: function (msg : Cardinal; dwFlag : Word) : BOOL; stdcall; 

implementation 

{$R *.dfm} 

type Tmydata = packed record 
     datacount: integer; 
     ind: boolean; 
    end; 

const cCondorApplication = 'notepad.exe'; 
     cinjComFuntionsDLL = 'injComFunctions.dll'; 

var myData : TMydata; 

procedure TfrmMain.WMNOTIFYCD(var Msg: TWMCopyData); 
begin 
    if Msg.CopyDataStruct^.cbData = sizeof(TMydata) then 
    begin 
    CopyMemory(@myData,Msg.CopyDataStruct^.lpData,sizeof(TMyData)); 
    WriteText(IntToStr(mydata.datacount)) 
    end; 
end; 

procedure TfrmMain.WriteText(s : string); 
begin 
    mmo1.Lines.Add(DateTimeToStr(now) + ':> ' + s); 
end; 

procedure TfrmMain.InjectMyFunctions; 
begin 
    if not fInjected then begin 
    if InjectLibrary(fCondorPID, PChar(GetExeDirectory + cinjComFuntionsDLL)) then fInjected := True; 
    end; 
end; 

procedure TfrmMain.UnloadMyFunctions; 
begin 
    if fInjected then begin 
    UnloadLibrary(fCondorPID, PChar(GetExeDirectory + cinjComFuntionsDLL)); 
    fInjected := False; 
    end; 
end; 

procedure TfrmMain.SearchCondor; 
begin 
    fCondorPID := FindProcess(cCondorApplication); 
    if fCondorPID <> 0 then begin 
    lbl1.Caption := 'Notepad is running!'; 
    InjectMyFunctions; 
    end else begin 
    lbl1.Caption := 'Notepad isn''t running!'; 
    end; 
end; 

procedure TfrmMain.FormDestroy(Sender: TObject); 
begin 
    UnloadMyFunctions; 
end; 

function TfrmMain.GetDebugPrivileges : Boolean; 
begin 
    Result := False; 
    if not SetDebugPrivilege(SE_PRIVILEGE_ENABLED) then begin 
    Application.MessageBox('No Debug rights!', 'Error', MB_OK); 
    end else begin 
    Result := True; 
    end; 
end; 

procedure TfrmMain.FormCreate(Sender: TObject); 
begin 
    @ChangeWindowMessageFilter := GetProcAddress(LoadLibrary('user32.dll'), 'ChangeWindowMessageFilter'); 
    ChangeWindowMessageFilter(WM_COPYDATA, 1); 
    fInjected := False; 
    fDontWork := not GetDebugPrivileges; 
    tmrSearchCondor.Enabled := not fDontWork; 
end; 

procedure TfrmMain.tmrSearchCondorTimer(Sender: TObject); 
begin 
    tmrSearchCondor.Enabled := False; 
    SearchCondor; 
    tmrSearchCondor.Enabled := True; 
end; 

end. 
0

Các tác giả của thư viện madExcept vv cung cấp chức năng IPC mà có thể được sử dụng thay cho thông điệp của Windows.

http://help.madshi.net/IPC.htm

tôi đã phát triển một màn hình Windows ở một sân khấu, và tôi muốn để có được bảo vệ màn hình của tôi để gửi một số thông báo cho một chương trình khác, và trong khi bảo vệ màn hình đã hoạt động, tôi đã không thể nhận được tin nhắn cửa sổ để làm việc giữa hai ứng dụng.

Tôi đã thay thế bằng chức năng IPC được đề cập ở trên.

Đã xử lý.

0

tôi sử dụng thư viện này cho IPC (sử dụng bộ nhớ chia sẻ + mutex): http://17slon.com/gp/gp/gpsync.htm

Nó có TGpMessageQueueReader và TGpMessageQueueWriter. Sử dụng "Global \" trước tên, để bạn có thể sử dụng nó để giao tiếp giữa Windows Service và "Service GUI Helper" khi người dùng đăng nhập. (Global \ prefix là cần thiết cho Vista vì vòng bảo mật phiên, mà còn cho Windows XP/2003 giữa các phiên người dùng).

Nó rất nhanh, đa luồng, vv Tôi sẽ sử dụng cái này thay vì WM_COPYDATA (chậm & nhiều overhead nếu bạn sử dụng nó rất nhiều, nhưng đối với những điều nhỏ nhặt thông điệp có thể OK)