NET-Mapnik
NET-Mapnik copied to clipboard
DllMain changes environment variables
NETMapnik only seems to work when the Mapnik data files are in the process's current working directory. I think this is because the GDAL_DATA, PROJ_LIB, and ICU_DATA environment variables are set to relative paths when the DLL is loaded.
BOOLEAN WINAPI DllMain(IN HINSTANCE hDllHandle,
IN DWORD nReason,
IN LPVOID Reserved)
{
switch (nReason)
{
case DLL_PROCESS_ATTACH:
_putenv_s("PROJ_LIB", "share\\proj");
_putenv_s("ICU_DATA", "share\\icu");
_putenv_s("GDAL_DATA", "share\\gdal");
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
I have tried changing the environment variables back to what they were before the DLL was loaded, but even when I do that, Mapnik still behaves like it wants to use the relative paths.
Is there another way for me to tell Mapnik where the actual GDAL, PROJ, etc. data files reside?
Ah, just found related issue #14. Still, I'd like to not force the user to put the data files in the working directory of the current process, mainly because I'm writing code in ASP.NET and the default working directory is C:\Windows\System32\inetsrv
. I don't want to install Mapnik files in that directory on my client's servers.
The reason for the hard coded environmental variables is to avoid conflicts with existing PROJ/GDAL/ICU installs and limit outside dependencies. That being said i am open to optionally allowing these variables to be overridden if it is done right (i.e. see discussion in #35).
Regarding the ASP.NET working directory, i am guessing that you are having issues referencing unmanaged dlls and data files at run time? This is a common problem in IIS because IIS shadow copies all your managed assemblies to a temp directory but leaves everything else behind. The best solution in my opinion is to turn shadow copy off (see issue #22). With shadow copy turned off IIS runs everything directly from your bin directory.
<system.web>
<hostingEnvironment shadowCopyBinAssemblies="false" />
</system.web>
Yes, I have discovered problems with shadow copy and disabled it. However I'm finding that even with shadow copy off, the working directory of the process is not the bin directory. It's C:\Windows\System32\inetsrv
, so it's looking for the proj folder at C:\Windows\System32\inetsrv\share\proj
instead of [MyAppDir]\bin\share\proj
.
I'm not a C++/CLI developer, but would something like this work?
void setEnvVarIfEmpty(const char* varName, const char* value)
{
size_t valueSize;
getenv_s( &valueSize, NULL, 0, varName);
if (valueSize == 0)
{
_putenv_s(varName, value);
}
}
setEnvVarIfEmpty("PROJ_LIB", "share\\proj");
setEnvVarIfEmpty("ICU_DATA", "share\\icu");
setEnvVarIfEmpty("GDAL_DATA", "share\\gdal");
I believe everything should work as expected with shadowCopyBinAssemblies set to false so this is a bit surprising to me.
I hesitate to use a set-var-if-empty pattern like you suggest. The default should be to use the data files that are local to net-mapnik. This is how it is done in node-mapnik and i agree with this approach. I'd be more inclined to use a NET_MAPNIK_GDAL_DATA environmental var that overrides the default location when set.
Well, perhaps some of the configuration I've done is making Environment.CurrentDirectory
default to a weird place.
- Windows 10 Pro
- x64 application (using mapnik.x64 NuGet package)
- Running under regular IIS (not IIS Express that comes with Visual Studio)
- Using an app pool that's running under a restricted user account (not a member of the regular interactive "Users" group)
Regarding the NET_MAPNIK_GDAL_DATA environment variable, that makes sense. Maybe if I get some time I'll contribute another pull request.