diff --git a/src/w32-util.c b/src/w32-util.c index a90f4056..27dc5bcc 100644 --- a/src/w32-util.c +++ b/src/w32-util.c @@ -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 . + **/ #ifdef HAVE_CONFIG_H #include @@ -75,6 +74,12 @@ 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; + #ifdef HAVE_ALLOW_SET_FOREGROUND_WINDOW @@ -112,6 +117,39 @@ dlclose (void * hd) } #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; +} + + void _gpgme_allow_set_foreground_window (pid_t pid) { @@ -270,51 +308,53 @@ read_w32_registry_string (const char *root, const char *dir, const char *name) } -#if 0 -static char * -find_program_in_registry (const char *name) +/* 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) { - char *program = NULL; + static char *inst_dir; - program = read_w32_registry_string (NULL, "Software\\GNU\\GnuPG", name); - if (program) + LOCK (get_path_lock); + if (!inst_dir) { - int i; + wchar_t *moddir; - 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] = '\\'; - } + moddir = malloc ((MAX_PATH+5) * sizeof *moddir); + if (moddir) + { + if (!GetModuleFileNameW (my_hmodule, moddir, MAX_PATH)) + *moddir = 0; + if (!*moddir) + gpg_err_set_errno (ENOENT); + else + { + inst_dir = wchar_to_utf8 (moddir); + if (inst_dir) + { + char *p = strrchr (inst_dir, '\\'); + if (p) + *p = 0; + } + } + free (moddir); + } } - 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) + result = malloc (strlen (dir) + 1 + strlen (name) + 1); + if (!result) return NULL; - result = malloc (strlen (tmp) + 1 + strlen (name) + 1); - if (!result) - { - free (tmp); - return NULL; - } - - strcpy (stpcpy (stpcpy (result, tmp), "\\"), name); - free (tmp); + strcpy (stpcpy (stpcpy (result, dir), "\\"), name); if (access (result, F_OK)) { free (result); @@ -325,6 +365,40 @@ find_program_in_inst_dir (const char *name) } +static char * +find_program_in_inst_dir (const char *inst_dir, const char *name) +{ + char *result; + char *dir; + + /* If an installation directory has been passed, this overrides a + location given bu the registry. The idea here is that we prefer + a a program installed alongside with gpgme. We don't want the + registry to override this to have a better isolation of an gpgme + aware applications for other effects. Note that the "Install + Directory" registry item has been used for ages in Gpg4win and + earlier GnuPG windows installers. It is technically not anymore + required. */ + if (inst_dir) + { + result = find_program_in_dir (inst_dir, name); + if (result) + return result; + } + + dir = read_w32_registry_string ("HKEY_LOCAL_MACHINE", + "Software\\GNU\\GnuPG", + "Install Directory"); + if (dir) + { + result = find_program_in_dir (dir, name); + free (dir); + return result; + } + return NULL; +} + + static char * find_program_at_standard_place (const char *name) { @@ -353,14 +427,12 @@ const char * _gpgme_get_gpg_path (void) { static char *gpg_program; + const char *inst_dir; + inst_dir = _gpgme_get_inst_dir (); 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"); + gpg_program = find_program_in_inst_dir (inst_dir, "gpg.exe"); if (!gpg_program) gpg_program = find_program_at_standard_place ("GNU\\GnuPG\\gpg.exe"); UNLOCK (get_path_lock); @@ -372,14 +444,12 @@ const char * _gpgme_get_gpgsm_path (void) { static char *gpgsm_program; + const char *inst_dir; + inst_dir = _gpgme_get_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"); + gpgsm_program = find_program_in_inst_dir (inst_dir, "gpgsm.exe"); if (!gpgsm_program) gpgsm_program = find_program_at_standard_place ("GNU\\GnuPG\\gpgsm.exe"); UNLOCK (get_path_lock); @@ -391,14 +461,12 @@ const char * _gpgme_get_gpgconf_path (void) { static char *gpgconf_program; + const char *inst_dir; + inst_dir = _gpgme_get_inst_dir (); 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"); + gpgconf_program = find_program_in_inst_dir (inst_dir, "gpgconf.exe"); if (!gpgconf_program) gpgconf_program = find_program_at_standard_place ("GNU\\GnuPG\\gpgconf.exe"); @@ -411,14 +479,12 @@ const char * _gpgme_get_g13_path (void) { static char *g13_program; + const char *inst_dir; + inst_dir = _gpgme_get_inst_dir (); LOCK (get_path_lock); -#if 0 if (!g13_program) - g13_program = find_program_in_registry ("g13Program"); -#endif - if (!g13_program) - g13_program = find_program_in_inst_dir ("g13.exe"); + g13_program = find_program_in_inst_dir (inst_dir, "g13.exe"); if (!g13_program) g13_program = find_program_at_standard_place ("GNU\\GnuPG\\g13.exe"); UNLOCK (get_path_lock); @@ -453,10 +519,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"); + w32spawn_program = find_program_in_inst_dir (inst_dir,"gpgme-w32spawn.exe"); if (!w32spawn_program) w32spawn_program = find_program_at_standard_place ("GNU\\GnuPG\\gpgme-w32spawn.exe"); @@ -641,3 +709,18 @@ _gpgme_w32ce_get_debug_envvar (void) 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*/