The SA-MP Injector C# library is a C# solution designed to simplify automated launching and connection of San Andreas Multiplayer (SA-MP) and Open Multiplayer (OMP) clients to servers. It works as a DLL-injection tool, programmatically loading samp.dll or omp-client.dll into the Grand Theft Auto: San Andreas process (gta_sa.exe). Its primary purpose is to let other C# applications (for example, custom launchers, server-management tools, or utilities) start the game with specific parameters (nickname, IP, port, and password) in a way that’s transparent to the user, automating the connection to an SA-MP/OMP server.
$ dotnet add package SA-MPInjector
A C# library for programmatic injection of DLLs into SA-MP and OMP processes, allowing automated connection to servers.
The SA-MP Injector C# library is a C# solution designed to simplify the automated startup and connection of San Andreas Multiplayer (SA-MP) and Open Multiplayer (OMP) clients to servers. It acts as a DLL (Dynamic Link Library) injection tool, programmatically loading the samp.dll or omp-client.dll libraries into the Grand Theft Auto: San Andreas game process (gta_sa.exe).
The main purpose of this library is to allow other C# applications (such as custom launchers, server management tools, or utilities) to start the game with specific parameters (nickname, IP, port, and password) transparently to the user, automating the process of connecting to a SA-MP/OMP server.
The design of SA-MP Injector C# focuses on robustness, security, and a simplified user interface, encapsulating the complexities of low-level system operations.
The core functionality of DLL injection and creating suspended processes is intrinsically a low-level operating system operation. For this, the library makes extensive use of the P/Invoke (Platform Invoke) feature of .NET, allowing native Windows API functions (mainly from kernel32.dll) to be called directly from C# code. This is evident in the declaration of partial methods and the use of the [LibraryImport(KERNEL32, SetLastError = true)] attribute.
SafeHandle)Operations with operating system resources, such as process and thread handles, require careful management to avoid memory or resource leaks. The library employs classes derived from SafeHandle (SafeProcessHandle and SafeThreadHandle) to ensure that these resources are always released correctly, even in the event of exceptions. This adheres to the RAII (Resource Acquisition Is Initialization) principle of C++ and extends it to the .NET environment.
The library incorporates several layers of security:
SetLastError = true and Marshal.GetLastWin32Error()) to provide detailed and understandable error messages.net7.0-windows.ImplicitUsings, Nullable, AllowUnsafeBlocks, and LibraryImport.x86 (32-bit) is the mandatory target due to the architecture of gta_sa.exe and the SA-MP/OMP DLLs.<!-- samp-injector-csharp.csproj -->
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net7.0-windows</TargetFrameworks>
<PlatformTarget>x86</PlatformTarget> <!-- CRITICAL: Must be x86 -->
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <!-- Required for advanced P/Invoke -->
</PropertyGroup>
</Project>
samp.dll or omp-client.dll must be present in the game's root directory, depending on the desired injection type.The simplest way to use this library is to add the Samp_Injector_CSharp project as a reference in your own C# project.
samp-injector-csharp.csproj project.To start the game and connect to a server, simply call the static Injector.Initialize_Game method.
using Samp_Injector_CSharp;
using System;
using System.Windows.Forms; // For MessageBox, if it's not a WinForms project
namespace Launcher {
public partial class Main : Form {
public Main() {
InitializeComponent();
}
private void Connect(object sender, EventArgs e) {
string inject_type = "SAMP"; // "SAMP" or "OMP"
string game_folder = @"C:\Games\GTA San Andreas"; // Path to the GTA: SA folder
string nickname = "Name";
string ip = "127.0.0.1";
string port = "7777";
string password = ""; // Leave empty if there is no password
// Example of SA-MP injection
Injector.Initialize_Game(inject_type, game_folder, nickname, ip, port, password);
// If it is OMP, change inject_type:
// inject_type = "OMP";
// Injector.Initialize_Game(inject_type, game_folder, nickname, ip, port, password);
}
}
}
The library is structured into several files, each with a clear and well-defined responsibility, which promotes organization, maintainability, and separation of concerns. Below is a detailed description of each component.
Constants.csThis file is a centralized repository of all constants and immutable values that are used throughout the library. Its existence promotes code maintenance, readability, and consistency by ensuring that critical values are defined in a single location.
The organization of constants by category makes it easier to understand their purpose:
Game Related Constants
MIN_PORT: Defines the minimum allowed value for a server's connection port (1).MAX_PORT: Defines the maximum allowed value for a server's connection port (65535).MAX_NICKNAME_LENGTH: Specifies the maximum allowed length for the player's nickname (23 characters), a limit imposed by the SA-MP/OMP client itself.File Names
SAMP_DLL_NAME: The name of the main library file for the SA-MP client ("samp.dll").OMP_DLL_NAME: The name of the Open Multiplayer client library file ("omp-client.dll"), used in OMP type injections.GAME_EXE_NAME: The name of the Grand Theft Auto: San Andreas game executable ("gta_sa.exe").System Libraries and Functions
KERNEL32_DLL: The name of the Windows system library that contains essential functions for process and memory manipulation ("kernel32.dll").LOAD_LIBRARY_FUNC: The name of the function within kernel32.dll responsible for dynamically loading a library ("LoadLibraryA").Command Line Arguments
CMD_ARGS_PART1: The initial part of the command-line arguments for the game ("-c -n ").CMD_ARGS_PART2: Separator for the IP address (" -h ").CMD_ARGS_PART3: Separator for the port (" -p ").CMD_ARGS_PART4_PASSWORD: Prefix for the password argument (" -z "), used only if a password is provided.CMD_ARGS_BASE_LENGTH: The predefined length of the constant parts of the command line, excluding the executable and user values (14 characters).CMD_ARG_PASSWORD_LENGTH: The length of the password argument prefix (4 characters).Error Message Titles
ERROR_TITLE_SAMP: Default title for error dialog boxes related to SA-MP failures ("SA-MP Injector Error").ERROR_TITLE_OMP: Default title for error dialog boxes related to OMP failures ("OMP Injector Error").Process Creation Flags
CREATE_SUSPENDED: Flag that instructs the operating system to create a process and its main thread in a suspended state (0x00000004). This is crucial for injecting the DLL before the game starts running.PROCESS_CREATION_FLAGS: A combination of process creation flags, currently defined only as CREATE_SUSPENDED.Timeouts
DLL_INJECTION_TIMEOUT_MS: The maximum time (in milliseconds) the library will wait for the completion of the remote thread responsible for DLL injection (10000ms = 10 seconds).Memory Allocation Flags
MEM_COMMIT: Flag that reserves pages in virtual memory and "commits" them (allocates physical memory) (0x1000).MEM_RESERVE: Flag that only reserves a range of virtual address space for later use (0x2000).MEM_RELEASE: Flag that decommits and releases a region of pages (0x8000).MEMORY_ALLOCATION_TYPE: A combination of MEM_COMMIT and MEM_RESERVE, used to allocate memory for the DLL path in the remote process.MEMORY_PROTECTION: Defines the memory protection permissions (currently 0x04, which corresponds to PAGE_READWRITE in the Windows API, allowing reading and writing to the allocated memory).InjectionType.csThis file defines a simple enumerator to provide a type-safe and clear way to specify the type of injection to be performed. Using an enum instead of strings ("samp", "omp") prevents typos and makes the code more readable and robust.
// InjectionType.cs
namespace Samp_Injector_CSharp {
public enum Injection_Type {
SAMP,
OMP
}
}
Injector.csThis file is the public facade of the library, serving as the single entry point for consuming applications. It abstracts all the internal complexity of the injection process into a single static method.
Initialize_Game method receives all necessary parameters as strings, determines the injection type, and delegates the work to Injector_Core. It is also responsible for capturing the operation's result and presenting error messages to the end-user via MessageBox, making user interaction consistent.// Snippet from Injector.cs
public static class Injector {
private static readonly Injector_Core s_core = new();
public static void Initialize_Game(string inject_type_str, string folder, string nickname, string ip, string port, string password) {
// ... Logic to convert inject_type_str to Injection_Type ...
if (!s_core.Try_Initialize_Game(type, folder, nickname, ip, port, password, out string error_message)) {
string error_title = (type == Injection_Type.OMP) ? Constants.ERROR_TITLE_OMP : Constants.ERROR_TITLE_SAMP;
MessageBox.Show(error_message, error_title, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
InjectorCore.csThis is the "brain" of the library, where the sequence of injection operations is orchestrated. It connects the input validators with the process handlers to execute the complete workflow.
Try_Initialize_Game method defines the step-by-step logic: it validates the inputs, creates the game process in a suspended state, injects the necessary DLLs (samp.dll and, optionally, omp-client.dll), and, if everything is successful, resumes the game's thread. A crucial aspect is the finally block, which ensures that the game process is terminated (Kill()) in case of any failure during the injection steps, preventing "zombie" processes.// Snippet from InjectorCore.cs
internal sealed class Injector_Core {
public bool Try_Initialize_Game(...) {
// ... Input validation ...
using Process_Handler.Process_Info process_info = Process_Handler.Create_Game_Process(...);
// ...
bool success = false;
try {
// ... samp.dll injection ...
// ... Optional omp-client.dll injection ...
// ... Resume game thread ...
success = true;
return true;
}
finally {
if (!success && !process_info.ProcessHandle.IsInvalid)
process_info.ProcessHandle.Kill();
}
}
}
InputValidator.csActs as the library's first line of defense, ensuring that only valid and safe data is processed. Pre-validation prevents low-level exceptions and allows the library to provide clear and actionable error messages.
Try_Validate method performs a series of checks, including the nickname format, the numerical range of the port, and, crucially, the existence of essential files (gta_sa.exe, samp.dll, etc.) in the specified directory. If any check fails, it returns false and populates an out string with the error description.// Snippet from InputValidator.cs
internal static class Input_Validator {
public static bool Try_Validate(...) {
if (nickname.Length > Constants.MAX_NICKNAME_LENGTH)
return (error_message = $"Nickname length exceeds the maximum...") != null && false;
string game_exe_path = Path.Combine(folder_path, Constants.GAME_EXE_NAME);
if (!File.Exists(game_exe_path))
return (error_message = $"Game executable not found...") != null && false;
// ...
return true;
}
}
NativeImports.csThis file is the bridge between the managed C# code and the unmanaged native Windows APIs. It uses the P/Invoke interoperability feature to declare function signatures from kernel32.dll.
extern methods with [LibraryImport] or [DllImport] attributes that correspond to Windows API functions, such as CreateProcessA, VirtualAllocEx, and CreateRemoteThread. It also defines data structures (Startup_Info, Process_Information) with a memory layout compatible with native code. For optimization, the handles to kernel32.dll and the address of the LoadLibraryA function are loaded statically upon initialization.// Snippet from NativeImports.cs
internal static unsafe partial class Native_Imports {
private const string KERNEL32 = Constants.KERNEL32_DLL;
internal static readonly IntPtr load_library_address = NativeLibrary.GetExport(s_kernel32_handle, Constants.LOAD_LIBRARY_FUNC);
[LibraryImport(KERNEL32, SetLastError = true)]
internal static partial int ResumeThread(SafeThreadHandle hThread);
[LibraryImport(KERNEL32, SetLastError = true)]
internal static partial IntPtr CreateRemoteThread(SafeProcessHandle hProcess, ...);
}
ProcessHandler.csThis is the low-level layer that performs process manipulation operations. It uses the functions imported from NativeImports.cs to interact directly with the operating system.
Create_Game_Process: Builds the command line and starts gta_sa.exe with the CREATE_SUSPENDED flag.Inject_DLL: Implements the DLL injection technique by creating a remote thread. This is the most critical function, orchestrating memory allocation, writing, and remote execution of LoadLibraryA.Resume_Game_Thread: Performs the final step of "unfreezing" the game's main thread.// Snippet from ProcessHandler.cs
internal static bool Inject_DLL(SafeProcessHandle process_handle, string dll_path, out string error_message) {
// ... Allocation and writing to remote memory ...
IntPtr remote_thread = Native_Imports.CreateRemoteThread(process_handle, IntPtr.Zero, 0, Native_Imports.load_library_address, remote_memory, 0, IntPtr.Zero);
if (remote_thread == IntPtr.Zero)
return (error_message = $"Failed to create a remote thread...") != null && false;
// ... Wait for completion and check the result ...
return true;
}
SafeHandles.csThis file implements a recommended interoperability practice: the use of SafeHandle to manage unmanaged resources. This ensures that Windows process and thread handles are released deterministically and safely.
SafeProcessHandle and SafeThreadHandle classes inherit from SafeHandleZeroOrMinusOneIsInvalid. They encapsulate an IntPtr that represents the native handle. The main advantage is the implementation of the ReleaseHandle method, which is guaranteed by the .NET runtime to be called when the object is disposed (e.g., at the end of a using block), preventing resource leaks.// Snippet from SafeHandles.cs
internal sealed class SafeProcessHandle : SafeHandleZeroOrMinusOneIsInvalid {
// ... Constructors ...
protected override bool ReleaseHandle() {
// This call is guaranteed by .NET to release the native handle.
return Native_Imports.CloseHandle(handle);
}
}
The DLL injection process is a sequence of critical steps that need to be executed precisely to be successful. The SA-MP Injector C# library orchestrates this as follows:
Before any interaction with the system, all user-provided parameters (game folder path, nickname, IP, port, and password) are checked by Input_Validator. This includes:
gta_sa.exe, samp.dll, and omp-client.dll (if Injection_Type is OMP) exist at the expected paths.[!NOTE] This preventive step is crucial to avoid unexpected API failures and provide clear feedback to the user.
The library uses Native_Imports.CreateProcessA to start gta_sa.exe. However, a crucial detail is the use of the Constants.CREATE_SUSPENDED flag.
Process_Handler.Build_Full_Command_Args_ANSI to include all server connection parameters (-c -n <nickname> -h <ip> -p <port> -z <password>).CreateProcessA returns handles to the process and the main thread, which are encapsulated in SafeProcessHandle and SafeThreadHandle for safe resource management.[!IMPORTANT] Suspended creation is vital for injection. If the game started running before the injection, it could initialize its own security mechanisms, or
samp.dll/omp-client.dllcould be loaded before our control, making the injection more complex or ineffective.
samp.dll InjectionWith the game process suspended, the Process_Handler.Inject_DLL function performs the following steps:
LoadLibraryA: The address of the LoadLibraryA function (from kernel32.dll) in the game process is obtained. This is the function Windows uses to load DLLs.Native_Imports.VirtualAllocEx is used to allocate a block of memory within the virtual address space of the gta_sa.exe process. The block size is sufficient to store the full path of samp.dll.samp.dll is written to the newly allocated memory in the game process using Native_Imports.WriteProcessMemory.Native_Imports.CreateRemoteThread is called to create a new thread in the gta_sa.exe process. This thread is instructed to execute LoadLibraryA with the address of the DLL path string as its only argument.Constants.DLL_INJECTION_TIMEOUT_MS) for the remote thread to complete its execution, indicating that LoadLibraryA has attempted to load the DLL.LoadLibraryA was successful, it returns the base address of the loaded DLL. A zero value or failure to get the exit code indicates that the injection failed.Native_Imports.VirtualFreeEx), and the remote thread's handle is closed (Native_Imports.CloseHandle).omp-client.dll Injection (Optional, SA-MP Dependent)[!TIP] The injection of
omp-client.dllalways occurs after the successful injection ofsamp.dll. The OMP client uses the SA-MP infrastructure, sosamp.dllis a requirement.
If the specified Injection_Type is OMP, step 3 is repeated to inject omp-client.dll. The logic is identical, ensuring that both libraries necessary for OMP are loaded before the game fully starts.
Finally, after all necessary DLLs have been successfully injected, the Process_Handler.Resume_Game_Thread function is called. This function uses Native_Imports.ResumeThread to allow the main thread of gta_sa.exe to continue its execution. The game now starts with the SA-MP/OMP DLLs already loaded and the command-line arguments for server connection applied.
The library is designed to provide clear feedback in case of failure. Most errors are caught, and a descriptive error_message is returned to be presented to the user, usually via a MessageBox.
These errors occur before any system operations and are detected by Input_Validator.
"Nickname cannot be empty. Please provide a valid nickname.""Nickname length exceeds the maximum allowed of 23 characters. Please use a shorter nickname.""Invalid port format. The port must be a numeric value. Please provide a valid integer for the port.""The specified port number (70000) is outside the valid range of 1 to 65535. Please provide a valid port.""Game executable not found. Please ensure 'gta_sa.exe' exists at the specified path: C:\Program Files (x86)\Rockstar Games\GTA San Andreas\gta_sa.exe""SA-MP library not found. Please ensure 'samp.dll' exists at the specified path: C:\Program Files (x86)\Rockstar Games\GTA San Andreas\samp.dll""OMP library not found. Please ensure 'omp-client.dll' exists at the specified path for OMP injection: C:\Program Files (x86)\Rockstar Games\GTA San Andreas\omp-client.dll"gta_sa.exe), the SA-MP DLL (samp.dll), or the OMP DLL (omp-client.dll) were not found in the specified game folder.These errors occur when the library attempts to start gta_sa.exe.
"Failed to create game process. Ensure 'gta_sa.exe' is not running and you have sufficient permissions to execute the file. System Error: Access is denied."gta_sa.exe may already be running, preventing a new instance from being created, or the operating system may have a lock on the file.gta_sa.exe are running. Run the application as an administrator, if possible. Check the integrity of the gta_sa.exe file.These are the most critical errors and occur during the attempt to inject samp.dll or omp-client.dll into the game process.
kernel32.dll Handle Unavailable"Failed to obtain a handle to kernel32.dll. This is an essential system library and this error indicates a severe system issue."kernel32.dll library, fundamental for system operations in Windows, could not be loaded or its handle could not be obtained. This is extremely rare and suggests a serious problem with the operating system.LoadLibraryA Function Unavailable"Failed to find the address of the LoadLibraryA function in kernel32.dll. This is critical for injecting the DLL."LoadLibraryA function, essential for dynamically loading DLLs, could not be found in kernel32.dll. Like the previous error, this is a rare low-level problem.kernel32.dll handle."Failed to allocate memory in the target process. This might be due to insufficient permissions or process protection mechanisms."gta_sa.exe.
gta_sa.exe process or the operating system may be applying protections against code injection."Failed to write DLL path to the target process memory. Verify process permissions and ensure the DLL path is accessible.""Failed to create a remote thread in the target process to execute the DLL injection. This could be due to security restrictions or process state. System Error: Not enough memory resources are available to process this command."CreateRemoteThread API failed to create a new thread in the gta_sa.exe process to call LoadLibraryA.
"Timeout or error waiting for DLL injection to complete. System Error: The wait operation timed out."LoadLibraryA) did not finish its execution within the specified timeout (10 seconds).
LoadLibraryA may have crashed or taken too long.LoadLibraryA indefinitely."DLL injection failed or returned an error. The LoadLibrary call may have failed in the target process."LoadLibraryA indicated failure (usually 0 or NULL).
samp.dll or omp-client.dll may depend on other DLLs that are not present in the game directory or the system PATH.samp.dll/omp-client.dll. Ensure that all DLL dependencies are present.This is the last possible error in the injection cycle.
"Failed to resume the game process thread: Invalid handle."ResumeThread API failed to restart the main thread of gta_sa.exe.
Copyright © AlderGrounds
This software is licensed under the terms of the MIT License ("License"); you may use this software according to the License terms. A copy of the License can be obtained at: MIT License
This license grants, free of charge, to any person obtaining a copy of this software and associated documentation files, the following rights:
All copies or substantial portions of the software must include:
The software and all associated documentation are protected by copyright laws. The AlderGrounds retains the original copyright of the software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
For detailed information about the MIT License, visit: https://opensource.org/licenses/MIT