Suchen Sie nach einer Alternative zu Windows-Nachrichten in Inter-Prozess-Kommunikation verwendet
-
21-08-2019 - |
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
- Empfangene Nachrichten sind unteilbar
- 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
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 PipesAuch 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.
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.
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)