/// <summary> /// Creates the shared memory region and map a view to it. /// </summary> private void InitializeMemoryMapping(string memoryMapName, bool allowExistingMapping) { // Null means use the default security permissions IntPtr pointerToSecurityAttributes = NativeMethods.NullPtr; IntPtr pSDNative = IntPtr.Zero; try { // Check to see if the user is an administrator, this is done to prevent non // administrator processes from accessing the shared memory. On a vista machine // the check does not differentiate beween the application being elevated to have // administrator rights or the application being started with administrator rights. // If the user is an administator create a new set of securityAttributes which make // the shared memory only accessable to administrators. if (NativeMethods.IsUserAdministrator()) { NativeMethods.SECURITY_ATTRIBUTES saAttr = new NativeMethods.SECURITY_ATTRIBUTES(); uint pSDLength = 0; if (!NativeMethods.ConvertStringSecurityDescriptorToSecurityDescriptor(NativeMethods.ADMINONLYSDDL, NativeMethods.SECURITY_DESCRIPTOR_REVISION, ref pSDNative, ref pSDLength)) { throw new System.ComponentModel.Win32Exception(); } saAttr.bInheritHandle = 0; saAttr.nLength = Marshal.SizeOf(typeof(NativeMethods.SECURITY_ATTRIBUTES)); saAttr.lpSecurityDescriptor = pSDNative; pointerToSecurityAttributes = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(NativeMethods.SECURITY_ATTRIBUTES))); Marshal.StructureToPtr(saAttr, pointerToSecurityAttributes, true); } // The file mapping has either the default (current user) security permissions or // permissions restricted to only administrator users depending on the check above. // If pointerToSecurityAttributes is null the default permissions are used. this.pageFileMapping = NativeMethods.CreateFileMapping ( NativeMethods.InvalidHandle, pointerToSecurityAttributes, NativeMethods.PAGE_READWRITE, 0, size + 4, memoryMapName ); // If only new mappings are allowed and the current one has been created by somebody else // delete the mapping. Note that we would like to compare the GetLastError value against // ERROR_ALREADY_EXISTS but CLR sometimes overwrites the last error so to be safe we'll // not reuse the node for any unsuccessful value. if (!allowExistingMapping && Marshal.GetLastWin32Error() != NativeMethods.ERROR_SUCCESS) { if (!pageFileMapping.IsInvalid && !pageFileMapping.IsClosed) { NativeMethods.UnmapViewOfFile(pageFileView); pageFileMapping.Close(); } } } finally { NativeMethods.LocalFree(pointerToSecurityAttributes); NativeMethods.LocalFree(pSDNative); } if (!this.pageFileMapping.IsInvalid && !pageFileMapping.IsClosed) { // Maps a view of a file mapping into the address space of the calling process so that we can use the // view to read and write to the shared memory region. this.pageFileView = NativeMethods.MapViewOfFile ( this.pageFileMapping, NativeMethods.FILE_MAP_ALL_ACCESS, // Give the map read, write, and copy access 0, // Start mapped view at high order offset 0 0, // Start mapped view at low order offset 0 // The size of the shared memory plus some extra space for an int // to write the number of bytes written (IntPtr)(size + 4) ); // Check to see if the file view has been created on the fileMapping. if (this.pageFileView == NativeMethods.NullPtr) { // Make the shared memory not usable. this.pageFileMapping.Close(); } else { this.name = memoryMapName; } } }
/// <summary> /// This function launches a new node given a node index /// </summary> private void LaunchNode(int nodeIndex) { EventWaitHandle nodeReadyEvent = null; string msbuildLocation = Path.Combine(locationOfMSBuildExe, "MSBuild.exe"); ErrorUtilities.VerifyThrow(File.Exists(msbuildLocation),"Msbuild.exe cannot be found at: "+msbuildLocation); bool exitedDueToError = true; try { NativeMethods.STARTUPINFO startInfo = new NativeMethods.STARTUPINFO(); startInfo.cb = Marshal.SizeOf(startInfo); uint dwCreationFlags = NativeMethods.NORMAL_PRIORITY_CLASS; if (!Engine.debugMode) { startInfo.hStdError = NativeMethods.InvalidHandle; startInfo.hStdInput = NativeMethods.InvalidHandle; startInfo.hStdOutput = NativeMethods.InvalidHandle; startInfo.dwFlags = NativeMethods.STARTF_USESTDHANDLES; dwCreationFlags = dwCreationFlags | NativeMethods.CREATE_NO_WINDOW; } NativeMethods.SECURITY_ATTRIBUTES pSec = new NativeMethods.SECURITY_ATTRIBUTES(); NativeMethods.SECURITY_ATTRIBUTES tSec = new NativeMethods.SECURITY_ATTRIBUTES(); pSec.nLength = Marshal.SizeOf(pSec); tSec.nLength = Marshal.SizeOf(tSec); NativeMethods.PROCESS_INFORMATION pInfo = new NativeMethods.PROCESS_INFORMATION(); string appName = msbuildLocation; // Repeat the executable name as the first token of the command line because the command line // parser logic expects it and will otherwise skip the first argument string cmdLine = msbuildLocation + " /nologo /oldom /nodemode:" + nodeData[nodeIndex].NodeNumber; NativeMethods.CreateProcess(appName, cmdLine, ref pSec, ref tSec, false, dwCreationFlags, NativeMethods.NullPtr, null, ref startInfo, out pInfo); nodeReadyEvent = new EventWaitHandle(false, EventResetMode.ManualReset, LocalNodeProviderGlobalNames.NodeActiveEventName(nodeData[nodeIndex].NodeNumber)); // Wait until the node is ready to process the requests if (nodeReadyEvent.WaitOne(launchTimeout, false)) { exitedDueToError = false; } } finally { // Dispose before losing scope if (nodeReadyEvent != null) { nodeReadyEvent.Close(); } if (exitedDueToError) { nodeData[nodeIndex].CommunicationFailed = true; } } }