Как я могу получить OutputDebugString из службы?

Я пытаюсь перехватить все OutputDebugString сообщения (в том числе от сервисов) с использованием следующего кода. Все работало нормально, пока я не перешел на Windows 7.

Проблема в том, что, поскольку службы Windows Vista работают в низкоуровневом сеансе #0, некоторые говорят, что невозможно поймать их и некоторые из них. Что вы думаете?

Можно ли изменить следующий код, увеличив некоторые права, чтобы иметь возможность получать OutputDebugString из сеанса №0? Другими словами; возможно ли совместно использовать DBWIN_BUFFER в сеансе № 0 с сеансом № 1?

Я бы сказал, что это должно быть возможно, потому что, например. DebugView может это сделать, и я не вижу помощника службы, который бы отправлял эти сообщения (например, через именованные каналы) из сеанса № 0 в сеанс № 1, где работает графический интерфейс.

Проблема будет ИМО в настройках безопасности. Может ли кто-нибудь предложить мне, как изменить их?

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;

Я добавил тег C#, даже если код написан на Delphi, поскольку атрибуты безопасности являются общими для всего Windows API, а у C# много последователей :)


person Community    schedule 17.06.2011    source источник


Ответы (1)


Кто-то обсуждал ту же проблему на форумах SysInternals. Их решение состояло в том, чтобы добавить "Global\" к именованным объектам .

Поэтому используйте следующее

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');
person Bruce McGee    schedule 17.06.2011
comment
+1 и принять. Спасибо; работает отлично. Я добавлю конкретное решение к вашему ответу с извинением. - person ; 17.06.2011