2009-10-05 58 views
4

我很感兴趣,这将是多么似是而非捕获的Win32调试跟踪全系统的DebugView的方式做。谢天谢地,我对内核消息不感兴趣,所以我不需要任何帮助。这需要使用C#,但如果有必要,我很满意非托管/不安全。在.NET中复制DebugView的功能 - 全局Win32调试挂钩?

是否有全局钩子,我可以得到还是我掀起下一个艰辛的道路?

我真的不知道在哪里的最好的地方是开始这一点。

回答

4

我终于到了那里。它采取了一些严重的google搜索,但我发现了一篇文章这有助于...

所有荣誉都归Chritian Birkl他相当出色的代码项目DbMon.NET - A simple .NET OutputDebugString capturer

的代码非常重要的,但在这里它是:

using System; 
using System.Threading; 
using System.Runtime.InteropServices; 

public delegate void OnOutputDebugStringHandler(int pid, string text); 


public sealed class DebugMonitor 
{ 

    private DebugMonitor() 
    { 
     ; 
    } 

    #region Win32 API Imports 

    [StructLayout(LayoutKind.Sequential)] 
    private struct SECURITY_DESCRIPTOR 
    { 
     public byte revision; 
     public byte size; 
     public short control; 
     public IntPtr owner; 
     public IntPtr group; 
     public IntPtr sacl; 
     public IntPtr dacl; 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    private struct SECURITY_ATTRIBUTES 
    { 
     public int nLength; 
     public IntPtr lpSecurityDescriptor; 
     public int bInheritHandle; 
    } 

    [Flags] 
    private enum PageProtection : uint 
    { 
     NoAccess = 0x01, 
     Readonly = 0x02, 
     ReadWrite = 0x04, 
     WriteCopy = 0x08, 
     Execute = 0x10, 
     ExecuteRead = 0x20, 
     ExecuteReadWrite = 0x40, 
     ExecuteWriteCopy = 0x80, 
     Guard = 0x100, 
     NoCache = 0x200, 
     WriteCombine = 0x400, 
    } 


    private const int WAIT_OBJECT_0 = 0; 
    private const uint INFINITE = 0xFFFFFFFF; 
    private const int ERROR_ALREADY_EXISTS = 183; 

    private const uint SECURITY_DESCRIPTOR_REVISION = 1; 

    private const uint SECTION_MAP_READ = 0x0004; 

    [DllImport("kernel32.dll", SetLastError = true)] 
    private static extern IntPtr MapViewOfFile(IntPtr hFileMappingObject, uint 
     dwDesiredAccess, uint dwFileOffsetHigh, uint dwFileOffsetLow, 
     uint dwNumberOfBytesToMap); 

    [DllImport("kernel32.dll", SetLastError = true)] 
    private static extern bool UnmapViewOfFile(IntPtr lpBaseAddress); 

    [DllImport("advapi32.dll", SetLastError = true)] 
    private static extern bool InitializeSecurityDescriptor(ref SECURITY_DESCRIPTOR sd, uint dwRevision); 

    [DllImport("advapi32.dll", SetLastError = true)] 
    private static extern bool SetSecurityDescriptorDacl(ref SECURITY_DESCRIPTOR sd, bool daclPresent, IntPtr dacl, bool daclDefaulted); 

    [DllImport("kernel32.dll")] 
    private static extern IntPtr CreateEvent(ref SECURITY_ATTRIBUTES sa, bool bManualReset, bool bInitialState, string lpName); 

    [DllImport("kernel32.dll")] 
    private static extern bool PulseEvent(IntPtr hEvent); 

    [DllImport("kernel32.dll")] 
    private static extern bool SetEvent(IntPtr hEvent); 

    [DllImport("kernel32.dll", SetLastError = true)] 
    private static extern IntPtr CreateFileMapping(IntPtr hFile, 
     ref SECURITY_ATTRIBUTES lpFileMappingAttributes, PageProtection flProtect, uint dwMaximumSizeHigh, 
     uint dwMaximumSizeLow, string lpName); 

