1 /* 2 * Directory id handling 3 * 4 * Copyright 2002 Alexandre Julliard for CodeWeavers 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #include "setupapi_private.h" 22 23 #define MAX_SYSTEM_DIRID DIRID_PRINTPROCESSOR 24 #define MIN_CSIDL_DIRID 0x4000 25 #define MAX_CSIDL_DIRID 0x403f 26 27 struct user_dirid 28 { 29 int id; 30 WCHAR *str; 31 }; 32 33 static int nb_user_dirids; /* number of user dirids in use */ 34 static int alloc_user_dirids; /* number of allocated user dirids */ 35 static struct user_dirid *user_dirids; 36 static const WCHAR *system_dirids[MAX_SYSTEM_DIRID+1]; 37 static const WCHAR *csidl_dirids[MAX_CSIDL_DIRID-MIN_CSIDL_DIRID+1]; 38 39 /* retrieve the string for unknown dirids */ 40 static const WCHAR *get_unknown_dirid(void) 41 { 42 static WCHAR *unknown_dirid; 43 static const WCHAR unknown_str[] = {'\\','u','n','k','n','o','w','n',0}; 44 45 if (!unknown_dirid) 46 { 47 UINT len = GetSystemDirectoryW( NULL, 0 ) + strlenW(unknown_str); 48 if (!(unknown_dirid = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return NULL; 49 GetSystemDirectoryW( unknown_dirid, len ); 50 strcatW( unknown_dirid, unknown_str ); 51 } 52 return unknown_dirid; 53 } 54 55 static const WCHAR *get_csidl_dir(DWORD csidl); 56 57 /* create the string for a system dirid */ 58 static const WCHAR *create_system_dirid( int dirid ) 59 { 60 static const WCHAR Null[] = {0}; 61 static const WCHAR C_Root[] = {'C',':','\\',0}; 62 static const WCHAR Drivers[] = {'\\','d','r','i','v','e','r','s',0}; 63 static const WCHAR Inf[] = {'\\','i','n','f',0}; 64 static const WCHAR Help[] = {'\\','h','e','l','p',0}; 65 static const WCHAR Fonts[] = {'\\','f','o','n','t','s',0}; 66 static const WCHAR Viewers[] = {'\\','v','i','e','w','e','r','s',0}; 67 static const WCHAR System[] = {'\\','s','y','s','t','e','m',0}; 68 static const WCHAR Spool[] = {'\\','s','p','o','o','l',0}; 69 static const WCHAR UserProfile[] = {'U','S','E','R','P','R','O','F','I','L','E',0}; 70 71 WCHAR buffer[MAX_PATH+32], *str; 72 int len; 73 DWORD needed; 74 75 switch(dirid) 76 { 77 case DIRID_NULL: 78 return Null; 79 case DIRID_WINDOWS: 80 GetWindowsDirectoryW( buffer, MAX_PATH ); 81 break; 82 case DIRID_SYSTEM: 83 GetSystemDirectoryW( buffer, MAX_PATH ); 84 break; 85 case DIRID_DRIVERS: 86 GetSystemDirectoryW( buffer, MAX_PATH ); 87 strcatW( buffer, Drivers ); 88 break; 89 case DIRID_INF: 90 GetWindowsDirectoryW( buffer, MAX_PATH ); 91 strcatW( buffer, Inf ); 92 break; 93 case DIRID_HELP: 94 GetWindowsDirectoryW( buffer, MAX_PATH ); 95 strcatW( buffer, Help ); 96 break; 97 case DIRID_FONTS: 98 GetWindowsDirectoryW( buffer, MAX_PATH ); 99 strcatW( buffer, Fonts ); 100 break; 101 case DIRID_VIEWERS: 102 GetSystemDirectoryW( buffer, MAX_PATH ); 103 strcatW( buffer, Viewers ); 104 break; 105 case DIRID_APPS: 106 return C_Root; /* FIXME */ 107 case DIRID_SHARED: 108 GetWindowsDirectoryW( buffer, MAX_PATH ); 109 break; 110 case DIRID_BOOT: 111 return C_Root; /* FIXME */ 112 case DIRID_SYSTEM16: 113 GetWindowsDirectoryW( buffer, MAX_PATH ); 114 strcatW( buffer, System ); 115 break; 116 case DIRID_SPOOL: 117 case DIRID_SPOOLDRIVERS: /* FIXME */ 118 GetWindowsDirectoryW( buffer, MAX_PATH ); 119 strcatW( buffer, Spool ); 120 break; 121 case DIRID_USERPROFILE: 122 if (GetEnvironmentVariableW( UserProfile, buffer, MAX_PATH )) break; 123 return get_csidl_dir(CSIDL_PROFILE); 124 case DIRID_LOADER: 125 return C_Root; /* FIXME */ 126 case DIRID_PRINTPROCESSOR: 127 if (!GetPrintProcessorDirectoryW(NULL, NULL, 1, (LPBYTE)buffer, sizeof(buffer), &needed)) 128 { 129 WARN( "cannot retrieve print processor directory\n" ); 130 return get_unknown_dirid(); 131 } 132 break; 133 case DIRID_COLOR: /* FIXME */ 134 default: 135 FIXME( "unknown dirid %d\n", dirid ); 136 return get_unknown_dirid(); 137 } 138 len = (strlenW(buffer) + 1) * sizeof(WCHAR); 139 if ((str = HeapAlloc( GetProcessHeap(), 0, len ))) memcpy( str, buffer, len ); 140 return str; 141 } 142 143 static const WCHAR *get_csidl_dir( DWORD csidl ) 144 { 145 WCHAR buffer[MAX_PATH], *str; 146 int len; 147 148 if (!SHGetSpecialFolderPathW( NULL, buffer, csidl, TRUE )) 149 { 150 FIXME( "CSIDL %x not found\n", csidl ); 151 return get_unknown_dirid(); 152 } 153 len = (strlenW(buffer) + 1) * sizeof(WCHAR); 154 if ((str = HeapAlloc( GetProcessHeap(), 0, len ))) memcpy( str, buffer, len ); 155 return str; 156 } 157 158 /* retrieve the string corresponding to a dirid, or NULL if none */ 159 const WCHAR *DIRID_get_string( int dirid ) 160 { 161 int i; 162 163 if (dirid == DIRID_ABSOLUTE || dirid == DIRID_ABSOLUTE_16BIT) dirid = DIRID_NULL; 164 165 if (dirid >= DIRID_USER) 166 { 167 for (i = 0; i < nb_user_dirids; i++) 168 if (user_dirids[i].id == dirid) return user_dirids[i].str; 169 WARN("user id %d not found\n", dirid ); 170 return NULL; 171 } 172 else if (dirid >= MIN_CSIDL_DIRID) 173 { 174 if (dirid > MAX_CSIDL_DIRID) return get_unknown_dirid(); 175 dirid -= MIN_CSIDL_DIRID; 176 if (!csidl_dirids[dirid]) csidl_dirids[dirid] = get_csidl_dir( dirid ); 177 return csidl_dirids[dirid]; 178 } 179 else 180 { 181 if (dirid > MAX_SYSTEM_DIRID) return get_unknown_dirid(); 182 if (!system_dirids[dirid]) system_dirids[dirid] = create_system_dirid( dirid ); 183 return system_dirids[dirid]; 184 } 185 } 186 187 /* store a user dirid string */ 188 static BOOL store_user_dirid( HINF hinf, int id, WCHAR *str ) 189 { 190 int i; 191 192 for (i = 0; i < nb_user_dirids; i++) if (user_dirids[i].id == id) break; 193 194 if (i < nb_user_dirids) HeapFree( GetProcessHeap(), 0, user_dirids[i].str ); 195 else 196 { 197 if (nb_user_dirids >= alloc_user_dirids) 198 { 199 int new_size = max( 32, alloc_user_dirids * 2 ); 200 201 struct user_dirid *new; 202 203 if (user_dirids) 204 new = HeapReAlloc( GetProcessHeap(), 0, user_dirids, 205 new_size * sizeof(*new) ); 206 else 207 new = HeapAlloc( GetProcessHeap(), 0, 208 new_size * sizeof(*new) ); 209 210 if (!new) return FALSE; 211 user_dirids = new; 212 alloc_user_dirids = new_size; 213 } 214 nb_user_dirids++; 215 } 216 user_dirids[i].id = id; 217 user_dirids[i].str = str; 218 TRACE("id %d -> %s\n", id, debugstr_w(str) ); 219 return TRUE; 220 } 221 222 223 /*********************************************************************** 224 * SetupSetDirectoryIdA (SETUPAPI.@) 225 */ 226 BOOL WINAPI SetupSetDirectoryIdA( HINF hinf, DWORD id, PCSTR dir ) 227 { 228 UNICODE_STRING dirW; 229 int i; 230 231 if (!id) /* clear everything */ 232 { 233 for (i = 0; i < nb_user_dirids; i++) HeapFree( GetProcessHeap(), 0, user_dirids[i].str ); 234 nb_user_dirids = 0; 235 return TRUE; 236 } 237 if (id < DIRID_USER) 238 { 239 SetLastError( ERROR_INVALID_PARAMETER ); 240 return FALSE; 241 } 242 243 /* duplicate the string */ 244 if (!RtlCreateUnicodeStringFromAsciiz( &dirW, dir )) 245 { 246 SetLastError( ERROR_NOT_ENOUGH_MEMORY ); 247 return FALSE; 248 } 249 return store_user_dirid( hinf, id, dirW.Buffer ); 250 } 251 252 253 /*********************************************************************** 254 * SetupSetDirectoryIdW (SETUPAPI.@) 255 */ 256 BOOL WINAPI SetupSetDirectoryIdW( HINF hinf, DWORD id, PCWSTR dir ) 257 { 258 int i, len; 259 WCHAR *str; 260 261 if (!id) /* clear everything */ 262 { 263 for (i = 0; i < nb_user_dirids; i++) HeapFree( GetProcessHeap(), 0, user_dirids[i].str ); 264 nb_user_dirids = 0; 265 return TRUE; 266 } 267 if (id < DIRID_USER) 268 { 269 SetLastError( ERROR_INVALID_PARAMETER ); 270 return FALSE; 271 } 272 273 /* duplicate the string */ 274 len = (strlenW(dir)+1) * sizeof(WCHAR); 275 if (!(str = HeapAlloc( GetProcessHeap(), 0, len ))) return FALSE; 276 memcpy( str, dir, len ); 277 return store_user_dirid( hinf, id, str ); 278 } 279