Hi,

I've been looking at an issue where using a JNI library built with MSVC 14
with TomEE under Windows 2016 as a service with commons-daemon isn't able
to pick up environment variables set for the service using getenv().

I note from
https://github.com/apache/commons-daemon/tree/master/src/native/windows
that the build chain is VC 6 and Platform SDK for Windows Server 2003 R2 -
the build with that fails with and error on this line for me:
https://github.com/apache/commons-daemon/blob/master/src/native/windows/src/log.c#L61
-
if I change "10000000ULL" to "10000000i64", it compiles and links ok.

Doing a "dumpbin /headers prunsrv.exe" on the 1.1.0 release shows a linker
version of 9.00, and looking at the imports, it uses msvcrt.dll (as opposed
to msvcrt800.dll). I'd like to get my build chain as close as possible to
what's actually used to create the binaries that are distributed. Is there
a more recent buildchain (DDK?) that uses a later compiler/linker, but
still uses msvcrt.dll rather than msvcrtXX.dll?

While digging further into the issue, it appears that different runtime
DLLs effectively get their own copy of the environment, and the JNI library
built with VC14 is using ucrtbase.dll for getenv, while commons-daemon is
adding entries from to the environment using _wputenv in msvcrt.dll. The
attached code demonstrates this. This article looks related as well:
https://docs.microsoft.com/en-us/cpp/c-runtime-library/potential-errors-passing-crt-objects-across-dll-boundaries?view=vs-2019

I have experimented with dynamically loading ucrtbase.dll and calling its
_wputenv() in addition to the _wputenv() call in msvcrt in commons-daemon,
and doing nothing if the library or function isn't present. I need to do
more testing on this, but my setInprocEnvironment()  function looks like
this:

static void setInprocEnvironment()
{
    LPWSTR p, e;
    HINSTANCE hinstUcrtLib;
    WPUTENV wputenv_ucrt;

    if (!SO_ENVIRONMENT)
        return;    /* Nothing to do */

    hinstUcrtLib = LoadLibrary(TEXT("ucrtbase.dll"));

    if (hinstUcrtLib != NULL) {
        wputenv_ucrt = (WPUTENV) GetProcAddress(hinstUcrtLib, "_wputenv");
    }

    for (p = SO_ENVIRONMENT; *p; p++) {
        e = apxExpandStrW(gPool, p);
        _wputenv(e);

        if (wputenv_ucrt != NULL) {
            wputenv_ucrt(e);
        }

        apxFree(e);
        while (*p)
            p++;
    }

    if (hinstUcrtLib != NULL) {
        FreeLibrary(hinstUcrtLib);
    }
}

This does work for my specific use-case, but I don't know if this is a
"good" approach, or something that the community would consider adopting.
I'd be grateful for feedback, and I'm happy to try different approaches and
create patches - I probably just need some pointers.

I did also try calling SetEnvironmentVariableW() (which didn't work,
although its possible I made a mistake, so I can certainly try it again).
Compiling commons-daemon with VC14 did appear to work, but that has the
issue of loading in specific versions of msvcrtXX.dll which sounds rather
undesirable.

Many thanks

Jon
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org
For additional commands, e-mail: dev-h...@commons.apache.org

Reply via email to