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.
@@ -44,30 +95,20 @@ internal static class NativeMethods
4495 /// </returns>
4596 public static bool ProcMonDebugOutput ( string message , params object [ ] args )
4697 {
47- if ( false == lookedUpProcessType )
48- {
49- lookedUpProcessType = true ;
50-
51- Assembly mscorlibAssem = Assembly . GetAssembly ( typeof ( object ) ) ;
52- Module [ ] mods = mscorlibAssem . GetModules ( ) ;
53- PortableExecutableKinds peK ;
54- ImageFileMachine ifn ;
55- mods [ 0 ] . GetPEKind ( out peK , out ifn ) ;
56- is64BitProcess = ImageFileMachine . I386 != ifn ;
57- }
58-
5998 bool returnValue = false ;
6099 try
61100 {
62- string renderedMessage = string . Format ( message , args ) ;
63- if ( true == is64BitProcess )
64- {
65- returnValue = ProcMonDebugOutputx64 ( renderedMessage ) ;
66- }
67- else
101+ StringBuilder renderedMessage = new StringBuilder ( ) ;
102+ renderedMessage . AppendFormat ( message , args ) ;
103+ uint outLen ;
104+ if ( hProcMon == null || hProcMon . IsInvalid )
68105 {
69- returnValue = ProcMonDebugOutputWin32 ( renderedMessage ) ;
106+ hProcMon = CreateFile ( ) ;
70107 }
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 ) ;
71112 }
72113 catch ( EntryPointNotFoundException notFoundException )
73114 {
@@ -79,21 +120,5 @@ public static bool ProcMonDebugOutput(string message, params object[] args)
79120
80121 return returnValue ;
81122 }
82-
83- [ DllImport ( "ProcMonDebugOutputx64.dll" ,
84- CharSet = CharSet . Unicode ,
85- EntryPoint = "ProcMonDebugOutput" ,
86- SetLastError = true ,
87- CallingConvention = CallingConvention . StdCall ) ]
88- [ return : MarshalAs ( UnmanagedType . Bool ) ]
89- private static extern bool ProcMonDebugOutputx64 ( string lpOutput ) ;
90-
91- [ DllImport ( "ProcMonDebugOutputWin32.dll" ,
92- CharSet = CharSet . Unicode ,
93- EntryPoint = "ProcMonDebugOutput" ,
94- SetLastError = true ,
95- CallingConvention = CallingConvention . StdCall ) ]
96- [ return : MarshalAs ( UnmanagedType . Bool ) ]
97- private static extern bool ProcMonDebugOutputWin32 ( string lpOutput ) ;
98123 }
99124}
0 commit comments