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