w32: Avoid conflict with Mingw-w64 version 4.0.4-1
[gpgme.git] / src / w32-util.c
index a4a01f4..a27955b 100644 (file)
@@ -1,24 +1,23 @@
 /* w32-util.c - Utility functions for the W32 API
-   Copyright (C) 1999 Free Software Foundation, Inc
-   Copyright (C) 2001 Werner Koch (dd9jn)
-   Copyright (C) 2001, 2002, 2003, 2004, 2007 g10 Code GmbH
-
-   This file is part of GPGME.
-   GPGME is free software; you can redistribute it and/or modify it
-   under the terms of the GNU Lesser General Public License as
-   published by the Free Software Foundation; either version 2.1 of
-   the License, or (at your option) any later version.
-   
-   GPGME is distributed in the hope that it will be useful, but
-   WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-   
-   You should have received a copy of the GNU Lesser General Public
-   License along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-   02111-1307, USA.  */
+ * Copyright (C) 1999 Free Software Foundation, Inc
+ * Copyright (C) 2001 Werner Koch (dd9jn)
+ * Copyright (C) 2001, 2002, 2003, 2004, 2007, 2013 g10 Code GmbH
+ *
+ * This file is part of GPGME.
+ *
+ * GPGME is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * GPGME is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ **/
 
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #include <assert.h>
 #include <errno.h>
 #include <stdint.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <signal.h>
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
 #include <fcntl.h>
+#include <io.h>
+
+#if __MINGW64_VERSION_MAJOR >= 2
+# define _WIN32_IE 0x0501 /* Required by mingw64 toolkit.  */
+#else
+# define _WIN32_IE 0x0400 /* Required for SHGetSpecialFolderPathA.  */
+#endif
+
+/* We need to include the windows stuff here prior to shlobj.h so that
+   we get the right winsock version.  This is usually done in util.h
+   but that header also redefines some Windows functions which we need
+   to avoid unless having included shlobj.h.  */
+#include <winsock2.h>
+#include <ws2tcpip.h>
 #include <windows.h>
 #include <shlobj.h>
-#include <io.h>
 
 #include "util.h"
+#include "ath.h"
 #include "sema.h"
 #include "debug.h"
+#include "sys-util.h"
+
+
+#ifndef HAVE_W32CE_SYSTEM
+#define HAVE_ALLOW_SET_FOREGROUND_WINDOW 1
+#endif
+#ifndef F_OK
+# define F_OK 0
+#endif
+
 
 DEFINE_STATIC_LOCK (get_path_lock);
 
+/* The module handle of this DLL.  If we are linked statically,
+   dllmain does not exists and thus the value of my_hmodule will be
+   NULL.  The effect is that a GetModuleFileName always returns the
+   file name of the DLL or executable which contains the gpgme code.  */
+static HMODULE my_hmodule;
+
+/* These variables store the malloced name of alternative default
+   binaries.  The are set only once by gpgme_set_global_flag.  */
+static char *default_gpg_name;
+static char *default_gpgconf_name;
+/* If this variable is not NULL the value is assumed to be the
+   installation directory.  The variable may only be set once by
+   gpgme_set_global_flag and accessed by _gpgme_get_inst_dir.  */
+static char *override_inst_dir;
+
+#ifdef HAVE_ALLOW_SET_FOREGROUND_WINDOW
 
 #define RTLD_LAZY 0
 
-static __inline__ void *
+static GPG_ERR_INLINE void *
 dlopen (const char * name, int flag)
 {
   void * hd = LoadLibrary (name);
   return hd;
 }
 
-static __inline__ void *
+static GPG_ERR_INLINE void *
 dlsym (void * hd, const char * sym)
 {
   if (hd && sym)
@@ -68,7 +114,7 @@ dlsym (void * hd, const char * sym)
   return NULL;
 }
 
-static __inline__ int
+static GPG_ERR_INLINE int
 dlclose (void * hd)
 {
   if (hd)
@@ -77,7 +123,111 @@ dlclose (void * hd)
       return 0;
     }
   return -1;
