private static void CreateProcess( string lpApplicationName, string lpCommandLine, bool bInheritHandles, uint dwCreationFlags, ref Syscalls.STARTUPINFO lpStartupInfo, out Syscalls.PROCESS_INFORMATION lpProcessInformation) { int retval; retval = Syscalls._CreateProcess( lpApplicationName, lpCommandLine, new IntPtr(0), new IntPtr(0), bInheritHandles, dwCreationFlags, new IntPtr(0), null, ref lpStartupInfo, out lpProcessInformation); if (retval == 0) { int errcode = Marshal.GetLastWin32Error(); throw new Exception("Cannot create process (" + errcode + ": " + Syscalls.GetLastErrorStringMessage() + ")"); } }
/// <summary> /// Handles when a Start Ticket is received. /// </summary> /// <param name="_context"></param> private void OnStartTicketResponse(KasQuery ctx) { Debug.Assert(m_state == AppSharingState.StartTicket); AnpMsg cmd = ctx.Cmd; AnpMsg res = ctx.Res; if (m_state != AppSharingState.StartTicket) { Logging.Log(2, "Received spurious Screen Sharing Start ticket."); return; } if (res.Type == KAnpType.KANP_RES_VNC_START_TICKET) { m_ticket = res.Elements[0].Bin; /* Start MetaVNC (specify the desired window's handle)*/ int handle = Int32.Parse((String)ctx.MetaData[0]); bool supportSession = (bool)ctx.MetaData[2]; String vncServerPath = "\"" + Base.GetKwmInstallationPath() + @"vnc\kappserver.exe" + "\""; String args = (handle == 0) ? " -shareall" : " -sharehwnd " + (String)ctx.MetaData[0]; // If a window is being shared (not the desktop), set // it visible and in foreground. if (handle != 0) { IntPtr hWnd = new IntPtr(handle); if (Syscalls.IsIconic(hWnd)) Syscalls.ShowWindowAsync(hWnd, (int)Syscalls.WindowStatus.SW_RESTORE); Base.KSetForegroundWindow(hWnd); } /* Remove any indication of previous server's listening port */ RegistryKey port = Base.GetKwmCURegKey(); port.DeleteValue(m_portRegItem, false); port.DeleteValue(m_portRegItemWritten, false); port.Close(); // Set registry options in order to allow/deny // remote control. SetSupportSessionMode(supportSession); Logging.Log("Starting the first instance of MetaVNC (no args)."); m_serverProcess = new RawProcess(vncServerPath); m_serverProcess.CreationFlags = (uint)Syscalls.CREATION_FLAGS.CREATE_NO_WINDOW; m_serverProcess.InheritHandles = false; Syscalls.STARTUPINFO si = new Syscalls.STARTUPINFO(); si.dwFlags = 1; m_serverProcess.StartupInfo = si; m_serverProcess.ProcessEnd += HandleOnProcessEnd; m_serverProcess.Start(); Logging.Log("Started."); /* Wait until we can get our hands on the process's window handle */ int retries = 15; bool found = false; while (retries > 0) { Logging.Log("Trying to start WinVNC ( " + retries + ")"); IntPtr serverHandle = Syscalls.FindWindow("WinVNC Tray Icon", 0); if (serverHandle != IntPtr.Zero) { found = true; break; } System.Threading.Thread.Sleep(250); retries--; } if (!found) throw new Exception("Screen sharing error: server could not be started."); /* Start another process of metaVNC. * This is needed to pass the window handle * we want, it was easier to do this that way * than to pass it directly on the cmd line when * starting the process the first time. */ Logging.Log("Starting MetaVNC for the second time (this is normal): " + vncServerPath + args); m_dummyServerProcess = new RawProcess(vncServerPath + args); m_dummyServerProcess.CreationFlags = (uint)Syscalls.CREATION_FLAGS.CREATE_NO_WINDOW; m_dummyServerProcess.InheritHandles = false; m_dummyServerProcess.StartupInfo = si; m_dummyServerProcess.ProcessEnd += HandleOnProcessEnd; m_dummyServerProcess.Start(); // Find out on which port we need to tell ktlstunnel to // connect to the server RegistryKey kwmKey = Base.GetKwmCURegKey(); object readPort = null; object portOK = null; // Actively poll the synchronization key for 6 seconds. retries = 30; found = false; while (retries > 0) { portOK = kwmKey.GetValue(m_portRegItemWritten); if (portOK != null) { found = true; break; } System.Threading.Thread.Sleep(200); retries--; } if (!found) { if (kwmKey != null) kwmKey.Close(); ResetToIdle(); Misc.KwmTellUser("Screen sharing error: a timeout occured while waiting for the server's listening port."); return; } // At this stage we can presume the port was // correctly really written by the VNC server. readPort = kwmKey.GetValue(m_portRegItem); kwmKey.Close(); if (port == null) { ResetToIdle(); Misc.KwmTellUser("Screen sharing error: unable to read the server's listening port."); return; } Logging.Log("Screen Sharing server's port: " + (int)readPort); /* Connect a new tunnel */ m_tunnel = Helper.CreateTunnel(); m_tunnel.Connect("localhost", (int)readPort); /* Negociate role */ AnpMsg inMsg = Helper.NewKAnpMsg(KAnpType.KANP_CMD_MGT_SELECT_ROLE); inMsg.AddUInt32(KAnpType.KANP_KCD_ROLE_APP_SHARE); m_tunnel.SendMsg(inMsg); AnpMsg outMsg = m_tunnel.GetMsg(); if (outMsg.Type == KAnpType.KANP_RES_FAIL) { ResetToIdle(); Misc.KwmTellUser(outMsg.Elements[1].String); return; } Debug.Assert(outMsg.Type == KAnpType.KANP_RES_OK); AnpMsg startSession = Helper.NewKAnpMsg(KAnpType.KANP_CMD_VNC_START_SESSION); startSession.AddBin(m_ticket); startSession.AddString((String)ctx.MetaData[1]); m_tunnel.SendMsg(startSession); outMsg = m_tunnel.GetMsg(); if (outMsg.Type == KAnpType.KANP_RES_FAIL) { ResetToIdle(); Misc.KwmTellUser(outMsg.Elements[1].String); return; } Debug.Assert(outMsg.Type == KAnpType.KANP_RES_VNC_START_SESSION); m_createdSessionID = outMsg.Elements[0].UInt64; /* Disconnect tunnel so it can connect to metaVNC server */ Logging.Log("About to call disconnect on ktlstunnel."); m_tunnel.Disconnect(); CurrentState = AppSharingState.Started; m_connectedSessionID = 0; StopInactivityMonitor(); // 10 minutes inactivityMonitor = MonitorCreator.CreateInstance(MonitorType.GlobalHookMonitor); inactivityMonitor.Interval = 600000; inactivityMonitor.Elapsed += new ElapsedEventHandler(HandleSessionTimeout); inactivityMonitor.Enabled = true; } else if (res.Type == KAnpType.KANP_RES_FAIL) { ResetToIdle(); Misc.KwmTellUser(res.Elements[1].String); } else { Logging.Log(2, "unexpected response in OnStartTicketResponse"); } }