1 /* 2 KeePass Password Safe - The Open-Source Password Manager 3 Copyright (C) 2003-2021 Dominik Reichl <dominik.reichl@t-online.de> 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 2 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, write to the Free Software 17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 */ 19 20 using System; 21 using System.Collections.Generic; 22 using System.ComponentModel; 23 using System.Diagnostics; 24 using System.Drawing; 25 using System.IO; 26 using System.Reflection; 27 using System.Runtime.InteropServices; 28 using System.Security.Cryptography; 29 using System.Text; 30 using System.Text.RegularExpressions; 31 using System.Windows.Forms; 32 33 using Microsoft.Win32; 34 35 using KeePass.App; 36 using KeePass.Forms; 37 using KeePass.Native; 38 using KeePass.Resources; 39 using KeePass.Util.Spr; 40 41 using KeePassLib; 42 using KeePassLib.Delegates; 43 using KeePassLib.Serialization; 44 using KeePassLib.Utility; 45 46 using NativeLib = KeePassLib.Native.NativeLib; 47 48 namespace KeePass.Util 49 { 50 public sealed class OpenUrlEventArgs : EventArgs 51 { 52 private string m_strUrl; 53 public string Url 54 { 55 get { return m_strUrl; } 56 set { m_strUrl = value; } 57 } 58 59 private readonly PwEntry m_pe; 60 public PwEntry Entry 61 { 62 get { return m_pe; } 63 } 64 65 private readonly bool m_bAllowOverride; 66 public bool AllowOverride 67 { 68 get { return m_bAllowOverride; } 69 } 70 71 private readonly string m_strBaseRaw; 72 public string BaseRaw 73 { 74 get { return m_strBaseRaw; } 75 } 76 OpenUrlEventArgs(string strUrlToOpen, PwEntry peDataSource, bool bAllowOverride, string strBaseRaw)77 public OpenUrlEventArgs(string strUrlToOpen, PwEntry peDataSource, 78 bool bAllowOverride, string strBaseRaw) 79 { 80 m_strUrl = strUrlToOpen; 81 m_pe = peDataSource; 82 m_bAllowOverride = bAllowOverride; 83 m_strBaseRaw = strBaseRaw; 84 } 85 } 86 87 public static class WinUtil 88 { 89 private static bool m_bIsWindows9x = false; 90 private static bool m_bIsWindows2000 = false; 91 private static bool m_bIsWindowsXP = false; 92 private static bool m_bIsAtLeastWindows2000 = false; 93 private static bool m_bIsAtLeastWindowsVista = false; 94 private static bool m_bIsAtLeastWindows7 = false; 95 private static bool m_bIsAtLeastWindows8 = false; 96 private static bool m_bIsAtLeastWindows10 = false; 97 private static bool m_bIsAppX = false; 98 99 private static string m_strExePath = null; 100 101 private static ulong m_uFrameworkVersion = 0; 102 103 public static event EventHandler<OpenUrlEventArgs> OpenUrlPre; 104 105 public static bool IsWindows9x 106 { 107 get { return m_bIsWindows9x; } 108 } 109 110 public static bool IsWindows2000 111 { 112 get { return m_bIsWindows2000; } 113 } 114 115 public static bool IsWindowsXP 116 { 117 get { return m_bIsWindowsXP; } 118 } 119 120 public static bool IsAtLeastWindows2000 121 { 122 get { return m_bIsAtLeastWindows2000; } 123 } 124 125 public static bool IsAtLeastWindowsVista 126 { 127 get { return m_bIsAtLeastWindowsVista; } 128 } 129 130 public static bool IsAtLeastWindows7 131 { 132 get { return m_bIsAtLeastWindows7; } 133 } 134 135 public static bool IsAtLeastWindows8 136 { 137 get { return m_bIsAtLeastWindows8; } 138 } 139 140 public static bool IsAtLeastWindows10 141 { 142 get { return m_bIsAtLeastWindows10; } 143 } 144 145 public static bool IsAppX 146 { 147 get { return m_bIsAppX; } 148 } 149 WinUtil()150 static WinUtil() 151 { 152 if(NativeLib.IsUnix()) return; 153 154 OperatingSystem os = Environment.OSVersion; 155 Version v = os.Version; 156 157 m_bIsWindows9x = (os.Platform == PlatformID.Win32Windows); 158 m_bIsWindows2000 = ((v.Major == 5) && (v.Minor == 0)); 159 m_bIsWindowsXP = ((v.Major == 5) && (v.Minor == 1)); 160 161 m_bIsAtLeastWindows2000 = (v.Major >= 5); 162 m_bIsAtLeastWindowsVista = (v.Major >= 6); 163 m_bIsAtLeastWindows7 = ((v.Major >= 7) || ((v.Major == 6) && (v.Minor >= 1))); 164 m_bIsAtLeastWindows8 = ((v.Major >= 7) || ((v.Major == 6) && (v.Minor >= 2))); 165 166 // Environment.OSVersion is reliable only up to version 6.2; 167 // https://msdn.microsoft.com/library/windows/desktop/ms724832.aspx 168 RegistryKey rk = null; 169 try 170 { 171 rk = Registry.LocalMachine.OpenSubKey( 172 "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", false); 173 if(rk != null) 174 { 175 string str = rk.GetValue("CurrentMajorVersionNumber", 176 string.Empty).ToString(); 177 uint u; 178 if(uint.TryParse(str, out u)) 179 m_bIsAtLeastWindows10 = (u >= 10); 180 else { Debug.Assert(string.IsNullOrEmpty(str)); } 181 } 182 else { Debug.Assert(false); } 183 } 184 catch(Exception) { Debug.Assert(false); } 185 finally { if(rk != null) rk.Close(); } 186 187 try 188 { 189 string strDir = UrlUtil.GetFileDirectory(GetExecutable(), false, false); 190 if(strDir.IndexOf("\\WindowsApps\\", StrUtil.CaseIgnoreCmp) >= 0) 191 { 192 Regex rx = new Regex("\\\\WindowsApps\\\\.*?_\\d+(\\.\\d+)*_", 193 RegexOptions.IgnoreCase); 194 m_bIsAppX = rx.IsMatch(strDir); 195 } 196 else { Debug.Assert(!m_bIsAppX); } // No AppX by default 197 } 198 catch(Exception) { Debug.Assert(false); } 199 } 200 OpenEntryUrl(PwEntry pe)201 public static void OpenEntryUrl(PwEntry pe) 202 { 203 if(pe == null) { Debug.Assert(false); throw new ArgumentNullException("pe"); } 204 205 string strUrl = pe.Strings.ReadSafe(PwDefs.UrlField); 206 207 // The user interface enables the URL open command if and 208 // only if the URL is not empty, i.e. it ignores overrides 209 if(strUrl.Length == 0) return; 210 211 if(pe.OverrideUrl.Length > 0) 212 OpenUrl(pe.OverrideUrl, pe, true, strUrl); 213 else 214 { 215 string strOverride = Program.Config.Integration.UrlOverride; 216 if(strOverride.Length > 0) 217 OpenUrl(strOverride, pe, true, strUrl); 218 else 219 OpenUrl(strUrl, pe, true); 220 } 221 } 222 OpenUrl(string strUrlToOpen, PwEntry peDataSource)223 public static void OpenUrl(string strUrlToOpen, PwEntry peDataSource) 224 { 225 OpenUrl(strUrlToOpen, peDataSource, true, null); 226 } 227 OpenUrl(string strUrlToOpen, PwEntry peDataSource, bool bAllowOverride)228 public static void OpenUrl(string strUrlToOpen, PwEntry peDataSource, 229 bool bAllowOverride) 230 { 231 OpenUrl(strUrlToOpen, peDataSource, bAllowOverride, null); 232 } 233 OpenUrl(string strUrlToOpen, PwEntry peDataSource, bool bAllowOverride, string strBaseRaw)234 public static void OpenUrl(string strUrlToOpen, PwEntry peDataSource, 235 bool bAllowOverride, string strBaseRaw) 236 { 237 VoidDelegate f = delegate() 238 { 239 try { OpenUrlPriv(strUrlToOpen, peDataSource, bAllowOverride, strBaseRaw); } 240 catch(Exception) { Debug.Assert(false); } 241 }; 242 243 MainForm mf = Program.MainForm; 244 if((mf != null) && mf.InvokeRequired) mf.Invoke(f); 245 else f(); 246 } 247 OpenUrlPriv(string strUrlToOpen, PwEntry peDataSource, bool bAllowOverride, string strBaseRaw)248 private static void OpenUrlPriv(string strUrlToOpen, PwEntry peDataSource, 249 bool bAllowOverride, string strBaseRaw) 250 { 251 if(string.IsNullOrEmpty(strUrlToOpen)) { Debug.Assert(false); return; } 252 253 if(WinUtil.OpenUrlPre != null) 254 { 255 OpenUrlEventArgs e = new OpenUrlEventArgs(strUrlToOpen, peDataSource, 256 bAllowOverride, strBaseRaw); 257 WinUtil.OpenUrlPre(null, e); 258 strUrlToOpen = e.Url; 259 260 if(string.IsNullOrEmpty(strUrlToOpen)) return; 261 } 262 263 string strPrevWorkDir = WinUtil.GetWorkingDirectory(); 264 string strThisExe = WinUtil.GetExecutable(); 265 266 string strExeDir = UrlUtil.GetFileDirectory(strThisExe, false, true); 267 WinUtil.SetWorkingDirectory(strExeDir); 268 269 string strUrl = CompileUrl(strUrlToOpen, peDataSource, bAllowOverride, 270 strBaseRaw, null); 271 272 if(string.IsNullOrEmpty(strUrl)) { } // Might be placeholder only 273 else if(WinUtil.IsCommandLineUrl(strUrl)) 274 { 275 string strApp, strArgs; 276 StrUtil.SplitCommandLine(WinUtil.GetCommandLineFromUrl(strUrl), 277 out strApp, out strArgs); 278 279 try 280 { 281 try { NativeLib.StartProcess(strApp, strArgs); } 282 catch(Win32Exception) 283 { 284 ProcessStartInfo psi = new ProcessStartInfo(); 285 psi.FileName = strApp; 286 if(!string.IsNullOrEmpty(strArgs)) psi.Arguments = strArgs; 287 psi.UseShellExecute = false; 288 289 NativeLib.StartProcess(psi); 290 } 291 } 292 catch(Exception exCmd) 293 { 294 string strMsg = KPRes.FileOrUrl + ": " + strApp; 295 if(!string.IsNullOrEmpty(strArgs)) 296 strMsg += MessageService.NewParagraph + 297 KPRes.Arguments + ": " + strArgs; 298 299 MessageService.ShowWarning(strMsg, exCmd); 300 } 301 } 302 else // Standard URL 303 { 304 try { NativeLib.StartProcess(strUrl); } 305 catch(Exception exUrl) 306 { 307 MessageService.ShowWarning(strUrl, exUrl); 308 } 309 } 310 311 // Restore previous working directory 312 WinUtil.SetWorkingDirectory(strPrevWorkDir); 313 314 // SprEngine.Compile might have modified the database 315 MainForm mf = Program.MainForm; 316 if(mf != null) 317 { 318 mf.RefreshEntriesList(); 319 mf.UpdateUI(false, null, false, null, false, null, false); 320 } 321 } 322 CompileUrl(string strUrlToOpen, PwEntry pe, bool bAllowOverride, string strBaseRaw, bool? obForceEncCmd)323 internal static string CompileUrl(string strUrlToOpen, PwEntry pe, 324 bool bAllowOverride, string strBaseRaw, bool? obForceEncCmd) 325 { 326 MainForm mf = Program.MainForm; 327 PwDatabase pd = null; 328 try { if(mf != null) pd = mf.DocumentManager.SafeFindContainerOf(pe); } 329 catch(Exception) { Debug.Assert(false); } 330 331 string strUrlFlt = strUrlToOpen; 332 strUrlFlt = strUrlFlt.TrimStart(new char[] { ' ', '\t', '\r', '\n' }); 333 334 bool bEncCmd = (obForceEncCmd.HasValue ? obForceEncCmd.Value : 335 WinUtil.IsCommandLineUrl(strUrlFlt)); 336 337 SprContext ctx = new SprContext(pe, pd, SprCompileFlags.All, false, bEncCmd); 338 ctx.Base = strBaseRaw; 339 ctx.BaseIsEncoded = false; 340 341 string strUrl = SprEngine.Compile(strUrlFlt, ctx); 342 343 string strOvr = Program.Config.Integration.UrlSchemeOverrides.GetOverrideForUrl( 344 strUrl); 345 if(!bAllowOverride) strOvr = null; 346 if(strOvr != null) 347 { 348 bool bEncCmdOvr = WinUtil.IsCommandLineUrl(strOvr); 349 350 SprContext ctxOvr = new SprContext(pe, pd, SprCompileFlags.All, 351 false, bEncCmdOvr); 352 ctxOvr.Base = strUrl; 353 ctxOvr.BaseIsEncoded = bEncCmd; 354 355 strUrl = SprEngine.Compile(strOvr, ctxOvr); 356 } 357 358 return strUrl; 359 } 360 OpenUrlWithApp(string strUrlToOpen, PwEntry peDataSource, string strAppPath)361 public static void OpenUrlWithApp(string strUrlToOpen, PwEntry peDataSource, 362 string strAppPath) 363 { 364 if(string.IsNullOrEmpty(strUrlToOpen)) { Debug.Assert(false); return; } 365 if(string.IsNullOrEmpty(strAppPath)) { Debug.Assert(false); return; } 366 367 string strUrl = strUrlToOpen.Trim(); 368 if(strUrl.Length == 0) { Debug.Assert(false); return; } 369 strUrl = SprEncoding.EncodeForCommandLine(strUrl); 370 371 string strApp = strAppPath.Trim(); 372 if(strApp.Length == 0) { Debug.Assert(false); return; } 373 strApp = SprEncoding.EncodeForCommandLine(strApp); 374 375 string str = "cmd://\"" + strApp + "\" \"" + strUrl + "\""; 376 OpenUrl(str, peDataSource, false); 377 } 378 OpenUrlDirectly(string strUrl)379 internal static void OpenUrlDirectly(string strUrl) 380 { 381 if(string.IsNullOrEmpty(strUrl)) { Debug.Assert(false); return; } 382 383 try { NativeLib.StartProcess(strUrl); } 384 catch(Exception ex) { MessageService.ShowWarning(strUrl, ex); } 385 } 386 Restart()387 public static void Restart() 388 { 389 try { NativeLib.StartProcess(WinUtil.GetExecutable()); } 390 catch(Exception ex) { MessageService.ShowWarning(ex); } 391 } 392 GetExecutable()393 public static string GetExecutable() 394 { 395 string str = m_strExePath; 396 if(str != null) return str; 397 398 try { str = Assembly.GetExecutingAssembly().Location; } 399 catch(Exception) { } 400 401 if(string.IsNullOrEmpty(str)) 402 { 403 str = Assembly.GetExecutingAssembly().GetName().CodeBase; 404 str = UrlUtil.FileUrlToPath(str); 405 } 406 407 m_strExePath = str; 408 return str; 409 } 410 411 private static string g_strAsmVersion = null; GetAssemblyVersion()412 internal static string GetAssemblyVersion() 413 { 414 if(g_strAsmVersion == null) 415 { 416 try 417 { 418 Version v = typeof(WinUtil).Assembly.GetName().Version; 419 g_strAsmVersion = v.ToString(4); 420 } 421 catch(Exception) { Debug.Assert(false); } 422 423 if(g_strAsmVersion == null) 424 g_strAsmVersion = StrUtil.VersionToString(PwDefs.FileVersion64, 4); 425 } 426 427 return g_strAsmVersion; 428 } 429 430 /// <summary> 431 /// Shorten a path. 432 /// </summary> 433 /// <param name="strPath">Path to make shorter.</param> 434 /// <param name="cchMax">Maximum number of characters in the returned string.</param> 435 /// <returns>Shortened path.</returns> CompactPath(string strPath, int cchMax)436 public static string CompactPath(string strPath, int cchMax) 437 { 438 Debug.Assert(strPath != null); 439 if(strPath == null) throw new ArgumentNullException("strPath"); 440 Debug.Assert(cchMax >= 0); 441 if(cchMax < 0) throw new ArgumentOutOfRangeException("cchMax"); 442 443 if(strPath.Length <= cchMax) return strPath; 444 if(cchMax == 0) return string.Empty; 445 446 try 447 { 448 if(!NativeLib.IsUnix()) 449 { 450 StringBuilder sb = new StringBuilder(strPath.Length + 2); 451 452 if(NativeMethods.PathCompactPathEx(sb, strPath, (uint)cchMax + 1, 0)) 453 { 454 if((sb.Length <= cchMax) && (sb.Length != 0)) 455 return sb.ToString(); 456 else { Debug.Assert(false); } 457 } 458 } 459 } 460 catch(Exception) { Debug.Assert(false); } 461 462 return StrUtil.CompactString3Dots(strPath, cchMax); 463 } 464 FlushStorageBuffers(char chDriveLetter, bool bOnlyIfRemovable)465 public static bool FlushStorageBuffers(char chDriveLetter, bool bOnlyIfRemovable) 466 { 467 string strDriveLetter = new string(chDriveLetter, 1); 468 bool bResult = true; 469 470 try 471 { 472 if(bOnlyIfRemovable) 473 { 474 DriveInfo di = new DriveInfo(strDriveLetter); 475 if(di.DriveType != DriveType.Removable) return true; 476 } 477 478 string strDevice = "\\\\.\\" + strDriveLetter + ":"; 479 480 IntPtr hDevice = NativeMethods.CreateFile(strDevice, 481 NativeMethods.EFileAccess.GenericRead | NativeMethods.EFileAccess.GenericWrite, 482 NativeMethods.EFileShare.Read | NativeMethods.EFileShare.Write, 483 IntPtr.Zero, NativeMethods.ECreationDisposition.OpenExisting, 484 0, IntPtr.Zero); 485 if(NativeMethods.IsInvalidHandleValue(hDevice)) 486 { 487 Debug.Assert(false); 488 return false; 489 } 490 491 string strDir = FreeDriveIfCurrent(chDriveLetter); 492 493 uint dwDummy; 494 if(NativeMethods.DeviceIoControl(hDevice, NativeMethods.FSCTL_LOCK_VOLUME, 495 IntPtr.Zero, 0, IntPtr.Zero, 0, out dwDummy, IntPtr.Zero) != false) 496 { 497 if(NativeMethods.DeviceIoControl(hDevice, NativeMethods.FSCTL_UNLOCK_VOLUME, 498 IntPtr.Zero, 0, IntPtr.Zero, 0, out dwDummy, IntPtr.Zero) == false) 499 { 500 Debug.Assert(false); 501 } 502 } 503 else bResult = false; 504 505 if(strDir.Length > 0) WinUtil.SetWorkingDirectory(strDir); 506 507 if(!NativeMethods.CloseHandle(hDevice)) { Debug.Assert(false); } 508 } 509 catch(Exception) 510 { 511 Debug.Assert(false); 512 return false; 513 } 514 515 return bResult; 516 } 517 FlushStorageBuffers(string strFileOnStorage, bool bOnlyIfRemovable)518 public static bool FlushStorageBuffers(string strFileOnStorage, bool bOnlyIfRemovable) 519 { 520 if(strFileOnStorage == null) { Debug.Assert(false); return false; } 521 if(strFileOnStorage.Length < 3) return false; 522 if(strFileOnStorage[1] != ':') return false; 523 if(strFileOnStorage[2] != '\\') return false; 524 525 return FlushStorageBuffers(char.ToUpper(strFileOnStorage[0]), bOnlyIfRemovable); 526 } 527 FreeDriveIfCurrent(char chDriveLetter)528 private static string FreeDriveIfCurrent(char chDriveLetter) 529 { 530 try 531 { 532 string strCur = WinUtil.GetWorkingDirectory(); 533 if((strCur == null) || (strCur.Length < 3)) return string.Empty; 534 if(strCur[1] != ':') return string.Empty; 535 if(strCur[2] != '\\') return string.Empty; 536 537 char chPar = char.ToUpper(chDriveLetter); 538 char chCur = char.ToUpper(strCur[0]); 539 if(chPar != chCur) return string.Empty; 540 541 string strTemp = UrlUtil.GetTempPath(); 542 WinUtil.SetWorkingDirectory(strTemp); 543 544 return strCur; 545 } 546 catch(Exception) { Debug.Assert(false); } 547 548 return string.Empty; 549 } 550 551 private static readonly string[] m_vIE7Windows = new string[] { 552 "Windows Internet Explorer", "Maxthon" 553 }; 554 IsInternetExplorer7Window(string strWindowTitle)555 public static bool IsInternetExplorer7Window(string strWindowTitle) 556 { 557 if(strWindowTitle == null) return false; // No assert or throw 558 if(strWindowTitle.Length == 0) return false; // No assert or throw 559 560 foreach(string str in m_vIE7Windows) 561 { 562 if(strWindowTitle.IndexOf(str) >= 0) return true; 563 } 564 565 return false; 566 } 567 HashFile(IOConnectionInfo iocFile)568 public static byte[] HashFile(IOConnectionInfo iocFile) 569 { 570 if(iocFile == null) { Debug.Assert(false); return null; } // Assert only 571 572 Stream sIn; 573 try 574 { 575 sIn = IOConnection.OpenRead(iocFile); 576 if(sIn == null) throw new FileNotFoundException(); 577 } 578 catch(Exception) { return null; } 579 580 byte[] pbHash; 581 try 582 { 583 using(SHA256Managed sha256 = new SHA256Managed()) 584 { 585 pbHash = sha256.ComputeHash(sIn); 586 } 587 } 588 catch(Exception) { Debug.Assert(false); sIn.Close(); return null; } 589 590 sIn.Close(); 591 return pbHash; 592 } 593 594 // See GetCommandLineFromUrl when editing this method IsCommandLineUrl(string strUrl)595 public static bool IsCommandLineUrl(string strUrl) 596 { 597 if(strUrl == null) { Debug.Assert(false); return false; } 598 599 string strLower = strUrl.ToLower(); 600 601 if(strLower.StartsWith("cmd://")) return true; 602 if(strLower.StartsWith("\\\\")) return true; // UNC path support 603 604 return false; 605 } 606 607 // See IsCommandLineUrl when editing this method GetCommandLineFromUrl(string strUrl)608 public static string GetCommandLineFromUrl(string strUrl) 609 { 610 if(strUrl == null) { Debug.Assert(false); return string.Empty; } 611 612 string strLower = strUrl.ToLower(); 613 614 if(strLower.StartsWith("cmd://")) return strUrl.Remove(0, 6); 615 if(strLower.StartsWith("\\\\")) return strUrl; // UNC path support 616 617 return strUrl; 618 } 619 RunElevated(string strExe, string strArgs, bool bShowMessageIfFailed)620 public static bool RunElevated(string strExe, string strArgs, 621 bool bShowMessageIfFailed) 622 { 623 if(strExe == null) throw new ArgumentNullException("strExe"); 624 625 try 626 { 627 ProcessStartInfo psi = new ProcessStartInfo(); 628 psi.FileName = strExe; 629 if(!string.IsNullOrEmpty(strArgs)) psi.Arguments = strArgs; 630 psi.UseShellExecute = true; 631 632 // Elevate on Windows Vista and higher 633 if(WinUtil.IsAtLeastWindowsVista) psi.Verb = "runas"; 634 635 NativeLib.StartProcess(psi); 636 } 637 catch(Exception ex) 638 { 639 if(bShowMessageIfFailed) MessageService.ShowWarning(ex); 640 return false; 641 } 642 643 return true; 644 } 645 GetMaxNetFrameworkVersion()646 public static ulong GetMaxNetFrameworkVersion() 647 { 648 if(m_uFrameworkVersion != 0) return m_uFrameworkVersion; 649 650 try { m_uFrameworkVersion = GetMaxNetVersionPriv(); } 651 catch(Exception) { Debug.Assert(false); } 652 653 if(m_uFrameworkVersion == 0) 654 { 655 Version v = Environment.Version; 656 if(v.Major > 0) m_uFrameworkVersion |= (uint)v.Major; 657 m_uFrameworkVersion <<= 16; 658 if(v.Minor > 0) m_uFrameworkVersion |= (uint)v.Minor; 659 m_uFrameworkVersion <<= 16; 660 if(v.Build > 0) m_uFrameworkVersion |= (uint)v.Build; 661 m_uFrameworkVersion <<= 16; 662 if(v.Revision > 0) m_uFrameworkVersion |= (uint)v.Revision; 663 } 664 665 return m_uFrameworkVersion; 666 } 667 GetMaxNetVersionPriv()668 private static ulong GetMaxNetVersionPriv() 669 { 670 RegistryKey kNdp = Registry.LocalMachine.OpenSubKey( 671 "SOFTWARE\\Microsoft\\NET Framework Setup\\NDP", false); 672 if(kNdp == null) { Debug.Assert(false); return 0; } 673 674 ulong uMaxVer = 0; 675 676 string[] vInNdp = kNdp.GetSubKeyNames(); 677 foreach(string strInNdp in vInNdp) 678 { 679 if(strInNdp == null) { Debug.Assert(false); continue; } 680 if(!strInNdp.StartsWith("v", StrUtil.CaseIgnoreCmp)) continue; 681 682 RegistryKey kVer = kNdp.OpenSubKey(strInNdp, false); 683 if(kVer != null) 684 { 685 UpdateNetVersionFromRegKey(kVer, ref uMaxVer); 686 687 string[] vProfiles = kVer.GetSubKeyNames(); 688 foreach(string strProfile in vProfiles) 689 { 690 if(string.IsNullOrEmpty(strProfile)) { Debug.Assert(false); continue; } 691 692 RegistryKey kPro = kVer.OpenSubKey(strProfile, false); 693 UpdateNetVersionFromRegKey(kPro, ref uMaxVer); 694 if(kPro != null) kPro.Close(); 695 } 696 697 kVer.Close(); 698 } 699 else { Debug.Assert(false); } 700 } 701 702 kNdp.Close(); 703 return uMaxVer; 704 } 705 UpdateNetVersionFromRegKey(RegistryKey k, ref ulong uMaxVer)706 private static void UpdateNetVersionFromRegKey(RegistryKey k, ref ulong uMaxVer) 707 { 708 if(k == null) { Debug.Assert(false); return; } 709 710 try 711 { 712 // https://msdn.microsoft.com/en-us/library/hh925568.aspx 713 string strInstall = k.GetValue("Install", string.Empty).ToString(); 714 if((strInstall.Length > 0) && (strInstall != "1")) return; 715 716 string strVer = k.GetValue("Version", string.Empty).ToString(); 717 if(strVer.Length > 0) 718 { 719 ulong uVer = StrUtil.ParseVersion(strVer); 720 if(uVer > uMaxVer) uMaxVer = uVer; 721 } 722 } 723 catch(Exception) { Debug.Assert(false); } 724 } 725 726 /* private static ulong GetMaxNetVersionPriv() 727 { 728 string strSysRoot = Environment.GetEnvironmentVariable("SystemRoot"); 729 string strFrameworks = UrlUtil.EnsureTerminatingSeparator(strSysRoot, 730 false) + "Microsoft.NET" + Path.DirectorySeparatorChar + "Framework"; 731 if(!Directory.Exists(strFrameworks)) { Debug.Assert(false); return 0; } 732 733 ulong uFrameworkVersion = 0; 734 DirectoryInfo diFrameworks = new DirectoryInfo(strFrameworks); 735 foreach(DirectoryInfo di in diFrameworks.GetDirectories("v*", 736 SearchOption.TopDirectoryOnly)) 737 { 738 string strVer = di.Name.TrimStart('v', 'V'); 739 ulong uVer = StrUtil.ParseVersion(strVer); 740 if(uVer > uFrameworkVersion) uFrameworkVersion = uVer; 741 } 742 743 return uFrameworkVersion; 744 } */ 745 GetOSStr()746 public static string GetOSStr() 747 { 748 if(NativeLib.IsUnix()) return "Unix"; 749 return "Windows"; 750 } 751 RemoveZoneIdentifier(string strFilePath)752 public static void RemoveZoneIdentifier(string strFilePath) 753 { 754 // No throw 755 if(string.IsNullOrEmpty(strFilePath)) { Debug.Assert(false); return; } 756 757 try 758 { 759 string strZoneId = strFilePath + ":Zone.Identifier"; 760 761 if(NativeMethods.FileExists(strZoneId)) 762 NativeMethods.DeleteFile(strZoneId); 763 } 764 catch(Exception) { Debug.Assert(NativeLib.IsUnix()); } 765 } 766 767 [Obsolete] RunConsoleApp(string strAppPath, string strParams)768 public static string RunConsoleApp(string strAppPath, string strParams) 769 { 770 return NativeLib.RunConsoleApp(strAppPath, strParams); 771 } 772 LocateSystemApp(string strExeName)773 public static string LocateSystemApp(string strExeName) 774 { 775 if(strExeName == null) { Debug.Assert(false); return string.Empty; } 776 if(strExeName.Length == 0) return strExeName; 777 778 if(NativeLib.IsUnix()) return strExeName; 779 780 try 781 { 782 string str = null; 783 for(int i = 0; i < 3; ++i) 784 { 785 if(i == 0) 786 str = Environment.GetFolderPath( 787 Environment.SpecialFolder.System); 788 else if(i == 1) 789 str = Environment.GetEnvironmentVariable("WinDir"); 790 else if(i == 2) 791 str = Environment.GetEnvironmentVariable("SystemRoot"); 792 793 if(!string.IsNullOrEmpty(str)) 794 { 795 str = UrlUtil.EnsureTerminatingSeparator(str, false); 796 str += strExeName; 797 798 if(File.Exists(str)) return str; 799 } 800 } 801 } 802 catch(Exception) { Debug.Assert(false); } 803 804 return strExeName; 805 } 806 GetHomeDirectory()807 public static string GetHomeDirectory() 808 { 809 string str = null; 810 try 811 { 812 str = Environment.GetFolderPath(Environment.SpecialFolder.Personal); 813 } 814 catch(Exception) { Debug.Assert(false); } 815 816 if(string.IsNullOrEmpty(str)) 817 { 818 try 819 { 820 str = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); 821 } 822 catch(Exception) { Debug.Assert(false); } 823 } 824 825 if(string.IsNullOrEmpty(str)) { Debug.Assert(false); return string.Empty; } 826 827 return str; 828 } 829 GetWorkingDirectory()830 public static string GetWorkingDirectory() 831 { 832 string strWorkDir = null; 833 try { strWorkDir = Directory.GetCurrentDirectory(); } 834 catch(Exception) { Debug.Assert(false); } 835 836 return (!string.IsNullOrEmpty(strWorkDir) ? strWorkDir : GetHomeDirectory()); 837 } 838 SetWorkingDirectory(string strWorkDir)839 public static void SetWorkingDirectory(string strWorkDir) 840 { 841 string str = strWorkDir; // May be null 842 843 if(!string.IsNullOrEmpty(str)) 844 { 845 try { if(!Directory.Exists(str)) str = null; } 846 catch(Exception) { Debug.Assert(false); str = null; } 847 } 848 849 if(string.IsNullOrEmpty(str)) 850 str = GetHomeDirectory(); // Not app dir 851 852 try { Directory.SetCurrentDirectory(str); } 853 catch(Exception) { Debug.Assert(false); } 854 } 855 ShowFileInFileManager(string strFilePath, bool bShowError)856 internal static void ShowFileInFileManager(string strFilePath, bool bShowError) 857 { 858 if(string.IsNullOrEmpty(strFilePath)) { Debug.Assert(false); return; } 859 860 try 861 { 862 string strDir = UrlUtil.GetFileDirectory(strFilePath, false, true); 863 if(NativeLib.IsUnix()) 864 { 865 NativeLib.StartProcess(strDir); 866 return; 867 } 868 869 string strExplorer = WinUtil.LocateSystemApp("Explorer.exe"); 870 871 if(File.Exists(strFilePath)) 872 NativeLib.StartProcess(strExplorer, "/select,\"" + 873 NativeLib.EncodeDataToArgs(strFilePath) + "\""); 874 else 875 NativeLib.StartProcess(strDir); 876 } 877 catch(Exception ex) 878 { 879 if(bShowError) 880 MessageService.ShowWarning(strFilePath, ex.Message); 881 } 882 } 883 } 884 } 885