Decompiled source of AutoHotkeyInterop v1.0.0

AutoHotkey.Interop.dll

Decompiled 9 months ago
using System;
using System.Diagnostics;
using System.IO;
using System.IO.Pipes;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using AutoHotkey.Interop.Pipes;
using AutoHotkey.Interop.Util;
using Microsoft.Win32.SafeHandles;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("AutoHotkey.Interop")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("AutoHotkey.Interop")]
[assembly: AssemblyCopyright("Copyright ©  2014")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("8a7cbbfe-ccb2-42ef-b90f-d937ae6ed741")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: InternalsVisibleTo("AutoHotkey.Interop.Tests")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace AutoHotkey.Interop
{
	internal class AhkEscape
	{
		public static string Quote(string msg)
		{
			if (msg == null)
			{
				throw new ArgumentNullException("msg");
			}
			if (msg.StartsWith("\"") && msg.EndsWith("\""))
			{
				msg = msg.Remove(0, 1);
				msg = msg.Remove(msg.Length - 1, 1);
				msg = "\"" + Escape(msg) + "\"";
			}
			else
			{
				msg = "\"" + Escape(msg) + "\"";
			}
			return msg;
		}

		public static string Escape(string msg)
		{
			if (msg == null)
			{
				throw new ArgumentNullException("msg");
			}
			return msg.Replace("`", "``").Replace("\r", "`r").Replace("\n", "`n")
				.Replace("\t", "`t")
				.Replace("\"", "\"\"");
		}
	}
	internal static class AutoHotkeyDll
	{
		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct Execute
		{
			public const byte Add = 0;

			public const byte Run = 1;

			public const byte RunWait = 2;
		}

		private const string DLLPATH = "AutoHotkey.dll";

		[DllImport("AutoHotkey.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
		public static extern uint ahkdll([MarshalAs(UnmanagedType.LPWStr)] string Path, [MarshalAs(UnmanagedType.LPWStr)] string Options, [MarshalAs(UnmanagedType.LPWStr)] string Parameters);

		[DllImport("AutoHotkey.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
		public static extern uint ahktextdll([MarshalAs(UnmanagedType.LPWStr)] string Code, [MarshalAs(UnmanagedType.LPWStr)] string Options, [MarshalAs(UnmanagedType.LPWStr)] string Parameters);

		[DllImport("AutoHotkey.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
		public static extern bool ahkReady();

		[DllImport("AutoHotkey.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
		public static extern void ahkTerminate(uint timeout);

		[DllImport("AutoHotkey.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
		public static extern void ahkReload();

		[DllImport("AutoHotkey.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
		public static extern void ahkPause([MarshalAs(UnmanagedType.LPWStr)] string strState);

		[DllImport("AutoHotkey.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
		public static extern uint addFile([MarshalAs(UnmanagedType.LPWStr)] string FilePath, byte AllowDuplicateInclude, byte IgnoreLoadFailure);

		[DllImport("AutoHotkey.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
		public static extern uint addScript([MarshalAs(UnmanagedType.LPWStr)] string code, byte execute);

		[DllImport("AutoHotkey.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
		public static extern bool ahkExec([MarshalAs(UnmanagedType.LPWStr)] string code);

		[DllImport("AutoHotkey.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
		public static extern bool ahkLabel([MarshalAs(UnmanagedType.LPWStr)] string labelName, bool noWait);

		[DllImport("AutoHotkey.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
		public static extern IntPtr ahkFunction([MarshalAs(UnmanagedType.LPWStr)] string functionName, [MarshalAs(UnmanagedType.LPWStr)] string parameter1, [MarshalAs(UnmanagedType.LPWStr)] string parameter2, [MarshalAs(UnmanagedType.LPWStr)] string parameter3, [MarshalAs(UnmanagedType.LPWStr)] string parameter4, [MarshalAs(UnmanagedType.LPWStr)] string parameter5, [MarshalAs(UnmanagedType.LPWStr)] string parameter6, [MarshalAs(UnmanagedType.LPWStr)] string parameter7, [MarshalAs(UnmanagedType.LPWStr)] string parameter8, [MarshalAs(UnmanagedType.LPWStr)] string parameter9, [MarshalAs(UnmanagedType.LPWStr)] string parameter10);

		[DllImport("AutoHotkey.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
		public static extern bool ahkPostFunction([MarshalAs(UnmanagedType.LPWStr)] string functionName, [MarshalAs(UnmanagedType.LPWStr)] string Parameters);

		[DllImport("AutoHotkey.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
		public static extern bool ahkassign([MarshalAs(UnmanagedType.LPWStr)] string VariableName, [MarshalAs(UnmanagedType.LPWStr)] string NewValue);

		[DllImport("AutoHotkey.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
		public static extern IntPtr ahkgetvar([MarshalAs(UnmanagedType.LPWStr)] string VariableName, [MarshalAs(UnmanagedType.I4)] int GetPointer);

		[DllImport("AutoHotkey.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
		public static extern IntPtr ahkFindFunc([MarshalAs(UnmanagedType.LPWStr)] string FuncName);

		[DllImport("AutoHotkey.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
		public static extern IntPtr ahkFindLabel([MarshalAs(UnmanagedType.LPWStr)] string LabelName);

		[DllImport("AutoHotkey.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode, EntryPoint = "getVar")]
		public static extern IntPtr GetVar([MarshalAs(UnmanagedType.LPWStr)] string Variable);
	}
	public class AutoHotkeyEngine
	{
		private static Lazy<AutoHotkeyEngine> lazyInstance = new Lazy<AutoHotkeyEngine>(() => new AutoHotkeyEngine());

		public static AutoHotkeyEngine Instance => lazyInstance.Value;

		private AutoHotkeyEngine()
		{
			AutoHotkeyDllLoader.EnsureDllIsLoaded();
			AutoHotkeyDll.ahktextdll("", "", "");
		}

		public string GetVar(string variableName)
		{
			IntPtr ptr = AutoHotkeyDll.ahkgetvar(variableName, 0);
			return Marshal.PtrToStringUni(ptr);
		}

		public void SetVar(string variableName, string value)
		{
			if (value == null)
			{
				value = "";
			}
			AutoHotkeyDll.ahkassign(variableName, value);
		}

		public string Eval(string code)
		{
			string code2 = "A__EVAL:=" + code;
			AutoHotkeyDll.ahkExec(code2);
			return GetVar("A__EVAL");
		}

		public void LoadFile(string filePath)
		{
			string fullPath = Path.GetFullPath(filePath);
			string scriptText = File.ReadAllText(filePath);
			LoadScript(scriptText);
		}

		public void LoadScript(string scriptText)
		{
			AutoHotkeyDll.addScript(scriptText, 2);
		}

		public void ExecRaw(string code)
		{
			AutoHotkeyDll.ahkExec(code);
		}

		public void Terminate()
		{
			AutoHotkeyDll.ahkTerminate(1000u);
		}

		public void Reset()
		{
			Terminate();
			AutoHotkeyDll.ahkReload();
			AutoHotkeyDll.ahktextdll("", "", "");
		}

		public void Suspend()
		{
			ExecRaw("Suspend, On");
		}

		public void UnSuspend()
		{
			ExecRaw("Suspend, Off");
		}

		public string ExecFunction(string functionName, string param1 = null, string param2 = null, string param3 = null, string param4 = null, string param5 = null, string param6 = null, string param7 = null, string param8 = null, string param9 = null, string param10 = null)
		{
			IntPtr intPtr = AutoHotkeyDll.ahkFunction(functionName, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10);
			if (intPtr == IntPtr.Zero)
			{
				return null;
			}
			return Marshal.PtrToStringUni(intPtr);
		}

		public bool FunctionExists(string functionName)
		{
			IntPtr intPtr = AutoHotkeyDll.ahkFindFunc(functionName);
			return intPtr != IntPtr.Zero;
		}

		public void ExecLabel(string labelName)
		{
			AutoHotkeyDll.ahkLabel(labelName, noWait: false);
		}

		public bool LabelExists(string labelName)
		{
			IntPtr intPtr = AutoHotkeyDll.ahkFindLabel(labelName);
			return intPtr != IntPtr.Zero;
		}

		public void InitalizePipesModule(Func<string, string> sendPipeMessageHandler)
		{
			PipesModuleLoader.LoadPipesModule(sendPipeMessageHandler);
		}
	}
	[SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
	internal sealed class SafeLibraryHandle : SafeHandleZeroOrMinusOneIsInvalid
	{
		[DllImport("kernel32.dll", SetLastError = true)]
		public static extern SafeLibraryHandle LoadLibrary(string lpFileName);

		[DllImport("kernel32.dll", SetLastError = true)]
		[SuppressUnmanagedCodeSecurity]
		[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
		private static extern bool FreeLibrary(IntPtr hModule);

		private SafeLibraryHandle()
			: base(ownsHandle: true)
		{
		}

		protected override bool ReleaseHandle()
		{
			return FreeLibrary(handle);
		}

		protected override void Dispose(bool disposing)
		{
			base.Dispose(disposing);
		}
	}
}
namespace AutoHotkey.Interop.Util
{
	internal static class AutoHotkeyDllLoader
	{
		private static readonly Lazy<SafeLibraryHandle> dllHandle = new Lazy<SafeLibraryHandle>(LoadDll);

		internal static void EnsureDllIsLoaded()
		{
			if (!dllHandle.IsValueCreated)
			{
				SafeLibraryHandle value = dllHandle.Value;
			}
		}

		private static SafeLibraryHandle LoadDll()
		{
			string text = (ProcessorType.Is32Bit() ? "x86" : "x64");
			string text2 = text + "/AutoHotkey.dll";
			if (File.Exists(text2))
			{
				return SafeLibraryHandle.LoadLibrary(text2);
			}
			return ExtractAndLoadEmbededResource(text2);
		}

		private static SafeLibraryHandle ExtractAndLoadEmbededResource(string relativePath)
		{
			Assembly assembly = typeof(AutoHotkeyEngine).Assembly;
			string text = EmbededResourceHelper.FindByName(assembly, relativePath);
			if (text != null)
			{
				string tempFolderPath = GetTempFolderPath();
				string text2 = Path.Combine(tempFolderPath, relativePath);
				EmbededResourceHelper.ExtractToFile(assembly, text, text2);
				return SafeLibraryHandle.LoadLibrary(text2);
			}
			return null;
		}

		private static string GetTempFolderPath()
		{
			string tempPath = Path.GetTempPath();
			string path = "AutoHotkey.Interop";
			string path2 = typeof(AutoHotkeyEngine).Assembly.GetName().Version.ToString();
			return Path.Combine(tempPath, path, path2);
		}
	}
	internal static class EmbededResourceHelper
	{
		public static string FindByName(Assembly assembly, string path)
		{
			path = Regex.Replace(path, "[/\\\\]", ".");
			string value = (path.StartsWith(".") ? path : ("." + path));
			string[] manifestResourceNames = assembly.GetManifestResourceNames();
			string[] array = manifestResourceNames;
			foreach (string text in array)
			{
				if (text.EndsWith(value, StringComparison.InvariantCultureIgnoreCase))
				{
					return text;
				}
				if (text.Equals(path, StringComparison.InvariantCultureIgnoreCase))
				{
					return text;
				}
			}
			return null;
		}

		public static void ExtractToFile(Assembly assembly, string embededResourceName, string outputFilePath)
		{
			if (File.Exists(outputFilePath))
			{
				return;
			}
			string text = FindByName(assembly, embededResourceName);
			if (text == null)
			{
				throw new FileNotFoundException($"Cannot find resource name of '{embededResourceName}' in assembly '{assembly.GetName().Name}'", embededResourceName);
			}
			EnsureDirectoryExistsForFile(outputFilePath);
			using Stream stream = assembly.GetManifestResourceStream(text);
			using FileStream destination = File.Open(outputFilePath, FileMode.Create);
			stream.CopyTo(destination);
			stream.Flush();
		}

		public static string ExtractToText(Assembly assembly, string embededResourceName)
		{
			string text = FindByName(assembly, embededResourceName);
			if (text == null)
			{
				throw new FileNotFoundException($"Cannot find resource name of '{embededResourceName}' in assembly '{assembly.GetName().Name}'", embededResourceName);
			}
			using Stream stream = assembly.GetManifestResourceStream(text);
			using StreamReader streamReader = new StreamReader(stream);
			return streamReader.ReadToEnd();
		}

		private static void EnsureDirectoryExistsForFile(string targetFileName)
		{
			string fullPath = Path.GetFullPath(targetFileName);
			string directoryName = Path.GetDirectoryName(fullPath);
			if (!Directory.Exists(directoryName))
			{
				Directory.CreateDirectory(directoryName);
			}
		}
	}
	internal static class ProcessorType
	{
		public static bool Is64Bit()
		{
			return IntPtr.Size == 8;
		}

		public static bool Is32Bit()
		{
			return IntPtr.Size == 4;
		}
	}
}
namespace AutoHotkey.Interop.Pipes
{
	internal class MessageHandlerPipeServer : NamedPipeServer
	{
		private Func<string, string> messageHandler = null;

		public MessageHandlerPipeServer(string pipeName, Func<string, string> messageHandler)
			: base(pipeName)
		{
			if (pipeName == null)
			{
				throw new ArgumentNullException("pipeName");
			}
			if (messageHandler == null)
			{
				throw new ArgumentNullException("messageHandler");
			}
			this.messageHandler = messageHandler;
		}

		protected override string HandleClientMessage(string clientMessage)
		{
			return messageHandler(clientMessage);
		}
	}
	internal abstract class NamedPipeServer
	{
		private readonly string pipeName;

		private volatile NamedPipeServerStream serverStream;

		public bool IsClientConnected
		{
			get
			{
				if (serverStream == null)
				{
					return false;
				}
				return serverStream.IsConnected;
			}
		}

		public NamedPipeServer(string pipeName)
		{
			this.pipeName = pipeName;
		}

		public void Start()
		{
			serverStream = MakeNamedPipeServerStream(pipeName);
			serverStream.BeginWaitForConnection(DoConnectionLoop, null);
		}

		private async void DoConnectionLoop(IAsyncResult result)
		{
			if (!result.IsCompleted || serverStream == null)
			{
				return;
			}
			try
			{
				serverStream.EndWaitForConnection(result);
			}
			catch (IOException)
			{
				RebuildNamedPipe();
				return;
			}
			catch (ObjectDisposedException)
			{
				RebuildNamedPipe();
				return;
			}
			catch (OperationCanceledException)
			{
				RebuildNamedPipe();
				return;
			}
			while (IsClientConnected && serverStream != null)
			{
				string clientMessage;
				try
				{
					clientMessage = await ReadClientMessage(serverStream);
				}
				catch (IOException)
				{
					RebuildNamedPipe();
					return;
				}
				catch (ObjectDisposedException)
				{
					RebuildNamedPipe();
					return;
				}
				catch (OperationCanceledException)
				{
					RebuildNamedPipe();
					return;
				}
				string serverResponce = HandleClientMessage(clientMessage);
				if (serverStream == null)
				{
					break;
				}
				try
				{
					await SendResponceToClient(serverStream, serverResponce);
				}
				catch (IOException)
				{
					RebuildNamedPipe();
					return;
				}
				catch (ObjectDisposedException)
				{
					RebuildNamedPipe();
					return;
				}
				catch (OperationCanceledException)
				{
					RebuildNamedPipe();
					return;
				}
			}
			if (serverStream != null)
			{
				serverStream.BeginWaitForConnection(DoConnectionLoop, null);
			}
		}

		private void RebuildNamedPipe()
		{
			Shutdown();
			serverStream = MakeNamedPipeServerStream(pipeName);
			serverStream.BeginWaitForConnection(DoConnectionLoop, null);
		}

		protected abstract string HandleClientMessage(string clientMessage);

		private static async Task SendResponceToClient(NamedPipeServerStream stream, string serverResponce)
		{
			byte[] responceData = Encoding.Unicode.GetBytes(serverResponce);
			await stream.WriteAsync(responceData, 0, responceData.Length);
			await stream.FlushAsync();
			stream.WaitForPipeDrain();
		}

		private static async Task<string> ReadClientMessage(NamedPipeServerStream stream)
		{
			byte[] buffer = new byte[65535];
			int read = await stream.ReadAsync(buffer, 0, buffer.Length);
			return Encoding.Unicode.GetString(buffer, 0, read);
		}

		public void Shutdown()
		{
			if (serverStream != null)
			{
				try
				{
					serverStream.Close();
				}
				catch
				{
				}
				try
				{
					serverStream.Dispose();
				}
				catch
				{
				}
				serverStream = null;
			}
		}

		private NamedPipeServerStream MakeNamedPipeServerStream(string pipeName)
		{
			return new NamedPipeServerStream(pipeName, PipeDirection.InOut, -1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
		}
	}
	public static class PipesModuleLoader
	{
		public static object lockObj = new object();

		internal static MessageHandlerPipeServer Server { get; private set; }

		public static void LoadPipesModule(Func<string, string> messageHandler)
		{
			lock (lockObj)
			{
				string pipename = GeneratePipeName();
				InitPipeServer(pipename, messageHandler);
				InitPipeClient(pipename);
			}
		}

		private static void InitPipeClient(string pipename)
		{
			if (!AutoHotkeyEngine.Instance.FunctionExists("pipeclient_getversion"))
			{
				string scriptText = EmbededResourceHelper.ExtractToText(typeof(PipesModuleLoader).Assembly, "Pipes/pipeclient.ahk");
				AutoHotkeyEngine.Instance.LoadScript(scriptText);
			}
			else
			{
				AutoHotkeyEngine.Instance.LoadScript("A__PIPECLIENT.close()");
			}
			AutoHotkeyEngine.Instance.LoadScript($"A__PIPECLIENT := new pipeclient({AhkEscape.Quote(pipename)})");
		}

		private static void InitPipeServer(string pipename, Func<string, string> messageHandler)
		{
			if (Server != null)
			{
				Server.Shutdown();
			}
			Server = new MessageHandlerPipeServer(pipename, messageHandler);
			Server.Start();
		}

		private static string GeneratePipeName()
		{
			return "AHK-PIPE-" + Guid.NewGuid().ToString().Replace("-", "");
		}
	}
}