using System.IO.Pipes; using System.Diagnostics; using System.Text; using System; using System.Reflection; using System.Runtime.InteropServices; using System.ComponentModel; using Microsoft.Win32; using C4IT.Logging; using System.Threading; using System.Windows; using static C4IT.Logging.cLogManager; using System.Collections.Generic; namespace FasdDesktopUi.Basics { static public class cF4sdPipeClient { static public bool Send(string SendStr, string PipeName, int TimeOut = 1000) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { if (DefaultLogger.IsDebug) { var _msg = new List() { $"send to pipe {PipeName}", SendStr }; DefaultLogger.LogList(LogLevels.Debug, _msg); } NamedPipeClientStream pipeStream = new NamedPipeClientStream (".", PipeName, PipeDirection.Out, PipeOptions.WriteThrough); // The connect function will indefinitely wait for the pipe to become available // If that is not acceptable specify a maximum waiting time (in ms) pipeStream.Connect(TimeOut); byte[] _buffer = Encoding.UTF8.GetBytes(SendStr); pipeStream.Write(_buffer, 0, _buffer.Length); pipeStream.Flush(); pipeStream.Close(); pipeStream.Dispose(); return true; } catch (TimeoutException oEX) { if (cLogManager.DefaultLogger.IsDebug) cLogManager.DefaultLogger.LogException(oEX); } catch { } finally { LogMethodEnd(CM); } return false; } static public void RegisterProtocol(string protocolString, string urlCommand) { try { string codeBase = Assembly.GetExecutingAssembly().CodeBase; var u = new Uri(codeBase); var Path = u.LocalPath; var RegBase = Registry.CurrentUser.OpenSubKey("Software\\Classes", true); var RegHandler = RegBase.CreateSubKey(protocolString.ToUpperInvariant()); RegHandler.SetValue("", $"URL: {protocolString.ToUpperInvariant()} Protocol Handler"); RegHandler.SetValue("URL Protocol", ""); var RegHandler2 = RegHandler.CreateSubKey("DefaultIcon"); RegHandler2.SetValue("", Path); var RegHandler3 = RegHandler.CreateSubKey("shell\\open\\command"); RegHandler3.SetValue("", $"\"{Path}\" {urlCommand.ToLowerInvariant()} \"%1\""); RegHandler = Registry.CurrentUser.CreateSubKey($"SOFTWARE\\Microsoft\\Internet Explorer\\ProtocolExecute\\{protocolString.ToLowerInvariant()}"); RegHandler.SetValue("WarnOnOpen", 0,RegistryValueKind.DWord); } catch { } } } public delegate void DelegateMessage(string Reply); public class cF4sdPipeServer : IDisposable { public event DelegateMessage PipeMessage; string _pipeName; NamedPipeServerStream pipeServer; bool _LowerIntegrity; int _MaxSize; public void Listen(string PipeName, int MaxSize = 255, bool LowerIntegrity = false, int Timeout = 10000) { try { // Set to class level var so we can re-use in the async callback method _pipeName = PipeName; _MaxSize = MaxSize; _LowerIntegrity = LowerIntegrity; if (pipeServer != null ) { try { pipeServer.Close(); pipeServer.Dispose(); pipeServer = null; } catch { } } bool _connected = false; bool _firstTry = true; var _startTime = DateTime.UtcNow; while ((DateTime.UtcNow - _startTime).TotalMilliseconds < Timeout && !_connected) { try { if (!_firstTry) Thread.Sleep(200); _firstTry = false; // Create the new async pipe if (pipeServer == null) pipeServer = new NamedPipeServerStream(PipeName, PipeDirection.In, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous); if (_LowerIntegrity) InterProcessSecurity.SetLowIntegrityLevel(pipeServer.SafePipeHandle); // Wait for a connection var _res = pipeServer.BeginWaitForConnection(new AsyncCallback(WaitForConnectionCallBack), pipeServer); _connected = _res != null; } catch { } } if (!_connected) { cLogManager.DefaultLogger.LogEntry(LogLevels.Error, $"The pipe '{PipeName}' could not be opened in listen mode."); } } catch (Exception oEX) { cLogManager.DefaultLogger.LogException(oEX); } } private void WaitForConnectionCallBack(IAsyncResult iar) { try { // Get the pipe NamedPipeServerStream pipeServer = (NamedPipeServerStream)iar.AsyncState; // End waiting for the connection pipeServer.EndWaitForConnection(iar); byte[] buffer = new byte[_MaxSize]; // Read the incoming message int count = pipeServer.Read(buffer, 0, _MaxSize); // Convert byte buffer to string string stringData = Encoding.UTF8.GetString(buffer, 0, count); // Pass message back to calling form PipeMessage.Invoke(stringData); // Kill original sever and create new wait server pipeServer.Close(); pipeServer = null; pipeServer = new NamedPipeServerStream(_pipeName, PipeDirection.In, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous); if (_LowerIntegrity) InterProcessSecurity.SetLowIntegrityLevel(pipeServer.SafePipeHandle); // Recursively wait for the connection again and again.... pipeServer.BeginWaitForConnection( new AsyncCallback(WaitForConnectionCallBack), pipeServer); } catch { return; } } public void Stop() { if (pipeServer != null) { pipeServer.Close(); pipeServer.Dispose(); pipeServer = null; } } public void Dispose() { Stop(); } } public static class InterProcessSecurity { public const string LOW_INTEGRITY_SSL_SACL = "S:(ML;;NW;;;LW)"; public static int ERROR_SUCCESS = 0x0; public const int LABEL_SECURITY_INFORMATION = 0x00000010; public enum SE_OBJECT_TYPE { SE_UNKNOWN_OBJECT_TYPE = 0, SE_FILE_OBJECT, SE_SERVICE, SE_PRINTER, SE_REGISTRY_KEY, SE_LMSHARE, SE_KERNEL_OBJECT, SE_WINDOW_OBJECT, SE_DS_OBJECT, SE_DS_OBJECT_ALL, SE_PROVIDER_DEFINED_OBJECT, SE_WMIGUID_OBJECT, SE_REGISTRY_WOW64_32KEY } [DllImport("advapi32.dll", EntryPoint = "ConvertStringSecurityDescriptorToSecurityDescriptorW")] [return: MarshalAs(UnmanagedType.Bool)] public static extern Boolean ConvertStringSecurityDescriptorToSecurityDescriptor( [MarshalAs(UnmanagedType.LPWStr)] String strSecurityDescriptor, UInt32 sDRevision, ref IntPtr securityDescriptor, ref UInt32 securityDescriptorSize); [DllImport("kernel32.dll", EntryPoint = "LocalFree")] public static extern UInt32 LocalFree(IntPtr hMem); [DllImport("Advapi32.dll", EntryPoint = "SetSecurityInfo")] public static extern int SetSecurityInfo(SafeHandle hFileMappingObject, SE_OBJECT_TYPE objectType, Int32 securityInfo, IntPtr psidOwner, IntPtr psidGroup, IntPtr pDacl, IntPtr pSacl); [DllImport("advapi32.dll", EntryPoint = "GetSecurityDescriptorSacl")] [return: MarshalAs(UnmanagedType.Bool)] public static extern Boolean GetSecurityDescriptorSacl( IntPtr pSecurityDescriptor, out IntPtr lpbSaclPresent, out IntPtr pSacl, out IntPtr lpbSaclDefaulted); public static void SetLowIntegrityLevel(SafeHandle hObject) { IntPtr pSD = IntPtr.Zero; uint securityDescriptorSize = 0; if (ConvertStringSecurityDescriptorToSecurityDescriptor(LOW_INTEGRITY_SSL_SACL, 1, ref pSD, ref securityDescriptorSize)) { try { if (GetSecurityDescriptorSacl(pSD, out IntPtr lpbSaclPresent, out IntPtr pSacl, out IntPtr lpbSaclDefaulted)) { var err = SetSecurityInfo(hObject, SE_OBJECT_TYPE.SE_KERNEL_OBJECT, LABEL_SECURITY_INFORMATION, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, pSacl); if (err != ERROR_SUCCESS) { throw new Win32Exception(err); } } } finally { LocalFree(pSD); } } } } }