Make the win32 putenv() override update *all* present versions of the
authorMagnus Hagander <magnus@hagander.net>
Fri, 1 Jan 2010 14:57:19 +0000 (14:57 +0000)
committerMagnus Hagander <magnus@hagander.net>
Fri, 1 Jan 2010 14:57:19 +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 9a32387337e4d6bc292927ad5b0740b06f293b06..0578dde81811ba701b32e116bb29d3a14062e527 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/port/win32env.c,v 1.3 2009/06/11 14:49:15 momjian Exp $
+ *   $PostgreSQL: pgsql/src/port/win32env.c,v 1.3.2.1 2010/01/01 14:57:19 mha Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -27,30 +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;
-   int         ret;
+   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)
-           return 1;
-       putenvFunc = (PUTENVPROC) GetProcAddress(hmodule, "_putenv");
-       if (putenvFunc == NULL)
-           return 1;
+       if (rtmodules[i].putenvFunc == NULL)
+       {
+           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);
    }
-   ret = putenvFunc(envval);
-   if (ret != 0)
-       return ret;
-#endif   /* _MSC_VER >= 1300 */
-
+#endif     /* _MSC_VER */
 
    /*
     * Update the process environment - to make modifications visible to child