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

WinINet.cs 7.7 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. /****************************** Module Header ******************************\
  2. Module Name: WinINet.cs
  3. Project: CSWebBrowserWithProxy
  4. Copyright (c) Microsoft Corporation.
  5. This class is used to set the proxy. or restore to the system proxy for the
  6. current application
  7. This source is subject to the Microsoft Public License.
  8. See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL.
  9. All other rights reserved.
  10. THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
  11. EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
  12. WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
  13. \***************************************************************************/
  14. using System;
  15. using System.Collections.Generic;
  16. using System.Linq;
  17. using System.Runtime.InteropServices;
  18. using Shadowsocks.Controller;
  19. namespace Shadowsocks.Util.SystemProxy
  20. {
  21. public static class WinINet
  22. {
  23. /// <summary>
  24. /// Set IE settings.
  25. /// </summary>
  26. private static void SetIEProxy(bool enable, bool global, string proxyServer, string pacURL, string connName)
  27. {
  28. List<INTERNET_PER_CONN_OPTION> _optionlist = new List<INTERNET_PER_CONN_OPTION>();
  29. if (enable)
  30. {
  31. if (global)
  32. {
  33. // global proxy
  34. _optionlist.Add(new INTERNET_PER_CONN_OPTION
  35. {
  36. dwOption = (int)INTERNET_PER_CONN_OptionEnum.INTERNET_PER_CONN_FLAGS_UI,
  37. Value = { dwValue = (int)(INTERNET_OPTION_PER_CONN_FLAGS_UI.PROXY_TYPE_PROXY
  38. | INTERNET_OPTION_PER_CONN_FLAGS_UI.PROXY_TYPE_DIRECT) }
  39. });
  40. _optionlist.Add(new INTERNET_PER_CONN_OPTION
  41. {
  42. dwOption = (int)INTERNET_PER_CONN_OptionEnum.INTERNET_PER_CONN_PROXY_SERVER,
  43. Value = { pszValue = Marshal.StringToHGlobalAuto(proxyServer) }
  44. });
  45. _optionlist.Add(new INTERNET_PER_CONN_OPTION
  46. {
  47. dwOption = (int)INTERNET_PER_CONN_OptionEnum.INTERNET_PER_CONN_PROXY_BYPASS,
  48. Value = { pszValue = Marshal.StringToHGlobalAuto("<local>") }
  49. });
  50. }
  51. else
  52. {
  53. // pac
  54. _optionlist.Add(new INTERNET_PER_CONN_OPTION
  55. {
  56. dwOption = (int)INTERNET_PER_CONN_OptionEnum.INTERNET_PER_CONN_FLAGS_UI,
  57. Value = { dwValue = (int)INTERNET_OPTION_PER_CONN_FLAGS_UI.PROXY_TYPE_AUTO_PROXY_URL }
  58. });
  59. _optionlist.Add(new INTERNET_PER_CONN_OPTION
  60. {
  61. dwOption = (int)INTERNET_PER_CONN_OptionEnum.INTERNET_PER_CONN_AUTOCONFIG_URL,
  62. Value = { pszValue = Marshal.StringToHGlobalAuto(pacURL) }
  63. });
  64. }
  65. }
  66. else
  67. {
  68. // direct
  69. _optionlist.Add(new INTERNET_PER_CONN_OPTION
  70. {
  71. dwOption = (int)INTERNET_PER_CONN_OptionEnum.INTERNET_PER_CONN_FLAGS_UI,
  72. Value = { dwValue = (int)(INTERNET_OPTION_PER_CONN_FLAGS_UI.PROXY_TYPE_AUTO_DETECT
  73. | INTERNET_OPTION_PER_CONN_FLAGS_UI.PROXY_TYPE_DIRECT) }
  74. });
  75. }
  76. // Get total length of INTERNET_PER_CONN_OPTIONs
  77. var len = _optionlist.Sum(each => Marshal.SizeOf(each));
  78. // Allocate a block of memory of the options.
  79. IntPtr buffer = Marshal.AllocCoTaskMem(len);
  80. IntPtr current = buffer;
  81. // Marshal data from a managed object to an unmanaged block of memory.
  82. foreach (INTERNET_PER_CONN_OPTION eachOption in _optionlist)
  83. {
  84. Marshal.StructureToPtr(eachOption, current, false);
  85. current = (IntPtr)((int)current + Marshal.SizeOf(eachOption));
  86. }
  87. // Initialize a INTERNET_PER_CONN_OPTION_LIST instance.
  88. INTERNET_PER_CONN_OPTION_LIST optionList = new INTERNET_PER_CONN_OPTION_LIST();
  89. // Point to the allocated memory.
  90. optionList.pOptions = buffer;
  91. // Return the unmanaged size of an object in bytes.
  92. optionList.Size = Marshal.SizeOf(optionList);
  93. optionList.Connection = connName.IsNullOrEmpty()
  94. ? IntPtr.Zero // NULL means LAN
  95. : Marshal.StringToHGlobalAuto(connName); // TODO: not working if contains Chinese
  96. optionList.OptionCount = _optionlist.Count;
  97. optionList.OptionError = 0;
  98. int optionListSize = Marshal.SizeOf(optionList);
  99. // Allocate memory for the INTERNET_PER_CONN_OPTION_LIST instance.
  100. IntPtr intptrStruct = Marshal.AllocCoTaskMem(optionListSize);
  101. // Marshal data from a managed object to an unmanaged block of memory.
  102. Marshal.StructureToPtr(optionList, intptrStruct, true);
  103. // Set internet settings.
  104. bool bReturn = NativeMethods.InternetSetOption(
  105. IntPtr.Zero,
  106. INTERNET_OPTION.INTERNET_OPTION_PER_CONNECTION_OPTION,
  107. intptrStruct, optionListSize);
  108. // Free the allocated memory.
  109. Marshal.FreeCoTaskMem(buffer);
  110. Marshal.FreeCoTaskMem(intptrStruct);
  111. // Throw an exception if this operation failed.
  112. if (!bReturn)
  113. {
  114. throw new Exception("InternetSetOption: " + Marshal.GetLastWin32Error());
  115. }
  116. // Notify the system that the registry settings have been changed and cause
  117. // the proxy data to be reread from the registry for a handle.
  118. bReturn = NativeMethods.InternetSetOption(
  119. IntPtr.Zero,
  120. INTERNET_OPTION.INTERNET_OPTION_PROXY_SETTINGS_CHANGED,
  121. IntPtr.Zero, 0);
  122. if (!bReturn)
  123. {
  124. Logging.Error("InternetSetOption:INTERNET_OPTION_PROXY_SETTINGS_CHANGED");
  125. }
  126. bReturn = NativeMethods.InternetSetOption(
  127. IntPtr.Zero,
  128. INTERNET_OPTION.INTERNET_OPTION_REFRESH,
  129. IntPtr.Zero, 0);
  130. if (!bReturn)
  131. {
  132. Logging.Error("InternetSetOption:INTERNET_OPTION_REFRESH");
  133. }
  134. }
  135. public static void SetIEProxy(bool enable, bool global, string proxyServer, string pacURL)
  136. {
  137. string[] allConnections = null;
  138. var ret = RemoteAccessService.GetAllConns(ref allConnections);
  139. if (ret == 2)
  140. throw new Exception("Cannot get all connections");
  141. if (ret == 1)
  142. {
  143. // no entries, only set LAN
  144. SetIEProxy(enable, global, proxyServer, pacURL, null);
  145. }
  146. else if (ret == 0)
  147. {
  148. // found entries, set LAN and each connection
  149. SetIEProxy(enable, global, proxyServer, pacURL, null);
  150. foreach (string connName in allConnections)
  151. {
  152. SetIEProxy(enable, global, proxyServer, pacURL, connName);
  153. }
  154. }
  155. }
  156. }
  157. }