⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mta2sta.cs

📁 SharpDevelop2.0.0 c#开发免费工具
💻 CS
字号:
// <file>
//     <copyright see="prj:///doc/copyright.txt"/>
//     <license see="prj:///doc/license.txt"/>
//     <owner name="David Srbecký" email="dsrbecky@gmail.com"/>
//     <version>$Revision: 930 $</version>
// </file>

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;

namespace Debugger
{
	public delegate T MethodInvokerWithReturnValue<T>();
	
	public enum CallMethod {DirectCall, Manual, HiddenForm, HiddenFormWithTimeout};
	
	public class MTA2STA
	{
		Form hiddenForm;
		IntPtr hiddenFormHandle;
		
		System.Threading.Thread targetThread;
		CallMethod callMethod = CallMethod.HiddenFormWithTimeout;
		
		Queue<MethodInvoker> pendingCalls = new Queue<MethodInvoker>();
		ManualResetEvent pendingCallsNotEmpty = new ManualResetEvent(false);
		
		WaitHandle EnqueueCall(MethodInvoker callDelegate)
		{
			lock (pendingCalls) {
				ManualResetEvent callDone = new ManualResetEvent(false);
				pendingCalls.Enqueue(delegate{
				                     	callDelegate();
				                     	callDone.Set();
				                     });
				pendingCallsNotEmpty.Set();
				return callDone;
			}
		}
		
		void PerformAllCalls()
		{
			lock (pendingCalls) {
				while (pendingCalls.Count > 0) {
					pendingCalls.Dequeue()();
				}
				pendingCallsNotEmpty.Reset();
			}
		}
		
		public CallMethod CallMethod {
			get {
				return callMethod;
			}
			set {
				callMethod = value;
			}
		}
		
		public MTA2STA()
		{
			targetThread = System.Threading.Thread.CurrentThread;
			
			hiddenForm = new Form();
			// Force handle creation
			hiddenFormHandle = hiddenForm.Handle;
		}
		
		/// <summary>
		/// SoftWait waits for any of the given WaitHandles and allows processing of calls during the wait
		/// </summary>
		public int SoftWait(params WaitHandle[] waitFor)
		{
			List<WaitHandle> waits = new List<WaitHandle> (waitFor);
			waits.Add(pendingCallsNotEmpty);
			while(true) {
				int i = WaitHandle.WaitAny(waits.ToArray());
				PerformAllCalls();
				if (i < waits.Count - 1) { // If not pendingCallsNotEmpty
					return i;
				}
			}
		}
		
		/// <summary>
		/// Performs all waiting calls on the current thread
		/// </summary>
		public void Pulse()
		{
			PerformAllCalls();
		}
		
		/// <summary>
		/// Schedules invocation of method and returns immediately
		/// </summary>
		public WaitHandle AsyncCall(MethodInvoker callDelegate)
		{
			WaitHandle callDone = EnqueueCall(callDelegate);
			TriggerInvoke();
			return callDone;
		}
		
		public T Call<T>(MethodInvokerWithReturnValue<T> callDelegate)
		{
			T returnValue = default(T);
			Call(delegate { returnValue = callDelegate(); }, true);
			return returnValue;
		}
		
		public void Call(MethodInvoker callDelegate)
		{
			Call(callDelegate, false);
		}
		
		void Call(MethodInvoker callDelegate, bool hasReturnValue)
		{
			// Enqueue the call
			WaitHandle callDone = EnqueueCall(callDelegate);
			
			if (targetThread == System.Threading.Thread.CurrentThread) {
				PerformAllCalls();
				return;
			}
			
			// We have the call waiting in queue, we need to call it (not waiting for it to finish)
			TriggerInvoke();
			
			// Wait for the call to finish
			if (!hasReturnValue && callMethod == CallMethod.HiddenFormWithTimeout) {
				// Give it 5 seconds to run
				if (!callDone.WaitOne(5000, true)) {
					System.Console.WriteLine("Call time out! Continuing...");
				}
			} else {
				callDone.WaitOne();
			}
		}
		
		void TriggerInvoke()
		{
			switch (callMethod) {
				case CallMethod.DirectCall:
					PerformAllCalls();
					break;
				case CallMethod.Manual:
					// Nothing we can do - someone else must call SoftWait or Pulse
					break;
				case CallMethod.HiddenForm:
				case CallMethod.HiddenFormWithTimeout:
					hiddenForm.BeginInvoke((MethodInvoker)PerformAllCalls);
					break;
			}
		}
		
		public static object MarshalParamTo(object param, Type outputType)
		{
			if (param is IntPtr) {
				return MarshalIntPtrTo((IntPtr)param, outputType);
			} else {
				return param;
			}
		}
		
		public static T MarshalIntPtrTo<T>(IntPtr param)
		{
			return (T)MarshalIntPtrTo(param, typeof(T));
		}
		
		public static object MarshalIntPtrTo(IntPtr param, Type outputType)
		{
			// 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
			object comObject = Marshal.GetObjectForIUnknown(param);
			return Activator.CreateInstance(outputType, comObject);
		}
		
		/// <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;
			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);
			}
			
			try {
				if (targetObject is Type) {
					return method.Invoke(null, convertedParams);
				} else {
					return method.Invoke(targetObject, convertedParams);
				}
			} catch (System.Exception exception) {
				throw new Debugger.DebuggerException("Invoke of " + functionName + " failed.", exception);
			}
		}
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -