pidgin/win32/winpidgin.c

changeset 39078
bbaab5d6a8d5
parent 39077
1dfbc870c461
child 39079
f77c547e07c6
equal deleted inserted replaced
39077:1dfbc870c461 39078:bbaab5d6a8d5
34 #include <string.h> 34 #include <string.h>
35 #include <stdio.h> 35 #include <stdio.h>
36 #include <sys/types.h> 36 #include <sys/types.h>
37 #include <sys/stat.h> 37 #include <sys/stat.h>
38 38
39 #ifndef IS_WIN32_CROSS_COMPILED
40 typedef int (__cdecl* LPFNPIDGINMAIN)(HINSTANCE, int, char**); 39 typedef int (__cdecl* LPFNPIDGINMAIN)(HINSTANCE, int, char**);
41 #endif 40 typedef BOOL (WINAPI* LPFNSETDLLDIRECTORY)(LPCWSTR);
42 typedef void (WINAPI* LPFNSETDLLDIRECTORY)(LPCWSTR);
43 typedef BOOL (WINAPI* LPFNATTACHCONSOLE)(DWORD); 41 typedef BOOL (WINAPI* LPFNATTACHCONSOLE)(DWORD);
44 typedef BOOL (WINAPI* LPFNSETPROCESSDEPPOLICY)(DWORD); 42 typedef BOOL (WINAPI* LPFNSETPROCESSDEPPOLICY)(DWORD);
45 43
46 static BOOL portable_mode = FALSE; 44 static BOOL portable_mode = FALSE;
47 45
48 /* 46 /*
49 * PROTOTYPES 47 * PROTOTYPES
50 */ 48 */
51 #ifdef IS_WIN32_CROSS_COMPILED
52 int __cdecl pidgin_main(HINSTANCE hint, int argc, char *argv[]);
53 #else
54 static LPFNPIDGINMAIN pidgin_main = NULL; 49 static LPFNPIDGINMAIN pidgin_main = NULL;
55 #endif
56 static LPFNSETDLLDIRECTORY MySetDllDirectory = NULL;
57 50
58 static const wchar_t *get_win32_error_message(DWORD err) { 51 static const wchar_t *get_win32_error_message(DWORD err) {
59 static wchar_t err_msg[512]; 52 static wchar_t err_msg[512];
60 53
61 FormatMessageW( 54 FormatMessageW(
65 (LPWSTR) &err_msg, sizeof(err_msg) / sizeof(wchar_t), NULL); 58 (LPWSTR) &err_msg, sizeof(err_msg) / sizeof(wchar_t), NULL);
66 59
67 return err_msg; 60 return err_msg;
68 } 61 }
69 62
70 static BOOL reg_value_exists(HKEY key, wchar_t *sub_key, wchar_t *val_name) {
71 HKEY hkey;
72 LONG retv;
73 DWORD index;
74 wchar_t name_buffer[100];
75 BOOL exists = FALSE;
76
77 if (sub_key == NULL || val_name == NULL)
78 return FALSE;
79
80 retv = RegOpenKeyExW(key, sub_key, 0, KEY_ENUMERATE_SUB_KEYS, &hkey);
81 if (retv != ERROR_SUCCESS)
82 return FALSE;
83
84 if (val_name[0] == L'\0') {
85 RegCloseKey(hkey);
86 return TRUE;
87 }
88
89 index = 0;
90 while (TRUE)
91 {
92 DWORD name_size = sizeof(name_buffer);
93 retv = RegEnumValueW(hkey, index++, name_buffer, &name_size,
94 NULL, NULL, NULL, NULL);
95 if (retv != ERROR_SUCCESS)
96 break;
97 name_size /= sizeof(wchar_t);
98 if (wcsncmp(name_buffer, val_name, name_size) == 0) {
99 exists = TRUE;
100 break;
101 }
102 }
103
104 RegCloseKey(hkey);
105 return exists;
106 }
107
108 static BOOL read_reg_string(HKEY key, wchar_t *sub_key, wchar_t *val_name, LPBYTE data, LPDWORD data_len) {
109 HKEY hkey;
110 BOOL ret = FALSE;
111 LONG retv;
112
113 if (ERROR_SUCCESS == (retv = RegOpenKeyExW(key, sub_key, 0,
114 KEY_QUERY_VALUE, &hkey))) {
115 if (ERROR_SUCCESS == (retv = RegQueryValueExW(hkey, val_name,
116 NULL, NULL, data, data_len)))
117 ret = TRUE;
118 else {
119 const wchar_t *err_msg = get_win32_error_message(retv);
120
121 wprintf(L"Could not read reg key '%s' subkey '%s' value: '%s'.\nMessage: (%ld) %s\n",
122 (key == HKEY_LOCAL_MACHINE) ? L"HKLM"
123 : ((key == HKEY_CURRENT_USER) ? L"HKCU" : L"???"),
124 sub_key, val_name, retv, err_msg);
125 }
126 RegCloseKey(hkey);
127 }
128 else {
129 wchar_t szBuf[80];
130
131 FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, retv, 0,
132 (LPWSTR) &szBuf, sizeof(szBuf) / sizeof(wchar_t), NULL);
133 wprintf(L"Could not open reg subkey: %s\nError: (%ld) %s\n",
134 sub_key, retv, szBuf);
135 }
136
137 return ret;
138 }
139
140 static BOOL check_for_gtk(const wchar_t *path) {
141 struct _stat stat_buf;
142 wchar_t test_path[MAX_PATH + 1];
143
144 _snwprintf(test_path, sizeof(test_path) / sizeof(wchar_t),
145 L"%s\\libgtk-win32-2.0-0.dll", path);
146 test_path[sizeof(test_path) / sizeof(wchar_t) - 1] = L'\0';
147
148 return (_wstat(test_path, &stat_buf) == 0);
149 }
150
151 static void common_dll_prep(const wchar_t *path) {
152 HMODULE hmod;
153 HKEY hkey;
154 wchar_t alt_path_buff[MAX_PATH + 1];
155 wchar_t tmp_path[MAX_PATH + 1];
156 /* Hold strlen("FS_PLUGIN_PATH=" or "GST_PLUGIN_SYSTEM_PATH") +
157 * MAX_PATH + 1
158 */
159 wchar_t set_path[MAX_PATH + 24];
160 wchar_t *fslash, *bslash;
161
162 if (!check_for_gtk(path)) {
163 const wchar_t *winpath = _wgetenv(L"PATH");
164 wchar_t *delim;
165
166 if (winpath == NULL) {
167 printf("Unable to determine GTK+ path (and PATH is not set).\n");
168 exit(-1);
169 }
170
171 path = NULL;
172 do
173 {
174 wcsncpy(alt_path_buff, winpath, MAX_PATH);
175 alt_path_buff[MAX_PATH] = L'\0';
176 delim = wcschr(alt_path_buff, L';');
177 if (delim != NULL) {
178 delim[0] = L'\0';
179 winpath = wcschr(winpath, L';') + 1;
180 }
181 if (check_for_gtk(alt_path_buff)) {
182 path = alt_path_buff;
183 break;
184 }
185 }
186 while (delim != NULL);
187
188 if (path == NULL) {
189 printf("Unable to determine GTK+ path.\n");
190 exit(-1);
191 }
192 }
193
194 wprintf(L"GTK+ path found: %s\n", path);
195
196 wcsncpy(tmp_path, path, MAX_PATH);
197 tmp_path[MAX_PATH] = L'\0';
198 bslash = wcsrchr(tmp_path, L'\\');
199 fslash = wcsrchr(tmp_path, L'/');
200 if (bslash && bslash > fslash)
201 bslash[0] = L'\0';
202 else if (fslash && fslash > bslash)
203 fslash[0] = L'\0';
204 /* tmp_path now contains \path\to\Pidgin\Gtk */
205
206 _snwprintf(set_path, sizeof(set_path) / sizeof(wchar_t),
207 L"FS_PLUGIN_PATH=%s\\lib\\farstream-0.1", tmp_path);
208 set_path[sizeof(set_path) / sizeof(wchar_t) - 1] = L'\0';
209 _wputenv(set_path);
210
211 _snwprintf(set_path, sizeof(set_path) / sizeof(wchar_t),
212 L"GST_PLUGIN_SYSTEM_PATH=%s\\lib\\gstreamer-0.10", tmp_path);
213 set_path[sizeof(set_path) / sizeof(wchar_t) - 1] = L'\0';
214 _wputenv(set_path);
215
216 _snwprintf(set_path, sizeof(set_path) / sizeof(wchar_t),
217 L"GST_PLUGIN_PATH=%s\\lib\\gstreamer-0.10", tmp_path);
218 set_path[sizeof(set_path) / sizeof(wchar_t) - 1] = L'\0';
219 _wputenv(set_path);
220
221 if ((hmod = GetModuleHandleW(L"kernel32.dll"))) {
222 MySetDllDirectory = (LPFNSETDLLDIRECTORY) GetProcAddress(
223 hmod, "SetDllDirectoryW");
224 if (!MySetDllDirectory)
225 printf("SetDllDirectory not supported\n");
226 } else
227 printf("Error getting kernel32.dll module handle\n");
228
229 /* For Windows XP SP1+ / Server 2003 we use SetDllDirectory to avoid dll hell */
230 if (MySetDllDirectory) {
231 MySetDllDirectory(path);
232 }
233
234 /* For the rest, we set the current directory and make sure
235 * SafeDllSearch is set to 0 where needed. */
236 else {
237 OSVERSIONINFOW osinfo;
238
239 printf("Setting current directory to GTK+ dll directory\n");
240 SetCurrentDirectoryW(path);
241 /* For Windows 2000 (SP3+) / WinXP (No SP):
242 * If SafeDllSearchMode is set to 1, Windows system directories are
243 * searched for dlls before the current directory. Therefore we set it
244 * to 0.
245 */
246 osinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
247 GetVersionExW(&osinfo);
248 if ((osinfo.dwMajorVersion == 5
249 && osinfo.dwMinorVersion == 0
250 && wcscmp(osinfo.szCSDVersion, L"Service Pack 3") >= 0)
251 ||
252 (osinfo.dwMajorVersion == 5
253 && osinfo.dwMinorVersion == 1
254 && wcscmp(osinfo.szCSDVersion, L"") >= 0)
255 ) {
256 DWORD regval = 1;
257 DWORD reglen = sizeof(DWORD);
258
259 printf("Using Win2k (SP3+) / WinXP (No SP)... Checking SafeDllSearch\n");
260 read_reg_string(HKEY_LOCAL_MACHINE,
261 L"System\\CurrentControlSet\\Control\\Session Manager",
262 L"SafeDllSearchMode",
263 (LPBYTE) &regval,
264 &reglen);
265
266 if (regval != 0) {
267 printf("Trying to set SafeDllSearchMode to 0\n");
268 regval = 0;
269 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
270 L"System\\CurrentControlSet\\Control\\Session Manager",
271 0, KEY_SET_VALUE, &hkey
272 ) == ERROR_SUCCESS) {
273 if (RegSetValueExW(hkey,
274 L"SafeDllSearchMode", 0,
275 REG_DWORD, (LPBYTE) &regval,
276 sizeof(DWORD)
277 ) != ERROR_SUCCESS)
278 printf("Error writing SafeDllSearchMode. Error: %u\n",
279 (UINT) GetLastError());
280 RegCloseKey(hkey);
281 } else
282 printf("Error opening Session Manager key for writing. Error: %u\n",
283 (UINT) GetLastError());
284 } else
285 printf("SafeDllSearchMode is set to 0\n");
286 }/*end else*/
287 }
288 }
289
290 #ifndef IS_WIN32_CROSS_COMPILED
291 static void dll_prep(const wchar_t *pidgin_dir) {
292 wchar_t path[MAX_PATH + 1];
293 path[0] = L'\0';
294
295 if (*pidgin_dir) {
296 _snwprintf(path, sizeof(path) / sizeof(wchar_t), L"%s\\Gtk\\bin", pidgin_dir);
297 path[sizeof(path) / sizeof(wchar_t) - 1] = L'\0';
298 }
299
300 common_dll_prep(path);
301 }
302 #endif
303
304 static void portable_mode_dll_prep(const wchar_t *pidgin_dir) { 63 static void portable_mode_dll_prep(const wchar_t *pidgin_dir) {
305 /* need to be able to fit MAX_PATH + "PURPLEHOME=" in path2 */ 64 /* need to be able to fit MAX_PATH + "PURPLEHOME=" in path2 */
306 wchar_t path[MAX_PATH + 1]; 65 wchar_t path[MAX_PATH + 1];
307 wchar_t path2[MAX_PATH + 12]; 66 wchar_t path2[MAX_PATH + 12];
308 const wchar_t *prev = NULL; 67 const wchar_t *prev = NULL;
309 68
310 /* We assume that GTK+ is installed under \\path\to\Pidgin\..\GTK 69 /* We want settings to go into \\path\to\Pidgin\'s parent directory
311 * First we find \\path\to 70 * First we find \\path\to
312 */ 71 */
313 if (*pidgin_dir) 72 if (*pidgin_dir)
314 /* pidgin_dir points to \\path\to\Pidgin */ 73 /* pidgin_dir points to \\path\to\Pidgin */
315 prev = wcsrchr(pidgin_dir, L'\\'); 74 prev = wcsrchr(pidgin_dir, L'\\');
319 wcsncpy(path, pidgin_dir, cnt); 78 wcsncpy(path, pidgin_dir, cnt);
320 path[cnt] = L'\0'; 79 path[cnt] = L'\0';
321 } else { 80 } else {
322 printf("Unable to determine current executable path. \n" 81 printf("Unable to determine current executable path. \n"
323 "This will prevent the settings dir from being set.\n"); 82 "This will prevent the settings dir from being set.\n");
324 common_dll_prep(L'\0');
325 return; 83 return;
326 } 84 }
327 85
328 /* Set $HOME so that the GTK+ settings get stored in the right place */ 86 /* Set $HOME so that the GTK+ settings get stored in the right place */
329 _snwprintf(path2, sizeof(path2) / sizeof(wchar_t), L"HOME=%s", path); 87 _snwprintf(path2, sizeof(path2) / sizeof(wchar_t), L"HOME=%s", path);
332 /* Set up the settings dir base to be \\path\to 90 /* Set up the settings dir base to be \\path\to
333 * The actual settings dir will be \\path\to\.purple */ 91 * The actual settings dir will be \\path\to\.purple */
334 _snwprintf(path2, sizeof(path2) / sizeof(wchar_t), L"PURPLEHOME=%s", path); 92 _snwprintf(path2, sizeof(path2) / sizeof(wchar_t), L"PURPLEHOME=%s", path);
335 wprintf(L"Setting settings dir: %s\n", path2); 93 wprintf(L"Setting settings dir: %s\n", path2);
336 _wputenv(path2); 94 _wputenv(path2);
337
338 _snwprintf(path2, sizeof(path2) / sizeof(wchar_t), L"%s\\Gtk\\bin",
339 pidgin_dir);
340 path2[sizeof(path2) / sizeof(wchar_t) - 1] = L'\0';
341 if (check_for_gtk(path2))
342 common_dll_prep(path2);
343 else {
344 /* set the GTK+ path to be \\path\to\GTK\bin */
345 wcscat(path, L"\\GTK\\bin");
346 common_dll_prep(path);
347 }
348 } 95 }
349 96
350 #define PIDGIN_WM_FOCUS_REQUEST (WM_APP + 13) 97 #define PIDGIN_WM_FOCUS_REQUEST (WM_APP + 13)
351 #define PIDGIN_WM_PROTOCOL_HANDLE (WM_APP + 14) 98 #define PIDGIN_WM_PROTOCOL_HANDLE (WM_APP + 14)
352 99
597 } 344 }
598 345
599 /* Restore pidgin_dir to point to where the executable is */ 346 /* Restore pidgin_dir to point to where the executable is */
600 pidgin_dir_start[0] = L'\0'; 347 pidgin_dir_start[0] = L'\0';
601 } 348 }
349
350 #ifndef USE_WIN32_FHS
351 /* Add bin/ subdirectory to DLL path */
352 if ((hmod = GetModuleHandleW(L"kernel32.dll"))) {
353 LPFNSETDLLDIRECTORY MySetDllDirectory =
354 (LPFNSETDLLDIRECTORY)
355 GetProcAddress(hmod, "SetDllDirectoryW");
356
357 if (MySetDllDirectory) {
358 wcscat(pidgin_dir, L"\\bin");
359 if (MySetDllDirectory(pidgin_dir)) {
360 wprintf(L"Added DLL directory to search path: %s\n",
361 pidgin_dir);
362 } else {
363 DWORD dw = GetLastError();
364 const wchar_t *err_msg = get_win32_error_message(dw);
365 wprintf(L"Error calling SetDllDirectory(): (%u) %s\n", dw, err_msg);
366 }
367 } else {
368 DWORD dw = GetLastError();
369 const wchar_t *err_msg = get_win32_error_message(dw);
370 wprintf(L"Error loading SetDllDirectory(): (%u) %s\n", dw, err_msg);
371 }
372
373 /* Restore pidgin_dir to point to where the executable is */
374 pidgin_dir_start[0] = L'\0';
375 } else {
376 printf("Error getting kernel32.dll handle\n");
377 }
378 #endif
602 } else { 379 } else {
603 DWORD dw = GetLastError(); 380 DWORD dw = GetLastError();
604 const wchar_t *err_msg = get_win32_error_message(dw); 381 const wchar_t *err_msg = get_win32_error_message(dw);
605 _snwprintf(errbuf, 512, 382 _snwprintf(errbuf, 512,
606 L"Error getting module filename.\nError: (%u) %s", 383 L"Error getting module filename.\nError: (%u) %s",
617 portable_mode = TRUE; 394 portable_mode = TRUE;
618 } 395 }
619 396
620 if (portable_mode) 397 if (portable_mode)
621 portable_mode_dll_prep(pidgin_dir); 398 portable_mode_dll_prep(pidgin_dir);
622 #ifndef IS_WIN32_CROSS_COMPILED
623 else if (!getenv("PIDGIN_NO_DLL_CHECK"))
624 dll_prep(pidgin_dir);
625 #endif
626 399
627 /* If help, version or multiple flag used, do not check Mutex */ 400 /* If help, version or multiple flag used, do not check Mutex */
628 if (!help && !version) 401 if (!help && !version)
629 if (!winpidgin_set_running(getenv("PIDGIN_MULTI_INST") == NULL && !multiple)) 402 if (!winpidgin_set_running(getenv("PIDGIN_MULTI_INST") == NULL && !multiple))
630 return 0; 403 return 0;
631 404
632 #ifndef IS_WIN32_CROSS_COMPILED
633 /* Now we are ready for Pidgin .. */ 405 /* Now we are ready for Pidgin .. */
634 wcscat(pidgin_dir, L"\\pidgin.dll"); 406 if ((hmod = LoadLibraryW(L"libpidgin-20.dll")))
635 if ((hmod = LoadLibraryW(pidgin_dir)))
636 pidgin_main = (LPFNPIDGINMAIN) GetProcAddress(hmod, "pidgin_main"); 407 pidgin_main = (LPFNPIDGINMAIN) GetProcAddress(hmod, "pidgin_main");
637 #endif 408
638
639 /* Restore pidgin_dir to point to where the executable is */
640 if (pidgin_dir_start)
641 pidgin_dir_start[0] = L'\0';
642
643 #ifndef IS_WIN32_CROSS_COMPILED
644 if (!pidgin_main) { 409 if (!pidgin_main) {
645 DWORD dw = GetLastError(); 410 DWORD dw = GetLastError();
646 BOOL mod_not_found = (dw == ERROR_MOD_NOT_FOUND || dw == ERROR_DLL_NOT_FOUND);
647 const wchar_t *err_msg = get_win32_error_message(dw); 411 const wchar_t *err_msg = get_win32_error_message(dw);
648 412
649 _snwprintf(errbuf, 512, L"Error loading pidgin.dll.\nError: (%u) %s%s%s", 413 _snwprintf(errbuf, 512, L"Error loading libpidgin-20.dll.\n"
650 (UINT) dw, err_msg, 414 "Error: (%u) %s", (UINT) dw, err_msg);
651 mod_not_found ? L"\n" : L"",
652 mod_not_found ? L"This probably means that GTK+ can't be found." : L"");
653 wprintf(L"%s\n", errbuf); 415 wprintf(L"%s\n", errbuf);
654 MessageBoxW(NULL, errbuf, L"Error", MB_OK | MB_TOPMOST); 416 MessageBoxW(NULL, errbuf, L"Error", MB_OK | MB_TOPMOST);
655 417
656 return 0; 418 return 0;
657 } 419 }
658 #endif
659 420
660 /* Convert argv to utf-8*/ 421 /* Convert argv to utf-8*/
661 szArglist = CommandLineToArgvW(cmdLine, &j); 422 szArglist = CommandLineToArgvW(cmdLine, &j);
662 pidgin_argc = j; 423 pidgin_argc = j;
663 pidgin_argv = malloc(pidgin_argc* sizeof(char*)); 424 pidgin_argv = malloc(pidgin_argc* sizeof(char*));

mercurial