SystemInfo.cs 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328
  1. #region Apache License
  2. //
  3. // Licensed to the Apache Software Foundation (ASF) under one or more
  4. // contributor license agreements. See the NOTICE file distributed with
  5. // this work for additional information regarding copyright ownership.
  6. // The ASF licenses this file to you under the Apache License, Version 2.0
  7. // (the "License"); you may not use this file except in compliance with
  8. // the License. You may obtain a copy of the License at
  9. //
  10. // http://www.apache.org/licenses/LICENSE-2.0
  11. //
  12. // Unless required by applicable law or agreed to in writing, software
  13. // distributed under the License is distributed on an "AS IS" BASIS,
  14. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. // See the License for the specific language governing permissions and
  16. // limitations under the License.
  17. //
  18. #endregion
  19. using System;
  20. #if NETSTANDARD1_3
  21. using System.Globalization;
  22. #else
  23. using System.Configuration;
  24. #endif
  25. using System.Reflection;
  26. using System.Text;
  27. using System.IO;
  28. using System.Runtime.InteropServices;
  29. using System.Collections;
  30. namespace log4net.Util
  31. {
  32. /// <summary>
  33. /// Utility class for system specific information.
  34. /// </summary>
  35. /// <remarks>
  36. /// <para>
  37. /// Utility class of static methods for system specific information.
  38. /// </para>
  39. /// </remarks>
  40. /// <author>Nicko Cadell</author>
  41. /// <author>Gert Driesen</author>
  42. /// <author>Alexey Solofnenko</author>
  43. public sealed class SystemInfo
  44. {
  45. #region Private Constants
  46. private const string DEFAULT_NULL_TEXT = "(null)";
  47. private const string DEFAULT_NOT_AVAILABLE_TEXT = "NOT AVAILABLE";
  48. #endregion
  49. #region Private Instance Constructors
  50. /// <summary>
  51. /// Private constructor to prevent instances.
  52. /// </summary>
  53. /// <remarks>
  54. /// <para>
  55. /// Only static methods are exposed from this type.
  56. /// </para>
  57. /// </remarks>
  58. private SystemInfo()
  59. {
  60. }
  61. #endregion Private Instance Constructors
  62. #region Public Static Constructor
  63. /// <summary>
  64. /// Initialize default values for private static fields.
  65. /// </summary>
  66. /// <remarks>
  67. /// <para>
  68. /// Only static methods are exposed from this type.
  69. /// </para>
  70. /// </remarks>
  71. static SystemInfo()
  72. {
  73. string nullText = DEFAULT_NULL_TEXT;
  74. string notAvailableText = DEFAULT_NOT_AVAILABLE_TEXT;
  75. #if !NETCF
  76. // Look for log4net.NullText in AppSettings
  77. string nullTextAppSettingsKey = SystemInfo.GetAppSetting("log4net.NullText");
  78. if (nullTextAppSettingsKey != null && nullTextAppSettingsKey.Length > 0)
  79. {
  80. LogLog.Debug(declaringType, "Initializing NullText value to [" + nullTextAppSettingsKey + "].");
  81. nullText = nullTextAppSettingsKey;
  82. }
  83. // Look for log4net.NotAvailableText in AppSettings
  84. string notAvailableTextAppSettingsKey = SystemInfo.GetAppSetting("log4net.NotAvailableText");
  85. if (notAvailableTextAppSettingsKey != null && notAvailableTextAppSettingsKey.Length > 0)
  86. {
  87. LogLog.Debug(declaringType, "Initializing NotAvailableText value to [" + notAvailableTextAppSettingsKey + "].");
  88. notAvailableText = notAvailableTextAppSettingsKey;
  89. }
  90. #endif
  91. s_notAvailableText = notAvailableText;
  92. s_nullText = nullText;
  93. }
  94. #endregion
  95. #region Public Static Properties
  96. /// <summary>
  97. /// Gets the system dependent line terminator.
  98. /// </summary>
  99. /// <value>
  100. /// The system dependent line terminator.
  101. /// </value>
  102. /// <remarks>
  103. /// <para>
  104. /// Gets the system dependent line terminator.
  105. /// </para>
  106. /// </remarks>
  107. public static string NewLine
  108. {
  109. get
  110. {
  111. #if NETCF
  112. return "\r\n";
  113. #else
  114. return System.Environment.NewLine;
  115. #endif
  116. }
  117. }
  118. /// <summary>
  119. /// Gets the base directory for this <see cref="AppDomain"/>.
  120. /// </summary>
  121. /// <value>The base directory path for the current <see cref="AppDomain"/>.</value>
  122. /// <remarks>
  123. /// <para>
  124. /// Gets the base directory for this <see cref="AppDomain"/>.
  125. /// </para>
  126. /// <para>
  127. /// The value returned may be either a local file path or a URI.
  128. /// </para>
  129. /// </remarks>
  130. public static string ApplicationBaseDirectory
  131. {
  132. get
  133. {
  134. #if NETCF
  135. - return System.IO.Path.GetDirectoryName(SystemInfo.EntryAssemblyLocation) + System.IO.Path.DirectorySeparatorChar;
  136. #elif NETSTANDARD1_3
  137. return Directory.GetCurrentDirectory();
  138. #else
  139. return AppDomain.CurrentDomain.BaseDirectory;
  140. #endif
  141. }
  142. }
  143. /// <summary>
  144. /// Gets the path to the configuration file for the current <see cref="AppDomain"/>.
  145. /// </summary>
  146. /// <value>The path to the configuration file for the current <see cref="AppDomain"/>.</value>
  147. /// <remarks>
  148. /// <para>
  149. /// The .NET Compact Framework 1.0 does not have a concept of a configuration
  150. /// file. For this runtime, we use the entry assembly location as the root for
  151. /// the configuration file name.
  152. /// </para>
  153. /// <para>
  154. /// The value returned may be either a local file path or a URI.
  155. /// </para>
  156. /// </remarks>
  157. public static string ConfigurationFileLocation
  158. {
  159. get
  160. {
  161. #if NETCF || NETSTANDARD1_3
  162. return SystemInfo.EntryAssemblyLocation+".config";
  163. #else
  164. return System.AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
  165. #endif
  166. }
  167. }
  168. /// <summary>
  169. /// Gets the path to the file that first executed in the current <see cref="AppDomain"/>.
  170. /// </summary>
  171. /// <value>The path to the entry assembly.</value>
  172. /// <remarks>
  173. /// <para>
  174. /// Gets the path to the file that first executed in the current <see cref="AppDomain"/>.
  175. /// </para>
  176. /// </remarks>
  177. public static string EntryAssemblyLocation
  178. {
  179. get
  180. {
  181. #if NETCF
  182. return SystemInfo.NativeEntryAssemblyLocation;
  183. #elif NETSTANDARD1_3 // TODO GetEntryAssembly is available for netstandard1.5
  184. return AppContext.BaseDirectory;
  185. #else
  186. return System.Reflection.Assembly.GetEntryAssembly().Location;
  187. #endif
  188. }
  189. }
  190. /// <summary>
  191. /// Gets the ID of the current thread.
  192. /// </summary>
  193. /// <value>The ID of the current thread.</value>
  194. /// <remarks>
  195. /// <para>
  196. /// On the .NET framework, the <c>AppDomain.GetCurrentThreadId</c> method
  197. /// is used to obtain the thread ID for the current thread. This is the
  198. /// operating system ID for the thread.
  199. /// </para>
  200. /// <para>
  201. /// On the .NET Compact Framework 1.0 it is not possible to get the
  202. /// operating system thread ID for the current thread. The native method
  203. /// <c>GetCurrentThreadId</c> is implemented inline in a header file
  204. /// and cannot be called.
  205. /// </para>
  206. /// <para>
  207. /// On the .NET Framework 2.0 the <c>Thread.ManagedThreadId</c> is used as this
  208. /// gives a stable id unrelated to the operating system thread ID which may
  209. /// change if the runtime is using fibers.
  210. /// </para>
  211. /// </remarks>
  212. public static int CurrentThreadId
  213. {
  214. get
  215. {
  216. #if NETCF_1_0
  217. return System.Threading.Thread.CurrentThread.GetHashCode();
  218. #elif NET_2_0 || NETCF_2_0 || MONO_2_0 || MONO_3_5 || MONO_4_0 || NETSTANDARD1_3
  219. return System.Threading.Thread.CurrentThread.ManagedThreadId;
  220. #else
  221. return AppDomain.GetCurrentThreadId();
  222. #endif
  223. }
  224. }
  225. /// <summary>
  226. /// Get the host name or machine name for the current machine
  227. /// </summary>
  228. /// <value>
  229. /// The hostname or machine name
  230. /// </value>
  231. /// <remarks>
  232. /// <para>
  233. /// Get the host name or machine name for the current machine
  234. /// </para>
  235. /// <para>
  236. /// The host name (<see cref="System.Net.Dns.GetHostName"/>) or
  237. /// the machine name (<c>Environment.MachineName</c>) for
  238. /// the current machine, or if neither of these are available
  239. /// then <c>NOT AVAILABLE</c> is returned.
  240. /// </para>
  241. /// </remarks>
  242. public static string HostName
  243. {
  244. get
  245. {
  246. if (s_hostName == null)
  247. {
  248. // Get the DNS host name of the current machine
  249. try
  250. {
  251. // Lookup the host name
  252. s_hostName = System.Net.Dns.GetHostName();
  253. }
  254. catch (System.Net.Sockets.SocketException)
  255. {
  256. LogLog.Debug(declaringType, "Socket exception occurred while getting the dns hostname. Error Ignored.");
  257. }
  258. catch (System.Security.SecurityException)
  259. {
  260. // We may get a security exception looking up the hostname
  261. // You must have Unrestricted DnsPermission to access resource
  262. LogLog.Debug(declaringType, "Security exception occurred while getting the dns hostname. Error Ignored.");
  263. }
  264. catch (Exception ex)
  265. {
  266. LogLog.Debug(declaringType, "Some other exception occurred while getting the dns hostname. Error Ignored.", ex);
  267. }
  268. // Get the NETBIOS machine name of the current machine
  269. if (s_hostName == null || s_hostName.Length == 0)
  270. {
  271. try
  272. {
  273. #if NETSTANDARD1_3
  274. s_hostName = Environment.GetEnvironmentVariable("COMPUTERNAME");
  275. #elif (!SSCLI && !NETCF)
  276. s_hostName = Environment.MachineName;
  277. #endif
  278. }
  279. catch(InvalidOperationException)
  280. {
  281. }
  282. catch(System.Security.SecurityException)
  283. {
  284. // We may get a security exception looking up the machine name
  285. // You must have Unrestricted EnvironmentPermission to access resource
  286. }
  287. }
  288. // Couldn't find a value
  289. if (s_hostName == null || s_hostName.Length == 0)
  290. {
  291. s_hostName = s_notAvailableText;
  292. LogLog.Debug(declaringType, "Could not determine the hostname. Error Ignored. Empty host name will be used");
  293. }
  294. }
  295. return s_hostName;
  296. }
  297. }
  298. /// <summary>
  299. /// Get this application's friendly name
  300. /// </summary>
  301. /// <value>
  302. /// The friendly name of this application as a string
  303. /// </value>
  304. /// <remarks>
  305. /// <para>
  306. /// If available the name of the application is retrieved from
  307. /// the <c>AppDomain</c> using <c>AppDomain.CurrentDomain.FriendlyName</c>.
  308. /// </para>
  309. /// <para>
  310. /// Otherwise the file name of the entry assembly is used.
  311. /// </para>
  312. /// </remarks>
  313. public static string ApplicationFriendlyName
  314. {
  315. get
  316. {
  317. if (s_appFriendlyName == null)
  318. {
  319. try
  320. {
  321. #if !(NETCF || NETSTANDARD1_3)
  322. s_appFriendlyName = AppDomain.CurrentDomain.FriendlyName;
  323. #endif
  324. }
  325. catch(System.Security.SecurityException)
  326. {
  327. // This security exception will occur if the caller does not have
  328. // some undefined set of SecurityPermission flags.
  329. LogLog.Debug(declaringType, "Security exception while trying to get current domain friendly name. Error Ignored.");
  330. }
  331. if (s_appFriendlyName == null || s_appFriendlyName.Length == 0)
  332. {
  333. try
  334. {
  335. string assemblyLocation = SystemInfo.EntryAssemblyLocation;
  336. s_appFriendlyName = System.IO.Path.GetFileName(assemblyLocation);
  337. }
  338. catch(System.Security.SecurityException)
  339. {
  340. // Caller needs path discovery permission
  341. }
  342. }
  343. if (s_appFriendlyName == null || s_appFriendlyName.Length == 0)
  344. {
  345. s_appFriendlyName = s_notAvailableText;
  346. }
  347. }
  348. return s_appFriendlyName;
  349. }
  350. }
  351. /// <summary>
  352. /// Get the start time for the current process.
  353. /// </summary>
  354. /// <remarks>
  355. /// <para>
  356. /// This is the time at which the log4net library was loaded into the
  357. /// AppDomain. Due to reports of a hang in the call to <c>System.Diagnostics.Process.StartTime</c>
  358. /// this is not the start time for the current process.
  359. /// </para>
  360. /// <para>
  361. /// The log4net library should be loaded by an application early during its
  362. /// startup, therefore this start time should be a good approximation for
  363. /// the actual start time.
  364. /// </para>
  365. /// <para>
  366. /// Note that AppDomains may be loaded and unloaded within the
  367. /// same process without the process terminating, however this start time
  368. /// will be set per AppDomain.
  369. /// </para>
  370. /// </remarks>
  371. [Obsolete("Use ProcessStartTimeUtc and convert to local time if needed.")]
  372. public static DateTime ProcessStartTime
  373. {
  374. get { return s_processStartTimeUtc.ToLocalTime(); }
  375. }
  376. /// <summary>
  377. /// Get the UTC start time for the current process.
  378. /// </summary>
  379. /// <remarks>
  380. /// <para>
  381. /// This is the UTC time at which the log4net library was loaded into the
  382. /// AppDomain. Due to reports of a hang in the call to <c>System.Diagnostics.Process.StartTime</c>
  383. /// this is not the start time for the current process.
  384. /// </para>
  385. /// <para>
  386. /// The log4net library should be loaded by an application early during its
  387. /// startup, therefore this start time should be a good approximation for
  388. /// the actual start time.
  389. /// </para>
  390. /// <para>
  391. /// Note that AppDomains may be loaded and unloaded within the
  392. /// same process without the process terminating, however this start time
  393. /// will be set per AppDomain.
  394. /// </para>
  395. /// </remarks>
  396. public static DateTime ProcessStartTimeUtc
  397. {
  398. get { return s_processStartTimeUtc; }
  399. }
  400. /// <summary>
  401. /// Text to output when a <c>null</c> is encountered.
  402. /// </summary>
  403. /// <remarks>
  404. /// <para>
  405. /// Use this value to indicate a <c>null</c> has been encountered while
  406. /// outputting a string representation of an item.
  407. /// </para>
  408. /// <para>
  409. /// The default value is <c>(null)</c>. This value can be overridden by specifying
  410. /// a value for the <c>log4net.NullText</c> appSetting in the application's
  411. /// .config file.
  412. /// </para>
  413. /// </remarks>
  414. public static string NullText
  415. {
  416. get { return s_nullText; }
  417. set { s_nullText = value; }
  418. }
  419. /// <summary>
  420. /// Text to output when an unsupported feature is requested.
  421. /// </summary>
  422. /// <remarks>
  423. /// <para>
  424. /// Use this value when an unsupported feature is requested.
  425. /// </para>
  426. /// <para>
  427. /// The default value is <c>NOT AVAILABLE</c>. This value can be overridden by specifying
  428. /// a value for the <c>log4net.NotAvailableText</c> appSetting in the application's
  429. /// .config file.
  430. /// </para>
  431. /// </remarks>
  432. public static string NotAvailableText
  433. {
  434. get { return s_notAvailableText; }
  435. set { s_notAvailableText = value; }
  436. }
  437. #endregion Public Static Properties
  438. #region Public Static Methods
  439. /// <summary>
  440. /// Gets the assembly location path for the specified assembly.
  441. /// </summary>
  442. /// <param name="myAssembly">The assembly to get the location for.</param>
  443. /// <returns>The location of the assembly.</returns>
  444. /// <remarks>
  445. /// <para>
  446. /// This method does not guarantee to return the correct path
  447. /// to the assembly. If only tries to give an indication as to
  448. /// where the assembly was loaded from.
  449. /// </para>
  450. /// </remarks>
  451. public static string AssemblyLocationInfo(Assembly myAssembly)
  452. {
  453. #if NETCF
  454. return "Not supported on Microsoft .NET Compact Framework";
  455. #elif NETSTANDARD1_3 // TODO Assembly.Location available in netstandard1.5
  456. return "Not supported on .NET Core";
  457. #else
  458. if (myAssembly.GlobalAssemblyCache)
  459. {
  460. return "Global Assembly Cache";
  461. }
  462. else
  463. {
  464. try
  465. {
  466. #if NET_4_0 || MONO_4_0
  467. if (myAssembly.IsDynamic)
  468. {
  469. return "Dynamic Assembly";
  470. }
  471. #else
  472. if (myAssembly is System.Reflection.Emit.AssemblyBuilder)
  473. {
  474. return "Dynamic Assembly";
  475. }
  476. else if(myAssembly.GetType().FullName == "System.Reflection.Emit.InternalAssemblyBuilder")
  477. {
  478. return "Dynamic Assembly";
  479. }
  480. #endif
  481. else
  482. {
  483. // This call requires FileIOPermission for access to the path
  484. // if we don't have permission then we just ignore it and
  485. // carry on.
  486. return myAssembly.Location;
  487. }
  488. }
  489. catch (NotSupportedException)
  490. {
  491. // The location information may be unavailable for dynamic assemblies and a NotSupportedException
  492. // is thrown in those cases. See: http://msdn.microsoft.com/de-de/library/system.reflection.assembly.location.aspx
  493. return "Dynamic Assembly";
  494. }
  495. catch (TargetInvocationException ex)
  496. {
  497. return "Location Detect Failed (" + ex.Message + ")";
  498. }
  499. catch (ArgumentException ex)
  500. {
  501. return "Location Detect Failed (" + ex.Message + ")";
  502. }
  503. catch (System.Security.SecurityException)
  504. {
  505. return "Location Permission Denied";
  506. }
  507. }
  508. #endif
  509. }
  510. /// <summary>
  511. /// Gets the fully qualified name of the <see cref="Type" />, including
  512. /// the name of the assembly from which the <see cref="Type" /> was
  513. /// loaded.
  514. /// </summary>
  515. /// <param name="type">The <see cref="Type" /> to get the fully qualified name for.</param>
  516. /// <returns>The fully qualified name for the <see cref="Type" />.</returns>
  517. /// <remarks>
  518. /// <para>
  519. /// This is equivalent to the <c>Type.AssemblyQualifiedName</c> property,
  520. /// but this method works on the .NET Compact Framework 1.0 as well as
  521. /// the full .NET runtime.
  522. /// </para>
  523. /// </remarks>
  524. public static string AssemblyQualifiedName(Type type)
  525. {
  526. return type.FullName + ", "
  527. #if NETSTANDARD1_3
  528. + type.GetTypeInfo().Assembly.FullName;
  529. #else
  530. + type.Assembly.FullName;
  531. #endif
  532. }
  533. /// <summary>
  534. /// Gets the short name of the <see cref="Assembly" />.
  535. /// </summary>
  536. /// <param name="myAssembly">The <see cref="Assembly" /> to get the name for.</param>
  537. /// <returns>The short name of the <see cref="Assembly" />.</returns>
  538. /// <remarks>
  539. /// <para>
  540. /// The short name of the assembly is the <see cref="Assembly.FullName" />
  541. /// without the version, culture, or public key. i.e. it is just the
  542. /// assembly's file name without the extension.
  543. /// </para>
  544. /// <para>
  545. /// Use this rather than <c>Assembly.GetName().Name</c> because that
  546. /// is not available on the Compact Framework.
  547. /// </para>
  548. /// <para>
  549. /// Because of a FileIOPermission security demand we cannot do
  550. /// the obvious Assembly.GetName().Name. We are allowed to get
  551. /// the <see cref="Assembly.FullName" /> of the assembly so we
  552. /// start from there and strip out just the assembly name.
  553. /// </para>
  554. /// </remarks>
  555. public static string AssemblyShortName(Assembly myAssembly)
  556. {
  557. string name = myAssembly.FullName;
  558. int offset = name.IndexOf(',');
  559. if (offset > 0)
  560. {
  561. name = name.Substring(0, offset);
  562. }
  563. return name.Trim();
  564. // TODO: Do we need to unescape the assembly name string?
  565. // Doc says '\' is an escape char but has this already been
  566. // done by the string loader?
  567. }
  568. /// <summary>
  569. /// Gets the file name portion of the <see cref="Assembly" />, including the extension.
  570. /// </summary>
  571. /// <param name="myAssembly">The <see cref="Assembly" /> to get the file name for.</param>
  572. /// <returns>The file name of the assembly.</returns>
  573. /// <remarks>
  574. /// <para>
  575. /// Gets the file name portion of the <see cref="Assembly" />, including the extension.
  576. /// </para>
  577. /// </remarks>
  578. public static string AssemblyFileName(Assembly myAssembly)
  579. {
  580. #if NETCF || NETSTANDARD1_3 // TODO Assembly.Location is in netstandard1.5 System.Reflection
  581. // This is not very good because it assumes that only
  582. // the entry assembly can be an EXE. In fact multiple
  583. // EXEs can be loaded in to a process.
  584. string assemblyShortName = SystemInfo.AssemblyShortName(myAssembly);
  585. string entryAssemblyShortName = System.IO.Path.GetFileNameWithoutExtension(SystemInfo.EntryAssemblyLocation);
  586. if (string.Compare(assemblyShortName, entryAssemblyShortName, true) == 0)
  587. {
  588. // assembly is entry assembly
  589. return assemblyShortName + ".exe";
  590. }
  591. else
  592. {
  593. // assembly is not entry assembly
  594. return assemblyShortName + ".dll";
  595. }
  596. #else
  597. return System.IO.Path.GetFileName(myAssembly.Location);
  598. #endif
  599. }
  600. /// <summary>
  601. /// Loads the type specified in the type string.
  602. /// </summary>
  603. /// <param name="relativeType">A sibling type to use to load the type.</param>
  604. /// <param name="typeName">The name of the type to load.</param>
  605. /// <param name="throwOnError">Flag set to <c>true</c> to throw an exception if the type cannot be loaded.</param>
  606. /// <param name="ignoreCase"><c>true</c> to ignore the case of the type name; otherwise, <c>false</c></param>
  607. /// <returns>The type loaded or <c>null</c> if it could not be loaded.</returns>
  608. /// <remarks>
  609. /// <para>
  610. /// If the type name is fully qualified, i.e. if contains an assembly name in
  611. /// the type name, the type will be loaded from the system using
  612. /// <see cref="M:Type.GetType(string,bool)"/>.
  613. /// </para>
  614. /// <para>
  615. /// If the type name is not fully qualified, it will be loaded from the assembly
  616. /// containing the specified relative type. If the type is not found in the assembly
  617. /// then all the loaded assemblies will be searched for the type.
  618. /// </para>
  619. /// </remarks>
  620. public static Type GetTypeFromString(Type relativeType, string typeName, bool throwOnError, bool ignoreCase)
  621. {
  622. #if NETSTANDARD1_3
  623. return GetTypeFromString(relativeType.GetTypeInfo().Assembly, typeName, throwOnError, ignoreCase);
  624. #else
  625. return GetTypeFromString(relativeType.Assembly, typeName, throwOnError, ignoreCase);
  626. #endif
  627. }
  628. #if !NETSTANDARD1_3
  629. /// <summary>
  630. /// Loads the type specified in the type string.
  631. /// </summary>
  632. /// <param name="typeName">The name of the type to load.</param>
  633. /// <param name="throwOnError">Flag set to <c>true</c> to throw an exception if the type cannot be loaded.</param>
  634. /// <param name="ignoreCase"><c>true</c> to ignore the case of the type name; otherwise, <c>false</c></param>
  635. /// <returns>The type loaded or <c>null</c> if it could not be loaded.</returns>
  636. /// <remarks>
  637. /// <para>
  638. /// If the type name is fully qualified, i.e. if contains an assembly name in
  639. /// the type name, the type will be loaded from the system using
  640. /// <see cref="M:Type.GetType(string,bool)"/>.
  641. /// </para>
  642. /// <para>
  643. /// If the type name is not fully qualified it will be loaded from the
  644. /// assembly that is directly calling this method. If the type is not found
  645. /// in the assembly then all the loaded assemblies will be searched for the type.
  646. /// </para>
  647. /// </remarks>
  648. public static Type GetTypeFromString(string typeName, bool throwOnError, bool ignoreCase)
  649. {
  650. return GetTypeFromString(Assembly.GetCallingAssembly(), typeName, throwOnError, ignoreCase);
  651. }
  652. #endif
  653. /// <summary>
  654. /// Loads the type specified in the type string.
  655. /// </summary>
  656. /// <param name="relativeAssembly">An assembly to load the type from.</param>
  657. /// <param name="typeName">The name of the type to load.</param>
  658. /// <param name="throwOnError">Flag set to <c>true</c> to throw an exception if the type cannot be loaded.</param>
  659. /// <param name="ignoreCase"><c>true</c> to ignore the case of the type name; otherwise, <c>false</c></param>
  660. /// <returns>The type loaded or <c>null</c> if it could not be loaded.</returns>
  661. /// <remarks>
  662. /// <para>
  663. /// If the type name is fully qualified, i.e. if contains an assembly name in
  664. /// the type name, the type will be loaded from the system using
  665. /// <see cref="M:Type.GetType(string,bool)"/>.
  666. /// </para>
  667. /// <para>
  668. /// If the type name is not fully qualified it will be loaded from the specified
  669. /// assembly. If the type is not found in the assembly then all the loaded assemblies
  670. /// will be searched for the type.
  671. /// </para>
  672. /// </remarks>
  673. public static Type GetTypeFromString(Assembly relativeAssembly, string typeName, bool throwOnError, bool ignoreCase)
  674. {
  675. // Check if the type name specifies the assembly name
  676. if(typeName.IndexOf(',') == -1)
  677. {
  678. //LogLog.Debug(declaringType, "SystemInfo: Loading type ["+typeName+"] from assembly ["+relativeAssembly.FullName+"]");
  679. #if NETSTANDARD1_3
  680. return relativeAssembly.GetType(typeName, throwOnError, ignoreCase);
  681. #elif NETCF
  682. return relativeAssembly.GetType(typeName, throwOnError);
  683. #else
  684. // Attempt to lookup the type from the relativeAssembly
  685. Type type = relativeAssembly.GetType(typeName, false, ignoreCase);
  686. if (type != null)
  687. {
  688. // Found type in relative assembly
  689. //LogLog.Debug(declaringType, "SystemInfo: Loaded type ["+typeName+"] from assembly ["+relativeAssembly.FullName+"]");
  690. return type;
  691. }
  692. Assembly[] loadedAssemblies = null;
  693. try
  694. {
  695. loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies();
  696. }
  697. catch(System.Security.SecurityException)
  698. {
  699. // Insufficient permissions to get the list of loaded assemblies
  700. }
  701. if (loadedAssemblies != null)
  702. {
  703. Type fallback = null;
  704. // Search the loaded assemblies for the type
  705. foreach (Assembly assembly in loadedAssemblies)
  706. {
  707. Type t = assembly.GetType(typeName, false, ignoreCase);
  708. if (t != null)
  709. {
  710. // Found type in loaded assembly
  711. LogLog.Debug(declaringType, "Loaded type ["+typeName+"] from assembly ["+assembly.FullName+"] by searching loaded assemblies.");
  712. if (assembly.GlobalAssemblyCache)
  713. {
  714. fallback = t;
  715. }
  716. else
  717. {
  718. return t;
  719. }
  720. }
  721. }
  722. if (fallback != null)
  723. {
  724. return fallback;
  725. }
  726. }
  727. // Didn't find the type
  728. if (throwOnError)
  729. {
  730. throw new TypeLoadException("Could not load type ["+typeName+"]. Tried assembly ["+relativeAssembly.FullName+"] and all loaded assemblies");
  731. }
  732. return null;
  733. #endif
  734. }
  735. else
  736. {
  737. // Includes explicit assembly name
  738. //LogLog.Debug(declaringType, "SystemInfo: Loading type ["+typeName+"] from global Type");
  739. #if NETCF
  740. // In NETCF 2 and 3 arg versions seem to behave differently
  741. // https://issues.apache.org/jira/browse/LOG4NET-113
  742. return Type.GetType(typeName, throwOnError);
  743. #else
  744. return Type.GetType(typeName, throwOnError, ignoreCase);
  745. #endif
  746. }
  747. }
  748. /// <summary>
  749. /// Generate a new guid
  750. /// </summary>
  751. /// <returns>A new Guid</returns>
  752. /// <remarks>
  753. /// <para>
  754. /// Generate a new guid
  755. /// </para>
  756. /// </remarks>
  757. public static Guid NewGuid()
  758. {
  759. #if NETCF_1_0
  760. return PocketGuid.NewGuid();
  761. #else
  762. return Guid.NewGuid();
  763. #endif
  764. }
  765. /// <summary>
  766. /// Create an <see cref="ArgumentOutOfRangeException"/>
  767. /// </summary>
  768. /// <param name="parameterName">The name of the parameter that caused the exception</param>
  769. /// <param name="actualValue">The value of the argument that causes this exception</param>
  770. /// <param name="message">The message that describes the error</param>
  771. /// <returns>the ArgumentOutOfRangeException object</returns>
  772. /// <remarks>
  773. /// <para>
  774. /// Create a new instance of the <see cref="ArgumentOutOfRangeException"/> class
  775. /// with a specified error message, the parameter name, and the value
  776. /// of the argument.
  777. /// </para>
  778. /// <para>
  779. /// The Compact Framework does not support the 3 parameter constructor for the
  780. /// <see cref="ArgumentOutOfRangeException"/> type. This method provides an
  781. /// implementation that works for all platforms.
  782. /// </para>
  783. /// </remarks>
  784. public static ArgumentOutOfRangeException CreateArgumentOutOfRangeException(string parameterName, object actualValue, string message)
  785. {
  786. #if NETCF_1_0
  787. return new ArgumentOutOfRangeException(message + " [param=" + parameterName + "] [value=" + actualValue + "]");
  788. #elif NETCF_2_0
  789. return new ArgumentOutOfRangeException(parameterName, message + " [value=" + actualValue + "]");
  790. #else
  791. return new ArgumentOutOfRangeException(parameterName, actualValue, message);
  792. #endif
  793. }
  794. /// <summary>
  795. /// Parse a string into an <see cref="Int32"/> value
  796. /// </summary>
  797. /// <param name="s">the string to parse</param>
  798. /// <param name="val">out param where the parsed value is placed</param>
  799. /// <returns><c>true</c> if the string was able to be parsed into an integer</returns>
  800. /// <remarks>
  801. /// <para>
  802. /// Attempts to parse the string into an integer. If the string cannot
  803. /// be parsed then this method returns <c>false</c>. The method does not throw an exception.
  804. /// </para>
  805. /// </remarks>
  806. public static bool TryParse(string s, out int val)
  807. {
  808. #if NETCF
  809. val = 0;
  810. try
  811. {
  812. val = int.Parse(s, System.Globalization.NumberStyles.Integer, System.Globalization.CultureInfo.InvariantCulture);
  813. return true;
  814. }
  815. catch
  816. {
  817. }
  818. return false;
  819. #else
  820. // Initialise out param
  821. val = 0;
  822. try
  823. {
  824. double doubleVal;
  825. if (Double.TryParse(s, System.Globalization.NumberStyles.Integer, System.Globalization.CultureInfo.InvariantCulture, out doubleVal))
  826. {
  827. val = Convert.ToInt32(doubleVal);
  828. return true;
  829. }
  830. }
  831. catch
  832. {
  833. // Ignore exception, just return false
  834. }
  835. return false;
  836. #endif
  837. }
  838. /// <summary>
  839. /// Parse a string into an <see cref="Int64"/> value
  840. /// </summary>
  841. /// <param name="s">the string to parse</param>
  842. /// <param name="val">out param where the parsed value is placed</param>
  843. /// <returns><c>true</c> if the string was able to be parsed into an integer</returns>
  844. /// <remarks>
  845. /// <para>
  846. /// Attempts to parse the string into an integer. If the string cannot
  847. /// be parsed then this method returns <c>false</c>. The method does not throw an exception.
  848. /// </para>
  849. /// </remarks>
  850. public static bool TryParse(string s, out long val)
  851. {
  852. #if NETCF
  853. val = 0;
  854. try
  855. {
  856. val = long.Parse(s, System.Globalization.NumberStyles.Integer, System.Globalization.CultureInfo.InvariantCulture);
  857. return true;
  858. }
  859. catch
  860. {
  861. }
  862. return false;
  863. #else
  864. // Initialise out param
  865. val = 0;
  866. try
  867. {
  868. double doubleVal;
  869. if (Double.TryParse(s, System.Globalization.NumberStyles.Integer, System.Globalization.CultureInfo.InvariantCulture, out doubleVal))
  870. {
  871. val = Convert.ToInt64(doubleVal);
  872. return true;
  873. }
  874. }
  875. catch
  876. {
  877. // Ignore exception, just return false
  878. }
  879. return false;
  880. #endif
  881. }
  882. /// <summary>
  883. /// Parse a string into an <see cref="Int16"/> value
  884. /// </summary>
  885. /// <param name="s">the string to parse</param>
  886. /// <param name="val">out param where the parsed value is placed</param>
  887. /// <returns><c>true</c> if the string was able to be parsed into an integer</returns>
  888. /// <remarks>
  889. /// <para>
  890. /// Attempts to parse the string into an integer. If the string cannot
  891. /// be parsed then this method returns <c>false</c>. The method does not throw an exception.
  892. /// </para>
  893. /// </remarks>
  894. public static bool TryParse(string s, out short val)
  895. {
  896. #if NETCF
  897. val = 0;
  898. try
  899. {
  900. val = short.Parse(s, System.Globalization.NumberStyles.Integer, System.Globalization.CultureInfo.InvariantCulture);
  901. return true;
  902. }
  903. catch
  904. {
  905. }
  906. return false;
  907. #else
  908. // Initialise out param
  909. val = 0;
  910. try
  911. {
  912. double doubleVal;
  913. if (Double.TryParse(s, System.Globalization.NumberStyles.Integer, System.Globalization.CultureInfo.InvariantCulture, out doubleVal))
  914. {
  915. val = Convert.ToInt16(doubleVal);
  916. return true;
  917. }
  918. }
  919. catch
  920. {
  921. // Ignore exception, just return false
  922. }
  923. return false;
  924. #endif
  925. }
  926. /// <summary>
  927. /// Lookup an application setting
  928. /// </summary>
  929. /// <param name="key">the application settings key to lookup</param>
  930. /// <returns>the value for the key, or <c>null</c></returns>
  931. /// <remarks>
  932. /// <para>
  933. /// Configuration APIs are not supported under the Compact Framework
  934. /// </para>
  935. /// </remarks>
  936. public static string GetAppSetting(string key)
  937. {
  938. try
  939. {
  940. #if NETCF || NETSTANDARD1_3
  941. // Configuration APIs are not suported under the Compact Framework
  942. #elif NET_2_0
  943. return ConfigurationManager.AppSettings[key];
  944. #else
  945. return ConfigurationSettings.AppSettings[key];
  946. #endif
  947. }
  948. catch(Exception ex)
  949. {
  950. // If an exception is thrown here then it looks like the config file does not parse correctly.
  951. LogLog.Error(declaringType, "Exception while reading ConfigurationSettings. Check your .config file is well formed XML.", ex);
  952. }
  953. return null;
  954. }
  955. /// <summary>
  956. /// Convert a path into a fully qualified local file path.
  957. /// </summary>
  958. /// <param name="path">The path to convert.</param>
  959. /// <returns>The fully qualified path.</returns>
  960. /// <remarks>
  961. /// <para>
  962. /// Converts the path specified to a fully
  963. /// qualified path. If the path is relative it is
  964. /// taken as relative from the application base
  965. /// directory.
  966. /// </para>
  967. /// <para>
  968. /// The path specified must be a local file path, a URI is not supported.
  969. /// </para>
  970. /// </remarks>
  971. public static string ConvertToFullPath(string path)
  972. {
  973. if (path == null)
  974. {
  975. throw new ArgumentNullException("path");
  976. }
  977. string baseDirectory = "";
  978. try
  979. {
  980. string applicationBaseDirectory = SystemInfo.ApplicationBaseDirectory;
  981. if (applicationBaseDirectory != null)
  982. {
  983. // applicationBaseDirectory may be a URI not a local file path
  984. Uri applicationBaseDirectoryUri = new Uri(applicationBaseDirectory);
  985. if (applicationBaseDirectoryUri.IsFile)
  986. {
  987. baseDirectory = applicationBaseDirectoryUri.LocalPath;
  988. }
  989. }
  990. }
  991. catch
  992. {
  993. // Ignore URI exceptions & SecurityExceptions from SystemInfo.ApplicationBaseDirectory
  994. }
  995. if (baseDirectory != null && baseDirectory.Length > 0)
  996. {
  997. // Note that Path.Combine will return the second path if it is rooted
  998. return Path.GetFullPath(Path.Combine(baseDirectory, path));
  999. }
  1000. return Path.GetFullPath(path);
  1001. }
  1002. /// <summary>
  1003. /// Creates a new case-insensitive instance of the <see cref="Hashtable"/> class with the default initial capacity.
  1004. /// </summary>
  1005. /// <returns>A new case-insensitive instance of the <see cref="Hashtable"/> class with the default initial capacity</returns>
  1006. /// <remarks>
  1007. /// <para>
  1008. /// The new Hashtable instance uses the default load factor, the CaseInsensitiveHashCodeProvider, and the CaseInsensitiveComparer.
  1009. /// </para>
  1010. /// </remarks>
  1011. public static Hashtable CreateCaseInsensitiveHashtable()
  1012. {
  1013. #if NETCF_1_0
  1014. return new Hashtable(CaseInsensitiveHashCodeProvider.Default, CaseInsensitiveComparer.Default);
  1015. #elif NETCF_2_0 || NET_2_0 || MONO_2_0 || MONO_3_5 || MONO_4_0
  1016. return new Hashtable(StringComparer.OrdinalIgnoreCase);
  1017. #else
  1018. return System.Collections.Specialized.CollectionsUtil.CreateCaseInsensitiveHashtable();
  1019. #endif
  1020. }
  1021. /// <summary>
  1022. /// Tests two strings for equality, the ignoring case.
  1023. /// </summary>
  1024. /// <remarks>
  1025. /// If the platform permits, culture information is ignored completely (ordinal comparison).
  1026. /// The aim of this method is to provide a fast comparison that deals with <c>null</c> and ignores different casing.
  1027. /// It is not supposed to deal with various, culture-specific habits.
  1028. /// Use it to compare against pure ASCII constants, like keywords etc.
  1029. /// </remarks>
  1030. /// <param name="a">The one string.</param>
  1031. /// <param name="b">The other string.</param>
  1032. /// <returns><c>true</c> if the strings are equal, <c>false</c> otherwise.</returns>
  1033. public static Boolean EqualsIgnoringCase(String a, String b)
  1034. {
  1035. #if NET_1_0 || NET_1_1 || NETCF_1_0
  1036. return string.Compare(a, b, true, System.Globalization.CultureInfo.InvariantCulture) == 0
  1037. #elif NETSTANDARD1_3
  1038. return CultureInfo.InvariantCulture.CompareInfo.Compare(a, b, CompareOptions.IgnoreCase) == 0;
  1039. #else // >= .NET-2.0
  1040. return String.Equals(a, b, StringComparison.OrdinalIgnoreCase);
  1041. #endif
  1042. }
  1043. #endregion Public Static Methods
  1044. #region Private Static Methods
  1045. #if NETCF
  1046. private static string NativeEntryAssemblyLocation
  1047. {
  1048. get
  1049. {
  1050. StringBuilder moduleName = null;
  1051. IntPtr moduleHandle = GetModuleHandle(IntPtr.Zero);
  1052. if (moduleHandle != IntPtr.Zero)
  1053. {
  1054. moduleName = new StringBuilder(255);
  1055. if (GetModuleFileName(moduleHandle, moduleName, moduleName.Capacity) == 0)
  1056. {
  1057. throw new NotSupportedException(NativeError.GetLastError().ToString());
  1058. }
  1059. }
  1060. else
  1061. {
  1062. throw new NotSupportedException(NativeError.GetLastError().ToString());
  1063. }
  1064. return moduleName.ToString();
  1065. }
  1066. }
  1067. [DllImport("CoreDll.dll", SetLastError=true, CharSet=CharSet.Unicode)]
  1068. private static extern IntPtr GetModuleHandle(IntPtr ModuleName);
  1069. [DllImport("CoreDll.dll", SetLastError=true, CharSet=CharSet.Unicode)]
  1070. private static extern Int32 GetModuleFileName(
  1071. IntPtr hModule,
  1072. StringBuilder ModuleName,
  1073. Int32 cch);
  1074. #endif
  1075. #endregion Private Static Methods
  1076. #region Public Static Fields
  1077. /// <summary>
  1078. /// Gets an empty array of types.
  1079. /// </summary>
  1080. /// <remarks>
  1081. /// <para>
  1082. /// The <c>Type.EmptyTypes</c> field is not available on
  1083. /// the .NET Compact Framework 1.0.
  1084. /// </para>
  1085. /// </remarks>
  1086. public static readonly Type[] EmptyTypes = new Type[0];
  1087. #endregion Public Static Fields
  1088. #region Private Static Fields
  1089. /// <summary>
  1090. /// The fully qualified type of the SystemInfo class.
  1091. /// </summary>
  1092. /// <remarks>
  1093. /// Used by the internal logger to record the Type of the
  1094. /// log message.
  1095. /// </remarks>
  1096. private readonly static Type declaringType = typeof(SystemInfo);
  1097. /// <summary>
  1098. /// Cache the host name for the current machine
  1099. /// </summary>
  1100. private static string s_hostName;
  1101. /// <summary>
  1102. /// Cache the application friendly name
  1103. /// </summary>
  1104. private static string s_appFriendlyName;
  1105. /// <summary>
  1106. /// Text to output when a <c>null</c> is encountered.
  1107. /// </summary>
  1108. private static string s_nullText;
  1109. /// <summary>
  1110. /// Text to output when an unsupported feature is requested.
  1111. /// </summary>
  1112. private static string s_notAvailableText;
  1113. /// <summary>
  1114. /// Start time for the current process.
  1115. /// </summary>
  1116. private static DateTime s_processStartTimeUtc = DateTime.UtcNow;
  1117. #endregion
  1118. #region Compact Framework Helper Classes
  1119. #if NETCF_1_0
  1120. /// <summary>
  1121. /// Generate GUIDs on the .NET Compact Framework.
  1122. /// </summary>
  1123. public class PocketGuid
  1124. {
  1125. // guid variant types
  1126. private enum GuidVariant
  1127. {
  1128. ReservedNCS = 0x00,
  1129. Standard = 0x02,
  1130. ReservedMicrosoft = 0x06,
  1131. ReservedFuture = 0x07
  1132. }
  1133. // guid version types
  1134. private enum GuidVersion
  1135. {
  1136. TimeBased = 0x01,
  1137. Reserved = 0x02,
  1138. NameBased = 0x03,
  1139. Random = 0x04
  1140. }
  1141. // constants that are used in the class
  1142. private class Const
  1143. {
  1144. // number of bytes in guid
  1145. public const int ByteArraySize = 16;
  1146. // multiplex variant info
  1147. public const int VariantByte = 8;
  1148. public const int VariantByteMask = 0x3f;
  1149. public const int VariantByteShift = 6;
  1150. // multiplex version info
  1151. public const int VersionByte = 7;
  1152. public const int VersionByteMask = 0x0f;
  1153. public const int VersionByteShift = 4;
  1154. }
  1155. // imports for the crypto api functions
  1156. private class WinApi
  1157. {
  1158. public const uint PROV_RSA_FULL = 1;
  1159. public const uint CRYPT_VERIFYCONTEXT = 0xf0000000;
  1160. [DllImport("CoreDll.dll")]
  1161. public static extern bool CryptAcquireContext(
  1162. ref IntPtr phProv, string pszContainer, string pszProvider,
  1163. uint dwProvType, uint dwFlags);
  1164. [DllImport("CoreDll.dll")]
  1165. public static extern bool CryptReleaseContext(
  1166. IntPtr hProv, uint dwFlags);
  1167. [DllImport("CoreDll.dll")]
  1168. public static extern bool CryptGenRandom(
  1169. IntPtr hProv, int dwLen, byte[] pbBuffer);
  1170. }
  1171. // all static methods
  1172. private PocketGuid()
  1173. {
  1174. }
  1175. /// <summary>
  1176. /// Return a new System.Guid object.
  1177. /// </summary>
  1178. public static Guid NewGuid()
  1179. {
  1180. IntPtr hCryptProv = IntPtr.Zero;
  1181. Guid guid = Guid.Empty;
  1182. try
  1183. {
  1184. // holds random bits for guid
  1185. byte[] bits = new byte[Const.ByteArraySize];
  1186. // get crypto provider handle
  1187. if (!WinApi.CryptAcquireContext(ref hCryptProv, null, null,
  1188. WinApi.PROV_RSA_FULL, WinApi.CRYPT_VERIFYCONTEXT))
  1189. {
  1190. throw new SystemException(
  1191. "Failed to acquire cryptography handle.");
  1192. }
  1193. // generate a 128 bit (16 byte) cryptographically random number
  1194. if (!WinApi.CryptGenRandom(hCryptProv, bits.Length, bits))
  1195. {
  1196. throw new SystemException(
  1197. "Failed to generate cryptography random bytes.");
  1198. }
  1199. // set the variant
  1200. bits[Const.VariantByte] &= Const.VariantByteMask;
  1201. bits[Const.VariantByte] |=
  1202. ((int)GuidVariant.Standard << Const.VariantByteShift);
  1203. // set the version
  1204. bits[Const.VersionByte] &= Const.VersionByteMask;
  1205. bits[Const.VersionByte] |=
  1206. ((int)GuidVersion.Random << Const.VersionByteShift);
  1207. // create the new System.Guid object
  1208. guid = new Guid(bits);
  1209. }
  1210. finally
  1211. {
  1212. // release the crypto provider handle
  1213. if (hCryptProv != IntPtr.Zero)
  1214. WinApi.CryptReleaseContext(hCryptProv, 0);
  1215. }
  1216. return guid;
  1217. }
  1218. }
  1219. #endif
  1220. #endregion Compact Framework Helper Classes
  1221. }
  1222. }