title: How can I receive OutputDebugString from a service?
body: <p>I'm trying to catch all <a href="http://msdn.microsoft.com/en-us/library/aa363362%28v=vs.85%29.aspx" rel="nofollow noreferrer">OutputDebugString</a> messages (including those from services) using the following code. It worked fine until I migrated to Windows 7.</p>
  
  <p>The problem is that since Windows Vista services are running in the low level Session #0, some people say that <a href="http://borland.newsgroups.archived.at/public.delphi.nativeapi.win32/200711/0711019285.html" rel="nofollow noreferrer">it's impossible</a> to catch them and some that it is. What do you think?</p>
  
  <p>Is it possible to modify the following code by increasing some rights to be able to receive <a href="http://msdn.microsoft.com/en-us/library/aa363362%28v=vs.85%29.aspx" rel="nofollow noreferrer">OutputDebugString</a> messages from the Session #0? In other words; is it possible to share DBWIN_BUFFER in the session #0 with Session #1?</p>
  
  <p>I would say it should be possible because e.g. DebugView can do that, and I can't see any service helper which would send those messages (e.g. through the named pipes) from the Session #0 to Session #1, where the GUI's running.</p>
  
  <p>The problem will be IMO in the security settings. Can anyone suggest me how to modify them?</p>
  
  <pre><code>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;
  </code></pre>
  
  <p><sub>I've added the C# tag even if the code is in Delphi because the security attributes are common for the whole Windows API and C# has many followers :)</sub></p>