InteropHelp.cs (7747B)
1 // This file is provided under The MIT License as part of Steamworks.NET. 2 // Copyright (c) 2013-2019 Riley Labrecque 3 // Please see the included LICENSE.txt for additional information. 4 5 // This file is automatically generated. 6 // Changes to this file will be reverted when you update Steamworks.NET 7 8 #if UNITY_ANDROID || UNITY_IOS || UNITY_TIZEN || UNITY_TVOS || UNITY_WEBGL || UNITY_WSA || UNITY_PS4 || UNITY_WII || UNITY_XBOXONE || UNITY_SWITCH 9 #define DISABLESTEAMWORKS 10 #endif 11 12 #if !DISABLESTEAMWORKS 13 14 using System.Runtime.InteropServices; 15 using IntPtr = System.IntPtr; 16 17 using System.Text; 18 19 namespace Steamworks { 20 public class InteropHelp { 21 public static void TestIfPlatformSupported() { 22 #if !UNITY_EDITOR && !UNITY_STANDALONE && !STEAMWORKS_WIN && !STEAMWORKS_LIN_OSX 23 throw new System.InvalidOperationException("Steamworks functions can only be called on platforms that Steam is available on."); 24 #endif 25 } 26 27 public static void TestIfAvailableClient() { 28 TestIfPlatformSupported(); 29 if (CSteamAPIContext.GetSteamClient() == System.IntPtr.Zero) { 30 if (!CSteamAPIContext.Init()) { 31 throw new System.InvalidOperationException("Steamworks is not initialized."); 32 } 33 } 34 } 35 36 public static void TestIfAvailableGameServer() { 37 TestIfPlatformSupported(); 38 if (CSteamGameServerAPIContext.GetSteamClient() == System.IntPtr.Zero) { 39 if (!CSteamGameServerAPIContext.Init()) { 40 throw new System.InvalidOperationException("Steamworks GameServer is not initialized."); 41 } 42 } 43 } 44 45 // This continues to exist for both 'out string' and strings returned by Steamworks functions. 46 public static string PtrToStringUTF8(IntPtr nativeUtf8) { 47 if (nativeUtf8 == IntPtr.Zero) { 48 return null; 49 } 50 51 int len = 0; 52 53 while (Marshal.ReadByte(nativeUtf8, len) != 0) { 54 ++len; 55 } 56 57 if (len == 0) { 58 return string.Empty; 59 } 60 61 byte[] buffer = new byte[len]; 62 Marshal.Copy(nativeUtf8, buffer, 0, buffer.Length); 63 return Encoding.UTF8.GetString(buffer); 64 } 65 66 // This is for 'const char *' arguments which we need to ensure do not get GC'd while Steam is using them. 67 // We can't use an ICustomMarshaler because Unity crashes when a string between 96 and 127 characters long is defined/initialized at the top of class scope... 68 #if UNITY_EDITOR || UNITY_STANDALONE || STEAMWORKS_WIN || STEAMWORKS_LIN_OSX 69 public class UTF8StringHandle : Microsoft.Win32.SafeHandles.SafeHandleZeroOrMinusOneIsInvalid { 70 public UTF8StringHandle(string str) 71 : base(true) { 72 if (str == null) { 73 SetHandle(IntPtr.Zero); 74 return; 75 } 76 77 // +1 for '\0' 78 byte[] strbuf = new byte[Encoding.UTF8.GetByteCount(str) + 1]; 79 Encoding.UTF8.GetBytes(str, 0, str.Length, strbuf, 0); 80 IntPtr buffer = Marshal.AllocHGlobal(strbuf.Length); 81 Marshal.Copy(strbuf, 0, buffer, strbuf.Length); 82 83 SetHandle(buffer); 84 } 85 86 protected override bool ReleaseHandle() { 87 if (!IsInvalid) { 88 Marshal.FreeHGlobal(handle); 89 } 90 return true; 91 } 92 } 93 #else 94 public class UTF8StringHandle : IDisposable { 95 public UTF8StringHandle(string str) { } 96 public void Dispose() {} 97 } 98 #endif 99 100 // TODO - Should be IDisposable 101 // We can't use an ICustomMarshaler because Unity dies when MarshalManagedToNative() gets called with a generic type. 102 public class SteamParamStringArray { 103 // The pointer to each AllocHGlobal() string 104 IntPtr[] m_Strings; 105 // The pointer to the condensed version of m_Strings 106 IntPtr m_ptrStrings; 107 // The pointer to the StructureToPtr version of SteamParamStringArray_t that will get marshaled 108 IntPtr m_pSteamParamStringArray; 109 110 public SteamParamStringArray(System.Collections.Generic.IList<string> strings) { 111 if (strings == null) { 112 m_pSteamParamStringArray = IntPtr.Zero; 113 return; 114 } 115 116 m_Strings = new IntPtr[strings.Count]; 117 for (int i = 0; i < strings.Count; ++i) { 118 byte[] strbuf = new byte[Encoding.UTF8.GetByteCount(strings[i]) + 1]; 119 Encoding.UTF8.GetBytes(strings[i], 0, strings[i].Length, strbuf, 0); 120 m_Strings[i] = Marshal.AllocHGlobal(strbuf.Length); 121 Marshal.Copy(strbuf, 0, m_Strings[i], strbuf.Length); 122 } 123 124 m_ptrStrings = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr)) * m_Strings.Length); 125 SteamParamStringArray_t stringArray = new SteamParamStringArray_t() { 126 m_ppStrings = m_ptrStrings, 127 m_nNumStrings = m_Strings.Length 128 }; 129 Marshal.Copy(m_Strings, 0, stringArray.m_ppStrings, m_Strings.Length); 130 131 m_pSteamParamStringArray = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SteamParamStringArray_t))); 132 Marshal.StructureToPtr(stringArray, m_pSteamParamStringArray, false); 133 } 134 135 ~SteamParamStringArray() { 136 foreach (IntPtr ptr in m_Strings) { 137 Marshal.FreeHGlobal(ptr); 138 } 139 140 if (m_ptrStrings != IntPtr.Zero) { 141 Marshal.FreeHGlobal(m_ptrStrings); 142 } 143 144 if (m_pSteamParamStringArray != IntPtr.Zero) { 145 Marshal.FreeHGlobal(m_pSteamParamStringArray); 146 } 147 } 148 149 public static implicit operator IntPtr(SteamParamStringArray that) { 150 return that.m_pSteamParamStringArray; 151 } 152 } 153 } 154 155 // TODO - Should be IDisposable 156 // MatchMaking Key-Value Pair Marshaller 157 public class MMKVPMarshaller { 158 private IntPtr m_pNativeArray; 159 private IntPtr m_pArrayEntries; 160 161 public MMKVPMarshaller(MatchMakingKeyValuePair_t[] filters) { 162 if (filters == null) { 163 return; 164 } 165 166 int sizeOfMMKVP = Marshal.SizeOf(typeof(MatchMakingKeyValuePair_t)); 167 168 m_pNativeArray = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr)) * filters.Length); 169 m_pArrayEntries = Marshal.AllocHGlobal(sizeOfMMKVP * filters.Length); 170 for (int i = 0; i < filters.Length; ++i) { 171 Marshal.StructureToPtr(filters[i], new IntPtr(m_pArrayEntries.ToInt64() + (i * sizeOfMMKVP)), false); 172 } 173 174 Marshal.WriteIntPtr(m_pNativeArray, m_pArrayEntries); 175 } 176 177 ~MMKVPMarshaller() { 178 if (m_pArrayEntries != IntPtr.Zero) { 179 Marshal.FreeHGlobal(m_pArrayEntries); 180 } 181 if (m_pNativeArray != IntPtr.Zero) { 182 Marshal.FreeHGlobal(m_pNativeArray); 183 } 184 } 185 186 public static implicit operator IntPtr(MMKVPMarshaller that) { 187 return that.m_pNativeArray; 188 } 189 } 190 191 public class DllCheck { 192 #if DISABLED 193 [DllImport("kernel32.dll")] 194 public static extern IntPtr GetModuleHandle(string lpModuleName); 195 196 [DllImport("kernel32.dll", CharSet = CharSet.Auto)] 197 extern static int GetModuleFileName(IntPtr hModule, StringBuilder strFullPath, int nSize); 198 #endif 199 200 /// <summary> 201 /// This is an optional runtime check to ensure that the dlls are the correct version. Returns false only if the steam_api.dll is found and it's the wrong size or version number. 202 /// </summary> 203 public static bool Test() { 204 #if DISABLED 205 bool ret = CheckSteamAPIDLL(); 206 #endif 207 return true; 208 } 209 210 #if DISABLED 211 private static bool CheckSteamAPIDLL() { 212 string fileName; 213 int fileBytes; 214 if (IntPtr.Size == 4) { 215 fileName = "steam_api.dll"; 216 fileBytes = Version.SteamAPIDLLSize; 217 } 218 else { 219 fileName = "steam_api64.dll"; 220 fileBytes = Version.SteamAPI64DLLSize; 221 } 222 223 IntPtr handle = GetModuleHandle(fileName); 224 if (handle == IntPtr.Zero) { 225 return true; 226 } 227 228 StringBuilder filePath = new StringBuilder(256); 229 GetModuleFileName(handle, filePath, filePath.Capacity); 230 string file = filePath.ToString(); 231 232 // If we can not find the file we'll just skip it and let the DllNotFoundException take care of it. 233 if (System.IO.File.Exists(file)) { 234 System.IO.FileInfo fInfo = new System.IO.FileInfo(file); 235 if (fInfo.Length != fileBytes) { 236 return false; 237 } 238 239 if (System.Diagnostics.FileVersionInfo.GetVersionInfo(file).FileVersion != Version.SteamAPIDLLVersion) { 240 return false; 241 } 242 } 243 return true; 244 } 245 #endif 246 } 247 } 248 249 #endif // !DISABLESTEAMWORKS