ScpXInputBridge/XInputDll.cs (139 lines of code) (raw):
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using log4net;
using Microsoft.Win32;
using ScpControl.Shared.Win32;
using ScpControl.Shared.XInput;
namespace ScpXInputBridge
{
public partial class XInputDll
{
#region Methods
/// <summary>
/// Initializes library.
/// </summary>
static XInputDll()
{
Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
Log.InfoFormat("Library loaded by process {0} [{1}]",
Process.GetCurrentProcess().ProcessName,
Process.GetCurrentProcess().MainWindowTitle);
var myself = Assembly.GetExecutingAssembly().GetName();
var myPath = Assembly.GetExecutingAssembly().Location;
var myName = Path.GetFileName(myPath);
Log.InfoFormat("Initializing library {0} [{1}]", myName, myself.Version);
try
{
var basePath = BasePath;
Log.DebugFormat("ScpToolkit bin path: {0}", basePath);
var controlPath = ScpControlPath;
Log.DebugFormat("ScpControl bin path: {0}", controlPath);
// resolve assembly dependencies
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
var asmName = new AssemblyName(args.Name).Name;
var asmPath = Path.Combine(basePath, string.Format("{0}.dll", asmName));
Log.DebugFormat("Loading assembly {0} from {1}", asmName, asmPath);
return Assembly.LoadFrom(asmPath);
};
var scpControl = Assembly.LoadFrom(controlPath);
var scpProxyType = scpControl.GetType("ScpControl.ScpProxy");
Proxy = Activator.CreateInstance(scpProxyType);
Proxy.Start();
}
catch (Exception ex)
{
Log.FatalFormat("Error during library initialization: {0}", ex);
return;
}
// if no custom path specified by user, use DLL in system32 dir
var xinputPath = !string.IsNullOrEmpty(XInputDllPath) && File.Exists(XInputDllPath)
? XInputDllPath
: Path.Combine(Environment.SystemDirectory, myName);
Log.DebugFormat("Original XInput DLL path: {0}", xinputPath);
NativeDllHandle = Kernel32Natives.LoadLibrary(xinputPath);
if (NativeDllHandle == IntPtr.Zero)
{
Log.FatalFormat("Couldn't load native DLL: {0}", new Win32Exception(Marshal.GetLastWin32Error()));
return;
}
Log.Info("Library initialized");
}
#endregion
#region Private delegates
private static readonly Lazy<XInputEnableFunction> OriginalXInputEnableFunction =
new Lazy<XInputEnableFunction>(
() => Kernel32Natives.GetMethod<XInputEnableFunction>(NativeDllHandle, "XInputEnable"));
private static readonly Lazy<XInputGetStateFunction> OriginalXInputGetStateFunction = new Lazy
<XInputGetStateFunction>(
() => Kernel32Natives.GetMethod<XInputGetStateFunction>(NativeDllHandle, "XInputGetState"));
private static readonly Lazy<XInputSetStateFunction> OriginalXInputSetStateFunction = new Lazy
<XInputSetStateFunction>(
() => Kernel32Natives.GetMethod<XInputSetStateFunction>(NativeDllHandle, "XInputSetState"));
private static readonly Lazy<XInputGetCapabilitiesFunction> OriginalXInputGetCapabilitiesFunction = new Lazy
<XInputGetCapabilitiesFunction>(
() => Kernel32Natives.GetMethod<XInputGetCapabilitiesFunction>(NativeDllHandle, "XInputGetCapabilities"));
private static readonly Lazy<XInputGetDSoundAudioDeviceGuidsFunction>
OriginalXInputGetDSoundAudioDeviceGuidsFunction = new Lazy<XInputGetDSoundAudioDeviceGuidsFunction>(
() => Kernel32Natives.GetMethod<XInputGetDSoundAudioDeviceGuidsFunction>(NativeDllHandle,
"XInputGetDSoundAudioDeviceGuids"));
private static readonly Lazy<XInputGetBatteryInformationFunction> OriginalXInputGetBatteryInformationFunction = new Lazy
<XInputGetBatteryInformationFunction>(
() => Kernel32Natives.GetMethod<XInputGetBatteryInformationFunction>(NativeDllHandle,
"XInputGetBatteryInformation"));
private static readonly Lazy<XInputGetKeystrokeFunction> OriginalXInputGetKeystrokeFunction = new Lazy
<XInputGetKeystrokeFunction>(
() => Kernel32Natives.GetMethod<XInputGetKeystrokeFunction>(NativeDllHandle, "XInputGetKeystroke"));
#endregion
#region Private properties
private static string BasePath
{
get
{
using (var hklm = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32))
{
using (
var regKey = hklm.OpenSubKey(@"SOFTWARE\Nefarius Software Solutions\ScpToolkit", false)
)
{
return regKey != null ? (string) regKey.GetValue("Path") : string.Empty;
}
}
}
}
private static string ScpControlPath
{
get
{
using (var hklm = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32))
{
using (
var regKey =
hklm.OpenSubKey(
@"SOFTWARE\Nefarius Software Solutions\ScpToolkit\ScpControl", false))
{
return regKey != null ? (string) regKey.GetValue("Path") : string.Empty;
}
}
}
}
private static string XInputDllPath
{
get
{
using (var hklm = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32))
{
using (
var regKey =
hklm.OpenSubKey(@"SOFTWARE\Nefarius Software Solutions\ScpToolkit\XInput",
false))
{
return regKey != null ? (string) regKey.GetValue("DllPathOverride") : string.Empty;
}
}
}
}
#endregion
#region Private fields
private static readonly IntPtr NativeDllHandle = IntPtr.Zero;
private static readonly dynamic Proxy;
private const string CfgFile = "ScpXInput.ini";
private static readonly string WorkingDirectory = AppDomain.CurrentDomain.BaseDirectory;
private static readonly ILog Log;
#endregion
#region Delegates for GetProcAddress
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private delegate void XInputEnableFunction(bool enable);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private delegate uint XInputGetStateFunction(uint dwUserIndex, ref XINPUT_STATE pState);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private delegate uint XInputSetStateFunction(uint dwUserIndex, ref XINPUT_VIBRATION pVibration);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private delegate uint XInputGetCapabilitiesFunction(uint dwUserIndex, uint dwFlags,
ref XINPUT_CAPABILITIES pCapabilities);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private delegate uint XInputGetDSoundAudioDeviceGuidsFunction(uint dwUserIndex, ref Guid pDSoundRenderGuid,
ref Guid pDSoundCaptureGuid);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private delegate uint XInputGetBatteryInformationFunction(uint dwUserIndex, byte devType,
ref XINPUT_BATTERY_INFORMATION pBatteryInformation);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private delegate uint XInputGetKeystrokeFunction(
uint dwUserIndex, uint dwReserved, ref XINPUT_KEYSTROKE pKeystroke);
#endregion
}
}