| /* | |
| * Directory id handling | |
| * | |
| * Copyright 2002 Alexandre Julliard for CodeWeavers | |
| * | |
| * This library is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU Lesser General Public | |
| * License as published by the Free Software Foundation; either | |
| * version 2.1 of the License, or (at your option) any later version. | |
| * | |
| * This library is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| * Lesser General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Lesser General Public | |
| * License along with this library; if not, write to the Free Software | |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| */ | |
| #include <stdarg.h> | |
| #include "windef.h" | |
| #include "winbase.h" | |
| #include "winreg.h" | |
| #include "winternl.h" | |
| #include "winerror.h" | |
| #include "wingdi.h" | |
| #include "winuser.h" | |
| #include "winnls.h" | |
| #include "setupapi.h" | |
| #include "shlobj.h" | |
| #include "wine/unicode.h" | |
| #include "setupapi_private.h" | |
| #include "wine/debug.h" | |
| WINE_DEFAULT_DEBUG_CHANNEL(setupapi); | |
| #define MAX_SYSTEM_DIRID DIRID_PRINTPROCESSOR | |
| #define MIN_CSIDL_DIRID 0x4000 | |
| #define MAX_CSIDL_DIRID 0x403f | |
| struct user_dirid | |
| { | |
| int id; | |
| WCHAR *str; | |
| }; | |
| static int nb_user_dirids; /* number of user dirids in use */ | |
| static int alloc_user_dirids; /* number of allocated user dirids */ | |
| static struct user_dirid *user_dirids; | |
| static const WCHAR *system_dirids[MAX_SYSTEM_DIRID+1]; | |
| static const WCHAR *csidl_dirids[MAX_CSIDL_DIRID-MIN_CSIDL_DIRID+1]; | |
| /* retrieve the string for unknown dirids */ | |
| static const WCHAR *get_unknown_dirid(void) | |
| { | |
| static WCHAR *unknown_dirid; | |
| static const WCHAR unknown_str[] = {'\\','u','n','k','n','o','w','n',0}; | |
| if (!unknown_dirid) | |
| { | |
| UINT len = GetSystemDirectoryW( NULL, 0 ) + strlenW(unknown_str); | |
| if (!(unknown_dirid = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return NULL; | |
| GetSystemDirectoryW( unknown_dirid, len ); | |
| strcatW( unknown_dirid, unknown_str ); | |
| } | |
| return unknown_dirid; | |
| } | |
| static const WCHAR *get_csidl_dir(DWORD csidl); | |
| /* create the string for a system dirid */ | |
| static const WCHAR *create_system_dirid( int dirid ) | |
| { | |
| static const WCHAR Null[] = {0}; | |
| static const WCHAR C_Root[] = {'C',':','\\',0}; | |
| static const WCHAR Drivers[] = {'\\','d','r','i','v','e','r','s',0}; | |
| static const WCHAR Inf[] = {'\\','i','n','f',0}; | |
| static const WCHAR Help[] = {'\\','h','e','l','p',0}; | |
| static const WCHAR Fonts[] = {'\\','f','o','n','t','s',0}; | |
| static const WCHAR Viewers[] = {'\\','v','i','e','w','e','r','s',0}; | |
| static const WCHAR System[] = {'\\','s','y','s','t','e','m',0}; | |
| static const WCHAR Spool[] = {'\\','s','p','o','o','l',0}; | |
| static const WCHAR UserProfile[] = {'U','S','E','R','P','R','O','F','I','L','E',0}; | |
| WCHAR buffer[MAX_PATH+32], *str; | |
| int len; | |
| switch(dirid) | |
| { | |
| case DIRID_NULL: | |
| return Null; | |
| case DIRID_WINDOWS: | |
| GetWindowsDirectoryW( buffer, MAX_PATH ); | |
| break; | |
| case DIRID_SYSTEM: | |
| GetSystemDirectoryW( buffer, MAX_PATH ); | |
| break; | |
| case DIRID_DRIVERS: | |
| GetSystemDirectoryW( buffer, MAX_PATH ); | |
| strcatW( buffer, Drivers ); | |
| break; | |
| case DIRID_INF: | |
| GetWindowsDirectoryW( buffer, MAX_PATH ); | |
| strcatW( buffer, Inf ); | |
| break; | |
| case DIRID_HELP: | |
| GetWindowsDirectoryW( buffer, MAX_PATH ); | |
| strcatW( buffer, Help ); | |
| break; | |
| case DIRID_FONTS: | |
| GetWindowsDirectoryW( buffer, MAX_PATH ); | |
| strcatW( buffer, Fonts ); | |
| break; | |
| case DIRID_VIEWERS: | |
| GetSystemDirectoryW( buffer, MAX_PATH ); | |
| strcatW( buffer, Viewers ); | |
| break; | |
| case DIRID_APPS: | |
| return C_Root; /* FIXME */ | |
| case DIRID_SHARED: | |
| GetWindowsDirectoryW( buffer, MAX_PATH ); | |
| break; | |
| case DIRID_BOOT: | |
| return C_Root; /* FIXME */ | |
| case DIRID_SYSTEM16: | |
| GetWindowsDirectoryW( buffer, MAX_PATH ); | |
| strcatW( buffer, System ); | |
| break; | |
| case DIRID_SPOOL: | |
| case DIRID_SPOOLDRIVERS: /* FIXME */ | |
| GetWindowsDirectoryW( buffer, MAX_PATH ); | |
| strcatW( buffer, Spool ); | |
| break; | |
| case DIRID_USERPROFILE: | |
| if (GetEnvironmentVariableW( UserProfile, buffer, MAX_PATH )) break; | |
| return get_csidl_dir(CSIDL_PROFILE); | |
| case DIRID_LOADER: | |
| return C_Root; /* FIXME */ | |
| case DIRID_COLOR: /* FIXME */ | |
| case DIRID_PRINTPROCESSOR: /* FIXME */ | |
| default: | |
| FIXME( "unknown dirid %d\n", dirid ); | |
| return get_unknown_dirid(); | |
| } | |
| len = (strlenW(buffer) + 1) * sizeof(WCHAR); | |
| if ((str = HeapAlloc( GetProcessHeap(), 0, len ))) memcpy( str, buffer, len ); | |
| return str; | |
| } | |
| static const WCHAR *get_csidl_dir( DWORD csidl ) | |
| { | |
| WCHAR buffer[MAX_PATH], *str; | |
| int len; | |
| if (!SHGetSpecialFolderPathW( NULL, buffer, csidl, TRUE )) | |
| { | |
| FIXME( "CSIDL %lx not found\n", csidl ); | |
| return get_unknown_dirid(); | |
| } | |
| len = (strlenW(buffer) + 1) * sizeof(WCHAR); | |
| if ((str = HeapAlloc( GetProcessHeap(), 0, len ))) memcpy( str, buffer, len ); | |
| return str; | |
| } | |
| /* retrieve the string corresponding to a dirid, or NULL if none */ | |
| const WCHAR *DIRID_get_string( HINF hinf, int dirid ) | |
| { | |
| int i; | |
| if (dirid == DIRID_ABSOLUTE || dirid == DIRID_ABSOLUTE_16BIT) dirid = DIRID_NULL; | |
| if (dirid >= DIRID_USER) | |
| { | |
| for (i = 0; i < nb_user_dirids; i++) | |
| if (user_dirids[i].id == dirid) return user_dirids[i].str; | |
| ERR("user id %d not found\n", dirid ); | |
| return NULL; | |
| } | |
| else if (dirid >= MIN_CSIDL_DIRID) | |
| { | |
| if (dirid > MAX_CSIDL_DIRID) return get_unknown_dirid(); | |
| dirid -= MIN_CSIDL_DIRID; | |
| if (!csidl_dirids[dirid]) csidl_dirids[dirid] = get_csidl_dir( dirid ); | |
| return csidl_dirids[dirid]; | |
| } | |
| else | |
| { | |
| if (dirid > MAX_SYSTEM_DIRID) return get_unknown_dirid(); | |
| if (dirid == DIRID_SRCPATH) return PARSER_get_src_root( hinf ); | |
| if (!system_dirids[dirid]) system_dirids[dirid] = create_system_dirid( dirid ); | |
| return system_dirids[dirid]; | |
| } | |
| } | |
| /* store a user dirid string */ | |
| static BOOL store_user_dirid( HINF hinf, int id, WCHAR *str ) | |
| { | |
| int i; | |
| for (i = 0; i < nb_user_dirids; i++) if (user_dirids[i].id == id) break; | |
| if (i < nb_user_dirids) HeapFree( GetProcessHeap(), 0, user_dirids[i].str ); | |
| else | |
| { | |
| if (nb_user_dirids >= alloc_user_dirids) | |
| { | |
| int new_size = max( 32, alloc_user_dirids * 2 ); | |
| struct user_dirid *new; | |
| if (user_dirids) | |
| new = HeapReAlloc( GetProcessHeap(), 0, user_dirids, | |
| new_size * sizeof(*new) ); | |
| else | |
| new = HeapAlloc( GetProcessHeap(), 0, | |
| new_size * sizeof(*new) ); | |
| if (!new) return FALSE; | |
| user_dirids = new; | |
| alloc_user_dirids = new_size; | |
| } | |
| nb_user_dirids++; | |
| } | |
| user_dirids[i].id = id; | |
| user_dirids[i].str = str; | |
| TRACE("id %d -> %s\n", id, debugstr_w(str) ); | |
| return TRUE; | |
| } | |
| /*********************************************************************** | |
| * SetupSetDirectoryIdA (SETUPAPI.@) | |
| */ | |
| BOOL WINAPI SetupSetDirectoryIdA( HINF hinf, DWORD id, PCSTR dir ) | |
| { | |
| UNICODE_STRING dirW; | |
| int i; | |
| if (!id) /* clear everything */ | |
| { | |
| for (i = 0; i < nb_user_dirids; i++) HeapFree( GetProcessHeap(), 0, user_dirids[i].str ); | |
| nb_user_dirids = 0; | |
| return TRUE; | |
| } | |
| if (id < DIRID_USER) | |
| { | |
| SetLastError( ERROR_INVALID_PARAMETER ); | |
| return FALSE; | |
| } | |
| /* duplicate the string */ | |
| if (!RtlCreateUnicodeStringFromAsciiz( &dirW, dir )) | |
| { | |
| SetLastError( ERROR_NOT_ENOUGH_MEMORY ); | |
| return FALSE; | |
| } | |
| return store_user_dirid( hinf, id, dirW.Buffer ); | |
| } | |
| /*********************************************************************** | |
| * SetupSetDirectoryIdW (SETUPAPI.@) | |
| */ | |
| BOOL WINAPI SetupSetDirectoryIdW( HINF hinf, DWORD id, PCWSTR dir ) | |
| { | |
| int i, len; | |
| WCHAR *str; | |
| if (!id) /* clear everything */ | |
| { | |
| for (i = 0; i < nb_user_dirids; i++) HeapFree( GetProcessHeap(), 0, user_dirids[i].str ); | |
| nb_user_dirids = 0; | |
| return TRUE; | |
| } | |
| if (id < DIRID_USER) | |
| { | |
| SetLastError( ERROR_INVALID_PARAMETER ); | |
| return FALSE; | |
| } | |
| /* duplicate the string */ | |
| len = (strlenW(dir)+1) * sizeof(WCHAR); | |
| if (!(str = HeapAlloc( GetProcessHeap(), 0, len ))) return FALSE; | |
| memcpy( str, dir, len ); | |
| return store_user_dirid( hinf, id, str ); | |
| } |