Replaced the old VS templates with ones that offer more flexiblity. Started replacing the Content Project for the samples with our custom project type. Inlcuded a basic not yet working AssimpImporter.
243 lines
9.2 KiB
C#
243 lines
9.2 KiB
C#
/* ****************************************************************************
|
|
*
|
|
* Copyright (c) Microsoft Corporation.
|
|
*
|
|
* This source code is subject to terms and conditions of the Apache License, Version 2.0. A
|
|
* copy of the license can be found in the License.html file at the root of this distribution. If
|
|
* you cannot locate the Apache License, Version 2.0, please send an email to
|
|
* vspython@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
|
|
* by the terms of the Apache License, Version 2.0.
|
|
*
|
|
* You must not remove this notice, or any other, from this software.
|
|
*
|
|
* ***************************************************************************/
|
|
|
|
namespace Microsoft.VisualStudio.Project
|
|
{
|
|
using System;
|
|
using System.Diagnostics;
|
|
using System.Globalization;
|
|
using System.Threading;
|
|
using System.Windows.Forms;
|
|
|
|
public sealed class UIThread : IDisposable
|
|
{
|
|
private WindowsFormsSynchronizationContext synchronizationContext;
|
|
private bool isUnitTestingMode;
|
|
private Thread uithread;
|
|
#if DEBUG
|
|
/// <summary>
|
|
/// Stack trace when synchronizationContext was captured
|
|
/// </summary>
|
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")]
|
|
private StackTrace captureStackTrace;
|
|
#endif
|
|
|
|
/// <summary>
|
|
/// RunSync puts orignal exception stacktrace to Exception.Data by this key if action throws on UI thread
|
|
/// </summary>
|
|
/// WrappedStacktraceKey is a string to keep exception serializable.
|
|
private const string WrappedStacktraceKey = "$$Microsoft.VisualStudio.Package.UIThread.WrappedStacktraceKey$$";
|
|
|
|
/// <summary>
|
|
/// The singleton instance.
|
|
/// </summary>
|
|
private static volatile UIThread instance = new UIThread();
|
|
|
|
public UIThread()
|
|
{
|
|
this.Initialize();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the singleton instance
|
|
/// </summary>
|
|
public static UIThread Instance
|
|
{
|
|
get
|
|
{
|
|
return instance;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks whether this is the UI thread.
|
|
/// </summary>
|
|
public bool IsUIThread
|
|
{
|
|
get { return this.uithread == System.Threading.Thread.CurrentThread; }
|
|
}
|
|
|
|
#region IDisposable Members
|
|
/// <summary>
|
|
/// Dispose implementation.
|
|
/// </summary>
|
|
public void Dispose()
|
|
{
|
|
if (this.synchronizationContext != null)
|
|
{
|
|
this.synchronizationContext.Dispose();
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
/// <summary>
|
|
/// Initializes unit testing mode for this object
|
|
/// </summary>
|
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
|
public void InitUnitTestingMode()
|
|
{
|
|
Debug.Assert(this.synchronizationContext == null, "Context has already been captured; too late to InitUnitTestingMode");
|
|
this.isUnitTestingMode = true;
|
|
}
|
|
|
|
[Conditional("DEBUG")]
|
|
public void MustBeCalledFromUIThread()
|
|
{
|
|
Debug.Assert(this.uithread == System.Threading.Thread.CurrentThread || this.isUnitTestingMode, "This must be called from the GUI thread");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Runs an action asynchronously on an associated forms synchronization context.
|
|
/// </summary>
|
|
/// <param name="a">The action to run</param>
|
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
|
|
public void Run(Action a)
|
|
{
|
|
if (this.isUnitTestingMode)
|
|
{
|
|
a();
|
|
return;
|
|
}
|
|
Debug.Assert(this.synchronizationContext != null, "The SynchronizationContext must be captured before calling this method");
|
|
#if DEBUG
|
|
StackTrace stackTrace = new StackTrace(true);
|
|
#endif
|
|
this.synchronizationContext.Post(delegate(object ignore) {
|
|
try
|
|
{
|
|
this.MustBeCalledFromUIThread();
|
|
a();
|
|
}
|
|
#if DEBUG
|
|
catch (Exception e)
|
|
{
|
|
// swallow, random exceptions should not kill process
|
|
Debug.Assert(false, string.Format(CultureInfo.InvariantCulture, "UIThread.Run caught and swallowed exception: {0}\n\noriginally invoked from stack:\n{1}", e.ToString(), stackTrace.ToString()));
|
|
}
|
|
#else
|
|
catch (Exception)
|
|
{
|
|
// swallow, random exceptions should not kill process
|
|
}
|
|
#endif
|
|
}, null);
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Runs an action synchronously on an associated forms synchronization context
|
|
/// </summary>
|
|
/// <param name="a">The action to run.</param>
|
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
|
|
public void RunSync(Action a)
|
|
{
|
|
// if we're already on the UI thread run immediately - this prevents
|
|
// re-entrancy at unexpected times when we're already on the UI thread.
|
|
if (this.isUnitTestingMode ||
|
|
uithread == Thread.CurrentThread)
|
|
{
|
|
a();
|
|
return;
|
|
}
|
|
Exception exn = null; ;
|
|
Debug.Assert(this.synchronizationContext != null, "The SynchronizationContext must be captured before calling this method");
|
|
|
|
// Send on UI thread will execute immediately.
|
|
this.synchronizationContext.Send(ignore => {
|
|
try
|
|
{
|
|
this.MustBeCalledFromUIThread();
|
|
a();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
exn = e;
|
|
}
|
|
}, null
|
|
);
|
|
if (exn != null)
|
|
{
|
|
// throw exception on calling thread, preserve stacktrace
|
|
if (!exn.Data.Contains(WrappedStacktraceKey)) exn.Data[WrappedStacktraceKey] = exn.StackTrace;
|
|
throw exn;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Runs an action synchronously on an associated forms synchronization context
|
|
/// </summary>
|
|
/// <typeparam name="T">Return type</typeparam>
|
|
/// <param name="a">The function</param>
|
|
/// <returns></returns>
|
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
|
|
public T RunSync<T>(Func<T> a) {
|
|
T retValue = default(T);
|
|
if (this.isUnitTestingMode) {
|
|
return a();
|
|
}
|
|
Exception exn = null; ;
|
|
Debug.Assert(this.synchronizationContext != null, "The SynchronizationContext must be captured before calling this method");
|
|
|
|
// Send on UI thread will execute immediately.
|
|
this.synchronizationContext.Send(ignore => {
|
|
try {
|
|
this.MustBeCalledFromUIThread();
|
|
retValue = a();
|
|
} catch (Exception e) {
|
|
exn = e;
|
|
}
|
|
}, null
|
|
);
|
|
if (exn != null) {
|
|
// throw exception on calling thread, preserve stacktrace
|
|
if (exn.Data != null && !exn.Data.Contains(WrappedStacktraceKey)) exn.Data[WrappedStacktraceKey] = exn.StackTrace;
|
|
throw exn;
|
|
}
|
|
return retValue;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes this object.
|
|
/// </summary>
|
|
private void Initialize()
|
|
{
|
|
if (this.isUnitTestingMode) return;
|
|
this.uithread = System.Threading.Thread.CurrentThread;
|
|
|
|
if (this.synchronizationContext == null)
|
|
{
|
|
#if DEBUG
|
|
// This is a handy place to do this, since the product and all interesting unit tests
|
|
// must go through this code path.
|
|
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(delegate(object sender, UnhandledExceptionEventArgs args) {
|
|
if (args.IsTerminating)
|
|
{
|
|
string s = String.Format(CultureInfo.InvariantCulture, "An unhandled exception is about to terminate the process. Exception info:\n{0}", args.ExceptionObject.ToString());
|
|
Debug.Assert(false, s);
|
|
}
|
|
});
|
|
|
|
this.captureStackTrace = new StackTrace(true);
|
|
#endif
|
|
this.synchronizationContext = new WindowsFormsSynchronizationContext();
|
|
}
|
|
else
|
|
{
|
|
// Make sure we are always capturing the same thread.
|
|
Debug.Assert(this.uithread == Thread.CurrentThread);
|
|
}
|
|
}
|
|
}
|
|
} |