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.
264 lines
9.1 KiB
C#
264 lines
9.1 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.
|
|
*
|
|
* ***************************************************************************/
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Runtime.InteropServices;
|
|
using Microsoft.VisualStudio;
|
|
using IOleServiceProvider = Microsoft.VisualStudio.OLE.Interop.IServiceProvider;
|
|
|
|
namespace Microsoft.VisualStudio.Project
|
|
{
|
|
public class OleServiceProvider : IOleServiceProvider, IDisposable
|
|
{
|
|
#region Public Types
|
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")]
|
|
public delegate object ServiceCreatorCallback(Type serviceType);
|
|
#endregion
|
|
|
|
#region Private Types
|
|
private class ServiceData : IDisposable
|
|
{
|
|
private Type serviceType;
|
|
private object instance;
|
|
private ServiceCreatorCallback creator;
|
|
private bool shouldDispose;
|
|
public ServiceData(Type serviceType, object instance, ServiceCreatorCallback callback, bool shouldDispose)
|
|
{
|
|
VsUtilities.ArgumentNotNull("serviceType", serviceType);
|
|
|
|
if ((null == instance) && (null == callback))
|
|
{
|
|
throw new ArgumentNullException("instance");
|
|
}
|
|
|
|
this.serviceType = serviceType;
|
|
this.instance = instance;
|
|
this.creator = callback;
|
|
this.shouldDispose = shouldDispose;
|
|
}
|
|
|
|
public object ServiceInstance
|
|
{
|
|
get
|
|
{
|
|
if (null == instance)
|
|
{
|
|
instance = creator(serviceType);
|
|
System.Diagnostics.Debug.Assert(serviceType != null);
|
|
}
|
|
return instance;
|
|
}
|
|
}
|
|
|
|
public Guid Guid
|
|
{
|
|
get { return serviceType.GUID; }
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
if ((shouldDispose) && (null != instance))
|
|
{
|
|
IDisposable disp = instance as IDisposable;
|
|
if (null != disp)
|
|
{
|
|
disp.Dispose();
|
|
}
|
|
instance = null;
|
|
}
|
|
creator = null;
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region fields
|
|
|
|
private Dictionary<Guid, ServiceData> services = new Dictionary<Guid, ServiceData>();
|
|
private bool isDisposed;
|
|
/// <summary>
|
|
/// Defines an object that will be a mutex for this object for synchronizing thread calls.
|
|
/// </summary>
|
|
private static volatile object Mutex = new object();
|
|
#endregion
|
|
|
|
#region ctors
|
|
public OleServiceProvider()
|
|
{
|
|
}
|
|
#endregion
|
|
|
|
#region IOleServiceProvider Members
|
|
|
|
public int QueryService(ref Guid guidService, ref Guid riid, out IntPtr ppvObject)
|
|
{
|
|
ppvObject = (IntPtr)0;
|
|
int hr = VSConstants.S_OK;
|
|
|
|
ServiceData serviceInstance = null;
|
|
|
|
if (services != null && services.ContainsKey(guidService))
|
|
{
|
|
serviceInstance = services[guidService];
|
|
}
|
|
|
|
if (serviceInstance == null)
|
|
{
|
|
return VSConstants.E_NOINTERFACE;
|
|
}
|
|
|
|
// Now check to see if the user asked for an IID other than
|
|
// IUnknown. If so, we must do another QI.
|
|
//
|
|
if (riid.Equals(NativeMethods.IID_IUnknown))
|
|
{
|
|
object inst = serviceInstance.ServiceInstance;
|
|
if (inst == null)
|
|
{
|
|
return VSConstants.E_NOINTERFACE;
|
|
}
|
|
ppvObject = Marshal.GetIUnknownForObject(serviceInstance.ServiceInstance);
|
|
}
|
|
else
|
|
{
|
|
IntPtr pUnk = IntPtr.Zero;
|
|
try
|
|
{
|
|
pUnk = Marshal.GetIUnknownForObject(serviceInstance.ServiceInstance);
|
|
hr = Marshal.QueryInterface(pUnk, ref riid, out ppvObject);
|
|
}
|
|
finally
|
|
{
|
|
if (pUnk != IntPtr.Zero)
|
|
{
|
|
Marshal.Release(pUnk);
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Dispose
|
|
|
|
/// <summary>
|
|
/// The IDispose interface Dispose method for disposing the object determinastically.
|
|
/// </summary>
|
|
public void Dispose()
|
|
{
|
|
Dispose(true);
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
#endregion
|
|
|
|
/// <summary>
|
|
/// Adds the given service to the service container.
|
|
/// </summary>
|
|
/// <param name="serviceType">The type of the service to add.</param>
|
|
/// <param name="serviceInstance">An instance of the service.</param>
|
|
/// <param name="shouldDisposeServiceInstance">true if the Dipose of the service provider is allowed to dispose the sevice instance.</param>
|
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope",
|
|
Justification = "The services created here will be disposed in the Dispose method of this type.")]
|
|
public void AddService(Type serviceType, object serviceInstance, bool shouldDisposeServiceInstance)
|
|
{
|
|
// Create the description of this service. Note that we don't do any validation
|
|
// of the parameter here because the constructor of ServiceData will do it for us.
|
|
ServiceData service = new ServiceData(serviceType, serviceInstance, null, shouldDisposeServiceInstance);
|
|
|
|
// Now add the service desctription to the dictionary.
|
|
AddService(service);
|
|
}
|
|
|
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope",
|
|
Justification = "The services created here will be disposed in the Dispose method of this type.")]
|
|
public void AddService(Type serviceType, ServiceCreatorCallback callback, bool shouldDisposeServiceInstance)
|
|
{
|
|
// Create the description of this service. Note that we don't do any validation
|
|
// of the parameter here because the constructor of ServiceData will do it for us.
|
|
ServiceData service = new ServiceData(serviceType, null, callback, shouldDisposeServiceInstance);
|
|
|
|
// Now add the service desctription to the dictionary.
|
|
AddService(service);
|
|
}
|
|
|
|
private void AddService(ServiceData data)
|
|
{
|
|
// Make sure that the collection of services is created.
|
|
if (null == services)
|
|
{
|
|
services = new Dictionary<Guid, ServiceData>();
|
|
}
|
|
|
|
// Disallow the addition of duplicate services.
|
|
if (services.ContainsKey(data.Guid))
|
|
{
|
|
throw new InvalidOperationException();
|
|
}
|
|
|
|
services.Add(data.Guid, data);
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// Removes the given service type from the service container.
|
|
/// </devdoc>
|
|
public void RemoveService(Type serviceType)
|
|
{
|
|
VsUtilities.ArgumentNotNull("serviceType", serviceType);
|
|
|
|
if (services.ContainsKey(serviceType.GUID))
|
|
{
|
|
services.Remove(serviceType.GUID);
|
|
}
|
|
}
|
|
|
|
#region helper methods
|
|
/// <summary>
|
|
/// The method that does the cleanup.
|
|
/// </summary>
|
|
/// <param name="disposing"></param>
|
|
protected virtual void Dispose(bool disposing)
|
|
{
|
|
// Everybody can go here.
|
|
if (!this.isDisposed)
|
|
{
|
|
// Synchronize calls to the Dispose simulteniously.
|
|
lock (Mutex)
|
|
{
|
|
if (disposing)
|
|
{
|
|
// Remove all our services
|
|
if (services != null)
|
|
{
|
|
foreach (ServiceData data in services.Values)
|
|
{
|
|
data.Dispose();
|
|
}
|
|
services.Clear();
|
|
services = null;
|
|
}
|
|
}
|
|
|
|
this.isDisposed = true;
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
}
|
|
}
|