internal void AddMessage(BuildMessage message) { _messages.Add(message); }
public bool UpdateResources(string filename, BuildResults results) { bool returnValue = true; int beginUpdateRetries = 20; // Number of retries const int beginUpdateRetryInterval = 100; // In milliseconds bool endUpdate = false; // Only call EndUpdateResource() if this is true // Directory.GetCurrentDirectory() has previously been set to the project location string filePath = Path.Combine(Directory.GetCurrentDirectory(), filename); if (_stringResources.Count == 0 && _fileResources.Count == 0) { return(true); } IntPtr hUpdate = IntPtr.Zero; try { hUpdate = NativeMethods.BeginUpdateResourceW(filePath, false); while (IntPtr.Zero == hUpdate && Marshal.GetHRForLastWin32Error() == ERROR_SHARING_VIOLATION && beginUpdateRetries > 0) // If it equals 0x80070020 (ERROR_SHARING_VIOLATION), sleep & retry { // This warning can be useful for debugging, but shouldn't be displayed to an actual user // results.AddMessage(BuildMessage.CreateMessage(BuildMessageSeverity.Warning, "GenerateBootstrapper.General", String.Format("Unable to begin updating resource for {0} with error {1:X}, trying again after short sleep", filename, Marshal.GetHRForLastWin32Error()))); hUpdate = NativeMethods.BeginUpdateResourceW(filePath, false); beginUpdateRetries--; Thread.Sleep(beginUpdateRetryInterval); } // If after all that we still failed, throw a build error if (IntPtr.Zero == hUpdate) { results.AddMessage(BuildMessage.CreateMessage(BuildMessageSeverity.Error, "GenerateBootstrapper.General", $"Unable to begin updating resource for {filename} with error {Marshal.GetHRForLastWin32Error():X}")); return(false); } endUpdate = true; if (hUpdate != IntPtr.Zero) { foreach (StringResource resource in _stringResources) { byte[] data = StringToByteArray(resource.Data); if (!NativeMethods.UpdateResourceW(hUpdate, (IntPtr)resource.Type, resource.Name, 0, data, data.Length)) { results.AddMessage(BuildMessage.CreateMessage(BuildMessageSeverity.Error, "GenerateBootstrapper.General", $"Unable to update resource for {filename} with error {Marshal.GetHRForLastWin32Error():X}")); return(false); } } if (_fileResources.Count > 0) { int index = 0; byte[] countArray = StringToByteArray(_fileResources.Count.ToString("G", CultureInfo.InvariantCulture)); if (!NativeMethods.UpdateResourceW(hUpdate, (IntPtr)42, "COUNT", 0, countArray, countArray.Length)) { results.AddMessage(BuildMessage.CreateMessage(BuildMessageSeverity.Error, "GenerateBootstrapper.General", $"Unable to update count resource for {filename} with error {Marshal.GetHRForLastWin32Error():X}")); return(false); } foreach (FileResource resource in _fileResources) { // Read in the file data int fileLength; byte[] fileContent; using (FileStream fs = File.OpenRead(resource.Filename)) { fileLength = (int)fs.Length; fileContent = new byte[fileLength]; fs.Read(fileContent, 0, fileLength); } // Update the resources to include this file's data string dataName = string.Format(CultureInfo.InvariantCulture, "FILEDATA{0}", index); if (!NativeMethods.UpdateResourceW(hUpdate, (IntPtr)42, dataName, 0, fileContent, fileLength)) { results.AddMessage(BuildMessage.CreateMessage(BuildMessageSeverity.Error, "GenerateBootstrapper.General", $"Unable to update data resource for {filename} with error {Marshal.GetHRForLastWin32Error():X}")); return(false); } // Add this file's key to the resources string keyName = string.Format(CultureInfo.InvariantCulture, "FILEKEY{0}", index); byte[] data = StringToByteArray(resource.Key); if (!NativeMethods.UpdateResourceW(hUpdate, (IntPtr)42, keyName, 0, data, data.Length)) { results.AddMessage(BuildMessage.CreateMessage(BuildMessageSeverity.Error, "GenerateBootstrapper.General", $"Unable to update key resource for {filename} with error {Marshal.GetHRForLastWin32Error():X}")); return(false); } index++; } } } } finally { if (endUpdate && !NativeMethods.EndUpdateResource(hUpdate, false)) { results.AddMessage(BuildMessage.CreateMessage(BuildMessageSeverity.Error, "GenerateBootstrapper.General", $"Unable to finish updating resource for {filename} with error {Marshal.GetHRForLastWin32Error():X}")); returnValue = false; } } return(returnValue); }