Frage

ich habe eine Multi-Thread-Anwendung (MIDAS), die Verwendung von Windows-Nachrichten für die Kommunikation mit sich selbst macht.

MAIN FORM

Die Hauptform erhält Windows-Nachrichten von der RDM gesendet LogData ( ‚DataToLog‘)

Da Windows-Nachrichten verwendet werden, haben sie die folgenden Attribute

  1. Empfangene Nachrichten sind unteilbar
  2. Empfangene Nachrichten werden in der Reihenfolge der Warteschlange sie gesendet werden

FRAGE:

Können Sie eine bessere Möglichkeit, dies zu tun, ohne Fenster Nachrichten mit?

MAIN FORM CODE

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 CODE

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:

Warum soll ich die Windows-Nachrichten loswerden:

  • Ich möchte die Anwendung in einen Windows-Dienst konvertieren
  • Wenn das System besetzt ist - die Windows-Nachrichtenpuffer voll ist und die Dinge verlangsamt
War es hilfreich?

Lösung

Verwenden von Named Pipes. Wenn Sie nicht wissen, wie sie zu benutzen, dann ist jetzt die Zeit zu lernen.

Mit Named Pipes können Sie jede Art von Datenstruktur (solange der Server und der Client wissen, was das Datenstruktur ist) senden. Normalerweise verwende ich eine Reihe von Aufzeichnungen große Sammlungen von Informationen her zurück und zu senden. Sehr praktisch.

Ich benutze Russell Libbys kostenlos (Open-Source) Named Pipe-Komponenten. Kommt mit einer TPipeServer und einer TPipeClient visuellen Komponente. Sie machen mit Named Pipes unglaublich einfach, und Named Pipes sind für Interprozesskommunikation (IPC).

Sie die Komponente bekommen hier . Die Beschreibung von der Quelle: // Beschreibung: Set von Client und Server Named Pipe-Komponenten für Delphi, als // auch eine Konsolenrohrumleitung Komponente.

zum Senden / Empfangen von Nachrichten über Named Pipes

Auch half Russell mir auf Experten-Austausch mit einer älteren Version dieser Komponente in einer Konsolenanwendung zu arbeiten. Dies kann als Leitfaden hilft Ihnen, in immer und läuft mit seinen Komponenten. Bitte beachten Sie, dass in einer VCL-Anwendung oder eine Dienstleistung, Sie brauchen nicht Ihre eigene Nachricht Schleife zu schreiben, wie ich in dieser Konsole App tat.

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.

Andere Tipps

Option 1: Custom Message Queue

Sie können eine benutzerdefinierte Nachrichtenwarteschlange, bauen und Push-Nachrichten an die Warteschlange, sortieren Sie die Warteschlange basierend auf Geschäftsregeln und Pop-Nachrichten aus der Warteschlange aus dem Haupt-Thread für die Verarbeitung. Verwenden Sie einen kritischen Abschnitt für die Synchronisation.

Option 2: Rückrufe

Rückrufe verwenden, um Daten zu senden, hin und her von den Fäden. Wieder einen kritischen Abschnitt für die Synchronisation verwendet werden.

OmniThreadLibrary enthält sehr effiziente Message-Queue in OtlComm.pas Einheit.

Dokumentation ist nicht sehr gut im Moment ( hier starten ), aber man kann immer die Forum .

Ja -. Gabr Sie Windows-Nachrichten in einem Dienst verwenden können,

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

Bevor Windows Vista, können Sie Ihren Service zur Interaktion mit dem Desktop konfiguriert haben. Das macht den Service läuft auf dem gleichen Desktop als angemeldeten Benutzer, also ein Programm, als dieser Benutzer ausgeführt Nachrichten senden könnte Fenster Ihren Dienstes. Windows Vista isoliert Dienste, obwohl; sie kann nicht mehr Zusammenarbeit mit dem Desktop des Benutzers interagieren.

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

Ein Zitat von Rob Kennedy Antwort auf 'TService werden keine Nachrichten verarbeiten'

Aber ich werde ‚frmMain.Handle‘ nicht in der Lage zu verwenden, um Nachrichten an das Hauptformular in Windows Vista von der RDM zu veröffentlichen.

