| |
1 /* |
| |
2 * gaim |
| |
3 * |
| |
4 * File: win32dep.c |
| |
5 * Date: June, 2002 |
| |
6 * Description: Windows dependant code for Gaim |
| |
7 * |
| |
8 * Copyright (C) 2002-2003, Herman Bloggs <hermanator12002@yahoo.com> |
| |
9 * |
| |
10 * This program is free software; you can redistribute it and/or modify |
| |
11 * it under the terms of the GNU General Public License as published by |
| |
12 * the Free Software Foundation; either version 2 of the License, or |
| |
13 * (at your option) any later version. |
| |
14 * |
| |
15 * This program is distributed in the hope that it will be useful, |
| |
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| |
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| |
18 * GNU General Public License for more details. |
| |
19 * |
| |
20 * You should have received a copy of the GNU General Public License |
| |
21 * along with this program; if not, write to the Free Software |
| |
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| |
23 * |
| |
24 */ |
| |
25 #define _WIN32_IE 0x500 |
| |
26 #include <windows.h> |
| |
27 #include <io.h> |
| |
28 #include <stdlib.h> |
| |
29 #include <stdio.h> |
| |
30 #include <winuser.h> |
| |
31 |
| |
32 #include <glib.h> |
| |
33 #include <glib/gstdio.h> |
| |
34 |
| |
35 #include "gaim.h" |
| |
36 #include "debug.h" |
| |
37 #include "notify.h" |
| |
38 |
| |
39 #include <libintl.h> |
| |
40 |
| |
41 #include "win32dep.h" |
| |
42 |
| |
43 /* |
| |
44 * DEFINES & MACROS |
| |
45 */ |
| |
46 #define _(x) gettext(x) |
| |
47 |
| |
48 /* |
| |
49 * DATA STRUCTS |
| |
50 */ |
| |
51 |
| |
52 /* For shfolder.dll */ |
| |
53 typedef HRESULT (CALLBACK* LPFNSHGETFOLDERPATHA)(HWND, int, HANDLE, DWORD, LPSTR); |
| |
54 typedef HRESULT (CALLBACK* LPFNSHGETFOLDERPATHW)(HWND, int, HANDLE, DWORD, LPWSTR); |
| |
55 |
| |
56 /* |
| |
57 * LOCALS |
| |
58 */ |
| |
59 static char *app_data_dir, *install_dir, *lib_dir, *locale_dir; |
| |
60 |
| |
61 /* |
| |
62 * GLOBALS |
| |
63 */ |
| |
64 HINSTANCE libgaimdll_hInstance = 0; |
| |
65 |
| |
66 /* |
| |
67 * PROTOS |
| |
68 */ |
| |
69 |
| |
70 FARPROC wgaim_find_and_loadproc(char*, char*); |
| |
71 char* wgaim_data_dir(void); |
| |
72 |
| |
73 /* |
| |
74 * STATIC CODE |
| |
75 */ |
| |
76 |
| |
77 static void wgaim_debug_print(GaimDebugLevel level, const char *category, const char *format, va_list args) { |
| |
78 char *str = NULL; |
| |
79 if (args != NULL) { |
| |
80 str = g_strdup_vprintf(format, args); |
| |
81 } else { |
| |
82 str = g_strdup(format); |
| |
83 } |
| |
84 printf("%s%s%s", category ? category : "", category ? ": " : "", str); |
| |
85 g_free(str); |
| |
86 } |
| |
87 |
| |
88 static GaimDebugUiOps ops = { |
| |
89 wgaim_debug_print |
| |
90 }; |
| |
91 |
| |
92 /* |
| |
93 * PUBLIC CODE |
| |
94 */ |
| |
95 |
| |
96 /* Escape windows dir separators. This is needed when paths are saved, |
| |
97 and on being read back have their '\' chars used as an escape char. |
| |
98 Returns an allocated string which needs to be freed. |
| |
99 */ |
| |
100 char* wgaim_escape_dirsep(char* filename) { |
| |
101 int sepcount = 0; |
| |
102 char* ret = NULL; |
| |
103 int cnt = 0; |
| |
104 |
| |
105 ret = filename; |
| |
106 while(*ret) { |
| |
107 if(*ret == '\\') |
| |
108 sepcount++; |
| |
109 ret++; |
| |
110 } |
| |
111 ret = g_malloc0(strlen(filename) + sepcount + 1); |
| |
112 while(*filename) { |
| |
113 ret[cnt] = *filename; |
| |
114 if(*filename == '\\') |
| |
115 ret[++cnt] = '\\'; |
| |
116 filename++; |
| |
117 cnt++; |
| |
118 } |
| |
119 ret[cnt] = '\0'; |
| |
120 return ret; |
| |
121 } |
| |
122 |
| |
123 /* Determine whether the specified dll contains the specified procedure. |
| |
124 If so, load it (if not already loaded). */ |
| |
125 FARPROC wgaim_find_and_loadproc(char* dllname, char* procedure) { |
| |
126 HMODULE hmod; |
| |
127 BOOL did_load = FALSE; |
| |
128 FARPROC proc = 0; |
| |
129 |
| |
130 if(!(hmod = GetModuleHandle(dllname))) { |
| |
131 gaim_debug(GAIM_DEBUG_WARNING, "wgaim", "%s not already loaded; loading it...\n", dllname); |
| |
132 if(!(hmod = LoadLibrary(dllname))) { |
| |
133 gaim_debug(GAIM_DEBUG_ERROR, "wgaim", "Could not load: %s\n", dllname); |
| |
134 return NULL; |
| |
135 } |
| |
136 else |
| |
137 did_load = TRUE; |
| |
138 } |
| |
139 |
| |
140 if((proc = GetProcAddress(hmod, procedure))) { |
| |
141 gaim_debug(GAIM_DEBUG_INFO, "wgaim", "This version of %s contains %s\n", |
| |
142 dllname, procedure); |
| |
143 return proc; |
| |
144 } |
| |
145 else { |
| |
146 gaim_debug(GAIM_DEBUG_WARNING, "wgaim", "Function %s not found in dll %s\n", |
| |
147 procedure, dllname); |
| |
148 if(did_load) { |
| |
149 /* unload dll */ |
| |
150 FreeLibrary(hmod); |
| |
151 } |
| |
152 return NULL; |
| |
153 } |
| |
154 } |
| |
155 |
| |
156 /* Determine Gaim Paths during Runtime */ |
| |
157 |
| |
158 /* Get paths to special Windows folders. */ |
| |
159 char *wgaim_get_special_folder(int folder_type) { |
| |
160 static LPFNSHGETFOLDERPATHA MySHGetFolderPathA = NULL; |
| |
161 static LPFNSHGETFOLDERPATHW MySHGetFolderPathW = NULL; |
| |
162 char *retval = NULL; |
| |
163 |
| |
164 if (!MySHGetFolderPathW) { |
| |
165 MySHGetFolderPathW = (LPFNSHGETFOLDERPATHW) |
| |
166 wgaim_find_and_loadproc("shfolder.dll", "SHGetFolderPathW"); |
| |
167 } |
| |
168 |
| |
169 if (MySHGetFolderPathW) { |
| |
170 wchar_t utf_16_dir[MAX_PATH + 1]; |
| |
171 |
| |
172 if (SUCCEEDED(MySHGetFolderPathW(NULL, folder_type, NULL, |
| |
173 SHGFP_TYPE_CURRENT, utf_16_dir))) { |
| |
174 retval = g_utf16_to_utf8(utf_16_dir, -1, NULL, NULL, NULL); |
| |
175 } |
| |
176 } |
| |
177 |
| |
178 if (!retval) { |
| |
179 if (!MySHGetFolderPathA) { |
| |
180 MySHGetFolderPathA = (LPFNSHGETFOLDERPATHA) |
| |
181 wgaim_find_and_loadproc("shfolder.dll", "SHGetFolderPathA"); |
| |
182 } |
| |
183 if (MySHGetFolderPathA) { |
| |
184 char locale_dir[MAX_PATH + 1]; |
| |
185 |
| |
186 if (SUCCEEDED(MySHGetFolderPathA(NULL, folder_type, NULL, |
| |
187 SHGFP_TYPE_CURRENT, locale_dir))) { |
| |
188 retval = g_locale_to_utf8(locale_dir, -1, NULL, NULL, NULL); |
| |
189 } |
| |
190 } |
| |
191 } |
| |
192 |
| |
193 return retval; |
| |
194 } |
| |
195 |
| |
196 char* wgaim_install_dir(void) { |
| |
197 static gboolean initialized = FALSE; |
| |
198 |
| |
199 if (!initialized) { |
| |
200 char *tmp = NULL; |
| |
201 if (G_WIN32_HAVE_WIDECHAR_API()) { |
| |
202 wchar_t winstall_dir[MAXPATHLEN]; |
| |
203 if (GetModuleFileNameW(NULL, winstall_dir, |
| |
204 MAXPATHLEN) > 0) { |
| |
205 tmp = g_utf16_to_utf8(winstall_dir, -1, |
| |
206 NULL, NULL, NULL); |
| |
207 } |
| |
208 } else { |
| |
209 gchar cpinstall_dir[MAXPATHLEN]; |
| |
210 if (GetModuleFileNameA(NULL, cpinstall_dir, |
| |
211 MAXPATHLEN) > 0) { |
| |
212 tmp = g_locale_to_utf8(cpinstall_dir, |
| |
213 -1, NULL, NULL, NULL); |
| |
214 } |
| |
215 } |
| |
216 |
| |
217 if (tmp == NULL) { |
| |
218 tmp = g_win32_error_message(GetLastError()); |
| |
219 gaim_debug(GAIM_DEBUG_ERROR, "wgaim", |
| |
220 "GetModuleFileName error: %s\n", tmp); |
| |
221 g_free(tmp); |
| |
222 return NULL; |
| |
223 } else { |
| |
224 install_dir = g_path_get_dirname(tmp); |
| |
225 g_free(tmp); |
| |
226 initialized = TRUE; |
| |
227 } |
| |
228 } |
| |
229 |
| |
230 return install_dir; |
| |
231 } |
| |
232 |
| |
233 char* wgaim_lib_dir(void) { |
| |
234 static gboolean initialized = FALSE; |
| |
235 |
| |
236 if (!initialized) { |
| |
237 char *inst_dir = wgaim_install_dir(); |
| |
238 if (inst_dir != NULL) { |
| |
239 lib_dir = g_strdup_printf("%s" G_DIR_SEPARATOR_S "plugins", inst_dir); |
| |
240 initialized = TRUE; |
| |
241 } else { |
| |
242 return NULL; |
| |
243 } |
| |
244 } |
| |
245 |
| |
246 return lib_dir; |
| |
247 } |
| |
248 |
| |
249 char* wgaim_locale_dir(void) { |
| |
250 static gboolean initialized = FALSE; |
| |
251 |
| |
252 if (!initialized) { |
| |
253 char *inst_dir = wgaim_install_dir(); |
| |
254 if (inst_dir != NULL) { |
| |
255 locale_dir = g_strdup_printf("%s" G_DIR_SEPARATOR_S "locale", inst_dir); |
| |
256 initialized = TRUE; |
| |
257 } else { |
| |
258 return NULL; |
| |
259 } |
| |
260 } |
| |
261 |
| |
262 return locale_dir; |
| |
263 } |
| |
264 |
| |
265 char* wgaim_data_dir(void) { |
| |
266 return app_data_dir; |
| |
267 } |
| |
268 |
| |
269 /* Miscellaneous */ |
| |
270 |
| |
271 gboolean wgaim_read_reg_string(HKEY key, char* sub_key, char* val_name, LPBYTE data, LPDWORD data_len) { |
| |
272 HKEY hkey; |
| |
273 gboolean ret = FALSE; |
| |
274 |
| |
275 if(ERROR_SUCCESS == RegOpenKeyEx(key, sub_key, 0, KEY_QUERY_VALUE, |
| |
276 &hkey)) { |
| |
277 if(ERROR_SUCCESS == RegQueryValueEx(hkey, val_name, 0, NULL, |
| |
278 data, data_len)) |
| |
279 ret = TRUE; |
| |
280 RegCloseKey(key); |
| |
281 } |
| |
282 return ret; |
| |
283 } |
| |
284 |
| |
285 void wgaim_init(void) { |
| |
286 WORD wVersionRequested; |
| |
287 WSADATA wsaData; |
| |
288 const char *perlenv; |
| |
289 char *newenv; |
| |
290 |
| |
291 gaim_debug_set_ui_ops(&ops); |
| |
292 gaim_debug_info("wgaim", "wgaim_init start\n"); |
| |
293 |
| |
294 gaim_debug_info("wgaim", "Glib:%u.%u.%u\n", |
| |
295 glib_major_version, glib_minor_version, glib_micro_version); |
| |
296 |
| |
297 /* Winsock init */ |
| |
298 wVersionRequested = MAKEWORD(2, 2); |
| |
299 WSAStartup(wVersionRequested, &wsaData); |
| |
300 |
| |
301 /* Confirm that the winsock DLL supports 2.2 */ |
| |
302 /* Note that if the DLL supports versions greater than |
| |
303 2.2 in addition to 2.2, it will still return 2.2 in |
| |
304 wVersion since that is the version we requested. */ |
| |
305 if(LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) { |
| |
306 gaim_debug(GAIM_DEBUG_WARNING, "wgaim", "Could not find a usable WinSock DLL. Oh well.\n"); |
| |
307 WSACleanup(); |
| |
308 } |
| |
309 |
| |
310 /* Set Environmental Variables */ |
| |
311 /* Tell perl where to find Gaim's perl modules */ |
| |
312 perlenv = g_getenv("PERL5LIB"); |
| |
313 newenv = g_strdup_printf("PERL5LIB=%s%s%s" G_DIR_SEPARATOR_S "perlmod;", |
| |
314 perlenv ? perlenv : "", |
| |
315 perlenv ? ";" : "", |
| |
316 wgaim_install_dir()); |
| |
317 if (putenv(newenv) < 0) |
| |
318 gaim_debug(GAIM_DEBUG_WARNING, "wgaim", "putenv failed\n"); |
| |
319 g_free(newenv); |
| |
320 |
| |
321 /* Set app data dir, used by gaim_home_dir */ |
| |
322 newenv = (char*) g_getenv("GAIMHOME"); |
| |
323 if (newenv) { |
| |
324 app_data_dir = g_strdup(newenv); |
| |
325 } else { |
| |
326 app_data_dir = wgaim_get_special_folder(CSIDL_APPDATA); |
| |
327 if (!app_data_dir) { |
| |
328 app_data_dir = g_strdup("C:"); |
| |
329 } |
| |
330 } |
| |
331 |
| |
332 gaim_debug(GAIM_DEBUG_INFO, "wgaim", "Gaim settings dir: %s\n", app_data_dir); |
| |
333 |
| |
334 gaim_debug(GAIM_DEBUG_INFO, "wgaim", "wgaim_init end\n"); |
| |
335 } |
| |
336 |
| |
337 /* Windows Cleanup */ |
| |
338 |
| |
339 void wgaim_cleanup(void) { |
| |
340 gaim_debug(GAIM_DEBUG_INFO, "wgaim", "wgaim_cleanup\n"); |
| |
341 |
| |
342 /* winsock cleanup */ |
| |
343 WSACleanup(); |
| |
344 |
| |
345 g_free(app_data_dir); |
| |
346 } |
| |
347 |
| |
348 /* DLL initializer */ |
| |
349 BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved ) { |
| |
350 libgaimdll_hInstance = hinstDLL; |
| |
351 return TRUE; |
| |
352 } |