12

Estoy tratando de atrapar todos los mensajes OutputDebugString (incluidos los de los servicios) utilizando el siguiente código. Funcionó bien hasta que migré a Windows 7.¿Cómo puedo recibir OutputDebugString desde un servicio?

El problema es que debido a que los servicios de Windows Vista se ejecutan en el bajo nivel Session # 0, algunas personas dicen que it's impossible para atraparlos y algunos que sí lo están. ¿Qué piensas?

¿Es posible modificar el siguiente código aumentando algunos derechos para poder recibir mensajes OutputDebugString de la sesión # 0? En otras palabras; ¿es posible compartir DBWIN_BUFFER en la sesión # 0 con Session # 1?

Yo diría que debería ser posible porque, p. DebugView puede hacer eso, y no puedo ver ningún ayudante de servicio que envíe esos mensajes (por ejemplo, a través de las canalizaciones con nombre) de la sesión # 0 a la sesión # 1, donde se ejecuta la GUI.

El problema será IMO en la configuración de seguridad. ¿Alguien puede sugerirme cómo modificarlos?

type 
    TODSThread = class(TThread) 
    protected 
    procedure Execute; override; 
    end; 

... 

procedure TODSThread.Execute; 
var SharedMem: Pointer; 
    SharedFile: THandle; 
    WaitingResult: DWORD; 
    SharedMessage: string; 
    DataReadyEvent: THandle; 
    BufferReadyEvent: THandle; 
    SecurityAttributes: SECURITY_ATTRIBUTES; 
    SecurityDescriptor: SECURITY_DESCRIPTOR; 

begin 
    SecurityAttributes.nLength := SizeOf(SECURITY_ATTRIBUTES); 
    SecurityAttributes.bInheritHandle := True; 
    SecurityAttributes.lpSecurityDescriptor := @SecurityDescriptor; 

    if not InitializeSecurityDescriptor(@SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION) then 
    Exit; 

    if not SetSecurityDescriptorDacl(@SecurityDescriptor, True, nil, False) then 
    Exit; 

    BufferReadyEvent := CreateEvent(@SecurityAttributes, False, True, 'DBWIN_BUFFER_READY'); 

    if BufferReadyEvent = 0 then 
    Exit; 

    DataReadyEvent := CreateEvent(@SecurityAttributes, False, False, 'DBWIN_DATA_READY'); 

    if DataReadyEvent = 0 then 
    Exit; 

    SharedFile := CreateFileMapping(THandle(-1), @SecurityAttributes, PAGE_READWRITE, 0, 4096, 'DBWIN_BUFFER'); 

    if SharedFile = 0 then 
    Exit; 

    SharedMem := MapViewOfFile(SharedFile, FILE_MAP_READ, 0, 0, 512); 

    if not Assigned(SharedMem) then 
    Exit; 

    while (not Terminated) and (not Application.Terminated) do 
    begin 
     SetEvent(BufferReadyEvent); 
     WaitingResult := WaitForSingleObject(DataReadyEvent, INFINITE); 

     case WaitingResult of 
     WAIT_TIMEOUT: Continue; 
     WAIT_OBJECT_0: 
      begin 
      SharedMessage := String(PAnsiChar(SharedMem) + SizeOf(DWORD)); 
      // here I have what I need and process it in the main thread 
      end; 

     WAIT_FAILED: Continue; 
    end; 
    end; 

    UnmapViewOfFile(SharedMem); 
    CloseHandle(SharedFile); 
end; 

He añadido la etiqueta C#, incluso si el código está en Delphi porque los atributos de seguridad son comunes para toda la API de Windows y C# tiene muchos seguidores :)

Respuesta

11

Alguien habló de la misma problema en el SysInternals forums. Su solución fue add "Global\" to the named objects.

a fin de utilizar el siguiente

CreateEvent(@SecurityAttributes, False, True, 'Global\DBWIN_BUFFER_READY'); 
CreateEvent(@SecurityAttributes, False, False, 'Global\DBWIN_DATA_READY'); 
CreateFileMapping(THandle(-1), @SecurityAttributes, PAGE_READWRITE, 0, 4096, 'Global\DBWIN_BUFFER'); 
+1

+1 y aceptar. Gracias; funciona perfectamente. Añadiré la solución específica a tu respuesta con excusa. –

Cuestiones relacionadas