Multipurpose utility for managing Games for Windows - LIVE installs and content. (Mirrored from https://github.com/InvoxiPlayGames/GfWLUtility)
at master 25 kB view raw
1using GfWLUtility.Properties; 2using System; 3using System.Diagnostics; 4using System.Drawing; 5using System.Globalization; 6using System.IO; 7using System.Linq; 8using System.Windows.Forms; 9 10namespace GfWLUtility 11{ 12 public partial class MainWindow : Form 13 { 14 public MainWindow() 15 { 16 InitializeComponent(); 17 } 18 19 private void LoadSystemInfoGroup() 20 { 21 showPCIDCheckbox.Checked = false; 22 pcidText.Text = UtilityFuncs.CensorString(GfWLRegistry.GetPCID(), 2, 2, 4); 23 versionText.Text = GfWLRegistry.GetVersion(); 24 } 25 26 public string CurrentTabName() 27 { 28 return mainTabControl.SelectedTab.Text; 29 } 30 31 private bool ConfirmIsAdmin() 32 { 33 if (!Program.Elevated) 34 { 35 // no UAC prompt on Windows XP, and while technically Run As... still exists it's not what i'm going for 36 if (!UtilityFuncs.IsWindowsXP()) 37 { 38 DialogResult r = MessageBox.Show("You must run GfWL Utility as administrator to use this functionality.\n\nDo you want to relaunch as administrator?", 39 "Permission Required", MessageBoxButtons.YesNo, MessageBoxIcon.Information); 40 if (r == DialogResult.Yes) 41 { 42 Program.RelaunchAsAdmin($"--tab {CurrentTabName()}"); 43 return false; 44 } else 45 { 46 return false; 47 } 48 } else 49 { 50 MessageBox.Show("You must run GfWL Utility as an administrator to use this functionality.", 51 "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); 52 return false; 53 } 54 } 55 else return true; 56 } 57 58 private void LoadRuntimeInfoGroup() 59 { 60 string xlive_path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "xlive.dll"); 61 if (File.Exists(xlive_path)) 62 { 63 Version xlive_version = UtilityFuncs.GetProductVersion(xlive_path); 64 runtimeInstallLabel.Text = "Runtime installed!"; 65 runtimeVersionLabel.Text = $"Version {xlive_version}"; 66 // hardcoded latest version. sucks? 67 if (xlive_version.CompareTo(new Version("3.5.95.0")) >= 0) { 68 gfwlLogoPicture.Image = Resources.GfWLCheck; 69 installRuntimeButton.Enabled = false; 70 installRuntimeButton.Text = "Up to date!"; 71 } else 72 { 73 gfwlLogoPicture.Image = Resources.GfWLOld; 74 installRuntimeButton.Enabled = true; 75 installRuntimeButton.Text = "Update runtime"; 76 } 77 } else 78 { 79 gfwlLogoPicture.Image = Resources.GfWLUnknown; 80 runtimeInstallLabel.Text = "Runtime not installed."; 81 runtimeVersionLabel.Text = ""; 82 installRuntimeButton.Enabled = true; 83 installRuntimeButton.Text = "Install runtime"; 84 } 85 } 86 87 private void LoadMarketplaceInfoGroup() 88 { 89 string dashdir = GfWLRegistry.GetDashPath(); 90 string gfwdashpath = ""; 91 if (dashdir != null) 92 gfwdashpath = Path.Combine(dashdir, "GFWLive.exe"); 93 if (gfwdashpath != null && File.Exists(gfwdashpath)) 94 { 95 Version dash_version = UtilityFuncs.GetProductVersion(gfwdashpath); 96 marketplaceInstallLabel.Text = "Marketplace installed!"; 97 marketplaceVersionLabel.Text = $"Version {dash_version}"; 98 // hardcoded latest version. sucks? 99 if (dash_version.CompareTo(new Version("3.5.67.0")) >= 0) 100 { 101 Bitmap dashIcon = UtilityFuncs.Get48x48Icon(gfwdashpath); 102 if (dashIcon != null) 103 marketplaceLogoPicture.Image = dashIcon; 104 else 105 marketplaceLogoPicture.Image = Resources.GfWLCheck; 106 installMarketplaceButton.Enabled = false; 107 installMarketplaceButton.Text = "Up to date!"; 108 } 109 else 110 { 111 marketplaceLogoPicture.Image = Resources.GfWLOld; 112 installMarketplaceButton.Enabled = true; 113 installMarketplaceButton.Text = "Update marketplace"; 114 } 115 } 116 else 117 { 118 marketplaceLogoPicture.Image = Resources.GfWLUnknown; 119 marketplaceInstallLabel.Text = "Marketplace not installed."; 120 marketplaceVersionLabel.Text = ""; 121 installMarketplaceButton.Enabled = true; 122 installMarketplaceButton.Text = "Install marketplace"; 123 } 124 } 125 126 private void LoadWLIDGroup() 127 { 128 bool is_old = false; 129 // wlidcli has the icon assets so we use that first 130 string wlid_path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "wlidcli.dll"); 131 // check the Windows Live ID assistant install path 132 if (!File.Exists(wlid_path) && GfWLRegistry.GetMsidcrlPath() != null) 133 { 134 wlid_path = Path.Combine(GfWLRegistry.GetMsidcrlPath(), "wlidcli.dll"); 135 // msidcrl40 gets installed as part of the Windows Live ID runtime but also is included in Windows 8+'s system32 folder 136 if (!File.Exists(wlid_path)) 137 wlid_path = Path.Combine(GfWLRegistry.GetMsidcrlPath(), "msidcrl40.dll"); 138 } 139 // check system32 in case it exists there 140 if (!File.Exists(wlid_path)) 141 wlid_path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "msidcrl40.dll"); 142 // hack to get older versions to show up as existing but old 143 if (!File.Exists(wlid_path)) 144 { 145 wlid_path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "msidcrl30.dll"); 146 is_old = true; 147 } 148 // final check - do we have a valid path 149 if (File.Exists(wlid_path)) 150 { 151 Version wlid_version = UtilityFuncs.GetProductVersion(wlid_path); 152 wlidInstallLabel.Text = "Assistant installed!"; 153 // are we on 8+? 154 if (UtilityFuncs.IsWindowsModern()) 155 wlidInfoLabel.Text = ""; 156 else 157 wlidInfoLabel.Text = $"Version {wlid_version}"; 158 159 Bitmap wlidIcon = UtilityFuncs.Get48x48Icon(wlid_path); 160 if (wlidIcon != null) 161 wlidLogoPicture.Image = wlidIcon; 162 else 163 wlidLogoPicture.Image = Resources.WLIDOld; 164 165 // hardcoded latest version. sucks? 166 // technically this isn't even the latest version - newer versions do in fact exist 167 if (UtilityFuncs.IsWindowsModern() || (!is_old && wlid_version.CompareTo(new Version("6.500.3165.0")) >= 0)) 168 { 169 installWLIDButton.Enabled = false; 170 installWLIDButton.Text = UtilityFuncs.IsWindowsModern() ? "Included in Windows" : "Up to date!"; 171 } 172 else 173 { 174 installWLIDButton.Enabled = true; 175 installWLIDButton.Text = "Update sign-in assistant"; 176 } 177 } 178 else 179 { 180 wlidLogoPicture.Image = Resources.WLIDUnknown; 181 wlidInstallLabel.Text = "Assistant missing."; 182 wlidInfoLabel.Text = ""; 183 installWLIDButton.Enabled = true; 184 installWLIDButton.Text = "Install sign-in assistant"; 185 } 186 } 187 188 private void LoadConnBlockGroup() 189 { 190 if (DomainBlock.IsDomainBlocked("services.gamesforwindows.com")) 191 blockServicesButton.Text = "Unblock Services"; 192 else 193 blockServicesButton.Text = "Block Services"; 194 195 if (DomainBlock.IsDomainBlocked("xeas.xboxlive.com") || 196 DomainBlock.IsDomainBlocked("xemacs.xboxlive.com") || 197 DomainBlock.IsDomainBlocked("xetgs.xboxlive.com")) 198 blockLiveButton.Text = "Unblock LIVE"; 199 else 200 blockLiveButton.Text = "Block LIVE"; 201 } 202 203 private void LoadAllGroups() 204 { 205 LoadConnBlockGroup(); 206 LoadRuntimeInfoGroup(); 207 LoadSystemInfoGroup(); 208 LoadMarketplaceInfoGroup(); 209 LoadWLIDGroup(); 210 } 211 212 private void RefreshGamePage() 213 { 214 titleNameBox.Text = string.Empty; 215 titleIDBox.Text = string.Empty; 216 titleProductKeyBox.Text = string.Empty; 217 titleIDFormattedLabel.Text = string.Empty; 218 titleShowKeyCheck.Checked = false; 219 220 if (gameListBox.SelectedIndex == -1) 221 { 222 titleShowKeyCheck.Enabled = false; 223 return; 224 } 225 226 titleShowKeyCheck.Enabled = true; 227 228 KnownTitle selected = (KnownTitle)gameListBox.SelectedItem; 229 titleNameBox.Text = selected.Name; 230 titleIDBox.Text = selected.TitleID.ToString("X8"); 231 titleIDFormattedLabel.Text = "(" + UtilityFuncs.GetFormattedTitleID(selected.TitleID) + ")"; 232 titleProductKeyBox.Text = UtilityFuncs.CensorString(TitleManager.GetTitleProductKey(selected.TitleID), 6, 6, 5); 233 titleIconPicture.ImageLocation = $"http://image.xboxlive.com/global/t.{selected.TitleID:X8}/icon/0/8000"; 234 } 235 236 private void RefreshProfilePage() 237 { 238 accountNameBox.Text = string.Empty; 239 accountNameBox.Enabled = true; 240 accountXuidBox.Text = string.Empty; 241 accountGamerpic.ImageLocation = string.Empty; 242 243 accountLiveCheck.Visible = false; 244 onlineXuidBox.Visible = false; 245 onlineXuidLabel.Visible = false; 246 msaLabel.Visible = false; 247 msaEmailBox.Visible = false; 248 showMsaCheck.Visible = false; 249 pnetCheck.Visible = false; 250 showMsaCheck.Checked = false; 251 252 if (accountsListBox.SelectedIndex == -1) 253 { 254 return; 255 } 256 257 KnownUser selected = (KnownUser)accountsListBox.SelectedItem; 258 accountNameBox.Text = selected.HasFullInformation ? selected.Gamertag : "Missing Profile Info"; 259 accountNameBox.Enabled = selected.HasFullInformation; 260 accountLiveCheck.Visible = selected.HasFullInformation; 261 accountXuidBox.Text = selected.XUID.ToString("X16"); 262 accountGamerpic.ImageLocation = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), 263 $"Microsoft\\Xlive\\Content\\{selected.XUID:X8}\\FFFE07D1\\00010000\\{selected.XUID:X8}_MountPt\\tile_64.png"); 264 265 if (selected.HasFullInformation) 266 { 267 accountLiveCheck.Checked = selected.LiveEnabled; 268 if (selected.LiveEnabled) 269 { 270 onlineXuidBox.Visible = true; 271 onlineXuidLabel.Visible = true; 272 msaLabel.Visible = true; 273 msaEmailBox.Visible = true; 274 showMsaCheck.Visible = true; 275 pnetCheck.Visible = true; 276 277 pnetCheck.Visible = selected.Pnet; 278 pnetCheck.Checked = selected.Pnet; 279 msaEmailBox.Text = UtilityFuncs.CensorEmail(selected.MsaEmail); 280 onlineXuidBox.Text = selected.OnlineXUID.ToString("X16"); 281 } 282 } 283 } 284 285 private void SearchForTitles() 286 { 287 string titlePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), 288 $"Microsoft\\Xlive\\Titles"); 289 if (Directory.Exists(titlePath)) 290 { 291 string[] titleSubdirs = Directory.GetDirectories(titlePath); 292 foreach(string subdir in titleSubdirs) 293 { 294 string titleID = Path.GetFileName(subdir); 295 uint titleIDInt = 0; 296 if (!uint.TryParse(titleID, NumberStyles.HexNumber, 297 CultureInfo.CurrentCulture, out titleIDInt)) 298 continue; 299 TitleManager.FoundTitleExists(titleIDInt); 300 } 301 } 302 303 gameListBox.Items.Clear(); 304 foreach (KnownTitle title in TitleManager.KnownTitles.Values) 305 { 306 gameListBox.Items.Add(title); 307 } 308 309 RefreshGamePage(); 310 } 311 312 private void SearchForProfiles() 313 { 314 string profilesPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), 315 $"Microsoft\\Xlive\\Content"); 316 if (Directory.Exists(profilesPath)) 317 { 318 string[] titleSubdirs = Directory.GetDirectories(profilesPath); 319 foreach (string subdir in titleSubdirs) 320 { 321 string xuid = Path.GetFileName(subdir); 322 ulong xuidInt = 0; 323 if (!ulong.TryParse(xuid, NumberStyles.HexNumber, 324 CultureInfo.CurrentCulture, out xuidInt)) 325 continue; 326 // make sure it's a valid local xuid 327 if ((xuidInt & 0xE000000000000000) != 0xE000000000000000) 328 continue; 329 UserManager.FoundUserExists(xuidInt); 330 UserManager.PopulateUserInformation(xuidInt, $"{subdir}\\FFFE07D1\\00010000\\{xuidInt:X16}_MountPt\\Account"); 331 } 332 } 333 334 accountsListBox.Items.Clear(); 335 foreach (KnownUser title in UserManager.KnownUsers.Values) 336 { 337 accountsListBox.Items.Add(title); 338 } 339 340 RefreshProfilePage(); 341 } 342 343 private void MainWindow_Load(object sender, EventArgs e) 344 { 345 // detect Windows older than 2000 and bail out 346 if (UtilityFuncs.IsWindowsLegacy()) 347 { 348 MessageBox.Show("Games for Windows - LIVE and GfWL Utility requires Windows XP or later.", 349 "OS Unsupported", MessageBoxButtons.OK, MessageBoxIcon.Error); 350 Application.Exit(); 351 return; 352 } 353 // load information 354 LoadAllGroups(); 355 SearchForProfiles(); 356 SearchForTitles(); 357 if (Program.Elevated && !UtilityFuncs.IsWindowsXP()) 358 Text += " (Administrator)"; 359 // check if we're supposed to be launching a specific tab 360 if (Program.Arguments.Contains("--tab")) 361 { 362 // gross 363 string targetTab = null; 364 // find the tab argument and get the argument value 365 for(int i = 0; i < Program.Arguments.Length; i++) 366 { 367 if (Program.Arguments[i] == "--tab" && Program.Arguments.Length >= (i + 2)) 368 { 369 targetTab = Program.Arguments[i + 1]; 370 break; 371 } 372 } 373 // if we've got a value find the tab itself 374 if (targetTab != null) 375 { 376 foreach(TabPage tab in mainTabControl.TabPages) 377 { 378 if (tab.Text == targetTab) 379 mainTabControl.SelectedTab = tab; 380 } 381 } 382 } 383 } 384 385 private void showPCIDCheckbox_CheckedChanged(object sender, EventArgs e) 386 { 387 if (showPCIDCheckbox.Checked) 388 pcidText.Text = GfWLRegistry.GetPCID(); 389 else 390 pcidText.Text = UtilityFuncs.CensorString(GfWLRegistry.GetPCID(), 2, 2, 4); 391 } 392 393 private void blockServicesButton_Click(object sender, EventArgs e) 394 { 395 if (!ConfirmIsAdmin()) 396 return; 397 398 if (DomainBlock.IsDomainBlocked("services.gamesforwindows.com")) 399 DomainBlock.UnblockDomain("services.gamesforwindows.com"); 400 else 401 DomainBlock.BlockDomain("services.gamesforwindows.com"); 402 403 LoadConnBlockGroup(); 404 } 405 406 private void blockLiveButton_Click(object sender, EventArgs e) 407 { 408 if (!ConfirmIsAdmin()) 409 return; 410 411 string[] domains = new string[] { "xeas.xboxlive.com", "xemacs.xboxlive.com", "xetgs.xboxlive.com" }; 412 if (domains.Any(DomainBlock.IsDomainBlocked)) 413 { 414 foreach (var d in domains) DomainBlock.UnblockDomain(d); 415 } 416 else 417 { 418 DialogResult r = MessageBox.Show("Blocking LIVE means all Games for Windows - LIVE games will no longer be able to sign in, and some games may be unplayable. Are you sure you want to continue?", 419 "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Warning); 420 if (r == DialogResult.Yes) 421 { 422 foreach (var d in domains) DomainBlock.BlockDomain(d); 423 } 424 } 425 426 LoadConnBlockGroup(); 427 } 428 429 private void githubLinkLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) 430 { 431 Process.Start("https://github.com/InvoxiPlayGames/GfWLUtility"); 432 } 433 434 private void gameListBox_SelectedIndexChanged(object sender, EventArgs e) 435 { 436 RefreshGamePage(); 437 } 438 439 private void titleShowKeyCheck_CheckedChanged(object sender, EventArgs e) 440 { 441 KnownTitle selected = (KnownTitle)gameListBox.SelectedItem; 442 if (selected == null) return; 443 if (titleShowKeyCheck.Checked) 444 titleProductKeyBox.Text = TitleManager.GetTitleProductKey(selected.TitleID); 445 else 446 titleProductKeyBox.Text = UtilityFuncs.CensorString(TitleManager.GetTitleProductKey(selected.TitleID), 6, 6, 5); 447 } 448 449 private void accountsListBox_SelectedIndexChanged(object sender, EventArgs e) 450 { 451 RefreshProfilePage(); 452 } 453 454 private void dataExportButton_Click(object sender, EventArgs e) 455 { 456 ExportForm form = new ExportForm(); 457 form.ShowDialog(this); 458 } 459 460 private void dataImportButton_Click(object sender, EventArgs e) 461 { 462 MessageBox.Show("Data import is not currently supported.", "GfWL Utility", MessageBoxButtons.OK, MessageBoxIcon.Error); 463 } 464 465 private void installRuntimeButton_Click(object sender, EventArgs e) 466 { 467 // check if we have the latest redistributable msi downloaded 468 string msiPath = DownloadForm.FileAlreadyExists(StaticFileInformation.xliveupdate_3_5_95_msi); 469 if (msiPath == null || !File.Exists(msiPath)) 470 { 471 // download the cabinet file 472 DownloadForm form = new DownloadForm(); 473 DownloadFormResult fr = form.StartFileDownload(StaticFileInformation.titleupdate_3_5_95_cab, this); 474 if (fr == DownloadFormResult.DownloadCancelled) 475 { 476 MessageBox.Show("The download was cancelled.", "GfWL Utility", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); 477 return; 478 } 479 else if (fr == DownloadFormResult.DownloadFailure) 480 { 481 MessageBox.Show("The download failed.", "GfWL Utility", MessageBoxButtons.OK, MessageBoxIcon.Error); 482 return; 483 } 484 string cabPath = form.GetOutputFilePath(); 485 if (!File.Exists(cabPath)) 486 { 487 MessageBox.Show("The download worked, but the CAB doesn't exist?!", "GfWL Utility", MessageBoxButtons.OK, MessageBoxIcon.Error); 488 return; 489 } 490 CabinetExtractor cex = new CabinetExtractor(cabPath, UtilityFuncs.GetLocalDirectory("Downloads")); 491 if (!cex.Extract() || DownloadForm.FileAlreadyExists(StaticFileInformation.xliveupdate_3_5_95_msi) == null) 492 { 493 MessageBox.Show("Failed to extract the System Update CAB.", "GfWL Utility", MessageBoxButtons.OK, MessageBoxIcon.Error); 494 return; 495 } 496 // delete the original cab file 497 File.Delete(cabPath); 498 } 499 500 DoMSIDownloadAndInstall(StaticFileInformation.xliveupdate_3_5_95_msi); 501 LoadRuntimeInfoGroup(); 502 } 503 504 private void DoMSIDownloadAndInstall(FileInformation fi) 505 { 506 DownloadForm form = new DownloadForm(); 507 // check if the file already exists in the downloads cache 508 string msiPath = DownloadForm.FileAlreadyExists(fi); 509 if (msiPath == null || !File.Exists(msiPath)) 510 { 511 // if it doesn't, download it 512 DownloadFormResult fr = form.StartFileDownload(fi, this); 513 if (fr == DownloadFormResult.DownloadCancelled) 514 { 515 MessageBox.Show("The download was cancelled.", "GfWL Utility", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); 516 return; 517 } 518 else if (fr == DownloadFormResult.DownloadFailure) 519 { 520 MessageBox.Show("The download failed.", "GfWL Utility", MessageBoxButtons.OK, MessageBoxIcon.Error); 521 return; 522 } 523 msiPath = form.GetOutputFilePath(); 524 if (!File.Exists(msiPath)) 525 { 526 MessageBox.Show("The download worked, but the MSI doesn't exist?! Make sure any anti-virus software is not interfering.", "GfWL Utility", MessageBoxButtons.OK, MessageBoxIcon.Error); 527 return; 528 } 529 } 530 531 Process p = new Process(); 532 p.StartInfo.FileName = "msiexec"; 533 p.StartInfo.Arguments = $"/qf /i \"{msiPath}\""; 534 p.StartInfo.UseShellExecute = true; 535 p.Start(); 536 p.WaitForExit(); 537 } 538 539 private void installMarketplaceButton_Click(object sender, EventArgs e) 540 { 541 DoMSIDownloadAndInstall(StaticFileInformation.gfwlclient_msi); 542 LoadMarketplaceInfoGroup(); 543 } 544 545 private void installWLIDButton_Click(object sender, EventArgs e) 546 { 547 if (UtilityFuncs.IsWindows64Bit()) 548 DoMSIDownloadAndInstall(StaticFileInformation.wllogin_64_msi); 549 DoMSIDownloadAndInstall(StaticFileInformation.wllogin_32_msi); 550 LoadWLIDGroup(); 551 } 552 553 private void showMsaCheck_CheckedChanged(object sender, EventArgs e) 554 { 555 KnownUser selected = (KnownUser)accountsListBox.SelectedItem; 556 if (selected == null) return; 557 if (showMsaCheck.Checked) 558 msaEmailBox.Text = selected.MsaEmail; 559 else 560 msaEmailBox.Text = UtilityFuncs.CensorEmail(selected.MsaEmail); 561 } 562 563 private void viewCacheLink_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) 564 { 565 if (Directory.Exists(UtilityFuncs.GetLocalDirectory(""))) 566 Process.Start(UtilityFuncs.GetLocalDirectory("")); 567 else 568 MessageBox.Show("The cache folder does not exist.", "GfWL Utility", MessageBoxButtons.OK, MessageBoxIcon.Information); 569 } 570 571 private void clearCacheButton_Click(object sender, EventArgs e) 572 { 573 if (Directory.Exists(UtilityFuncs.GetLocalDirectory(""))) { 574 try 575 { 576 Directory.Delete(UtilityFuncs.GetLocalDirectory(""), true); 577 MessageBox.Show("The cache folder has been cleared!", "GfWL Utility", MessageBoxButtons.OK, MessageBoxIcon.Information); 578 } catch (Exception ex) 579 { 580 MessageBox.Show($"The cache folder could not be deleted.\n\nError: {ex.Message}", "GfWL Utility", MessageBoxButtons.OK, MessageBoxIcon.Error); 581 } 582 } 583 else 584 MessageBox.Show("The cache folder does not exist.", "GfWL Utility", MessageBoxButtons.OK, MessageBoxIcon.Information); 585 } 586 587 private void refreshProfileInfoButton_Click(object sender, EventArgs e) 588 { 589 ProfileInfoExtractor p = new ProfileInfoExtractor(); 590 p.ShowDialog(this); 591 if (p.Success) 592 SearchForProfiles(); 593 } 594 } 595}