﻿import core.runtime;
import win32.windows;
import std.string;

class WinDLLException : Exception
{
	private this( string msg ) { super(msg); }
}

class WinDLL
{
	// constructor:
	//   Load a DLL of specified name.
	//   Avoid loading the DLL from the current directory for security.

	this( string dllname )
	{
		char original_cur[MAX_PATH];
		char sys[MAX_PATH];
		GetCurrentDirectoryA(original_cur.length, original_cur.ptr);
		GetSystemDirectoryA(sys.ptr, sys.length);
		SetCurrentDirectoryA(sys.ptr);
		handle = cast(HINSTANCE) Runtime.loadLibrary(dllname);
		SetCurrentDirectoryA(original_cur.ptr);
		if( handle is null )
			throw new WinDLLException( dllname ~ " not found" );
	}

	static WinDLL load( string name )
	{
		try {
			return new WinDLL(name);
		} catch(WinDLLException e) { return null; }
	}

	// close:
	//   free the DLL

	void close()
	{
		if( handle )
		{
			Runtime.unloadLibrary(handle);
			handle = null;
		}
	}

	// get_api:
	//   extract a function with specified name from the DLL.
	//   may return null.

	template get_api(FnT)
	{
		FnT get_api( string apiname )
			in { assert(handle); }
			body
			{
				return cast(FnT) GetProcAddress( handle, apiname.toStringz() );
			}
	}

	// load_resource:
	//   extract a resource

	void* load_resource( string resname, const char* type )
		in { assert(handle); }
		body
		{
			if(resname in rsrc_map)
				return rsrc_map[resname];

			HRSRC hi = FindResource( handle, resname.toStringz(), type );
			if( hi is null )
				return null;
			HGLOBAL hr = LoadResource( handle, hi );
			if( hr is null )
				return null;
			void* v = LockResource( hr );
			rsrc_map[resname] = v;
			return v;
		}

	// load_diaglog:
	//   specialized version of load_resource

	void* load_dialog( string resname )
	{
		return load_resource( resname, RT_DIALOG );
	}

	private HINSTANCE handle;
	private void*[string] rsrc_map;
}