Alles, was ich tun muß, ist eine andere Art des Beitrages zu finden und die Meldung erhalten,

Windows-Nachrichten können nach wie vor in Windows Vista verwendet werden! Die Frage auf der Hand, dass eine Technologie in Vista mit einem niedrigen Integritätslevel (IL) User Interface Privilege Isolation (UIPI) verhindert, dass Prozesse genannt von Nachrichten an eine proccess mit einem hohen IL sendet (zB ein Windows-Dienst hat ein hohes IL und benutzer- Modus Anwendungen haben Medium IL).

Allerdings kann diese Anwendungen umgangen und Medium IL werden können erlaubt sein WM zu hohen IL-Prozessen zu senden.

Wikipedia sagt es am besten:

  

UIPI ist keine Sicherheitsgrenze , und zielt nicht darauf ab zum Schutz vor   alle zertrümmern Angriffe. UI Accessibility   Anwendungen können UIPI umgehen, indem   Festlegung ihrer „uiAccess“ Wert auf TRUE   als Teil ihrer Manifest-Datei. Diese   erfordert die Anwendung in der sein   Programme oder Windows-Verzeichnis, wie   auch durch einen gültigen Code unterzeichnet werden   Behörde unterzeichnen, aber diese   Anforderungen nicht unbedingt stoppen   Malware von ihnen respektiert.

     

Darüber hinaus werden einige Nachrichten noch erlaubt durch, wie zum Beispiel   WM_KEYDOWN , die eine niedrigere IL erlaubt   Prozess Ansteuereingang auf eine erhöhte   Eingabeaufforderung.

     

Schließlich ist die Funktion   Change ermöglicht eine   Medium IL Prozess (alle nicht erhöhen   Prozesse außer Internet Explorer   Geschützter Modus) , um die Nachrichten zu ändern   dass ein hoher IL Prozess kann erhalten   von einem niedrigen IL-Prozess. Diese   effektiv ermöglicht unter Umgehung UIPI,   es sei denn, aus dem Internet Explorer ausgeführt werden   oder eines ihrer untergeordneten Prozesse.

Jemand über Delphi-PRAXIS (Link in deutscher Sprache. Google Verwenden Sie die Seite zu übersetzen) hat dieses Problem bereits in Angriff genommen und veröffentlichte ihren Code Change verwenden. Ich glaube, ihr Problem ist, dass WM_COPYDATA nicht auf Vista funktionieren würde, bis sie ihren Code geändert UIPI für WM_COPYDATA zu umgehen.

Original-Link (deutsch)

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.

Die Schöpfer der MadExcept Bibliothek usw. bieten IPC-Funktionalität, die anstelle von Windows-Nachrichten verwendet werden kann.

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

Ich entwickeln einen Windows-Bildschirmschoner zu einem bestimmten Zeitpunkt, und ich wollte meinen Bildschirmschoner bekommen einig Benachrichtigung an ein anderes Programm zu senden, und während des Bildschirmschoner aktiv war, war ich nicht in der Lage Fenstermeldungen zu erhalten zwischen den beiden Anwendungen zu arbeiten.

I ersetzt es mit der IPC-Funktionalität oben erwähnt wird.

Arbeitete einen Genuss.

Ich benutze diese Bibliothek für IPc (verwendet Speicher + Mutex gemeinsam): http://17slon.com/gp/gp/gpsync.htm

Es hat TGpMessageQueueReader und TGpMessageQueueWriter. Verwenden Sie „Global \“ vor dem Namen, so können Sie es verwenden, um zwischen einem Windows-Dienst und einem „Service GUI Helper“ zu kommunizieren, wenn sich ein Benutzer anmeldet. (Global \ Präfix für Vista benötigt wird, da der Sitzungssicherheitsringe, aber auch für Windows XP / 2003 zwischen Benutzersitzungen).

Es ist sehr schnell, multithreaded, usw. ich diese statt WM_COPYDATA verwenden würden (slow & viel Aufwand, wenn Sie es eine Menge zu verwenden, sondern auch für kleine Dinge können Nachrichten in Ordnung sein)

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top