CLI tool for running Playbooks
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3340 lines
151 KiB

6 months ago
  1. using System.Text;
  2. using System.Threading;
  3. using System.Runtime.InteropServices;
  4. using System.ComponentModel;
  5. using System.ComponentModel.Design;
  6. using System.Runtime.CompilerServices;
  7. using System.Diagnostics;
  8. using System;
  9. using System.Collections;
  10. using System.Collections.Generic;
  11. using System.IO;
  12. using Microsoft.Win32.SafeHandles;
  13. using System.Collections.Specialized;
  14. using System.Globalization;
  15. using System.Security;
  16. using System.Security.Permissions;
  17. using System.Runtime.Versioning;
  18. using System.Runtime.ConstrainedExecution;
  19. using Microsoft.Win32;
  20. namespace TrustedUninstaller.Shared
  21. {
  22. [DefaultEvent("Exited"), DefaultProperty("StartInfo"), HostProtection(SharedState = true, Synchronization = true, ExternalProcessMgmt = true, SelfAffectingProcessMgmt = true)]
  23. public static class AugmentedProcess
  24. {
  25. public class Process : Component
  26. {
  27. public enum CreateType {
  28. UserToken,
  29. RawToken
  30. }
  31. //
  32. // FIELDS
  33. //
  34. bool haveProcessId;
  35. int processId;
  36. bool haveProcessHandle;
  37. SafeProcessHandle m_processHandle;
  38. bool isRemoteMachine;
  39. string machineName;
  40. ProcessInfo processInfo;
  41. Int32 m_processAccess;
  42. ProcessThreadCollection threads;
  43. ProcessModuleCollection modules;
  44. bool haveMainWindow;
  45. IntPtr mainWindowHandle; // no need to use SafeHandle for window
  46. string mainWindowTitle;
  47. bool haveWorkingSetLimits;
  48. bool haveProcessorAffinity;
  49. IntPtr processorAffinity;
  50. bool havePriorityClass;
  51. ProcessPriorityClass priorityClass;
  52. ProcessStartInfo startInfo;
  53. bool watchForExit;
  54. bool watchingForExit;
  55. EventHandler onExited;
  56. bool exited;
  57. int exitCode;
  58. bool signaled;
  59. DateTime exitTime;
  60. bool haveExitTime;
  61. bool responding;
  62. bool haveResponding;
  63. bool priorityBoostEnabled;
  64. bool havePriorityBoostEnabled;
  65. bool raisedOnExited;
  66. bool expandEnvironmentVariables;
  67. RegisteredWaitHandle registeredWaitHandle;
  68. WaitHandle waitHandle;
  69. ISynchronizeInvoke synchronizingObject;
  70. StreamReader standardOutput;
  71. StreamWriter standardInput;
  72. StreamReader standardError;
  73. OperatingSystem operatingSystem;
  74. bool disposed;
  75. static object s_CreateProcessLock = new object();
  76. // This enum defines the operation mode for redirected process stream.
  77. // We don't support switching between synchronous mode and asynchronous mode.
  78. private enum StreamReadMode
  79. {
  80. undefined,
  81. syncMode,
  82. asyncMode
  83. }
  84. StreamReadMode outputStreamReadMode;
  85. StreamReadMode errorStreamReadMode;
  86. public event DataReceivedEventHandler OutputDataReceived;
  87. public event DataReceivedEventHandler ErrorDataReceived;
  88. // Abstract the stream details
  89. internal AsyncStreamReader output;
  90. internal AsyncStreamReader error;
  91. internal bool pendingOutputRead;
  92. internal bool pendingErrorRead;
  93. internal static TraceSwitch processTracing = null;
  94. public Process()
  95. {
  96. this.machineName = ".";
  97. this.outputStreamReadMode = StreamReadMode.undefined;
  98. this.errorStreamReadMode = StreamReadMode.undefined;
  99. this.m_processAccess = NativeMethods.PROCESS_ALL_ACCESS;
  100. }
  101. [ResourceExposure(ResourceScope.Machine)]
  102. Process(string machineName, bool isRemoteMachine, int processId, ProcessInfo processInfo) : base()
  103. {
  104. this.processInfo = processInfo;
  105. this.machineName = machineName;
  106. this.isRemoteMachine = isRemoteMachine;
  107. this.processId = processId;
  108. this.haveProcessId = true;
  109. this.outputStreamReadMode = StreamReadMode.undefined;
  110. this.errorStreamReadMode = StreamReadMode.undefined;
  111. this.m_processAccess = NativeMethods.PROCESS_ALL_ACCESS;
  112. }
  113. //
  114. // PROPERTIES
  115. //
  116. bool Associated
  117. {
  118. get
  119. {
  120. return haveProcessId || haveProcessHandle;
  121. }
  122. }
  123. public string ProcessName
  124. {
  125. get
  126. {
  127. this.EnsureState(Process.State.HaveProcessInfo);
  128. return this.processInfo.processName;
  129. }
  130. }
  131. public int ExitCode
  132. {
  133. get
  134. {
  135. EnsureState(State.Exited);
  136. return exitCode;
  137. }
  138. }
  139. public bool HasExited
  140. {
  141. get
  142. {
  143. if (!exited)
  144. {
  145. EnsureState(State.Associated);
  146. SafeProcessHandle handle = null;
  147. try
  148. {
  149. handle = GetProcessHandle(NativeMethods.PROCESS_QUERY_INFORMATION | NativeMethods.SYNCHRONIZE, false);
  150. if (handle.IsInvalid)
  151. {
  152. exited = true;
  153. }
  154. else
  155. {
  156. int exitCode;
  157. // Although this is the wrong way to check whether the process has exited,
  158. // it was historically the way we checked for it, and a lot of code then took a dependency on
  159. // the fact that this would always be set before the pipes were closed, so they would read
  160. // the exit code out after calling ReadToEnd() or standard output or standard error. In order
  161. // to allow 259 to function as a valid exit code and to break as few people as possible that
  162. // took the ReadToEnd dependency, we check for an exit code before doing the more correct
  163. // check to see if we have been signalled.
  164. if (NativeMethods.GetExitCodeProcess(handle, out exitCode) && exitCode != NativeMethods.STILL_ACTIVE)
  165. {
  166. this.exited = true;
  167. this.exitCode = exitCode;
  168. }
  169. else
  170. {
  171. // The best check for exit is that the kernel process object handle is invalid,
  172. // or that it is valid and signaled. Checking if the exit code != STILL_ACTIVE
  173. // does not guarantee the process is closed,
  174. // since some process could return an actual STILL_ACTIVE exit code (259).
  175. if (!signaled) // if we just came from WaitForExit, don't repeat
  176. {
  177. ProcessWaitHandle wh = null;
  178. try
  179. {
  180. wh = new ProcessWaitHandle(handle);
  181. this.signaled = wh.WaitOne(0, false);
  182. }
  183. finally
  184. {
  185. if (wh != null) wh.Close();
  186. }
  187. }
  188. if (signaled)
  189. {
  190. if (!NativeMethods.GetExitCodeProcess(handle, out exitCode)) throw new Win32Exception();
  191. this.exited = true;
  192. this.exitCode = exitCode;
  193. }
  194. }
  195. }
  196. }
  197. finally
  198. {
  199. ReleaseProcessHandle(handle);
  200. }
  201. if (exited)
  202. {
  203. RaiseOnExited();
  204. }
  205. }
  206. return exited;
  207. }
  208. }
  209. public IntPtr Handle
  210. {
  211. [ResourceExposure(ResourceScope.Machine)]
  212. [ResourceConsumption(ResourceScope.Machine)]
  213. get
  214. {
  215. EnsureState(State.Associated);
  216. return OpenProcessHandle(this.m_processAccess).DangerousGetHandle();
  217. }
  218. }
  219. [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  220. public SafeProcessHandle SafeHandle
  221. {
  222. get
  223. {
  224. EnsureState(State.Associated);
  225. return OpenProcessHandle(this.m_processAccess);
  226. }
  227. }
  228. public int Id
  229. {
  230. get
  231. {
  232. EnsureState(State.HaveId);
  233. return processId;
  234. }
  235. }
  236. public string MachineName
  237. {
  238. get
  239. {
  240. EnsureState(State.Associated);
  241. return machineName;
  242. }
  243. }
  244. [System.Runtime.InteropServices.ComVisible(false)]
  245. public long NonpagedSystemMemorySize64
  246. {
  247. get
  248. {
  249. EnsureState(State.HaveNtProcessInfo);
  250. return processInfo.poolNonpagedBytes;
  251. }
  252. }
  253. [System.Runtime.InteropServices.ComVisible(false)]
  254. public long PagedMemorySize64
  255. {
  256. get
  257. {
  258. EnsureState(State.HaveNtProcessInfo);
  259. return processInfo.pageFileBytes;
  260. }
  261. }
  262. [System.Runtime.InteropServices.ComVisible(false)]
  263. public long PagedSystemMemorySize64
  264. {
  265. get
  266. {
  267. EnsureState(State.HaveNtProcessInfo);
  268. return processInfo.poolPagedBytes;
  269. }
  270. }
  271. [System.Runtime.InteropServices.ComVisible(false)]
  272. public long PeakPagedMemorySize64
  273. {
  274. get
  275. {
  276. EnsureState(State.HaveNtProcessInfo);
  277. return processInfo.pageFileBytesPeak;
  278. }
  279. }
  280. [System.Runtime.InteropServices.ComVisible(false)]
  281. public long PeakWorkingSet64
  282. {
  283. get
  284. {
  285. EnsureState(State.HaveNtProcessInfo);
  286. return processInfo.workingSetPeak;
  287. }
  288. }
  289. [System.Runtime.InteropServices.ComVisible(false)]
  290. public long PeakVirtualMemorySize64
  291. {
  292. get
  293. {
  294. EnsureState(State.HaveNtProcessInfo);
  295. return processInfo.virtualBytesPeak;
  296. }
  297. }
  298. private OperatingSystem OperatingSystem
  299. {
  300. get
  301. {
  302. if (operatingSystem == null)
  303. {
  304. operatingSystem = Environment.OSVersion;
  305. }
  306. return operatingSystem;
  307. }
  308. }
  309. [System.Runtime.InteropServices.ComVisible(false)]
  310. public long PrivateMemorySize64
  311. {
  312. get
  313. {
  314. EnsureState(State.HaveNtProcessInfo);
  315. return processInfo.privateBytes;
  316. }
  317. }
  318. public int SessionId
  319. {
  320. get
  321. {
  322. EnsureState(State.HaveNtProcessInfo);
  323. return processInfo.sessionId;
  324. }
  325. }
  326. public ProcessStartInfo StartInfo
  327. {
  328. get
  329. {
  330. return startInfo;
  331. }
  332. [ResourceExposure(ResourceScope.Machine)]
  333. set
  334. {
  335. if (value == null)
  336. {
  337. throw new ArgumentNullException("value");
  338. }
  339. startInfo = value;
  340. }
  341. }
  342. public bool ExpandEnvironmentVariables
  343. {
  344. get
  345. {
  346. return expandEnvironmentVariables;
  347. }
  348. set
  349. {
  350. expandEnvironmentVariables = value;
  351. }
  352. }
  353. public ISynchronizeInvoke SynchronizingObject
  354. {
  355. get
  356. {
  357. if (this.synchronizingObject == null && DesignMode)
  358. {
  359. IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost));
  360. if (host != null)
  361. {
  362. object baseComponent = host.RootComponent;
  363. if (baseComponent != null && baseComponent is ISynchronizeInvoke) this.synchronizingObject = (ISynchronizeInvoke)baseComponent;
  364. }
  365. }
  366. return this.synchronizingObject;
  367. }
  368. set
  369. {
  370. this.synchronizingObject = value;
  371. }
  372. }
  373. [System.Runtime.InteropServices.ComVisible(false)]
  374. public long VirtualMemorySize64
  375. {
  376. get
  377. {
  378. EnsureState(State.HaveNtProcessInfo);
  379. return processInfo.virtualBytes;
  380. }
  381. }
  382. public bool EnableRaisingEvents
  383. {
  384. get
  385. {
  386. return watchForExit;
  387. }
  388. set
  389. {
  390. if (value != watchForExit)
  391. {
  392. if (Associated)
  393. {
  394. if (value)
  395. {
  396. OpenProcessHandle();
  397. EnsureWatchingForExit();
  398. }
  399. else
  400. {
  401. StopWatchingForExit();
  402. }
  403. }
  404. watchForExit = value;
  405. }
  406. }
  407. }
  408. public StreamWriter StandardInput
  409. {
  410. get
  411. {
  412. if (standardInput == null)
  413. {
  414. throw new InvalidOperationException("CantGetStandardIn");
  415. }
  416. return standardInput;
  417. }
  418. }
  419. public StreamReader StandardOutput
  420. {
  421. get
  422. {
  423. if (standardOutput == null)
  424. {
  425. throw new InvalidOperationException("CantGetStandardOut");
  426. }
  427. if (outputStreamReadMode == StreamReadMode.undefined)
  428. {
  429. outputStreamReadMode = StreamReadMode.syncMode;
  430. }
  431. else if (outputStreamReadMode != StreamReadMode.syncMode)
  432. {
  433. throw new InvalidOperationException("CantMixSyncAsyncOperation");
  434. }
  435. return standardOutput;
  436. }
  437. }
  438. public StreamReader StandardError
  439. {
  440. get
  441. {
  442. if (standardError == null)
  443. {
  444. throw new InvalidOperationException("CantGetStandardError");
  445. }
  446. if (errorStreamReadMode == StreamReadMode.undefined)
  447. {
  448. errorStreamReadMode = StreamReadMode.syncMode;
  449. }
  450. else if (errorStreamReadMode != StreamReadMode.syncMode)
  451. {
  452. throw new InvalidOperationException("CantMixSyncAsyncOperation");
  453. }
  454. return standardError;
  455. }
  456. }
  457. public int WorkingSet
  458. {
  459. get
  460. {
  461. EnsureState(State.HaveNtProcessInfo);
  462. return unchecked((int)processInfo.workingSet);
  463. }
  464. }
  465. [System.Runtime.InteropServices.ComVisible(false)]
  466. public long WorkingSet64
  467. {
  468. get
  469. {
  470. EnsureState(State.HaveNtProcessInfo);
  471. return processInfo.workingSet;
  472. }
  473. }
  474. public event EventHandler Exited
  475. {
  476. add
  477. {
  478. onExited += value;
  479. }
  480. remove
  481. {
  482. onExited -= value;
  483. }
  484. }
  485. /// <devdoc>
  486. /// Release the temporary handle we used to get process information.
  487. /// If we used the process handle stored in the process object (we have all access to the handle,) don't release it.
  488. /// </devdoc>
  489. /// <internalonly/>
  490. void ReleaseProcessHandle(SafeProcessHandle handle)
  491. {
  492. if (handle == null)
  493. {
  494. return;
  495. }
  496. if (haveProcessHandle && handle == m_processHandle)
  497. {
  498. return;
  499. }
  500. handle.Close();
  501. }
  502. /// <devdoc>
  503. /// This is called from the threadpool when a proces exits.
  504. /// </devdoc>
  505. /// <internalonly/>
  506. private void CompletionCallback(object context, bool wasSignaled)
  507. {
  508. StopWatchingForExit();
  509. RaiseOnExited();
  510. }
  511. /// <internalonly/>
  512. /// <devdoc>
  513. /// <para>
  514. /// Free any resources associated with this component.
  515. /// </para>
  516. /// </devdoc>
  517. protected override void Dispose(bool disposing)
  518. {
  519. if (!disposed)
  520. {
  521. if (disposing)
  522. {
  523. //Dispose managed and unmanaged resources
  524. Close();
  525. }
  526. this.disposed = true;
  527. base.Dispose(disposing);
  528. }
  529. }
  530. /// <devdoc>
  531. /// <para>
  532. /// Frees any resources associated with this component.
  533. /// </para>
  534. /// </devdoc>
  535. public void Close()
  536. {
  537. if (Associated)
  538. {
  539. if (haveProcessHandle)
  540. {
  541. StopWatchingForExit();
  542. m_processHandle.Close();
  543. m_processHandle = null;
  544. haveProcessHandle = false;
  545. }
  546. haveProcessId = false;
  547. isRemoteMachine = false;
  548. machineName = ".";
  549. raisedOnExited = false;
  550. //Don't call close on the Readers and writers
  551. //since they might be referenced by somebody else while the
  552. //process is still alive but this method called.
  553. standardOutput = null;
  554. standardInput = null;
  555. standardError = null;
  556. output = null;
  557. error = null;
  558. Refresh();
  559. }
  560. }
  561. /// <devdoc>
  562. /// Helper method for checking preconditions when accessing properties.
  563. /// </devdoc>
  564. /// <internalonly/>
  565. [ResourceExposure(ResourceScope.None)]
  566. [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
  567. void EnsureState(State state)
  568. {
  569. if ((state & State.Associated) != (State)0)
  570. if (!Associated)
  571. throw new InvalidOperationException("NoAssociatedProcess");
  572. if ((state & State.IsLocal) != (State)0 && isRemoteMachine)
  573. {
  574. throw new NotSupportedException("NotSupportedRemote");
  575. }
  576. if ((state & Process.State.HaveProcessInfo) != (Process.State) 0 && this.processInfo == null)
  577. {
  578. if ((state & Process.State.HaveId) == (Process.State) 0)
  579. this.EnsureState(Process.State.HaveId);
  580. this.processInfo = GetProcessInfo(this.processId, this.machineName);
  581. if (this.processInfo == null)
  582. throw new InvalidOperationException("NoProcessInfo");
  583. }
  584. if ((state & State.Exited) != (State)0)
  585. {
  586. if (!HasExited)
  587. {
  588. throw new InvalidOperationException("WaitTillExit");
  589. }
  590. if (!haveProcessHandle)
  591. {
  592. throw new InvalidOperationException("NoProcessHandle");
  593. }
  594. }
  595. }
  596. void EnsureWatchingForExit()
  597. {
  598. if (!watchingForExit)
  599. {
  600. lock (this)
  601. {
  602. if (!watchingForExit)
  603. {
  604. watchingForExit = true;
  605. try
  606. {
  607. this.waitHandle = new ProcessWaitHandle(m_processHandle);
  608. this.registeredWaitHandle = ThreadPool.RegisterWaitForSingleObject(this.waitHandle, new WaitOrTimerCallback(this.CompletionCallback), null, -1, true);
  609. }
  610. catch
  611. {
  612. watchingForExit = false;
  613. throw;
  614. }
  615. }
  616. }
  617. }
  618. }
  619. protected void OnExited()
  620. {
  621. EventHandler exited = onExited;
  622. if (exited != null)
  623. {
  624. if (this.SynchronizingObject != null && this.SynchronizingObject.InvokeRequired)
  625. this.SynchronizingObject.BeginInvoke(exited, new object[]
  626. {
  627. this, EventArgs.Empty
  628. });
  629. else exited(this, EventArgs.Empty);
  630. }
  631. }
  632. [ResourceExposure(ResourceScope.None)]
  633. [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
  634. SafeProcessHandle GetProcessHandle(int access, bool throwIfExited)
  635. {
  636. if (haveProcessHandle)
  637. {
  638. if (throwIfExited)
  639. {
  640. // Since haveProcessHandle is true, we know we have the process handle
  641. // open with at least SYNCHRONIZE access, so we can wait on it with
  642. // zero timeout to see if the process has exited.
  643. ProcessWaitHandle waitHandle = null;
  644. try
  645. {
  646. waitHandle = new ProcessWaitHandle(m_processHandle);
  647. if (waitHandle.WaitOne(0, false))
  648. {
  649. if (haveProcessId) throw new InvalidOperationException("Process has exited: " + processId);
  650. else throw new InvalidOperationException("ProcessHasExitedNoId");
  651. }
  652. }
  653. finally
  654. {
  655. if (waitHandle != null)
  656. {
  657. waitHandle.Close();
  658. }
  659. }
  660. }
  661. return m_processHandle;
  662. }
  663. else
  664. {
  665. throw new Exception("(AME) Process handle not available.");
  666. }
  667. }
  668. /// <devdoc>
  669. /// Gets a short-term handle to the process, with the given access. If a handle exists,
  670. /// then it is reused. If the process has exited, it throws an exception.
  671. /// </devdoc>
  672. /// <internalonly/>
  673. SafeProcessHandle GetProcessHandle(int access)
  674. {
  675. return GetProcessHandle(access, true);
  676. }
  677. /// <devdoc>
  678. /// Opens a long-term handle to the process, with all access. If a handle exists,
  679. /// then it is reused. If the process has exited, it throws an exception.
  680. /// </devdoc>
  681. /// <internalonly/>
  682. SafeProcessHandle OpenProcessHandle()
  683. {
  684. return OpenProcessHandle(NativeMethods.PROCESS_ALL_ACCESS);
  685. }
  686. SafeProcessHandle OpenProcessHandle(Int32 access)
  687. {
  688. if (!haveProcessHandle)
  689. {
  690. //Cannot open a new process handle if the object has been disposed, since finalization has been suppressed.
  691. if (this.disposed)
  692. {
  693. throw new ObjectDisposedException(GetType().Name);
  694. }
  695. SetProcessHandle(GetProcessHandle(access));
  696. }
  697. return m_processHandle;
  698. }
  699. /// <devdoc>
  700. /// Raise the Exited event, but make sure we don't do it more than once.
  701. /// </devdoc>
  702. /// <internalonly/>
  703. void RaiseOnExited()
  704. {
  705. if (!raisedOnExited)
  706. {
  707. lock (this)
  708. {
  709. if (!raisedOnExited)
  710. {
  711. raisedOnExited = true;
  712. OnExited();
  713. }
  714. }
  715. }
  716. }
  717. /// <devdoc>
  718. /// <para>
  719. /// Discards any information about the associated process
  720. /// that has been cached inside the process component. After <see cref='System.Diagnostics.Process.Refresh'/> is called, the
  721. /// first request for information for each property causes the process component
  722. /// to obtain a new value from the associated process.
  723. /// </para>
  724. /// </devdoc>
  725. public void Refresh()
  726. {
  727. processInfo = null;
  728. threads = null;
  729. modules = null;
  730. mainWindowTitle = null;
  731. exited = false;
  732. signaled = false;
  733. haveMainWindow = false;
  734. haveWorkingSetLimits = false;
  735. haveProcessorAffinity = false;
  736. havePriorityClass = false;
  737. haveExitTime = false;
  738. haveResponding = false;
  739. havePriorityBoostEnabled = false;
  740. }
  741. /// <devdoc>
  742. /// Helper to associate a process handle with this component.
  743. /// </devdoc>
  744. /// <internalonly/>
  745. void SetProcessHandle(SafeProcessHandle processHandle)
  746. {
  747. this.m_processHandle = processHandle;
  748. this.haveProcessHandle = true;
  749. if (watchForExit)
  750. {
  751. EnsureWatchingForExit();
  752. }
  753. }
  754. /// <devdoc>
  755. /// Helper to associate a process id with this component.
  756. /// </devdoc>
  757. /// <internalonly/>
  758. [ResourceExposure(ResourceScope.Machine)]
  759. void SetProcessId(int processId)
  760. {
  761. this.processId = processId;
  762. this.haveProcessId = true;
  763. }
  764. /// <devdoc>
  765. /// <para>
  766. /// Starts a process specified by the <see cref='System.Diagnostics.Process.StartInfo'/> property of this <see cref='System.Diagnostics.Process'/>
  767. /// component and associates it with the
  768. /// <see cref='System.Diagnostics.Process'/> . If a process resource is reused
  769. /// rather than started, the reused process is associated with this <see cref='System.Diagnostics.Process'/>
  770. /// component.
  771. /// </para>
  772. /// </devdoc>
  773. [ResourceExposure(ResourceScope.None)]
  774. [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
  775. public bool Start(CreateType type, ref Win32.TokensEx.SafeTokenHandle token)
  776. {
  777. Close();
  778. ProcessStartInfo startInfo = StartInfo;
  779. if (startInfo.FileName.Length == 0) throw new InvalidOperationException("FileNameMissing");
  780. return StartWithCreateProcess(startInfo, type, ref token);
  781. }
  782. [ResourceExposure(ResourceScope.Process)]
  783. [ResourceConsumption(ResourceScope.Process)]
  784. private static void CreatePipeWithSecurityAttributes(out SafeFileHandle hReadPipe, out SafeFileHandle hWritePipe, NativeMethods.SECURITY_ATTRIBUTES lpPipeAttributes, int nSize)
  785. {
  786. bool ret = NativeMethods.CreatePipe(out hReadPipe, out hWritePipe, lpPipeAttributes, nSize);
  787. if (!ret || hReadPipe.IsInvalid || hWritePipe.IsInvalid)
  788. {
  789. throw new Win32Exception();
  790. }
  791. }
  792. // Using synchronous Anonymous pipes for process input/output redirection means we would end up
  793. // wasting a worker threadpool thread per pipe instance. Overlapped pipe IO is desirable, since
  794. // it will take advantage of the NT IO completion port infrastructure. But we can't really use
  795. // Overlapped I/O for process input/output as it would break Console apps (managed Console class
  796. // methods such as WriteLine as well as native CRT functions like printf) which are making an
  797. // assumption that the console standard handles (obtained via GetStdHandle()) are opened
  798. // for synchronous I/O and hence they can work fine with ReadFile/WriteFile synchrnously!
  799. [ResourceExposure(ResourceScope.None)]
  800. [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
  801. private void CreatePipe(out SafeFileHandle parentHandle, out SafeFileHandle childHandle, bool parentInputs)
  802. {
  803. NativeMethods.SECURITY_ATTRIBUTES securityAttributesParent = new NativeMethods.SECURITY_ATTRIBUTES();
  804. securityAttributesParent.bInheritHandle = true;
  805. SafeFileHandle hTmp = null;
  806. try
  807. {
  808. if (parentInputs)
  809. {
  810. CreatePipeWithSecurityAttributes(out childHandle, out hTmp, securityAttributesParent, 0);
  811. }
  812. else
  813. {
  814. CreatePipeWithSecurityAttributes(out hTmp, out childHandle, securityAttributesParent, 0);
  815. }
  816. // Duplicate the parent handle to be non-inheritable so that the child process
  817. // doesn't have access. This is done for correctness sake, exact reason is unclear.
  818. // One potential theory is that child process can do something brain dead like
  819. // closing the parent end of the pipe and there by getting into a blocking situation
  820. // as parent will not be draining the pipe at the other end anymore.
  821. if (!NativeMethods.DuplicateHandle(new HandleRef(this, NativeMethods.GetCurrentProcess()), hTmp, new HandleRef(this, NativeMethods.GetCurrentProcess()), out parentHandle, 0, false,
  822. NativeMethods.DUPLICATE_SAME_ACCESS))
  823. {
  824. throw new Win32Exception();
  825. }
  826. }
  827. finally
  828. {
  829. if (hTmp != null && !hTmp.IsInvalid)
  830. {
  831. hTmp.Close();
  832. }
  833. }
  834. }
  835. private static StringBuilder BuildCommandLine(string executableFileName, string arguments)
  836. {
  837. // Construct a StringBuilder with the appropriate command line
  838. // to pass to CreateProcess. If the filename isn't already
  839. // in quotes, we quote it here. This prevents some security
  840. // problems (it specifies exactly which part of the string
  841. // is the file to execute).
  842. StringBuilder commandLine = new StringBuilder();
  843. string fileName = executableFileName.Trim();
  844. bool fileNameIsQuoted = (fileName.StartsWith("\"", StringComparison.Ordinal) && fileName.EndsWith("\"", StringComparison.Ordinal));
  845. if (!fileNameIsQuoted)
  846. {
  847. commandLine.Append("\"");
  848. }
  849. commandLine.Append(fileName);
  850. if (!fileNameIsQuoted)
  851. {
  852. commandLine.Append("\"");
  853. }
  854. if (!String.IsNullOrEmpty(arguments))
  855. {
  856. commandLine.Append(" ");
  857. commandLine.Append(arguments);
  858. }
  859. return commandLine;
  860. }
  861. [ResourceExposure(ResourceScope.Machine)]
  862. [ResourceConsumption(ResourceScope.Machine)]
  863. private bool StartWithCreateProcess(ProcessStartInfo startInfo, CreateType type, ref Win32.TokensEx.SafeTokenHandle token)
  864. {
  865. // See knowledge base article Q190351 for an explanation of the following code. Noteworthy tricky points:
  866. // * The handles are duplicated as non-inheritable before they are passed to CreateProcess so
  867. // that the child process can not close them
  868. // * CreateProcess allows you to redirect all or none of the standard IO handles, so we use
  869. // GetStdHandle for the handles that are not being redirected
  870. //Cannot start a new process and store its handle if the object has been disposed, since finalization has been suppressed.
  871. if (this.disposed)
  872. {
  873. throw new ObjectDisposedException(GetType().Name);
  874. }
  875. StringBuilder commandLine = BuildCommandLine(startInfo.FileName, startInfo.Arguments);
  876. NativeMethods.STARTUPINFO startupInfo = new NativeMethods.STARTUPINFO();
  877. NativeMethods.PROCESS_INFORMATION processInfo = new NativeMethods.PROCESS_INFORMATION();
  878. SafeProcessHandle procSH = new SafeProcessHandle();
  879. SafeThreadHandle threadSH = new SafeThreadHandle();
  880. bool retVal;
  881. int errorCode = 0;
  882. // handles used in parent process
  883. SafeFileHandle standardInputWritePipeHandle = null;
  884. SafeFileHandle standardOutputReadPipeHandle = null;
  885. SafeFileHandle standardErrorReadPipeHandle = null;
  886. IntPtr environmentPtr = (IntPtr)0;
  887. //GCHandle environmentHandle = new GCHandle();
  888. lock (s_CreateProcessLock)
  889. {
  890. try
  891. {
  892. // set up the streams
  893. if (startInfo.CreateNoWindow && (startInfo.RedirectStandardInput || startInfo.RedirectStandardOutput || startInfo.RedirectStandardError))
  894. {
  895. if (startInfo.StandardOutputEncoding != null && !startInfo.RedirectStandardOutput)
  896. {
  897. throw new InvalidOperationException("StandardOutputEncodingNotAllowed");
  898. }
  899. if (startInfo.StandardErrorEncoding != null && !startInfo.RedirectStandardError)
  900. {
  901. throw new InvalidOperationException("StandardErrorEncodingNotAllowed");
  902. }
  903. if (startInfo.RedirectStandardInput)
  904. {
  905. CreatePipe(out standardInputWritePipeHandle, out startupInfo.hStdInput, true);
  906. }
  907. else
  908. {
  909. startupInfo.hStdInput = new SafeFileHandle(NativeMethods.GetStdHandle(NativeMethods.STD_INPUT_HANDLE), false);
  910. }
  911. if (startInfo.RedirectStandardOutput)
  912. {
  913. CreatePipe(out standardOutputReadPipeHandle, out startupInfo.hStdOutput, false);
  914. }
  915. else
  916. {
  917. startupInfo.hStdOutput = new SafeFileHandle(NativeMethods.GetStdHandle(NativeMethods.STD_OUTPUT_HANDLE), false);
  918. }
  919. if (startInfo.RedirectStandardError)
  920. {
  921. CreatePipe(out standardErrorReadPipeHandle, out startupInfo.hStdError, false);
  922. }
  923. else
  924. {
  925. startupInfo.hStdError = new SafeFileHandle(NativeMethods.GetStdHandle(NativeMethods.STD_ERROR_HANDLE), false);
  926. }
  927. startupInfo.dwFlags = NativeMethods.STARTF_USESTDHANDLES;
  928. }
  929. // set up the creation flags paramater
  930. int creationFlags = 0;
  931. if (startInfo.CreateNoWindow) creationFlags |= NativeMethods.CREATE_NO_WINDOW;
  932. // set up the environment block parameterhttps://www.beyondtrust.com/assets/documents/BeyondTrust-Microsoft-Vulnerabilities-Report-2021.pdf
  933. //if (startInfo.environmentVariables != null)
  934. if (true)
  935. {
  936. creationFlags |= NativeMethods.CREATE_UNICODE_ENVIRONMENT;
  937. //byte[] environmentBytes = EnvironmentBlock.ToByteArray(startInfo.environmentVariables, true);
  938. //environmentHandle = GCHandle.Alloc(environmentBytes, GCHandleType.Pinned);
  939. //environmentPtr = environmentHandle.AddrOfPinnedObject();
  940. Win32.Process.CreateEnvironmentBlock(out environmentPtr, token, false);
  941. }
  942. /*
  943. if (ExpandEnvironmentVariables && startInfo.Arguments.Contains("%"))
  944. {
  945. Environment.ExpandEnvironmentVariables()
  946. var envVars = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
  947. IntPtr next = environmentPtr;
  948. while (Marshal.ReadByte(next) != 0)
  949. {
  950. var str = Marshal.PtrToStringUni(next);
  951. // skip first character because windows allows env vars to begin with equal sign
  952. var splitPoint = str.IndexOf('=', 1);
  953. var envVarName = str.Substring(0, splitPoint);
  954. var envVarVal = str.Substring(splitPoint + 1);
  955. envVars.Add(envVarName, envVarVal);
  956. next = (IntPtr)((Int64)next + (str.Length * 2) + 2);
  957. }
  958. return envVars;
  959. }
  960. */
  961. if (!startInfo.CreateNoWindow)
  962. {
  963. creationFlags |= (int)Win32.Process.ProcessCreationFlags.CREATE_DEFAULT_ERROR_MODE;
  964. creationFlags |= (int)Win32.Process.ProcessCreationFlags.CREATE_NEW_CONSOLE;
  965. creationFlags |= (int)Win32.Process.ProcessCreationFlags.CREATE_NEW_PROCESS_GROUP;
  966. //startupInfo.lpDesktop = "Winsta0\\Default";
  967. }
  968. string workingDirectory = startInfo.WorkingDirectory;
  969. if (workingDirectory == string.Empty) workingDirectory = Environment.CurrentDirectory;
  970. RuntimeHelpers.PrepareConstrainedRegions();
  971. try { }
  972. finally
  973. {
  974. retVal = false;
  975. if (type == CreateType.UserToken)
  976. {
  977. retVal = NativeMethods.CreateProcessAsUser(token,
  978. null, // we don't need this since all the info is in commandLine
  979. commandLine, // pointer to the command line string
  980. null, // pointer to process security attributes, we don't need to inheriat the handle
  981. null, // pointer to thread security attributes
  982. true, // handle inheritance flag
  983. creationFlags, // creation flags
  984. environmentPtr, // pointer to new environment block
  985. workingDirectory, // pointer to current directory name
  986. startupInfo, // pointer to STARTUPINFO
  987. processInfo // pointer to PROCESS_INFORMATION
  988. );
  989. } else if (type == CreateType.RawToken)
  990. {
  991. retVal = NativeMethods.CreateProcessWithToken(token,
  992. NativeMethods.LogonFlags.LOGON_WITH_PROFILE,
  993. null, // we don't need this since all the info is in commandLine
  994. commandLine, // pointer to the command line string
  995. creationFlags, // creation flags
  996. environmentPtr, // pointer to new environment block
  997. workingDirectory, // pointer to current directory name
  998. startupInfo, // pointer to STARTUPINFO
  999. processInfo // pointer to PROCESS_INFORMATION
  1000. );
  1001. }
  1002. /*
  1003. retVal = NativeMethods.CreateProcess(null, // we don't need this since all the info is in commandLine
  1004. commandLine, // pointer to the command line string
  1005. null, // pointer to process security attributes, we don't need to inheriat the handle
  1006. null, // pointer to thread security attributes
  1007. true, // handle inheritance flag
  1008. creationFlags, // creation flags
  1009. environmentPtr, // pointer to new environment block
  1010. workingDirectory, // pointer to current directory name
  1011. startupInfo, // pointer to STARTUPINFO
  1012. processInfo // pointer to PROCESS_INFORMATION
  1013. );
  1014. */
  1015. if (!retVal) errorCode = Marshal.GetLastWin32Error();
  1016. if (processInfo.hProcess != (IntPtr)0 && processInfo.hProcess != (IntPtr)NativeMethods.INVALID_HANDLE_VALUE) procSH.InitialSetHandle(processInfo.hProcess);
  1017. if (processInfo.hThread != (IntPtr)0 && processInfo.hThread != (IntPtr)NativeMethods.INVALID_HANDLE_VALUE) threadSH.InitialSetHandle(processInfo.hThread);
  1018. }
  1019. if (!retVal)
  1020. {
  1021. if (errorCode == NativeMethods.ERROR_BAD_EXE_FORMAT || errorCode == NativeMethods.ERROR_EXE_MACHINE_TYPE_MISMATCH)
  1022. {
  1023. throw new Win32Exception(errorCode, "InvalidApplication");
  1024. }
  1025. throw new Win32Exception(errorCode);
  1026. }
  1027. }
  1028. finally
  1029. {
  1030. // free environment block
  1031. //if (environmentHandle.IsAllocated)
  1032. //{
  1033. // environmentHandle.Free();
  1034. //}
  1035. Win32.Process.DestroyEnvironmentBlock(environmentPtr);
  1036. startupInfo.Dispose();
  1037. }
  1038. }
  1039. if (startInfo.RedirectStandardInput)
  1040. {
  1041. standardInput = new StreamWriter(new FileStream(standardInputWritePipeHandle, FileAccess.Write, 4096, false), Console.InputEncoding, 4096);
  1042. standardInput.AutoFlush = true;
  1043. }
  1044. if (startInfo.RedirectStandardOutput)
  1045. {
  1046. Encoding enc = (startInfo.StandardOutputEncoding != null) ? startInfo.StandardOutputEncoding : Console.OutputEncoding;
  1047. standardOutput = new StreamReader(new FileStream(standardOutputReadPipeHandle, FileAccess.Read, 4096, false), enc, true, 4096);
  1048. }
  1049. if (startInfo.RedirectStandardError)
  1050. {
  1051. Encoding enc = (startInfo.StandardErrorEncoding != null) ? startInfo.StandardErrorEncoding : Console.OutputEncoding;
  1052. standardError = new StreamReader(new FileStream(standardErrorReadPipeHandle, FileAccess.Read, 4096, false), enc, true, 4096);
  1053. }
  1054. bool ret = false;
  1055. if (!procSH.IsInvalid)
  1056. {
  1057. SetProcessHandle(procSH);
  1058. SetProcessId(processInfo.dwProcessId);
  1059. threadSH.Close();
  1060. ret = true;
  1061. }
  1062. return ret;
  1063. }
  1064. /*
  1065. private static string ExpandEnvironmentVariables(string name, Dictionary<string, string> environment)
  1066. {
  1067. switch (name)
  1068. {
  1069. case null:
  1070. case "":
  1071. return name;
  1072. default:
  1073. environment = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
  1074. {
  1075. {"SuSSY", "gussys"},
  1076. {"AMoGus", "gussys"},
  1077. {"Sussex", "gussys"}
  1078. };
  1079. StringBuilder result = new StringBuilder();
  1080. int index = name.IndexOf('%');
  1081. if (index > 0)
  1082. result.Append(name.Substring(index));
  1083. int lastValidIndex = -1;
  1084. while (index != -1)
  1085. {
  1086. lastValidIndex = index;
  1087. var end = name.IndexOf('%', index + 1);
  1088. if (end == -1)
  1089. {
  1090. result.Append('%');
  1091. break;
  1092. }
  1093. // Double % escape
  1094. if (end == index + 1)
  1095. {
  1096. index = name.IndexOf('%', index + 2);
  1097. result.Append(index == -1 ? "%" : "%" + name.Substring(end + 1, index - (end + 1)));
  1098. continue;
  1099. }
  1100. lastValidIndex = end;
  1101. if (environment.TryGetValue(name.Substring(index + 1, end - (index + 1)), out string varValue))
  1102. result.Append(varValue);
  1103. index = name.IndexOf('%', end + 1);
  1104. if (index != -1)
  1105. {
  1106. result.Append(name.Substring(end + 1, index - (end + 1)));
  1107. }
  1108. }
  1109. result.Append(lastValidIndex != -1 ? name.Substring(index + 1, name.Length - (index + 1)) : name);
  1110. return result.ToString();
  1111. }
  1112. }
  1113. */
  1114. [ResourceExposure(ResourceScope.Machine)]
  1115. [ResourceConsumption(ResourceScope.Machine)]
  1116. private bool StartWithShellExecuteEx(ProcessStartInfo startInfo)
  1117. {
  1118. //Cannot start a new process and store its handle if the object has been disposed, since finalization has been suppressed.
  1119. if (this.disposed) throw new ObjectDisposedException(GetType().Name);
  1120. if (!String.IsNullOrEmpty(startInfo.UserName) || (startInfo.Password != null))
  1121. {
  1122. throw new InvalidOperationException("CantStartAsUser");
  1123. }
  1124. if (startInfo.RedirectStandardInput || startInfo.RedirectStandardOutput || startInfo.RedirectStandardError)
  1125. {
  1126. throw new InvalidOperationException("CantRedirectStreams");
  1127. }
  1128. if (startInfo.StandardErrorEncoding != null)
  1129. {
  1130. throw new InvalidOperationException("StandardErrorEncodingNotAllowed");
  1131. }
  1132. if (startInfo.StandardOutputEncoding != null)
  1133. {
  1134. throw new InvalidOperationException("StandardOutputEncodingNotAllowed");
  1135. }
  1136. // can't set env vars with ShellExecuteEx...
  1137. if (startInfo.environmentVariables != null)
  1138. {
  1139. throw new InvalidOperationException("CantUseEnvVars");
  1140. }
  1141. NativeMethods.ShellExecuteInfo shellExecuteInfo = new NativeMethods.ShellExecuteInfo();
  1142. shellExecuteInfo.fMask = NativeMethods.SEE_MASK_NOCLOSEPROCESS;
  1143. if (startInfo.ErrorDialog)
  1144. {
  1145. shellExecuteInfo.hwnd = startInfo.ErrorDialogParentHandle;
  1146. }
  1147. else
  1148. {
  1149. shellExecuteInfo.fMask |= NativeMethods.SEE_MASK_FLAG_NO_UI;
  1150. }
  1151. switch (startInfo.WindowStyle)
  1152. {
  1153. case ProcessWindowStyle.Hidden:
  1154. shellExecuteInfo.nShow = NativeMethods.SW_HIDE;
  1155. break;
  1156. case ProcessWindowStyle.Minimized:
  1157. shellExecuteInfo.nShow = NativeMethods.SW_SHOWMINIMIZED;
  1158. break;
  1159. case ProcessWindowStyle.Maximized:
  1160. shellExecuteInfo.nShow = NativeMethods.SW_SHOWMAXIMIZED;
  1161. break;
  1162. default:
  1163. shellExecuteInfo.nShow = NativeMethods.SW_SHOWNORMAL;
  1164. break;
  1165. }
  1166. try
  1167. {
  1168. if (startInfo.FileName.Length != 0) shellExecuteInfo.lpFile = Marshal.StringToHGlobalAuto(startInfo.FileName);
  1169. if (startInfo.Verb.Length != 0) shellExecuteInfo.lpVerb = Marshal.StringToHGlobalAuto(startInfo.Verb);
  1170. if (startInfo.Arguments.Length != 0) shellExecuteInfo.lpParameters = Marshal.StringToHGlobalAuto(startInfo.Arguments);
  1171. if (startInfo.WorkingDirectory.Length != 0) shellExecuteInfo.lpDirectory = Marshal.StringToHGlobalAuto(startInfo.WorkingDirectory);
  1172. shellExecuteInfo.fMask |= NativeMethods.SEE_MASK_FLAG_DDEWAIT;
  1173. ShellExecuteHelper executeHelper = new ShellExecuteHelper(shellExecuteInfo);
  1174. if (!executeHelper.ShellExecuteOnSTAThread())
  1175. {
  1176. int error = executeHelper.ErrorCode;
  1177. if (error == 0)
  1178. {
  1179. switch ((long)shellExecuteInfo.hInstApp)
  1180. {
  1181. case NativeMethods.SE_ERR_FNF:
  1182. error = NativeMethods.ERROR_FILE_NOT_FOUND;
  1183. break;
  1184. case NativeMethods.SE_ERR_PNF:
  1185. error = NativeMethods.ERROR_PATH_NOT_FOUND;
  1186. break;
  1187. case NativeMethods.SE_ERR_ACCESSDENIED:
  1188. error = NativeMethods.ERROR_ACCESS_DENIED;
  1189. break;
  1190. case NativeMethods.SE_ERR_OOM:
  1191. error = NativeMethods.ERROR_NOT_ENOUGH_MEMORY;
  1192. break;
  1193. case NativeMethods.SE_ERR_DDEFAIL:
  1194. case NativeMethods.SE_ERR_DDEBUSY:
  1195. case NativeMethods.SE_ERR_DDETIMEOUT:
  1196. error = NativeMethods.ERROR_DDE_FAIL;
  1197. break;
  1198. case NativeMethods.SE_ERR_SHARE:
  1199. error = NativeMethods.ERROR_SHARING_VIOLATION;
  1200. break;
  1201. case NativeMethods.SE_ERR_NOASSOC:
  1202. error = NativeMethods.ERROR_NO_ASSOCIATION;
  1203. break;
  1204. case NativeMethods.SE_ERR_DLLNOTFOUND:
  1205. error = NativeMethods.ERROR_DLL_NOT_FOUND;
  1206. break;
  1207. default:
  1208. error = (int)shellExecuteInfo.hInstApp;
  1209. break;
  1210. }
  1211. }
  1212. if (error == NativeMethods.ERROR_BAD_EXE_FORMAT || error == NativeMethods.ERROR_EXE_MACHINE_TYPE_MISMATCH)
  1213. {
  1214. throw new Win32Exception(error, "InvalidApplication");
  1215. }
  1216. throw new Win32Exception(error);
  1217. }
  1218. }
  1219. finally
  1220. {
  1221. if (shellExecuteInfo.lpFile != (IntPtr)0) Marshal.FreeHGlobal(shellExecuteInfo.lpFile);
  1222. if (shellExecuteInfo.lpVerb != (IntPtr)0) Marshal.FreeHGlobal(shellExecuteInfo.lpVerb);
  1223. if (shellExecuteInfo.lpParameters != (IntPtr)0) Marshal.FreeHGlobal(shellExecuteInfo.lpParameters);
  1224. if (shellExecuteInfo.lpDirectory != (IntPtr)0) Marshal.FreeHGlobal(shellExecuteInfo.lpDirectory);
  1225. }
  1226. if (shellExecuteInfo.hProcess != (IntPtr)0)
  1227. {
  1228. SafeProcessHandle handle = new SafeProcessHandle(shellExecuteInfo.hProcess);
  1229. SetProcessHandle(handle);
  1230. return true;
  1231. }
  1232. return false;
  1233. }
  1234. /// <devdoc>
  1235. /// <para>
  1236. /// Starts a process resource specified by the process start
  1237. /// information passed in, for example the file name of the process to start.
  1238. /// Associates the process resource with a new <see cref='System.Diagnostics.Process'/>
  1239. /// component.
  1240. /// </para>
  1241. /// </devdoc>
  1242. [ResourceExposure(ResourceScope.Machine)]
  1243. [ResourceConsumption(ResourceScope.Machine)]
  1244. public static Process Start(CreateType type, ProcessStartInfo startInfo, Win32.TokensEx.SafeTokenHandle token)
  1245. {
  1246. Process process = new Process();
  1247. if (startInfo == null) throw new ArgumentNullException("startInfo");
  1248. process.StartInfo = startInfo;
  1249. if (process.Start(type, ref token))
  1250. {
  1251. return process;
  1252. }
  1253. return null;
  1254. }
  1255. /// <devdoc>
  1256. /// <para>
  1257. /// Stops the
  1258. /// associated process immediately.
  1259. /// </para>
  1260. /// </devdoc>
  1261. [ResourceExposure(ResourceScope.Machine)]
  1262. [ResourceConsumption(ResourceScope.Machine)]
  1263. public void Kill()
  1264. {
  1265. SafeProcessHandle handle = null;
  1266. try
  1267. {
  1268. handle = GetProcessHandle(NativeMethods.PROCESS_TERMINATE);
  1269. if (!NativeMethods.TerminateProcess(handle, -1)) throw new Win32Exception();
  1270. }
  1271. finally
  1272. {
  1273. ReleaseProcessHandle(handle);
  1274. }
  1275. }
  1276. /// <devdoc>
  1277. /// Make sure we are not watching for process exit.
  1278. /// </devdoc>
  1279. /// <internalonly/>
  1280. void StopWatchingForExit()
  1281. {
  1282. if (watchingForExit)
  1283. {
  1284. lock (this)
  1285. {
  1286. if (watchingForExit)
  1287. {
  1288. watchingForExit = false;
  1289. registeredWaitHandle.Unregister(null);
  1290. waitHandle.Close();
  1291. waitHandle = null;
  1292. registeredWaitHandle = null;
  1293. }
  1294. }
  1295. }
  1296. }
  1297. /// <devdoc>
  1298. /// <para>
  1299. /// Instructs the <see cref='System.Diagnostics.Process'/> component to wait the specified number of milliseconds for the associated process to exit.
  1300. /// </para>
  1301. /// </devdoc>
  1302. public bool WaitForExit(int milliseconds)
  1303. {
  1304. SafeProcessHandle handle = null;
  1305. bool exited;
  1306. ProcessWaitHandle processWaitHandle = null;
  1307. try
  1308. {
  1309. handle = GetProcessHandle(NativeMethods.SYNCHRONIZE, false);
  1310. if (handle.IsInvalid)
  1311. {
  1312. exited = true;
  1313. }
  1314. else
  1315. {
  1316. processWaitHandle = new ProcessWaitHandle(handle);
  1317. if (processWaitHandle.WaitOne(milliseconds, false))
  1318. {
  1319. exited = true;
  1320. signaled = true;
  1321. }
  1322. else
  1323. {
  1324. exited = false;
  1325. signaled = false;
  1326. }
  1327. }
  1328. }
  1329. finally
  1330. {
  1331. if (processWaitHandle != null)
  1332. {
  1333. processWaitHandle.Close();
  1334. }
  1335. // If we have a hard timeout, we cannot wait for the streams
  1336. if (output != null && milliseconds == -1)
  1337. {
  1338. output.WaitUtilEOF();
  1339. }
  1340. if (error != null && milliseconds == -1)
  1341. {
  1342. error.WaitUtilEOF();
  1343. }
  1344. ReleaseProcessHandle(handle);
  1345. }
  1346. if (exited && watchForExit)
  1347. {
  1348. RaiseOnExited();
  1349. }
  1350. return exited;
  1351. }
  1352. /// <devdoc>
  1353. /// <para>
  1354. /// Instructs the <see cref='System.Diagnostics.Process'/> component to wait
  1355. /// indefinitely for the associated process to exit.
  1356. /// </para>
  1357. /// </devdoc>
  1358. public void WaitForExit()
  1359. {
  1360. WaitForExit(-1);
  1361. }
  1362. /// <devdoc>
  1363. /// <para>
  1364. /// Causes the <see cref='System.Diagnostics.Process'/> component to wait the
  1365. /// specified number of milliseconds for the associated process to enter an
  1366. /// idle state.
  1367. /// This is only applicable for processes with a user interface,
  1368. /// therefore a message loop.
  1369. /// </para>
  1370. /// </devdoc>
  1371. public bool WaitForInputIdle(int milliseconds)
  1372. {
  1373. SafeProcessHandle handle = null;
  1374. bool idle;
  1375. try
  1376. {
  1377. handle = GetProcessHandle(NativeMethods.SYNCHRONIZE | NativeMethods.PROCESS_QUERY_INFORMATION);
  1378. int ret = NativeMethods.WaitForInputIdle(handle, milliseconds);
  1379. switch (ret)
  1380. {
  1381. case NativeMethods.WAIT_OBJECT_0:
  1382. idle = true;
  1383. break;
  1384. case NativeMethods.WAIT_TIMEOUT:
  1385. idle = false;
  1386. break;
  1387. case NativeMethods.WAIT_FAILED:
  1388. default:
  1389. throw new InvalidOperationException("InputIdleUnkownError");
  1390. }
  1391. }
  1392. finally
  1393. {
  1394. ReleaseProcessHandle(handle);
  1395. }
  1396. return idle;
  1397. }
  1398. /// <devdoc>
  1399. /// <para>
  1400. /// Instructs the <see cref='System.Diagnostics.Process'/> component to wait
  1401. /// indefinitely for the associated process to enter an idle state. This
  1402. /// is only applicable for processes with a user interface, therefore a message loop.
  1403. /// </para>
  1404. /// </devdoc>
  1405. public bool WaitForInputIdle()
  1406. {
  1407. return WaitForInputIdle(Int32.MaxValue);
  1408. }
  1409. // Support for working asynchronously with streams
  1410. /// <devdoc>
  1411. /// <para>
  1412. /// Instructs the <see cref='System.Diagnostics.Process'/> component to start
  1413. /// reading the StandardOutput stream asynchronously. The user can register a callback
  1414. /// that will be called when a line of data terminated by \n,\r or \r\n is reached, or the end of stream is reached
  1415. /// then the remaining information is returned. The user can add an event handler to OutputDataReceived.
  1416. /// </para>
  1417. /// </devdoc>
  1418. [System.Runtime.InteropServices.ComVisible(false)]
  1419. public void BeginOutputReadLine()
  1420. {
  1421. if (outputStreamReadMode == StreamReadMode.undefined)
  1422. {
  1423. outputStreamReadMode = StreamReadMode.asyncMode;
  1424. }
  1425. else if (outputStreamReadMode != StreamReadMode.asyncMode)
  1426. {
  1427. throw new InvalidOperationException("CantMixSyncAsyncOperation");
  1428. }
  1429. if (pendingOutputRead) throw new InvalidOperationException("PendingAsyncOperation");
  1430. pendingOutputRead = true;
  1431. // We can't detect if there's a pending sychronous read, tream also doesn't.
  1432. if (output == null)
  1433. {
  1434. if (standardOutput == null)
  1435. {
  1436. throw new InvalidOperationException("CantGetStandardOut");
  1437. }
  1438. Stream s = standardOutput.BaseStream;
  1439. output = new AsyncStreamReader(this, s, new UserCallBack(this.OutputReadNotifyUser), standardOutput.CurrentEncoding);
  1440. }
  1441. output.BeginReadLine();
  1442. }
  1443. /// <devdoc>
  1444. /// <para>
  1445. /// Instructs the <see cref='System.Diagnostics.Process'/> component to start
  1446. /// reading the StandardError stream asynchronously. The user can register a callback
  1447. /// that will be called when a line of data terminated by \n,\r or \r\n is reached, or the end of stream is reached
  1448. /// then the remaining information is returned. The user can add an event handler to ErrorDataReceived.
  1449. /// </para>
  1450. /// </devdoc>
  1451. [System.Runtime.InteropServices.ComVisible(false)]
  1452. public void BeginErrorReadLine()
  1453. {
  1454. if (errorStreamReadMode == StreamReadMode.undefined)
  1455. {
  1456. errorStreamReadMode = StreamReadMode.asyncMode;
  1457. }
  1458. else if (errorStreamReadMode != StreamReadMode.asyncMode)
  1459. {
  1460. throw new InvalidOperationException("CantMixSyncAsyncOperation");
  1461. }
  1462. if (pendingErrorRead)
  1463. {
  1464. throw new InvalidOperationException("PendingAsyncOperation");
  1465. }
  1466. pendingErrorRead = true;
  1467. // We can't detect if there's a pending sychronous read, stream also doesn't.
  1468. if (error == null)
  1469. {
  1470. if (standardError == null)
  1471. {
  1472. throw new InvalidOperationException("CantGetStandardError");
  1473. }
  1474. Stream s = standardError.BaseStream;
  1475. error = new AsyncStreamReader(this, s, new UserCallBack(this.ErrorReadNotifyUser), standardError.CurrentEncoding);
  1476. }
  1477. error.BeginReadLine();
  1478. }
  1479. /// <devdoc>
  1480. /// <para>
  1481. /// Instructs the <see cref='System.Diagnostics.Process'/> component to cancel the asynchronous operation
  1482. /// specified by BeginOutputReadLine().
  1483. /// </para>
  1484. /// </devdoc>
  1485. [System.Runtime.InteropServices.ComVisible(false)]
  1486. public void CancelOutputRead()
  1487. {
  1488. if (output != null)
  1489. {
  1490. output.CancelOperation();
  1491. }
  1492. else
  1493. {
  1494. throw new InvalidOperationException("NoAsyncOperation");
  1495. }
  1496. pendingOutputRead = false;
  1497. }
  1498. /// <devdoc>
  1499. /// <para>
  1500. /// Instructs the <see cref='System.Diagnostics.Process'/> component to cancel the asynchronous operation
  1501. /// specified by BeginErrorReadLine().
  1502. /// </para>
  1503. /// </devdoc>
  1504. [System.Runtime.InteropServices.ComVisible(false)]
  1505. public void CancelErrorRead()
  1506. {
  1507. if (error != null)
  1508. {
  1509. error.CancelOperation();
  1510. }
  1511. else
  1512. {
  1513. throw new InvalidOperationException("No async operation.");
  1514. }
  1515. pendingErrorRead = false;
  1516. }
  1517. internal void OutputReadNotifyUser(String data)
  1518. {
  1519. // To avoid ---- between remove handler and raising the event
  1520. DataReceivedEventHandler outputDataReceived = OutputDataReceived;
  1521. if (outputDataReceived != null)
  1522. {
  1523. DataReceivedEventArgs e = new DataReceivedEventArgs(data);
  1524. if (SynchronizingObject != null && SynchronizingObject.InvokeRequired)
  1525. {
  1526. SynchronizingObject.Invoke(outputDataReceived, new object[]
  1527. {
  1528. this, e
  1529. });
  1530. }
  1531. else
  1532. {
  1533. outputDataReceived(this, e); // Call back to user informing data is available.
  1534. }
  1535. }
  1536. }
  1537. internal void ErrorReadNotifyUser(String data)
  1538. {
  1539. // To avoid ---- between remove handler and raising the event
  1540. DataReceivedEventHandler errorDataReceived = ErrorDataReceived;
  1541. if (errorDataReceived != null)
  1542. {
  1543. DataReceivedEventArgs e = new DataReceivedEventArgs(data);
  1544. if (SynchronizingObject != null && SynchronizingObject.InvokeRequired)
  1545. {
  1546. SynchronizingObject.Invoke(errorDataReceived, new object[]
  1547. {
  1548. this, e
  1549. });
  1550. }
  1551. else
  1552. {
  1553. errorDataReceived(this, e); // Call back to user informing data is available.
  1554. }
  1555. }
  1556. }
  1557. /// <summary>
  1558. /// A desired internal state.
  1559. /// </summary>
  1560. /// <internalonly/>
  1561. enum State
  1562. {
  1563. HaveId = 0x1,
  1564. IsLocal = 0x2,
  1565. IsNt = 0x4,
  1566. HaveProcessInfo = 0x8,
  1567. Exited = 0x10,
  1568. Associated = 0x20,
  1569. IsWin2k = 0x40,
  1570. HaveNtProcessInfo = HaveProcessInfo | IsNt
  1571. }
  1572. }
  1573. /// <devdoc>
  1574. /// This data structure contains information about a process that is collected
  1575. /// in bulk by querying the operating system. The reason to make this a separate
  1576. /// structure from the process component is so that we can throw it away all at once
  1577. /// when Refresh is called on the component.
  1578. /// </devdoc>
  1579. /// <internalonly/>
  1580. internal class ProcessInfo
  1581. {
  1582. public ArrayList threadInfoList = new ArrayList();
  1583. public int basePriority;
  1584. public string processName;
  1585. public int processId;
  1586. public int handleCount;
  1587. public long poolPagedBytes;
  1588. public long poolNonpagedBytes;
  1589. public long virtualBytes;
  1590. public long virtualBytesPeak;
  1591. public long workingSetPeak;
  1592. public long workingSet;
  1593. public long pageFileBytesPeak;
  1594. public long pageFileBytes;
  1595. public long privateBytes;
  1596. public int mainModuleId; // used only for win9x - id is only for use with CreateToolHelp32
  1597. public int sessionId;
  1598. }
  1599. /// <devdoc>
  1600. /// This data structure contains information about a thread in a process that
  1601. /// is collected in bulk by querying the operating system. The reason to
  1602. /// make this a separate structure from the ProcessThread component is so that we
  1603. /// can throw it away all at once when Refresh is called on the component.
  1604. /// </devdoc>
  1605. /// <internalonly/>
  1606. internal class ThreadInfo
  1607. {
  1608. public int threadId;
  1609. public int processId;
  1610. public int basePriority;
  1611. public int currentPriority;
  1612. public IntPtr startAddress;
  1613. public System.Diagnostics.ThreadState threadState;
  1614. public ThreadWaitReason threadWaitReason;
  1615. }
  1616. /// <devdoc>
  1617. /// This data structure contains information about a module in a process that
  1618. /// is collected in bulk by querying the operating system. The reason to
  1619. /// make this a separate structure from the ProcessModule component is so that we
  1620. /// can throw it away all at once when Refresh is called on the component.
  1621. /// </devdoc>
  1622. /// <internalonly/>
  1623. internal class ModuleInfo
  1624. {
  1625. public string baseName;
  1626. public string fileName;
  1627. public IntPtr baseOfDll;
  1628. public IntPtr entryPoint;
  1629. public int sizeOfImage;
  1630. public int Id; // used only on win9x - for matching up with ProcessInfo.mainModuleId
  1631. }
  1632. internal static class EnvironmentBlock
  1633. {
  1634. public static byte[] ToByteArray(StringDictionary sd, bool unicode)
  1635. {
  1636. // get the keys
  1637. string[] keys = new string[sd.Count];
  1638. byte[] envBlock = null;
  1639. sd.Keys.CopyTo(keys, 0);
  1640. // get the values
  1641. string[] values = new string[sd.Count];
  1642. sd.Values.CopyTo(values, 0);
  1643. // sort both by the keys
  1644. // Windows 2000 requires the environment block to be sorted by the key
  1645. // It will first converting the case the strings and do ordinal comparison.
  1646. Array.Sort(keys, values, OrdinalCaseInsensitiveComparer.Default);
  1647. // create a list of null terminated "key=val" strings
  1648. StringBuilder stringBuff = new StringBuilder();
  1649. for (int i = 0; i < sd.Count; ++i)
  1650. {
  1651. stringBuff.Append(keys[i]);
  1652. stringBuff.Append('=');
  1653. stringBuff.Append(values[i]);
  1654. stringBuff.Append('\0');
  1655. }
  1656. // an extra null at the end indicates end of list.
  1657. stringBuff.Append('\0');
  1658. if (unicode)
  1659. {
  1660. envBlock = Encoding.Unicode.GetBytes(stringBuff.ToString());
  1661. }
  1662. else
  1663. {
  1664. envBlock = Encoding.Default.GetBytes(stringBuff.ToString());
  1665. if (envBlock.Length > UInt16.MaxValue) throw new InvalidOperationException("Environment block is too long.");
  1666. }
  1667. return envBlock;
  1668. }
  1669. }
  1670. internal class OrdinalCaseInsensitiveComparer : IComparer
  1671. {
  1672. internal static readonly OrdinalCaseInsensitiveComparer Default = new OrdinalCaseInsensitiveComparer();
  1673. public int Compare(Object a, Object b)
  1674. {
  1675. String sa = a as String;
  1676. String sb = b as String;
  1677. if (sa != null && sb != null)
  1678. {
  1679. return String.Compare(sa, sb, StringComparison.OrdinalIgnoreCase);
  1680. }
  1681. return Comparer.Default.Compare(a, b);
  1682. }
  1683. }
  1684. internal class ShellExecuteHelper
  1685. {
  1686. private NativeMethods.ShellExecuteInfo _executeInfo;
  1687. private int _errorCode;
  1688. private bool _succeeded;
  1689. public ShellExecuteHelper(NativeMethods.ShellExecuteInfo executeInfo)
  1690. {
  1691. _executeInfo = executeInfo;
  1692. }
  1693. [ResourceExposure(ResourceScope.None)]
  1694. [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
  1695. public void ShellExecuteFunction()
  1696. {
  1697. if (!(_succeeded = NativeMethods.ShellExecuteEx(_executeInfo)))
  1698. {
  1699. _errorCode = Marshal.GetLastWin32Error();
  1700. }
  1701. }
  1702. public bool ShellExecuteOnSTAThread()
  1703. {
  1704. //
  1705. // SHELL API ShellExecute() requires STA in order to work correctly.
  1706. // If current thread is not a STA thread, we need to call ShellExecute on a new thread.
  1707. //
  1708. if (Thread.CurrentThread.GetApartmentState() != ApartmentState.STA)
  1709. {
  1710. ThreadStart threadStart = new ThreadStart(this.ShellExecuteFunction);
  1711. Thread executionThread = new Thread(threadStart);
  1712. executionThread.SetApartmentState(ApartmentState.STA);
  1713. executionThread.Start();
  1714. executionThread.Join();
  1715. }
  1716. else
  1717. {
  1718. ShellExecuteFunction();
  1719. }
  1720. return _succeeded;
  1721. }
  1722. public int ErrorCode
  1723. {
  1724. get
  1725. {
  1726. return _errorCode;
  1727. }
  1728. }
  1729. }
  1730. private static long[] CachedBuffer;
  1731. private static int GetNewBufferSize(int existingBufferSize, int requiredSize)
  1732. {
  1733. if (requiredSize == 0)
  1734. {
  1735. int num = existingBufferSize * 2;
  1736. return num >= existingBufferSize ? num : throw new OutOfMemoryException();
  1737. }
  1738. int num1 = requiredSize + 10240;
  1739. return num1 >= requiredSize ? num1 : throw new OutOfMemoryException();
  1740. }
  1741. internal static ProcessInfo GetProcessInfo(int processId, string machineName)
  1742. {
  1743. ProcessInfo[] processInfos = GetProcessInfos((Predicate<int>)(pid => pid == processId));
  1744. if (processInfos.Length == 1) return processInfos[0];
  1745. return (ProcessInfo)null;
  1746. }
  1747. internal static ProcessInfo[] GetProcessInfos(Predicate<int> processIdFilter = null)
  1748. {
  1749. int returnedSize = 0;
  1750. GCHandle gcHandle = new GCHandle();
  1751. int num = 131072;
  1752. long[] numArray = Interlocked.Exchange<long[]>(ref CachedBuffer, (long[])null);
  1753. try
  1754. {
  1755. int error;
  1756. do
  1757. {
  1758. if (numArray == null) numArray = new long[(num + 7) / 8];
  1759. else num = numArray.Length * 8;
  1760. gcHandle = GCHandle.Alloc((object)numArray, GCHandleType.Pinned);
  1761. error = NativeMethods.NtQuerySystemInformation(5, gcHandle.AddrOfPinnedObject(), num, out returnedSize);
  1762. if (error == -1073741820)
  1763. {
  1764. if (gcHandle.IsAllocated) gcHandle.Free();
  1765. numArray = (long[])null;
  1766. num = GetNewBufferSize(num, returnedSize);
  1767. }
  1768. } while (error == -1073741820);
  1769. if (error < 0) throw new InvalidOperationException("CouldntGetProcessInfos", (Exception)new Win32Exception(error));
  1770. return GetProcessInfos(gcHandle.AddrOfPinnedObject(), processIdFilter);
  1771. }
  1772. finally
  1773. {
  1774. Interlocked.Exchange<long[]>(ref CachedBuffer, numArray);
  1775. if (gcHandle.IsAllocated) gcHandle.Free();
  1776. }
  1777. }
  1778. private static ProcessInfo[] GetProcessInfos(IntPtr dataPtr, Predicate<int> processIdFilter)
  1779. {
  1780. Hashtable hashtable = new Hashtable(60);
  1781. long num = 0;
  1782. while (true)
  1783. {
  1784. IntPtr ptr1 = (IntPtr)((long)dataPtr + num);
  1785. NativeMethods.SystemProcessInformation structure1 = new NativeMethods.SystemProcessInformation();
  1786. Marshal.PtrToStructure(ptr1, (object)structure1);
  1787. int int32 = structure1.UniqueProcessId.ToInt32();
  1788. if (processIdFilter == null || processIdFilter(int32))
  1789. {
  1790. ProcessInfo processInfo = new ProcessInfo();
  1791. processInfo.processId = int32;
  1792. processInfo.handleCount = (int)structure1.HandleCount;
  1793. processInfo.sessionId = (int)structure1.SessionId;
  1794. processInfo.poolPagedBytes = (long)(ulong)structure1.QuotaPagedPoolUsage;
  1795. processInfo.poolNonpagedBytes = (long)(ulong)structure1.QuotaNonPagedPoolUsage;
  1796. processInfo.virtualBytes = (long)(ulong)structure1.VirtualSize;
  1797. processInfo.virtualBytesPeak = (long)(ulong)structure1.PeakVirtualSize;
  1798. processInfo.workingSetPeak = (long)(ulong)structure1.PeakWorkingSetSize;
  1799. processInfo.workingSet = (long)(ulong)structure1.WorkingSetSize;
  1800. processInfo.pageFileBytesPeak = (long)(ulong)structure1.PeakPagefileUsage;
  1801. processInfo.pageFileBytes = (long)(ulong)structure1.PagefileUsage;
  1802. processInfo.privateBytes = (long)(ulong)structure1.PrivatePageCount;
  1803. processInfo.basePriority = structure1.BasePriority;
  1804. if (structure1.NamePtr == IntPtr.Zero)
  1805. {
  1806. processInfo.processName = processInfo.processId != 4 ?
  1807. (processInfo.processId != 0 ? processInfo.processId.ToString((IFormatProvider)CultureInfo.InvariantCulture) : "Idle") : "System";
  1808. }
  1809. else
  1810. {
  1811. string str = GetProcessShortName(Marshal.PtrToStringUni(structure1.NamePtr, (int)structure1.NameLength / 2));
  1812. processInfo.processName = str;
  1813. }
  1814. hashtable[(object)processInfo.processId] = (object)processInfo;
  1815. IntPtr ptr2 = (IntPtr)((long)ptr1 + (long)Marshal.SizeOf((object)structure1));
  1816. for (int index = 0; (long)index < (long)structure1.NumberOfThreads; ++index)
  1817. {
  1818. NativeMethods.SystemThreadInformation structure2 = new NativeMethods.SystemThreadInformation();
  1819. Marshal.PtrToStructure(ptr2, (object)structure2);
  1820. processInfo.threadInfoList.Add((object)new ThreadInfo()
  1821. {
  1822. processId = (int)structure2.UniqueProcess,
  1823. threadId = (int)structure2.UniqueThread,
  1824. basePriority = structure2.BasePriority,
  1825. currentPriority = structure2.Priority,
  1826. startAddress = structure2.StartAddress,
  1827. threadState = (System.Diagnostics.ThreadState)structure2.ThreadState,
  1828. threadWaitReason = GetThreadWaitReason((int)structure2.WaitReason)
  1829. });
  1830. ptr2 = (IntPtr)((long)ptr2 + (long)Marshal.SizeOf((object)structure2));
  1831. }
  1832. }
  1833. if (structure1.NextEntryOffset != 0U) num += (long)structure1.NextEntryOffset;
  1834. else break;
  1835. }
  1836. ProcessInfo[] processInfos = new ProcessInfo[hashtable.Values.Count];
  1837. hashtable.Values.CopyTo((Array)processInfos, 0);
  1838. return processInfos;
  1839. }
  1840. internal static ThreadWaitReason GetThreadWaitReason(int value)
  1841. {
  1842. switch (value)
  1843. {
  1844. case 0:
  1845. case 7:
  1846. return ThreadWaitReason.Executive;
  1847. case 1:
  1848. case 8:
  1849. return ThreadWaitReason.FreePage;
  1850. case 2:
  1851. case 9:
  1852. return ThreadWaitReason.PageIn;
  1853. case 3:
  1854. case 10:
  1855. return ThreadWaitReason.SystemAllocation;
  1856. case 4:
  1857. case 11:
  1858. return ThreadWaitReason.ExecutionDelay;
  1859. case 5:
  1860. case 12:
  1861. return ThreadWaitReason.Suspended;
  1862. case 6:
  1863. case 13:
  1864. return ThreadWaitReason.UserRequest;
  1865. case 14:
  1866. return ThreadWaitReason.EventPairHigh;
  1867. case 15:
  1868. return ThreadWaitReason.EventPairLow;
  1869. case 16:
  1870. return ThreadWaitReason.LpcReceive;
  1871. case 17:
  1872. return ThreadWaitReason.LpcReply;
  1873. case 18:
  1874. return ThreadWaitReason.VirtualMemory;
  1875. case 19:
  1876. return ThreadWaitReason.PageOut;
  1877. default:
  1878. return ThreadWaitReason.Unknown;
  1879. }
  1880. }
  1881. internal static string GetProcessShortName(string name)
  1882. {
  1883. if (string.IsNullOrEmpty(name))
  1884. return string.Empty;
  1885. int num1 = -1;
  1886. int startIndex1 = -1;
  1887. for (int index = 0; index < name.Length; ++index)
  1888. {
  1889. if (name[index] == '\\')
  1890. num1 = index;
  1891. else if (name[index] == '.')
  1892. startIndex1 = index;
  1893. }
  1894. int num2 = startIndex1 != -1 ? (!string.Equals(".exe", name.Substring(startIndex1), StringComparison.OrdinalIgnoreCase) ? name.Length - 1 : startIndex1 - 1) : name.Length - 1;
  1895. int startIndex2 = num1 != -1 ? num1 + 1 : 0;
  1896. return name.Substring(startIndex2, num2 - startIndex2 + 1);
  1897. }
  1898. [HostProtection(MayLeakOnAbort = true)]
  1899. internal static class NativeMethods
  1900. {
  1901. public static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
  1902. public const int STARTF_USESTDHANDLES = 0x00000100;
  1903. public const int STD_INPUT_HANDLE = -10;
  1904. public const int STD_OUTPUT_HANDLE = -11;
  1905. public const int STD_ERROR_HANDLE = -12;
  1906. public const int STILL_ACTIVE = 0x00000103;
  1907. public const int SW_HIDE = 0;
  1908. public const int WAIT_OBJECT_0 = 0x00000000;
  1909. public const int WAIT_FAILED = unchecked((int)0xFFFFFFFF);
  1910. public const int WAIT_TIMEOUT = 0x00000102;
  1911. public const int WAIT_ABANDONED = 0x00000080;
  1912. public const int ERROR_BAD_EXE_FORMAT = 193;
  1913. public const int ERROR_EXE_MACHINE_TYPE_MISMATCH = 216;
  1914. [DllImport("ntdll.dll", CharSet = CharSet.Auto)]
  1915. public static extern int NtQuerySystemInformation(
  1916. int query,
  1917. IntPtr dataPtr,
  1918. int size,
  1919. out int returnedSize);
  1920. [StructLayout(LayoutKind.Sequential)]
  1921. internal class SystemProcessInformation
  1922. {
  1923. internal uint NextEntryOffset;
  1924. internal uint NumberOfThreads;
  1925. private long SpareLi1;
  1926. private long SpareLi2;
  1927. private long SpareLi3;
  1928. private long CreateTime;
  1929. private long UserTime;
  1930. private long KernelTime;
  1931. internal ushort NameLength;
  1932. internal ushort MaximumNameLength;
  1933. internal IntPtr NamePtr;
  1934. internal int BasePriority;
  1935. internal IntPtr UniqueProcessId;
  1936. internal IntPtr InheritedFromUniqueProcessId;
  1937. internal uint HandleCount;
  1938. internal uint SessionId;
  1939. internal UIntPtr PageDirectoryBase;
  1940. internal UIntPtr PeakVirtualSize;
  1941. internal UIntPtr VirtualSize;
  1942. internal uint PageFaultCount;
  1943. internal UIntPtr PeakWorkingSetSize;
  1944. internal UIntPtr WorkingSetSize;
  1945. internal UIntPtr QuotaPeakPagedPoolUsage;
  1946. internal UIntPtr QuotaPagedPoolUsage;
  1947. internal UIntPtr QuotaPeakNonPagedPoolUsage;
  1948. internal UIntPtr QuotaNonPagedPoolUsage;
  1949. internal UIntPtr PagefileUsage;
  1950. internal UIntPtr PeakPagefileUsage;
  1951. internal UIntPtr PrivatePageCount;
  1952. private long ReadOperationCount;
  1953. private long WriteOperationCount;
  1954. private long OtherOperationCount;
  1955. private long ReadTransferCount;
  1956. private long WriteTransferCount;
  1957. private long OtherTransferCount;
  1958. }
  1959. [StructLayout(LayoutKind.Sequential)]
  1960. internal class SystemThreadInformation
  1961. {
  1962. private long KernelTime;
  1963. private long UserTime;
  1964. private long CreateTime;
  1965. private uint WaitTime;
  1966. internal IntPtr StartAddress;
  1967. internal IntPtr UniqueProcess;
  1968. internal IntPtr UniqueThread;
  1969. internal int Priority;
  1970. internal int BasePriority;
  1971. internal uint ContextSwitches;
  1972. internal uint ThreadState;
  1973. internal uint WaitReason;
  1974. }
  1975. [StructLayout(LayoutKind.Sequential)]
  1976. internal class STARTUPINFO
  1977. {
  1978. public int cb;
  1979. public IntPtr lpReserved = IntPtr.Zero;
  1980. public string lpDesktop = null;
  1981. public IntPtr lpTitle = IntPtr.Zero;
  1982. public int dwX = 0;
  1983. public int dwY = 0;
  1984. public int dwXSize = 0;
  1985. public int dwYSize = 0;
  1986. public int dwXCountChars = 0;
  1987. public int dwYCountChars = 0;
  1988. public int dwFillAttribute = 0;
  1989. public int dwFlags;
  1990. public short wShowWindow = 0;
  1991. public short cbReserved2 = 0;
  1992. public IntPtr lpReserved2 = IntPtr.Zero;
  1993. public SafeFileHandle hStdInput = new SafeFileHandle(IntPtr.Zero, false);
  1994. public SafeFileHandle hStdOutput = new SafeFileHandle(IntPtr.Zero, false);
  1995. public SafeFileHandle hStdError = new SafeFileHandle(IntPtr.Zero, false);
  1996. public STARTUPINFO()
  1997. {
  1998. cb = Marshal.SizeOf(this);
  1999. }
  2000. public void Dispose()
  2001. {
  2002. // close the handles created for child process
  2003. if (hStdInput != null && !hStdInput.IsInvalid)
  2004. {
  2005. hStdInput.Close();
  2006. hStdInput = null;
  2007. }
  2008. if (hStdOutput != null && !hStdOutput.IsInvalid)
  2009. {
  2010. hStdOutput.Close();
  2011. hStdOutput = null;
  2012. }
  2013. if (hStdError != null && !hStdError.IsInvalid)
  2014. {
  2015. hStdError.Close();
  2016. hStdError = null;
  2017. }
  2018. }
  2019. }
  2020. [StructLayout(LayoutKind.Sequential)]
  2021. internal class SECURITY_ATTRIBUTES
  2022. {
  2023. public int nLength = 12;
  2024. public SafeLocalMemHandle lpSecurityDescriptor = new SafeLocalMemHandle(IntPtr.Zero, false);
  2025. public bool bInheritHandle;
  2026. }
  2027. [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
  2028. [ResourceExposure(ResourceScope.None)]
  2029. public static extern bool GetExitCodeProcess(SafeProcessHandle processHandle, out int exitCode);
  2030. [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
  2031. [ResourceExposure(ResourceScope.None)]
  2032. public static extern bool GetProcessTimes(SafeProcessHandle handle, out long creation, out long exit, out long kernel, out long user);
  2033. [DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
  2034. [ResourceExposure(ResourceScope.Process)]
  2035. public static extern IntPtr GetStdHandle(int whichHandle);
  2036. [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
  2037. [ResourceExposure(ResourceScope.Process)]
  2038. public static extern bool CreatePipe(out SafeFileHandle hReadPipe, out SafeFileHandle hWritePipe, SECURITY_ATTRIBUTES lpPipeAttributes, int nSize);
  2039. [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true, BestFitMapping = false)]
  2040. [ResourceExposure(ResourceScope.Process)]
  2041. public static extern bool CreateProcess([MarshalAs(UnmanagedType.LPTStr)] string lpApplicationName, // LPCTSTR
  2042. StringBuilder lpCommandLine, // LPTSTR - note: CreateProcess might insert a null somewhere in this string
  2043. SECURITY_ATTRIBUTES lpProcessAttributes, // LPSECURITY_ATTRIBUTES
  2044. SECURITY_ATTRIBUTES lpThreadAttributes, // LPSECURITY_ATTRIBUTES
  2045. bool bInheritHandles, // BOOL
  2046. int dwCreationFlags, // DWORD
  2047. IntPtr lpEnvironment, // LPVOID
  2048. [MarshalAs(UnmanagedType.LPTStr)] string lpCurrentDirectory, // LPCTSTR
  2049. STARTUPINFO lpStartupInfo, // LPSTARTUPINFO
  2050. PROCESS_INFORMATION lpProcessInformation // LPPROCESS_INFORMATION
  2051. );
  2052. [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
  2053. [ResourceExposure(ResourceScope.Machine)]
  2054. public static extern bool TerminateProcess(SafeProcessHandle processHandle, int exitCode);
  2055. [DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
  2056. [ResourceExposure(ResourceScope.Process)]
  2057. public static extern IntPtr GetCurrentProcess();
  2058. [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true, BestFitMapping = false)]
  2059. [SuppressUnmanagedCodeSecurityAttribute]
  2060. [ResourceExposure(ResourceScope.Machine)]
  2061. public static extern bool CreateProcessAsUser(Win32.TokensEx.SafeTokenHandle hToken, string lpApplicationName, StringBuilder lpCommandLine, SECURITY_ATTRIBUTES lpProcessAttributes, SECURITY_ATTRIBUTES lpThreadAttributes,
  2062. bool bInheritHandles, int dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory, STARTUPINFO lpStartupInfo, PROCESS_INFORMATION lpProcessInformation);
  2063. [DllImport("advapi32", SetLastError = true, CharSet = CharSet.Auto)]
  2064. internal static extern bool CreateProcessWithToken(
  2065. Win32.TokensEx.SafeTokenHandle hToken,
  2066. LogonFlags dwLogonFlags,
  2067. string lpApplicationName,
  2068. StringBuilder lpCommandLine,
  2069. int dwCreationFlags,
  2070. IntPtr lpEnvironment,
  2071. string lpCurrentDirectory,
  2072. STARTUPINFO lpStartupInfo,
  2073. PROCESS_INFORMATION lpProcessInformation);
  2074. [DllImport("advapi32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true, BestFitMapping = false)]
  2075. [ResourceExposure(ResourceScope.Machine)]
  2076. internal static extern bool CreateProcessWithLogonW(string userName, string domain, IntPtr password, LogonFlags logonFlags, [MarshalAs(UnmanagedType.LPTStr)] string appName,
  2077. StringBuilder cmdLine, int creationFlags, IntPtr environmentBlock, [MarshalAs(UnmanagedType.LPTStr)] string lpCurrentDirectory, // LPCTSTR
  2078. STARTUPINFO lpStartupInfo, PROCESS_INFORMATION lpProcessInformation);
  2079. //TODO: TOKEN
  2080. [StructLayout(LayoutKind.Sequential)]
  2081. internal class PROCESS_INFORMATION
  2082. {
  2083. public IntPtr hProcess = IntPtr.Zero;
  2084. public IntPtr hThread = IntPtr.Zero;
  2085. public int dwProcessId = 0;
  2086. public int dwThreadId = 0;
  2087. }
  2088. [Flags]
  2089. internal enum LogonFlags
  2090. {
  2091. LOGON_WITH_PROFILE = 0x00000001,
  2092. LOGON_NETCREDENTIALS_ONLY = 0x00000002
  2093. }
  2094. public const int QS_KEY = 0x0001,
  2095. QS_MOUSEMOVE = 0x0002,
  2096. QS_MOUSEBUTTON = 0x0004,
  2097. QS_POSTMESSAGE = 0x0008,
  2098. QS_TIMER = 0x0010,
  2099. QS_PAINT = 0x0020,
  2100. QS_SENDMESSAGE = 0x0040,
  2101. QS_HOTKEY = 0x0080,
  2102. QS_ALLPOSTMESSAGE = 0x0100,
  2103. QS_MOUSE = QS_MOUSEMOVE | QS_MOUSEBUTTON,
  2104. QS_INPUT = QS_MOUSE | QS_KEY,
  2105. QS_ALLEVENTS = QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY,
  2106. QS_ALLINPUT = QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY | QS_SENDMESSAGE;
  2107. [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
  2108. [ResourceExposure(ResourceScope.None)]
  2109. public static extern int WaitForInputIdle(SafeProcessHandle handle, int milliseconds);
  2110. [DllImport("shell32.dll", CharSet = CharSet.Auto, SetLastError = true)]
  2111. [ResourceExposure(ResourceScope.Machine)]
  2112. public static extern bool ShellExecuteEx(ShellExecuteInfo info);
  2113. [DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true, BestFitMapping = false)]
  2114. [ResourceExposure(ResourceScope.Machine)]
  2115. public static extern bool DuplicateHandle(HandleRef hSourceProcessHandle, SafeHandle hSourceHandle, HandleRef hTargetProcess, out SafeFileHandle targetHandle, int dwDesiredAccess,
  2116. bool bInheritHandle, int dwOptions);
  2117. [DllImport("kernel32.dll", CharSet = System.Runtime.InteropServices.CharSet.Ansi, SetLastError = true, BestFitMapping = false)]
  2118. [ResourceExposure(ResourceScope.Machine)]
  2119. public static extern bool DuplicateHandle(HandleRef hSourceProcessHandle, SafeHandle hSourceHandle, HandleRef hTargetProcess, out SafeWaitHandle targetHandle, int dwDesiredAccess,
  2120. bool bInheritHandle, int dwOptions);
  2121. [DllImport("user32.dll", CharSet = CharSet.Auto, BestFitMapping = true)]
  2122. [ResourceExposure(ResourceScope.None)]
  2123. public static extern int GetWindowText(HandleRef hWnd, StringBuilder lpString, int nMaxCount);
  2124. [DllImport("user32.dll", CharSet = CharSet.Auto)]
  2125. [ResourceExposure(ResourceScope.None)]
  2126. public static extern int GetWindowTextLength(HandleRef hWnd);
  2127. [DllImport("user32.dll", CharSet = CharSet.Auto)]
  2128. [ResourceExposure(ResourceScope.None)]
  2129. public static extern IntPtr SendMessageTimeout(HandleRef hWnd, int msg, IntPtr wParam, IntPtr lParam, int flags, int timeout, out IntPtr pdwResult);
  2130. [DllImport("user32.dll", CharSet = CharSet.Auto)]
  2131. [ResourceExposure(ResourceScope.None)]
  2132. public static extern int GetWindowLong(HandleRef hWnd, int nIndex);
  2133. [DllImport("user32.dll", CharSet = CharSet.Auto)]
  2134. [ResourceExposure(ResourceScope.None)]
  2135. public static extern int PostMessage(HandleRef hwnd, int msg, IntPtr wparam, IntPtr lparam);
  2136. [StructLayout(LayoutKind.Sequential)]
  2137. internal class ShellExecuteInfo
  2138. {
  2139. public int cbSize;
  2140. public int fMask;
  2141. public IntPtr hwnd = (IntPtr)0;
  2142. public IntPtr lpVerb = (IntPtr)0;
  2143. public IntPtr lpFile = (IntPtr)0;
  2144. public IntPtr lpParameters = (IntPtr)0;
  2145. public IntPtr lpDirectory = (IntPtr)0;
  2146. public int nShow;
  2147. public IntPtr hInstApp = (IntPtr)0;
  2148. public IntPtr lpIDList = (IntPtr)0;
  2149. public IntPtr lpClass = (IntPtr)0;
  2150. public IntPtr hkeyClass = (IntPtr)0;
  2151. public int dwHotKey = 0;
  2152. public IntPtr hIcon = (IntPtr)0;
  2153. public IntPtr hProcess = (IntPtr)0;
  2154. [ResourceExposure(ResourceScope.Machine)]
  2155. public ShellExecuteInfo()
  2156. {
  2157. cbSize = Marshal.SizeOf(this);
  2158. }
  2159. }
  2160. [StructLayout(LayoutKind.Sequential)]
  2161. internal struct LUID
  2162. {
  2163. public int LowPart;
  2164. public int HighPart;
  2165. }
  2166. public const int SEE_MASK_NOCLOSEPROCESS = 0x00000040;
  2167. public const int SEE_MASK_CONNECTNETDRV = 0x00000080;
  2168. public const int SEE_MASK_FLAG_DDEWAIT = 0x00000100;
  2169. public const int SEE_MASK_DOENVSUBST = 0x00000200;
  2170. public const int SEE_MASK_FLAG_NO_UI = 0x00000400;
  2171. public const int PROCESS_TERMINATE = 0x0001;
  2172. public const int PROCESS_QUERY_INFORMATION = 0x0400;
  2173. public const int PROCESS_QUERY_LIMITED_INFORMATION = 0x1000;
  2174. public const int STANDARD_RIGHTS_REQUIRED = 0x000F0000;
  2175. public const int SYNCHRONIZE = 0x00100000;
  2176. public const int PROCESS_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFF;
  2177. public const int READ_CONTROL = 0x00020000;
  2178. public const int STANDARD_RIGHTS_READ = READ_CONTROL;
  2179. public const int KEY_QUERY_VALUE = 0x0001;
  2180. public const int KEY_ENUMERATE_SUB_KEYS = 0x0008;
  2181. public const int KEY_NOTIFY = 0x0010;
  2182. public const int ERROR_BROKEN_PIPE = 109;
  2183. public const int ERROR_NO_DATA = 232;
  2184. public const int ERROR_HANDLE_EOF = 38;
  2185. public const int ERROR_IO_INCOMPLETE = 996;
  2186. public const int ERROR_IO_PENDING = 997;
  2187. public const int ERROR_FILE_EXISTS = 0x50;
  2188. public const int ERROR_FILENAME_EXCED_RANGE = 0xCE; // filename too long.
  2189. public const int ERROR_MORE_DATA = 234;
  2190. public const int ERROR_CANCELLED = 1223;
  2191. public const int ERROR_FILE_NOT_FOUND = 2;
  2192. public const int ERROR_PATH_NOT_FOUND = 3;
  2193. public const int ERROR_ACCESS_DENIED = 5;
  2194. public const int ERROR_INVALID_HANDLE = 6;
  2195. public const int ERROR_NOT_ENOUGH_MEMORY = 8;
  2196. public const int ERROR_BAD_COMMAND = 22;
  2197. public const int ERROR_SHARING_VIOLATION = 32;
  2198. public const int ERROR_OPERATION_ABORTED = 995;
  2199. public const int ERROR_NO_ASSOCIATION = 1155;
  2200. public const int ERROR_DLL_NOT_FOUND = 1157;
  2201. public const int ERROR_DDE_FAIL = 1156;
  2202. public const int ERROR_INVALID_PARAMETER = 87;
  2203. public const int ERROR_PARTIAL_COPY = 299;
  2204. public const int ERROR_SUCCESS = 0;
  2205. public const int ERROR_ALREADY_EXISTS = 183;
  2206. public const int ERROR_COUNTER_TIMEOUT = 1121;
  2207. public const int DUPLICATE_CLOSE_SOURCE = 1;
  2208. public const int DUPLICATE_SAME_ACCESS = 2;
  2209. public const int SE_ERR_FNF = 2;
  2210. public const int SE_ERR_PNF = 3;
  2211. public const int SE_ERR_ACCESSDENIED = 5;
  2212. public const int SE_ERR_OOM = 8;
  2213. public const int SE_ERR_DLLNOTFOUND = 32;
  2214. public const int SE_ERR_SHARE = 26;
  2215. public const int SE_ERR_ASSOCINCOMPLETE = 27;
  2216. public const int SE_ERR_DDETIMEOUT = 28;
  2217. public const int SE_ERR_DDEFAIL = 29;
  2218. public const int SE_ERR_DDEBUSY = 30;
  2219. public const int SE_ERR_NOASSOC = 31;
  2220. public const int CREATE_NO_WINDOW = 0x08000000;
  2221. public const int CREATE_SUSPENDED = 0x00000004;
  2222. public const int CREATE_UNICODE_ENVIRONMENT = 0x00000400;
  2223. public const int SMTO_ABORTIFHUNG = 0x0002;
  2224. public const int GWL_STYLE = -16;
  2225. public const int GCL_WNDPROC = -24;
  2226. public const int GWL_WNDPROC = -4;
  2227. public const int WS_DISABLED = 0x08000000;
  2228. public const int WM_NULL = 0x0000;
  2229. public const int WM_CLOSE = 0x0010;
  2230. public const int SW_SHOWNORMAL = 1;
  2231. public const int SW_NORMAL = 1;
  2232. public const int SW_SHOWMINIMIZED = 2;
  2233. public const int SW_SHOWMAXIMIZED = 3;
  2234. public const int SW_MAXIMIZE = 3;
  2235. public const int SW_SHOWNOACTIVATE = 4;
  2236. public const int SW_SHOW = 5;
  2237. public const int SW_MINIMIZE = 6;
  2238. public const int SW_SHOWMINNOACTIVE = 7;
  2239. public const int SW_SHOWNA = 8;
  2240. public const int SW_RESTORE = 9;
  2241. public const int SW_SHOWDEFAULT = 10;
  2242. public const int SW_MAX = 10;
  2243. public const int GW_OWNER = 4;
  2244. public const int WHITENESS = 0x00FF0062;
  2245. }
  2246. internal delegate void UserCallBack(String data);
  2247. internal class AsyncStreamReader : IDisposable
  2248. {
  2249. internal const int DefaultBufferSize = 1024; // Byte buffer size
  2250. private const int MinBufferSize = 128;
  2251. private Stream stream;
  2252. private Encoding encoding;
  2253. private Decoder decoder;
  2254. private byte[] byteBuffer;
  2255. private char[] charBuffer;
  2256. // Record the number of valid bytes in the byteBuffer, for a few checks.
  2257. // This is the maximum number of chars we can get from one call to
  2258. // ReadBuffer. Used so ReadBuffer can tell when to copy data into
  2259. // a user's char[] directly, instead of our internal char[].
  2260. private int _maxCharsPerBuffer;
  2261. // Store a backpointer to the process class, to check for user callbacks
  2262. private Process process;
  2263. // Delegate to call user function.
  2264. private UserCallBack userCallBack;
  2265. // Internal Cancel operation
  2266. private bool cancelOperation;
  2267. private ManualResetEvent eofEvent;
  2268. private Queue messageQueue;
  2269. private StringBuilder sb;
  2270. private bool bLastCarriageReturn;
  2271. // Cache the last position scanned in sb when searching for lines.
  2272. private int currentLinePos;
  2273. internal AsyncStreamReader(Process process, Stream stream, UserCallBack callback, Encoding encoding) : this(process, stream, callback, encoding, DefaultBufferSize) { }
  2274. // Creates a new AsyncStreamReader for the given stream. The
  2275. // character encoding is set by encoding and the buffer size,
  2276. // in number of 16-bit characters, is set by bufferSize.
  2277. //
  2278. internal AsyncStreamReader(Process process, Stream stream, UserCallBack callback, Encoding encoding, int bufferSize)
  2279. {
  2280. Init(process, stream, callback, encoding, bufferSize);
  2281. messageQueue = new Queue();
  2282. }
  2283. private void Init(Process process, Stream stream, UserCallBack callback, Encoding encoding, int bufferSize)
  2284. {
  2285. this.process = process;
  2286. this.stream = stream;
  2287. this.encoding = encoding;
  2288. this.userCallBack = callback;
  2289. decoder = encoding.GetDecoder();
  2290. if (bufferSize < MinBufferSize) bufferSize = MinBufferSize;
  2291. byteBuffer = new byte[bufferSize];
  2292. _maxCharsPerBuffer = encoding.GetMaxCharCount(bufferSize);
  2293. charBuffer = new char[_maxCharsPerBuffer];
  2294. cancelOperation = false;
  2295. eofEvent = new ManualResetEvent(false);
  2296. sb = null;
  2297. this.bLastCarriageReturn = false;
  2298. }
  2299. public virtual void Close()
  2300. {
  2301. Dispose(true);
  2302. }
  2303. void IDisposable.Dispose()
  2304. {
  2305. Dispose(true);
  2306. GC.SuppressFinalize(this);
  2307. }
  2308. protected virtual void Dispose(bool disposing)
  2309. {
  2310. if (disposing)
  2311. {
  2312. if (stream != null) stream.Close();
  2313. }
  2314. if (stream != null)
  2315. {
  2316. stream = null;
  2317. encoding = null;
  2318. decoder = null;
  2319. byteBuffer = null;
  2320. charBuffer = null;
  2321. }
  2322. if (eofEvent != null)
  2323. {
  2324. eofEvent.Close();
  2325. eofEvent = null;
  2326. }
  2327. }
  2328. public virtual Encoding CurrentEncoding
  2329. {
  2330. get
  2331. {
  2332. return encoding;
  2333. }
  2334. }
  2335. public virtual Stream BaseStream
  2336. {
  2337. get
  2338. {
  2339. return stream;
  2340. }
  2341. }
  2342. // User calls BeginRead to start the asynchronous read
  2343. internal void BeginReadLine()
  2344. {
  2345. if (cancelOperation)
  2346. {
  2347. cancelOperation = false;
  2348. }
  2349. if (sb == null)
  2350. {
  2351. sb = new StringBuilder(DefaultBufferSize);
  2352. stream.BeginRead(byteBuffer, 0, byteBuffer.Length, new AsyncCallback(ReadBuffer), null);
  2353. }
  2354. else
  2355. {
  2356. FlushMessageQueue();
  2357. }
  2358. }
  2359. internal void CancelOperation()
  2360. {
  2361. cancelOperation = true;
  2362. }
  2363. // This is the async callback function. Only one thread could/should call this.
  2364. private void ReadBuffer(IAsyncResult ar)
  2365. {
  2366. int byteLen;
  2367. try
  2368. {
  2369. byteLen = stream.EndRead(ar);
  2370. }
  2371. catch (IOException)
  2372. {
  2373. // We should ideally consume errors from operations getting cancelled
  2374. // so that we don't crash the unsuspecting parent with an unhandled exc.
  2375. // This seems to come in 2 forms of exceptions (depending on platform and scenario),
  2376. // namely OperationCanceledException and IOException (for errorcode that we don't
  2377. // map explicitly).
  2378. byteLen = 0; // Treat this as EOF
  2379. }
  2380. catch (OperationCanceledException)
  2381. {
  2382. // We should consume any OperationCanceledException from child read here
  2383. // so that we don't crash the parent with an unhandled exc
  2384. byteLen = 0; // Treat this as EOF
  2385. }
  2386. if (byteLen == 0)
  2387. {
  2388. // We're at EOF, we won't call this function again from here on.
  2389. lock (messageQueue)
  2390. {
  2391. if (sb.Length != 0)
  2392. {
  2393. messageQueue.Enqueue(sb.ToString());
  2394. sb.Length = 0;
  2395. }
  2396. messageQueue.Enqueue(null);
  2397. }
  2398. try
  2399. {
  2400. // UserCallback could throw, we should still set the eofEvent
  2401. FlushMessageQueue();
  2402. }
  2403. finally
  2404. {
  2405. eofEvent.Set();
  2406. }
  2407. }
  2408. else
  2409. {
  2410. int charLen = decoder.GetChars(byteBuffer, 0, byteLen, charBuffer, 0);
  2411. sb.Append(charBuffer, 0, charLen);
  2412. GetLinesFromStringBuilder();
  2413. stream.BeginRead(byteBuffer, 0, byteBuffer.Length, new AsyncCallback(ReadBuffer), null);
  2414. }
  2415. }
  2416. // Read lines stored in StringBuilder and the buffer we just read into.
  2417. // A line is defined as a sequence of characters followed by
  2418. // a carriage return ('\r'), a line feed ('\n'), or a carriage return
  2419. // immediately followed by a line feed. The resulting string does not
  2420. // contain the terminating carriage return and/or line feed. The returned
  2421. // value is null if the end of the input stream has been reached.
  2422. //
  2423. private void GetLinesFromStringBuilder()
  2424. {
  2425. int currentIndex = currentLinePos;
  2426. int lineStart = 0;
  2427. int len = sb.Length;
  2428. // skip a beginning '\n' character of new block if last block ended
  2429. // with '\r'
  2430. if (bLastCarriageReturn && (len > 0) && sb[0] == '\n')
  2431. {
  2432. currentIndex = 1;
  2433. lineStart = 1;
  2434. bLastCarriageReturn = false;
  2435. }
  2436. while (currentIndex < len)
  2437. {
  2438. char ch = sb[currentIndex];
  2439. // Note the following common line feed chars:
  2440. // \n - UNIX \r\n - DOS \r - Mac
  2441. if (ch == '\r' || ch == '\n')
  2442. {
  2443. string s = sb.ToString(lineStart, currentIndex - lineStart);
  2444. lineStart = currentIndex + 1;
  2445. // skip the "\n" character following "\r" character
  2446. if ((ch == '\r') && (lineStart < len) && (sb[lineStart] == '\n'))
  2447. {
  2448. lineStart++;
  2449. currentIndex++;
  2450. }
  2451. lock (messageQueue)
  2452. {
  2453. messageQueue.Enqueue(s);
  2454. }
  2455. }
  2456. currentIndex++;
  2457. }
  2458. // Protect length as IndexOutOfRangeException was being thrown when less than a
  2459. // character's worth of bytes was read at the beginning of a line.
  2460. if (len > 0 && sb[len - 1] == '\r')
  2461. {
  2462. bLastCarriageReturn = true;
  2463. }
  2464. // Keep the rest characaters which can't form a new line in string builder.
  2465. if (lineStart < len)
  2466. {
  2467. if (lineStart == 0)
  2468. {
  2469. // we found no breaklines, in this case we cache the position
  2470. // so next time we don't have to restart from the beginning
  2471. currentLinePos = currentIndex;
  2472. }
  2473. else
  2474. {
  2475. sb.Remove(0, lineStart);
  2476. currentLinePos = 0;
  2477. }
  2478. }
  2479. else
  2480. {
  2481. sb.Length = 0;
  2482. currentLinePos = 0;
  2483. }
  2484. FlushMessageQueue();
  2485. }
  2486. private void FlushMessageQueue()
  2487. {
  2488. while (true)
  2489. {
  2490. // When we call BeginReadLine, we also need to flush the queue
  2491. // So there could be a ---- between the ReadBuffer and BeginReadLine
  2492. // We need to take lock before DeQueue.
  2493. if (messageQueue.Count > 0)
  2494. {
  2495. lock (messageQueue)
  2496. {
  2497. if (messageQueue.Count > 0)
  2498. {
  2499. string s = (string)messageQueue.Dequeue();
  2500. // skip if the read is the read is cancelled
  2501. // this might happen inside UserCallBack
  2502. // However, continue to drain the queue
  2503. if (!cancelOperation)
  2504. {
  2505. userCallBack(s);
  2506. }
  2507. }
  2508. }
  2509. }
  2510. else
  2511. {
  2512. break;
  2513. }
  2514. }
  2515. }
  2516. // Wait until we hit EOF. This is called from Process.WaitForExit
  2517. // We will lose some information if we don't do this.
  2518. internal void WaitUtilEOF()
  2519. {
  2520. if (eofEvent != null)
  2521. {
  2522. eofEvent.WaitOne();
  2523. eofEvent.Close();
  2524. eofEvent = null;
  2525. }
  2526. }
  2527. }
  2528. public delegate void DataReceivedEventHandler(Object sender, DataReceivedEventArgs e);
  2529. public class DataReceivedEventArgs : EventArgs
  2530. {
  2531. internal string _data;
  2532. internal DataReceivedEventArgs(string data) => this._data = data;
  2533. public string Data => this._data;
  2534. }
  2535. internal class ProcessWaitHandle : WaitHandle
  2536. {
  2537. [ResourceExposure(ResourceScope.None)]
  2538. [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
  2539. internal ProcessWaitHandle(SafeProcessHandle processHandle) : base()
  2540. {
  2541. SafeWaitHandle waitHandle = null;
  2542. bool succeeded = NativeMethods.DuplicateHandle(new HandleRef(this, NativeMethods.GetCurrentProcess()), processHandle, new HandleRef(this, NativeMethods.GetCurrentProcess()), out waitHandle,
  2543. 0, false, NativeMethods.DUPLICATE_SAME_ACCESS);
  2544. if (!succeeded)
  2545. {
  2546. Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
  2547. }
  2548. this.SafeWaitHandle = waitHandle;
  2549. }
  2550. }
  2551. [SuppressUnmanagedCodeSecurityAttribute]
  2552. internal sealed class SafeThreadHandle : SafeHandleZeroOrMinusOneIsInvalid
  2553. {
  2554. internal SafeThreadHandle() : base(true) { }
  2555. internal void InitialSetHandle(IntPtr h)
  2556. {
  2557. Debug.Assert(base.IsInvalid, "Safe handle should only be set once");
  2558. base.SetHandle(h);
  2559. }
  2560. override protected bool ReleaseHandle()
  2561. {
  2562. return CloseHandle(handle);
  2563. }
  2564. [DllImport("kernel32.dll", ExactSpelling = true, CharSet = System.Runtime.InteropServices.CharSet.Auto, SetLastError = true)]
  2565. public static extern bool CloseHandle(IntPtr handle);
  2566. }
  2567. [HostProtectionAttribute(MayLeakOnAbort = true)]
  2568. [SuppressUnmanagedCodeSecurityAttribute]
  2569. internal sealed class SafeLocalMemHandle : SafeHandleZeroOrMinusOneIsInvalid
  2570. {
  2571. [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
  2572. internal SafeLocalMemHandle(IntPtr existingHandle, bool ownsHandle) : base(ownsHandle)
  2573. {
  2574. SetHandle(existingHandle);
  2575. }
  2576. [DllImport("kernel32.dll")]
  2577. [ResourceExposure(ResourceScope.None)]
  2578. [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  2579. private static extern IntPtr LocalFree(IntPtr hMem);
  2580. override protected bool ReleaseHandle()
  2581. {
  2582. return LocalFree(handle) == IntPtr.Zero;
  2583. }
  2584. }
  2585. [SuppressUnmanagedCodeSecurityAttribute]
  2586. public sealed class SafeProcessHandle : SafeHandleZeroOrMinusOneIsInvalid
  2587. {
  2588. internal static SafeProcessHandle InvalidHandle = new SafeProcessHandle(IntPtr.Zero);
  2589. // Note that OpenProcess returns 0 on failure
  2590. internal SafeProcessHandle() : base(true) { }
  2591. internal SafeProcessHandle(IntPtr handle) : base(true)
  2592. {
  2593. SetHandle(handle);
  2594. }
  2595. [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
  2596. public SafeProcessHandle(IntPtr existingHandle, bool ownsHandle) : base(ownsHandle)
  2597. {
  2598. SetHandle(existingHandle);
  2599. }
  2600. [DllImport("kernel32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto, SetLastError = true)]
  2601. [ResourceExposure(ResourceScope.Machine)]
  2602. internal static extern SafeProcessHandle OpenProcess(int access, bool inherit, int processId);
  2603. internal void InitialSetHandle(IntPtr h)
  2604. {
  2605. Debug.Assert(base.IsInvalid, "Safe handle should only be set once");
  2606. base.handle = h;
  2607. }
  2608. override protected bool ReleaseHandle()
  2609. {
  2610. return CloseHandle(handle);
  2611. }
  2612. [DllImport("kernel32.dll", ExactSpelling = true, CharSet = System.Runtime.InteropServices.CharSet.Auto, SetLastError = true)]
  2613. public static extern bool CloseHandle(IntPtr handle);
  2614. }
  2615. [TypeConverter(typeof(ExpandableObjectConverter)),
  2616. // Disabling partial trust scenarios
  2617. PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust"), HostProtection(SharedState = true, SelfAffectingProcessMgmt = true)]
  2618. public sealed class ProcessStartInfo
  2619. {
  2620. string fileName;
  2621. string arguments;
  2622. string directory;
  2623. string verb;
  2624. ProcessWindowStyle windowStyle;
  2625. bool errorDialog;
  2626. IntPtr errorDialogParentHandle;
  2627. bool useShellExecute = false;
  2628. string userName;
  2629. string domain;
  2630. SecureString password;
  2631. string passwordInClearText;
  2632. bool loadUserProfile;
  2633. bool redirectStandardInput = false;
  2634. bool redirectStandardOutput = false;
  2635. bool redirectStandardError = false;
  2636. Encoding standardOutputEncoding;
  2637. Encoding standardErrorEncoding;
  2638. bool createNoWindow = false;
  2639. WeakReference weakParentProcess;
  2640. internal StringDictionary environmentVariables;
  2641. /// <devdoc>
  2642. /// Default constructor. At least the <see cref='System.Diagnostics.ProcessStartInfo.FileName'/>
  2643. /// property must be set before starting the process.
  2644. /// </devdoc>
  2645. public ProcessStartInfo() { }
  2646. internal ProcessStartInfo(Process parent)
  2647. {
  2648. this.weakParentProcess = new WeakReference(parent);
  2649. }
  2650. /// <devdoc>
  2651. /// Specifies the name of the application or document that is to be started.
  2652. /// </devdoc>
  2653. [ResourceExposure(ResourceScope.Machine)]
  2654. public ProcessStartInfo(string fileName)
  2655. {
  2656. this.fileName = fileName;
  2657. }
  2658. /// <devdoc>
  2659. /// Specifies the name of the application that is to be started, as well as a set
  2660. /// of command line arguments to pass to the application.
  2661. /// </devdoc>
  2662. [ResourceExposure(ResourceScope.Machine)]
  2663. public ProcessStartInfo(string fileName, string arguments)
  2664. {
  2665. this.fileName = fileName;
  2666. this.arguments = arguments;
  2667. }
  2668. /// <devdoc>
  2669. /// <para>
  2670. /// Specifies the verb to use when opening the filename. For example, the "print"
  2671. /// verb will print a document specified using <see cref='System.Diagnostics.ProcessStartInfo.FileName'/>.
  2672. /// Each file extension has it's own set of verbs, which can be obtained using the
  2673. /// <see cref='System.Diagnostics.ProcessStartInfo.Verbs'/> property.
  2674. /// The default verb can be specified using "".
  2675. /// </para>
  2676. /// <note type="rnotes">
  2677. /// Discuss 'opening' vs. 'starting.' I think the part about the
  2678. /// default verb was a dev comment.
  2679. /// Find out what
  2680. /// that means.
  2681. /// </note>
  2682. /// </devdoc>
  2683. public string Verb
  2684. {
  2685. get
  2686. {
  2687. if (verb == null) return string.Empty;
  2688. return verb;
  2689. }
  2690. set
  2691. {
  2692. verb = value;
  2693. }
  2694. }
  2695. public string Arguments
  2696. {
  2697. get
  2698. {
  2699. if (arguments == null) return string.Empty;
  2700. return arguments;
  2701. }
  2702. set
  2703. {
  2704. arguments = value;
  2705. }
  2706. }
  2707. public bool CreateNoWindow
  2708. {
  2709. get
  2710. {
  2711. return createNoWindow;
  2712. }
  2713. set
  2714. {
  2715. createNoWindow = value;
  2716. }
  2717. }
  2718. public StringDictionary EnvironmentVariables
  2719. {
  2720. [ResourceExposure(ResourceScope.Machine)]
  2721. [ResourceConsumption(ResourceScope.Machine)]
  2722. get
  2723. {
  2724. // Note:
  2725. // Creating a detached ProcessStartInfo will pre-populate the environment
  2726. // with current environmental variables.
  2727. // When used with an existing Process.ProcessStartInfo the following behavior
  2728. // * Desktop - Populates with current Environment (rather than that of the process)
  2729. if (environmentVariables == null)
  2730. {
  2731. environmentVariables = new StringDictionaryWithComparer();
  2732. // if not in design mode, initialize the child environment block with all the parent variables
  2733. if (!(this.weakParentProcess != null && this.weakParentProcess.IsAlive && ((Component)this.weakParentProcess.Target).Site != null &&
  2734. ((Component)this.weakParentProcess.Target).Site.DesignMode))
  2735. {
  2736. foreach (DictionaryEntry entry in System.Environment.GetEnvironmentVariables()) environmentVariables.Add((string)entry.Key, (string)entry.Value);
  2737. }
  2738. }
  2739. return environmentVariables;
  2740. }
  2741. }
  2742. private IDictionary<string, string> environment;
  2743. public IDictionary<string, string> Environment
  2744. {
  2745. get
  2746. {
  2747. if (environment == null)
  2748. {
  2749. environment = this.EnvironmentVariables.AsGenericDictionary();
  2750. }
  2751. return environment;
  2752. }
  2753. }
  2754. public bool RedirectStandardInput
  2755. {
  2756. get
  2757. {
  2758. return redirectStandardInput;
  2759. }
  2760. set
  2761. {
  2762. redirectStandardInput = value;
  2763. }
  2764. }
  2765. public bool RedirectStandardOutput
  2766. {
  2767. get
  2768. {
  2769. return redirectStandardOutput;
  2770. }
  2771. set
  2772. {
  2773. redirectStandardOutput = value;
  2774. }
  2775. }
  2776. public bool RedirectStandardError
  2777. {
  2778. get
  2779. {
  2780. return redirectStandardError;
  2781. }
  2782. set
  2783. {
  2784. redirectStandardError = value;
  2785. }
  2786. }
  2787. public Encoding StandardErrorEncoding
  2788. {
  2789. get
  2790. {
  2791. return standardErrorEncoding;
  2792. }
  2793. set
  2794. {
  2795. standardErrorEncoding = value;
  2796. }
  2797. }
  2798. public Encoding StandardOutputEncoding
  2799. {
  2800. get
  2801. {
  2802. return standardOutputEncoding;
  2803. }
  2804. set
  2805. {
  2806. standardOutputEncoding = value;
  2807. }
  2808. }
  2809. public bool UseShellExecute
  2810. {
  2811. get
  2812. {
  2813. return useShellExecute;
  2814. }
  2815. set
  2816. {
  2817. useShellExecute = value;
  2818. }
  2819. }
  2820. /// <devdoc>
  2821. /// Returns the set of verbs associated with the file specified by the
  2822. /// <see cref='System.Diagnostics.ProcessStartInfo.FileName'/> property.
  2823. /// </devdoc>
  2824. [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  2825. public string[] Verbs
  2826. {
  2827. [ResourceExposure(ResourceScope.None)]
  2828. [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
  2829. get
  2830. {
  2831. ArrayList verbs = new ArrayList();
  2832. RegistryKey key = null;
  2833. string extension = Path.GetExtension(FileName);
  2834. try
  2835. {
  2836. if (extension != null && extension.Length > 0)
  2837. {
  2838. key = Registry.ClassesRoot.OpenSubKey(extension);
  2839. if (key != null)
  2840. {
  2841. string value = (string)key.GetValue(String.Empty);
  2842. key.Close();
  2843. key = Registry.ClassesRoot.OpenSubKey(value + "\\shell");
  2844. if (key != null)
  2845. {
  2846. string[] names = key.GetSubKeyNames();
  2847. for (int i = 0; i < names.Length; i++)
  2848. if (string.Compare(names[i], "new", StringComparison.OrdinalIgnoreCase) != 0)
  2849. verbs.Add(names[i]);
  2850. key.Close();
  2851. key = null;
  2852. }
  2853. }
  2854. }
  2855. }
  2856. finally
  2857. {
  2858. if (key != null) key.Close();
  2859. }
  2860. string[] temp = new string[verbs.Count];
  2861. verbs.CopyTo(temp, 0);
  2862. return temp;
  2863. }
  2864. }
  2865. public string UserName
  2866. {
  2867. get
  2868. {
  2869. if (userName == null)
  2870. {
  2871. return string.Empty;
  2872. }
  2873. else
  2874. {
  2875. return userName;
  2876. }
  2877. }
  2878. set
  2879. {
  2880. userName = value;
  2881. }
  2882. }
  2883. public SecureString Password
  2884. {
  2885. get
  2886. {
  2887. return password;
  2888. }
  2889. set
  2890. {
  2891. password = value;
  2892. }
  2893. }
  2894. public string PasswordInClearText
  2895. {
  2896. get
  2897. {
  2898. return passwordInClearText;
  2899. }
  2900. set
  2901. {
  2902. passwordInClearText = value;
  2903. }
  2904. }
  2905. public string Domain
  2906. {
  2907. get
  2908. {
  2909. if (domain == null)
  2910. {
  2911. return string.Empty;
  2912. }
  2913. else
  2914. {
  2915. return domain;
  2916. }
  2917. }
  2918. set
  2919. {
  2920. domain = value;
  2921. }
  2922. }
  2923. public bool LoadUserProfile
  2924. {
  2925. get
  2926. {
  2927. return loadUserProfile;
  2928. }
  2929. set
  2930. {
  2931. loadUserProfile = value;
  2932. }
  2933. }
  2934. public string FileName
  2935. {
  2936. [ResourceExposure(ResourceScope.Machine)]
  2937. get
  2938. {
  2939. if (fileName == null) return string.Empty;
  2940. return fileName;
  2941. }
  2942. [ResourceExposure(ResourceScope.Machine)]
  2943. set
  2944. {
  2945. fileName = value;
  2946. }
  2947. }
  2948. public string WorkingDirectory
  2949. {
  2950. [ResourceExposure(ResourceScope.Machine)]
  2951. get
  2952. {
  2953. if (directory == null) return string.Empty;
  2954. return directory;
  2955. }
  2956. [ResourceExposure(ResourceScope.Machine)]
  2957. set
  2958. {
  2959. directory = value;
  2960. }
  2961. }
  2962. public bool ErrorDialog
  2963. {
  2964. get
  2965. {
  2966. return errorDialog;
  2967. }
  2968. set
  2969. {
  2970. errorDialog = value;
  2971. }
  2972. }
  2973. [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  2974. public IntPtr ErrorDialogParentHandle
  2975. {
  2976. get
  2977. {
  2978. return errorDialogParentHandle;
  2979. }
  2980. set
  2981. {
  2982. errorDialogParentHandle = value;
  2983. }
  2984. }
  2985. public ProcessWindowStyle WindowStyle
  2986. {
  2987. get
  2988. {
  2989. return windowStyle;
  2990. }
  2991. set
  2992. {
  2993. if (!Enum.IsDefined(typeof(ProcessWindowStyle), value)) throw new InvalidEnumArgumentException("value", (int)value, typeof(ProcessWindowStyle));
  2994. windowStyle = value;
  2995. }
  2996. }
  2997. }
  2998. [Serializable]
  2999. internal class StringDictionaryWithComparer : StringDictionary
  3000. {
  3001. public StringDictionaryWithComparer() : this((IEqualityComparer)StringComparer.OrdinalIgnoreCase) { }
  3002. public StringDictionaryWithComparer(IEqualityComparer comparer) => this.ReplaceHashtable(new Hashtable(comparer));
  3003. public override string this[string key]
  3004. {
  3005. get => key != null ? (string)this.contents[(object)key] : throw new ArgumentNullException(nameof(key));
  3006. set
  3007. {
  3008. if (key == null) throw new ArgumentNullException(nameof(key));
  3009. this.contents[(object)key] = (object)value;
  3010. }
  3011. }
  3012. public override void Add(string key, string value)
  3013. {
  3014. if (key == null) throw new ArgumentNullException(nameof(key));
  3015. this.contents.Add((object)key, (object)value);
  3016. }
  3017. public override bool ContainsKey(string key) => key != null ? this.contents.ContainsKey((object)key) : throw new ArgumentNullException(nameof(key));
  3018. public override void Remove(string key)
  3019. {
  3020. if (key == null) throw new ArgumentNullException(nameof(key));
  3021. this.contents.Remove((object)key);
  3022. }
  3023. }
  3024. [Serializable]
  3025. public class StringDictionary : IEnumerable
  3026. {
  3027. internal Hashtable contents = new Hashtable();
  3028. /// <summary>Gets the number of key/value pairs in the <see cref="T:System.Collections.Specialized.StringDictionary" />.</summary>
  3029. /// <returns>The number of key/value pairs in the <see cref="T:System.Collections.Specialized.StringDictionary" />.
  3030. /// Retrieving the value of this property is an O(1) operation.</returns>
  3031. public virtual int Count => this.contents.Count;
  3032. /// <summary>Gets a value indicating whether access to the <see cref="T:System.Collections.Specialized.StringDictionary" /> is synchronized (thread safe).</summary>
  3033. /// <returns>
  3034. /// <see langword="true" /> if access to the <see cref="T:System.Collections.Specialized.StringDictionary" /> is synchronized (thread safe); otherwise, <see langword="false" />.</returns>
  3035. public virtual bool IsSynchronized => this.contents.IsSynchronized;
  3036. /// <summary>Gets or sets the value associated with the specified key.</summary>
  3037. /// <param name="key">The key whose value to get or set.</param>
  3038. /// <returns>The value associated with the specified key. If the specified key is not found, Get returns <see langword="null" />, and Set creates a new entry with the specified key.</returns>
  3039. /// <exception cref="T:System.ArgumentNullException">
  3040. /// <paramref name="key" /> is <see langword="null" />.</exception>
  3041. public virtual string this[string key]
  3042. {
  3043. get
  3044. {
  3045. if (key == null) throw new ArgumentNullException(nameof(key));
  3046. return (string)this.contents[(object)key.ToLower(CultureInfo.InvariantCulture)];
  3047. }
  3048. set
  3049. {
  3050. if (key == null) throw new ArgumentNullException(nameof(key));
  3051. this.contents[(object)key.ToLower(CultureInfo.InvariantCulture)] = (object)value;
  3052. }
  3053. }
  3054. /// <summary>Gets a collection of keys in the <see cref="T:System.Collections.Specialized.StringDictionary" />.</summary>
  3055. /// <returns>An <see cref="T:System.Collections.ICollection" /> that provides the keys in the <see cref="T:System.Collections.Specialized.StringDictionary" />.</returns>
  3056. public virtual ICollection Keys => this.contents.Keys;
  3057. /// <summary>Gets an object that can be used to synchronize access to the <see cref="T:System.Collections.Specialized.StringDictionary" />.</summary>
  3058. /// <returns>An <see cref="T:System.Object" /> that can be used to synchronize access to the <see cref="T:System.Collections.Specialized.StringDictionary" />.</returns>
  3059. public virtual object SyncRoot => this.contents.SyncRoot;
  3060. /// <summary>Gets a collection of values in the <see cref="T:System.Collections.Specialized.StringDictionary" />.</summary>
  3061. /// <returns>An <see cref="T:System.Collections.ICollection" /> that provides the values in the <see cref="T:System.Collections.Specialized.StringDictionary" />.</returns>
  3062. public virtual ICollection Values => this.contents.Values;
  3063. /// <summary>Adds an entry with the specified key and value into the <see cref="T:System.Collections.Specialized.StringDictionary" />.</summary>
  3064. /// <param name="key">The key of the entry to add.</param>
  3065. /// <param name="value">The value of the entry to add. The value can be <see langword="null" />.</param>
  3066. /// <exception cref="T:System.ArgumentNullException">
  3067. /// <paramref name="key" /> is <see langword="null" />.</exception>
  3068. /// <exception cref="T:System.ArgumentException">An entry with the same key already exists in the <see cref="T:System.Collections.Specialized.StringDictionary" />.</exception>
  3069. /// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Specialized.StringDictionary" /> is read-only.</exception>
  3070. public virtual void Add(string key, string value)
  3071. {
  3072. if (key == null) throw new ArgumentNullException(nameof(key));
  3073. this.contents.Add((object)key.ToLower(CultureInfo.InvariantCulture), (object)value);
  3074. }
  3075. /// <summary>Removes all entries from the <see cref="T:System.Collections.Specialized.StringDictionary" />.</summary>
  3076. /// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Specialized.StringDictionary" /> is read-only.</exception>
  3077. public virtual void Clear() => this.contents.Clear();
  3078. /// <summary>Determines if the <see cref="T:System.Collections.Specialized.StringDictionary" /> contains a specific key.</summary>
  3079. /// <param name="key">The key to locate in the <see cref="T:System.Collections.Specialized.StringDictionary" />.</param>
  3080. /// <returns>
  3081. /// <see langword="true" /> if the <see cref="T:System.Collections.Specialized.StringDictionary" /> contains an entry with the specified key; otherwise, <see langword="false" />.</returns>
  3082. /// <exception cref="T:System.ArgumentNullException">The key is <see langword="null" />.</exception>
  3083. public virtual bool ContainsKey(string key)
  3084. {
  3085. if (key == null) throw new ArgumentNullException(nameof(key));
  3086. return this.contents.ContainsKey((object)key.ToLower(CultureInfo.InvariantCulture));
  3087. }
  3088. /// <summary>Determines if the <see cref="T:System.Collections.Specialized.StringDictionary" /> contains a specific value.</summary>
  3089. /// <param name="value">The value to locate in the <see cref="T:System.Collections.Specialized.StringDictionary" />. The value can be <see langword="null" />.</param>
  3090. /// <returns>
  3091. /// <see langword="true" /> if the <see cref="T:System.Collections.Specialized.StringDictionary" /> contains an element with the specified value; otherwise, <see langword="false" />.</returns>
  3092. public virtual bool ContainsValue(string value) => this.contents.ContainsValue((object)value);
  3093. /// <summary>Copies the string dictionary values to a one-dimensional <see cref="T:System.Array" /> instance at the specified index.</summary>
  3094. /// <param name="array">The one-dimensional <see cref="T:System.Array" /> that is the destination of the values copied from the <see cref="T:System.Collections.Specialized.StringDictionary" />.</param>
  3095. /// <param name="index">The index in the array where copying begins.</param>
  3096. /// <exception cref="T:System.ArgumentException">
  3097. /// <paramref name="array" /> is multidimensional.
  3098. /// -or-
  3099. /// The number of elements in the <see cref="T:System.Collections.Specialized.StringDictionary" /> is greater than the available space from <paramref name="index" /> to the end of <paramref name="array" />.</exception>
  3100. /// <exception cref="T:System.ArgumentNullException">
  3101. /// <paramref name="array" /> is <see langword="null" />.</exception>
  3102. /// <exception cref="T:System.ArgumentOutOfRangeException">
  3103. /// <paramref name="index" /> is less than the lower bound of <paramref name="array" />.</exception>
  3104. public virtual void CopyTo(Array array, int index) => this.contents.CopyTo(array, index);
  3105. /// <summary>Returns an enumerator that iterates through the string dictionary.</summary>
  3106. /// <returns>An <see cref="T:System.Collections.IEnumerator" /> that iterates through the string dictionary.</returns>
  3107. public virtual IEnumerator GetEnumerator() => (IEnumerator)this.contents.GetEnumerator();
  3108. /// <summary>Removes the entry with the specified key from the string dictionary.</summary>
  3109. /// <param name="key">The key of the entry to remove.</param>
  3110. /// <exception cref="T:System.ArgumentNullException">The key is <see langword="null" />.</exception>
  3111. /// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Specialized.StringDictionary" /> is read-only.</exception>
  3112. public virtual void Remove(string key)
  3113. {
  3114. if (key == null) throw new ArgumentNullException(nameof(key));
  3115. this.contents.Remove((object)key.ToLower(CultureInfo.InvariantCulture));
  3116. }
  3117. internal void ReplaceHashtable(Hashtable useThisHashtableInstead) => this.contents = useThisHashtableInstead;
  3118. internal IDictionary<string, string> AsGenericDictionary() => (IDictionary<string, string>)new StringDictionary.GenericAdapter(this);
  3119. private class GenericAdapter : IDictionary<string, string>, ICollection<KeyValuePair<string, string>>, IEnumerable<KeyValuePair<string, string>>, IEnumerable
  3120. {
  3121. private StringDictionary m_stringDictionary;
  3122. private StringDictionary.GenericAdapter.ICollectionToGenericCollectionAdapter _values;
  3123. private StringDictionary.GenericAdapter.ICollectionToGenericCollectionAdapter _keys;
  3124. internal GenericAdapter(StringDictionary stringDictionary) => this.m_stringDictionary = stringDictionary;
  3125. public void Add(string key, string value) => this[key] = value;
  3126. public bool ContainsKey(string key) => this.m_stringDictionary.ContainsKey(key);
  3127. public void Clear() => this.m_stringDictionary.Clear();
  3128. public int Count => this.m_stringDictionary.Count;
  3129. public string this[string key]
  3130. {
  3131. get
  3132. {
  3133. if (key == null) throw new ArgumentNullException(nameof(key));
  3134. return this.m_stringDictionary.ContainsKey(key) ? this.m_stringDictionary[key] : throw new KeyNotFoundException();
  3135. }
  3136. set
  3137. {
  3138. if (key == null) throw new ArgumentNullException(nameof(key));
  3139. this.m_stringDictionary[key] = value;
  3140. }
  3141. }
  3142. public ICollection<string> Keys
  3143. {
  3144. get
  3145. {
  3146. if (this._keys == null)
  3147. this._keys = new StringDictionary.GenericAdapter.ICollectionToGenericCollectionAdapter(this.m_stringDictionary, StringDictionary.GenericAdapter.KeyOrValue.Key);
  3148. return (ICollection<string>)this._keys;
  3149. }
  3150. }
  3151. public ICollection<string> Values
  3152. {
  3153. get
  3154. {
  3155. if (this._values == null)
  3156. this._values = new StringDictionary.GenericAdapter.ICollectionToGenericCollectionAdapter(this.m_stringDictionary, StringDictionary.GenericAdapter.KeyOrValue.Value);
  3157. return (ICollection<string>)this._values;
  3158. }
  3159. }
  3160. public bool Remove(string key)
  3161. {
  3162. if (!this.m_stringDictionary.ContainsKey(key)) return false;
  3163. this.m_stringDictionary.Remove(key);
  3164. return true;
  3165. }
  3166. public bool TryGetValue(string key, out string value)
  3167. {
  3168. if (!this.m_stringDictionary.ContainsKey(key))
  3169. {
  3170. value = (string)null;
  3171. return false;
  3172. }
  3173. value = this.m_stringDictionary[key];
  3174. return true;
  3175. }
  3176. void ICollection<KeyValuePair<string, string>>.Add(KeyValuePair<string, string> item) => this.m_stringDictionary.Add(item.Key, item.Value);
  3177. bool ICollection<KeyValuePair<string, string>>.Contains(KeyValuePair<string, string> item)
  3178. {
  3179. string str;
  3180. return this.TryGetValue(item.Key, out str) && str.Equals(item.Value);
  3181. }
  3182. void ICollection<KeyValuePair<string, string>>.CopyTo(KeyValuePair<string, string>[] array, int arrayIndex)
  3183. {
  3184. if (array == null) throw new ArgumentNullException(nameof(array), "ArgumentNull_Array");
  3185. if (arrayIndex < 0) throw new ArgumentOutOfRangeException(nameof(arrayIndex), "ArgumentOutOfRange_NeedNonNegNum");
  3186. if (array.Length - arrayIndex < this.Count) throw new ArgumentException("Arg_ArrayPlusOffTooSmall");
  3187. int num = arrayIndex;
  3188. foreach (DictionaryEntry dictionaryEntry in this.m_stringDictionary) array[num++] = new KeyValuePair<string, string>((string)dictionaryEntry.Key, (string)dictionaryEntry.Value);
  3189. }
  3190. bool ICollection<KeyValuePair<string, string>>.IsReadOnly => false;
  3191. bool ICollection<KeyValuePair<string, string>>.Remove(KeyValuePair<string, string> item)
  3192. {
  3193. if (!((ICollection<KeyValuePair<string, string>>)this).Contains(item)) return false;
  3194. this.m_stringDictionary.Remove(item.Key);
  3195. return true;
  3196. }
  3197. IEnumerator IEnumerable.GetEnumerator() => (IEnumerator)this.GetEnumerator();
  3198. public IEnumerator<KeyValuePair<string, string>> GetEnumerator()
  3199. {
  3200. foreach (DictionaryEntry dictionaryEntry in this.m_stringDictionary) yield return new KeyValuePair<string, string>((string)dictionaryEntry.Key, (string)dictionaryEntry.Value);
  3201. }
  3202. internal enum KeyOrValue
  3203. {
  3204. Key,
  3205. Value,
  3206. }
  3207. private class ICollectionToGenericCollectionAdapter : ICollection<string>, IEnumerable<string>, IEnumerable
  3208. {
  3209. private StringDictionary _internal;
  3210. private StringDictionary.GenericAdapter.KeyOrValue _keyOrValue;
  3211. public ICollectionToGenericCollectionAdapter(StringDictionary source, StringDictionary.GenericAdapter.KeyOrValue keyOrValue)
  3212. {
  3213. this._internal = source != null ? source : throw new ArgumentNullException(nameof(source));
  3214. this._keyOrValue = keyOrValue;
  3215. }
  3216. public void Add(string item) => this.ThrowNotSupportedException();
  3217. public void Clear() => this.ThrowNotSupportedException();
  3218. public void ThrowNotSupportedException()
  3219. {
  3220. if (this._keyOrValue == StringDictionary.GenericAdapter.KeyOrValue.Key) throw new NotSupportedException("NotSupported_KeyCollectionSet");
  3221. throw new NotSupportedException("NotSupported_ValueCollectionSet");
  3222. }
  3223. public bool Contains(string item) => this._keyOrValue == StringDictionary.GenericAdapter.KeyOrValue.Key ? this._internal.ContainsKey(item) : this._internal.ContainsValue(item);
  3224. public void CopyTo(string[] array, int arrayIndex) => this.GetUnderlyingCollection().CopyTo((Array)array, arrayIndex);
  3225. public int Count => this._internal.Count;
  3226. public bool IsReadOnly => true;
  3227. public bool Remove(string item)
  3228. {
  3229. this.ThrowNotSupportedException();
  3230. return false;
  3231. }
  3232. private ICollection GetUnderlyingCollection() => this._keyOrValue == StringDictionary.GenericAdapter.KeyOrValue.Key ? this._internal.Keys : this._internal.Values;
  3233. public IEnumerator<string> GetEnumerator()
  3234. {
  3235. foreach (string underlying in (IEnumerable)this.GetUnderlyingCollection()) yield return underlying;
  3236. }
  3237. IEnumerator IEnumerable.GetEnumerator() => this.GetUnderlyingCollection().GetEnumerator();
  3238. }
  3239. }
  3240. }
  3241. }
  3242. }