Make the win32 putenv() override update *all* present versions of the
authorMagnus Hagander <magnus@hagander.net>
Fri, 1 Jan 2010 14:57:16 +0000 (14:57 +0000)
committerMagnus Hagander <magnus@hagander.net>
Fri, 1 Jan 2010 14:57:16 +0000 (14:57 +0000)
MSVCRxx runtime, not just the current + Visual Studio 6 (MSVCRT). Clearly
there can be an almost unlimited number of runtimes loaded at the same
time.

Per report from Hiroshi Inoue

src/port/win32env.c

index 6f15433078e0cbdff2267ba7df2a3469587acfb8..2aa448eef2dbf5bf4d9ff136836409a6ba7439fc 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/port/win32env.c,v 1.5 2009/12/27 16:11:28 mha Exp $
+ *   $PostgreSQL: pgsql/src/port/win32env.c,v 1.6 2010/01/01 14:57:16 mha Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -27,34 +27,72 @@ pgwin32_putenv(const char *envval)
     * Each version of MSVCRT has its own _putenv() call in the runtime
     * library.
     *
-    * If we're in VC 7.0 or later (means != mingw), update in the 6.0
-    * MSVCRT.DLL environment as well, to work with third party libraries
-    * linked against it (such as gnuwin32 libraries).
+    * mingw always uses MSVCRT.DLL, but if we are in a Visual C++ environment,
+    * attempt to update the environment in all MSVCRT modules that are
+    * currently loaded, to work properly with any third party libraries
+    * linked against a different MSVCRT but still relying on environment
+    * variables.
+    *
+    * Also separately update the system environment that gets inherited by
+    * subprocesses.
     */
-#if defined(_MSC_VER) && (_MSC_VER >= 1300)
+#ifdef _MSC_VER
    typedef int (_cdecl * PUTENVPROC) (const char *);
-   HMODULE     hmodule;
-   static PUTENVPROC putenvFunc = NULL;
+   static struct {
+       char       *modulename;
+       HMODULE     hmodule;
+       PUTENVPROC putenvFunc;
+   } rtmodules[] = {
+       { "msvcrt", 0, NULL},  /* Visual Studio 6.0 / mingw */
+       { "msvcr70", 0, NULL}, /* Visual Studio 2002 */
+       { "msvcr71", 0, NULL}, /* Visual Studio 2003 */
+       { "msvcr80", 0, NULL}, /* Visual Studio 2005 */
+       { "msvcr90", 0, NULL}, /* Visual Studio 2008 */
+       { NULL, 0, NULL}
+   };
+   int i;
 
-   if (putenvFunc == NULL)
+   for (i = 0; rtmodules[i].modulename; i++)
    {
-       hmodule = GetModuleHandle("msvcrt");
-       if (hmodule != NULL)
+       if (rtmodules[i].putenvFunc == NULL)
        {
-           /*
-            * If the module is found, attempt to find the function. If not, that just
-            * means we're not linked with msvcrt, so fall through and make our other
-            * modifications anyway.
-            * Ignore any errors and update whatever we can, since callers don't
-            * check the return value anyway.
-            */
-           putenvFunc = (PUTENVPROC) GetProcAddress(hmodule, "_putenv");
-           if (putenvFunc != NULL)
-               putenvFunc(envval);
+           if (rtmodules[i].hmodule == 0)
+           {
+               /* Not attempted before, so try to find this DLL */
+               rtmodules[i].hmodule = GetModuleHandle(rtmodules[i].modulename);
+               if (rtmodules[i].hmodule == NULL)
+               {
+                   /*
+                    * Set to INVALID_HANDLE_VALUE so we know we have tried this one
+                    * before, and won't try again.
+                    */
+                   rtmodules[i].hmodule = INVALID_HANDLE_VALUE;
+                   continue;
+               }
+               else
+               {
+                   rtmodules[i].putenvFunc = (PUTENVPROC) GetProcAddress(rtmodules[i].hmodule, "_putenv");
+                   if (rtmodules[i].putenvFunc == NULL)
+                   {
+                       CloseHandle(rtmodules[i].hmodule);
+                       rtmodules[i].hmodule = INVALID_HANDLE_VALUE;
+                       continue;
+                   }
+               }
+           }
+           else
+           {
+               /*
+                * Module loaded, but we did not find the function last time. We're
+                * not going to find it this time either...
+                */
+               continue;
+           }
        }
+       /* At this point, putenvFunc is set or we have exited the loop */
+       rtmodules[i].putenvFunc(envval);
    }
-#endif   /* _MSC_VER >= 1300 */
-
+#endif     /* _MSC_VER */
 
    /*
     * Update the process environment - to make modifications visible to child