    [DllImport("kernel32.dll", SetLastError = true)] 
    private static extern bool CloseHandle(IntPtr hHandle); 

    [DllImport("kernel32", SetLastError = true, ExactSpelling = true)] 
    private static extern Int32 WaitForSingleObject(IntPtr handle, uint milliseconds); 
    #endregion 


    public static event OnOutputDebugStringHandler OnOutputDebugString; 

    private static IntPtr m_AckEvent = IntPtr.Zero; 

    private static IntPtr m_ReadyEvent = IntPtr.Zero; 

    private static IntPtr m_SharedFile = IntPtr.Zero; 

    private static IntPtr m_SharedMem = IntPtr.Zero; 

    private static Thread m_Capturer = null; 

    private static object m_SyncRoot = new object(); 

    private static Mutex m_Mutex = null; 


    public static void Start() 
    { 
     lock (m_SyncRoot) 
     { 
      if (m_Capturer != null) 
       throw new ApplicationException("This DebugMonitor is already started."); 

      if (Environment.OSVersion.ToString().IndexOf("Microsoft") == -1) 
       throw new NotSupportedException("This DebugMonitor is only supported on Microsoft operating systems."); 

      bool createdNew = false; 
      m_Mutex = new Mutex(false, typeof(DebugMonitor).Namespace, out createdNew); 
      if (!createdNew) 
       throw new ApplicationException("There is already an instance of 'DbMon.NET' running."); 

      SECURITY_DESCRIPTOR sd = new SECURITY_DESCRIPTOR(); 

      if (!InitializeSecurityDescriptor(ref sd, SECURITY_DESCRIPTOR_REVISION)) 
      { 
       throw CreateApplicationException("Failed to initializes the security descriptor."); 
      } 

      if (!SetSecurityDescriptorDacl(ref sd, true, IntPtr.Zero, false)) 
      { 
       throw CreateApplicationException("Failed to initializes the security descriptor"); 
      } 

      SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES(); 

      m_AckEvent = CreateEvent(ref sa, false, false, "DBWIN_BUFFER_READY"); 
      if (m_AckEvent == IntPtr.Zero) 
      { 
       throw CreateApplicationException("Failed to create event 'DBWIN_BUFFER_READY'"); 
      } 

      m_ReadyEvent = CreateEvent(ref sa, false, false, "DBWIN_DATA_READY"); 
      if (m_ReadyEvent == IntPtr.Zero) 
      { 
       throw CreateApplicationException("Failed to create event 'DBWIN_DATA_READY'"); 
      } 

      m_SharedFile = CreateFileMapping(new IntPtr(-1), ref sa, PageProtection.ReadWrite, 0, 4096, "DBWIN_BUFFER"); 
      if (m_SharedFile == IntPtr.Zero) 
      { 
       throw CreateApplicationException("Failed to create a file mapping to slot 'DBWIN_BUFFER'"); 
      } 

      m_SharedMem = MapViewOfFile(m_SharedFile, SECTION_MAP_READ, 0, 0, 512); 
      if (m_SharedMem == IntPtr.Zero) 
      { 
       throw CreateApplicationException("Failed to create a mapping view for slot 'DBWIN_BUFFER'"); 
      } 

      m_Capturer = new Thread(new ThreadStart(Capture)); 
      m_Capturer.Start(); 
     } 
    } 

    private static void Capture() 
    { 
     try 
     { 
      IntPtr pString = new IntPtr(
       m_SharedMem.ToInt32() + Marshal.SizeOf(typeof(int)) 
      ); 

      while (true) 
      { 
       SetEvent(m_AckEvent); 

       int ret = WaitForSingleObject(m_ReadyEvent, INFINITE); 

       if (m_Capturer == null) 
        break; 

       if (ret == WAIT_OBJECT_0) 
       { 
        FireOnOutputDebugString(
         Marshal.ReadInt32(m_SharedMem), 
          Marshal.PtrToStringAnsi(pString)); 
       } 
      } 
     } 
     catch 
     { 
      throw; 

     } 
     finally 
     { 
      Dispose(); 
     } 
    } 

