memlib

This module is designed to be a drop-in replacement for dynlib pragma and dynlib module in Windows. The main part of this module is a pure nim implementation of the famous MemoryModule library. So that the we can embed all DLLs into the main EXE file.

Types

MemoryModule = ptr MemoryModuleObj
Pointer to a MemoryModule object.
DllContent = distinct string
Represents DLL file in binary format.

Procs

proc checkedLoadLib(data: DllContent): MemoryModule {...}{.inline,
    raises: [Exception, LibraryError], tags: [RootEffect].}
Loads a DLL from memory. Raise LibraryError if the DLL could not be loaded.
proc checkedLoadLib(data: openArray[byte | char]): MemoryModule {...}{.inline.}
Loads a DLL from memory. Raise LibraryError if the DLL could not be loaded.
proc checkedSymAddr(lib: MemoryModule; name: string | LPCSTR): pointer {...}{.inline.}
Retrieves the address of a procedure from DLL by name. Raise LibraryError if the symbol could not be found.
proc checkedSymAddr(lib: MemoryModule; ordinal: range[0 .. 65535]): pointer {...}{.inline,
    raises: [LibraryError], tags: [].}
Retrieves the address of a procedure from DLL by ordinal. Raise LibraryError if the ordinal out of range.
proc loadLib(data: DllContent): MemoryModule {...}{.inline, raises: [], tags: [RootEffect].}
Loads a DLL from memory. Returns nil if the DLL could not be loaded.
proc loadLib(data: openArray[byte | char]): MemoryModule {...}{.inline.}
Loads a DLL from memory. Returns nil if the DLL could not be loaded.
proc symAddr(lib: MemoryModule; name: string | LPCSTR): pointer {...}{.inline.}
Retrieves the address of a procedure from DLL by name. Returns nil if the symbol could not be found.
proc symAddr(lib: MemoryModule; ordinal: range[0 .. 65535]): pointer {...}{.inline,
    raises: [], tags: [].}
Retrieves the address of a procedure from DLL by ordinal. Returns nil if the ordinal out of range.
proc unloadLib(lib: MemoryModule) {...}{.inline, raises: [Exception], tags: [RootEffect].}
Unloads the DLL.
proc run(lib: MemoryModule): int {...}{.discardable, raises: [LibraryError, Exception],
                               tags: [RootEffect].}

Execute entry point (EXE only). The entry point can only be executed if the EXE has been loaded to the correct base address or it could be relocated (i.e. relocation information have not been stripped by the linker).

Important: calling this function will not return, i.e. once the loaded EXE finished running, the process will terminate.

Raise LibraryError if the entry point could not be executed.

proc findResource(lib: HMODULE; name: LPCTSTR; typ: LPCTSTR; lang: WORD = 0): HRSRC {...}{.
    raises: [LibraryError], tags: [].}
Find the location of a resource with the specified type, name and language.
proc sizeOfResource(lib: HMODULE; resource: HRSRC): DWORD {...}{.raises: [], tags: [].}
Get the size of the resource in bytes.
proc loadResource(lib: HMODULE; resource: HRSRC): HGLOBAL {...}{.raises: [], tags: [].}
Get a pointer to the contents of the resource.
proc loadString(lib: HMODULE; id: UINT; lang: WORD = 0): string {...}{.raises: [LibraryError],
    tags: [].}
Load a string resource.
proc findResource(lib: MemoryModule; name: LPCTSTR; typ: LPCTSTR; lang: WORD = 0): HRSRC {...}{.
    inline, raises: [LibraryError], tags: [].}
Find the location of a resource with the specified type, name and language.
proc sizeOfResource(lib: MemoryModule; resource: HRSRC): DWORD {...}{.inline,
    raises: [LibraryError], tags: [].}
Get the size of the resource in bytes.
proc loadResource(lib: MemoryModule; resource: HRSRC): HGLOBAL {...}{.inline,
    raises: [LibraryError], tags: [].}
Get a pointer to the contents of the resource.
proc loadString(lib: MemoryModule; id: UINT; lang: WORD = 0): string {...}{.inline,
    raises: [LibraryError], tags: [].}
Load a string resource.
proc unhook(lib: MemoryModule) {...}{.raises: [], tags: [].}
Removes the hooks.
proc hook(lib: MemoryModule; name: string) {...}{.raises: [], tags: [].}
Hooks the system API (LoadLibrary and GetProcAddress only) with specified name. Following requests will be redirected to the memory module
proc checkedMemlookup(callPtr: ptr pointer; dll: DllContent; sym: LPCSTR) {...}{.
    raises: [Exception, LibraryError], tags: [RootEffect].}
A helper used by memlib macro.
proc memlookup(callPtr: ptr pointer; dll: DllContent; sym: LPCSTR) {...}{.raises: [],
    tags: [RootEffect].}
A helper used by memlib macro.
proc checkedLibLookup(callPtr: ptr pointer; lib: MemoryModule; sym: LPCSTR) {...}{.
    raises: [LibraryError], tags: [].}
A helper used by memlib macro.
proc libLookup(callPtr: ptr pointer; lib: MemoryModule; sym: LPCSTR) {...}{.raises: [],
    tags: [].}
A helper used by memlib macro.
proc checkedRtlookup(callPtr: ptr pointer; name: string; sym: LPCSTR) {...}{.
    raises: [LibraryError], tags: [].}
A helper used by memlib macro.
proc rtlookup(callPtr: ptr pointer; name: string; sym: LPCSTR) {...}{.raises: [], tags: [].}
A helper used by memlib macro.
proc staticReadDllWithName(dll: string; hint = true): (string, DllContent) {...}{.
    compiletime, raises: [ValueError, LibraryError],
    tags: [ReadEnvEffect, ReadDirEffect].}
Compile-time find and read library proc for DLL embedding. Returns the path and the binary in DllContent format. Supports dynlib name patterns. For example: libtcl(|8.5|8.4).
proc staticReadDll(dll: string; hint = true): DllContent {...}{.compiletime,
    raises: [ValueError, LibraryError], tags: [ReadEnvEffect, ReadDirEffect].}
Compile-time find and read library proc for DLL embedding. Returns the binary in DllContent format. Supports dynlib name patterns. For example: libtcl(|8.5|8.4).

Macros

macro checkedMemlib(dll, def: untyped): untyped
dynlib pragma replacement to load DLL from memory or at runtime. Raise LibraryError if error occurred. See memlib for details.
macro memlib(dll, def: untyped): untyped
dynlib pragma replacement to load DLL from memory or at runtime. Accepts a MemoryModule, DllContent, or string. The program will crash if error occurred, so only use this for trusted DLL.
ParameterMeaning
MemoryModuleUses the DLL loaded by loadLib or checkedLoadLib.
DllContentLoads DLL in binary format that returned by staticReadDll.
stringLoads the DLL at runtime by system API.

Examples:

const
  dll = staticReadDll("sqlite3_64.dll")
let lib = loadLib(dll)
proc libversion(): cstring {...}{.cdecl, memlib: lib, importc: "sqlite3_libversion".}
echo libversion()

Examples:

const
  dll = staticReadDll("sqlite3_64.dll")
proc libversion(): cstring {...}{.cdecl, memlib: dll, importc: "sqlite3_libversion".}
echo libversion()

Examples:

proc libversion(): cstring {...}{.cdecl, memlib: "sqlite3_64.dll",
                          importc: "sqlite3_libversion".}
echo libversion()
macro withPragma(pragma, body: untyped): untyped
push pragma replacement.

Examples:

proc test() =
  const
    dll = staticReadDll("sqlite3_64.dll")
  withPragma {cdecl, memlib: dll, importc: "sqlite3_libversion"}:
    proc libversion(): cstring
  echo libversion()
macro buildPragma(pragma, body: untyped): untyped
pragma pragma replacement.

Examples:

proc test() =
  const
    dll = staticReadDll("sqlite3_64.dll")
  buildPragma {cdecl, memlib: dll, importc: "sqlite3_libversion"}:
    mylib
  proc libversion(): cstring {...}{.mylib.}
  echo libversion()