201 lines
6.0 KiB
C#
201 lines
6.0 KiB
C#
|
// ----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
//
|
||
|
// ----------------------------------------------------------------------------
|
||
|
|
||
|
using System;
|
||
|
using System.Collections.Generic;
|
||
|
using System.Text;
|
||
|
using Microsoft.Build.Framework;
|
||
|
|
||
|
#if ENABLE_INTEROP
|
||
|
using System.Runtime.InteropServices;
|
||
|
using System.Threading;
|
||
|
using Windows;
|
||
|
#endif
|
||
|
|
||
|
namespace Microsoft.Singularity.BuildTasks
|
||
|
{
|
||
|
public abstract class TaskBase : Microsoft.Build.Framework.ITask
|
||
|
{
|
||
|
protected TaskBase()
|
||
|
{
|
||
|
_taskname = null;
|
||
|
_disableMessagePumping = true;
|
||
|
}
|
||
|
|
||
|
string _taskname;
|
||
|
|
||
|
protected string TaskName
|
||
|
{
|
||
|
get {
|
||
|
if (_taskname == null) {
|
||
|
_taskname = this.GetType().Name;
|
||
|
}
|
||
|
return _taskname;
|
||
|
}
|
||
|
set { _taskname = value; }
|
||
|
}
|
||
|
|
||
|
protected void LogMessage(string msg)
|
||
|
{
|
||
|
BuildMessageEventArgs e = new BuildMessageEventArgs(msg, null, this.TaskName, MessageImportance.Normal);
|
||
|
_engine.LogMessageEvent(e);
|
||
|
}
|
||
|
|
||
|
protected void LogError(string msg)
|
||
|
{
|
||
|
BuildErrorEventArgs e = new BuildErrorEventArgs(null, null, null, 0, 0, 0, 0, msg, null, this.TaskName);
|
||
|
_engine.LogErrorEvent(e);
|
||
|
}
|
||
|
|
||
|
protected void LogMessage(MessageImportance importance, string msg)
|
||
|
{
|
||
|
BuildMessageEventArgs e = new BuildMessageEventArgs(msg, null, this.TaskName, importance);
|
||
|
_engine.LogMessageEvent(e);
|
||
|
}
|
||
|
|
||
|
protected abstract bool Execute();
|
||
|
|
||
|
bool ITask.Execute()
|
||
|
{
|
||
|
if (_engine == null)
|
||
|
throw new InvalidOperationException("The BuildEngine property must be set before calling the Execute method.");
|
||
|
|
||
|
#if false
|
||
|
if (_host == null)
|
||
|
throw new InvalidOperationException("The Host property must be set before calling the Execute method.");
|
||
|
#endif
|
||
|
|
||
|
if (_disableMessagePumping)
|
||
|
return this.Execute();
|
||
|
|
||
|
bool returnValue = false;
|
||
|
ExecuteMethodAndPump(delegate() { returnValue = this.Execute(); });
|
||
|
return returnValue;
|
||
|
}
|
||
|
|
||
|
ITaskHost _host;
|
||
|
IBuildEngine _engine;
|
||
|
|
||
|
public IBuildEngine BuildEngine
|
||
|
{
|
||
|
get { return _engine; }
|
||
|
set { _engine = value; }
|
||
|
}
|
||
|
|
||
|
public ITaskHost HostObject
|
||
|
{
|
||
|
get { return _host; }
|
||
|
set { _host = value; }
|
||
|
}
|
||
|
|
||
|
bool _disableMessagePumping;
|
||
|
|
||
|
public bool DisableMessagePumping
|
||
|
{
|
||
|
get { return _disableMessagePumping; }
|
||
|
set { _disableMessagePumping = value; }
|
||
|
}
|
||
|
|
||
|
#if ENABLE_INTEROP
|
||
|
#region Code for pumping messages while executing tasks
|
||
|
|
||
|
unsafe void ExecuteMethodAndPump(SimpleMethod method)
|
||
|
{
|
||
|
if (method == null)
|
||
|
throw new ArgumentNullException("method");
|
||
|
|
||
|
if (_disableMessagePumping) {
|
||
|
LogMessage("Message pumping is disabled - executing method directly");
|
||
|
method();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (Thread.CurrentThread.GetApartmentState() == ApartmentState.MTA) {
|
||
|
LogMessage("Message pumping is disabled - this thread is an MTA thread");
|
||
|
method();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
bool quit = false;
|
||
|
uint mainThreadId = Kernel32.GetCurrentThreadId();
|
||
|
// LogMessage("main thread id = " + mainThreadId);
|
||
|
Exception worker_exception = null;
|
||
|
|
||
|
Thread thread = new Thread(delegate()
|
||
|
{
|
||
|
try {
|
||
|
method();
|
||
|
worker_exception = null;
|
||
|
}
|
||
|
catch (Exception ex) {
|
||
|
worker_exception = ex;
|
||
|
}
|
||
|
quit = true;
|
||
|
User32.PostThreadMessageW(mainThreadId, User32.WM_NULL, IntPtr.Zero, IntPtr.Zero);
|
||
|
});
|
||
|
|
||
|
thread.Start();
|
||
|
|
||
|
for (;;) {
|
||
|
if (quit) {
|
||
|
// LogMessage("Main thread received quit notification. Quitting.");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
MSG msg = new MSG();
|
||
|
if (Windows.User32.GetMessageW(& msg, IntPtr.Zero, 0, 0)) {
|
||
|
User32.TranslateMessage(&msg);
|
||
|
User32.DispatchMessageW(&msg);
|
||
|
}
|
||
|
else {
|
||
|
LogMessage("Received WM_QUIT or GetMessage failed! Bailing.");
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// LogMessage("Waiting for worker thread to finish...");
|
||
|
thread.Join();
|
||
|
// LogMessage("Worker thread is done.");
|
||
|
|
||
|
if (worker_exception != null) {
|
||
|
throw worker_exception;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void ExecuteMethodAndPumpThreadMain(object untyped_method)
|
||
|
{
|
||
|
SimpleMethod method = (SimpleMethod)untyped_method;
|
||
|
}
|
||
|
|
||
|
#endregion
|
||
|
#endif
|
||
|
|
||
|
|
||
|
#region Helper methods that don't have a better place to live.
|
||
|
|
||
|
protected bool ValidateCSharpIdentifier(string name, string id, bool allowDots)
|
||
|
{
|
||
|
if (String.IsNullOrEmpty(id)) {
|
||
|
LogError(String.Format("The parameter '{0}' is required, but no value was provided.", name));
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (!Util.ValidateCSharpIdentifier(id, allowDots)) {
|
||
|
LogError(String.Format("The value '{0}' provided to parameter '{1}' is not a valid C# identifier.", id, name));
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
#endregion
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
delegate void SimpleMethod();
|
||
|
}
|