Use IShellFolder::GetDisplayNameOf instead of SHGetPathFromIDList to
[wine] / dlls / vmm.vxd / vmm.c
1 /*
2  * VMM VxD implementation
3  *
4  * Copyright 1998 Marcus Meissner
5  * Copyright 1998 Ulrich Weigand
6  * Copyright 1998 Patrik Stridvall
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include "config.h"
24 #include "wine/port.h"
25
26 #include <stdarg.h>
27
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winreg.h"
31 #include "winnls.h"
32 #include "ntstatus.h"
33 #include "winternl.h"
34 #include "wine/debug.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(vxd);
37
38 /*
39  * VMM VxDCall service names are (mostly) taken from Stan Mitchell's
40  * "Inside the Windows 95 File System"
41  */
42
43 #define N_VMM_SERVICE 41
44
45 static const char * const VMM_Service_Name[N_VMM_SERVICE] =
46 {
47     "PageReserve",            /* 0x0000 */
48     "PageCommit",             /* 0x0001 */
49     "PageDecommit",           /* 0x0002 */
50     "PagerRegister",          /* 0x0003 */
51     "PagerQuery",             /* 0x0004 */
52     "HeapAllocate",           /* 0x0005 */
53     "ContextCreate",          /* 0x0006 */
54     "ContextDestroy",         /* 0x0007 */
55     "PageAttach",             /* 0x0008 */
56     "PageFlush",              /* 0x0009 */
57     "PageFree",               /* 0x000A */
58     "ContextSwitch",          /* 0x000B */
59     "HeapReAllocate",         /* 0x000C */
60     "PageModifyPermissions",  /* 0x000D */
61     "PageQuery",              /* 0x000E */
62     "GetCurrentContext",      /* 0x000F */
63     "HeapFree",               /* 0x0010 */
64     "RegOpenKey",             /* 0x0011 */
65     "RegCreateKey",           /* 0x0012 */
66     "RegCloseKey",            /* 0x0013 */
67     "RegDeleteKey",           /* 0x0014 */
68     "RegSetValue",            /* 0x0015 */
69     "RegDeleteValue",         /* 0x0016 */
70     "RegQueryValue",          /* 0x0017 */
71     "RegEnumKey",             /* 0x0018 */
72     "RegEnumValue",           /* 0x0019 */
73     "RegQueryValueEx",        /* 0x001A */
74     "RegSetValueEx",          /* 0x001B */
75     "RegFlushKey",            /* 0x001C */
76     "RegQueryInfoKey",        /* 0x001D */
77     "GetDemandPageInfo",      /* 0x001E */
78     "BlockOnID",              /* 0x001F */
79     "SignalID",               /* 0x0020 */
80     "RegLoadKey",             /* 0x0021 */
81     "RegUnLoadKey",           /* 0x0022 */
82     "RegSaveKey",             /* 0x0023 */
83     "RegRemapPreDefKey",      /* 0x0024 */
84     "PageChangePager",        /* 0x0025 */
85     "RegQueryMultipleValues", /* 0x0026 */
86     "RegReplaceKey",          /* 0x0027 */
87     "<KERNEL32.101>"          /* 0x0028 -- What does this do??? */
88 };
89
90 /* PageReserve arena values */
91 #define PR_PRIVATE    0x80000400 /* anywhere in private arena */
92 #define PR_SHARED     0x80060000 /* anywhere in shared arena */
93 #define PR_SYSTEM     0x80080000 /* anywhere in system arena */
94
95 /* PageReserve flags */
96 #define PR_FIXED      0x00000008 /* don't move during PageReAllocate */
97 #define PR_4MEG       0x00000001 /* allocate on 4mb boundary */
98 #define PR_STATIC     0x00000010 /* see PageReserve documentation */
99
100 /* PageCommit default pager handle values */
101 #define PD_ZEROINIT   0x00000001 /* swappable zero-initialized pages */
102 #define PD_NOINIT     0x00000002 /* swappable uninitialized pages */
103 #define PD_FIXEDZERO  0x00000003 /* fixed zero-initialized pages */
104 #define PD_FIXED      0x00000004 /* fixed uninitialized pages */
105
106 /* PageCommit flags */
107 #define PC_FIXED      0x00000008 /* pages are permanently locked */
108 #define PC_LOCKED     0x00000080 /* pages are made present and locked */
109 #define PC_LOCKEDIFDP 0x00000100 /* pages are locked if swap via DOS */
110 #define PC_WRITEABLE  0x00020000 /* make the pages writeable */
111 #define PC_USER       0x00040000 /* make the pages ring 3 accessible */
112 #define PC_INCR       0x40000000 /* increment "pagerdata" each page */
113 #define PC_PRESENT    0x80000000 /* make pages initially present */
114 #define PC_STATIC     0x20000000 /* allow commit in PR_STATIC object */
115 #define PC_DIRTY      0x08000000 /* make pages initially dirty */
116 #define PC_CACHEDIS   0x00100000 /* Allocate uncached pages - new for WDM */
117 #define PC_CACHEWT    0x00080000 /* Allocate write through cache pages - new for WDM */
118 #define PC_PAGEFLUSH  0x00008000 /* Touch device mapped pages on alloc - new for WDM */
119
120 /* PageCommitContig additional flags */
121 #define PCC_ZEROINIT  0x00000001 /* zero-initialize new pages */
122 #define PCC_NOLIN     0x10000000 /* don't map to any linear address */
123
124
125 /* Pop a DWORD from the 32-bit stack */
126 static inline DWORD stack32_pop( CONTEXT86 *context )
127 {
128     DWORD ret = *(DWORD *)context->Esp;
129     context->Esp += sizeof(DWORD);
130     return ret;
131 }
132
133
134 /***********************************************************************
135  *           VxDCall   (VMM.VXD.@)
136  */
137 DWORD WINAPI VMM_VxDCall( DWORD service, CONTEXT86 *context )
138 {
139     static int warned;
140
141     switch ( LOWORD(service) )
142     {
143     case 0x0000: /* PageReserve */
144     {
145         LPVOID address;
146         LPVOID ret;
147         DWORD psize = getpagesize();
148         ULONG page   = (ULONG) stack32_pop( context );
149         ULONG npages = (ULONG) stack32_pop( context );
150         ULONG flags  = (ULONG) stack32_pop( context );
151
152         TRACE("PageReserve: page: %08lx, npages: %08lx, flags: %08lx partial stub!\n",
153               page, npages, flags );
154
155         if ( page == PR_SYSTEM ) {
156           ERR("Can't reserve ring 1 memory\n");
157           return -1;
158         }
159         /* FIXME: This has to be handled separately for the separate
160            address-spaces we now have */
161         if ( page == PR_PRIVATE || page == PR_SHARED ) page = 0;
162         /* FIXME: Handle flags in some way */
163         address = (LPVOID )(page * psize);
164         ret = VirtualAlloc ( address, ( npages * psize ), MEM_RESERVE, 0 );
165         TRACE("PageReserve: returning: %08lx\n", (DWORD )ret );
166         if ( ret == NULL )
167           return -1;
168         else
169           return (DWORD )ret;
170     }
171
172     case 0x0001: /* PageCommit */
173     {
174         LPVOID address;
175         LPVOID ret;
176         DWORD virt_perm;
177         DWORD psize = getpagesize();
178         ULONG page   = (ULONG) stack32_pop( context );
179         ULONG npages = (ULONG) stack32_pop( context );
180         ULONG hpd  = (ULONG) stack32_pop( context );
181         ULONG pagerdata   = (ULONG) stack32_pop( context );
182         ULONG flags  = (ULONG) stack32_pop( context );
183
184         TRACE("PageCommit: page: %08lx, npages: %08lx, hpd: %08lx pagerdata: "
185               "%08lx, flags: %08lx partial stub\n",
186               page, npages, hpd, pagerdata, flags );
187
188         if ( flags & PC_USER )
189           if ( flags & PC_WRITEABLE )
190             virt_perm = PAGE_EXECUTE_READWRITE;
191           else
192             virt_perm = PAGE_EXECUTE_READ;
193         else
194           virt_perm = PAGE_NOACCESS;
195
196         address = (LPVOID )(page * psize);
197         ret = VirtualAlloc ( address, ( npages * psize ), MEM_COMMIT, virt_perm );
198         TRACE("PageCommit: Returning: %08lx\n", (DWORD )ret );
199         return (DWORD )ret;
200
201     }
202
203     case 0x0002: /* PageDecommit */
204     {
205         LPVOID address;
206         BOOL ret;
207         DWORD psize = getpagesize();
208         ULONG page = (ULONG) stack32_pop( context );
209         ULONG npages = (ULONG) stack32_pop( context );
210         ULONG flags = (ULONG) stack32_pop( context );
211
212         TRACE("PageDecommit: page: %08lx, npages: %08lx, flags: %08lx partial stub\n",
213               page, npages, flags );
214         address = (LPVOID )( page * psize );
215         ret = VirtualFree ( address, ( npages * psize ), MEM_DECOMMIT );
216         TRACE("PageDecommit: Returning: %s\n", ret ? "TRUE" : "FALSE" );
217         return ret;
218     }
219
220     case 0x000d: /* PageModifyPermissions */
221     {
222         DWORD pg_old_perm;
223         DWORD pg_new_perm;
224         DWORD virt_old_perm;
225         DWORD virt_new_perm;
226         MEMORY_BASIC_INFORMATION mbi;
227         LPVOID address;
228         DWORD psize = getpagesize();
229         ULONG page = stack32_pop ( context );
230         ULONG npages = stack32_pop ( context );
231         ULONG permand = stack32_pop ( context );
232         ULONG permor = stack32_pop ( context );
233
234         TRACE("PageModifyPermissions %08lx %08lx %08lx %08lx partial stub\n",
235               page, npages, permand, permor );
236         address = (LPVOID )( page * psize );
237
238         VirtualQuery ( address, &mbi, sizeof ( MEMORY_BASIC_INFORMATION ));
239         virt_old_perm = mbi.Protect;
240
241         switch ( virt_old_perm & mbi.Protect ) {
242         case PAGE_READONLY:
243         case PAGE_EXECUTE:
244         case PAGE_EXECUTE_READ:
245           pg_old_perm = PC_USER;
246           break;
247         case PAGE_READWRITE:
248         case PAGE_WRITECOPY:
249         case PAGE_EXECUTE_READWRITE:
250         case PAGE_EXECUTE_WRITECOPY:
251           pg_old_perm = PC_USER | PC_WRITEABLE;
252           break;
253         case PAGE_NOACCESS:
254         default:
255           pg_old_perm = 0;
256           break;
257         }
258         pg_new_perm = pg_old_perm;
259         pg_new_perm &= permand & ~PC_STATIC;
260         pg_new_perm |= permor  & ~PC_STATIC;
261
262         virt_new_perm = ( virt_old_perm )  & ~0xff;
263         if ( pg_new_perm & PC_USER )
264         {
265           if ( pg_new_perm & PC_WRITEABLE )
266             virt_new_perm |= PAGE_EXECUTE_READWRITE;
267           else
268             virt_new_perm |= PAGE_EXECUTE_READ;
269         }
270
271         if ( ! VirtualProtect ( address, ( npages * psize ), virt_new_perm, &virt_old_perm ) ) {
272           ERR("Can't change page permissions for %08lx\n", (DWORD )address );
273           return 0xffffffff;
274         }
275         TRACE("Returning: %08lx\n", pg_old_perm );
276         return pg_old_perm;
277     }
278
279     case 0x000a: /* PageFree */
280     {
281         BOOL ret;
282         LPVOID hmem = (LPVOID) stack32_pop( context );
283         DWORD flags = (DWORD ) stack32_pop( context );
284
285         TRACE("PageFree: hmem: %08lx, flags: %08lx partial stub\n",
286               (DWORD )hmem, flags );
287
288         ret = VirtualFree ( hmem, 0, MEM_RELEASE );
289         TRACE("Returning: %d\n", ret );
290         return ret;
291     }
292
293     case 0x0011:  /* RegOpenKey */
294         stack32_pop( context ); /* kkey */
295         stack32_pop( context ); /* lpszSubKey */
296         stack32_pop( context ); /* retkey */
297         /* return RegOpenKeyExA( hkey, lpszSubKey, 0, KEY_ALL_ACCESS, retkey ); */
298         if (!warned)
299         {
300             ERR( "Using the native Win95 advapi32.dll is no longer supported.\n" );
301             ERR( "Please configure advapi32 to builtin.\n" );
302             warned++;
303         }
304         return ERROR_CALL_NOT_IMPLEMENTED;
305
306     case 0x0012:  /* RegCreateKey */
307         stack32_pop( context ); /* hkey */
308         stack32_pop( context ); /* lpszSubKey */
309         stack32_pop( context ); /* retkey */
310         /* return RegCreateKeyA( hkey, lpszSubKey, retkey ); */
311         if (!warned)
312         {
313             ERR( "Using the native Win95 advapi32.dll is no longer supported.\n" );
314             ERR( "Please configure advapi32 to builtin.\n" );
315             warned++;
316         }
317         return ERROR_CALL_NOT_IMPLEMENTED;
318
319     case 0x0013:  /* RegCloseKey */
320         stack32_pop( context ); /* hkey */
321         /* return RegCloseKey( hkey ); */
322         return ERROR_CALL_NOT_IMPLEMENTED;
323
324     case 0x0014:  /* RegDeleteKey */
325         stack32_pop( context ); /* hkey */
326         stack32_pop( context ); /* lpszSubKey */
327         /* return RegDeleteKeyA( hkey, lpszSubKey ); */
328         return ERROR_CALL_NOT_IMPLEMENTED;
329
330     case 0x0015:  /* RegSetValue */
331         stack32_pop( context ); /* hkey */
332         stack32_pop( context ); /* lpszSubKey */
333         stack32_pop( context ); /* dwType */
334         stack32_pop( context ); /* lpszData */
335         stack32_pop( context ); /* cbData */
336         /* return RegSetValueA( hkey, lpszSubKey, dwType, lpszData, cbData ); */
337         return ERROR_CALL_NOT_IMPLEMENTED;
338
339     case 0x0016:  /* RegDeleteValue */
340         stack32_pop( context ); /* hkey */
341         stack32_pop( context ); /* lpszValue */
342         /* return RegDeleteValueA( hkey, lpszValue ); */
343         return ERROR_CALL_NOT_IMPLEMENTED;
344
345     case 0x0017:  /* RegQueryValue */
346         stack32_pop( context ); /* hkey */
347         stack32_pop( context ); /* lpszSubKey */
348         stack32_pop( context ); /* lpszData */
349         stack32_pop( context ); /* lpcbData */
350         /* return RegQueryValueA( hkey, lpszSubKey, lpszData, lpcbData ); */
351         return ERROR_CALL_NOT_IMPLEMENTED;
352
353     case 0x0018:  /* RegEnumKey */
354         stack32_pop( context ); /* hkey */
355         stack32_pop( context ); /* iSubkey */
356         stack32_pop( context ); /* lpszName */
357         stack32_pop( context ); /* lpcchName */
358         /* return RegEnumKeyA( hkey, iSubkey, lpszName, lpcchName ); */
359         return ERROR_CALL_NOT_IMPLEMENTED;
360
361     case 0x0019:  /* RegEnumValue */
362         stack32_pop( context ); /* hkey */
363         stack32_pop( context ); /* iValue */
364         stack32_pop( context ); /* lpszValue */
365         stack32_pop( context ); /* lpcchValue */
366         stack32_pop( context ); /* lpReserved */
367         stack32_pop( context ); /* lpdwType */
368         stack32_pop( context ); /* lpbData */
369         stack32_pop( context ); /* lpcbData */
370         /* return RegEnumValueA( hkey, iValue, lpszValue, lpcchValue, lpReserved, lpdwType, lpbData, lpcbData ); */
371         return ERROR_CALL_NOT_IMPLEMENTED;
372
373     case 0x001A:  /* RegQueryValueEx */
374         stack32_pop( context ); /* hkey */
375         stack32_pop( context ); /* lpszValue */
376         stack32_pop( context ); /* lpReserved */
377         stack32_pop( context ); /* lpdwType */
378         stack32_pop( context ); /* lpbData */
379         stack32_pop( context ); /* lpcbData */
380         /* return RegQueryValueExA( hkey, lpszValue, lpReserved, lpdwType, lpbData, lpcbData ); */
381         return ERROR_CALL_NOT_IMPLEMENTED;
382
383     case 0x001B:  /* RegSetValueEx */
384         stack32_pop( context ); /* hkey */
385         stack32_pop( context ); /* lpszValue */
386         stack32_pop( context ); /* dwReserved */
387         stack32_pop( context ); /* dwType */
388         stack32_pop( context ); /* lpbData */
389         stack32_pop( context ); /* cbData */
390         /* return RegSetValueExA( hkey, lpszValue, dwReserved, dwType, lpbData, cbData ); */
391         return ERROR_CALL_NOT_IMPLEMENTED;
392
393     case 0x001C:  /* RegFlushKey */
394         stack32_pop( context ); /* hkey */
395         /* return RegFlushKey( hkey ); */
396         return ERROR_CALL_NOT_IMPLEMENTED;
397
398     case 0x001D:  /* RegQueryInfoKey */
399         /* NOTE: This VxDCall takes only a subset of the parameters that the
400                  corresponding Win32 API call does. The implementation in Win95
401                  ADVAPI32 sets all output parameters not mentioned here to zero. */
402         stack32_pop( context ); /* hkey */
403         stack32_pop( context ); /* lpcSubKeys */
404         stack32_pop( context ); /* lpcchMaxSubKey */
405         stack32_pop( context ); /* lpcValues */
406         stack32_pop( context ); /* lpcchMaxValueName */
407         stack32_pop( context ); /* lpcchMaxValueData */
408         /* return RegQueryInfoKeyA( hkey, lpcSubKeys, lpcchMaxSubKey, lpcValues, lpcchMaxValueName, lpcchMaxValueData ); */
409         return ERROR_CALL_NOT_IMPLEMENTED;
410
411     case 0x001e: /* GetDemandPageInfo */
412     {
413          DWORD dinfo = (DWORD)stack32_pop( context );
414          DWORD flags = (DWORD)stack32_pop( context );
415
416          /* GetDemandPageInfo is supposed to fill out the struct at
417           * "dinfo" with various low-level memory management information.
418           * Apps are certainly not supposed to call this, although it's
419           * demoed and documented by Pietrek on pages 441-443 of "Windows
420           * 95 System Programming Secrets" if any program needs a real
421           * implementation of this.
422           */
423
424          FIXME("GetDemandPageInfo(%08lx %08lx): stub!\n", dinfo, flags);
425
426          return 0;
427     }
428
429     case 0x0021:  /* RegLoadKey */
430     {
431         HKEY    hkey       = (HKEY)  stack32_pop( context );
432         LPCSTR  lpszSubKey = (LPCSTR)stack32_pop( context );
433         LPCSTR  lpszFile   = (LPCSTR)stack32_pop( context );
434         FIXME("RegLoadKey(%p,%s,%s): stub\n",hkey, debugstr_a(lpszSubKey), debugstr_a(lpszFile));
435         return ERROR_CALL_NOT_IMPLEMENTED;
436     }
437
438     case 0x0022:  /* RegUnLoadKey */
439     {
440         HKEY    hkey       = (HKEY)  stack32_pop( context );
441         LPCSTR  lpszSubKey = (LPCSTR)stack32_pop( context );
442         FIXME("RegUnLoadKey(%p,%s): stub\n",hkey, debugstr_a(lpszSubKey));
443         return ERROR_CALL_NOT_IMPLEMENTED;
444     }
445
446     case 0x0023:  /* RegSaveKey */
447     {
448         HKEY    hkey       = (HKEY)  stack32_pop( context );
449         LPCSTR  lpszFile   = (LPCSTR)stack32_pop( context );
450         LPSECURITY_ATTRIBUTES sa = (LPSECURITY_ATTRIBUTES)stack32_pop( context );
451         FIXME("RegSaveKey(%p,%s,%p): stub\n",hkey, debugstr_a(lpszFile),sa);
452         return ERROR_CALL_NOT_IMPLEMENTED;
453     }
454
455 #if 0 /* Functions are not yet implemented in misc/registry.c */
456     case 0x0024:  /* RegRemapPreDefKey */
457     case 0x0026:  /* RegQueryMultipleValues */
458 #endif
459
460     case 0x0027:  /* RegReplaceKey */
461     {
462         HKEY    hkey       = (HKEY)  stack32_pop( context );
463         LPCSTR  lpszSubKey = (LPCSTR)stack32_pop( context );
464         LPCSTR  lpszNewFile= (LPCSTR)stack32_pop( context );
465         LPCSTR  lpszOldFile= (LPCSTR)stack32_pop( context );
466         FIXME("RegReplaceKey(%p,%s,%s,%s): stub\n", hkey, debugstr_a(lpszSubKey),
467               debugstr_a(lpszNewFile),debugstr_a(lpszOldFile));
468         return ERROR_CALL_NOT_IMPLEMENTED;
469     }
470
471     default:
472         if (LOWORD(service) < N_VMM_SERVICE)
473             FIXME( "Unimplemented service %s (%08lx)\n",
474                    VMM_Service_Name[LOWORD(service)], service);
475         else
476             FIXME( "Unknown service %08lx\n", service);
477         return 0xffffffff;  /* FIXME */
478     }
479 }