2009-10-05 60 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#代碼。