    private static void FireOnOutputDebugString(int pid, string text) 
    { 
     if (OnOutputDebugString == null) 
      return; 

     #if !DEBUG 
      try 
      { 
     #endif 

       OnOutputDebugString(pid, text); 

     #if !DEBUG 
      } 
      catch (Exception ex) 
      { 
       Console.WriteLine("An 'OnOutputDebugString' handler failed to execute: " + ex.ToString()); 
      } 
     #endif 
    } 


    private static void Dispose() 
    { 
     if (m_AckEvent != IntPtr.Zero) 
     { 
      if (!CloseHandle(m_AckEvent)) 
      { 
       throw CreateApplicationException("Failed to close handle for 'AckEvent'"); 
      } 
      m_AckEvent = IntPtr.Zero; 
     } 

     if (m_ReadyEvent != IntPtr.Zero) 
     { 
      if (!CloseHandle(m_ReadyEvent)) 
      { 
       throw CreateApplicationException("Failed to close handle for 'ReadyEvent'"); 
      } 
      m_ReadyEvent = IntPtr.Zero; 
     } 

     if (m_SharedFile != IntPtr.Zero) 
     { 
      if (!CloseHandle(m_SharedFile)) 
      { 
       throw CreateApplicationException("Failed to close handle for 'SharedFile'"); 
      } 
      m_SharedFile = IntPtr.Zero; 
     } 


     if (m_SharedMem != IntPtr.Zero) 
     { 
      if (!UnmapViewOfFile(m_SharedMem)) 
      { 
       throw CreateApplicationException("Failed to unmap view for slot 'DBWIN_BUFFER'"); 
      } 
      m_SharedMem = IntPtr.Zero; 
     } 

     if (m_Mutex != null) 
     { 
      m_Mutex.Close(); 
      m_Mutex = null; 
     } 
    } 

    public static void Stop() 
    { 
     lock (m_SyncRoot) 
     { 
      if (m_Capturer == null) 
       throw new ObjectDisposedException("DebugMonitor", "This DebugMonitor is not running."); 
      m_Capturer = null; 
      PulseEvent(m_ReadyEvent); 
      while (m_AckEvent != IntPtr.Zero) 
       ; 
     } 
    } 

    private static ApplicationException CreateApplicationException(string text) 
    { 
     if (text == null || text.Length < 1) 
      throw new ArgumentNullException("text", "'text' may not be empty or null."); 

     return new ApplicationException(string.Format("{0}. Last Win32 Error was {1}", 
      text, Marshal.GetLastWin32Error())); 
    } 
} 
+1

+1您抽空分享您的解决方案的麻烦。 – RichieHindle 2009-10-10 22:17:43

+0

你为什么打算创建一个SECURITY_DESCRIPTOR?您不要在任何地方将其设置在SECURITY_ATTRIBUTES中。 Attributes结构中的NULL授予与调用进程关联的默认访问权限。默认情况下,进程的访问令牌中的默认DACL只允许访问访问令牌所代表的用户。 http://msdn.microsoft.com/en-us/library/windows/desktop/aa379560(v=vs.85).aspx – Dan 2013-03-31 04:40:57

+0

使用“IntPtr.ToInt64”而不是“IntPtr.ToInt32”会更好吗用于将4个字节添加到消息字符串中?在64位系统上,32位转换可能导致溢出。虽然它现在在我的系统上正常工作(使用16 GB中几乎5个)。 – ygoe 2013-09-03 21:46:40

1

我会与TraceListener类开始,虽然我不知道这是否可以被用来捕获Win32的调试跟踪。

2

我写了一个工具,它做的。它不是100%等同于DebugView,但它还有其他一些很好的功能(比如能够对轨迹着色):-)。

这是可以在这里找到:TraceSpy

因为它是100%开源的,它包含了演示如何做到这一点的C#代码。