text: ﻿/*
   *  Injectors - Function Calls Using Variadic Templates
   *
   *  Copyright (C) 2014 LINK/2012 <dma_2012@hotmail.com>
   *
   *  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.
   *
   */
  #pragma once
  #include "pch.h"
  
  #if __cplusplus >= 201103L || _MSC_VER >= 1800   // MSVC 2013
  #else
  #error "This feature is not supported on this compiler"
  #endif
  
  namespace Injector
  {
  	template<class Prototype>
  	struct cstd;
  
  	template<class Ret, class ...Args>
  	struct cstd<Ret(Args...)>
  	{
  		// Call function at @p returning @Ret with args @Args
  		static Ret call(memory_pointer_tr p, Args... a)
  		{
  			auto fn = (Ret(*)(Args...)) p.get<void>();
  			return fn(std::forward<Args>(a)...);
  		}
  
  		template<uintptr_t addr>    // Uses lazy pointer
  		static Ret call(Args... a)
  		{
  			return call(lazy_pointer<addr>::get(), std::forward<Args>(a)...);
  		}
  	};
  
  	template<class Prototype>
  	struct stdcall;
  
  	template<class Ret, class ...Args>
  	struct stdcall<Ret(Args...)>
  	{
  		// Call function at @p returning @Ret with args @Args
  		static Ret call(memory_pointer_tr p, Args... a)
  		{
  			auto fn = (Ret(__stdcall*)(Args...)) p.get<void>();
  			return fn(std::forward<Args>(a)...);
  		}
  
  		template<uintptr_t addr>    // Uses lazy pointer
  		static Ret call(Args... a)
  		{
  			return call(lazy_pointer<addr>::get(), std::forward<Args>(a)...);
  		}
  	};
  
  	template<class Prototype>
  	struct fastcall;
  
  	template<class Ret, class ...Args>
  	struct fastcall<Ret(Args...)>
  	{
  		// Call function at @p returning @Ret with args @Args
  		static Ret call(memory_pointer_tr p, Args... a)
  		{
  			auto fn = (Ret(__fastcall*)(Args...)) p.get<void>();;
  			return fn(std::forward<Args>(a)...);
  		}
  
  		template<uintptr_t addr>    // Uses lazy pointer
  		static Ret call(Args... a)
  		{
  			return call(lazy_pointer<addr>::get(), std::forward<Args>(a)...);
  		}
  	};
  
  	template<class Prototype>
  	struct thiscall;
  
  	template<class Ret, class ...Args>
  	struct thiscall<Ret(Args...)>
  	{
  		// Call function at @p returning @Ret with args @Args
  		static Ret call(memory_pointer_tr p, Args... a)
  		{
  			auto fn = (Ret(__thiscall*)(Args...)) p.get<void>();
  			return fn(std::forward<Args>(a)...);
  		}
  
  		// Call function at the index @i from the vtable of the object @a[0]
  		template<size_t i>
  		static Ret vtbl(Args... a)
  		{
  			auto obj = raw_ptr(std::get<0>(std::forward_as_tuple(a...)));
  			auto p = raw_ptr((*obj.template get<void**>())[i]);
  			return call(p, std::forward<Args>(a)...);
  		}
  
  		template<uintptr_t addr>    // Uses lazy pointer
  		static Ret call(Args... a)
  		{
  			return call(lazy_pointer<addr>::get(), std::forward<Args>(a)...);
  		}
  	};
  }
  
  