/* * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 "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; }; #ifdef __i386__ static const WCHAR printer_env[] = L"w32x86"; #elif defined __x86_64__ static const WCHAR printer_env[] = L"x64"; #elif defined __arm__ static const WCHAR printer_env[] = L"arm"; #elif defined __aarch64__ static const WCHAR printer_env[] = L"arm64"; #else #error not defined for this cpu #endif 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 *printer_dirids[5]; /* 66000..66004 */ 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; if (!unknown_dirid) { UINT len = GetSystemDirectoryW( NULL, 0 ) + lstrlenW(L"\\unknown"); if (!(unknown_dirid = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return NULL; GetSystemDirectoryW( unknown_dirid, len ); lstrcatW( unknown_dirid, L"\\unknown" ); } 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 ) { WCHAR buffer[MAX_PATH+32], *str; int len; switch(dirid) { case DIRID_NULL: return L""; case DIRID_WINDOWS: GetWindowsDirectoryW( buffer, MAX_PATH ); break; case DIRID_SYSTEM: GetSystemDirectoryW( buffer, MAX_PATH ); break; case DIRID_DRIVERS: GetSystemDirectoryW( buffer, MAX_PATH ); lstrcatW( buffer, L"\\drivers" ); break; case DIRID_INF: GetWindowsDirectoryW( buffer, MAX_PATH ); lstrcatW( buffer, L"\\inf" ); break; case DIRID_HELP: GetWindowsDirectoryW( buffer, MAX_PATH ); lstrcatW( buffer, L"\\help" ); break; case DIRID_FONTS: GetWindowsDirectoryW( buffer, MAX_PATH ); lstrcatW( buffer, L"\\fonts" ); break; case DIRID_VIEWERS: GetSystemDirectoryW( buffer, MAX_PATH ); lstrcatW( buffer, L"\\viewers" ); break; case DIRID_COLOR: GetSystemDirectoryW( buffer, MAX_PATH ); lstrcatW( buffer, L"\\spool\\drivers\\color" ); break; case DIRID_APPS: return L"C:\\"; /* FIXME */ case DIRID_SHARED: GetWindowsDirectoryW( buffer, MAX_PATH ); break; case DIRID_BOOT: return L"C:\\"; /* FIXME */ case DIRID_SYSTEM16: GetWindowsDirectoryW( buffer, MAX_PATH ); lstrcatW( buffer, L"\\system" ); break; case DIRID_SPOOL: GetSystemDirectoryW( buffer, MAX_PATH ); lstrcatW( buffer, L"\\spool" ); break; case DIRID_SPOOLDRIVERS: GetSystemDirectoryW( buffer, MAX_PATH ); lstrcatW( buffer, L"\\spool\\drivers" ); break; case DIRID_USERPROFILE: if (GetEnvironmentVariableW( L"USERPROFILE", buffer, MAX_PATH )) break; return get_csidl_dir(CSIDL_PROFILE); case DIRID_LOADER: return L"C:\\"; /* FIXME */ case DIRID_PRINTPROCESSOR: GetSystemDirectoryW( buffer, MAX_PATH ); lstrcatW( buffer, L"\\spool\\prtprocs\\" ); lstrcatW( buffer, printer_env ); break; default: FIXME( "unknown dirid %d\n", dirid ); return get_unknown_dirid(); } len = (lstrlenW(buffer) + 1) * sizeof(WCHAR); if ((str = HeapAlloc( GetProcessHeap(), 0, len ))) memcpy( str, buffer, len ); return str; } static const WCHAR *create_printer_dirid( DWORD dirid ) { WCHAR buffer[MAX_PATH+32], *str; int len; switch (dirid) { case 66000: /* printer driver */ GetSystemDirectoryW( buffer, MAX_PATH ); lstrcatW( buffer, L"\\spool\\drivers\\" ); lstrcatW( buffer, printer_env ); break; case 66001: /* print processor */ return create_system_dirid( DIRID_PRINTPROCESSOR ); case 66002: /* system directory (FIXME: only for native architecture) */ GetSystemDirectoryW( buffer, MAX_PATH ); break; case 66003: /* color directory */ return create_system_dirid( DIRID_COLOR ); case 66004: /* asp files directory */ default: FIXME( "unsupported dirid %ld\n", dirid ); return get_unknown_dirid(); } len = (lstrlenW(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 = (lstrlenW(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( int dirid ) { int i; if (dirid == DIRID_ABSOLUTE || dirid == DIRID_ABSOLUTE_16BIT) dirid = DIRID_NULL; if (dirid >= 66000 && dirid <= 66004) { if (!printer_dirids[dirid - 66000]) printer_dirids[dirid - 66000] = create_printer_dirid( dirid ); return printer_dirids[dirid - 66000]; } else if (dirid >= DIRID_USER) { for (i = 0; i < nb_user_dirids; i++) if (user_dirids[i].id == dirid) return user_dirids[i].str; WARN("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 (!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 = (lstrlenW(dir)+1) * sizeof(WCHAR); if (!(str = HeapAlloc( GetProcessHeap(), 0, len ))) return FALSE; memcpy( str, dir, len ); return store_user_dirid( hinf, id, str ); }