|
|
|
@ -11,122 +11,125 @@ using System.Runtime.InteropServices; |
|
|
|
using System.Threading; |
|
|
|
using System.Threading; |
|
|
|
using System.Windows.Forms; |
|
|
|
using System.Windows.Forms; |
|
|
|
|
|
|
|
|
|
|
|
using Debugger.Interop.CorDebug; |
|
|
|
namespace Debugger |
|
|
|
|
|
|
|
|
|
|
|
namespace Debugger.Interop.CorDebug |
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
|
|
|
|
delegate object MethodInvokerWithReturnValue(); |
|
|
|
|
|
|
|
|
|
|
|
class MTA2STA |
|
|
|
class MTA2STA |
|
|
|
{ |
|
|
|
{ |
|
|
|
Form hiddenForm; |
|
|
|
Form hiddenForm; |
|
|
|
IntPtr hiddenFormHandle; |
|
|
|
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() |
|
|
|
public MTA2STA() |
|
|
|
{ |
|
|
|
{ |
|
|
|
hiddenForm = new Form(); |
|
|
|
hiddenForm = new Form(); |
|
|
|
|
|
|
|
// Force handle creation
|
|
|
|
hiddenFormHandle = hiddenForm.Handle; |
|
|
|
hiddenFormHandle = hiddenForm.Handle; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void TraceMsg(string msg) |
|
|
|
static void TraceMsg(string msg) |
|
|
|
{ |
|
|
|
{ |
|
|
|
//System.Console.WriteLine("MTA2STA: " + 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) { |
|
|
|
return CallInSTA(delegate { return InvokeMethod(targetObject, functionName, functionParameters); }); |
|
|
|
TraceMsg("call to process: " + functionName + " {"); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
lock (DataLock) { |
|
|
|
public void CallInSTA(MethodInvoker callDelegate) |
|
|
|
this.targetObject = targetObject; |
|
|
|
{ |
|
|
|
this.functionName = functionName; |
|
|
|
CallInSTA(delegate { callDelegate(); return null; }, true); |
|
|
|
this.functionParameters = functionParameters; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public object CallInSTA(MethodInvokerWithReturnValue callDelegate) |
|
|
|
MTAThread = System.Threading.Thread.CurrentThread; |
|
|
|
{ |
|
|
|
if (hiddenForm.InvokeRequired == true) { |
|
|
|
return CallInSTA(callDelegate, true); // TODO: Make it false once it is safe
|
|
|
|
IAsyncResult async = hiddenForm.BeginInvoke(new EventHandler(PerformCall)); |
|
|
|
} |
|
|
|
//while (async.AsyncWaitHandle.WaitOne(1000,true) == false) {
|
|
|
|
|
|
|
|
// System.Console.WriteLine("Waiting for callback...");
|
|
|
|
object CallInSTA(MethodInvokerWithReturnValue callDelegate, bool mayAbandon) |
|
|
|
//}
|
|
|
|
{ |
|
|
|
if (async.AsyncWaitHandle.WaitOne(1000,true) == false) { |
|
|
|
if (hiddenForm.InvokeRequired == true) { |
|
|
|
System.Console.WriteLine("Callback time out! Unleashing debugger thread."); |
|
|
|
IAsyncResult async = hiddenForm.BeginInvoke(callDelegate); |
|
|
|
} |
|
|
|
// Firsy try... give it 1 second to run
|
|
|
|
|
|
|
|
if (async.AsyncWaitHandle.WaitOne(1000, true)) { |
|
|
|
|
|
|
|
return hiddenForm.EndInvoke(async); |
|
|
|
} else { |
|
|
|
} 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; |
|
|
|
MethodInfo method; |
|
|
|
object[] outputParams; |
|
|
|
if (targetObject is Type) { |
|
|
|
lock (DataLock) { |
|
|
|
method = ((Type)targetObject).GetMethod(functionName); |
|
|
|
object[] inputParams = functionParameters; |
|
|
|
} else { |
|
|
|
if (targetObject is Type) { |
|
|
|
method = targetObject.GetType().GetMethod(functionName); |
|
|
|
method = ((Type)targetObject).GetMethod(functionName); |
|
|
|
} |
|
|
|
} else { |
|
|
|
|
|
|
|
method = targetObject.GetType().GetMethod(functionName); |
|
|
|
ParameterInfo[] methodParamsInfo = method.GetParameters(); |
|
|
|
} |
|
|
|
object[] convertedParams = new object[methodParamsInfo.Length]; |
|
|
|
ParameterInfo[] outputParamsInfo = method.GetParameters(); |
|
|
|
|
|
|
|
outputParams = null; |
|
|
|
for (int i = 0; i < convertedParams.Length; i++) { |
|
|
|
if (outputParamsInfo != null) { |
|
|
|
convertedParams[i] = MarshalParamTo(functionParameters[i], methodParamsInfo[i].ParameterType); |
|
|
|
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]; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
TraceMsg ("Invoke " + functionName + "{"); |
|
|
|
|
|
|
|
object returnValue = null; |
|
|
|
TraceMsg ("Invoking " + functionName + "..."); |
|
|
|
try { |
|
|
|
try { |
|
|
|
if (targetObject is Type) { |
|
|
|
if (targetObject is Type) { |
|
|
|
returnValue = method.Invoke(null, outputParams); |
|
|
|
return method.Invoke(null, convertedParams); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
returnValue = method.Invoke(targetObject, outputParams); |
|
|
|
return method.Invoke(targetObject, convertedParams); |
|
|
|
} |
|
|
|
} |
|
|
|
} catch (System.Exception exception) { |
|
|
|
} catch (System.Exception exception) { |
|
|
|
throw new Debugger.DebuggerException("Invoke of " + functionName + " failed.", exception); |
|
|
|
throw new Debugger.DebuggerException("Invoke of " + functionName + " failed.", exception); |
|
|
|
} |
|
|
|
} |
|
|
|
TraceMsg ("} \\\\ Invoke"); |
|
|
|
|
|
|
|
return returnValue; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|