try catching some missing prereqs in emuhawk startup and print a report about it

This commit is contained in:
zeromus 2016-01-14 01:50:41 -06:00
parent a355f78631
commit 192458a190
5 changed files with 379 additions and 2 deletions

View File

@ -504,6 +504,12 @@
<Compile Include="CustomControls\MsgBox.designer.cs">
<DependentUpon>MsgBox.cs</DependentUpon>
</Compile>
<Compile Include="CustomControls\PrereqsAlert.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="CustomControls\PrereqsAlert.Designer.cs">
<DependentUpon>PrereqsAlert.cs</DependentUpon>
</Compile>
<Compile Include="CustomControls\QuickProgressPopup.cs">
<SubType>Form</SubType>
</Compile>
@ -1327,6 +1333,9 @@
<EmbeddedResource Include="CustomControls\MsgBox.resx">
<DependentUpon>MsgBox.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="CustomControls\PrereqsAlert.resx">
<DependentUpon>PrereqsAlert.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="CustomControls\QuickProgressPopup.resx">
<DependentUpon>QuickProgressPopup.cs</DependentUpon>
</EmbeddedResource>

View File

@ -0,0 +1,168 @@
namespace BizHawk.Client.EmuHawk.CustomControls
{
partial class PrereqsAlert
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(PrereqsAlert));
this.linkLabel1 = new System.Windows.Forms.LinkLabel();
this.label1 = new System.Windows.Forms.Label();
this.textBox1 = new System.Windows.Forms.TextBox();
this.label2 = new System.Windows.Forms.Label();
this.linkLabel2 = new System.Windows.Forms.LinkLabel();
this.label3 = new System.Windows.Forms.Label();
this.button1 = new System.Windows.Forms.Button();
this.label4 = new System.Windows.Forms.Label();
this.textBox2 = new System.Windows.Forms.TextBox();
this.SuspendLayout();
//
// linkLabel1
//
this.linkLabel1.AutoSize = true;
this.linkLabel1.Location = new System.Drawing.Point(21, 214);
this.linkLabel1.Name = "linkLabel1";
this.linkLabel1.Size = new System.Drawing.Size(291, 13);
this.linkLabel1.TabIndex = 0;
this.linkLabel1.TabStop = true;
this.linkLabel1.Text = "https://sourceforge.net/projects/bizhawk/files/Prerequisites";
this.linkLabel1.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabel1_LinkClicked);
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(12, 9);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(425, 13);
this.label1.TabIndex = 1;
this.label1.Text = "You\'re missing some of the following prerequisites, which prevents BizHawk from r" +
"unning:";
//
// textBox1
//
this.textBox1.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.textBox1.Location = new System.Drawing.Point(12, 34);
this.textBox1.Multiline = true;
this.textBox1.Name = "textBox1";
this.textBox1.ReadOnly = true;
this.textBox1.Size = new System.Drawing.Size(422, 142);
this.textBox1.TabIndex = 2;
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(0, 191);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(250, 13);
this.label2.TabIndex = 3;
this.label2.Text = "You should run the latest prerequisites installer from:";
//
// linkLabel2
//
this.linkLabel2.AutoSize = true;
this.linkLabel2.Location = new System.Drawing.Point(21, 261);
this.linkLabel2.Name = "linkLabel2";
this.linkLabel2.Size = new System.Drawing.Size(168, 13);
this.linkLabel2.TabIndex = 4;
this.linkLabel2.TabStop = true;
this.linkLabel2.Text = "http://tasvideos.org/Bizhawk.html";
this.linkLabel2.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabel2_LinkClicked);
//
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(3, 238);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(282, 13);
this.label3.TabIndex = 5;
this.label3.Text = "In case that URL is gone, you can get more information at:";
//
// button1
//
this.button1.Location = new System.Drawing.Point(374, 370);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(75, 23);
this.button1.TabIndex = 6;
this.button1.Text = "Close";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// label4
//
this.label4.AutoSize = true;
this.label4.Location = new System.Drawing.Point(3, 286);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(141, 13);
this.label4.TabIndex = 7;
this.label4.Text = "Here\'s some general advice:";
//
// textBox2
//
this.textBox2.Location = new System.Drawing.Point(12, 315);
this.textBox2.Multiline = true;
this.textBox2.Name = "textBox2";
this.textBox2.ReadOnly = true;
this.textBox2.Size = new System.Drawing.Size(332, 78);
this.textBox2.TabIndex = 8;
this.textBox2.Text = resources.GetString("textBox2.Text");
//
// PrereqsAlert
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(461, 402);
this.Controls.Add(this.textBox2);
this.Controls.Add(this.label4);
this.Controls.Add(this.button1);
this.Controls.Add(this.label3);
this.Controls.Add(this.linkLabel2);
this.Controls.Add(this.label2);
this.Controls.Add(this.textBox1);
this.Controls.Add(this.label1);
this.Controls.Add(this.linkLabel1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "PrereqsAlert";
this.Text = "Prerequisites Missing!";
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.LinkLabel linkLabel1;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.LinkLabel linkLabel2;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.Button button1;
public System.Windows.Forms.TextBox textBox1;
private System.Windows.Forms.Label label4;
private System.Windows.Forms.TextBox textBox2;
}
}

