Browse Source

Rewritten Debugger.MTA2STA

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@819 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
David Srbecký 20 years ago
parent
commit
cbf2a0fac6
  1. 169
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Debugger/Internal/MTA2STA.cs
  2. 2
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Debugger/Internal/ManagedCallbackProxy.cs

169
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Debugger/Internal/MTA2STA.cs

@ -11,122 +11,125 @@ using System.Runtime.InteropServices; @@ -11,122 +11,125 @@ using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
using Debugger.Interop.CorDebug;
namespace Debugger.Interop.CorDebug
namespace Debugger
{
delegate object MethodInvokerWithReturnValue();
class MTA2STA
{
{
Form hiddenForm;
IntPtr hiddenFormHandle;
object targetObject = null;
string functionName = null;
Object[] functionParameters = null;
System.Threading.Thread MTAThread;
static object OnlyOneAtTimeLock = new Object();
static object DataLock = new Object();
object returnValue;
public MTA2STA()
{
hiddenForm = new Form();
// Force handle creation
hiddenFormHandle = hiddenForm.Handle;
}
void TraceMsg(string msg)
static void TraceMsg(string msg)
{
//System.Console.WriteLine("MTA2STA: " + msg);
}
public object CallInSTA (object targetObject, string functionName, object[] functionParameters)
// Try to avoid this since it will catch exceptions and it is slow
public object CallInSTA(object targetObject, string functionName, object[] functionParameters)
{
lock (OnlyOneAtTimeLock) {
TraceMsg("call to process: " + functionName + " {");
lock (DataLock) {
this.targetObject = targetObject;
this.functionName = functionName;
this.functionParameters = functionParameters;
}
MTAThread = System.Threading.Thread.CurrentThread;
if (hiddenForm.InvokeRequired == true) {
IAsyncResult async = hiddenForm.BeginInvoke(new EventHandler(PerformCall));
//while (async.AsyncWaitHandle.WaitOne(1000,true) == false) {
// System.Console.WriteLine("Waiting for callback...");
//}
if (async.AsyncWaitHandle.WaitOne(1000,true) == false) {
System.Console.WriteLine("Callback time out! Unleashing debugger thread.");
}
return CallInSTA(delegate { return InvokeMethod(targetObject, functionName, functionParameters); });
}
public void CallInSTA(MethodInvoker callDelegate)
{
CallInSTA(delegate { callDelegate(); return null; }, true);
}
public object CallInSTA(MethodInvokerWithReturnValue callDelegate)
{
return CallInSTA(callDelegate, true); // TODO: Make it false once it is safe
}
object CallInSTA(MethodInvokerWithReturnValue callDelegate, bool mayAbandon)
{
if (hiddenForm.InvokeRequired == true) {
IAsyncResult async = hiddenForm.BeginInvoke(callDelegate);
// Firsy try... give it 1 second to run
if (async.AsyncWaitHandle.WaitOne(1000, true)) {
return hiddenForm.EndInvoke(async);
} else {
PerformCall(hiddenForm, EventArgs.Empty);
// Abandon the call if possible
if (mayAbandon) {
System.Console.WriteLine("Callback time out! Unleashing thread.");
return null;
} else {
System.Console.WriteLine("Warring: Call in STA is taking too long");
return hiddenForm.EndInvoke(async); // Keep waiting
}
}
} else {
return callDelegate();
}
}
TraceMsg("} // MTA2STA: call processed: " + functionName);
public static object MarshalParamTo(object param, Type outputType)
{
if (param is IntPtr) {
return MarshalIntPtrTo((IntPtr)param, outputType);
} else {
return param;
}
return returnValue;
}
void PerformCall(object sender, EventArgs e)
public static object MarshalIntPtrTo(IntPtr param, Type outputType)
{
returnValue = Call(targetObject, functionName, functionParameters);
// IntPtr requested as output (must be before the null check so that we pass IntPtr.Zero)
if (outputType == typeof(IntPtr)) {
return param;
}
// The parameter is null pointer
if ((IntPtr)param == IntPtr.Zero) {
return null;
}
// String requested as output
if (outputType == typeof(string)) {
return Marshal.PtrToStringAuto((IntPtr)param);
}
// Marshal a COM object
return Marshal.GetTypedObjectForIUnknown((IntPtr)param, outputType);
}
public object Call (object targetObject, string functionName, object[] functionParameters)
/// <summary>
/// Uses reflection to call method. Automaticaly marshals parameters.
/// </summary>
/// <param name="targetObject">Targed object which contains the method. In case of static mehod pass the Type</param>
/// <param name="functionName">The name of the function to call</param>
/// <param name="functionParameters">Parameters which should be send to the function. Parameters will be marshaled to proper type.</param>
/// <returns>Return value of the called function</returns>
public static object InvokeMethod(object targetObject, string functionName, object[] functionParameters)
{
MethodInfo method;
object[] outputParams;
lock (DataLock) {
object[] inputParams = functionParameters;
if (targetObject is Type) {
method = ((Type)targetObject).GetMethod(functionName);
} else {
method = targetObject.GetType().GetMethod(functionName);
}
ParameterInfo[] outputParamsInfo = method.GetParameters();
outputParams = null;
if (outputParamsInfo != null) {
outputParams = new object[outputParamsInfo.Length];
for (int i = 0; i < outputParams.Length; i++) {
if (inputParams[i] == null) {
outputParams[i] = null;
} else if (inputParams[i] is IntPtr) {
if (outputParamsInfo[i].ParameterType == typeof(IntPtr)) {
outputParams[i] = inputParams[i];
} else if ((IntPtr)inputParams[i] == IntPtr.Zero) {
outputParams[i] = null;
} else if (outputParamsInfo[i].ParameterType == typeof(string)) {
outputParams[i] = Marshal.PtrToStringAuto((IntPtr)inputParams[i]);
} else {
try{
outputParams[i] = null;
outputParams[i] = Marshal.GetTypedObjectForIUnknown((IntPtr)inputParams[i], outputParamsInfo[i].ParameterType);
} catch (System.Exception exception) {
throw new Debugger.DebuggerException("Marshaling of argument " + i.ToString() + " of " + functionName + " failed.", exception);
}
}
} else {
outputParams[i] = inputParams[i];
}
}
}
if (targetObject is Type) {
method = ((Type)targetObject).GetMethod(functionName);
} else {
method = targetObject.GetType().GetMethod(functionName);
}
ParameterInfo[] methodParamsInfo = method.GetParameters();
object[] convertedParams = new object[methodParamsInfo.Length];
for (int i = 0; i < convertedParams.Length; i++) {
convertedParams[i] = MarshalParamTo(functionParameters[i], methodParamsInfo[i].ParameterType);
}
TraceMsg ("Invoke " + functionName + "{");
object returnValue = null;
TraceMsg ("Invoking " + functionName + "...");
try {
if (targetObject is Type) {
returnValue = method.Invoke(null, outputParams);
return method.Invoke(null, convertedParams);
} else {
returnValue = method.Invoke(targetObject, outputParams);
return method.Invoke(targetObject, convertedParams);
}
} catch (System.Exception exception) {
throw new Debugger.DebuggerException("Invoke of " + functionName + " failed.", exception);
}
TraceMsg ("} \\\\ Invoke");
return returnValue;
}
}
}

2
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Debugger/Internal/ManagedCallbackProxy.cs

@ -46,7 +46,7 @@ namespace Debugger @@ -46,7 +46,7 @@ namespace Debugger
if (debugger.RequiredApartmentState == ApartmentState.STA) {
mta2sta.CallInSTA(realCallback, function, parameters);
} else {
mta2sta.Call(realCallback, function, parameters);
MTA2STA.InvokeMethod(realCallback, function, parameters);
}
}

Loading…
Cancel
Save