Add a separate sanity check for SMX.dll existing, since Windows gives the same error if a DLL is missing or one of its dependencies is missing.

master
Glenn Maynard 7 years ago
parent 8ea8070d51
commit 3d6eb112e6
  1. 11
      smx-config/App.xaml.cs
  2. 10
      smx-config/Helpers.cs
  3. 29
      smx-config/SMX.cs

@ -14,10 +14,17 @@ namespace smx_config
App() App()
{ {
AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionEventHandler; AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionEventHandler;
if(!SMX.SMX.DLLExists())
{
MessageBox.Show("SMXConfig encountered an unexpected error.\n\nSMX.dll couldn't be found:\n\n" + Helpers.GetLastWin32ErrorString(), "SMXConfig");
Current.Shutdown();
return;
}
if(!SMX.SMX.DLLAvailable()) if(!SMX.SMX.DLLAvailable())
{ {
MessageBox.Show("SMXConfig encountered an unexpected error:\n\nSMX.dll failed to load.", "SMXConfig"); MessageBox.Show("SMXConfig encountered an unexpected error.\n\nSMX.dll failed to load:\n\n" + Helpers.GetLastWin32ErrorString(), "SMXConfig");
Current.Shutdown(); Current.Shutdown();
return; return;
} }

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Threading; using System.Windows.Threading;
using SMXJSON; using SMXJSON;
@ -79,6 +80,15 @@ namespace smx_config
return false; return false;
} }
// Return the last Win32 error as a string.
public static string GetLastWin32ErrorString()
{
int error = Marshal.GetLastWin32Error();
if(error == 0)
return "";
return new System.ComponentModel.Win32Exception(error).Message;
}
// Work around Enumerable.SequenceEqual not checking if the arrays are null. // Work around Enumerable.SequenceEqual not checking if the arrays are null.
public static bool SequenceEqual<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second) public static bool SequenceEqual<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second)
{ {

@ -198,8 +198,27 @@ namespace SMX
public static class SMX public static class SMX
{ {
[System.Flags]
enum LoadLibraryFlags : uint
{
None = 0,
DONT_RESOLVE_DLL_REFERENCES = 0x00000001,
LOAD_IGNORE_CODE_AUTHZ_LEVEL = 0x00000010,
LOAD_LIBRARY_AS_DATAFILE = 0x00000002,
LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE = 0x00000040,
LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x00000020,
LOAD_LIBRARY_SEARCH_APPLICATION_DIR = 0x00000200,
LOAD_LIBRARY_SEARCH_DEFAULT_DIRS = 0x00001000,
LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR = 0x00000100,
LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800,
LOAD_LIBRARY_SEARCH_USER_DIRS = 0x00000400,
LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008
}
[DllImport("kernel32", SetLastError=true)] [DllImport("kernel32", SetLastError=true)]
static extern IntPtr LoadLibrary(string lpFileName); static extern IntPtr LoadLibrary(string lpFileName);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hReservedNull, LoadLibraryFlags dwFlags);
[DllImport("SMX.dll", CallingConvention = CallingConvention.Cdecl)] [DllImport("SMX.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern void SMX_Start( private static extern void SMX_Start(
[MarshalAs(UnmanagedType.FunctionPtr)] InternalUpdateCallback callback, [MarshalAs(UnmanagedType.FunctionPtr)] InternalUpdateCallback callback,
@ -229,11 +248,21 @@ namespace SMX
private static extern bool SMX_ReenableAutoLights(); private static extern bool SMX_ReenableAutoLights();
// Check if the native DLL is available. This is mostly to avoid exceptions in the designer. // Check if the native DLL is available. This is mostly to avoid exceptions in the designer.
// This returns false if the DLL doesn't load.
public static bool DLLAvailable() public static bool DLLAvailable()
{ {
return LoadLibrary("SMX.dll") != IntPtr.Zero; return LoadLibrary("SMX.dll") != IntPtr.Zero;
} }
// Check if the native DLL exists. This will return false if SMX.dll is missing entirely,
// but not if it fails to load for another reason like runtime dependencies. This just lets
// us print a more specific error message.
public static bool DLLExists()
{
return LoadLibraryEx("SMX.dll", (IntPtr)0, LoadLibraryFlags.LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE) != IntPtr.Zero;
}
public delegate void UpdateCallback(int PadNumber, SMXUpdateCallbackReason reason); public delegate void UpdateCallback(int PadNumber, SMXUpdateCallbackReason reason);
// The C API allows a user pointer, but we don't use that here. // The C API allows a user pointer, but we don't use that here.

Loading…
Cancel
Save