Program.cs 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. using System;
  2. using System.Diagnostics;
  3. using System.IO;
  4. using System.IO.Pipes;
  5. using System.Reflection;
  6. using System.Runtime.InteropServices;
  7. using System.Text;
  8. using System.Windows.Forms;
  9. // 有关程序集的一般信息由以下
  10. // 控制。更改这些特性值可修改
  11. // 与程序集关联的信息。
  12. [assembly: AssemblyTitle("ConsoleIcon")]
  13. [assembly: AssemblyProduct("ConsoleIcon")]
  14. [assembly: AssemblyDescription("Pass a icon file path for set to current console window")]
  15. [assembly: AssemblyCopyright("Copyright © 2022")]
  16. // 程序集的版本信息由下列四个值组成:
  17. //
  18. // 主版本
  19. // 次版本
  20. // 生成号
  21. // 修订号
  22. //
  23. //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
  24. //通过使用 "*",如下所示:
  25. // [assembly: AssemblyVersion("1.0.*")]
  26. [assembly: AssemblyVersion("1.0.0.0")]
  27. [assembly: AssemblyFileVersion("1.0.0.0")]
  28. namespace ConsoleIcon
  29. {
  30. internal class Program
  31. {
  32. private const string PipeName = nameof(ConsoleIcon) + "-" + nameof(PipeName);
  33. private static void Main(string[] args)
  34. {
  35. if (args.Length == 1)
  36. {
  37. if (false == File.Exists($@"\\.\pipe\{PipeName}"))
  38. {
  39. var daemonProcess = new Process
  40. {
  41. StartInfo =
  42. {
  43. WindowStyle = ProcessWindowStyle.Hidden,
  44. FileName = Application.ExecutablePath
  45. }
  46. };
  47. daemonProcess.Start();
  48. }
  49. var pipe = new NamedPipeClientStream(PipeName);
  50. pipe.Connect(500);
  51. IntPtr hWnd = GetConsoleWindow(); // https://stackoverflow.com/a/28616832/2430943
  52. var iconFilePath = Path.GetFullPath(args[0]);
  53. var writer = new StreamWriter(pipe);
  54. writer.WriteLine(hWnd.ToInt64());
  55. writer.WriteLine(iconFilePath);
  56. writer.Flush();
  57. pipe.Close();
  58. }
  59. else //Daemon
  60. {
  61. Console.WriteLine("Daemon start.");
  62. while (true)
  63. {
  64. var pipe = new NamedPipeServerStream(PipeName);
  65. pipe.WaitForConnection();
  66. Console.WriteLine("Accept Connection");
  67. var reader = new StreamReader(pipe, Encoding.UTF8);
  68. var hWnd = reader.ReadLine();
  69. var iconFilePath = reader.ReadLine();
  70. pipe.Close();
  71. Console.WriteLine($"Setting icon {iconFilePath}");
  72. Console.WriteLine($" to {hWnd:X}");
  73. try
  74. {
  75. var bytes = File.ReadAllBytes(iconFilePath);
  76. using var stream = new MemoryStream(bytes);
  77. System.Drawing.Icon icon = new System.Drawing.Icon(stream);
  78. SetWindowIcon(new IntPtr(long.Parse(hWnd)), icon);
  79. }
  80. catch (Exception e)
  81. {
  82. Console.WriteLine(e);
  83. }
  84. }
  85. }
  86. }
  87. private static void SetWindowIcon(IntPtr hWnd, System.Drawing.Icon icon)
  88. {
  89. IntPtr result01 = SendMessage(hWnd, (int)WinMessages.SETICON, 0, icon.Handle);
  90. IntPtr result02 = SendMessage(hWnd, (int)WinMessages.SETICON, 1, icon.Handle);
  91. }
  92. // https://stackoverflow.com/a/59897483/2430943
  93. public static void SetConsoleIcon(string iconFilePath)
  94. {
  95. if (Environment.OSVersion.Platform == PlatformID.Win32NT)
  96. {
  97. if (!string.IsNullOrEmpty(iconFilePath) && File.Exists(iconFilePath))
  98. {
  99. var bytes = File.ReadAllBytes(iconFilePath);
  100. using var stream = new MemoryStream(bytes);
  101. System.Drawing.Icon icon = new System.Drawing.Icon(stream);
  102. SetWindowIcon(icon);
  103. }
  104. }
  105. }
  106. private static void SetWindowIcon(System.Drawing.Icon icon)
  107. {
  108. IntPtr mwHandle = GetConsoleWindow(); // https://stackoverflow.com/a/28616832/2430943
  109. IntPtr result01 = SendMessage(mwHandle, (int)WinMessages.SETICON, 0, icon.Handle);
  110. IntPtr result02 = SendMessage(mwHandle, (int)WinMessages.SETICON, 1, icon.Handle);
  111. }
  112. [DllImport("kernel32.dll")]
  113. private static extern IntPtr GetConsoleWindow();
  114. public enum WinMessages : uint
  115. {
  116. /// <summary>
  117. /// An application sends the WM_SETICON message to associate a new large or small icon with a window.
  118. /// The system displays the large icon in the ALT+TAB dialog box, and the small icon in the window caption.
  119. /// </summary>
  120. SETICON = 0x0080,
  121. }
  122. [System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
  123. private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, IntPtr lParam);
  124. }
  125. }