Domanda

Ho una applicazione multithread (MIDAS) che si avvale di messaggi di windows per comunicare con se stesso.

FORM PRINCIPALE

La forma principale riceve i messaggi di windows inviato da RDM LogData(‘DataToLog’)

Perché i messaggi di windows vengono utilizzati sono i seguenti attributi

  1. I messaggi ricevuti sono Indivisibili
  2. I messaggi ricevuti sono in Coda nell'ordine in cui sono inviati

DOMANDA:

Si può Suggerire un modo migliore di fare questo senza l'utilizzo di messaggi di windows ?

MODULO PRINCIPALE CODICE

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;

CODICE RDM

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:

Perché voglio sbarazzarsi dei messaggi di windows:

  • Vorrei trasformare la domanda in un servizio di windows
  • Quando il sistema è occupato – il messaggio di windows buffer si riempie e cose rallenta
È stato utile?

Soluzione

Utilizzare Le Named Pipe.Se non sai come utilizzarli, quindi ora è il momento di imparare.

Con le named pipe, è possibile inviare qualsiasi tipo di struttura dati (purché sia il server che il client di sapere ciò che struttura dati è).Io di solito uso un array di record per inviare grandi raccolte di informazioni avanti e indietro.Molto utile.

Io uso Russell Libby libero (open-source) named pipe componenti.Viene fornito con un TPipeServer e un TPipeClient componente visiva.Fanno tramite named pipe incredibilmente facile, e named pipe sono grandi per inter-process communication (IPC).

È possibile ottenere il componente qui.La descrizione della fonte:// Descrizione :Set di client e server named pipe componenti per Delphi, come // una console tubo componente reindirizzamento.

Inoltre, Russell mi ha aiutato sul Esperti di Scambio con l'utilizzo di una versione precedente di questo componente a lavorare in un'applicazione di console per inviare/ricevere messaggi tramite named pipe.Questo può aiutare una guida per ottenere installato e funzionante con usando le sue componenti.Si prega di notare che in un VCL app o un servizio, non è necessario scrivere il proprio ciclo di messaggi, come ho fatto in questa applicazione console.

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.

Altri suggerimenti

Opzione 1:Messaggio Personalizzato Coda

È possibile creare un messaggio personalizzato coda di messaggi push e alla coda, ordinare la coda sulla base di regole di business, e pop i messaggi dalla coda dal thread principale per l'elaborazione.Utilizzare una sezione critica per la sincronizzazione.

Opzione 2:Richiamate

Utilizzare i callback per inviare i dati avanti e indietro dal thread.Ancora una volta, utilizzare una sezione critica per la sincronizzazione.

OmniThreadLibrary contiene molto efficiente coda di messaggi in OtlComm.pas unità.

La documentazione non è molto buono per il momento (inizia da qui ma si può sempre utilizzare il forum.

Sì – Gabr è possibile utilizzare i messaggi di windows in un servizio.

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

Prima di Windows Vista, si potrebbe avere configurato il servizio di interagire con il desktop.Che rende il servizio in esecuzione sullo stesso computer come un utente registrato, quindi, un programma in esecuzione come utente potrà inviare messaggi di servizio di windows.Windows Vista isolati servizi, anche se,non possono interagire con qualsiasi utente più il desktop.

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

Una Citazione da Rob Kennedy risposta ‘TService non elaborare i messaggi’

Ma non sarà in grado di utilizzare " frmMain.Maniglia " per inviare messaggi dal RDM al form principale in windows Vista.

Tutto quello che devo fare è trovare un modo diverso di invio e ricezione del messaggio

I Messaggi di Windows PUÒ ancora essere utilizzato in Windows Vista!Il problema è che una tecnologia in vista chiamato Interfaccia Utente Isolamento dei Privilegi a livello impedisce i processi con un basso livello di integrità (IL) dall'invio di messaggi a un processo con un alto IL (ad es.un servizio di windows ha un alto IL e in modalità utente in applicazioni di media IL).

Tuttavia, questo può essere ignorato e IL medio apps può essere consentito l'invio di wm alta IL processi.

Wikipedia dice che è meglio:

UIPI non è un limite di sicurezza, e non ha lo scopo di proteggere contro tutti in frantumi attacchi.Accessibilità dell'interfaccia utente Le applicazioni possono ignorare UIPI da impostazione delle loro "uiAccess" valore VERO come parte della loro file manifesto.Questo richiede l'applicazione per essere in Programma di File o di directory di Windows, come essere firmato da un codice valido diritto di firma, ma questi requisiti non necessariamente interrompere il malware dal loro rispetto.

Inoltre, alcuni messaggi sono ancora ammessi, per esempio WM_KEYDOWN, che consente un minor IL processo per unità di input di un elevato prompt dei comandi.

Infine, la funzione ChangeWindowMessageFilter permette un medio IL processo (tutti non elevata processi, ad eccezione di Internet Explorer La Modalità Protetta) per modificare i messaggi che un alto IL processo può ricevere inferiore IL processo.Questo efficacemente consente di bypassare UIPI, a meno che l'esecuzione di Internet Explorer o di uno dei suoi processi figli.

Qualcuno oltre a Delfi, la PRASSI (il link è in lingua tedesca.Usare Google per Tradurre la pagina) ha già affrontato questo problema e pubblicato il loro codice utilizzando ChangeWindowMessageFilter.Credo che il loro problema è che WM_COPYDATA non funzionare su Vista fino a quando hanno modificato il loro codice di bypass UIPI per WM_COPYDATA.

Original Link (In Tedesco)

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.

I creatori del madExcept biblioteca ecc fornire IPC funzionalità che può essere utilizzato invece di messaggi di Windows.

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

Ho sviluppato uno screensaver per Windows in uno stadio, e ho voluto ottenere il mio screensaver inviare una notifica a un altro programma, e mentre lo screensaver è attivo, sono stato in grado di ottenere i messaggi di finestra di lavoro tra le due applicazioni.

L'ho sostituita con l'IPC funzionalità di cui sopra.

Lavorato trattamento.

Io uso questa libreria per IPc (utilizza la memoria condivisa + mutex):http://17slon.com/gp/gp/gpsync.htm

Ha TGpMessageQueueReader e TGpMessageQueueWriter.Utilizzare "Globale\" davanti al nome, in modo che si può utilizzare per comunicare tra un Servizio di Windows e di un "Servizio GUI Helper" quando un utente si connette.(il Global\ prefisso è necessario per la Vista a causa della sessione di sicurezza, anelli, ma anche per Windows XP/2003 tra le sessioni utente).

È molto veloce, il multithreading, etc.Vorrei usare questo invece di WM_COPYDATA (lenta e molto di testa se si utilizza un sacco, ma per le piccole cose, i messaggi possono essere OK)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top