如何从服务接收 OutputDebugString?

Posted

技术标签:

【中文标题】如何从服务接收 OutputDebugString?【英文标题】:How can I receive OutputDebugString from a service? 【发布时间】:2011-09-17 02:33:31 【问题描述】:

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

问题在于,由于 Windows Vista 服务在低级别会话 #0 中运行,因此有人说 it's impossible 来捕获它们,而有些人说它是。你怎么看?

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

我会说这应该是可能的,因为例如DebugView 可以做到这一点,而且我看不到任何服务助手可以将这些消息(例如通过命名管道)从会话 #0 发送到运行 GUI 的会话 #1。

问题将是安全设置中的 IMO。谁能建议我如何修改它们?

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;

即使代码在 Delphi 中,我也添加了 C# 标签,因为安全属性对于整个 Windows API 是通用的,并且 C# 有很多追随者 :)

【问题讨论】:

【参考方案1】:

有人在SysInternals forums 中谈到了同样的问题。他们的解决方案是add "Global\" to the named objects。

所以使用下面的

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 并接受。谢谢;完美运行。我会在你的答案中添加具体的解决方案。

以上是关于如何从服务接收 OutputDebugString?的主要内容,如果未能解决你的问题,请参考以下文章

将 OutputDebugString 记录到文件中(没有 DebugView)

控制台中的 OutputDebugString()

Delphi和OutputDebugString

OutputDebugString 函数不在我的控制台应用程序中发送消息

如何从流服务器接收消息?

log4cxx OutputDebugString DebugView dbgview