través sistemas procesos ppt por paso operativos mensajes inter entre ejemplos distribuidos cooperacion comunicación comunicacion delphi winapi windows-vista window-messages

delphi - sistemas - Buscando una alternativa a los mensajes de Windows utilizados en la comunicación entre procesos



cooperacion entre procesos por comunicacion (7)

Tengo una aplicación multiproceso (MIDAS) que hace uso de los mensajes de Windows para comunicarse consigo mismo.

FORMA PRINCIPAL

El formulario principal recibe mensajes de Windows enviados por RDM LogData (''DataToLog'')

Debido a que se usan mensajes de Windows, tienen los siguientes atributos

  1. Los mensajes recibidos son indivisibles
  2. Los mensajes recibidos se ponen en cola en el orden en que se envían

PREGUNTA:

¿Puedes sugerir una manera mejor de hacerlo sin usar mensajes de Windows?

CÓDIGO PRINCIPAL

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;

CÓDIGO 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;

EDITAR:

Por qué quiero deshacerme de los mensajes de Windows:

  • Me gustaría convertir la aplicación en un servicio de Windows
  • Cuando el sistema está ocupado, el búfer de mensajes de Windows se llena y las cosas se ralentizan

¡Los mensajes de Windows PUEDEN aún ser utilizados en Windows Vista! El problema es que una tecnología en vista llamada Aislamiento de privilegios de interfaz de usuario (UIPI) impide que los procesos con un nivel de integridad inferior (IL) envíen mensajes a un proceso con un alto IL (por ejemplo, un servicio de Windows tiene un IL alto y las aplicaciones de modo tienen IL medio).

Sin embargo, esto puede pasarse por alto y las aplicaciones de IL medianas pueden enviar WM a procesos de alta IL.

Wikipedia lo dice mejor:

UIPI no es un límite de seguridad , y no apunta a proteger contra todos los ataques de desintegración. Las aplicaciones de accesibilidad UI pueden eludir UIPI configurando su valor "uiAccess" en TRUE como parte de su archivo de manifiesto. Esto requiere que la aplicación esté en el directorio Archivos de programa o Windows, así como que esté firmada por una autoridad de firma de código válida, pero estos requisitos no impedirán necesariamente que el malware los respete.

Además, algunos mensajes todavía están permitidos, como WM_KEYDOWN , que permite que un proceso IL más bajo active la entrada a un símbolo del sistema elevado.

Finalmente, la función ChangeWindowMessageFilter permite que un proceso de IL medio (todos los procesos no elevados, excepto el Modo protegido de Internet Explorer) cambie los mensajes que un proceso de IL alto puede recibir de un proceso de IL más bajo. Esto efectivamente permite pasar por encima de UIPI, a menos que se ejecute desde Internet Explorer o uno de sus procesos secundarios.

Alguien en Delphi-PRAXIS (el enlace está en alemán. Usa Google para Traducir la página) ya ha abordado este problema y ha publicado su código usando ChangeWindowMessageFilter. Creo que su problema es que WM_COPYDATA no funcionaría en Vista hasta que modificaran su código para eludir UIPI para WM_COPYDATA.

Enlace original (alemán)

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.


Los creadores de la biblioteca madExcept etc proporcionan funcionalidad IPC que se puede utilizar en lugar de los mensajes de Windows.

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

Desarrollé un protector de pantalla de Windows en una etapa, y quería que mi protector de pantalla enviara una notificación a otro programa, y ​​aunque el protector de pantalla estaba activo, no pude conseguir que los mensajes de la ventana funcionaran entre las dos aplicaciones.

Lo reemplacé con la funcionalidad de IPC mencionada anteriormente.

Funcionó una delicia.


Opción 1: cola de mensajes personalizados

Puede crear una cola de mensajes personalizada y enviar mensajes a la cola, ordenar la cola en función de las reglas comerciales y extraer los mensajes de la cola de la secuencia principal para su procesamiento. Use una sección crítica para la sincronización.

Opción 2: retrollamadas

Use las devoluciones de llamada para enviar datos hacia adelante y hacia atrás desde los hilos. De nuevo, use una sección crítica para la sincronización.


Sí, Gabr puede usar los mensajes de Windows en un servicio.

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

Antes de Windows Vista, podría haber configurado su servicio para interactuar con el escritorio. Eso hace que el servicio se ejecute en el mismo escritorio que un usuario conectado, por lo que un programa que se ejecute como ese usuario podría enviar mensajes a las ventanas de su servicio. Sin embargo, Windows Vista aísla los servicios; ya no pueden interactuar con el escritorio de ningún usuario.

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

Una cita de Rob Kennedy responde a ''TService no procesará mensajes''

Pero no podré usar ''frmMain.Handle'' para publicar mensajes del RDM al formulario principal en Windows Vista.

Todo lo que necesito hacer es encontrar una forma diferente de publicar y recibir el mensaje


Use tuberías con nombre. Si no sabe cómo usarlos, entonces ahora es el momento de aprender.

Con las canalizaciones con nombre, puede enviar cualquier tipo de estructura de datos (siempre que tanto el servidor como el cliente sepan qué es esa estructura de datos). Usualmente utilizo una variedad de registros para enviar grandes colecciones de información de ida y vuelta. Muy útil.

Uso los componentes de tubería con nombre libre (y de código abierto) de Russell Libby. Viene con un TPipeServer y un componente visual TPipeClient. Hacen que el uso de las tuberías con nombre sea increíblemente fácil, y las tuberías con nombre son excelentes para la comunicación entre procesos (IPC).

Puedes obtener el componente aquí . La descripción de la fuente es: // Descripción: Conjunto de componentes de canal con nombre de cliente y servidor para Delphi, como // bien un componente de redirección de canal de consola.

Además, Russell me ayudó en Experts-Exchange con el uso de una versión anterior de este componente para trabajar en una aplicación de consola para enviar / recibir mensajes por conductos específicos. Esto puede ayudar como una guía para ponerlo en funcionamiento con el uso de sus componentes. Tenga en cuenta que en una aplicación o servicio VCL, no necesita escribir su propio bucle de mensajes como lo hice en esta aplicación de consola.

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.


Uso esta biblioteca para IPc (usa memoria compartida + mutex): http://17slon.com/gp/gp/gpsync.htm

Tiene TGpMessageQueueReader y TGpMessageQueueWriter. Use "Global /" delante del nombre, para que pueda usarlo para comunicarse entre un Servicio de Windows y un "Servicio GUI Helper" cuando un usuario inicia sesión. (El prefijo Global / es necesario para Vista debido a los anillos de seguridad de la sesión, pero también para Windows XP / 2003 entre sesiones de usuario).

Es muy rápido, multiproceso, etc. Utilizaría este en lugar de WM_COPYDATA (lento y muy elevado si lo usa mucho, pero para cosas pequeñas los mensajes pueden estar bien)


OmniThreadLibrary contiene cola de mensajes muy eficiente en la unidad OtlComm.pas .

La documentación no es muy buena en este momento ( comience aquí ) pero siempre puede usar el foro .