88// - Moved to VS 2013 and .NET 4.5.1
99//////////////////////////////////////////////////////////////////////////////*/
1010
11+ using System . Text ;
12+ using Microsoft . Win32 . SafeHandles ;
13+
1114namespace Sysinternals . Debug
1215{
1316 using System ;
1417 using System . Diagnostics ;
15- using System . Reflection ;
1618 using System . Runtime . InteropServices ;
1719
1820 /// <summary>
1921 /// A class to wrap all the native code needed by this assembly.
2022 /// </summary>
2123 internal static class NativeMethods
2224 {
25+ // Constants to represent C preprocessor macros for PInvokes
26+ const uint GENERIC_WRITE = 0x40000000 ;
27+ const uint OPEN_EXISTING = 3 ;
28+ const uint FILE_WRITE_ACCESS = 0x0002 ;
29+ const uint FILE_SHARE_WRITE = 0x00000002 ;
30+ const uint FILE_ATTRIBUTE_NORMAL = 0x00000080 ;
31+ const uint METHOD_BUFFERED = 0 ;
32+
33+ // Procmon Constants
34+ const uint FILE_DEVICE_PROCMON_LOG = 0x00009535 ;
35+ const string PROCMON_DEBUGGER_HANDLER = "\\ \\ .\\ Global\\ ProcmonDebugLogger" ;
36+
2337 /// <summary>
24- /// Flag to check if we've already done the process lookup .
38+ /// The handle to the procmon log device .
2539 /// </summary>
26- private static bool lookedUpProcessType ;
40+ private static SafeFileHandle hProcMon ;
2741
2842 /// <summary>
29- /// True if the process is 64-bit .
43+ /// Get the IO Control code for the ProcMon log .
3044 /// </summary>
31- private static bool is64BitProcess ;
45+ private static uint IOCTL_EXTERNAL_LOG_DEBUGOUT { get { return CTL_CODE ( ) ; } }
46+
47+ /// <seealso href="http://msdn.microsoft.com/en-us/library/windows/hardware/ff543023(v=vs.85).aspx"/>
48+ private static uint CTL_CODE (
49+ uint DeviceType = FILE_DEVICE_PROCMON_LOG ,
50+ uint Function = 0x81 ,
51+ uint Method = METHOD_BUFFERED ,
52+ uint Access = FILE_WRITE_ACCESS )
53+ {
54+ return ( ( DeviceType << 16 ) | ( Access << 14 ) | ( Function << 2 ) | Method ) ;
55+ }
56+
57+ /// <remarks>This is only used for opening the procmon log handle, hence the default parameters.</remarks>
58+ /// <seealso href="http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx"/>
59+ [ DllImport ( "kernel32.dll" , SetLastError = true , CharSet = CharSet . Auto ) ]
60+ private static extern SafeFileHandle CreateFile (
61+ string lpFileName = PROCMON_DEBUGGER_HANDLER ,
62+ uint dwDesiredAccess = GENERIC_WRITE ,
63+ uint dwShareMode = FILE_SHARE_WRITE ,
64+ IntPtr lpSecurityAttributes = default ( IntPtr ) ,
65+ uint dwCreationDisposition = OPEN_EXISTING ,
66+ uint dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL ,
67+ IntPtr hTemplateFile = default ( IntPtr ) ) ;
68+
69+ [ DllImport ( "kernel32.dll" , ExactSpelling = true , SetLastError = true , CharSet = CharSet . Auto ) ]
70+ private static extern bool DeviceIoControl (
71+ SafeFileHandle hDevice , uint dwIoControlCode ,
72+ StringBuilder lpInBuffer , uint nInBufferSize ,
73+ IntPtr lpOutBuffer , uint nOutBufferSize ,
74+ out uint lpBytesReturned , IntPtr lpOverlapped ) ;
75+
76+ static NativeMethods ( )
77+ {
78+ AppDomain . CurrentDomain . ProcessExit += ( sender , args ) =>
79+ {
80+ if ( ! hProcMon . IsInvalid ) hProcMon . Close ( ) ;
81+ } ;
82+ }
3283
3384 /// <summary>
3485 /// Does the actual tracing to Process Monitor.
3586 /// </summary>
3687 /// <param name="message">
3788 /// The message to display.
3889 /// </param>
90+ /// <param name="args">
91+ /// The formatting arguments for the message
92+ /// </param>
3993 /// <returns>
4094 /// True if the trace succeeded, false otherwise.
4195 /// </returns>
42- public static bool ProcMonDebugOutput ( string message )
96+ public static bool ProcMonDebugOutput ( string message , params object [ ] args )
4397 {
44- if ( false == lookedUpProcessType )
45- {
46- lookedUpProcessType = true ;
47-
48- Assembly mscorlibAssem = Assembly . GetAssembly ( typeof ( object ) ) ;
49- Module [ ] mods = mscorlibAssem . GetModules ( ) ;
50- PortableExecutableKinds peK ;
51- ImageFileMachine ifn ;
52- mods [ 0 ] . GetPEKind ( out peK , out ifn ) ;
53- is64BitProcess = ImageFileMachine . I386 != ifn ;
54- }
55-
5698 bool returnValue = false ;
5799 try
58100 {
59- if ( true == is64BitProcess )
60- {
61- returnValue = ProcMonDebugOutputx64 ( message ) ;
62- }
63- else
101+ StringBuilder renderedMessage = new StringBuilder ( ) ;
102+ renderedMessage . AppendFormat ( message , args ) ;
103+ uint outLen ;
104+ if ( hProcMon == null || hProcMon . IsInvalid )
64105 {
65- returnValue = ProcMonDebugOutputWin32 ( message ) ;
106+ hProcMon = CreateFile ( ) ;
66107 }
108+ DeviceIoControl (
109+ hProcMon , IOCTL_EXTERNAL_LOG_DEBUGOUT ,
110+ renderedMessage , ( uint ) ( message . Length * Marshal . SizeOf ( typeof ( char ) ) ) ,
111+ IntPtr . Zero , 0 , out outLen , IntPtr . Zero ) ;
67112 }
68113 catch ( EntryPointNotFoundException notFoundException )
69114 {
@@ -75,21 +120,5 @@ public static bool ProcMonDebugOutput(string message)
75120
76121 return returnValue ;
77122 }
78-
79- [ DllImport ( "ProcMonDebugOutputx64.dll" ,
80- CharSet = CharSet . Unicode ,
81- EntryPoint = "ProcMonDebugOutput" ,
82- SetLastError = true ,
83- CallingConvention = CallingConvention . StdCall ) ]
84- [ return : MarshalAs ( UnmanagedType . Bool ) ]
85- private static extern bool ProcMonDebugOutputx64 ( string lpOutput ) ;
86-
87- [ DllImport ( "ProcMonDebugOutputWin32.dll" ,
88- CharSet = CharSet . Unicode ,
89- EntryPoint = "ProcMonDebugOutput" ,
90- SetLastError = true ,
91- CallingConvention = CallingConvention . StdCall ) ]
92- [ return : MarshalAs ( UnmanagedType . Bool ) ]
93- private static extern bool ProcMonDebugOutputWin32 ( string lpOutput ) ;
94123 }
95124}
0 commit comments