Bug 545892 - Always pass WM_NCPAINT events to the default event procedure. r=bent...
[mozilla-central.git] / xpcom / glue / nsGREGlue.cpp
blob814d7ed87e9290c46771ec4bb391160e1c6504ed
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is Mozilla Communicator.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corp.
19 * Portions created by the Initial Developer are Copyright (C) 2003
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Sean Su <ssu@netscape.com>
24 * Benjamin Smedberg <benjamin@smedbergs.us>
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
40 #include "nsXPCOMGlue.h"
42 #include "nsAutoPtr.h"
43 #include "nsINIParser.h"
44 #include "nsVersionComparator.h"
45 #include "nsXPCOMPrivate.h"
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <wchar.h>
52 #ifdef XP_WIN32
53 # include <windows.h>
54 # include <mbstring.h>
55 # include <io.h>
56 # define snprintf _snprintf
57 # define R_OK 04
58 #elif defined(XP_OS2)
59 # define INCL_DOS
60 # include <os2.h>
61 #elif defined(XP_MACOSX)
62 # include <CoreFoundation/CoreFoundation.h>
63 # include <unistd.h>
64 # include <dirent.h>
65 #elif defined(XP_UNIX)
66 # include <unistd.h>
67 # include <sys/param.h>
68 # include <dirent.h>
69 #elif defined(XP_BEOS)
70 # include <FindDirectory.h>
71 # include <Path.h>
72 # include <unistd.h>
73 # include <sys/param.h>
74 # include <OS.h>
75 # include <image.h>
76 # include <dirent.h>
77 # include <FindDirectory.h>
78 #endif
80 #include <sys/stat.h>
82 /**
83 * Like strncat, appends a buffer to another buffer. This is where the
84 * similarity ends. Firstly, the "count" here is the total size of the buffer
85 * (not the number of chars to append. Secondly, the function returns PR_FALSE
86 * if the buffer is not long enough to hold the concatenated string.
88 static PRBool safe_strncat(char *dest, const char *append, PRUint32 count)
90 char *end = dest + count - 1;
92 // skip to the end of dest
93 while (*dest)
94 ++dest;
96 while (*append && dest < end) {
97 *dest = *append;
98 ++dest, ++append;
101 *dest = '\0';
103 return *append == '\0';
106 #ifdef XP_WIN
107 static PRBool
108 CheckVersion(const PRUnichar* toCheck,
109 const GREVersionRange *versions,
110 PRUint32 versionsLength);
111 #endif
112 static PRBool
113 CheckVersion(const char* toCheck,
114 const GREVersionRange *versions,
115 PRUint32 versionsLength);
118 #if defined(XP_MACOSX)
120 static PRBool
121 GRE_FindGREFramework(const char* rootPath,
122 const GREVersionRange *versions,
123 PRUint32 versionsLength,
124 const GREProperty *properties,
125 PRUint32 propertiesLength,
126 char* buffer, PRUint32 buflen);
128 #elif defined(XP_UNIX) || defined(XP_BEOS)
130 static PRBool
131 GRE_GetPathFromConfigDir(const char* dirname,
132 const GREVersionRange *versions,
133 PRUint32 versionsLength,
134 const GREProperty *properties,
135 PRUint32 propertiesLength,
136 char* buffer, PRUint32 buflen);
138 static PRBool
139 GRE_GetPathFromConfigFile(const char* filename,
140 const GREVersionRange *versions,
141 PRUint32 versionsLength,
142 const GREProperty *properties,
143 PRUint32 propertiesLength,
144 char* buffer, PRUint32 buflen);
146 #elif defined(XP_WIN)
148 static PRBool
149 GRE_GetPathFromRegKey(HKEY aRegKey,
150 const GREVersionRange *versions,
151 PRUint32 versionsLength,
152 const GREProperty *properties,
153 PRUint32 propertiesLength,
154 char* buffer, PRUint32 buflen);
156 #endif
158 nsresult
159 GRE_GetGREPathWithProperties(const GREVersionRange *versions,
160 PRUint32 versionsLength,
161 const GREProperty *properties,
162 PRUint32 propertiesLength,
163 char *aBuffer, PRUint32 aBufLen)
165 #ifdef TARGET_XPCOM_ABI
166 // append the ABI to the properties to match only binary
167 // compatible GREs
168 static const GREProperty kExtraProperty =
169 { "abi", TARGET_XPCOM_ABI };
171 GREProperty *allProperties = new GREProperty[propertiesLength + 1];
172 if (!allProperties)
173 return NS_ERROR_OUT_OF_MEMORY;
175 for (PRUint32 i=0; i<propertiesLength; i++) {
176 allProperties[i].property = properties[i].property;
177 allProperties[i].value = properties[i].value;
179 allProperties[propertiesLength].property = kExtraProperty.property;
180 allProperties[propertiesLength].value = kExtraProperty.value;
181 PRUint32 allPropertiesLength = propertiesLength + 1;
182 #else
183 const GREProperty *allProperties = properties;
184 PRUint32 allPropertiesLength = propertiesLength;
185 #endif
187 // if GRE_HOME is in the environment, use that GRE
188 const char* env = getenv("GRE_HOME");
189 if (env && *env) {
190 char p[MAXPATHLEN];
191 snprintf(p, sizeof(p), "%s" XPCOM_FILE_PATH_SEPARATOR XPCOM_DLL, env);
192 p[sizeof(p) - 1] = '\0';
194 #if XP_UNIX
195 if (realpath(p, aBuffer))
196 return NS_OK;
197 #elif WINCE
198 if (p[0] != '\\')
200 WCHAR dir[MAX_PATH];
201 WCHAR path[MAX_PATH];
202 MultiByteToWideChar(CP_ACP, 0, p, -1, path, MAX_PATH);
203 _wfullpath(dir,path,MAX_PATH);
204 WideCharToMultiByte(CP_ACP, 0, dir, -1, aBuffer, MAX_PATH, NULL, NULL);
206 else {
207 strcpy(aBuffer, p);
209 return NS_OK;
210 #elif XP_WIN
211 if (_fullpath(aBuffer, p, aBufLen))
212 return NS_OK;
213 #elif XP_OS2
214 // realpath on OS/2 returns a unix-ized path, so re-native-ize
215 if (realpath(p, aBuffer)) {
216 for (char* ptr = strchr(aBuffer, '/'); ptr; ptr = strchr(ptr, '/'))
217 *ptr = '\\';
218 return NS_OK;
220 #elif XP_BEOS
221 BPath path;
222 status_t result;
223 result = path.SetTo(p,0,true);
224 if (result == B_OK)
226 sprintf(aBuffer, path.Path());
227 return NS_OK;
229 #else
230 // hope for the best
231 // xxxbsmedberg: other platforms should have a "make absolute" function
232 #endif
234 if (strlen(p) >= aBufLen)
235 return NS_ERROR_FILE_NAME_TOO_LONG;
237 strcpy(aBuffer, p);
239 return NS_OK;
242 // the Gecko bits that sit next to the application or in the LD_LIBRARY_PATH
243 env = getenv("USE_LOCAL_GRE");
244 if (env && *env) {
245 *aBuffer = nsnull;
246 return NS_OK;
249 #ifdef XP_MACOSX
250 aBuffer[0] = '\0';
252 // Check the bundle first, for <bundle>/Contents/Frameworks/XUL.framework/libxpcom.dylib
253 CFBundleRef appBundle = CFBundleGetMainBundle();
254 if (appBundle) {
255 CFURLRef fwurl = CFBundleCopyPrivateFrameworksURL(appBundle);
256 CFURLRef absfwurl = nsnull;
257 if (fwurl) {
258 absfwurl = CFURLCopyAbsoluteURL(fwurl);
259 CFRelease(fwurl);
262 if (absfwurl) {
263 CFURLRef xulurl =
264 CFURLCreateCopyAppendingPathComponent(NULL, absfwurl,
265 CFSTR(GRE_FRAMEWORK_NAME),
266 PR_TRUE);
268 if (xulurl) {
269 CFURLRef xpcomurl =
270 CFURLCreateCopyAppendingPathComponent(NULL, xulurl,
271 CFSTR("libxpcom.dylib"),
272 PR_FALSE);
274 if (xpcomurl) {
275 char tbuffer[MAXPATHLEN];
277 if (CFURLGetFileSystemRepresentation(xpcomurl, PR_TRUE,
278 (UInt8*) tbuffer,
279 sizeof(tbuffer)) &&
280 access(tbuffer, R_OK | X_OK) == 0) {
281 if (!realpath(tbuffer, aBuffer)) {
282 aBuffer[0] = '\0';
286 CFRelease(xpcomurl);
289 CFRelease(xulurl);
292 CFRelease(absfwurl);
296 if (aBuffer[0])
297 return NS_OK;
299 // Check ~/Library/Frameworks/XUL.framework/Versions/<version>/libxpcom.dylib
300 const char *home = getenv("HOME");
301 if (home && *home && GRE_FindGREFramework(home,
302 versions, versionsLength,
303 allProperties, allPropertiesLength,
304 aBuffer, aBufLen)) {
305 return NS_OK;
308 // Check /Library/Frameworks/XUL.framework/Versions/<version>/libxpcom.dylib
309 if (GRE_FindGREFramework("",
310 versions, versionsLength,
311 allProperties, allPropertiesLength,
312 aBuffer, aBufLen)) {
313 return NS_OK;
316 #elif defined(XP_UNIX)
317 env = getenv("MOZ_GRE_CONF");
318 if (env && GRE_GetPathFromConfigFile(env,
319 versions, versionsLength,
320 allProperties, allPropertiesLength,
321 aBuffer, aBufLen)) {
322 return NS_OK;
325 env = getenv("HOME");
326 if (env && *env) {
327 char buffer[MAXPATHLEN];
329 // Look in ~/.gre.config
331 snprintf(buffer, sizeof(buffer),
332 "%s" XPCOM_FILE_PATH_SEPARATOR GRE_CONF_NAME, env);
334 if (GRE_GetPathFromConfigFile(buffer,
335 versions, versionsLength,
336 allProperties, allPropertiesLength,
337 aBuffer, aBufLen)) {
338 return NS_OK;
341 // Look in ~/.gre.d/*.conf
343 snprintf(buffer, sizeof(buffer),
344 "%s" XPCOM_FILE_PATH_SEPARATOR GRE_USER_CONF_DIR, env);
346 if (GRE_GetPathFromConfigDir(buffer,
347 versions, versionsLength,
348 allProperties, allPropertiesLength,
349 aBuffer, aBufLen)) {
350 return NS_OK;
354 // Look for a global /etc/gre.conf file
355 if (GRE_GetPathFromConfigFile(GRE_CONF_PATH,
356 versions, versionsLength,
357 allProperties, allPropertiesLength,
358 aBuffer, aBufLen)) {
359 return NS_OK;
362 // Look for a group of config files in /etc/gre.d/
363 if (GRE_GetPathFromConfigDir(GRE_CONF_DIR,
364 versions, versionsLength,
365 allProperties, allPropertiesLength,
366 aBuffer, aBufLen)) {
367 return NS_OK;
370 #elif defined(XP_BEOS)
371 env = getenv("MOZ_GRE_CONF");
372 if (env && GRE_GetPathFromConfigFile(env,
373 versions, versionsLength,
374 allProperties, allPropertiesLength,
375 aBuffer, aBufLen)) {
376 return NS_OK;
379 char p[MAXPATHLEN];
380 if (find_directory(B_USER_SETTINGS_DIRECTORY, 0, 0, p, MAXPATHLEN)) {
381 char buffer[MAXPATHLEN];
383 // Look in B_USER_SETTINGS_DIRECTORY/gre.config
384 snprintf(buffer, sizeof(buffer),
385 "%s" XPCOM_FILE_PATH_SEPARATOR GRE_CONF_NAME, p);
387 if (GRE_GetPathFromConfigFile(buffer,
388 versions, versionsLength,
389 allProperties, allPropertiesLength,
390 aBuffer, aBufLen)) {
391 return NS_OK;
394 // Look in B_USER_SETTINGS_DIRECTORY/gre.d/*.conf
395 snprintf(buffer, sizeof(buffer),
396 "%s" XPCOM_FILE_PATH_SEPARATOR GRE_CONF_DIR, p);
398 if (GRE_GetPathFromConfigDir(buffer,
399 versions, versionsLength,
400 allProperties, allPropertiesLength,
401 aBuffer, aBufLen)) {
402 return NS_OK;
406 // Hope Zeta OS and Haiku OS multiuser versions will respect BeBook,
407 // for BeOS R5 COMMON and USER are equal
408 if (find_directory(B_COMMON_SETTINGS_DIRECTORY, 0, 0, p, MAXPATHLEN)) {
409 char buffer[MAXPATHLEN];
411 // Look for a B_COMMON_SETTINGS_DIRECTORY/gre.conf file
412 snprintf(buffer, sizeof(buffer),
413 "%s" XPCOM_FILE_PATH_SEPARATOR GRE_CONF_PATH, p);
414 if (GRE_GetPathFromConfigFile(buffer,
415 versions, versionsLength,
416 allProperties, allPropertiesLength,
417 aBuffer, aBufLen)) {
418 return NS_OK;
421 // Look for a group of config files in B_COMMON_SETTINGS_DIRECTORY/gre.d/
422 snprintf(buffer, sizeof(buffer),
423 "%s" XPCOM_FILE_PATH_SEPARATOR GRE_CONF_DIR, p);
424 if (GRE_GetPathFromConfigDir(buffer,
425 versions, versionsLength,
426 allProperties, allPropertiesLength,
427 aBuffer, aBufLen)) {
428 return NS_OK;
432 #elif defined(XP_WIN)
433 HKEY hRegKey = NULL;
435 // A couple of key points here:
436 // 1. Note the usage of the "Software\\mozilla.org\\GRE" subkey - this allows
437 // us to have multiple versions of GREs on the same machine by having
438 // subkeys such as 1.0, 1.1, 2.0 etc. under it.
439 // 2. In this sample below we're looking for the location of GRE version 1.2
440 // i.e. we're compatible with GRE 1.2 and we're trying to find it's install
441 // location.
443 // Please see http://www.mozilla.org/projects/embedding/GRE.html for
444 // more info.
446 if (::RegOpenKeyExW(HKEY_CURRENT_USER, GRE_WIN_REG_LOC, 0,
447 KEY_READ, &hRegKey) == ERROR_SUCCESS) {
448 PRBool ok = GRE_GetPathFromRegKey(hRegKey,
449 versions, versionsLength,
450 allProperties, allPropertiesLength,
451 aBuffer, aBufLen);
452 ::RegCloseKey(hRegKey);
454 if (ok)
455 return NS_OK;
458 if (::RegOpenKeyExW(HKEY_LOCAL_MACHINE, GRE_WIN_REG_LOC, 0,
459 KEY_ENUMERATE_SUB_KEYS, &hRegKey) == ERROR_SUCCESS) {
460 PRBool ok = GRE_GetPathFromRegKey(hRegKey,
461 versions, versionsLength,
462 allProperties, allPropertiesLength,
463 aBuffer, aBufLen);
464 ::RegCloseKey(hRegKey);
466 if (ok)
467 return NS_OK;
469 #endif
471 return NS_ERROR_FAILURE;
474 static PRBool
475 CheckVersion(const char* toCheck,
476 const GREVersionRange *versions,
477 PRUint32 versionsLength)
480 for (const GREVersionRange *versionsEnd = versions + versionsLength;
481 versions < versionsEnd;
482 ++versions) {
483 PRInt32 c = NS_CompareVersions(toCheck, versions->lower);
484 if (c < 0)
485 continue;
487 if (!c && !versions->lowerInclusive)
488 continue;
490 c = NS_CompareVersions(toCheck, versions->upper);
491 if (c > 0)
492 continue;
494 if (!c && !versions->upperInclusive)
495 continue;
497 return PR_TRUE;
500 return PR_FALSE;
503 #ifdef XP_WIN
505 // Allocate an array of characters using new[], converting from UTF8 to UTF-16.
506 // @note Use nsAutoArrayPtr for this result.
508 static PRUnichar*
509 ConvertUTF8toNewUTF16(const char *cstr)
511 int len = MultiByteToWideChar(CP_UTF8, 0, cstr, -1, NULL, 0);
512 WCHAR *wstr = new WCHAR[len];
513 MultiByteToWideChar(CP_UTF8, 0, cstr, -1, wstr, len);
514 return wstr;
517 typedef nsAutoArrayPtr<PRUnichar> AutoWString;
519 static PRBool
520 CheckVersion(const PRUnichar* toCheck,
521 const GREVersionRange *versions,
522 PRUint32 versionsLength)
524 for (const GREVersionRange *versionsEnd = versions + versionsLength;
525 versions < versionsEnd;
526 ++versions) {
527 AutoWString wlower(ConvertUTF8toNewUTF16(versions->lower));
528 PRInt32 c = NS_CompareVersions(toCheck, wlower);
529 if (c < 0)
530 continue;
532 if (!c && !versions->lowerInclusive)
533 continue;
535 AutoWString wupper(ConvertUTF8toNewUTF16(versions->upper));
536 c = NS_CompareVersions(toCheck, wupper);
537 if (c > 0)
538 continue;
540 if (!c && !versions->upperInclusive)
541 continue;
543 return PR_TRUE;
546 return PR_FALSE;
548 #endif
551 #ifdef XP_MACOSX
552 PRBool
553 GRE_FindGREFramework(const char* rootPath,
554 const GREVersionRange *versions,
555 PRUint32 versionsLength,
556 const GREProperty *properties,
557 PRUint32 propertiesLength,
558 char* buffer, PRUint32 buflen)
560 PRBool found = PR_FALSE;
562 snprintf(buffer, buflen,
563 "%s/Library/Frameworks/" GRE_FRAMEWORK_NAME "/Versions", rootPath);
564 DIR *dir = opendir(buffer);
565 if (dir) {
566 struct dirent *entry;
567 while (!found && (entry = readdir(dir))) {
568 if (CheckVersion(entry->d_name, versions, versionsLength)) {
569 snprintf(buffer, buflen,
570 "%s/Library/Frameworks/" GRE_FRAMEWORK_NAME
571 "/Versions/%s/" XPCOM_DLL, rootPath, entry->d_name);
572 if (access(buffer, R_OK | X_OK) == 0)
573 found = PR_TRUE;
577 closedir(dir);
580 if (found)
581 return PR_TRUE;
583 buffer[0] = '\0';
584 return PR_FALSE;
587 #elif defined(XP_UNIX) || defined(XP_BEOS)
589 static PRBool IsConfFile(const char *filename)
591 const char *dot = strrchr(filename, '.');
593 return (dot && strcmp(dot, ".conf") == 0);
596 PRBool
597 GRE_GetPathFromConfigDir(const char* dirname,
598 const GREVersionRange *versions,
599 PRUint32 versionsLength,
600 const GREProperty *properties,
601 PRUint32 propertiesLength,
602 char* buffer, PRUint32 buflen)
604 // Open the directory provided and try to read any files in that
605 // directory that end with .conf. We look for an entry that might
606 // point to the GRE that we're interested in.
607 DIR *dir = opendir(dirname);
608 if (!dir)
609 return nsnull;
611 PRBool found = PR_FALSE;
612 struct dirent *entry;
614 while (!found && (entry = readdir(dir))) {
616 // Only look for files that end in .conf
617 // IsConfFile will skip "." and ".."
618 if (!IsConfFile(entry->d_name))
619 continue;
621 char fullPath[MAXPATHLEN];
622 snprintf(fullPath, sizeof(fullPath), "%s" XPCOM_FILE_PATH_SEPARATOR "%s",
623 dirname, entry->d_name);
625 found = GRE_GetPathFromConfigFile(fullPath,
626 versions, versionsLength,
627 properties, propertiesLength,
628 buffer, buflen);
631 closedir(dir);
633 return found;
636 #define READ_BUFFER_SIZE 1024
638 struct INIClosure
640 nsINIParser *parser;
641 const GREVersionRange *versions;
642 PRUint32 versionsLength;
643 const GREProperty *properties;
644 PRUint32 propertiesLength;
645 char *pathBuffer;
646 PRUint32 buflen;
647 PRBool found;
650 static PRBool
651 CheckINIHeader(const char *aHeader, void *aClosure)
653 nsresult rv;
655 INIClosure *c = reinterpret_cast<INIClosure *>(aClosure);
657 if (!CheckVersion(aHeader, c->versions, c->versionsLength))
658 return PR_TRUE;
660 const GREProperty *properties = c->properties;
661 const GREProperty *endProperties = properties + c->propertiesLength;
662 for (; properties < endProperties; ++properties) {
663 char buffer[MAXPATHLEN];
664 rv = c->parser->GetString(aHeader, properties->property,
665 buffer, sizeof(buffer));
666 if (NS_FAILED(rv))
667 return PR_TRUE;
669 if (strcmp(buffer, properties->value))
670 return PR_TRUE;
673 rv = c->parser->GetString(aHeader, "GRE_PATH", c->pathBuffer, c->buflen);
674 if (NS_FAILED(rv))
675 return PR_TRUE;
677 if (!safe_strncat(c->pathBuffer, "/" XPCOM_DLL, c->buflen) ||
678 access(c->pathBuffer, R_OK))
679 return PR_TRUE;
681 // We found a good GRE! Stop looking.
682 c->found = PR_TRUE;
683 return PR_FALSE;
686 PRBool
687 GRE_GetPathFromConfigFile(const char* filename,
688 const GREVersionRange *versions,
689 PRUint32 versionsLength,
690 const GREProperty *properties,
691 PRUint32 propertiesLength,
692 char* pathBuffer, PRUint32 buflen)
694 nsINIParser parser;
695 nsresult rv = parser.Init(filename);
696 if (NS_FAILED(rv))
697 return PR_FALSE;
699 INIClosure c = {
700 &parser,
701 versions, versionsLength,
702 properties, propertiesLength,
703 pathBuffer, buflen,
704 PR_FALSE
707 parser.GetSections(CheckINIHeader, &c);
708 return c.found;
711 #elif defined(XP_WIN)
713 static PRBool
714 CopyWithEnvExpansion(PRUnichar* aDest, const PRUnichar* aSource, PRUint32 aBufLen,
715 DWORD aType)
717 switch (aType) {
718 case REG_SZ:
719 if (wcslen(aSource) >= aBufLen)
720 return PR_FALSE;
722 wcscpy(aDest, aSource);
723 return PR_TRUE;
725 case REG_EXPAND_SZ:
726 if (ExpandEnvironmentStringsW(aSource, aDest, aBufLen) > aBufLen)
727 return PR_FALSE;
729 return PR_TRUE;
732 // Whoops! We expected REG_SZ or REG_EXPAND_SZ, what happened here?
734 return PR_FALSE;
737 PRBool
738 GRE_GetPathFromRegKey(HKEY aRegKey,
739 const GREVersionRange *versions,
740 PRUint32 versionsLength,
741 const GREProperty *properties,
742 PRUint32 propertiesLength,
743 char* aBuffer, PRUint32 aBufLen)
745 // Formerly, GREs were registered at the registry key
746 // HKLM/Software/mozilla.org/GRE/<version> valuepair GreHome=Path.
747 // Nowadays, they are registered in any subkey of
748 // Software/mozilla.org/GRE, with the following valuepairs:
749 // Version=<version> (REG_SZ)
750 // GreHome=<path> (REG_SZ or REG_EXPAND_SZ)
751 // <Property>=<value> (REG_SZ)
753 // Additional meta-info may be available in the future, including
754 // localization info and other information which might be pertinent
755 // to selecting one GRE over another.
757 // When a GRE is being registered, it should try to register itself at
758 // HKLM/Software/mozilla.org/GRE/<Version> first, to preserve compatibility
759 // with older glue. If this key is already taken (i.e. there is more than
760 // one GRE of that version installed), it should append a unique number to
761 // the version, for example:
762 // 1.1 (already in use), 1.1_1, 1.1_2, etc...
764 DWORD i = 0;
765 PRUnichar buffer[MAXPATHLEN + 1];
767 while (PR_TRUE) {
768 PRUnichar name[MAXPATHLEN + 1];
769 DWORD nameLen = MAXPATHLEN;
770 if (::RegEnumKeyExW(aRegKey, i, name, &nameLen, NULL, NULL, NULL, NULL) !=
771 ERROR_SUCCESS) {
772 break;
775 HKEY subKey = NULL;
776 if (::RegOpenKeyExW(aRegKey, name, 0, KEY_QUERY_VALUE, &subKey) !=
777 ERROR_SUCCESS) {
778 continue;
781 PRUnichar version[40];
782 DWORD versionlen = 40;
783 PRUnichar pathbuf[MAXPATHLEN + 1];
784 DWORD pathlen;
785 DWORD pathtype;
787 PRBool ok = PR_FALSE;
789 if (::RegQueryValueExW(subKey, L"Version", NULL, NULL,
790 (BYTE*) version, &versionlen) == ERROR_SUCCESS &&
791 CheckVersion(version, versions, versionsLength)) {
793 ok = PR_TRUE;
794 const GREProperty *props = properties;
795 const GREProperty *propsEnd = properties + propertiesLength;
796 for (; ok && props < propsEnd; ++props) {
797 pathlen = MAXPATHLEN + 1;
799 AutoWString wproperty(ConvertUTF8toNewUTF16(props->property));
800 AutoWString wvalue(ConvertUTF8toNewUTF16(props->value));
801 if (::RegQueryValueExW(subKey, wproperty, NULL, &pathtype,
802 (BYTE*) pathbuf, &pathlen) != ERROR_SUCCESS ||
803 wcscmp(pathbuf, wvalue))
804 ok = PR_FALSE;
807 pathlen = sizeof(pathbuf);
808 if (ok &&
809 (!::RegQueryValueExW(subKey, L"GreHome", NULL, &pathtype,
810 (BYTE*) pathbuf, &pathlen) == ERROR_SUCCESS ||
811 !*pathbuf ||
812 !CopyWithEnvExpansion(buffer, pathbuf, MAXPATHLEN, pathtype))) {
813 ok = PR_FALSE;
815 else if (!wcsncat(buffer, L"\\" LXPCOM_DLL, aBufLen)
816 #ifdef WINCE
817 || (GetFileAttributesW(buffer) == INVALID_FILE_ATTRIBUTES)
818 #else
819 || _waccess(buffer, R_OK)
820 #endif
822 ok = PR_FALSE;
826 RegCloseKey(subKey);
828 if (ok) {
829 WideCharToMultiByte(CP_UTF8, 0, buffer, -1, aBuffer, aBufLen, NULL, NULL);
830 return PR_TRUE;
833 ++i;
836 aBuffer[0] = '\0';
838 return PR_FALSE;
840 #endif // XP_WIN