singrdk/base/Windows/BuildTasks/TaskBase.cs

201 lines
6.0 KiB
C#
Raw Normal View History

2008-11-17 18:29:00 -05:00
// ----------------------------------------------------------------------------
//
// 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();
}