is there nim package which can embed DLL/DLLs into EXE, so that we can release one-file application
thanks
here is the wrapper:
{.compile: "MemoryModule.c".}
type
HMEMORYMODULE* = pointer
HMEMORYRSRC* = pointer
HCUSTOMMODULE* = pointer
{.push: cdecl, importc, discardable.}
proc MemoryLoadLibrary*(loc: pointer, size: int): HMEMORYMODULE
proc MemoryLoadLibraryEx*(loc: pointer, size: int, allocMemory: pointer, freeMemory: pointer, loadLibrary: pointer, getProcAddress: pointer, freeLibrary: pointer, userdata: pointer): HMEMORYMODULE
proc MemoryGetProcAddress*(mMod: HMEMORYMODULE, pName: cstring): pointer
proc MemoryFreeLibrary*(mMod: HMEMORYMODULE)
proc MemoryCallEntryPoint*(mMod: HMEMORYMODULE): int
proc MemoryFindResource*(a1: HMEMORYMODULE; a2: cstring; a3: cstring): HMEMORYRSRC
proc MemoryFindResourceEx*(a1: HMEMORYMODULE; a2: cstring; a3: cstring; a4: int16): HMEMORYRSRC
proc MemorySizeofResource*(a1: HMEMORYMODULE; a2: HMEMORYRSRC): int32
proc MemoryLoadResource*(a1: HMEMORYMODULE; a2: HMEMORYRSRC): pointer
proc MemoryLoadString*(a1: HMEMORYMODULE; a2: uint; a3: cstring; a4: cint): cint
proc MemoryLoadStringEx*(a1: HMEMORYMODULE; a2: uint; a3: cstring; a4: cint; a5: int16): cint
{.pop.}
Error: 'push' cannot have arguments
nim c --app:lib add.nim can get libadd.dll
# add.nim
{.push dynlib exportc.}
{.pop.}
then compile and run
import rgv151_MemoryModule
var data = newFileStream("libadd.dll").readAll()
var handle = MemoryLoadLibrary(cast[pointer](data), len(data))
var h = MemoryGetProcAddress(handle, "add")
MemoryFreeLibrary(handle);
but get
Traceback (most recent call last)
R:\MemoryModule-master\b.nim(43) b
SIGSEGV: Illegal storage access. (Attempt to read from nil?)
Error: execution of an external program failed: 'R:\MemoryModule-master\b.exe '
Like this
import streams
type
AddXY = proc(x, y: int): int {.cdecl.}
const
dll = "libadd.dll"
bin = readFile dll
size = bin.len
let
inmem = alloc size
readsize = newStringStream(bin).readData(inmem, size)
handle = MemoryLoadLibrary(inmem, size)
addproc = cast[AddXY](MemoryGetProcAddress(handle, "add"))
echo addproc(1, 2)
MemoryFreeLibrary(handle)
dealloc inmem
thanks
so is this the standard code to read binary file in nim? Is there nothing simple with only 1~2 lines like python/C does with the rb parameter?
# python
data = open('file.dll', 'rb').read()
check out my example here: https://github.com/ba0f3/mm.nim/blob/master/tests/test1.nim
there are many ways to read a file, you can use readFile or slurp, depend on your need
Check out nimdeps which makes this easier - of course, it doesn't load DLL from memory but simply writes it to a file on first start. This also means you have to manually load it with the dynlib module but seems like that's something you plan on doing anyway.
lazylib is an alternative to the dynlib pragma if that's of interest as well.
1. The best way is to keep the file structure as simple as possible so that the common user can tell which is the EXE file easily. I don't think a .zip file is a good way; if the user has (de)compressor application installed, the double click will not open the .zip file as a directory
Well you can create a real installer, but assuming Windows users don't even know how .zip files work is hubris.
2. I am not willing to tell which DLLs are used. (btw, if I do so, do I break LGPL?)
No, you don't break the LGPL. And disassembling the program to see which DLLs or libraries it uses is very easy.
slurp or staticRead sounds too weird for me to recall what they really do
What would be more obvious and explanatory of a name than staticRead, given that one is familiar enough with the language to know that "static" refers to compile time values?
no I mean why newFileStream("libadd.dll").readAll() can't return binary data well, but staticRead("libadd.dll") returns binary data without problem.
What is the reasonable relationship between static and binary data, and bad-relationship between readall and binary data?