1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 /*
19  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
20  * file for a list of people on the GTK+ Team.  See the ChangeLog
21  * files for a list of changes.  These files are distributed with
22  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
23  */
24 
25 #include "config.h"
26 
27 #include "gdk/gdk.h"
28 
29 #include "gtkprivate.h"
30 
31 #define STRICT
32 #include <windows.h>
33 #include <commctrl.h>
34 #undef STRICT
35 
36 /* In practice, resulting DLL will have manifest resource under index 2.
37  * Fall back to that value if we can't find resource index programmatically.
38  */
39 #define EMPIRIC_MANIFEST_RESOURCE_INDEX 2
40 
41 
42 static HMODULE gtk_dll;
43 
44 BOOL WINAPI
DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)45 DllMain (HINSTANCE hinstDLL,
46          DWORD     fdwReason,
47          LPVOID    lpvReserved)
48 {
49   switch (fdwReason)
50     {
51     case DLL_PROCESS_ATTACH:
52       gtk_dll = (HMODULE) hinstDLL;
53       break;
54     }
55 
56   return TRUE;
57 }
58 
59 static BOOL CALLBACK
find_first_manifest(HMODULE module_handle,LPCSTR resource_type,LPSTR resource_name,LONG_PTR user_data)60 find_first_manifest (HMODULE  module_handle,
61                      LPCSTR   resource_type,
62                      LPSTR    resource_name,
63                      LONG_PTR user_data)
64 {
65   LPSTR *result_name = (LPSTR *) user_data;
66 
67   if (resource_type == RT_MANIFEST)
68     {
69       if (IS_INTRESOURCE (resource_name))
70         *result_name = resource_name;
71       else
72         *result_name = g_strdup (resource_name);
73       return FALSE;
74     }
75   return TRUE;
76 }
77 
78 /*
79  * Grabs the first manifest it finds in libgtk3 (which is expected to be the
80  * common-controls-6.0.0.0 manifest we embedded to enable visual styles),
81  * uses it to create a process-default activation context, activates that
82  * context, loads up the library passed in @dllname, then deactivates and
83  * releases the context.
84  *
85  * In practice this is used to force system DLLs (like comdlg32) to be
86  * loaded as if the application had the same manifest as libgtk3
87  * (otherwise libgtk3 manifest only affests libgtk3 itself).
88  * This way application does not need to have a manifest or to link
89  * against comctl32.
90  *
91  * Note that loaded library handle leaks, so only use this function in
92  * g_once_init_enter (leaking once is OK, Windows will clean up after us).
93  */
94 void
_gtk_load_dll_with_libgtk3_manifest(const gchar * dll_name)95 _gtk_load_dll_with_libgtk3_manifest (const gchar *dll_name)
96 {
97   HANDLE activation_ctx_handle;
98   ACTCTXA activation_ctx_descriptor;
99   ULONG_PTR activation_cookie;
100   LPSTR resource_name;
101   BOOL activated;
102   DWORD error_code;
103 
104   resource_name = NULL;
105   EnumResourceNames (gtk_dll, RT_MANIFEST, find_first_manifest,
106                      (LONG_PTR) &resource_name);
107 
108   if (resource_name == NULL)
109     resource_name = MAKEINTRESOURCEA (EMPIRIC_MANIFEST_RESOURCE_INDEX);
110 
111   memset (&activation_ctx_descriptor, 0, sizeof (activation_ctx_descriptor));
112   activation_ctx_descriptor.cbSize = sizeof (activation_ctx_descriptor);
113   activation_ctx_descriptor.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID |
114                                       ACTCTX_FLAG_HMODULE_VALID |
115                                       ACTCTX_FLAG_SET_PROCESS_DEFAULT;
116   activation_ctx_descriptor.hModule = gtk_dll;
117   activation_ctx_descriptor.lpResourceName = resource_name;
118   activation_ctx_handle = CreateActCtx (&activation_ctx_descriptor);
119   error_code = GetLastError ();
120 
121   if (activation_ctx_handle == INVALID_HANDLE_VALUE &&
122       error_code != ERROR_SXS_PROCESS_DEFAULT_ALREADY_SET)
123     g_warning ("Failed to CreateActCtx for module %p, resource %p: %lu",
124                gtk_dll, resource_name, GetLastError ());
125   else if (error_code != ERROR_SXS_PROCESS_DEFAULT_ALREADY_SET)
126     {
127       activation_cookie = 0;
128       activated = ActivateActCtx (activation_ctx_handle, &activation_cookie);
129 
130       if (!activated)
131         g_warning ("Failed to ActivateActCtx: %lu", GetLastError ());
132 
133       LoadLibraryA (dll_name);
134 
135       if (activated && !DeactivateActCtx (0, activation_cookie))
136         g_warning ("Failed to DeactivateActCtx: %lu", GetLastError ());
137 
138       ReleaseActCtx (activation_ctx_handle);
139     }
140 
141   if (!IS_INTRESOURCE (resource_name))
142     g_free (resource_name);
143 }
144 
145 const gchar *
_gtk_get_libdir(void)146 _gtk_get_libdir (void)
147 {
148   static char *gtk_libdir = NULL;
149   if (gtk_libdir == NULL)
150     {
151       gchar *root = g_win32_get_package_installation_directory_of_module (gtk_dll);
152       gchar *slash = strrchr (root, '\\');
153       if (slash != NULL &&
154           g_ascii_strcasecmp (slash + 1, ".libs") == 0)
155         gtk_libdir = GTK_LIBDIR;
156       else
157         gtk_libdir = g_build_filename (root, "lib", NULL);
158       g_free (root);
159     }
160 
161   return gtk_libdir;
162 }
163 
164 const gchar *
_gtk_get_localedir(void)165 _gtk_get_localedir (void)
166 {
167   static char *gtk_localedir = NULL;
168   if (gtk_localedir == NULL)
169     {
170       const gchar *p;
171       gchar *root, *temp;
172 
173       /* GTK_LOCALEDIR ends in either /lib/locale or
174        * /share/locale. Scan for that slash.
175        */
176       p = GTK_LOCALEDIR + strlen (GTK_LOCALEDIR);
177       while (*--p != '/')
178         ;
179       while (*--p != '/')
180         ;
181 
182       root = g_win32_get_package_installation_directory_of_module (gtk_dll);
183       temp = g_build_filename (root, p, NULL);
184       g_free (root);
185 
186       /* gtk_localedir is passed to bindtextdomain() which isn't
187        * UTF-8-aware.
188        */
189       gtk_localedir = g_win32_locale_filename_from_utf8 (temp);
190       g_free (temp);
191     }
192   return gtk_localedir;
193 }
194 
195 const gchar *
_gtk_get_datadir(void)196 _gtk_get_datadir (void)
197 {
198   static char *gtk_datadir = NULL;
199   if (gtk_datadir == NULL)
200     {
201       gchar *root = g_win32_get_package_installation_directory_of_module (gtk_dll);
202       gtk_datadir = g_build_filename (root, "share", NULL);
203       g_free (root);
204     }
205 
206   return gtk_datadir;
207 }
208 
209 const gchar *
_gtk_get_sysconfdir(void)210 _gtk_get_sysconfdir (void)
211 {
212   static char *gtk_sysconfdir = NULL;
213   if (gtk_sysconfdir == NULL)
214     {
215       gchar *root = g_win32_get_package_installation_directory_of_module (gtk_dll);
216       gtk_sysconfdir = g_build_filename (root, "etc", NULL);
217       g_free (root);
218     }
219 
220   return gtk_sysconfdir;
221 }
222 
223 const gchar *
_gtk_get_data_prefix(void)224 _gtk_get_data_prefix (void)
225 {
226   static char *gtk_data_prefix = NULL;
227   if (gtk_data_prefix == NULL)
228     gtk_data_prefix = g_win32_get_package_installation_directory_of_module (gtk_dll);
229 
230   return gtk_data_prefix;
231 }
232