1 // Copyright (c) Microsoft. All rights reserved.
2 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 
4 using System;
5 using System.IO;
6 using System.Text;
7 using System.Runtime.InteropServices;
8 
9 namespace Microsoft.Build.BuildEngine.Shared
10 {
11     /// <summary>
12     /// Interop methods.
13     /// </summary>
14     /// <owner>LukaszG</owner>
15     internal static class NativeMethods
16     {
17         #region Constants
18 
19         internal const uint ERROR_INSUFFICIENT_BUFFER = 0x8007007A;
20         internal const uint STARTUP_LOADER_SAFEMODE = 0x10;
21         internal const uint S_OK = 0x0;
22         internal const uint RUNTIME_INFO_DONT_SHOW_ERROR_DIALOG = 0x40;
23         internal const uint FILE_TYPE_CHAR = 0x0002;
24         internal const Int32 STD_OUTPUT_HANDLE = -11;
25 
26         private const string kernel32Dll = "kernel32.dll";
27         private const string mscoreeDLL = "mscoree.dll";
28 
29         internal static HandleRef NullHandleRef = new HandleRef(null, IntPtr.Zero);
30 
31         internal static IntPtr NullIntPtr = new IntPtr(0);
32         #endregion
33 
34         #region Member data
35 
36         /// <summary>
37         /// Default buffer size to use when dealing with the Windows API.
38         /// </summary>
39         /// <remarks>
40         /// This member is intentionally not a constant because we want to allow
41         /// unit tests to change it.
42         /// </remarks>
43         internal static int MAX_PATH = 260;
44 
45         #endregion
46 
47         #region Wrapper methods
48 
49         /// <summary>
50         /// Looks for the given file in the system path i.e. all locations in
51         /// the %PATH% environment variable.
52         /// </summary>
53         /// <param name="filename"></param>
54         /// <returns>The location of the file, or null if file not found.</returns>
FindOnPath(string filename)55         internal static string FindOnPath(string filename)
56         {
57             StringBuilder pathBuilder = new StringBuilder(MAX_PATH + 1);
58             string pathToFile = null;
59 
60             // we may need to make two attempts because there's a small chance
61             // the buffer may not be sized correctly the first time
62             for (int i = 0; i < 2; i++)
63             {
64                 uint result = SearchPath
65                                 (
66                                     null /* search the system path */,
67                                     filename /* look for this file */,
68                                     null /* don't add an extra extension to the filename when searching */,
69                                     pathBuilder.Capacity /* size of buffer */,
70                                     pathBuilder /* buffer to write path into */,
71                                     null /* don't want pointer to filename in the return path */
72                                 );
73 
74                 // if the buffer is not big enough
75                 if (result > pathBuilder.Capacity)
76                 {
77                     ErrorUtilities.VerifyThrow(i == 0, "We should not have to resize the buffer twice.");
78 
79                     // resize the buffer and try again
80                     pathBuilder.Capacity = (int)result;
81                 }
82                 else if (result > 0)
83                 {
84                     // file was found, so don't make another attempt
85                     pathToFile = pathBuilder.ToString();
86                     break;
87                 }
88                 else
89                 {
90                     // file was not found, so quit
91                     break;
92                 }
93             }
94 
95             return pathToFile;
96         }
97 
98         #endregion
99 
100         #region PInvoke
101 
102         /// <summary>
103         /// Gets the current OEM code page which is used by console apps
104         /// (as opposed to the Windows/ANSI code page used by the normal people)
105         /// Basically for each ANSI code page (set in Regional settings) there's a corresponding OEM code page
106         /// that needs to be used for instance when writing to batch files
107         /// </summary>
108         /// <owner>LukaszG</owner>
109         [DllImport(kernel32Dll)]
GetOEMCP()110         internal static extern int GetOEMCP();
111 
112 
113         [DllImport(kernel32Dll, SetLastError = true, CharSet = CharSet.Unicode)]
SearchPath( string path, string fileName, string extension, int numBufferChars, StringBuilder buffer, int[] filePart )114         private static extern uint SearchPath
115         (
116             string path,
117             string fileName,
118             string extension,
119             int numBufferChars,
120             StringBuilder buffer,
121             int[] filePart
122         );
123 
124 
125         [DllImport("kernel32.dll", PreserveSig = true, SetLastError = true)]
126         [return: MarshalAs(UnmanagedType.Bool)]
FreeLibrary([In] IntPtr module)127         internal static extern bool FreeLibrary([In] IntPtr module);
128 
129         [DllImport("kernel32.dll", PreserveSig = true, BestFitMapping = false, ThrowOnUnmappableChar = true, CharSet = CharSet.Ansi, SetLastError = true)]
GetProcAddress(IntPtr module, string procName)130         internal static extern IntPtr GetProcAddress(IntPtr module, string procName);
131 
132         [DllImport("kernel32.dll", CharSet = CharSet.Unicode, PreserveSig = true, SetLastError = true)]
LoadLibrary(string fileName)133         internal static extern IntPtr LoadLibrary(string fileName);
134 
135         [DllImport(mscoreeDLL, SetLastError = true, CharSet = CharSet.Unicode)]
GetRequestedRuntimeInfo(String pExe, String pwszVersion, String pConfigurationFile, uint startupFlags, uint runtimeInfoFlags, StringBuilder pDirectory, int dwDirectory, out uint dwDirectoryLength, StringBuilder pVersion, int cchBuffer, out uint dwlength)136         internal static extern uint GetRequestedRuntimeInfo(String pExe,
137                                                 String pwszVersion,
138                                                 String pConfigurationFile,
139                                                 uint startupFlags,
140                                                 uint runtimeInfoFlags,
141                                                 StringBuilder pDirectory,
142                                                 int dwDirectory,
143                                                 out uint dwDirectoryLength,
144                                                 StringBuilder pVersion,
145                                                 int cchBuffer,
146                                                 out uint dwlength);
147 
148         /// <summary>
149         /// Gets the fully qualified filename of the currently executing .exe
150         /// </summary>
151         [DllImport(kernel32Dll, SetLastError=true, CharSet = CharSet.Unicode)]
GetModuleFileName(HandleRef hModule, StringBuilder buffer, int length)152         internal static extern int GetModuleFileName(HandleRef hModule, StringBuilder buffer, int length);
153 
154         [DllImport("kernel32.dll")]
GetStdHandle(int nStdHandle)155         internal static extern IntPtr GetStdHandle(int nStdHandle);
156 
157         [DllImport("kernel32.dll")]
GetFileType(IntPtr hFile)158         internal static extern uint GetFileType(IntPtr hFile);
159 
160         [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
GetCurrentDirectory(int nBufferLength, StringBuilder lpBuffer)161         internal static extern int GetCurrentDirectory(int nBufferLength, StringBuilder lpBuffer);
162 
163         #endregion
164     }
165 }
166