332 lines
9.7 KiB
C
332 lines
9.7 KiB
C
/*
|
|
* 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 %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 *get_csidl_dir( DWORD csidl )
|
|
{
|
|
WCHAR buffer[MAX_PATH], *str;
|
|
int len;
|
|
|
|
if (!SHGetSpecialFolderPathW( NULL, buffer, csidl, TRUE ))
|
|
{
|
|
FIXME( "CSIDL %x 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 );
|
|
}
|