/* Copyright (c) 2019 Rick (rick 'at' gibbed 'dot' us) * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would * be appreciated but is not required. * * 2. Altered source versions must be plainly marked as such, and must not * be misrepresented as being the original software. * * 3. This notice may not be removed or altered from any source * distribution. */ using System; using System.IO; using System.Runtime.InteropServices; using Microsoft.Win32; namespace SAM.API { public static class Steam { private struct Native { [DllImport("kernel32.dll", SetLastError = true, BestFitMapping = false, ThrowOnUnmappableChar = true)] internal static extern IntPtr GetProcAddress(IntPtr module, string name); [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] internal static extern IntPtr LoadLibraryEx(string path, IntPtr file, uint flags); [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool SetDllDirectory(string path); internal const uint LoadWithAlteredSearchPath = 8; } private static Delegate GetExportDelegate(IntPtr module, string name) { IntPtr address = Native.GetProcAddress(module, name); return address == IntPtr.Zero ? null : Marshal.GetDelegateForFunctionPointer(address, typeof(TDelegate)); } private static TDelegate GetExportFunction(IntPtr module, string name) where TDelegate : class { return (TDelegate)((object)GetExportDelegate(module, name)); } private static IntPtr _Handle = IntPtr.Zero; public static string GetInstallPath() { return (string)Registry.GetValue(@"HKEY_LOCAL_MACHINE\Software\Valve\Steam", "InstallPath", null); } [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)] private delegate IntPtr NativeCreateInterface(string version, IntPtr returnCode); private static NativeCreateInterface _CallCreateInterface; public static TClass CreateInterface(string version) where TClass : INativeWrapper, new() { IntPtr address = _CallCreateInterface(version, IntPtr.Zero); if (address == IntPtr.Zero) { return default(TClass); } var rez = new TClass(); rez.SetupFunctions(address); return rez; } [UnmanagedFunctionPointer(CallingConvention.Cdecl)] [return: MarshalAs(UnmanagedType.I1)] private delegate bool NativeSteamGetCallback(int pipe, out Types.CallbackMessage message, out int call); private static NativeSteamGetCallback _CallSteamBGetCallback; public static bool GetCallback(int pipe, out Types.CallbackMessage message, out int call) { return _CallSteamBGetCallback(pipe, out message, out call); } [UnmanagedFunctionPointer(CallingConvention.Cdecl)] [return: MarshalAs(UnmanagedType.I1)] private delegate bool NativeSteamFreeLastCallback(int pipe); private static NativeSteamFreeLastCallback _CallSteamFreeLastCallback; public static bool FreeLastCallback(int pipe) { return _CallSteamFreeLastCallback(pipe); } public static bool Load() { if (_Handle != IntPtr.Zero) { return true; } string path = GetInstallPath(); if (path == null) { return false; } Native.SetDllDirectory(path + ";" + Path.Combine(path, "bin")); path = Path.Combine(path, "steamclient.dll"); IntPtr module = Native.LoadLibraryEx(path, IntPtr.Zero, Native.LoadWithAlteredSearchPath); if (module == IntPtr.Zero) { return false; } _CallCreateInterface = GetExportFunction(module, "CreateInterface"); if (_CallCreateInterface == null) { return false; } _CallSteamBGetCallback = GetExportFunction(module, "Steam_BGetCallback"); if (_CallSteamBGetCallback == null) { return false; } _CallSteamFreeLastCallback = GetExportFunction(module, "Steam_FreeLastCallback"); if (_CallSteamFreeLastCallback == null) { return false; } _Handle = module; return true; } } }