Mercurial > pidgin.yaz
comparison pidgin/win32/winpidgin.c @ 18521:c36b62c6e0b3
Convert portable winpidgin launcher executable to be the same binary as pidgin.exe and determine which behavior to use at runtime. Running "pidgin.exe --portable-mode" or renaming "pidgin.exe" to "pidgin-portable.exe" will cause the portable mode to be used.
author | Daniel Atallah <daniel.atallah@gmail.com> |
---|---|
date | Fri, 13 Jul 2007 18:03:45 +0000 |
parents | 850cccc126ad |
children | baf4849ec7b7 |
comparison
equal
deleted
inserted
replaced
18520:850cccc126ad | 18521:c36b62c6e0b3 |
---|---|
53 | 53 |
54 typedef int (CALLBACK* LPFNPIDGINMAIN)(HINSTANCE, int, char**); | 54 typedef int (CALLBACK* LPFNPIDGINMAIN)(HINSTANCE, int, char**); |
55 typedef void (CALLBACK* LPFNSETDLLDIRECTORY)(LPCTSTR); | 55 typedef void (CALLBACK* LPFNSETDLLDIRECTORY)(LPCTSTR); |
56 typedef BOOL (CALLBACK* LPFNATTACHCONSOLE)(DWORD); | 56 typedef BOOL (CALLBACK* LPFNATTACHCONSOLE)(DWORD); |
57 | 57 |
58 static BOOL portable_mode = FALSE; | |
59 | |
58 /* | 60 /* |
59 * PROTOTYPES | 61 * PROTOTYPES |
60 */ | 62 */ |
61 static LPFNPIDGINMAIN pidgin_main = NULL; | 63 static LPFNPIDGINMAIN pidgin_main = NULL; |
62 static LPFNSETDLLDIRECTORY MySetDllDirectory = NULL; | 64 static LPFNSETDLLDIRECTORY MySetDllDirectory = NULL; |
104 } | 106 } |
105 | 107 |
106 return ret; | 108 return ret; |
107 } | 109 } |
108 | 110 |
109 static void dll_prep() { | 111 static void common_dll_prep(const char *path) { |
110 char path[MAX_PATH + 1]; | |
111 HMODULE hmod; | 112 HMODULE hmod; |
112 HKEY hkey; | 113 HKEY hkey; |
113 #ifdef PORTABLE | 114 |
114 /* We assume that GTK+ is installed under \\path\to\Pidgin\..\GTK | |
115 * First we find \\path\to | |
116 */ | |
117 if (GetModuleFileName(NULL, path, MAX_PATH) != 0) { | |
118 char *tmp = path; | |
119 char *prev = NULL; | |
120 char *prev2 = NULL; | |
121 | |
122 while ((tmp = strchr(tmp, '\\'))) { | |
123 prev2 = prev; | |
124 prev = tmp; | |
125 tmp++; | |
126 } | |
127 | |
128 if (prev2) { | |
129 prev2[0] = '\0'; | |
130 } | |
131 } else { | |
132 printf("Unable to determine current executable path. \n" | |
133 "This will prevent the settings dir from being set.\n" | |
134 "Assuming GTK+ is in the PATH.\n"); | |
135 } | |
136 | |
137 if (path) { | |
138 /* Set up the settings dir base to be \\path\to | |
139 * The actual settings dir will be \\path\to\.purple */ | |
140 char settingsdir[strlen(path) + strlen("PURPLEHOME=") + 1]; | |
141 char aspelldir[strlen(path) + strlen("PIDGIN_ASPELL_DIR=\\Aspell\\bin") + 1]; | |
142 | |
143 snprintf(settingsdir, sizeof(settingsdir), "PURPLEHOME=%s", path); | |
144 printf("Setting settings dir: %s\n", settingsdir); | |
145 putenv(settingsdir); | |
146 | |
147 snprintf(aspelldir, sizeof(aspelldir), "PIDGIN_ASPELL_DIR=%s\\Aspell\\bin", path); | |
148 printf("%s\n", aspelldir); | |
149 putenv(aspelldir); | |
150 | |
151 /* set the GTK+ path to be \\path\to\GTK\bin */ | |
152 strcat(path, "\\GTK\\bin"); | |
153 } else | |
154 return; | |
155 #else /* PORTABLE */ | |
156 char gtkpath[MAX_PATH + 1]; | |
157 DWORD plen; | |
158 | |
159 plen = sizeof(gtkpath); | |
160 hkey = HKEY_CURRENT_USER; | |
161 if (!read_reg_string(hkey, "SOFTWARE\\GTK\\2.0", "Path", | |
162 (LPBYTE) >kpath, &plen)) { | |
163 hkey = HKEY_LOCAL_MACHINE; | |
164 if (!read_reg_string(hkey, "SOFTWARE\\GTK\\2.0", "Path", | |
165 (LPBYTE) >kpath, &plen)) { | |
166 printf("GTK+ Path Registry Key not found. " | |
167 "Assuming GTK+ is in the PATH.\n"); | |
168 return; | |
169 } | |
170 } | |
171 | |
172 /* this value is replaced during a successful RegQueryValueEx() */ | |
173 plen = sizeof(path); | |
174 /* Determine GTK+ dll path .. */ | |
175 if (!read_reg_string(hkey, "SOFTWARE\\GTK\\2.0", "DllPath", | |
176 (LPBYTE) &path, &plen)) { | |
177 strcpy(path, gtkpath); | |
178 strcat(path, "\\bin"); | |
179 } | |
180 #endif | |
181 printf("GTK+ path found: %s\n", path); | 115 printf("GTK+ path found: %s\n", path); |
182 | 116 |
183 if ((hmod = GetModuleHandle("kernel32.dll"))) { | 117 if ((hmod = GetModuleHandle("kernel32.dll"))) { |
184 MySetDllDirectory = (LPFNSETDLLDIRECTORY) GetProcAddress( | 118 MySetDllDirectory = (LPFNSETDLLDIRECTORY) GetProcAddress( |
185 hmod, "SetDllDirectoryA"); | 119 hmod, "SetDllDirectoryA"); |
245 (UINT) GetLastError()); | 179 (UINT) GetLastError()); |
246 } else | 180 } else |
247 printf("SafeDllSearchMode is set to 0\n"); | 181 printf("SafeDllSearchMode is set to 0\n"); |
248 }/*end else*/ | 182 }/*end else*/ |
249 } | 183 } |
184 } | |
185 | |
186 static void portable_mode_dll_prep(const char *pidgin_dir) { | |
187 /* need to be able to fit MAX_PATH + "PIDGIN_ASPELL_DIR=\\Aspell\\bin" in path2 */ | |
188 char path[MAX_PATH + 1]; | |
189 char path2[MAX_PATH + 33]; | |
190 const char *prev = NULL; | |
191 | |
192 /* We assume that GTK+ is installed under \\path\to\Pidgin\..\GTK | |
193 * First we find \\path\to | |
194 */ | |
195 if (*pidgin_dir) { | |
196 /* pidgin_dir points to \\path\to\Pidgin */ | |
197 const char *tmp = pidgin_dir; | |
198 | |
199 while ((tmp = strchr(tmp, '\\'))) { | |
200 prev = tmp; | |
201 tmp++; | |
202 } | |
203 } | |
204 | |
205 if (prev) { | |
206 int cnt = (prev - pidgin_dir); | |
207 strncpy(path, pidgin_dir, cnt); | |
208 path[cnt] = '\0'; | |
209 } else { | |
210 printf("Unable to determine current executable path. \n" | |
211 "This will prevent the settings dir from being set.\n" | |
212 "Assuming GTK+ is in the PATH.\n"); | |
213 return; | |
214 } | |
215 | |
216 | |
217 /* Set up the settings dir base to be \\path\to | |
218 * The actual settings dir will be \\path\to\.purple */ | |
219 snprintf(path2, sizeof(path2), "PURPLEHOME=%s", path); | |
220 printf("Setting settings dir: %s\n", path2); | |
221 putenv(path2); | |
222 | |
223 snprintf(path2, sizeof(path2), "PIDGIN_ASPELL_DIR=%s\\Aspell\\bin", path); | |
224 printf("%s\n", path2); | |
225 putenv(path2); | |
226 | |
227 /* set the GTK+ path to be \\path\to\GTK\bin */ | |
228 strcat(path, "\\GTK\\bin"); | |
229 | |
230 common_dll_prep(path); | |
231 } | |
232 | |
233 static void dll_prep() { | |
234 char path[MAX_PATH + 1]; | |
235 HKEY hkey; | |
236 char gtkpath[MAX_PATH + 1]; | |
237 DWORD plen; | |
238 | |
239 plen = sizeof(gtkpath); | |
240 hkey = HKEY_CURRENT_USER; | |
241 if (!read_reg_string(hkey, "SOFTWARE\\GTK\\2.0", "Path", | |
242 (LPBYTE) >kpath, &plen)) { | |
243 hkey = HKEY_LOCAL_MACHINE; | |
244 if (!read_reg_string(hkey, "SOFTWARE\\GTK\\2.0", "Path", | |
245 (LPBYTE) >kpath, &plen)) { | |
246 printf("GTK+ Path Registry Key not found. " | |
247 "Assuming GTK+ is in the PATH.\n"); | |
248 return; | |
249 } | |
250 } | |
251 | |
252 /* this value is replaced during a successful RegQueryValueEx() */ | |
253 plen = sizeof(path); | |
254 /* Determine GTK+ dll path .. */ | |
255 if (!read_reg_string(hkey, "SOFTWARE\\GTK\\2.0", "DllPath", | |
256 (LPBYTE) &path, &plen)) { | |
257 strcpy(path, gtkpath); | |
258 strcat(path, "\\bin"); | |
259 } | |
260 | |
261 common_dll_prep(path); | |
250 } | 262 } |
251 | 263 |
252 static char* winpidgin_lcid_to_posix(LCID lcid) { | 264 static char* winpidgin_lcid_to_posix(LCID lcid) { |
253 char *posix = NULL; | 265 char *posix = NULL; |
254 int lang_id = PRIMARYLANGID(lcid); | 266 int lang_id = PRIMARYLANGID(lcid); |
396 - Use default user locale | 408 - Use default user locale |
397 */ | 409 */ |
398 static const char *winpidgin_get_locale() { | 410 static const char *winpidgin_get_locale() { |
399 const char *locale = NULL; | 411 const char *locale = NULL; |
400 LCID lcid; | 412 LCID lcid; |
401 #ifndef PORTABLE | |
402 char data[10]; | 413 char data[10]; |
403 DWORD datalen = 10; | 414 DWORD datalen = 10; |
404 #endif | |
405 | 415 |
406 /* Check if user set PIDGINLANG env var */ | 416 /* Check if user set PIDGINLANG env var */ |
407 if ((locale = getenv("PIDGINLANG"))) | 417 if ((locale = getenv("PIDGINLANG"))) |
408 return locale; | 418 return locale; |
409 | 419 |
410 #ifndef PORTABLE | 420 if (!portable_mode && read_reg_string(HKEY_CURRENT_USER, "SOFTWARE\\pidgin", |
411 if (read_reg_string(HKEY_CURRENT_USER, "SOFTWARE\\pidgin", | |
412 "Installer Language", (LPBYTE) &data, &datalen)) { | 421 "Installer Language", (LPBYTE) &data, &datalen)) { |
413 if ((locale = winpidgin_lcid_to_posix(atoi(data)))) | 422 if ((locale = winpidgin_lcid_to_posix(atoi(data)))) |
414 return locale; | 423 return locale; |
415 } | 424 } |
416 #endif | |
417 | 425 |
418 lcid = GetUserDefaultLCID(); | 426 lcid = GetUserDefaultLCID(); |
419 if ((locale = winpidgin_lcid_to_posix(lcid))) | 427 if ((locale = winpidgin_lcid_to_posix(lcid))) |
420 return locale; | 428 return locale; |
421 | 429 |
523 | 531 |
524 int _stdcall | 532 int _stdcall |
525 WinMain (struct HINSTANCE__ *hInstance, struct HINSTANCE__ *hPrevInstance, | 533 WinMain (struct HINSTANCE__ *hInstance, struct HINSTANCE__ *hPrevInstance, |
526 char *lpszCmdLine, int nCmdShow) { | 534 char *lpszCmdLine, int nCmdShow) { |
527 char errbuf[512]; | 535 char errbuf[512]; |
528 char pidgindir[MAX_PATH]; | 536 char pidgin_dir[MAX_PATH]; |
537 char exe_name[MAX_PATH]; | |
529 HMODULE hmod; | 538 HMODULE hmod; |
530 char *tmp; | 539 char *tmp; |
531 | 540 |
532 /* If debug or help or version flag used, create console for output */ | 541 /* If debug or help or version flag used, create console for output */ |
533 if (strstr(lpszCmdLine, "-d") || strstr(lpszCmdLine, "-h") || strstr(lpszCmdLine, "-v")) { | 542 if (strstr(lpszCmdLine, "-d") || strstr(lpszCmdLine, "-h") || strstr(lpszCmdLine, "-v")) { |
553 handle_protocol(tmp); | 562 handle_protocol(tmp); |
554 return 0; | 563 return 0; |
555 } | 564 } |
556 | 565 |
557 /* Load exception handler if we have it */ | 566 /* Load exception handler if we have it */ |
558 if (GetModuleFileName(NULL, pidgindir, MAX_PATH) != 0) { | 567 if (GetModuleFileName(NULL, pidgin_dir, MAX_PATH) != 0) { |
559 char *prev = NULL; | 568 char *prev = NULL; |
560 tmp = pidgindir; | 569 tmp = pidgin_dir; |
561 | 570 |
571 /* primitive dirname() */ | |
562 while ((tmp = strchr(tmp, '\\'))) { | 572 while ((tmp = strchr(tmp, '\\'))) { |
563 prev = tmp; | 573 prev = tmp; |
564 tmp++; | 574 tmp++; |
565 } | 575 } |
566 | 576 |
567 if (prev) { | 577 if (prev) { |
568 prev[0] = '\0'; | 578 prev[0] = '\0'; |
569 strcat(pidgindir, "\\exchndl.dll"); | 579 |
570 if (LoadLibrary(pidgindir)) | 580 /* prev++ will now point to the executable file name */ |
581 strcpy(exe_name, prev + 1); | |
582 | |
583 strcat(pidgin_dir, "\\exchndl.dll"); | |
584 if (LoadLibrary(pidgin_dir)) | |
571 printf("Loaded exchndl.dll\n"); | 585 printf("Loaded exchndl.dll\n"); |
586 | |
587 prev[0] = '\0'; | |
572 } | 588 } |
573 } else { | 589 } else { |
574 DWORD dw = GetLastError(); | 590 DWORD dw = GetLastError(); |
575 const char *err_msg = get_win32_error_message(dw); | 591 const char *err_msg = get_win32_error_message(dw); |
576 snprintf(errbuf, 512, | 592 snprintf(errbuf, 512, |
577 "Error getting module filename.\nError: (%u) %s", | 593 "Error getting module filename.\nError: (%u) %s", |
578 (UINT) dw, err_msg); | 594 (UINT) dw, err_msg); |
579 printf("%s", errbuf); | 595 printf("%s", errbuf); |
580 MessageBox(NULL, errbuf, NULL, MB_OK | MB_TOPMOST); | 596 MessageBox(NULL, errbuf, NULL, MB_OK | MB_TOPMOST); |
581 } | 597 pidgin_dir[0] = '\0'; |
582 | 598 } |
583 #ifndef PORTABLE | 599 |
584 if (!getenv("PIDGIN_NO_DLL_CHECK")) | 600 /* Determine if we're running in portable mode */ |
585 #endif | 601 if (strstr(lpszCmdLine, "--portable-mode") |
602 || (exe_name != NULL && strstr(exe_name, "-portable.exe"))) { | |
603 printf("Running in PORTABLE mode.\n"); | |
604 portable_mode = TRUE; | |
605 } | |
606 | |
607 if (portable_mode) | |
608 portable_mode_dll_prep(pidgin_dir); | |
609 else if (!getenv("PIDGIN_NO_DLL_CHECK")) | |
586 dll_prep(); | 610 dll_prep(); |
587 | 611 |
588 winpidgin_set_locale(); | 612 winpidgin_set_locale(); |
589 /* If help, version or multiple flag used, do not check Mutex */ | 613 /* If help, version or multiple flag used, do not check Mutex */ |
590 if (!strstr(lpszCmdLine, "-h") && !strstr(lpszCmdLine, "-v") && !strstr(lpszCmdLine, "-m")) | 614 if (!strstr(lpszCmdLine, "-h") && !strstr(lpszCmdLine, "-v") && !strstr(lpszCmdLine, "-m")) |
591 if (!getenv("PIDGIN_MULTI_INST") && !winpidgin_set_running()) | 615 if (!getenv("PIDGIN_MULTI_INST") && !winpidgin_set_running()) |
592 return 0; | 616 return 0; |
593 | 617 |
594 /* Now we are ready for Pidgin .. */ | 618 /* Now we are ready for Pidgin .. */ |
595 if ((hmod = LoadLibrary("pidgin.dll"))) { | 619 if ((hmod = LoadLibrary("pidgin.dll"))) |
596 pidgin_main = (LPFNPIDGINMAIN) GetProcAddress(hmod, "pidgin_main"); | 620 pidgin_main = (LPFNPIDGINMAIN) GetProcAddress(hmod, "pidgin_main"); |
597 } | |
598 | 621 |
599 if (!pidgin_main) { | 622 if (!pidgin_main) { |
600 DWORD dw = GetLastError(); | 623 DWORD dw = GetLastError(); |
601 BOOL mod_not_found = (dw == ERROR_MOD_NOT_FOUND || dw == ERROR_DLL_NOT_FOUND); | 624 BOOL mod_not_found = (dw == ERROR_MOD_NOT_FOUND || dw == ERROR_DLL_NOT_FOUND); |
602 const char *err_msg = get_win32_error_message(dw); | 625 const char *err_msg = get_win32_error_message(dw); |