Fix usage of BizHawk within a folder with a semicolon in it
Semicolons are perfectly valid for path names, but windows disallows dll paths to contain such (presumingly internally using them as path separators like with PATH env var) A workaround for this is to simply use the "short name path" instead, which does not have a semicolon (but these names aren't guaranteed to exist, and in certain cases if they don't,GetShortPathNameW will just return the long name back, so semicolon still needs to be rechecked)
This commit is contained in:
parent
f382ec7590
commit
1f276242ec
|
@ -5,6 +5,7 @@ using System.IO;
|
|||
using System.Windows.Forms;
|
||||
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Common.StringExtensions;
|
||||
using BizHawk.Emulation.DiscSystem;
|
||||
|
||||
namespace BizHawk.Client.DiscoHawk
|
||||
|
@ -23,6 +24,7 @@ namespace BizHawk.Client.DiscoHawk
|
|||
|
||||
static Program()
|
||||
{
|
||||
// http://www.codeproject.com/Articles/310675/AppDomain-AssemblyResolve-Event-Tips
|
||||
// in case assembly resolution fails, such as if we moved them into the dll subdirectory, this event handler can reroute to them
|
||||
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
|
||||
|
||||
|
@ -33,18 +35,14 @@ namespace BizHawk.Client.DiscoHawk
|
|||
return;
|
||||
}
|
||||
|
||||
// http://www.codeproject.com/Articles/310675/AppDomain-AssemblyResolve-Event-Tips
|
||||
// this will look in subdirectory "dll" to load pinvoked stuff
|
||||
var dllDir = Path.Combine(AppContext.BaseDirectory, "dll");
|
||||
SetDllDirectoryW(dllDir);
|
||||
|
||||
try
|
||||
{
|
||||
// but before we even try doing that, whack the MOTW from everything in that directory (that's a dll)
|
||||
// before we load anything from the dll dir, whack the MOTW from everything in that directory (that's a dll)
|
||||
// otherwise, some people will have crashes at boot-up due to .net security disliking MOTW.
|
||||
// some people are getting MOTW through a combination of browser used to download bizhawk, and program used to dearchive it
|
||||
static void RemoveMOTW(string path) => DeleteFileW($"{path}:Zone.Identifier");
|
||||
var todo = new Queue<DirectoryInfo>(new[] { new DirectoryInfo(dllDir) });
|
||||
var dllDir = Path.Combine(AppContext.BaseDirectory, "dll");
|
||||
var todo = new Queue<DirectoryInfo>([ new DirectoryInfo(dllDir) ]);
|
||||
while (todo.Count != 0)
|
||||
{
|
||||
var di = todo.Dequeue();
|
||||
|
@ -72,6 +70,48 @@ namespace BizHawk.Client.DiscoHawk
|
|||
WmImports.ChangeWindowMessageFilter(WM_DROPFILES, WmImports.ChangeWindowMessageFilterFlags.Add);
|
||||
WmImports.ChangeWindowMessageFilter(WM_COPYDATA, WmImports.ChangeWindowMessageFilterFlags.Add);
|
||||
WmImports.ChangeWindowMessageFilter(WM_COPYGLOBALDATA, WmImports.ChangeWindowMessageFilterFlags.Add);
|
||||
|
||||
// this will look in subdirectory "dll" to load pinvoked stuff
|
||||
var dllDir = Path.Combine(AppContext.BaseDirectory, "dll");
|
||||
|
||||
// windows prohibits a semicolon for SetDllDirectoryW, although such paths are fully valid otherwise
|
||||
// presumingly windows internally has ; used as a path separator, like with PATH
|
||||
// or perhaps this is just some legacy junk windows keeps around for backwards compatibility reasons
|
||||
// we can possibly workaround this by using the "short path name" rather (but this isn't guaranteed to exist)
|
||||
const string SEMICOLON_IN_DIR_MSG =
|
||||
"DiscoHawk requires no semicolons within its base directory! DiscoHawk will now close.";
|
||||
|
||||
if (dllDir.ContainsOrdinal(';'))
|
||||
{
|
||||
var dllShortPathLen = Win32Imports.GetShortPathNameW(dllDir, null, 0);
|
||||
if (dllShortPathLen == 0)
|
||||
{
|
||||
MessageBox.Show(SEMICOLON_IN_DIR_MSG);
|
||||
return;
|
||||
}
|
||||
|
||||
var dllShortPathBuffer = new char[dllShortPathLen];
|
||||
dllShortPathLen = Win32Imports.GetShortPathNameW(dllDir, dllShortPathBuffer, dllShortPathLen);
|
||||
if (dllShortPathLen == 0)
|
||||
{
|
||||
MessageBox.Show(SEMICOLON_IN_DIR_MSG);
|
||||
return;
|
||||
}
|
||||
|
||||
dllDir = new string(dllShortPathBuffer, 0, dllShortPathLen);
|
||||
if (dllDir.ContainsOrdinal(';'))
|
||||
{
|
||||
MessageBox.Show(SEMICOLON_IN_DIR_MSG);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Win32Imports.SetDllDirectoryW(dllDir))
|
||||
{
|
||||
MessageBox.Show(
|
||||
$"SetDllDirectoryW failed with error code {Marshal.GetLastWin32Error()}, this is fatal. DiscoHawk will now close.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Do something for visuals, I guess
|
||||
|
|
|
@ -20,10 +20,6 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
// Declared here instead of a more usual place to avoid dependencies on the more usual place
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static extern bool SetDllDirectoryW(string lpPathName);
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static extern bool DeleteFileW(string lpFileName);
|
||||
|
@ -59,18 +55,15 @@ namespace BizHawk.Client.EmuHawk
|
|||
return;
|
||||
}
|
||||
|
||||
// this will look in subdirectory "dll" to load pinvoked stuff
|
||||
var dllDir = Path.Combine(AppContext.BaseDirectory, "dll");
|
||||
_ = SetDllDirectoryW(dllDir);
|
||||
|
||||
try
|
||||
{
|
||||
// but before we even try doing that, whack the MOTW from everything in that directory (that's a dll)
|
||||
// before we load anything from the dll dir, whack the MOTW from everything in that directory (that's a dll)
|
||||
// otherwise, some people will have crashes at boot-up due to .net security disliking MOTW.
|
||||
// some people are getting MOTW through a combination of browser used to download bizhawk, and program used to dearchive it
|
||||
// We need to do it here too... otherwise people get exceptions when externaltools we distribute try to startup
|
||||
static void RemoveMOTW(string path) => DeleteFileW($"{path}:Zone.Identifier");
|
||||
var todo = new Queue<DirectoryInfo>(new[] { new DirectoryInfo(dllDir) });
|
||||
var dllDir = Path.Combine(AppContext.BaseDirectory, "dll");
|
||||
var todo = new Queue<DirectoryInfo>([ new DirectoryInfo(dllDir) ]);
|
||||
while (todo.Count != 0)
|
||||
{
|
||||
var di = todo.Dequeue();
|
||||
|
@ -123,8 +116,52 @@ namespace BizHawk.Client.EmuHawk
|
|||
return -1;
|
||||
}
|
||||
|
||||
string dllDir = null;
|
||||
if (!OSTailoredCode.IsUnixHost)
|
||||
{
|
||||
// this will look in subdirectory "dll" to load pinvoked stuff
|
||||
// declared above to be re-used later on, see second SetDllDirectoryW call
|
||||
dllDir = Path.Combine(AppContext.BaseDirectory, "dll");
|
||||
|
||||
// windows prohibits a semicolon for SetDllDirectoryW, although such paths are fully valid otherwise
|
||||
// presumingly windows internally has ; used as a path separator, like with PATH
|
||||
// or perhaps this is just some legacy junk windows keeps around for backwards compatibility reasons
|
||||
// we can possibly workaround this by using the "short path name" rather (but this isn't guaranteed to exist)
|
||||
const string SEMICOLON_IN_DIR_MSG =
|
||||
"EmuHawk requires no semicolons within its base directory! EmuHawk will now close.";
|
||||
|
||||
if (dllDir.ContainsOrdinal(';'))
|
||||
{
|
||||
var dllShortPathLen = Win32Imports.GetShortPathNameW(dllDir, null, 0);
|
||||
if (dllShortPathLen == 0)
|
||||
{
|
||||
MessageBox.Show(SEMICOLON_IN_DIR_MSG);
|
||||
return -1;
|
||||
}
|
||||
|
||||
var dllShortPathBuffer = new char[dllShortPathLen];
|
||||
dllShortPathLen = Win32Imports.GetShortPathNameW(dllDir, dllShortPathBuffer, dllShortPathLen);
|
||||
if (dllShortPathLen == 0)
|
||||
{
|
||||
MessageBox.Show(SEMICOLON_IN_DIR_MSG);
|
||||
return -1;
|
||||
}
|
||||
|
||||
dllDir = new string(dllShortPathBuffer, 0, dllShortPathLen);
|
||||
if (dllDir.ContainsOrdinal(';'))
|
||||
{
|
||||
MessageBox.Show(SEMICOLON_IN_DIR_MSG);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Win32Imports.SetDllDirectoryW(dllDir))
|
||||
{
|
||||
MessageBox.Show(
|
||||
$"SetDllDirectoryW failed with error code {Marshal.GetLastWin32Error()}, this is fatal. EmuHawk will now close.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Check if we have the C++ VS2015-2022 redist all in one redist be installed
|
||||
var p = OSTailoredCode.LinkedLibManager.LoadOrZero("vcruntime140_1.dll");
|
||||
if (p != IntPtr.Zero)
|
||||
|
@ -287,8 +324,12 @@ namespace BizHawk.Client.EmuHawk
|
|||
// It isn't clear whether we need the earlier SetDllDirectory(), but I think we do.
|
||||
// note: this is pasted instead of being put in a static method due to this initialization code being sensitive to things like that, and not wanting to cause it to break
|
||||
// pasting should be safe (not affecting the jit order of things)
|
||||
var dllDir = Path.Combine(AppContext.BaseDirectory, "dll");
|
||||
_ = SetDllDirectoryW(dllDir);
|
||||
if (!Win32Imports.SetDllDirectoryW(dllDir))
|
||||
{
|
||||
MessageBox.Show(
|
||||
$"SetDllDirectoryW failed with error code {Marshal.GetLastWin32Error()}, this is fatal. EmuHawk will now close.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!initialConfig.SkipSuperuserPrivsCheck
|
||||
|
|
|
@ -74,5 +74,12 @@ namespace BizHawk.Common
|
|||
[DllImport("kernel32.dll", ExactSpelling = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool IsWow64Process(IntPtr hProcess, [MarshalAs(UnmanagedType.Bool)] out bool Wow64Process);
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool SetDllDirectoryW(string lpPathName);
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
|
||||
public static extern int GetShortPathNameW(string lpszLongPath, char[] lpszShortPath, int cchBuffer);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue