pascalabcnet/Debugger.Core/Src/Wrappers/ResourceManager.cs
Бондарев Иван e6e67c193c initial commit
2015-05-14 21:35:07 +02:00

115 lines
3.2 KiB
C#

// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="David Srbecký" email="dsrbecky@gmail.com"/>
// <version>$Revision: 2185 $</version>
// </file>
#pragma warning disable 1591
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Debugger.Interop;
namespace Debugger.Wrappers
{
class TrackedObjectMetaData
{
public Type ObjectType;
public int RefCount;
public TrackedObjectMetaData(Type objectType, int refCount)
{
this.ObjectType = objectType;
this.RefCount = refCount;
}
}
public static class ResourceManager
{
static MTA2STA mta2sta = new MTA2STA();
static bool trace = true;
static Dictionary<object, TrackedObjectMetaData> trackedCOMObjects = new Dictionary<object, TrackedObjectMetaData>();
public static bool TraceMessagesEnabled {
get {
return trace;
}
set {
trace = value;
}
}
public static void TrackCOMObject(object comObject, Type type)
{
if (comObject == null || !Marshal.IsComObject(comObject)) {
if (trace) Trace("Will not be tracked: {0}", type.Name);
} else {
TrackedObjectMetaData metaData;
if (trackedCOMObjects.TryGetValue(comObject, out metaData)) {
metaData.RefCount += 1;
} else {
metaData = new TrackedObjectMetaData(type,1);
trackedCOMObjects.Add(comObject, metaData);
}
if (trace) Trace("AddRef {0,2}: {1}", metaData.RefCount, type.Name);
}
}
public static void ReleaseCOMObject(object comObject, Type type)
{
// Ensure that the release is done synchronosly
try {
mta2sta.AsyncCall(delegate {
ReleaseCOMObjectInternal(comObject, type);
});
} catch (InvalidOperationException) {
// This might happen when the application is shuting down
}
}
static void ReleaseCOMObjectInternal(object comObject, Type type)
{
TrackedObjectMetaData metaData;
if (comObject != null && trackedCOMObjects.TryGetValue(comObject, out metaData)) {
metaData.RefCount -= 1;
if (metaData.RefCount == 0) {
Marshal.FinalReleaseComObject(comObject);
trackedCOMObjects.Remove(comObject);
}
if (trace) Trace("Release {0,2}: {1}", metaData.RefCount, type.Name);
} else {
if (trace) Trace("Was not tracked: {0}", type.Name);
}
}
public static void ReleaseAllTrackedCOMObjects()
{
if (trace) Trace("Releasing {0} tracked COM objects... ", trackedCOMObjects.Count);
while(trackedCOMObjects.Count > 0) {
foreach (KeyValuePair<object, TrackedObjectMetaData> pair in trackedCOMObjects) {
Marshal.FinalReleaseComObject(pair.Key);
if (trace) Trace(" * Releasing {0} ({1} references)", pair.Value.ObjectType.Name, pair.Value.RefCount);
trackedCOMObjects.Remove(pair.Key);
break;
}
}
if (trace) Trace(" * Done");
}
public static event EventHandler<MessageEventArgs> TraceMessage;
static void Trace(string msg, params object[] pars)
{
if (TraceMessage != null && trace) {
string message = String.Format("COM({0,-3}): {1}", trackedCOMObjects.Count, String.Format(msg, pars));
TraceMessage(null, new MessageEventArgs(null, message));
}
}
}
}
#pragma warning restore 1591