-}  
+}
+#endif /* HAVE_ALLOW_SET_FOREGROUND_WINDOW */
+
+
+/* Return a malloced string encoded in UTF-8 from the wide char input
+   string STRING.  Caller must free this value.  Returns NULL and sets
+   ERRNO on failure.  Calling this function with STRING set to NULL is
+   not defined.  */
+static char *
+wchar_to_utf8 (const wchar_t *string)
+{
+  int n;
+  char *result;
+
+  n = WideCharToMultiByte (CP_UTF8, 0, string, -1, NULL, 0, NULL, NULL);
+  if (n < 0)
+    {
+      gpg_err_set_errno (EINVAL);
+      return NULL;
+    }
+
+  result = malloc (n+1);
+  if (!result)
+    return NULL;
+
+  n = WideCharToMultiByte (CP_UTF8, 0, string, -1, result, n, NULL, NULL);
+  if (n < 0)
+    {
+      free (result);
+      gpg_err_set_errno (EINVAL);
+      result = NULL;
+    }
+  return result;
+}
+
+
+/* Replace all forward slashes by backslashes.  */
+static void
+replace_slashes (char *string)
+{
+  for (; *string; string++)
+    if (*string == '/')
+      *string = '\\';
+}
+
+
+/* Get the base name of NAME.  Returns a pointer into NAME right after
+   the last slash or backslash or to NAME if no slash or backslash
+   exists.  */
+static const char *
+get_basename (const char *name)
+{
+  const char *mark, *s;
+
+  for (mark=NULL, s=name; *s; s++)
+    if (*s == '/' || *s == '\\')
+      mark = s;
+
+  return mark? mark+1 : name;
+}
+
+
+void
+_gpgme_allow_set_foreground_window (pid_t pid)
+{
+#ifdef HAVE_ALLOW_SET_FOREGROUND_WINDOW
+  static int initialized;
+  static BOOL (WINAPI * func)(DWORD);
+  void *handle;
+
+  if (!initialized)
+    {
+      /* Available since W2000; thus we dynload it.  */
+      initialized = 1;
+      handle = dlopen ("user32.dll", RTLD_LAZY);
+      if (handle)
+        {
+          func = dlsym (handle, "AllowSetForegroundWindow");
+          if (!func)
+            {
+              dlclose (handle);
+              handle = NULL;
+            }
+        }
+    }
+
+  if (!pid || pid == (pid_t)(-1))
+    {
+      TRACE1 (DEBUG_ENGINE, "gpgme:AllowSetForegroundWindow", 0,
+             "no action for pid %d", (int)pid);
+    }
+  else if (func)
+    {
+      int rc = func (pid);
+      TRACE2 (DEBUG_ENGINE, "gpgme:AllowSetForegroundWindow", 0,
+             "called for pid %d; result=%d", (int)pid, rc);
+
+    }
+  else
+    {
+      TRACE0 (DEBUG_ENGINE, "gpgme:AllowSetForegroundWindow", 0,
+             "function not available");
+    }
+#endif /* HAVE_ALLOW_SET_FOREGROUND_WINDOW */
+}
 
 
 /* Return a string from the W32 Registry or NULL in case of error.
@@ -89,60 +239,65 @@ read_w32_registry_string (const char *root, const char *dir, const char *name)
   HKEY root_key, key_handle;
   DWORD n1, nbytes, type;
   char *result = NULL;
-       
-  if ( !root )
+
+  if (!root)
     root_key = HKEY_CURRENT_USER;
-  else if ( !strcmp( root, "HKEY_CLASSES_ROOT" ) )
+  else if (!strcmp( root, "HKEY_CLASSES_ROOT"))
     root_key = HKEY_CLASSES_ROOT;
-  else if ( !strcmp( root, "HKEY_CURRENT_USER" ) )
+  else if (!strcmp( root, "HKEY_CURRENT_USER"))
     root_key = HKEY_CURRENT_USER;
-  else if ( !strcmp( root, "HKEY_LOCAL_MACHINE" ) )
+  else if (!strcmp( root, "HKEY_LOCAL_MACHINE"))
     root_key = HKEY_LOCAL_MACHINE;
-  else if ( !strcmp( root, "HKEY_USERS" ) )
+  else if (!strcmp( root, "HKEY_USERS"))
     root_key = HKEY_USERS;
-  else if ( !strcmp( root, "HKEY_PERFORMANCE_DATA" ) )
+  else if (!strcmp( root, "HKEY_PERFORMANCE_DATA"))
     root_key = HKEY_PERFORMANCE_DATA;
-  else if ( !strcmp( root, "HKEY_CURRENT_CONFIG" ) )
+  else if (!strcmp( root, "HKEY_CURRENT_CONFIG"))
     root_key = HKEY_CURRENT_CONFIG;
   else
     return NULL;
-       
-  if ( RegOpenKeyEx ( root_key, dir, 0, KEY_READ, &key_handle ) )
+
+  if (RegOpenKeyExA (root_key, dir, 0, KEY_READ, &key_handle))
     {
       if (root)
         return NULL; /* no need for a RegClose, so return direct */
       /* It seems to be common practise to fall back to HKLM. */
