in src/Tasks/GenerateResource.cs [634:867]
public override bool Execute()
{
bool outOfProcExecutionSucceeded = true;
#if (!STANDALONEBUILD)
using (new CodeMarkerStartEnd(CodeMarkerEvent.perfMSBuildGenerateResourceBegin, CodeMarkerEvent.perfMSBuildGenerateResourceEnd))
#endif
{
// If we're extracting ResW files from assemblies (instead of building resources),
// our Sources can contain PDB's, pictures, and other non-DLL's. Prune that list.
// .NET Framework assemblies are not included. However, other Microsoft ones
// such as MSTestFramework may be included (resolved from GetSDKReferenceFiles).
if (ExtractResWFiles && Sources != null)
{
_satelliteInputs = new List<ITaskItem>();
List<ITaskItem> newSources = new List<ITaskItem>();
foreach (ITaskItem item in Sources)
{
if (item.ItemSpec.EndsWith(".dll", StringComparison.OrdinalIgnoreCase))
{
if (item.ItemSpec.EndsWith(".resources.dll", StringComparison.OrdinalIgnoreCase))
{
_satelliteInputs.Add(item);
}
else
{
newSources.Add(item);
}
}
}
Sources = newSources.ToArray();
}
// If there are no sources to process, just return (with success) and report the condition.
if ((Sources == null) || (Sources.Length == 0))
{
Log.LogMessageFromResources(MessageImportance.Low, "GenerateResource.NoSources");
// Indicate we generated nothing
OutputResources = null;
return true;
}
if (!ValidateParameters())
{
// Indicate we generated nothing
OutputResources = null;
return false;
}
// In the case that OutputResources wasn't set, build up the outputs by transforming the Sources
// However if we are extracting ResW files, we cannot easily tell which files we'll produce up front,
// without loading each assembly.
if (!ExtractResWFiles && !CreateOutputResourcesNames())
{
// Indicate we generated nothing
OutputResources = null;
return false;
}
List<ITaskItem> inputsToProcess;
List<ITaskItem> outputsToProcess;
List<ITaskItem> cachedOutputFiles; // For incremental builds, this is the set of already-existing, up to date files.
GetResourcesToProcess(out inputsToProcess, out outputsToProcess, out cachedOutputFiles);
if (inputsToProcess.Count == 0 && !Log.HasLoggedErrors)
{
if (cachedOutputFiles.Count > 0)
{
OutputResources = cachedOutputFiles.ToArray();
}
Log.LogMessageFromResources("GenerateResource.NothingOutOfDate");
}
else
{
if (!ComputePathToResGen())
{
// unable to compute the path to resgen.exe and that is necessary to
// continue forward, so return now.
return false;
}
if (ExecuteAsTool)
{
outOfProcExecutionSucceeded = GenerateResourcesUsingResGen(inputsToProcess, outputsToProcess);
}
else // Execute in-proc (or in a separate appdomain if necessary)
{
// Log equivalent command line as this is a convenient way to log all the references, etc
// even though we're not actually running resgen.exe
LogResgenCommandLine(inputsToProcess, outputsToProcess);
#if FEATURE_APPDOMAIN
// Figure out whether a separate AppDomain is required because an assembly would be locked.
bool needSeparateAppDomain = NeedSeparateAppDomain();
AppDomain appDomain = null;
#endif
ProcessResourceFiles process = null;
try
{
#if FEATURE_APPDOMAIN
if (needSeparateAppDomain)
{
// we're going to be remoting across the appdomain boundary, so
// create the list that we'll use to disconnect the taskitems once we're done
_remotedTaskItems = new List<ITaskItem>();
appDomain = AppDomain.CreateDomain
(
"generateResourceAppDomain",
null,
AppDomain.CurrentDomain.SetupInformation
);
object obj = appDomain.CreateInstanceFromAndUnwrap
(
typeof(ProcessResourceFiles).Module.FullyQualifiedName,
typeof(ProcessResourceFiles).FullName
);
Type processType = obj.GetType();
ErrorUtilities.VerifyThrow(processType == typeof(ProcessResourceFiles), "Somehow got a wrong and possibly incompatible type for ProcessResourceFiles.");
process = (ProcessResourceFiles)obj;
RecordItemsForDisconnectIfNecessary(_references);
RecordItemsForDisconnectIfNecessary(inputsToProcess);
RecordItemsForDisconnectIfNecessary(outputsToProcess);
}
else
#endif
{
process = new ProcessResourceFiles();
}
process.Run(Log, _references, inputsToProcess, _satelliteInputs, outputsToProcess, UseSourcePath,
StronglyTypedLanguage, _stronglyTypedNamespace, _stronglyTypedManifestPrefix,
StronglyTypedFileName, StronglyTypedClassName, PublicClass,
ExtractResWFiles, OutputDirectory);
this.StronglyTypedClassName = process.StronglyTypedClassName; // in case a default was chosen
this.StronglyTypedFileName = process.StronglyTypedFilename; // in case a default was chosen
_stronglyTypedResourceSuccessfullyCreated = process.StronglyTypedResourceSuccessfullyCreated;
if (null != process.UnsuccessfullyCreatedOutFiles)
{
foreach (string item in process.UnsuccessfullyCreatedOutFiles)
{
_unsuccessfullyCreatedOutFiles.Add(item);
}
}
if (ExtractResWFiles)
{
ITaskItem[] outputResources = process.ExtractedResWFiles.ToArray();
#if FEATURE_APPDOMAIN
if (needSeparateAppDomain)
{
// Ensure we can unload the other AppDomain, yet still use the
// ITaskItems we got back. Clone them.
outputResources = CloneValuesInThisAppDomain(outputResources);
}
#endif
if (cachedOutputFiles.Count > 0)
{
OutputResources = new ITaskItem[outputResources.Length + cachedOutputFiles.Count];
outputResources.CopyTo(OutputResources, 0);
cachedOutputFiles.CopyTo(OutputResources, outputResources.Length);
}
else
{
OutputResources = outputResources;
}
#if FEATURE_BINARY_SERIALIZATION
// Get portable library cache info (and if needed, marshal it to this AD).
List<ResGenDependencies.PortableLibraryFile> portableLibraryCacheInfo = process.PortableLibraryCacheInfo;
for (int i = 0; i < portableLibraryCacheInfo.Count; i++)
{
_cache.UpdatePortableLibrary(portableLibraryCacheInfo[i]);
}
#endif
}
process = null;
}
finally
{
#if FEATURE_APPDOMAIN
if (needSeparateAppDomain && appDomain != null)
{
Log.MarkAsInactive();
AppDomain.Unload(appDomain);
process = null;
appDomain = null;
// if we've been asked to remote these items then
// we need to disconnect them from .NET Remoting now we're all done with them
if (_remotedTaskItems != null)
{
foreach (ITaskItem item in _remotedTaskItems)
{
if (item is MarshalByRefObject)
{
// Tell remoting to forget connections to the taskitem
RemotingServices.Disconnect((MarshalByRefObject)item);
}
}
}
_remotedTaskItems = null;
}
#endif
}
}
}
#if FEATURE_BINARY_SERIALIZATION
// And now we serialize the cache to save our resgen linked file resolution for later use.
WriteStateFile();
#endif
RemoveUnsuccessfullyCreatedResourcesFromOutputResources();
RecordFilesWritten();
}
return !Log.HasLoggedErrors && outOfProcExecutionSucceeded;
}