Multipurpose utility for managing Games for Windows - LIVE installs and content. (Mirrored from https://github.com/InvoxiPlayGames/GfWLUtility)
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}