View File

@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace BizHawk.Client.EmuHawk.CustomControls
{
public partial class PrereqsAlert : Form
{
public PrereqsAlert()
{
InitializeComponent();
}
private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
linkLabel1.LinkVisited = true;
System.Diagnostics.Process.Start("https://sourceforge.net/projects/bizhawk/files/Prerequisites");
}
private void linkLabel2_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
linkLabel2.LinkVisited = true;
System.Diagnostics.Process.Start("http://tasvideos.org/Bizhawk.html");
}
private void button1_Click(object sender, EventArgs e)
{
Close();
}
}
}

View File

@ -0,0 +1,124 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="textBox2.Text" xml:space="preserve">
<value>We're not checking the version number of the VC 2010 runtime. Be sure you have the SP1 version installed.
DirectX Web Update is reportedly failing for some people as part of our prereqs installer. Try installing it manually.</value>
</data>
</root>

View File

@ -19,6 +19,37 @@ namespace BizHawk.Client.EmuHawk
{
//http://www.codeproject.com/Articles/310675/AppDomain-AssemblyResolve-Event-Tips
#if WINDOWS
//try loading libraries we know we'll need
//something in the winforms, etc. code below will cause .net to popup a missing msvcr100.dll in case that one's missing
//but oddly it lets us proceed and we'll then catch it here
var d3dx9 = Win32.LoadLibrary("d3dx9_43.dll");
var vc2015 = Win32.LoadLibrary("vcruntime140.dll");
var vc2010 = Win32.LoadLibrary("msvcr100.dll"); //TODO - check version?
var vc2010p = Win32.LoadLibrary("msvcp100.dll");
bool fail = false;
fail |= d3dx9 == IntPtr.Zero;
fail |= vc2015 == IntPtr.Zero;
fail |= vc2010 == IntPtr.Zero;
fail |= vc2010p == IntPtr.Zero;
if (fail)
{
var sw = new System.IO.StringWriter();
sw.WriteLine("[ OK ] .Net 4.0 (You couldn't even get here without it)");
sw.WriteLine("[{0}] Direct3d 9", d3dx9 == IntPtr.Zero ? "FAIL" : " OK ");
sw.WriteLine("[{0}] Visual C++ 2010 SP1 Runtime", (vc2010 == IntPtr.Zero || vc2010p == IntPtr.Zero) ? "FAIL" : " OK ");
sw.WriteLine("[{0}] Visual C++ 2015 Runtime", (vc2015 == IntPtr.Zero) ? "FAIL" : " OK ");
var str = sw.ToString();
var box = new BizHawk.Client.EmuHawk.CustomControls.PrereqsAlert();
box.textBox1.Text = str;
box.ShowDialog();
System.Diagnostics.Process.GetCurrentProcess().Kill();
}
Win32.FreeLibrary(d3dx9);
Win32.FreeLibrary(vc2015);
Win32.FreeLibrary(vc2010);
Win32.FreeLibrary(vc2010p);
// this will look in subdirectory "dll" to load pinvoked stuff
string dllDir = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "dll");
SetDllDirectory(dllDir);
@ -30,6 +61,7 @@ namespace BizHawk.Client.EmuHawk
//in case assembly resolution fails, such as if we moved them into the dll subdiretory, this event handler can reroute to them
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
#endif
}
@ -39,12 +71,20 @@ namespace BizHawk.Client.EmuHawk
return SubMain(args);
}
private static class Win32
{
[DllImport("kernel32.dll")]
public static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("kernel32.dll")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
[DllImport("kernel32.dll")]
public static extern bool FreeLibrary(IntPtr hModule);
}
//NoInlining should keep this code from getting jammed into Main() which would create dependencies on types which havent been setup by the resolver yet... or something like that
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
static int SubMain(string[] args)
{
GlobalWin.ExitCode = 0;
// this check has to be done VERY early. i stepped through a debug build with wrong .dll versions purposely used,
// and there was a TypeLoadException before the first line of SubMain was reached (some static ColorType init?)
// zero 25-dec-2012 - only do for public builds. its annoying during development