C# port of the TCUtils Library

English support forum

Moderators: white, Hacker, petermad, Stefan2

Post Reply
serby
New Member
New Member
Posts: 1
Joined: 2018-09-14, 19:29 UTC

C# port of the TCUtils Library

Post by *serby »

Code: Select all

using System;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;

namespace TCU {
	static class TCUtils {
		/*
		Sends a user command to Total Commander.
			Parameters:
				userCommand - Name of user command to send.
				sourceWindow - Name of the window from which the command is send.
		*/
		public static int sendUserCommand(string userCommand, IntPtr sourceWindow) {
			IntPtr targetWindow = NativeMethod.FindWindow("TTOTAL_CMD", null);
			if(targetWindow != IntPtr.Zero) {
				byte[] bcUserCommand = ASCIIEncoding.ASCII.GetBytes(userCommand);
				byte[] fpUserCommand = new byte[bcUserCommand.Length + 1];
				bcUserCommand.CopyTo(fpUserCommand, 0);
				fpUserCommand[bcUserCommand.Length] = 0;
				IntPtr marshaledUserCommand = Marshal.AllocHGlobal(fpUserCommand.Length);
				try {
					Marshal.Copy(fpUserCommand, 0, marshaledUserCommand, fpUserCommand.Length);
					COPYDATASTRUCT copyStruct = new COPYDATASTRUCT();
					copyStruct.dwData = new IntPtr((byte)'E' + 256 * (byte)'M');
					copyStruct.cbData = fpUserCommand.Length;
					copyStruct.lpData = marshaledUserCommand;
					NativeMethod.SendMessage(targetWindow, WM_COPYDATA, sourceWindow, ref copyStruct);
					int result = Marshal.GetLastWin32Error();
					if(result != 0) {
						return result;
					}
				} finally {
					Marshal.FreeHGlobal(marshaledUserCommand);
				}
				return 0;
			}
			return -1;
		}

		/* 
		Change one or both directories in Total Commander.
			Parameters:
				firstPath - Name of the first directory to change. Meaning depends on the flags parameter. Can be NULL.
				secondPath - Name of the second directory to change. Meaning depends on the flags parameter.  Can be NULL.
				flags - Can be "S", "T", "ST" or NULL. 
				S makes firstPath the source panel and secondPath the target panel otherwise firstPath is the left panel and   secondPath is the left panel.
				T opens the directory in a new tab. Otherwise the directory is changed in the current tab.
				sourceWindow - Name of the window from which the command is send.
		*/
		public static void sendChangeDirectory(string firstPath, string secondPath, string flags, IntPtr sourceWindow) {
			IntPtr targetWindow = NativeMethod.FindWindow("TTOTAL_CMD", null);
			if(targetWindow == IntPtr.Zero) {
				return;
			}

			StringBuilder commandLine = new StringBuilder();
			// One path is mandatory.
			if(string.IsNullOrEmpty(firstPath) && string.IsNullOrEmpty(secondPath)) {
				return;
			}
			// First or second path or both can be entered separated by carriage return.
			if(!string.IsNullOrEmpty(firstPath)) {
				commandLine.Append(firstPath);
			}
			commandLine.Append("\r");
			if(!string.IsNullOrEmpty(secondPath)) {
				commandLine.Append(secondPath);
			}
			byte[] bcCommandLine = ASCIIEncoding.ASCII.GetBytes(commandLine.ToString());
			byte[] bcFlags = ASCIIEncoding.ASCII.GetBytes(flags);
			byte[] fpCommandLine = new byte[bcCommandLine.Length + 1 + ( string.IsNullOrEmpty(flags) ? 0 : flags.Length + 1 )];
			bcCommandLine.CopyTo(fpCommandLine, 0);
			fpCommandLine[bcCommandLine.Length] = 0;
			if(!string.IsNullOrEmpty(flags)) {
				bcFlags.CopyTo(fpCommandLine, bcCommandLine.Length + 1);
				fpCommandLine[fpCommandLine.Length - 1] = 0;
			}
			IntPtr marshaledCommandLine = Marshal.AllocHGlobal(fpCommandLine.Length);
			try {
				Marshal.Copy(fpCommandLine, 0, marshaledCommandLine, fpCommandLine.Length);
				COPYDATASTRUCT copyStruct = new COPYDATASTRUCT(); ;
				copyStruct.dwData = new IntPtr((byte)'C' + 0x100 * (byte)'D');
				copyStruct.cbData = fpCommandLine.Length;
				copyStruct.lpData = marshaledCommandLine;
				NativeMethod.SendMessage(targetWindow, WM_COPYDATA, sourceWindow, ref copyStruct);
			} finally {
				Marshal.FreeHGlobal(marshaledCommandLine);
			}
		}
			   		 
		#region Native API Signatures and Types
		internal const int WM_COPYDATA = 0x004A;

		[StructLayout(LayoutKind.Sequential)]
		internal struct COPYDATASTRUCT {
			public IntPtr dwData;       // Specifies data to be passed
			public int cbData;          // Specifies the data size in bytes
			public IntPtr lpData;       // Pointer to data to be passed
		}
		
		[SuppressUnmanagedCodeSecurity]
		internal class NativeMethod {
			[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
			public static extern IntPtr SendMessage(IntPtr hWnd, int Msg,
				IntPtr wParam, ref COPYDATASTRUCT lParam);


			[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
			public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
		}
		#endregion
	}
}
User avatar
MVV
Power Member
Power Member
Posts: 8702
Joined: 2008-08-03, 12:51 UTC
Location: Russian Federation

Re: C# port of the TCUtils Library

Post by *MVV »

You should add Unicode support for CD command, last TC versions understand paths in UTF-8.
History.txt wrote:09.12.07 Added: Unicode support in WM_COPYDATA: prepend UTF8 byte order mark before each path containing Unicode characters (pure ANSI paths are passed as ANSI) -> /O switch now supports Unicode too
Post Reply