4 * Copyright 1993 Miguel de Icaza
5 * Copyright 1996 Alexandre Julliard
14 #include <sys/types.h>
22 #include "wine/winbase16.h"
26 #include "debugtools.h"
30 DEFAULT_DEBUG_CHANNEL(profile);
32 typedef struct tagPROFILEKEY
36 struct tagPROFILEKEY *next;
39 typedef struct tagPROFILESECTION
42 struct tagPROFILEKEY *key;
43 struct tagPROFILESECTION *next;
50 PROFILESECTION *section;
58 #define N_CACHED_PROFILES 10
60 /* Cached profile files */
61 static PROFILE *MRUProfile[N_CACHED_PROFILES]={NULL};
63 #define CurProfile (MRUProfile[0])
65 /* wine.ini config file registry root */
66 static HKEY wine_profile_key;
68 #define PROFILE_MAX_LINE_LEN 1024
70 /* Wine profile name in $HOME directory; must begin with slash */
71 static const char PROFILE_WineIniName[] = "/.winerc";
73 /* Wine profile: the profile file being used */
74 static char PROFILE_WineIniUsed[MAX_PATHNAME_LEN] = "";
76 /* Check for comments in profile */
77 #define IS_ENTRY_COMMENT(str) ((str)[0] == ';')
79 static const WCHAR wininiW[] = { 'w','i','n','.','i','n','i',0 };
81 static CRITICAL_SECTION PROFILE_CritSect = CRITICAL_SECTION_INIT;
83 static const char hex[16] = "0123456789ABCDEF";
85 /***********************************************************************
88 * Copy the content of an entry into a buffer, removing quotes, and possibly
89 * translating environment variables.
91 static void PROFILE_CopyEntry( char *buffer, const char *value, int len,
99 if ((*value == '\'') || (*value == '\"'))
101 if (value[1] && (value[strlen(value)-1] == *value)) quote = *value++;
106 lstrcpynA( buffer, value, len );
107 if (quote && (len >= strlen(value))) buffer[strlen(buffer)-1] = '\0';
111 for (p = value; (*p && (len > 1)); *buffer++ = *p++, len-- )
113 if ((*p == '$') && (p[1] == '{'))
117 const char *p2 = strchr( p, '}' );
118 if (!p2) continue; /* ignore it */
119 lstrcpynA(env_val, p + 2, min( sizeof(env_val), (int)(p2-p)-1 ));
120 if ((env_p = getenv( env_val )) != NULL)
122 lstrcpynA( buffer, env_p, len );
123 buffer += strlen( buffer );
124 len -= strlen( buffer );
129 if (quote && (len > 1)) buffer--;
134 /***********************************************************************
137 * Save a profile tree to a file.
139 static void PROFILE_Save( FILE *file, PROFILESECTION *section )
143 for ( ; section; section = section->next)
145 if (section->name) fprintf( file, "\r\n[%s]\r\n", section->name );
146 for (key = section->key; key; key = key->next)
148 fprintf( file, "%s", key->name );
149 if (key->value) fprintf( file, "=%s", key->value );
150 fprintf( file, "\r\n" );
156 /***********************************************************************
159 * Free a profile tree.
161 static void PROFILE_Free( PROFILESECTION *section )
163 PROFILESECTION *next_section;
164 PROFILEKEY *key, *next_key;
166 for ( ; section; section = next_section)
168 if (section->name) HeapFree( GetProcessHeap(), 0, section->name );
169 for (key = section->key; key; key = next_key)
171 next_key = key->next;
172 if (key->name) HeapFree( GetProcessHeap(), 0, key->name );
173 if (key->value) HeapFree( GetProcessHeap(), 0, key->value );
174 HeapFree( GetProcessHeap(), 0, key );
176 next_section = section->next;
177 HeapFree( GetProcessHeap(), 0, section );
181 static inline int PROFILE_isspace(char c)
183 if (isspace(c)) return 1;
184 if (c=='\r' || c==0x1a) return 1;
185 /* CR and ^Z (DOS EOF) are spaces too (found on CD-ROMs) */
190 /***********************************************************************
193 * Load a profile tree from a file.
195 static PROFILESECTION *PROFILE_Load( FILE *file )
197 char buffer[PROFILE_MAX_LINE_LEN];
200 PROFILESECTION *section, *first_section;
201 PROFILESECTION **next_section;
202 PROFILEKEY *key, *prev_key, **next_key;
204 first_section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) );
205 if(first_section == NULL) return NULL;
206 first_section->name = NULL;
207 first_section->key = NULL;
208 first_section->next = NULL;
209 next_section = &first_section->next;
210 next_key = &first_section->key;
213 while (fgets( buffer, PROFILE_MAX_LINE_LEN, file ))
217 while (*p && PROFILE_isspace(*p)) p++;
218 if (*p == '[') /* section start */
220 if (!(p2 = strrchr( p, ']' )))
222 WARN("Invalid section header at line %d: '%s'\n",
229 section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) );
230 if(section == NULL) break;
231 section->name = HEAP_strdupA( GetProcessHeap(), 0, p );
233 section->next = NULL;
234 *next_section = section;
235 next_section = §ion->next;
236 next_key = §ion->key;
239 TRACE("New section: '%s'\n",section->name);
246 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
248 if ((p2 = strchr( p, '=' )) != NULL)
251 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
253 while (*p2 && PROFILE_isspace(*p2)) p2++;
256 if(*p || !prev_key || *prev_key->name)
258 key = HeapAlloc( GetProcessHeap(), 0, sizeof(*key) );
259 if(key == NULL) break;
260 key->name = HEAP_strdupA( GetProcessHeap(), 0, p );
261 key->value = p2 ? HEAP_strdupA( GetProcessHeap(), 0, p2 ) : NULL;
264 next_key = &key->next;
267 TRACE("New key: name='%s', value='%s'\n",key->name,key->value?key->value:"(none)");
270 return first_section;
273 /* convert the .winerc file to the new format */
274 static int convert_config( FILE *in, const char *output_name )
276 char buffer[PROFILE_MAX_LINE_LEN];
280 /* create the output file, only if it doesn't exist already */
281 int fd = open( output_name, O_WRONLY|O_CREAT|O_EXCL, 0666 );
282 if (fd == -1) return 0;
284 out = fdopen( fd, "w" );
285 fprintf( out, "WINE REGISTRY Version 2\n" );
286 fprintf( out, ";; All keys relative to \\\\Machine\\\\Software\\\\Wine\\\\Wine\\\\Config\n\n" );
287 while (fgets( buffer, PROFILE_MAX_LINE_LEN, in ))
289 if (buffer[strlen(buffer)-1] == '\n') buffer[strlen(buffer)-1] = 0;
291 while (*p && PROFILE_isspace(*p)) p++;
292 if (*p == '[') /* section start */
294 if ((p2 = strrchr( p, ']' )))
298 fprintf( out, "[%s]\n", p );
303 if (*p == ';' || *p == '#')
305 fprintf( out, "%s\n", p );
310 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
312 if ((p2 = strchr( p, '=' )) != NULL)
315 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
317 while (*p2 && PROFILE_isspace(*p2)) p2++;
322 fprintf( out, "\n" );
328 if (*p == '\\') fputc( '\\', out );
332 fprintf( out, "\" = \"" );
337 if (*p2 == '\\') fputc( '\\', out );
342 fprintf( out, "\"\n" );
349 /***********************************************************************
350 * PROFILE_RegistryLoad
352 * Load a profile tree from a file into a registry key.
354 static DWORD PROFILE_RegistryLoad( HKEY root, FILE *file )
358 char buffer[PROFILE_MAX_LINE_LEN];
362 while (fgets( buffer, PROFILE_MAX_LINE_LEN, file ))
366 while (*p && PROFILE_isspace(*p)) p++;
367 if (*p == '[') /* section start */
369 if (!(p2 = strrchr( p, ']' )))
371 WARN("Invalid section header at line %d: '%s'\n",
378 if (hkey) RegCloseKey( hkey );
379 if ((err = RegCreateKeyExA( root, p, 0, NULL, REG_OPTION_VOLATILE,
380 KEY_ALL_ACCESS, NULL, &hkey, NULL ))) return err;
381 TRACE("New section: '%s'\n",p);
387 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
389 if ((p2 = strchr( p, '=' )) != NULL)
392 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
394 while (*p2 && PROFILE_isspace(*p2)) p2++;
397 if (*p && hkey && !IS_ENTRY_COMMENT(p))
400 if ((err = RegSetValueExA( hkey, p, 0, REG_SZ, p2, strlen(p2)+1 )))
405 TRACE("New key: name='%s', value='%s'\n",p,p2);
408 if (hkey) RegCloseKey( hkey );
413 /***********************************************************************
414 * PROFILE_DeleteSection
416 * Delete a section from a profile tree.
418 static BOOL PROFILE_DeleteSection( PROFILESECTION **section, LPCSTR name )
422 if ((*section)->name && !strcasecmp( (*section)->name, name ))
424 PROFILESECTION *to_del = *section;
425 *section = to_del->next;
427 PROFILE_Free( to_del );
430 section = &(*section)->next;
436 /***********************************************************************
439 * Delete a key from a profile tree.
441 static BOOL PROFILE_DeleteKey( PROFILESECTION **section,
442 LPCSTR section_name, LPCSTR key_name )
446 if ((*section)->name && !strcasecmp( (*section)->name, section_name ))
448 PROFILEKEY **key = &(*section)->key;
451 if (!strcasecmp( (*key)->name, key_name ))
453 PROFILEKEY *to_del = *key;
455 if (to_del->name) HeapFree( GetProcessHeap(), 0, to_del->name );
456 if (to_del->value) HeapFree( GetProcessHeap(), 0, to_del->value);
457 HeapFree( GetProcessHeap(), 0, to_del );
463 section = &(*section)->next;
469 /***********************************************************************
470 * PROFILE_DeleteAllKeys
472 * Delete all keys from a profile tree.
474 void PROFILE_DeleteAllKeys( LPCSTR section_name)
476 PROFILESECTION **section= &CurProfile->section;
479 if ((*section)->name && !strcasecmp( (*section)->name, section_name ))
481 PROFILEKEY **key = &(*section)->key;
484 PROFILEKEY *to_del = *key;
486 if (to_del->name) HeapFree( GetProcessHeap(), 0, to_del->name );
487 if (to_del->value) HeapFree( GetProcessHeap(), 0, to_del->value);
488 HeapFree( GetProcessHeap(), 0, to_del );
489 CurProfile->changed =TRUE;
492 section = &(*section)->next;
497 /***********************************************************************
500 * Find a key in a profile tree, optionally creating it.
502 static PROFILEKEY *PROFILE_Find( PROFILESECTION **section,
503 const char *section_name,
504 const char *key_name, int create )
509 while (PROFILE_isspace(*section_name)) section_name++;
510 p = section_name + strlen(section_name) - 1;
511 while ((p > section_name) && PROFILE_isspace(*p)) p--;
512 seclen = p - section_name + 1;
514 while (PROFILE_isspace(*key_name)) key_name++;
515 p = key_name + strlen(key_name) - 1;
516 while ((p > key_name) && PROFILE_isspace(*p)) p--;
517 keylen = p - key_name + 1;
521 if ( ((*section)->name)
522 && (!(strncasecmp( (*section)->name, section_name, seclen )))
523 && (((*section)->name)[seclen] == '\0') )
525 PROFILEKEY **key = &(*section)->key;
528 if ( (!(strncasecmp( (*key)->name, key_name, keylen )))
529 && (((*key)->name)[keylen] == '\0') )
533 if (!create) return NULL;
534 *key = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY) );
535 if(*key == NULL) return NULL;
536 (*key)->name = HEAP_strdupA( GetProcessHeap(), 0, key_name );
537 (*key)->value = NULL;
541 section = &(*section)->next;
543 if (!create) return NULL;
544 *section = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILESECTION) );
545 if(*section == NULL) return NULL;
546 (*section)->name = HEAP_strdupA( GetProcessHeap(), 0, section_name );
547 (*section)->next = NULL;
548 (*section)->key = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY) );
549 if((*section)->key == NULL)
551 HeapFree(GetProcessHeap(), 0, *section);
554 (*section)->key->name = HEAP_strdupA( GetProcessHeap(), 0, key_name );
555 (*section)->key->value = NULL;
556 (*section)->key->next = NULL;
557 return (*section)->key;
561 /***********************************************************************
564 * Flush the current profile to disk if changed.
566 static BOOL PROFILE_FlushFile(void)
568 char *p, buffer[MAX_PATHNAME_LEN];
569 const char *unix_name;
575 WARN("No current profile!\n");
579 if (!CurProfile->changed || !CurProfile->dos_name) return TRUE;
580 if (!(unix_name = CurProfile->unix_name) || !(file = fopen(unix_name, "w")))
582 /* Try to create it in $HOME/.wine */
583 /* FIXME: this will need a more general solution */
584 strcpy( buffer, get_config_dir() );
585 p = buffer + strlen(buffer);
587 strcpy( p, strrchr( CurProfile->dos_name, '\\' ) + 1 );
589 file = fopen( buffer, "w" );
595 WARN("could not save profile file %s\n", CurProfile->dos_name);
599 TRACE("Saving '%s' into '%s'\n", CurProfile->dos_name, unix_name );
600 PROFILE_Save( file, CurProfile->section );
602 CurProfile->changed = FALSE;
603 if(!stat(unix_name,&buf))
604 CurProfile->mtime=buf.st_mtime;
609 /***********************************************************************
610 * PROFILE_ReleaseFile
612 * Flush the current profile to disk and remove it from the cache.
614 static void PROFILE_ReleaseFile(void)
617 PROFILE_Free( CurProfile->section );
618 if (CurProfile->dos_name) HeapFree( GetProcessHeap(), 0, CurProfile->dos_name );
619 if (CurProfile->unix_name) HeapFree( GetProcessHeap(), 0, CurProfile->unix_name );
620 if (CurProfile->filename) HeapFree( GetProcessHeap(), 0, CurProfile->filename );
621 CurProfile->changed = FALSE;
622 CurProfile->section = NULL;
623 CurProfile->dos_name = NULL;
624 CurProfile->unix_name = NULL;
625 CurProfile->filename = NULL;
626 CurProfile->mtime = 0;
630 /***********************************************************************
633 * Open a profile file, checking the cached file first.
635 static BOOL PROFILE_Open( LPCSTR filename )
637 DOS_FULL_NAME full_name;
638 char buffer[MAX_PATHNAME_LEN];
639 char *newdos_name, *p;
643 PROFILE *tempProfile;
645 /* First time around */
648 for(i=0;i<N_CACHED_PROFILES;i++)
650 MRUProfile[i]=HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILE) );
651 if(MRUProfile[i] == NULL) break;
652 MRUProfile[i]->changed=FALSE;
653 MRUProfile[i]->section=NULL;
654 MRUProfile[i]->dos_name=NULL;
655 MRUProfile[i]->unix_name=NULL;
656 MRUProfile[i]->filename=NULL;
657 MRUProfile[i]->mtime=0;
660 /* Check for a match */
662 if (strchr( filename, '/' ) || strchr( filename, '\\' ) ||
663 strchr( filename, ':' ))
665 if (!DOSFS_GetFullName( filename, FALSE, &full_name )) return FALSE;
669 GetWindowsDirectoryA( buffer, sizeof(buffer) );
670 strcat( buffer, "\\" );
671 strcat( buffer, filename );
672 if (!DOSFS_GetFullName( buffer, FALSE, &full_name )) return FALSE;
675 for(i=0;i<N_CACHED_PROFILES;i++)
677 if ((MRUProfile[i]->filename && !strcmp( filename, MRUProfile[i]->filename )) ||
678 (MRUProfile[i]->dos_name && !strcmp( full_name.short_name, MRUProfile[i]->dos_name )))
683 tempProfile=MRUProfile[i];
685 MRUProfile[j]=MRUProfile[j-1];
686 CurProfile=tempProfile;
688 if(!stat(CurProfile->unix_name,&buf) && CurProfile->mtime==buf.st_mtime)
689 TRACE("(%s): already opened (mru=%d)\n",
692 TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
698 /* Flush the old current profile */
701 /* Make the oldest profile the current one only in order to get rid of it */
702 if(i==N_CACHED_PROFILES)
704 tempProfile=MRUProfile[N_CACHED_PROFILES-1];
705 for(i=N_CACHED_PROFILES-1;i>0;i--)
706 MRUProfile[i]=MRUProfile[i-1];
707 CurProfile=tempProfile;
709 if(CurProfile->filename) PROFILE_ReleaseFile();
711 /* OK, now that CurProfile is definitely free we assign it our new file */
712 newdos_name = HEAP_strdupA( GetProcessHeap(), 0, full_name.short_name );
713 CurProfile->dos_name = newdos_name;
714 CurProfile->filename = HEAP_strdupA( GetProcessHeap(), 0, filename );
716 /* Try to open the profile file, first in $HOME/.wine */
718 /* FIXME: this will need a more general solution */
719 strcpy( buffer, get_config_dir() );
720 p = buffer + strlen(buffer);
722 strcpy( p, strrchr( newdos_name, '\\' ) + 1 );
724 if ((file = fopen( buffer, "r" )))
726 TRACE("(%s): found it in %s\n",
728 CurProfile->unix_name = HEAP_strdupA( GetProcessHeap(), 0, buffer );
733 CurProfile->unix_name = HEAP_strdupA( GetProcessHeap(), 0,
734 full_name.long_name );
735 if ((file = fopen( full_name.long_name, "r" )))
736 TRACE("(%s): found it in %s\n",
737 filename, full_name.long_name );
742 CurProfile->section = PROFILE_Load( file );
744 if(!stat(CurProfile->unix_name,&buf))
745 CurProfile->mtime=buf.st_mtime;
749 /* Does not exist yet, we will create it in PROFILE_FlushFile */
750 WARN("profile file %s not found\n", newdos_name );
756 /***********************************************************************
759 * Returns all keys of a section.
760 * If return_values is TRUE, also include the corresponding values.
762 static INT PROFILE_GetSection( PROFILESECTION *section, LPCSTR section_name,
763 LPSTR buffer, UINT len, BOOL handle_env,
768 if(!buffer) return 0;
772 if (section->name && !strcasecmp( section->name, section_name ))
775 for (key = section->key; key; key = key->next)
778 if (!*key->name) continue; /* Skip empty lines */
779 if (IS_ENTRY_COMMENT(key->name)) continue; /* Skip comments */
780 PROFILE_CopyEntry( buffer, key->name, len - 1, handle_env );
781 len -= strlen(buffer) + 1;
782 buffer += strlen(buffer) + 1;
783 if (return_values && key->value) {
785 PROFILE_CopyEntry ( buffer,
786 key->value, len - 1, handle_env );
787 len -= strlen(buffer) + 1;
788 buffer += strlen(buffer) + 1;
793 /*If either lpszSection or lpszKey is NULL and the supplied
794 destination buffer is too small to hold all the strings,
795 the last string is truncated and followed by two null characters.
796 In this case, the return value is equal to cchReturnBuffer
804 section = section->next;
806 buffer[0] = buffer[1] = '\0';
811 static INT PROFILE_GetSectionNames( LPSTR buffer, UINT len )
815 PROFILESECTION *section;
817 if(!buffer) return 0;
819 for (section = CurProfile->section; section; section = section->next)
821 l = strlen(section->name);
826 strcpy(buf, section->name);
836 /***********************************************************************
839 * Get a profile string.
841 * Tests with GetPrivateProfileString16, W95a,
842 * with filled buffer ("****...") and section "set1" and key_name "1" valid:
843 * section key_name def_val res buffer
844 * "set1" "1" "x" 43 [data]
845 * "set1" "1 " "x" 43 [data] (!)
846 * "set1" " 1 "' "x" 43 [data] (!)
847 * "set1" "" "x" 1 "x"
848 * "set1" "" "x " 1 "x" (!)
849 * "set1" "" " x " 3 " x" (!)
850 * "set1" NULL "x" 6 "1\02\03\0\0"
851 * "set1" "" "x" 1 "x"
852 * NULL "1" "x" 0 "" (!)
858 static INT PROFILE_GetString( LPCSTR section, LPCSTR key_name,
859 LPCSTR def_val, LPSTR buffer, UINT len )
861 PROFILEKEY *key = NULL;
863 if(!buffer) return 0;
865 if (!def_val) def_val = "";
866 if (key_name && key_name[0])
868 key = PROFILE_Find( &CurProfile->section, section, key_name, FALSE );
869 PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def_val,
871 TRACE("('%s','%s','%s'): returning '%s'\n",
872 section, key_name, def_val, buffer );
873 return strlen( buffer );
875 if (key_name && !(key_name[0]))
876 /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227 */
878 if (section && section[0])
879 return PROFILE_GetSection(CurProfile->section, section, buffer, len,
886 /***********************************************************************
889 * Set a profile string.
891 static BOOL PROFILE_SetString( LPCSTR section_name, LPCSTR key_name,
894 if (!key_name) /* Delete a whole section */
896 TRACE("('%s')\n", section_name);
897 CurProfile->changed |= PROFILE_DeleteSection( &CurProfile->section,
899 return TRUE; /* Even if PROFILE_DeleteSection() has failed,
900 this is not an error on application's level.*/
902 else if (!value) /* Delete a key */
904 TRACE("('%s','%s')\n",
905 section_name, key_name );
906 CurProfile->changed |= PROFILE_DeleteKey( &CurProfile->section,
907 section_name, key_name );
908 return TRUE; /* same error handling as above */
910 else /* Set the key value */
912 PROFILEKEY *key = PROFILE_Find( &CurProfile->section, section_name,
914 TRACE("('%s','%s','%s'): \n",
915 section_name, key_name, value );
916 if (!key) return FALSE;
919 /* strip the leading spaces. We can safely strip \n\r and
920 * friends too, they should not happen here anyway. */
921 while (PROFILE_isspace(*value)) value++;
923 if (!strcmp( key->value, value ))
925 TRACE(" no change needed\n" );
926 return TRUE; /* No change needed */
928 TRACE(" replacing '%s'\n", key->value );
929 HeapFree( GetProcessHeap(), 0, key->value );
931 else TRACE(" creating key\n" );
932 key->value = HEAP_strdupA( GetProcessHeap(), 0, value );
933 CurProfile->changed = TRUE;
939 /***********************************************************************
940 * PROFILE_GetWineIniString
942 * Get a config string from the wine.ini file.
944 int PROFILE_GetWineIniString( const char *section, const char *key_name,
945 const char *def, char *buffer, int len )
947 char tmp[PROFILE_MAX_LINE_LEN];
951 if (!(err = RegOpenKeyA( wine_profile_key, section, &hkey )))
954 DWORD count = sizeof(tmp);
955 err = RegQueryValueExA( hkey, key_name, 0, &type, tmp, &count );
958 PROFILE_CopyEntry( buffer, err ? def : tmp, len, TRUE );
959 TRACE( "('%s','%s','%s'): returning '%s'\n", section, key_name, def, buffer );
960 return strlen(buffer);
964 /***********************************************************************
965 * PROFILE_EnumWineIniString
967 * Get a config string from the wine.ini file.
969 BOOL PROFILE_EnumWineIniString( const char *section, int index,
970 char *name, int name_len, char *buffer, int len )
972 char tmp[PROFILE_MAX_LINE_LEN];
975 DWORD count = sizeof(tmp);
977 if (RegOpenKeyA( wine_profile_key, section, &hkey )) return FALSE;
978 err = RegEnumValueA( hkey, index, name, (DWORD*)&name_len, NULL, &type, tmp, &count );
982 PROFILE_CopyEntry( buffer, tmp, len, TRUE );
983 TRACE( "('%s',%d): returning '%s'='%s'\n", section, index, name, buffer );
989 /***********************************************************************
990 * PROFILE_GetWineIniInt
992 * Get a config integer from the wine.ini file.
994 int PROFILE_GetWineIniInt( const char *section, const char *key_name, int def )
1000 PROFILE_GetWineIniString( section, key_name, "", buffer, sizeof(buffer) );
1001 if (!buffer[0]) return def;
1002 result = strtol( buffer, &p, 0 );
1003 return (p == buffer) ? 0 /* No digits at all */ : (int)result;
1007 /******************************************************************************
1009 * int PROFILE_GetWineIniBool(
1010 * char const *section,
1011 * char const *key_name,
1014 * Reads a boolean value from the wine.ini file. This function attempts to
1015 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
1016 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
1017 * true. Anything else results in the return of the default value.
1019 * This function uses 1 to indicate true, and 0 for false. You can check
1020 * for existence by setting def to something other than 0 or 1 and
1021 * examining the return value.
1023 int PROFILE_GetWineIniBool(
1024 char const *section,
1025 char const *key_name,
1031 PROFILE_GetWineIniString(section, key_name, "~", key_value, 2);
1033 switch(key_value[0]) {
1054 TRACE("(\"%s\", \"%s\", %s), "
1055 "[%c], ret %s.\n", section, key_name,
1056 def ? "TRUE" : "FALSE", key_value[0],
1057 retval ? "TRUE" : "FALSE");
1063 /***********************************************************************
1064 * PROFILE_LoadWineIni
1066 * Load the old .winerc file.
1068 int PROFILE_LoadWineIni(void)
1070 char buffer[MAX_PATHNAME_LEN];
1076 /* make sure HKLM\\Software\\Wine\\Wine exists as non-volatile key */
1077 if (RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine", &hKeySW ))
1079 ERR("Cannot create config registry key\n" );
1082 RegCloseKey( hKeySW );
1083 if (RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config", 0, NULL,
1084 REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &wine_profile_key, &disp ))
1086 ERR("Cannot create config registry key\n" );
1090 if (!CLIENT_IsBootThread()) return 1; /* already loaded */
1092 if ((p = getenv( "HOME" )) != NULL)
1094 lstrcpynA(buffer, p, MAX_PATHNAME_LEN - sizeof(PROFILE_WineIniName));
1095 strcat( buffer, PROFILE_WineIniName );
1096 if ((f = fopen( buffer, "r" )) != NULL)
1098 lstrcpynA(PROFILE_WineIniUsed,buffer,MAX_PATHNAME_LEN);
1102 else WARN("could not get $HOME value for config file.\n" );
1104 if (disp == REG_OPENED_EXISTING_KEY) return 1; /* loaded by the server */
1106 MESSAGE( "Can't open configuration file %s/config\n",get_config_dir() );
1111 if (disp == REG_OPENED_EXISTING_KEY)
1113 MESSAGE( "Warning: configuration loaded by the server from '%s/config',\n"
1114 " file '%s' was ignored.\n", get_config_dir(), PROFILE_WineIniUsed );
1119 /* convert to the new format */
1120 sprintf( buffer, "%s/config", get_config_dir() );
1121 if (convert_config( f, buffer ))
1123 MESSAGE( "The '%s' configuration file has been converted\n"
1124 "to the new format and saved as '%s'.\n", PROFILE_WineIniUsed, buffer );
1125 MESSAGE( "You should verify that the contents of the new file are correct,\n"
1126 "and then remove the old one and restart Wine.\n" );
1130 PROFILE_RegistryLoad( wine_profile_key, f );
1136 /***********************************************************************
1137 * PROFILE_UsageWineIni
1139 * Explain the wine.ini file to those who don't read documentation.
1140 * Keep below one screenful in length so that error messages above are
1143 void PROFILE_UsageWineIni(void)
1145 MESSAGE("Perhaps you have not properly edited or created "
1146 "your Wine configuration file.\n");
1147 MESSAGE("This is '%s/config'\n", get_config_dir());
1148 /* RTFM, so to say */
1151 /***********************************************************************
1152 * PROFILE_GetStringItem
1154 * Convenience function that turns a string 'xxx, yyy, zzz' into
1155 * the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
1157 char* PROFILE_GetStringItem( char* start )
1161 for (lpchX = start, lpch = NULL; *lpchX != '\0'; lpchX++ )
1165 if( lpch ) *lpch = '\0'; else *lpchX = '\0';
1167 if( !PROFILE_isspace(*lpchX) ) return lpchX;
1169 else if( PROFILE_isspace( *lpchX ) && !lpch ) lpch = lpchX;
1172 if( lpch ) *lpch = '\0';
1176 /********************* API functions **********************************/
1178 /***********************************************************************
1179 * GetProfileInt16 (KERNEL.57)
1181 UINT16 WINAPI GetProfileInt16( LPCSTR section, LPCSTR entry, INT16 def_val )
1183 return GetPrivateProfileInt16( section, entry, def_val, "win.ini" );
1187 /***********************************************************************
1188 * GetProfileIntA (KERNEL32.264)
1190 UINT WINAPI GetProfileIntA( LPCSTR section, LPCSTR entry, INT def_val )
1192 return GetPrivateProfileIntA( section, entry, def_val, "win.ini" );
1195 /***********************************************************************
1196 * GetProfileIntW (KERNEL32.264)
1198 UINT WINAPI GetProfileIntW( LPCWSTR section, LPCWSTR entry, INT def_val )
1200 return GetPrivateProfileIntW( section, entry, def_val, wininiW );
1204 * undoc_feature means:
1205 * return section names string list if both section and entry are NULL.
1207 static int PROFILE_GetPrivateProfileString( LPCSTR section, LPCSTR entry,
1208 LPCSTR def_val, LPSTR buffer,
1209 UINT16 len, LPCSTR filename,
1210 BOOL undoc_feature )
1213 LPSTR pDefVal = NULL;
1216 filename = "win.ini";
1218 /* strip any trailing ' ' of def_val. */
1221 LPSTR p = (LPSTR)&def_val[strlen(def_val)]; /* even "" works ! */
1229 if (*p == ' ') /* ouch, contained trailing ' ' */
1231 int len = (int)p - (int)def_val;
1232 pDefVal = HeapAlloc(GetProcessHeap(), 0, len + 1);
1233 strncpy(pDefVal, def_val, len);
1234 pDefVal[len] = '\0';
1238 pDefVal = (LPSTR)def_val;
1240 EnterCriticalSection( &PROFILE_CritSect );
1242 if (PROFILE_Open( filename )) {
1243 if ((undoc_feature) && (section == NULL) && (entry == NULL))
1244 /* undocumented; both section and entry are NULL */
1245 ret = PROFILE_GetSectionNames(buffer, len);
1247 ret = PROFILE_GetString( section, entry, pDefVal, buffer, len );
1249 lstrcpynA( buffer, pDefVal, len );
1250 ret = strlen( buffer );
1253 LeaveCriticalSection( &PROFILE_CritSect );
1255 if (pDefVal != def_val) /* allocated */
1256 HeapFree(GetProcessHeap(), 0, pDefVal);
1261 /***********************************************************************
1262 * GetPrivateProfileString16 (KERNEL.128)
1264 INT16 WINAPI GetPrivateProfileString16( LPCSTR section, LPCSTR entry,
1265 LPCSTR def_val, LPSTR buffer,
1266 UINT16 len, LPCSTR filename )
1268 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1269 buffer, len, filename, FALSE );
1272 /***********************************************************************
1273 * GetPrivateProfileStringA (KERNEL32.255)
1275 INT WINAPI GetPrivateProfileStringA( LPCSTR section, LPCSTR entry,
1276 LPCSTR def_val, LPSTR buffer,
1277 UINT len, LPCSTR filename )
1279 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1280 buffer, len, filename, TRUE );
1283 /***********************************************************************
1284 * GetPrivateProfileStringW (KERNEL32.256)
1286 INT WINAPI GetPrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1287 LPCWSTR def_val, LPWSTR buffer,
1288 UINT len, LPCWSTR filename )
1290 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1291 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1292 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1293 LPSTR def_valA = HEAP_strdupWtoA( GetProcessHeap(), 0, def_val );
1294 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1295 INT ret = GetPrivateProfileStringA( sectionA, entryA, def_valA,
1296 bufferA, len, filenameA );
1297 if (len > 0 && !MultiByteToWideChar( CP_ACP, 0, bufferA, -1, buffer, len ))
1299 HeapFree( GetProcessHeap(), 0, sectionA );
1300 HeapFree( GetProcessHeap(), 0, entryA );
1301 HeapFree( GetProcessHeap(), 0, filenameA );
1302 HeapFree( GetProcessHeap(), 0, def_valA );
1303 HeapFree( GetProcessHeap(), 0, bufferA);
1307 /***********************************************************************
1308 * GetProfileString16 (KERNEL.58)
1310 INT16 WINAPI GetProfileString16( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1311 LPSTR buffer, UINT16 len )
1313 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1314 buffer, len, "win.ini", FALSE );
1317 /***********************************************************************
1318 * GetProfileStringA (KERNEL32.268)
1320 INT WINAPI GetProfileStringA( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1321 LPSTR buffer, UINT len )
1323 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1324 buffer, len, "win.ini", TRUE );
1327 /***********************************************************************
1328 * GetProfileStringW (KERNEL32.269)
1330 INT WINAPI GetProfileStringW( LPCWSTR section, LPCWSTR entry,
1331 LPCWSTR def_val, LPWSTR buffer, UINT len )
1333 return GetPrivateProfileStringW( section, entry, def_val,
1334 buffer, len, wininiW );
1337 /***********************************************************************
1338 * WriteProfileString16 (KERNEL.59)
1340 BOOL16 WINAPI WriteProfileString16( LPCSTR section, LPCSTR entry,
1343 return WritePrivateProfileString16( section, entry, string, "win.ini" );
1346 /***********************************************************************
1347 * WriteProfileStringA (KERNEL32.587)
1349 BOOL WINAPI WriteProfileStringA( LPCSTR section, LPCSTR entry,
1352 return WritePrivateProfileStringA( section, entry, string, "win.ini" );
1355 /***********************************************************************
1356 * WriteProfileStringW (KERNEL32.588)
1358 BOOL WINAPI WriteProfileStringW( LPCWSTR section, LPCWSTR entry,
1361 return WritePrivateProfileStringW( section, entry, string, wininiW );
1365 /***********************************************************************
1366 * GetPrivateProfileInt16 (KERNEL.127)
1368 UINT16 WINAPI GetPrivateProfileInt16( LPCSTR section, LPCSTR entry,
1369 INT16 def_val, LPCSTR filename )
1371 long result=(long)GetPrivateProfileIntA(section,entry,def_val,filename);
1373 if (result > 65535) return 65535;
1374 if (result >= 0) return (UINT16)result;
1375 if (result < -32768) return -32768;
1376 return (UINT16)(INT16)result;
1379 /***********************************************************************
1380 * GetPrivateProfileIntA (KERNEL32.251)
1382 UINT WINAPI GetPrivateProfileIntA( LPCSTR section, LPCSTR entry,
1383 INT def_val, LPCSTR filename )
1389 PROFILE_GetPrivateProfileString( section, entry, "",
1390 buffer, sizeof(buffer), filename, FALSE );
1391 if (!buffer[0]) return (UINT)def_val;
1392 result = strtol( buffer, &p, 0 );
1393 if (p == buffer) return 0; /* No digits at all */
1394 return (UINT)result;
1397 /***********************************************************************
1398 * GetPrivateProfileIntW (KERNEL32.252)
1400 UINT WINAPI GetPrivateProfileIntW( LPCWSTR section, LPCWSTR entry,
1401 INT def_val, LPCWSTR filename )
1403 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1404 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1405 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1406 UINT res = GetPrivateProfileIntA(sectionA, entryA, def_val, filenameA);
1407 HeapFree( GetProcessHeap(), 0, sectionA );
1408 HeapFree( GetProcessHeap(), 0, filenameA );
1409 HeapFree( GetProcessHeap(), 0, entryA );
1413 /***********************************************************************
1414 * GetPrivateProfileSection16 (KERNEL.418)
1416 INT16 WINAPI GetPrivateProfileSection16( LPCSTR section, LPSTR buffer,
1417 UINT16 len, LPCSTR filename )
1419 return GetPrivateProfileSectionA( section, buffer, len, filename );
1422 /***********************************************************************
1423 * GetPrivateProfileSectionA (KERNEL32.255)
1425 INT WINAPI GetPrivateProfileSectionA( LPCSTR section, LPSTR buffer,
1426 DWORD len, LPCSTR filename )
1430 EnterCriticalSection( &PROFILE_CritSect );
1432 if (PROFILE_Open( filename ))
1433 ret = PROFILE_GetSection(CurProfile->section, section, buffer, len,
1436 LeaveCriticalSection( &PROFILE_CritSect );
1441 /***********************************************************************
1442 * GetPrivateProfileSectionW (KERNEL32.256)
1445 INT WINAPI GetPrivateProfileSectionW (LPCWSTR section, LPWSTR buffer,
1446 DWORD len, LPCWSTR filename )
1449 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1450 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1451 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1452 INT ret = GetPrivateProfileSectionA( sectionA, bufferA, len,
1454 MultiByteToWideChar(CP_ACP,0,bufferA,ret,buffer,len);
1455 HeapFree( GetProcessHeap(), 0, sectionA );
1456 HeapFree( GetProcessHeap(), 0, filenameA );
1457 HeapFree( GetProcessHeap(), 0, bufferA);
1461 /***********************************************************************
1462 * GetProfileSection16 (KERNEL.419)
1464 INT16 WINAPI GetProfileSection16( LPCSTR section, LPSTR buffer, UINT16 len )
1466 return GetPrivateProfileSection16( section, buffer, len, "win.ini" );
1469 /***********************************************************************
1470 * GetProfileSectionA (KERNEL32.268)
1472 INT WINAPI GetProfileSectionA( LPCSTR section, LPSTR buffer, DWORD len )
1474 return GetPrivateProfileSectionA( section, buffer, len, "win.ini" );
1477 /***********************************************************************
1478 * GetProfileSectionW (KERNEL32)
1480 INT WINAPI GetProfileSectionW( LPCWSTR section, LPWSTR buffer, DWORD len )
1482 return GetPrivateProfileSectionW( section, buffer, len, wininiW );
1486 /***********************************************************************
1487 * WritePrivateProfileString16 (KERNEL.129)
1489 BOOL16 WINAPI WritePrivateProfileString16( LPCSTR section, LPCSTR entry,
1490 LPCSTR string, LPCSTR filename )
1492 return WritePrivateProfileStringA(section,entry,string,filename);
1495 /***********************************************************************
1496 * WritePrivateProfileStringA (KERNEL32.582)
1498 BOOL WINAPI WritePrivateProfileStringA( LPCSTR section, LPCSTR entry,
1499 LPCSTR string, LPCSTR filename )
1503 EnterCriticalSection( &PROFILE_CritSect );
1505 if (PROFILE_Open( filename ))
1507 if (!section && !entry && !string)
1508 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1510 ret = PROFILE_SetString( section, entry, string );
1513 LeaveCriticalSection( &PROFILE_CritSect );
1517 /***********************************************************************
1518 * WritePrivateProfileStringW (KERNEL32.583)
1520 BOOL WINAPI WritePrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1521 LPCWSTR string, LPCWSTR filename )
1523 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1524 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1525 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1526 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1527 BOOL res = WritePrivateProfileStringA( sectionA, entryA,
1528 stringA, filenameA );
1529 HeapFree( GetProcessHeap(), 0, sectionA );
1530 HeapFree( GetProcessHeap(), 0, entryA );
1531 HeapFree( GetProcessHeap(), 0, stringA );
1532 HeapFree( GetProcessHeap(), 0, filenameA );
1536 /***********************************************************************
1537 * WritePrivateProfileSection16 (KERNEL.416)
1539 BOOL16 WINAPI WritePrivateProfileSection16( LPCSTR section,
1540 LPCSTR string, LPCSTR filename )
1542 return WritePrivateProfileSectionA( section, string, filename );
1545 /***********************************************************************
1546 * WritePrivateProfileSectionA (KERNEL32)
1548 BOOL WINAPI WritePrivateProfileSectionA( LPCSTR section,
1549 LPCSTR string, LPCSTR filename )
1554 EnterCriticalSection( &PROFILE_CritSect );
1556 if (PROFILE_Open( filename )) {
1557 if (!section && !string)
1558 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1559 else if (!string) /* delete the named section*/
1560 ret = PROFILE_SetString(section,NULL,NULL);
1562 PROFILE_DeleteAllKeys(section);
1565 LPSTR buf=HEAP_strdupA( GetProcessHeap(), 0, string );
1566 if((p=strchr( buf, '='))){
1568 ret = PROFILE_SetString( section, buf, p+1 );
1571 HeapFree( GetProcessHeap(), 0, buf );
1572 string += strlen(string)+1;
1578 LeaveCriticalSection( &PROFILE_CritSect );
1582 /***********************************************************************
1583 * WritePrivateProfileSectionW (KERNEL32)
1585 BOOL WINAPI WritePrivateProfileSectionW( LPCWSTR section,
1586 LPCWSTR string, LPCWSTR filename)
1589 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1590 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1591 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1592 BOOL res = WritePrivateProfileSectionA( sectionA, stringA, filenameA );
1593 HeapFree( GetProcessHeap(), 0, sectionA );
1594 HeapFree( GetProcessHeap(), 0, stringA );
1595 HeapFree( GetProcessHeap(), 0, filenameA );
1599 /***********************************************************************
1600 * WriteProfileSection16 (KERNEL.417)
1602 BOOL16 WINAPI WriteProfileSection16( LPCSTR section, LPCSTR keys_n_values)
1604 return WritePrivateProfileSection16( section, keys_n_values, "win.ini");
1607 /***********************************************************************
1608 * WriteProfileSectionA (KERNEL32.747)
1610 BOOL WINAPI WriteProfileSectionA( LPCSTR section, LPCSTR keys_n_values)
1613 return WritePrivateProfileSectionA( section, keys_n_values, "win.ini");
1616 /***********************************************************************
1617 * WriteProfileSectionW (KERNEL32.748)
1619 BOOL WINAPI WriteProfileSectionW( LPCWSTR section, LPCWSTR keys_n_values)
1621 return (WritePrivateProfileSectionW (section,keys_n_values, wininiW));
1624 /***********************************************************************
1625 * GetPrivateProfileSectionNames16 (KERNEL.143)
1627 WORD WINAPI GetPrivateProfileSectionNames16( LPSTR buffer, WORD size,
1632 EnterCriticalSection( &PROFILE_CritSect );
1634 if (PROFILE_Open( filename ))
1635 ret = PROFILE_GetSectionNames(buffer, size);
1637 LeaveCriticalSection( &PROFILE_CritSect );
1643 /***********************************************************************
1644 * GetProfileSectionNames16 (KERNEL.142)
1646 WORD WINAPI GetProfileSectionNames16( LPSTR buffer, WORD size)
1649 return (GetPrivateProfileSectionNames16 (buffer,size,"win.ini"));
1653 /***********************************************************************
1654 * GetPrivateProfileSectionNamesA (KERNEL32.365)
1656 DWORD WINAPI GetPrivateProfileSectionNamesA( LPSTR buffer, DWORD size,
1660 return (GetPrivateProfileSectionNames16 (buffer,size,filename));
1664 /***********************************************************************
1665 * GetPrivateProfileSectionNamesW (KERNEL32.366)
1667 DWORD WINAPI GetPrivateProfileSectionNamesW( LPWSTR buffer, DWORD size,
1671 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1672 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, size);
1674 INT ret = GetPrivateProfileSectionNames16 (bufferA, size, filenameA);
1675 if (size > 0 && !MultiByteToWideChar( CP_ACP, 0, bufferA, -1, buffer, size ))
1677 HeapFree( GetProcessHeap(), 0, bufferA);
1678 HeapFree( GetProcessHeap(), 0, filenameA );
1683 /***********************************************************************
1684 * GetPrivateProfileStruct16 (KERNEL.407)
1686 BOOL16 WINAPI GetPrivateProfileStruct16(LPCSTR section, LPCSTR key,
1687 LPVOID buf, UINT16 len, LPCSTR filename)
1689 return GetPrivateProfileStructA( section, key, buf, len, filename );
1692 /***********************************************************************
1693 * GetPrivateProfileStructA (KERNEL32.370)
1695 * Should match Win95's behaviour pretty much
1697 BOOL WINAPI GetPrivateProfileStructA (LPCSTR section, LPCSTR key,
1698 LPVOID buf, UINT len, LPCSTR filename)
1702 EnterCriticalSection( &PROFILE_CritSect );
1704 if (PROFILE_Open( filename )) {
1705 PROFILEKEY *k = PROFILE_Find ( &CurProfile->section, section, key, FALSE);
1707 TRACE("value (at %p): '%s'\n", k->value, k->value);
1708 if (((strlen(k->value) - 2) / 2) == len)
1715 end = k->value + strlen(k->value); /* -> '\0' */
1716 /* check for invalid chars in ASCII coded hex string */
1717 for (p=k->value; p < end; p++)
1721 WARN("invalid char '%c' in file '%s'->'[%s]'->'%s' !\n",
1722 *p, filename, section, key);
1729 BOOL highnibble = TRUE;
1731 LPBYTE binbuf = (LPBYTE)buf;
1733 end -= 2; /* don't include checksum in output data */
1734 /* translate ASCII hex format into binary data */
1735 for (p=k->value; p < end; p++)
1739 (c - 'A' + 10) : (c - '0');
1746 *binbuf++ = b; /* feed binary data into output */
1747 chksum += b; /* calculate checksum */
1749 highnibble ^= 1; /* toggle */
1751 /* retrieve stored checksum value */
1753 b = ( (c > '9') ? (c - 'A' + 10) : (c - '0') ) << 4;
1755 b += (c > '9') ? (c - 'A' + 10) : (c - '0');
1756 if (b == (chksum & 0xff)) /* checksums match ? */
1762 LeaveCriticalSection( &PROFILE_CritSect );
1767 /***********************************************************************
1768 * GetPrivateProfileStructW (KERNEL32.543)
1770 BOOL WINAPI GetPrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1771 LPVOID buffer, UINT len, LPCWSTR filename)
1773 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1774 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1775 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1776 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1778 INT ret = GetPrivateProfileStructA( sectionA, keyA, bufferA,
1780 if (len > 0 && !MultiByteToWideChar( CP_ACP, 0, bufferA, -1, buffer, len ))
1781 ((LPWSTR)buffer)[len-1] = 0;
1782 HeapFree( GetProcessHeap(), 0, bufferA);
1783 HeapFree( GetProcessHeap(), 0, sectionA );
1784 HeapFree( GetProcessHeap(), 0, keyA );
1785 HeapFree( GetProcessHeap(), 0, filenameA );
1792 /***********************************************************************
1793 * WritePrivateProfileStruct16 (KERNEL.406)
1795 BOOL16 WINAPI WritePrivateProfileStruct16 (LPCSTR section, LPCSTR key,
1796 LPVOID buf, UINT16 bufsize, LPCSTR filename)
1798 return WritePrivateProfileStructA( section, key, buf, bufsize, filename );
1801 /***********************************************************************
1802 * WritePrivateProfileStructA (KERNEL32.744)
1804 BOOL WINAPI WritePrivateProfileStructA (LPCSTR section, LPCSTR key,
1805 LPVOID buf, UINT bufsize, LPCSTR filename)
1812 if (!section && !key && !buf) /* flush the cache */
1813 return WritePrivateProfileStringA( NULL, NULL, NULL, filename );
1815 /* allocate string buffer for hex chars + checksum hex char + '\0' */
1816 outstring = HeapAlloc( GetProcessHeap(), 0, bufsize*2 + 2 + 1);
1818 for (binbuf = (LPBYTE)buf; binbuf < (LPBYTE)buf+bufsize; binbuf++) {
1819 *p++ = hex[*binbuf >> 4];
1820 *p++ = hex[*binbuf & 0xf];
1823 /* checksum is sum & 0xff */
1824 *p++ = hex[(sum & 0xf0) >> 4];
1825 *p++ = hex[sum & 0xf];
1828 EnterCriticalSection( &PROFILE_CritSect );
1830 if (PROFILE_Open( filename ))
1831 ret = PROFILE_SetString( section, key, outstring );
1833 LeaveCriticalSection( &PROFILE_CritSect );
1835 HeapFree( GetProcessHeap(), 0, outstring );
1840 /***********************************************************************
1841 * WritePrivateProfileStructW (KERNEL32.544)
1843 BOOL WINAPI WritePrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1844 LPVOID buf, UINT bufsize, LPCWSTR filename)
1846 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1847 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1848 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1849 INT ret = WritePrivateProfileStructA( sectionA, keyA, buf, bufsize,
1851 HeapFree( GetProcessHeap(), 0, sectionA );
1852 HeapFree( GetProcessHeap(), 0, keyA );
1853 HeapFree( GetProcessHeap(), 0, filenameA );
1859 /***********************************************************************
1860 * WriteOutProfiles (KERNEL.315)
1862 void WINAPI WriteOutProfiles16(void)
1864 EnterCriticalSection( &PROFILE_CritSect );
1865 PROFILE_FlushFile();
1866 LeaveCriticalSection( &PROFILE_CritSect );
1869 /***********************************************************************
1870 * CloseProfileUserMapping (KERNEL.138)
1872 BOOL WINAPI CloseProfileUserMapping(void) {
1873 FIXME("(), stub!\n");
1874 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);