-      if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle) )
+      if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle))
         return NULL; /* still no need for a RegClose, so return direct */
     }
 
   nbytes = 1;
-  if ( RegQueryValueEx( key_handle, name, 0, NULL, NULL, &nbytes ) )
+  if (RegQueryValueExA (key_handle, name, 0, NULL, NULL, &nbytes))
     {
       if (root)
         goto leave;
       /* Try to fallback to HKLM also vor a missing value.  */
       RegCloseKey (key_handle);
-      if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle) )
+      if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle))
         return NULL; /* Nope.  */
-      if (RegQueryValueEx ( key_handle, name, 0, NULL, NULL, &nbytes))
+      if (RegQueryValueExA (key_handle, name, 0, NULL, NULL, &nbytes))
         goto leave;
     }
-  result = malloc ( (n1=nbytes+1) );
-  if ( !result )
+  n1 = nbytes + 1;
+  result = malloc (n1);
+  if (!result)
     goto leave;
-  if ( RegQueryValueEx ( key_handle, name, 0, &type, result, &n1 ) )
+  if (RegQueryValueExA (key_handle, name, 0, &type, (LPBYTE) result, &n1))
     {
-      free(result); result = NULL;
+      free (result);
+      result = NULL;
       goto leave;
     }
   result[nbytes] = 0; /* Make sure it is really a string.  */
-  if (type == REG_EXPAND_SZ && strchr (result, '%')) 
+
+#ifndef HAVE_W32CE_SYSTEM
+  /* Windows CE does not have an environment.  */
+  if (type == REG_EXPAND_SZ && strchr (result, '%'))
     {
       char *tmp;
-        
+
       n1 += 1000;
-      tmp = malloc (n1+1);
+      tmp = malloc (n1 + 1);
       if (!tmp)
         goto leave;
       nbytes = ExpandEnvironmentStrings (result, tmp, n1);
@@ -169,7 +324,7 @@ read_w32_registry_string (const char *root, const char *dir, const char *name)
           result = malloc (strlen (tmp)+1);
           if (!result)
             result = tmp;
-          else 
+          else
             {
               strcpy (result, tmp);
               free (tmp);
@@ -180,96 +335,64 @@ read_w32_registry_string (const char *root, const char *dir, const char *name)
           free (tmp);
         }
     }
+#endif
 
  leave:
-  RegCloseKey( key_handle );
+  RegCloseKey (key_handle);
   return result;
 }
 
 
