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) &gtkpath, &plen)) {
163 hkey = HKEY_LOCAL_MACHINE;
164 if (!read_reg_string(hkey, "SOFTWARE\\GTK\\2.0", "Path",
165 (LPBYTE) &gtkpath, &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) &gtkpath, &plen)) {
243 hkey = HKEY_LOCAL_MACHINE;
244 if (!read_reg_string(hkey, "SOFTWARE\\GTK\\2.0", "Path",
245 (LPBYTE) &gtkpath, &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);