go-winloader
go-winloader copied to clipboard
Differences in work from windows.NewLazyDLL
Hi) Are there any differences when using memory loading from a system function in terms of threads using and resource allocation? Faced the fact that in a number of experiments with cef (chromium embedded framework), launching three functions when linking in LDFLAGS and windows.NewLazyDll opens a new webview and loads url there. When using winloader.LoadFromMemory I get no errors, windows open, it opens a webview with a blank page (also works context-menu), but no URL opens. I've been investigating this issue for a week now, but I can't find any clear indication of the cause of this behavior.
// #cgo LDFLAGS: -L. -llibcef
/* C.cef_initialize(&settings.MainArgs, cefSettings, &settings.AppHandler, C.NULL) */
// winloader.LoadFromMemory(b)
/* cefInitialize.Call(
uint64(uintptr(unsafe.Pointer(&settings.MainArgs))),
uint64(uintptr(unsafe.Pointer(cefSettings))),
uint64(uintptr(unsafe.Pointer(&settings.AppHandler))),
uint64(uintptr(unsafe.Pointer(C.NULL))),
) */
// windows.NewLazyDLL("libcef.dll")
cefInitialize.Call(
uintptr(unsafe.Pointer(&settings.MainArgs)),
uintptr(unsafe.Pointer(cefSettings)),
uintptr(unsafe.Pointer(&settings.AppHandler)),
uintptr(unsafe.Pointer(C.NULL)),
)
I am not asking for help with cef, but maybe there are some subtleties that I do not know about and which could give me an idea of how to solve this problem. Unlike EDGE, the CEF library requires a lot of dlls in its directory and I am impressed by the idea of embedding them as resources in my application.
Wow! I’m impressed that it gets so far already. For Edge we’re just loading a small loader stub (in fact, I’ve fully reverse engineered that stub over here: https://github.com/jchv/OpenWebView2Loader) which loads the user’s installed runtime normally. So this is quite a stress test in comparison.
Unfortunately, this could be pretty challenging to debug given the complexity of CEF, but it would be a great test case for the robustness of the library. So I am interested in trying to get it to work.
A couple of potential problems: the HMODULE for memory loaded modules is not present in the internal Windows structures, which may lead to some calls failing on it (such as calls that load resources.) Also, memory loaded modules will not have their entrypoint called on them when threads are created or destroyed, which may lead to problems with TLS.
For this case I would guess the second issue is most likely, but I haven’t figured out how to remedy it; the most “obvious” approach would be to take the signal from another DllMain entrypoint, but it definitely gets into “fun” territory quickly. We can always count on kernel32 being loaded, but I don’t know if it has a “traditional” entrypoint called by the kernel or not. If it does, maybe it would be possible to trampoline that so we can go and call it for all of the memory-loaded modules afterwards. A disadvantage of trampolines is their architecture dependence, but I should be able to at least test it on x86/AMD64/ARMv8, but I have no ARMv7 capable Windows setups (all I have is an M1 Mac with Parallels. The M1 Mac does not support 32-bit ARM, even inside VM guests.)
This is all a bit of speculation. Unfortunately I’m coming off of vacation from work shortly so I might not be able to dig in right away but I am interested.