如何从服务中接收OutputDebugString?

12

我正在尝试使用以下代码捕获所有OutputDebugString消息(包括来自服务的消息)。在迁移到Windows 7之前,它工作得很好。

问题在于自从Windows Vista以来,服务运行在低级Session#0中,有些人说不可能捕获它们,有些则说可以。你怎么看?

是否可以通过增加某些权限来修改以下代码,以便能够接收来自Session#0的OutputDebugString消息?换句话说,在会话#0中与会话#1共享DBWIN_BUFFER是否可能?

我认为应该是可能的,因为例如DebugView可以做到这一点,而我看不到任何服务助手会将那些消息(例如通过命名管道)从Session#0发送到GUI所在的Session#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# 有很多追随者 :)

1个回答

12

有人在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');

1
+1并接受。谢谢,运行得非常完美。我会将具体解决方案添加到您的答案中并表示歉意。 - user532231

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接