-/* This is a helper function to load and run a Windows function from
-   either of one DLLs. */
-static HRESULT
-w32_shgetfolderpath (HWND a, int b, HANDLE c, DWORD d, LPSTR e)
+/* Return the name of the directory with the gpgme DLL or the EXE (if
+   statically linked).  May return NULL on severe errors. */
+const char *
+_gpgme_get_inst_dir (void)
 {
-  static int initialized;
-  static HRESULT (WINAPI * func)(HWND,int,HANDLE,DWORD,LPSTR);
+  static char *inst_dir;
 
-  if (!initialized)
-    {
-      static char *dllnames[] = { "shell32.dll", "shfolder.dll", NULL };
-      void *handle;
-      int i;
+  if (override_inst_dir)
+    return override_inst_dir;
 
-      initialized = 1;
+  LOCK (get_path_lock);
+  if (!inst_dir)
+    {
+      wchar_t *moddir;
 
-      for (i=0, handle = NULL; !handle && dllnames[i]; i++)
+      moddir = malloc ((MAX_PATH+5) * sizeof *moddir);
+      if (moddir)
         {
-          handle = dlopen (dllnames[i], RTLD_LAZY);
-          if (handle)
+          if (!GetModuleFileNameW (my_hmodule, moddir, MAX_PATH))
+            *moddir = 0;
+          if (!*moddir)
+            gpg_err_set_errno (ENOENT);
+          else
             {
-              func = dlsym (handle, "SHGetFolderPathA");
-              if (!func)
+              inst_dir = wchar_to_utf8 (moddir);
+              if (inst_dir)
                 {
-                  dlclose (handle);
-                  handle = NULL;
+                  char *p = strrchr (inst_dir, '\\');
+                  if (p)
+                    *p = 0;
                 }
             }
+          free (moddir);
         }
     }
-
-  if (func)
-    return func (a,b,c,d,e);
-  else
-    return -1;
-}
-
-
-#if 0
-static char *
-find_program_in_registry (const char *name)
-{
-  char *program = NULL;
-    
-  program = read_w32_registry_string (NULL, "Software\\GNU\\GnuPG", name);
-  if (program)
-    {
-      int i;
-
-      TRACE2 (DEBUG_CTX, "gpgme:find_program_in_registry", 0,
-             "found %s in registry: `%s'", name, program);
-      for (i = 0; program[i]; i++)
-       {
-         if (program[i] == '/')
-           program[i] = '\\';
-       }
-    }
-  return program;
+  UNLOCK (get_path_lock);
+  return inst_dir;
 }
-#endif
 
 
 static char *
-find_program_in_inst_dir (const char *name)
+find_program_in_dir (const char *dir, const char *name)
 {
-  char *result = NULL;
-  char *tmp;
+  char *result;
 
-  tmp = read_w32_registry_string ("HKEY_LOCAL_MACHINE",
-                                 "Software\\GNU\\GnuPG",
-                                 "Install Directory");
-  if (!tmp)
-    return NULL;
-
-  result = malloc (strlen (tmp) + 1 + strlen (name) + 1);
+  result = malloc (strlen (dir) + 1 + strlen (name) + 1);
   if (!result)
-    {
-      free (tmp);
-      return NULL;
-    }
+    return NULL;
 
-  strcpy (stpcpy (stpcpy (result, tmp), "\\"), name);
-  free (tmp);
+  strcpy (stpcpy (stpcpy (result, dir), "\\"), name);
   if (access (result, F_OK))
     {
       free (result);
@@ -285,8 +408,14 @@ find_program_at_standard_place (const char *name)
 {
   char path[MAX_PATH];
   char *result = NULL;
-      
-  if (w32_shgetfolderpath (NULL, CSIDL_PROGRAM_FILES, NULL, 0, path) >= 0) 
+
+  /* See http://wiki.tcl.tk/17492 for details on compatibility.
+
+     We First try the generic place and then fallback to the x86
+     (i.e. 32 bit) place.  This will prefer a 64 bit of the program
+     over a 32 bit version on 64 bit Windows if installed.  */
+  if (SHGetSpecialFolderPathA (NULL, path, CSIDL_PROGRAM_FILES, 0)
+      || SHGetSpecialFolderPathA (NULL, path, CSIDL_PROGRAM_FILESX86, 0))
     {
       result = malloc (strlen (path) + 1 + strlen (name) + 1);
       if (result)
@@ -303,61 +432,164 @@ find_program_at_standard_place (const char *name)
 }
 
 
-const char *
-_gpgme_get_gpg_path (void)
+/* Set the default name for the gpg binary.  This function may only be
+   called by gpgme_set_global_flag.  Returns 0 on success.  */
+int
+_gpgme_set_default_gpg_name (const char *name)
 {
-  static char *gpg_program;
+  if (!default_gpg_name)
+    {
+      default_gpg_name = malloc (strlen (name) + 5);
+      if (default_gpg_name)
+        {
+          strcpy (stpcpy (default_gpg_name, name), ".exe");
+          replace_slashes (default_gpg_name);
+        }
+    }
+  return !default_gpg_name;
+}
 
-  LOCK (get_path_lock);
-#if 0
-  if (!gpg_program)
-    gpg_program = find_program_in_registry ("gpgProgram");
-#endif
-  if (!gpg_program)
-    gpg_program = find_program_in_inst_dir ("gpg.exe");
-  if (!gpg_program)
-    gpg_program = find_program_at_standard_place ("GNU\\GnuPG\\gpg.exe");
-  UNLOCK (get_path_lock);
-  return gpg_program;
+/* Set the default name for the gpgconf binary.  This function may only be
+   called by gpgme_set_global_flag.  Returns 0 on success.  */
+int
+_gpgme_set_default_gpgconf_name (const char *name)
+{
+  if (!default_gpgconf_name)
+    {
+      default_gpgconf_name = malloc (strlen (name) + 5);
+      if (default_gpgconf_name)
+        {
+          strcpy (stpcpy (default_gpgconf_name, name), ".exe");
+          replace_slashes (default_gpgconf_name);
+        }
+    }
+  return !default_gpgconf_name;
 }
 
 
-const char *
-_gpgme_get_gpgsm_path (void)
+/* Set the override installation directory.  This function may only be
+   called by gpgme_set_global_flag.  Returns 0 on success.  */
+int
+_gpgme_set_override_inst_dir (const char *dir)
 {
-  static char *gpgsm_program;
+  if (!override_inst_dir)
+    {
+      override_inst_dir = malloc (strlen (dir) + 1);
+      if (override_inst_dir)
+        {
+          strcpy (override_inst_dir, dir);
+          replace_slashes (override_inst_dir);
+          /* Remove a trailing slash.  */
+          if (*override_inst_dir
+              && override_inst_dir[strlen (override_inst_dir)-1] == '\\')
+            override_inst_dir[strlen (override_inst_dir)-1] = 0;
+        }
+    }
+  return !override_inst_dir;
+}
 
-  LOCK (get_path_lock);
-#if 0
-  if (!gpgsm_program)
-    gpgsm_program = find_program_in_registry ("gpgsmProgram");
-#endif
-  if (!gpgsm_program)
-    gpgsm_program = find_program_in_inst_dir ("gpgsm.exe");
-  if (!gpgsm_program)
-    gpgsm_program = find_program_at_standard_place ("GNU\\GnuPG\\gpgsm.exe");
-  UNLOCK (get_path_lock);
-  return gpgsm_program;
+
+/* Return the full file name of the GPG binary.  This function is used
+   iff gpgconf was not found and thus it can be assumed that gpg2 is
+   not installed.  This function is only called by get_gpgconf_item
+   and may not be called concurrently. */
+char *
+_gpgme_get_gpg_path (void)
+{
+  char *gpg = NULL;
+  const char *name, *inst_dir;
+
+  name = default_gpg_name? get_basename (default_gpg_name) : "gpg.exe";
+
+  /* 1. Try to find gpg.exe in the installation directory of gpgme.  */
+  inst_dir = _gpgme_get_inst_dir ();
+  if (inst_dir)
+    {
+      gpg = find_program_in_dir (inst_dir, name);
+    }
+
+  /* 2. Try to find gpg.exe using that ancient registry key.  */
+  if (!gpg)
+    {
+      char *dir;
+
+      dir = read_w32_registry_string ("HKEY_LOCAL_MACHINE",
+                                      "Software\\GNU\\GnuPG",
+                                      "Install Directory");
+      if (dir)
+        {
+          gpg = find_program_in_dir (dir, name);
+          free (dir);
+        }
+    }
+
+  /* 3. Try to find gpg.exe below CSIDL_PROGRAM_FILES.  */
+  if (!gpg)
+    {
+      name = default_gpg_name? default_gpg_name : "GNU\\GnuPG\\gpg.exe";
+      gpg = find_program_at_standard_place (name);
+    }
+
+  /* 4. Print a debug message if not found.  */
+  if (!gpg)
+    _gpgme_debug (DEBUG_ENGINE, "_gpgme_get_gpg_path: '%s' not found", name);
+
+  return gpg;
 }
 
 
-const char *
+/* This function is only called by get_gpgconf_item and may not be
+   called concurrently.  */
+char *
 _gpgme_get_gpgconf_path (void)
 {
-  static char *gpgconf_program;
+  char *gpgconf = NULL;
+  const char *inst_dir, *name;
 
-  LOCK (get_path_lock);
-#if 0
-  if (!gpgconf_program)
-    gpgconf_program = find_program_in_registry ("gpgconfProgram");
-#endif
-  if (!gpgconf_program)
-    gpgconf_program = find_program_in_inst_dir ("gpgconf.exe");
-  if (!gpgconf_program)
-    gpgconf_program
-      = find_program_at_standard_place ("GNU\\GnuPG\\gpgconf.exe");
-  UNLOCK (get_path_lock);
-  return gpgconf_program;
+  name = default_gpgconf_name? get_basename(default_gpgconf_name):"gpgconf.exe";
+
+  /* 1. Try to find gpgconf.exe in the installation directory of gpgme.  */
+  inst_dir = _gpgme_get_inst_dir ();
+  if (inst_dir)
+    {
+      gpgconf = find_program_in_dir (inst_dir, name);
+    }
+
+  /* 2. Try to find gpgconf.exe from GnuPG >= 2.1 below CSIDL_PROGRAM_FILES. */
+  if (!gpgconf)
+    {
+      const char *name2 = (default_gpgconf_name ? default_gpgconf_name
+                           /**/                 : "GnuPG\\bin\\gpgconf.exe");
+      gpgconf = find_program_at_standard_place (name2);
+    }
+
+  /* 3. Try to find gpgconf.exe using that ancient registry key.  This
+        should eventually be removed.  */
+  if (!gpgconf)
+    {
+      char *dir;
+
+      dir = read_w32_registry_string ("HKEY_LOCAL_MACHINE",
+                                      "Software\\GNU\\GnuPG",
+                                      "Install Directory");
+      if (dir)
+        {
+          gpgconf = find_program_in_dir (dir, name);
+          free (dir);
+        }
+    }
+
+  /* 4. Try to find gpgconf.exe from Gpg4win below CSIDL_PROGRAM_FILES.  */
+  if (!gpgconf)
+    {
+      gpgconf = find_program_at_standard_place ("GNU\\GnuPG\\gpgconf.exe");
+    }
+
+  /* 5. Print a debug message if not found.  */
+  if (!gpgconf)
+    _gpgme_debug (DEBUG_ENGINE, "_gpgme_get_gpgconf_path: '%s' not found",name);
+
+  return gpgconf;
 }
 
 
@@ -365,13 +597,12 @@ const char *
 _gpgme_get_w32spawn_path (void)
 {
   static char *w32spawn_program;
+  const char *inst_dir;
 
+  inst_dir = _gpgme_get_inst_dir ();
   LOCK (get_path_lock);
   if (!w32spawn_program)
-    w32spawn_program = find_program_in_inst_dir ("gpgme-w32spawn.exe");
-  if (!w32spawn_program)
-    w32spawn_program
-      = find_program_at_standard_place ("GNU\\GnuPG\\gpgme-w32spawn.exe");
+    w32spawn_program = find_program_in_dir (inst_dir, "gpgme-w32spawn.exe");
   UNLOCK (get_path_lock);
   return w32spawn_program;
 }
@@ -391,39 +622,15 @@ _gpgme_get_conf_int (const char *key, int *value)
   return 1;
 }
 
-
-void 
-_gpgme_allow_set_foregound_window (pid_t pid)
+\f
+#ifdef HAVE_W32CE_SYSTEM
+int
+_gpgme_mkstemp (int *fd, char **name)
 {
-  static int initialized;
-  static BOOL (WINAPI * func)(DWORD);
-  void *handle;
-
-  if (!initialized)
-    {
-      /* Available since W2000; thus we dynload it.  */
-      initialized = 1;
-      handle = dlopen ("user32.dll", RTLD_LAZY);
-      if (handle)
-        {
-          func = dlsym (handle, "AllowSetForegroundWindow");
-          if (!func)
-            {
-              dlclose (handle);
-              handle = NULL;
-            }
-        }
-    }
-
-  if (!pid || pid == (pid_t)(-1))
-    ;
-  else if (func)
-    func (pid);
-
+  return -1;
 }
+#else
 
-
-\f
 /* mkstemp extracted from libc/sysdeps/posix/tempname.c.  Copyright
    (C) 1991-1999, 2000, 2001, 2006 Free Software Foundation, Inc.
 
@@ -440,7 +647,7 @@ static const char letters[] =
    does not exist at the time of the call to mkstemp.  TMPL is
    overwritten with the result.  */
 static int
-mkstemp (char *tmpl)
+my_mkstemp (char *tmpl)
 {
   int len;
   char *XXXXXX;
@@ -469,7 +676,7 @@ mkstemp (char *tmpl)
   len = strlen (tmpl);
   if (len < 6 || strcmp (&tmpl[len - 6], "XXXXXX"))
     {
-      errno = EINVAL;
+      gpg_err_set_errno (EINVAL);
       return -1;
     }
 
@@ -484,7 +691,7 @@ mkstemp (char *tmpl)
     random_time_bits = (((uint64_t)ft.dwHighDateTime << 32)
                         | (uint64_t)ft.dwLowDateTime);
   }
-  value += random_time_bits ^ getpid ();
+  value += random_time_bits ^ ath_self ();
 
   for (count = 0; count < attempts; value += 7777, ++count)
     {
@@ -506,7 +713,7 @@ mkstemp (char *tmpl)
       fd = open (tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
       if (fd >= 0)
        {
-         errno = save_errno;
+         gpg_err_set_errno (save_errno);
          return fd;
        }
       else if (errno != EEXIST)
@@ -514,7 +721,7 @@ mkstemp (char *tmpl)
     }
 
   /* We got out of the loop because we ran out of combinations to try.  */
-  errno = EEXIST;
+  gpg_err_set_errno (EEXIST);
   return -1;
 }
 
@@ -529,13 +736,13 @@ _gpgme_mkstemp (int *fd, char **name)
   *fd = -1;
   *name = NULL;
 
-  err = GetTempPath (MAX_PATH + 1, tmp);
+  err = GetTempPathA (MAX_PATH + 1, tmp);
   if (err == 0 || err > MAX_PATH + 1)
     strcpy (tmp,"c:\\windows\\temp");
   else
     {
       int len = strlen(tmp);
-      
+
       /* GetTempPath may return with \ on the end */
       while(len > 0 && tmp[len - 1] == '\\')
        {
@@ -548,10 +755,50 @@ _gpgme_mkstemp (int *fd, char **name)
   if (!tmpname)
     return -1;
   strcpy (stpcpy (tmpname, tmp), "\\gpgme-XXXXXX");
-  *fd = mkstemp (tmpname);
+  *fd = my_mkstemp (tmpname);
   if (fd < 0)
-    return -1;
+    {
+      free (tmpname);
+      return -1;
+    }
 
   *name = tmpname;
   return 0;
 }
+#endif
+
+
+\f
+#ifdef HAVE_W32CE_SYSTEM
+/* Return a malloced string with the replacement value for the
+   GPGME_DEBUG envvar.  Caller must release.  Returns NULL if not
+   set.  */
+char *
+_gpgme_w32ce_get_debug_envvar (void)
+{
+  char *tmp;
+
+  tmp = read_w32_registry_string (NULL, "\\Software\\GNU\\gpgme", "debug");
+  if (tmp && !*tmp)
+    {
+      free (tmp);
+      tmp = NULL;
+    }
+  return tmp;
+}
+#endif /*HAVE_W32CE_SYSTEM*/
+
+
+/* Entry point called by the DLL loader.  */
+#ifdef DLL_EXPORT
+int WINAPI
+DllMain (HINSTANCE hinst, DWORD reason, LPVOID reserved)
+{
+  (void)reserved;
+
+  if (reason == DLL_PROCESS_ATTACH)
+    my_hmodule = hinst;
+
+  return TRUE;
+}
+#endif /*DLL_EXPORT*/