comdlg32: Fix German shortcut conflict.
[wine] / dlls / setupapi / dirid.c
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 <stdarg.h>
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winreg.h"
26 #include "winternl.h"
27 #include "winerror.h"
28 #include "wingdi.h"
29 #include "winuser.h"
30 #include "winnls.h"
31 #include "winspool.h"
32 #include "setupapi.h"
33 #include "shlobj.h"
34 #include "wine/unicode.h"
35 #include "setupapi_private.h"
36 #include "wine/debug.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
39
40 #define MAX_SYSTEM_DIRID DIRID_PRINTPROCESSOR
41 #define MIN_CSIDL_DIRID 0x4000
42 #define MAX_CSIDL_DIRID 0x403f
43
44 struct user_dirid
45 {
46     int    id;
47     WCHAR *str;
48 };
49
50 static int nb_user_dirids;     /* number of user dirids in use */
51 static int alloc_user_dirids;  /* number of allocated user dirids */
52 static struct user_dirid *user_dirids;
53 static const WCHAR *system_dirids[MAX_SYSTEM_DIRID+1];
54 static const WCHAR *csidl_dirids[MAX_CSIDL_DIRID-MIN_CSIDL_DIRID+1];
55
56 /* retrieve the string for unknown dirids */
57 static const WCHAR *get_unknown_dirid(void)
58 {
59     static WCHAR *unknown_dirid;
60     static const WCHAR unknown_str[] = {'\\','u','n','k','n','o','w','n',0};
61
62     if (!unknown_dirid)
63     {
64         UINT len = GetSystemDirectoryW( NULL, 0 ) + strlenW(unknown_str);
65         if (!(unknown_dirid = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return NULL;
66         GetSystemDirectoryW( unknown_dirid, len );
67         strcatW( unknown_dirid, unknown_str );
68     }
69     return unknown_dirid;
70 }
71
72 static const WCHAR *get_csidl_dir(DWORD csidl);
73
74 /* create the string for a system dirid */
75 static const WCHAR *create_system_dirid( int dirid )
76 {
77     static const WCHAR Null[]    = {0};
78     static const WCHAR C_Root[]  = {'C',':','\\',0};
79     static const WCHAR Drivers[] = {'\\','d','r','i','v','e','r','s',0};
80     static const WCHAR Inf[]     = {'\\','i','n','f',0};
81     static const WCHAR Help[]    = {'\\','h','e','l','p',0};
82     static const WCHAR Fonts[]   = {'\\','f','o','n','t','s',0};
83     static const WCHAR Viewers[] = {'\\','v','i','e','w','e','r','s',0};
84     static const WCHAR System[]  = {'\\','s','y','s','t','e','m',0};
85     static const WCHAR Spool[]   = {'\\','s','p','o','o','l',0};
86     static const WCHAR UserProfile[] = {'U','S','E','R','P','R','O','F','I','L','E',0};
87
88     WCHAR buffer[MAX_PATH+32], *str;
89     int len;
90     DWORD needed;
91
92     switch(dirid)
93     {
94     case DIRID_NULL:
95         return Null;
96     case DIRID_WINDOWS:
97         GetWindowsDirectoryW( buffer, MAX_PATH );
98         break;
99     case DIRID_SYSTEM:
100         GetSystemDirectoryW( buffer, MAX_PATH );
101         break;
102     case DIRID_DRIVERS:
103         GetSystemDirectoryW( buffer, MAX_PATH );
104         strcatW( buffer, Drivers );
105         break;
106     case DIRID_INF:
107         GetWindowsDirectoryW( buffer, MAX_PATH );
108         strcatW( buffer, Inf );
109         break;
110     case DIRID_HELP:
111         GetWindowsDirectoryW( buffer, MAX_PATH );
112         strcatW( buffer, Help );
113         break;
114     case DIRID_FONTS:
115         GetWindowsDirectoryW( buffer, MAX_PATH );
116         strcatW( buffer, Fonts );
117         break;
118     case DIRID_VIEWERS:
119         GetSystemDirectoryW( buffer, MAX_PATH );
120         strcatW( buffer, Viewers );
121         break;
122     case DIRID_APPS:
123         return C_Root;  /* FIXME */
124     case DIRID_SHARED:
125         GetWindowsDirectoryW( buffer, MAX_PATH );
126         break;
127     case DIRID_BOOT:
128         return C_Root;  /* FIXME */
129     case DIRID_SYSTEM16:
130         GetWindowsDirectoryW( buffer, MAX_PATH );
131         strcatW( buffer, System );
132         break;
133     case DIRID_SPOOL:
134     case DIRID_SPOOLDRIVERS:  /* FIXME */
135         GetWindowsDirectoryW( buffer, MAX_PATH );
136         strcatW( buffer, Spool );
137         break;
138     case DIRID_USERPROFILE:
139         if (GetEnvironmentVariableW( UserProfile, buffer, MAX_PATH )) break;
140         return get_csidl_dir(CSIDL_PROFILE);
141     case DIRID_LOADER:
142         return C_Root;  /* FIXME */
143     case DIRID_PRINTPROCESSOR:
144         if (!GetPrintProcessorDirectoryW(NULL, NULL, 1, (LPBYTE)buffer, sizeof(buffer), &needed))
145         {
146             WARN( "cannot retrieve print processor directory\n" );
147             return get_unknown_dirid();
148         }
149         break;
150     case DIRID_COLOR:  /* FIXME */
151     default:
152         FIXME( "unknown dirid %d\n", dirid );
153         return get_unknown_dirid();
154     }
155     len = (strlenW(buffer) + 1) * sizeof(WCHAR);
156     if ((str = HeapAlloc( GetProcessHeap(), 0, len ))) memcpy( str, buffer, len );
157     return str;
158 }
159
160 static const WCHAR *get_csidl_dir( DWORD csidl )
161 {
162     WCHAR buffer[MAX_PATH], *str;
163     int len;
164
165     if (!SHGetSpecialFolderPathW( NULL, buffer, csidl, TRUE ))
166     {
167         FIXME( "CSIDL %x not found\n", csidl );
168         return get_unknown_dirid();
169     }
170     len = (strlenW(buffer) + 1) * sizeof(WCHAR);
171     if ((str = HeapAlloc( GetProcessHeap(), 0, len ))) memcpy( str, buffer, len );
172     return str;
173 }
174
175 /* retrieve the string corresponding to a dirid, or NULL if none */
176 const WCHAR *DIRID_get_string( int dirid )
177 {
178     int i;
179
180     if (dirid == DIRID_ABSOLUTE || dirid == DIRID_ABSOLUTE_16BIT) dirid = DIRID_NULL;
181
182     if (dirid >= DIRID_USER)
183     {
184         for (i = 0; i < nb_user_dirids; i++)
185             if (user_dirids[i].id == dirid) return user_dirids[i].str;
186         WARN("user id %d not found\n", dirid );
187         return NULL;
188     }
189     else if (dirid >= MIN_CSIDL_DIRID)
190     {
191         if (dirid > MAX_CSIDL_DIRID) return get_unknown_dirid();
192         dirid -= MIN_CSIDL_DIRID;
193         if (!csidl_dirids[dirid]) csidl_dirids[dirid] = get_csidl_dir( dirid );
194         return csidl_dirids[dirid];
195     }
196     else
197     {
198         if (dirid > MAX_SYSTEM_DIRID) return get_unknown_dirid();
199         if (!system_dirids[dirid]) system_dirids[dirid] = create_system_dirid( dirid );
200         return system_dirids[dirid];
201     }
202 }
203
204 /* store a user dirid string */
205 static BOOL store_user_dirid( HINF hinf, int id, WCHAR *str )
206 {
207     int i;
208
209     for (i = 0; i < nb_user_dirids; i++) if (user_dirids[i].id == id) break;
210
211     if (i < nb_user_dirids) HeapFree( GetProcessHeap(), 0, user_dirids[i].str );
212     else
213     {
214         if (nb_user_dirids >= alloc_user_dirids)
215         {
216             int new_size = max( 32, alloc_user_dirids * 2 );
217
218             struct user_dirid *new;
219
220             if (user_dirids)
221                 new = HeapReAlloc( GetProcessHeap(), 0, user_dirids,
222                                                   new_size * sizeof(*new) );
223             else
224                 new = HeapAlloc( GetProcessHeap(), 0, 
225                                                   new_size * sizeof(*new) );
226
227             if (!new) return FALSE;
228             user_dirids = new;
229             alloc_user_dirids = new_size;
230         }
231         nb_user_dirids++;
232     }
233     user_dirids[i].id  = id;
234     user_dirids[i].str = str;
235     TRACE("id %d -> %s\n", id, debugstr_w(str) );
236     return TRUE;
237 }
238
239
240 /***********************************************************************
241  *              SetupSetDirectoryIdA    (SETUPAPI.@)
242  */
243 BOOL WINAPI SetupSetDirectoryIdA( HINF hinf, DWORD id, PCSTR dir )
244 {
245     UNICODE_STRING dirW;
246     int i;
247
248     if (!id)  /* clear everything */
249     {
250         for (i = 0; i < nb_user_dirids; i++) HeapFree( GetProcessHeap(), 0, user_dirids[i].str );
251         nb_user_dirids = 0;
252         return TRUE;
253     }
254     if (id < DIRID_USER)
255     {
256         SetLastError( ERROR_INVALID_PARAMETER );
257         return FALSE;
258     }
259
260     /* duplicate the string */
261     if (!RtlCreateUnicodeStringFromAsciiz( &dirW, dir ))
262     {
263         SetLastError( ERROR_NOT_ENOUGH_MEMORY );
264         return FALSE;
265     }
266     return store_user_dirid( hinf, id, dirW.Buffer );
267 }
268
269
270 /***********************************************************************
271  *              SetupSetDirectoryIdW    (SETUPAPI.@)
272  */
273 BOOL WINAPI SetupSetDirectoryIdW( HINF hinf, DWORD id, PCWSTR dir )
274 {
275     int i, len;
276     WCHAR *str;
277
278     if (!id)  /* clear everything */
279     {
280         for (i = 0; i < nb_user_dirids; i++) HeapFree( GetProcessHeap(), 0, user_dirids[i].str );
281         nb_user_dirids = 0;
282         return TRUE;
283     }
284     if (id < DIRID_USER)
285     {
286         SetLastError( ERROR_INVALID_PARAMETER );
287         return FALSE;
288     }
289
290     /* duplicate the string */
291     len = (strlenW(dir)+1) * sizeof(WCHAR);
292     if (!(str = HeapAlloc( GetProcessHeap(), 0, len ))) return FALSE;
293     memcpy( str, dir, len );
294     return store_user_dirid( hinf, id, str );
295 }