Use the right buffer size in SYSPARAMS_Load instead of some random
[wine] / win32 / device.c
1 /*
2  * Win32 device functions
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 <stdlib.h>
27 #ifdef HAVE_UNISTD_H
28 # include <unistd.h>
29 #endif
30 #include <sys/types.h>
31 #include <string.h>
32 #include <stdarg.h>
33 #include <time.h>
34
35 #include "windef.h"
36 #include "winbase.h"
37 #include "winreg.h"
38 #include "winerror.h"
39 #include "file.h"
40 #include "winioctl.h"
41 #include "winnt.h"
42 #include "msdos.h"
43 #include "miscemu.h"
44 #include "stackframe.h"
45 #include "wine/server.h"
46 #include "wine/debug.h"
47 #include "callback.h"
48
49 WINE_DEFAULT_DEBUG_CHANNEL(file);
50
51
52 static BOOL DeviceIo_VTDAPI(DWORD dwIoControlCode,
53                               LPVOID lpvInBuffer, DWORD cbInBuffer,
54                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
55                               LPDWORD lpcbBytesReturned,
56                               LPOVERLAPPED lpOverlapped);
57 static BOOL DeviceIo_MONODEBG(DWORD dwIoControlCode,
58                               LPVOID lpvInBuffer, DWORD cbInBuffer,
59                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
60                               LPDWORD lpcbBytesReturned,
61                               LPOVERLAPPED lpOverlapped);
62 static BOOL DeviceIo_MMDEVLDR(DWORD dwIoControlCode,
63                               LPVOID lpvInBuffer, DWORD cbInBuffer,
64                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
65                               LPDWORD lpcbBytesReturned,
66                               LPOVERLAPPED lpOverlapped);
67
68 static DWORD VxDCall_VMM( DWORD service, CONTEXT86 *context );
69
70 static BOOL DeviceIo_IFSMgr(DWORD dwIoControlCode,
71                               LPVOID lpvInBuffer, DWORD cbInBuffer,
72                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
73                               LPDWORD lpcbBytesReturned,
74                               LPOVERLAPPED lpOverlapped);
75
76 static BOOL DeviceIo_VCD(DWORD dwIoControlCode,
77                               LPVOID lpvInBuffer, DWORD cbInBuffer,
78                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
79                               LPDWORD lpcbBytesReturned,
80                               LPOVERLAPPED lpOverlapped);
81
82 static DWORD VxDCall_VWin32( DWORD service, CONTEXT86 *context );
83
84 static BOOL DeviceIo_VWin32(DWORD dwIoControlCode,
85                               LPVOID lpvInBuffer, DWORD cbInBuffer,
86                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
87                               LPDWORD lpcbBytesReturned,
88                               LPOVERLAPPED lpOverlapped);
89
90 static BOOL DeviceIo_PCCARD (DWORD dwIoControlCode,
91                               LPVOID lpvInBuffer, DWORD cbInBuffer,
92                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
93                               LPDWORD lpcbBytesReturned,
94                               LPOVERLAPPED lpOverlapped);
95
96 static BOOL DeviceIo_HASP (DWORD dwIoControlCode,
97                               LPVOID lpvInBuffer, DWORD cbInBuffer,
98                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
99                               LPDWORD lpcbBytesReturned,
100                               LPOVERLAPPED lpOverlapped);
101 /*
102  * VxD names are taken from the Win95 DDK
103  */
104
105 struct VxDInfo
106 {
107     LPCSTR  name;
108     WORD    id;
109     DWORD (*vxdcall)(DWORD, CONTEXT86 *);
110     BOOL  (*deviceio)(DWORD, LPVOID, DWORD,
111                         LPVOID, DWORD, LPDWORD, LPOVERLAPPED);
112 };
113
114 static const struct VxDInfo VxDList[] =
115 {
116     /* Standard VxD IDs */
117     { "VMM",      0x0001, VxDCall_VMM, NULL },
118     { "DEBUG",    0x0002, NULL, NULL },
119     { "VPICD",    0x0003, NULL, NULL },
120     { "VDMAD",    0x0004, NULL, NULL },
121     { "VTD",      0x0005, NULL, NULL },
122     { "V86MMGR",  0x0006, NULL, NULL },
123     { "PAGESWAP", 0x0007, NULL, NULL },
124     { "PARITY",   0x0008, NULL, NULL },
125     { "REBOOT",   0x0009, NULL, NULL },
126     { "VDD",      0x000A, NULL, NULL },
127     { "VSD",      0x000B, NULL, NULL },
128     { "VMD",      0x000C, NULL, NULL },
129     { "VKD",      0x000D, NULL, NULL },
130     { "VCD",      0x000E, NULL, DeviceIo_VCD },
131     { "VPD",      0x000F, NULL, NULL },
132     { "BLOCKDEV", 0x0010, NULL, NULL },
133     { "VMCPD",    0x0011, NULL, NULL },
134     { "EBIOS",    0x0012, NULL, NULL },
135     { "BIOSXLAT", 0x0013, NULL, NULL },
136     { "VNETBIOS", 0x0014, NULL, NULL },
137     { "DOSMGR",   0x0015, NULL, NULL },
138     { "WINLOAD",  0x0016, NULL, NULL },
139     { "SHELL",    0x0017, NULL, NULL },
140     { "VMPOLL",   0x0018, NULL, NULL },
141     { "VPROD",    0x0019, NULL, NULL },
142     { "DOSNET",   0x001A, NULL, NULL },
143     { "VFD",      0x001B, NULL, NULL },
144     { "VDD2",     0x001C, NULL, NULL },
145     { "WINDEBUG", 0x001D, NULL, NULL },
146     { "TSRLOAD",  0x001E, NULL, NULL },
147     { "BIOSHOOK", 0x001F, NULL, NULL },
148     { "INT13",    0x0020, NULL, NULL },
149     { "PAGEFILE", 0x0021, NULL, NULL },
150     { "SCSI",     0x0022, NULL, NULL },
151     { "MCA_POS",  0x0023, NULL, NULL },
152     { "SCSIFD",   0x0024, NULL, NULL },
153     { "VPEND",    0x0025, NULL, NULL },
154     { "VPOWERD",  0x0026, NULL, NULL },
155     { "VXDLDR",   0x0027, NULL, NULL },
156     { "NDIS",     0x0028, NULL, NULL },
157     { "BIOS_EXT", 0x0029, NULL, NULL },
158     { "VWIN32",   0x002A, VxDCall_VWin32, DeviceIo_VWin32 },
159     { "VCOMM",    0x002B, NULL, NULL },
160     { "SPOOLER",  0x002C, NULL, NULL },
161     { "WIN32S",   0x002D, NULL, NULL },
162     { "DEBUGCMD", 0x002E, NULL, NULL },
163
164     { "VNB",      0x0031, NULL, NULL },
165     { "SERVER",   0x0032, NULL, NULL },
166     { "CONFIGMG", 0x0033, NULL, NULL },
167     { "DWCFGMG",  0x0034, NULL, NULL },
168     { "SCSIPORT", 0x0035, NULL, NULL },
169     { "VFBACKUP", 0x0036, NULL, NULL },
170     { "ENABLE",   0x0037, NULL, NULL },
171     { "VCOND",    0x0038, NULL, NULL },
172
173     { "EFAX",     0x003A, NULL, NULL },
174     { "DSVXD",    0x003B, NULL, NULL },
175     { "ISAPNP",   0x003C, NULL, NULL },
176     { "BIOS",     0x003D, NULL, NULL },
177     { "WINSOCK",  0x003E, NULL, NULL },
178     { "WSOCK",    0x003E, NULL, NULL },
179     { "WSIPX",    0x003F, NULL, NULL },
180     { "IFSMgr",   0x0040, NULL, DeviceIo_IFSMgr },
181     { "VCDFSD",   0x0041, NULL, NULL },
182     { "MRCI2",    0x0042, NULL, NULL },
183     { "PCI",      0x0043, NULL, NULL },
184     { "PELOADER", 0x0044, NULL, NULL },
185     { "EISA",     0x0045, NULL, NULL },
186     { "DRAGCLI",  0x0046, NULL, NULL },
187     { "DRAGSRV",  0x0047, NULL, NULL },
188     { "PERF",     0x0048, NULL, NULL },
189     { "AWREDIR",  0x0049, NULL, NULL },
190
191     /* Far East support */
192     { "ETEN",     0x0060, NULL, NULL },
193     { "CHBIOS",   0x0061, NULL, NULL },
194     { "VMSGD",    0x0062, NULL, NULL },
195     { "VPPID",    0x0063, NULL, NULL },
196     { "VIME",     0x0064, NULL, NULL },
197     { "VHBIOSD",  0x0065, NULL, NULL },
198
199     /* Multimedia OEM IDs */
200     { "VTDAPI",   0x0442, NULL, DeviceIo_VTDAPI },
201     { "MMDEVLDR", 0x044A, NULL, DeviceIo_MMDEVLDR },
202
203     /* Network Device IDs */
204     { "VNetSup",  0x0480, NULL, NULL },
205     { "VRedir",   0x0481, NULL, NULL },
206     { "VBrowse",  0x0482, NULL, NULL },
207     { "VSHARE",   0x0483, NULL, NULL },
208     { "IFSMgr",   0x0484, NULL, NULL },
209     { "MEMPROBE", 0x0485, NULL, NULL },
210     { "VFAT",     0x0486, NULL, NULL },
211     { "NWLINK",   0x0487, NULL, NULL },
212     { "VNWLINK",  0x0487, NULL, NULL },
213     { "NWSUP",    0x0487, NULL, NULL },
214     { "VTDI",     0x0488, NULL, NULL },
215     { "VIP",      0x0489, NULL, NULL },
216     { "VTCP",     0x048A, NULL, NULL },
217     { "VCache",   0x048B, NULL, NULL },
218     { "VUDP",     0x048C, NULL, NULL },
219     { "VAsync",   0x048D, NULL, NULL },
220     { "NWREDIR",  0x048E, NULL, NULL },
221     { "STAT80",   0x048F, NULL, NULL },
222     { "SCSIPORT", 0x0490, NULL, NULL },
223     { "FILESEC",  0x0491, NULL, NULL },
224     { "NWSERVER", 0x0492, NULL, NULL },
225     { "SECPROV",  0x0493, NULL, NULL },
226     { "NSCL",     0x0494, NULL, NULL },
227     { "WSTCP",    0x0495, NULL, NULL },
228     { "NDIS2SUP", 0x0496, NULL, NULL },
229     { "MSODISUP", 0x0497, NULL, NULL },
230     { "Splitter", 0x0498, NULL, NULL },
231     { "PPP",      0x0499, NULL, NULL },
232     { "VDHCP",    0x049A, NULL, NULL },
233     { "VNBT",     0x049B, NULL, NULL },
234     { "LOGGER",   0x049D, NULL, NULL },
235     { "EFILTER",  0x049E, NULL, NULL },
236     { "FFILTER",  0x049F, NULL, NULL },
237     { "TFILTER",  0x04A0, NULL, NULL },
238     { "AFILTER",  0x04A1, NULL, NULL },
239     { "IRLAMP",   0x04A2, NULL, NULL },
240
241     { "PCCARD",   0x097C, NULL, DeviceIo_PCCARD },
242     { "HASP95",   0x3721, NULL, DeviceIo_HASP },
243
244     /* WINE additions, ids unknown */
245     { "MONODEBG.VXD", 0x4242, NULL, DeviceIo_MONODEBG },
246
247     { NULL,       0,      NULL, NULL }
248 };
249
250 /*
251  * VMM VxDCall service names are (mostly) taken from Stan Mitchell's
252  * "Inside the Windows 95 File System"
253  */
254
255 #define N_VMM_SERVICE 41
256
257 LPCSTR VMM_Service_Name[N_VMM_SERVICE] =
258 {
259     "PageReserve",            /* 0x0000 */
260     "PageCommit",             /* 0x0001 */
261     "PageDecommit",           /* 0x0002 */
262     "PagerRegister",          /* 0x0003 */
263     "PagerQuery",             /* 0x0004 */
264     "HeapAllocate",           /* 0x0005 */
265     "ContextCreate",          /* 0x0006 */
266     "ContextDestroy",         /* 0x0007 */
267     "PageAttach",             /* 0x0008 */
268     "PageFlush",              /* 0x0009 */
269     "PageFree",               /* 0x000A */
270     "ContextSwitch",          /* 0x000B */
271     "HeapReAllocate",         /* 0x000C */
272     "PageModifyPermissions",  /* 0x000D */
273     "PageQuery",              /* 0x000E */
274     "GetCurrentContext",      /* 0x000F */
275     "HeapFree",               /* 0x0010 */
276     "RegOpenKey",             /* 0x0011 */
277     "RegCreateKey",           /* 0x0012 */
278     "RegCloseKey",            /* 0x0013 */
279     "RegDeleteKey",           /* 0x0014 */
280     "RegSetValue",            /* 0x0015 */
281     "RegDeleteValue",         /* 0x0016 */
282     "RegQueryValue",          /* 0x0017 */
283     "RegEnumKey",             /* 0x0018 */
284     "RegEnumValue",           /* 0x0019 */
285     "RegQueryValueEx",        /* 0x001A */
286     "RegSetValueEx",          /* 0x001B */
287     "RegFlushKey",            /* 0x001C */
288     "RegQueryInfoKey",        /* 0x001D */
289     "GetDemandPageInfo",      /* 0x001E */
290     "BlockOnID",              /* 0x001F */
291     "SignalID",               /* 0x0020 */
292     "RegLoadKey",             /* 0x0021 */
293     "RegUnLoadKey",           /* 0x0022 */
294     "RegSaveKey",             /* 0x0023 */
295     "RegRemapPreDefKey",      /* 0x0024 */
296     "PageChangePager",        /* 0x0025 */
297     "RegQueryMultipleValues", /* 0x0026 */
298     "RegReplaceKey",          /* 0x0027 */
299     "<KERNEL32.101>"          /* 0x0028 -- What does this do??? */
300 };
301
302 /* PageReserve arena values */
303 #define PR_PRIVATE  0x80000400  /* anywhere in private arena */
304 #define PR_SHARED   0x80060000  /* anywhere in shared arena */
305 #define PR_SYSTEM   0x80080000  /* anywhere in system arena */
306
307 /* PageReserve flags */
308 #define PR_FIXED    0x00000008  /* don't move during PageReAllocate */
309 #define PR_4MEG     0x00000001  /* allocate on 4mb boundary */
310 #define PR_STATIC   0x00000010  /* see PageReserve documentation */
311
312 /* PageCommit default pager handle values */
313 #define PD_ZEROINIT 0x00000001  /* swappable zero-initialized pages */
314 #define PD_NOINIT   0x00000002  /* swappable uninitialized pages */
315 #define PD_FIXEDZERO    0x00000003  /* fixed zero-initialized pages */
316 #define PD_FIXED    0x00000004  /* fixed uninitialized pages */
317
318 /* PageCommit flags */
319 #define PC_FIXED    0x00000008  /* pages are permanently locked */
320 #define PC_LOCKED   0x00000080  /* pages are made present and locked */
321 #define PC_LOCKEDIFDP   0x00000100  /* pages are locked if swap via DOS */
322 #define PC_WRITEABLE    0x00020000  /* make the pages writeable */
323 #define PC_USER     0x00040000  /* make the pages ring 3 accessible */
324 #define PC_INCR     0x40000000  /* increment "pagerdata" each page */
325 #define PC_PRESENT  0x80000000  /* make pages initially present */
326 #define PC_STATIC   0x20000000  /* allow commit in PR_STATIC object */
327 #define PC_DIRTY    0x08000000  /* make pages initially dirty */
328 #define PC_CACHEDIS 0x00100000  /* Allocate uncached pages - new for WDM */
329 #define PC_CACHEWT  0x00080000  /* Allocate write through cache pages - new for WDM */
330 #define PC_PAGEFLUSH 0x00008000 /* Touch device mapped pages on alloc - new for WDM */
331
332 /* PageCommitContig additional flags */
333 #define PCC_ZEROINIT    0x00000001  /* zero-initialize new pages */
334 #define PCC_NOLIN   0x10000000  /* don't map to any linear address */
335
336
337
338 HANDLE DEVICE_Open( LPCWSTR filenameW, DWORD access, LPSECURITY_ATTRIBUTES sa )
339 {
340     const struct VxDInfo *info;
341     char filename[MAX_PATH];
342
343     if (!WideCharToMultiByte(CP_ACP, 0, filenameW, -1, filename, MAX_PATH, NULL, NULL))
344     {
345         SetLastError( ERROR_FILE_NOT_FOUND );
346         return 0;
347     }
348
349     for (info = VxDList; info->name; info++)
350         if (!strncasecmp( info->name, filename, strlen(info->name) ))
351             return FILE_CreateDevice( info->id | 0x10000, access, sa );
352
353     FIXME( "Unknown/unsupported VxD %s. Try setting Windows version to 'nt40' or 'win31'.\n",
354            filename);
355     SetLastError( ERROR_FILE_NOT_FOUND );
356     return 0;
357 }
358
359 static DWORD DEVICE_GetClientID( HANDLE handle )
360 {
361     DWORD       ret = 0;
362     SERVER_START_REQ( get_device_id )
363     {
364         req->handle = handle;
365         if (!wine_server_call( req )) ret = reply->id;
366     }
367     SERVER_END_REQ;
368     return ret;
369 }
370
371 static const struct VxDInfo *DEVICE_GetInfo( DWORD clientID )
372 {
373     const struct VxDInfo *info = NULL;
374
375     if (clientID & 0x10000)
376     {
377         for (info = VxDList; info->name; info++)
378             if (info->id == LOWORD(clientID)) break;
379     }
380     return info;
381 }
382
383 /****************************************************************************
384  *              DeviceIoControl (KERNEL32.@)
385  * This is one of those big ugly nasty procedure which can do
386  * a million and one things when it comes to devices. It can also be
387  * used for VxD communication.
388  *
389  * A return value of FALSE indicates that something has gone wrong which
390  * GetLastError can decipher.
391  */
392 BOOL WINAPI DeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode,
393                               LPVOID lpvInBuffer, DWORD cbInBuffer,
394                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
395                               LPDWORD lpcbBytesReturned,
396                               LPOVERLAPPED lpOverlapped)
397 {
398         DWORD clientID;
399
400         TRACE( "(%p,%ld,%p,%ld,%p,%ld,%p,%p)\n",
401                hDevice,dwIoControlCode,lpvInBuffer,cbInBuffer,
402                lpvOutBuffer,cbOutBuffer,lpcbBytesReturned,lpOverlapped  );
403
404         if (!(clientID = DEVICE_GetClientID( hDevice )))
405         {
406                 SetLastError( ERROR_INVALID_PARAMETER );
407                 return FALSE;
408         }
409
410         /* Check if this is a user defined control code for a VxD */
411         if( HIWORD( dwIoControlCode ) == 0 )
412         {
413                 const struct VxDInfo *info;
414                 if (!(info = DEVICE_GetInfo( clientID )))
415                 {
416                         FIXME( "No device found for id %lx\n", clientID);
417                 }
418                 else if ( info->deviceio )
419                 {
420                         return info->deviceio( dwIoControlCode,
421                                         lpvInBuffer, cbInBuffer,
422                                         lpvOutBuffer, cbOutBuffer,
423                                         lpcbBytesReturned, lpOverlapped );
424                 }
425                 else
426                 {
427                         FIXME( "Unimplemented control %ld for VxD device %s\n",
428                                dwIoControlCode, info->name ? info->name : "???" );
429                         /* FIXME: this is for invalid calls on W98SE,
430                          * but maybe we should use ERROR_CALL_NOT_IMPLEMENTED
431                          * instead ? */
432                         SetLastError( ERROR_INVALID_FUNCTION );
433                 }
434         }
435         else
436         {
437                 char str[3];
438
439                 strcpy(str,  "A:");
440                 str[0] += LOBYTE(clientID);
441                 if (GetDriveTypeA(str) == DRIVE_CDROM)
442                     return CDROM_DeviceIoControl(clientID, hDevice, dwIoControlCode, lpvInBuffer, cbInBuffer,
443                                                  lpvOutBuffer, cbOutBuffer, lpcbBytesReturned,
444                                                  lpOverlapped);
445                 else switch( dwIoControlCode )
446                 {
447                 case FSCTL_DELETE_REPARSE_POINT:
448                 case FSCTL_DISMOUNT_VOLUME:
449                 case FSCTL_GET_COMPRESSION:
450                 case FSCTL_GET_REPARSE_POINT:
451                 case FSCTL_LOCK_VOLUME:
452                 case FSCTL_QUERY_ALLOCATED_RANGES:
453                 case FSCTL_SET_COMPRESSION:
454                 case FSCTL_SET_REPARSE_POINT:
455                 case FSCTL_SET_SPARSE:
456                 case FSCTL_SET_ZERO_DATA:
457                 case FSCTL_UNLOCK_VOLUME:
458                 case IOCTL_DISK_CHECK_VERIFY:
459                 case IOCTL_DISK_EJECT_MEDIA:
460                 case IOCTL_DISK_FORMAT_TRACKS:
461                 case IOCTL_DISK_GET_DRIVE_GEOMETRY:
462                 case IOCTL_DISK_GET_DRIVE_LAYOUT:
463                 case IOCTL_DISK_GET_MEDIA_TYPES:
464                 case IOCTL_DISK_GET_PARTITION_INFO:
465                 case IOCTL_DISK_LOAD_MEDIA:
466                 case IOCTL_DISK_MEDIA_REMOVAL:
467                 case IOCTL_DISK_PERFORMANCE:
468                 case IOCTL_DISK_REASSIGN_BLOCKS:
469                 case IOCTL_DISK_SET_DRIVE_LAYOUT:
470                 case IOCTL_DISK_SET_PARTITION_INFO:
471                 case IOCTL_DISK_VERIFY:
472                 case IOCTL_SERIAL_LSRMST_INSERT:
473                 case IOCTL_STORAGE_CHECK_VERIFY:
474                 case IOCTL_STORAGE_EJECT_MEDIA:
475                 case IOCTL_STORAGE_GET_MEDIA_TYPES:
476                 case IOCTL_STORAGE_LOAD_MEDIA:
477                 case IOCTL_STORAGE_MEDIA_REMOVAL:
478                         FIXME( "unimplemented dwIoControlCode=%08lx\n", dwIoControlCode);
479                         SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
480                         return FALSE;
481                         break;
482                 default:
483                         FIXME( "ignored dwIoControlCode=%08lx\n",dwIoControlCode);
484                         SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
485                         return FALSE;
486                         break;
487                 }
488         }
489         return FALSE;
490 }
491
492 /***********************************************************************
493  *           DeviceIo_VTDAPI
494  */
495 static BOOL DeviceIo_VTDAPI(DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer,
496                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
497                               LPDWORD lpcbBytesReturned,
498                               LPOVERLAPPED lpOverlapped)
499 {
500     BOOL retv = TRUE;
501
502     switch (dwIoControlCode)
503     {
504     case 5:
505         if (lpvOutBuffer && (cbOutBuffer>=4))
506             *(DWORD*)lpvOutBuffer = GetTickCount();
507
508         if (lpcbBytesReturned)
509             *lpcbBytesReturned = 4;
510
511         break;
512
513     default:
514         FIXME( "Control %ld not implemented\n", dwIoControlCode);
515         retv = FALSE;
516         break;
517     }
518
519     return retv;
520 }
521
522 /***********************************************************************
523  *              VxDCall0 (KERNEL32.1)
524  *              VxDCall1 (KERNEL32.2)
525  *              VxDCall2 (KERNEL32.3)
526  *              VxDCall3 (KERNEL32.4)
527  *              VxDCall4 (KERNEL32.5)
528  *              VxDCall5 (KERNEL32.6)
529  *              VxDCall6 (KERNEL32.7)
530  *              VxDCall7 (KERNEL32.8)
531  *              VxDCall8 (KERNEL32.9)
532  */
533 void VxDCall( DWORD service, CONTEXT86 *context )
534 {
535     DWORD ret = 0xffffffff; /* FIXME */
536     int i;
537
538     TRACE( "(%08lx, ...)\n", service);
539
540     for (i = 0; VxDList[i].name; i++)
541         if (VxDList[i].id == HIWORD(service))
542             break;
543
544     if (!VxDList[i].name)
545         FIXME( "Unknown VxD (%08lx)\n", service);
546     else if (!VxDList[i].vxdcall)
547         FIXME( "Unimplemented VxD (%08lx)\n", service);
548     else
549         ret = VxDList[i].vxdcall( service, context );
550
551     context->Eax = ret;
552 }
553
554
555 /******************************************************************************
556  * The following is a massive duplication of the advapi32 code.
557  * Unfortunately sharing the code is not possible since the native
558  * Win95 advapi32 depends on it. Someday we should probably stop
559  * supporting native Win95 advapi32 altogether...
560  */
561
562
563 #define HKEY_SPECIAL_ROOT_FIRST   HKEY_CLASSES_ROOT
564 #define HKEY_SPECIAL_ROOT_LAST    HKEY_DYN_DATA
565 #define NB_SPECIAL_ROOT_KEYS      ((UINT)HKEY_SPECIAL_ROOT_LAST - (UINT)HKEY_SPECIAL_ROOT_FIRST + 1)
566
567 static HKEY special_root_keys[NB_SPECIAL_ROOT_KEYS];
568
569 static const WCHAR name_CLASSES_ROOT[] =
570     {'M','a','c','h','i','n','e','\\',
571      'S','o','f','t','w','a','r','e','\\',
572      'C','l','a','s','s','e','s',0};
573 static const WCHAR name_LOCAL_MACHINE[] =
574     {'M','a','c','h','i','n','e',0};
575 static const WCHAR name_USERS[] =
576     {'U','s','e','r',0};
577 static const WCHAR name_PERFORMANCE_DATA[] =
578     {'P','e','r','f','D','a','t','a',0};
579 static const WCHAR name_CURRENT_CONFIG[] =
580     {'M','a','c','h','i','n','e','\\',
581      'S','y','s','t','e','m','\\',
582      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
583      'H','a','r','d','w','a','r','e','P','r','o','f','i','l','e','s','\\',
584      'C','u','r','r','e','n','t',0};
585 static const WCHAR name_DYN_DATA[] =
586     {'D','y','n','D','a','t','a',0};
587
588 #define DECL_STR(key) { sizeof(name_##key)-sizeof(WCHAR), sizeof(name_##key), (LPWSTR)name_##key }
589 static UNICODE_STRING root_key_names[NB_SPECIAL_ROOT_KEYS] =
590 {
591     DECL_STR(CLASSES_ROOT),
592     { 0, 0, NULL },         /* HKEY_CURRENT_USER is determined dynamically */
593     DECL_STR(LOCAL_MACHINE),
594     DECL_STR(USERS),
595     DECL_STR(PERFORMANCE_DATA),
596     DECL_STR(CURRENT_CONFIG),
597     DECL_STR(DYN_DATA)
598 };
599 #undef DECL_STR
600
601
602 /* check if value type needs string conversion (Ansi<->Unicode) */
603 inline static int is_string( DWORD type )
604 {
605     return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
606 }
607
608 /* create one of the HKEY_* special root keys */
609 static HKEY create_special_root_hkey( HKEY hkey, DWORD access )
610 {
611     HKEY ret = 0;
612     int idx = (UINT)hkey - (UINT)HKEY_SPECIAL_ROOT_FIRST;
613
614     if (hkey == HKEY_CURRENT_USER)
615     {
616         if (RtlOpenCurrentUser( access, &hkey )) return 0;
617     }
618     else
619     {
620         OBJECT_ATTRIBUTES attr;
621
622         attr.Length = sizeof(attr);
623         attr.RootDirectory = 0;
624         attr.ObjectName = &root_key_names[idx];
625         attr.Attributes = 0;
626         attr.SecurityDescriptor = NULL;
627         attr.SecurityQualityOfService = NULL;
628         if (NtCreateKey( &hkey, access, &attr, 0, NULL, 0, NULL )) return 0;
629     }
630
631     if (!(ret = InterlockedCompareExchangePointer( (PVOID) &special_root_keys[idx], hkey, 0 )))
632         ret = hkey;
633     else
634         NtClose( hkey );  /* somebody beat us to it */
635     return ret;
636 }
637
638 /* map the hkey from special root to normal key if necessary */
639 inline static HKEY get_special_root_hkey( HKEY hkey )
640 {
641     HKEY ret = hkey;
642
643     if ((hkey >= HKEY_SPECIAL_ROOT_FIRST) && (hkey <= HKEY_SPECIAL_ROOT_LAST))
644     {
645         if (!(ret = special_root_keys[(UINT)hkey - (UINT)HKEY_SPECIAL_ROOT_FIRST]))
646             ret = create_special_root_hkey( hkey, KEY_ALL_ACCESS );
647     }
648     return ret;
649 }
650
651
652 /******************************************************************************
653  *           VMM_RegCreateKeyA
654  */
655 static DWORD VMM_RegCreateKeyA( HKEY hkey, LPCSTR name, PHKEY retkey )
656 {
657     OBJECT_ATTRIBUTES attr;
658     UNICODE_STRING nameW;
659     ANSI_STRING nameA;
660     NTSTATUS status;
661
662     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
663
664     attr.Length = sizeof(attr);
665     attr.RootDirectory = hkey;
666     attr.ObjectName = &nameW;
667     attr.Attributes = 0;
668     attr.SecurityDescriptor = NULL;
669     attr.SecurityQualityOfService = NULL;
670     RtlInitAnsiString( &nameA, name );
671
672     if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
673     {
674         status = NtCreateKey( retkey, KEY_ALL_ACCESS, &attr, 0, NULL,
675                               REG_OPTION_NON_VOLATILE, NULL );
676         RtlFreeUnicodeString( &nameW );
677     }
678     return RtlNtStatusToDosError( status );
679 }
680
681
682 /******************************************************************************
683  *           VMM_RegOpenKeyExA
684  */
685 DWORD WINAPI VMM_RegOpenKeyExA(HKEY hkey, LPCSTR name, DWORD reserved, REGSAM access, PHKEY retkey)
686 {
687     OBJECT_ATTRIBUTES attr;
688     UNICODE_STRING nameW;
689     STRING nameA;
690     NTSTATUS status;
691
692     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
693
694     attr.Length = sizeof(attr);
695     attr.RootDirectory = hkey;
696     attr.ObjectName = &nameW;
697     attr.Attributes = 0;
698     attr.SecurityDescriptor = NULL;
699     attr.SecurityQualityOfService = NULL;
700
701     RtlInitAnsiString( &nameA, name );
702     if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
703     {
704         status = NtOpenKey( retkey, access, &attr );
705         RtlFreeUnicodeString( &nameW );
706     }
707     return RtlNtStatusToDosError( status );
708 }
709
710
711 /******************************************************************************
712  *           VMM_RegCloseKey
713  */
714 static DWORD VMM_RegCloseKey( HKEY hkey )
715 {
716     if (!hkey || hkey >= (HKEY)0x80000000) return ERROR_SUCCESS;
717     return RtlNtStatusToDosError( NtClose( hkey ) );
718 }
719
720
721 /******************************************************************************
722  *           VMM_RegDeleteKeyA
723  */
724 static DWORD VMM_RegDeleteKeyA( HKEY hkey, LPCSTR name )
725 {
726     DWORD ret;
727     HKEY tmp;
728
729     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
730
731     if (!name || !*name) return RtlNtStatusToDosError( NtDeleteKey( hkey ) );
732     if (!(ret = VMM_RegOpenKeyExA( hkey, name, 0, 0, &tmp )))
733     {
734         ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
735         NtClose( tmp );
736     }
737     return ret;
738 }
739
740
741 /******************************************************************************
742  *           VMM_RegSetValueExA
743  */
744 static DWORD VMM_RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
745                                  CONST BYTE *data, DWORD count )
746 {
747     UNICODE_STRING nameW;
748     ANSI_STRING nameA;
749     WCHAR *dataW = NULL;
750     NTSTATUS status;
751
752     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
753
754     if (is_string(type))
755     {
756         DWORD lenW;
757
758         if (count)
759         {
760             /* if user forgot to count terminating null, add it (yes NT does this) */
761             if (data[count-1] && !data[count]) count++;
762         }
763         RtlMultiByteToUnicodeSize( &lenW, data, count );
764         if (!(dataW = HeapAlloc( GetProcessHeap(), 0, lenW ))) return ERROR_OUTOFMEMORY;
765         RtlMultiByteToUnicodeN( dataW, lenW, NULL, data, count );
766         count = lenW;
767         data = (BYTE *)dataW;
768     }
769
770     RtlInitAnsiString( &nameA, name );
771     if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
772     {
773         status = NtSetValueKey( hkey, &nameW, 0, type, data, count );
774         RtlFreeUnicodeString( &nameW );
775     }
776     if (dataW) HeapFree( GetProcessHeap(), 0, dataW );
777     return RtlNtStatusToDosError( status );
778 }
779
780
781 /******************************************************************************
782  *           VMM_RegSetValueA
783  */
784 static DWORD VMM_RegSetValueA( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
785 {
786     HKEY subkey = hkey;
787     DWORD ret;
788
789     if (type != REG_SZ) return ERROR_INVALID_PARAMETER;
790
791     if (name && name[0])  /* need to create the subkey */
792     {
793         if ((ret = VMM_RegCreateKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
794     }
795     ret = VMM_RegSetValueExA( subkey, NULL, 0, REG_SZ, (LPBYTE)data, strlen(data)+1 );
796     if (subkey != hkey) NtClose( subkey );
797     return ret;
798 }
799
800
801 /******************************************************************************
802  *           VMM_RegDeleteValueA
803  */
804 static DWORD VMM_RegDeleteValueA( HKEY hkey, LPCSTR name )
805 {
806     UNICODE_STRING nameW;
807     STRING nameA;
808     NTSTATUS status;
809
810     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
811
812     RtlInitAnsiString( &nameA, name );
813     if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
814     {
815         status = NtDeleteValueKey( hkey, &nameW );
816         RtlFreeUnicodeString( &nameW );
817     }
818     return RtlNtStatusToDosError( status );
819 }
820
821
822 /******************************************************************************
823  *           VMM_RegQueryValueExA
824  */
825 static DWORD VMM_RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
826                                    LPBYTE data, LPDWORD count )
827 {
828     NTSTATUS status;
829     ANSI_STRING nameA;
830     UNICODE_STRING nameW;
831     DWORD total_size;
832     char buffer[256], *buf_ptr = buffer;
833     KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
834     static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
835
836     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
837     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
838
839     RtlInitAnsiString( &nameA, name );
840     if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
841         return RtlNtStatusToDosError(status);
842
843     status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
844                               buffer, sizeof(buffer), &total_size );
845     if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
846
847     /* we need to fetch the contents for a string type even if not requested,
848      * because we need to compute the length of the ASCII string. */
849     if (data || is_string(info->Type))
850     {
851         /* retry with a dynamically allocated buffer */
852         while (status == STATUS_BUFFER_OVERFLOW)
853         {
854             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
855             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
856             {
857                 status = STATUS_NO_MEMORY;
858                 goto done;
859             }
860             info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
861             status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
862                                       buf_ptr, total_size, &total_size );
863         }
864
865         if (!status)
866         {
867             if (is_string(info->Type))
868             {
869                 DWORD len = WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info_size),
870                                                  (total_size - info_size) /sizeof(WCHAR),
871                                                  NULL, 0, NULL, NULL );
872                 if (data && len)
873                 {
874                     if (len > *count) status = STATUS_BUFFER_OVERFLOW;
875                     else
876                     {
877                         WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info_size),
878                                              (total_size - info_size) /sizeof(WCHAR),
879                                              data, len, NULL, NULL );
880                         /* if the type is REG_SZ and data is not 0-terminated
881                          * and there is enough space in the buffer NT appends a \0 */
882                         if (len < *count && data[len-1]) data[len] = 0;
883                     }
884                 }
885                 total_size = len + info_size;
886             }
887             else if (data)
888             {
889                 if (total_size - info_size > *count) status = STATUS_BUFFER_OVERFLOW;
890                 else memcpy( data, buf_ptr + info_size, total_size - info_size );
891             }
892         }
893         else if (status != STATUS_BUFFER_OVERFLOW) goto done;
894     }
895
896     if (type) *type = info->Type;
897     if (count) *count = total_size - info_size;
898
899  done:
900     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
901     RtlFreeUnicodeString( &nameW );
902     return RtlNtStatusToDosError(status);
903 }
904
905
906 /******************************************************************************
907  *           VMM_RegQueryValueA
908  */
909 static DWORD VMM_RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
910 {
911     DWORD ret;
912     HKEY subkey = hkey;
913
914     if (name && name[0])
915     {
916         if ((ret = VMM_RegOpenKeyExA( hkey, name, 0, KEY_ALL_ACCESS, &subkey )) != ERROR_SUCCESS)
917             return ret;
918     }
919     ret = VMM_RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, count );
920     if (subkey != hkey) NtClose( subkey );
921     if (ret == ERROR_FILE_NOT_FOUND)
922     {
923         /* return empty string if default value not found */
924         if (data) *data = 0;
925         if (count) *count = 1;
926         ret = ERROR_SUCCESS;
927     }
928     return ret;
929 }
930
931
932 /******************************************************************************
933  *           VMM_RegEnumValueA
934  */
935 static DWORD VMM_RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
936                                 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
937 {
938     NTSTATUS status;
939     DWORD total_size;
940     char buffer[256], *buf_ptr = buffer;
941     KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
942     static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
943
944     TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
945           hkey, index, value, val_count, reserved, type, data, count );
946
947     /* NT only checks count, not val_count */
948     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
949     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
950
951     total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
952     if (data) total_size += *count;
953     total_size = min( sizeof(buffer), total_size );
954
955     status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
956                                   buffer, total_size, &total_size );
957     if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
958
959     /* we need to fetch the contents for a string type even if not requested,
960      * because we need to compute the length of the ASCII string. */
961     if (value || data || is_string(info->Type))
962     {
963         /* retry with a dynamically allocated buffer */
964         while (status == STATUS_BUFFER_OVERFLOW)
965         {
966             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
967             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
968                 return ERROR_NOT_ENOUGH_MEMORY;
969             info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
970             status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
971                                           buf_ptr, total_size, &total_size );
972         }
973
974         if (status) goto done;
975
976         if (is_string(info->Type))
977         {
978             DWORD len;
979             RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
980                                        total_size - info->DataOffset );
981             if (data && len)
982             {
983                 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
984                 else
985                 {
986                     RtlUnicodeToMultiByteN( data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
987                                             total_size - info->DataOffset );
988                     /* if the type is REG_SZ and data is not 0-terminated
989                      * and there is enough space in the buffer NT appends a \0 */
990                     if (len < *count && data[len-1]) data[len] = 0;
991                 }
992             }
993             info->DataLength = len;
994         }
995         else if (data)
996         {
997             if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
998             else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
999         }
1000
1001         if (value && !status)
1002         {
1003             DWORD len;
1004
1005             RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
1006             if (len >= *val_count)
1007             {
1008                 status = STATUS_BUFFER_OVERFLOW;
1009                 if (*val_count)
1010                 {
1011                     len = *val_count - 1;
1012                     RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
1013                     value[len] = 0;
1014                 }
1015             }
1016             else
1017             {
1018                 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
1019                 value[len] = 0;
1020                 *val_count = len;
1021             }
1022         }
1023     }
1024     else status = STATUS_SUCCESS;
1025
1026     if (type) *type = info->Type;
1027     if (count) *count = info->DataLength;
1028
1029  done:
1030     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1031     return RtlNtStatusToDosError(status);
1032 }
1033
1034
1035 /******************************************************************************
1036  *           VMM_RegEnumKeyA
1037  */
1038 static DWORD VMM_RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
1039 {
1040     NTSTATUS status;
1041     char buffer[256], *buf_ptr = buffer;
1042     KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
1043     DWORD total_size;
1044
1045     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1046
1047     status = NtEnumerateKey( hkey, index, KeyNodeInformation,
1048                              buffer, sizeof(buffer), &total_size );
1049
1050     while (status == STATUS_BUFFER_OVERFLOW)
1051     {
1052         /* retry with a dynamically allocated buffer */
1053         if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1054         if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1055             return ERROR_NOT_ENOUGH_MEMORY;
1056         info = (KEY_NODE_INFORMATION *)buf_ptr;
1057         status = NtEnumerateKey( hkey, index, KeyNodeInformation,
1058                                  buf_ptr, total_size, &total_size );
1059     }
1060
1061     if (!status)
1062     {
1063         DWORD len;
1064
1065         RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
1066         if (len >= name_len) status = STATUS_BUFFER_OVERFLOW;
1067         else
1068         {
1069             RtlUnicodeToMultiByteN( name, len, NULL, info->Name, info->NameLength );
1070             name[len] = 0;
1071         }
1072     }
1073
1074     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1075     return RtlNtStatusToDosError( status );
1076 }
1077
1078
1079 /******************************************************************************
1080  *           VMM_RegQueryInfoKeyA
1081  *
1082  * NOTE: This VxDCall takes only a subset of the parameters that the
1083  * corresponding Win32 API call does. The implementation in Win95
1084  * ADVAPI32 sets all output parameters not mentioned here to zero.
1085  */
1086 static DWORD VMM_RegQueryInfoKeyA( HKEY hkey, LPDWORD subkeys, LPDWORD max_subkey,
1087                                    LPDWORD values, LPDWORD max_value, LPDWORD max_data )
1088 {
1089     NTSTATUS status;
1090     KEY_FULL_INFORMATION info;
1091     DWORD total_size;
1092
1093     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1094
1095     status = NtQueryKey( hkey, KeyFullInformation, &info, sizeof(info), &total_size );
1096     if (status && status != STATUS_BUFFER_OVERFLOW) return RtlNtStatusToDosError( status );
1097
1098     if (subkeys) *subkeys = info.SubKeys;
1099     if (max_subkey) *max_subkey = info.MaxNameLen;
1100     if (values) *values = info.Values;
1101     if (max_value) *max_value = info.MaxValueNameLen;
1102     if (max_data) *max_data = info.MaxValueDataLen;
1103     return ERROR_SUCCESS;
1104 }
1105
1106
1107 /***********************************************************************
1108  *           VxDCall_VMM
1109  */
1110 static DWORD VxDCall_VMM( DWORD service, CONTEXT86 *context )
1111 {
1112     switch ( LOWORD(service) )
1113     {
1114     case 0x0011:  /* RegOpenKey */
1115     {
1116         HKEY    hkey       = (HKEY)  stack32_pop( context );
1117         LPCSTR  lpszSubKey = (LPCSTR)stack32_pop( context );
1118         PHKEY   retkey     = (PHKEY)stack32_pop( context );
1119         return VMM_RegOpenKeyExA( hkey, lpszSubKey, 0, KEY_ALL_ACCESS, retkey );
1120     }
1121
1122     case 0x0012:  /* RegCreateKey */
1123     {
1124         HKEY    hkey       = (HKEY)  stack32_pop( context );
1125         LPCSTR  lpszSubKey = (LPCSTR)stack32_pop( context );
1126         PHKEY   retkey     = (PHKEY)stack32_pop( context );
1127         return VMM_RegCreateKeyA( hkey, lpszSubKey, retkey );
1128     }
1129
1130     case 0x0013:  /* RegCloseKey */
1131     {
1132         HKEY    hkey       = (HKEY)stack32_pop( context );
1133         return VMM_RegCloseKey( hkey );
1134     }
1135
1136     case 0x0014:  /* RegDeleteKey */
1137     {
1138         HKEY    hkey       = (HKEY)  stack32_pop( context );
1139         LPCSTR  lpszSubKey = (LPCSTR)stack32_pop( context );
1140         return VMM_RegDeleteKeyA( hkey, lpszSubKey );
1141     }
1142
1143     case 0x0015:  /* RegSetValue */
1144     {
1145         HKEY    hkey       = (HKEY)  stack32_pop( context );
1146         LPCSTR  lpszSubKey = (LPCSTR)stack32_pop( context );
1147         DWORD   dwType     = (DWORD) stack32_pop( context );
1148         LPCSTR  lpszData   = (LPCSTR)stack32_pop( context );
1149         DWORD   cbData     = (DWORD) stack32_pop( context );
1150         return VMM_RegSetValueA( hkey, lpszSubKey, dwType, lpszData, cbData );
1151     }
1152
1153     case 0x0016:  /* RegDeleteValue */
1154     {
1155         HKEY    hkey       = (HKEY) stack32_pop( context );
1156         LPSTR   lpszValue  = (LPSTR)stack32_pop( context );
1157         return VMM_RegDeleteValueA( hkey, lpszValue );
1158     }
1159
1160     case 0x0017:  /* RegQueryValue */
1161     {
1162         HKEY    hkey       = (HKEY)   stack32_pop( context );
1163         LPSTR   lpszSubKey = (LPSTR)  stack32_pop( context );
1164         LPSTR   lpszData   = (LPSTR)  stack32_pop( context );
1165         LPDWORD lpcbData   = (LPDWORD)stack32_pop( context );
1166         return VMM_RegQueryValueA( hkey, lpszSubKey, lpszData, lpcbData );
1167     }
1168
1169     case 0x0018:  /* RegEnumKey */
1170     {
1171         HKEY    hkey       = (HKEY) stack32_pop( context );
1172         DWORD   iSubkey    = (DWORD)stack32_pop( context );
1173         LPSTR   lpszName   = (LPSTR)stack32_pop( context );
1174         DWORD   lpcchName  = (DWORD)stack32_pop( context );
1175         return VMM_RegEnumKeyA( hkey, iSubkey, lpszName, lpcchName );
1176     }
1177
1178     case 0x0019:  /* RegEnumValue */
1179     {
1180         HKEY    hkey       = (HKEY)   stack32_pop( context );
1181         DWORD   iValue     = (DWORD)  stack32_pop( context );
1182         LPSTR   lpszValue  = (LPSTR)  stack32_pop( context );
1183         LPDWORD lpcchValue = (LPDWORD)stack32_pop( context );
1184         LPDWORD lpReserved = (LPDWORD)stack32_pop( context );
1185         LPDWORD lpdwType   = (LPDWORD)stack32_pop( context );
1186         LPBYTE  lpbData    = (LPBYTE) stack32_pop( context );
1187         LPDWORD lpcbData   = (LPDWORD)stack32_pop( context );
1188         return VMM_RegEnumValueA( hkey, iValue, lpszValue, lpcchValue,
1189                                   lpReserved, lpdwType, lpbData, lpcbData );
1190     }
1191
1192     case 0x001A:  /* RegQueryValueEx */
1193     {
1194         HKEY    hkey       = (HKEY)   stack32_pop( context );
1195         LPSTR   lpszValue  = (LPSTR)  stack32_pop( context );
1196         LPDWORD lpReserved = (LPDWORD)stack32_pop( context );
1197         LPDWORD lpdwType   = (LPDWORD)stack32_pop( context );
1198         LPBYTE  lpbData    = (LPBYTE) stack32_pop( context );
1199         LPDWORD lpcbData   = (LPDWORD)stack32_pop( context );
1200         return VMM_RegQueryValueExA( hkey, lpszValue, lpReserved,
1201                                      lpdwType, lpbData, lpcbData );
1202     }
1203
1204     case 0x001B:  /* RegSetValueEx */
1205     {
1206         HKEY    hkey       = (HKEY)  stack32_pop( context );
1207         LPSTR   lpszValue  = (LPSTR) stack32_pop( context );
1208         DWORD   dwReserved = (DWORD) stack32_pop( context );
1209         DWORD   dwType     = (DWORD) stack32_pop( context );
1210         LPBYTE  lpbData    = (LPBYTE)stack32_pop( context );
1211         DWORD   cbData     = (DWORD) stack32_pop( context );
1212         return VMM_RegSetValueExA( hkey, lpszValue, dwReserved,
1213                                    dwType, lpbData, cbData );
1214     }
1215
1216     case 0x001C:  /* RegFlushKey */
1217     {
1218         HKEY hkey = (HKEY)stack32_pop( context );
1219         FIXME( "RegFlushKey(%p): stub\n", hkey );
1220         return ERROR_SUCCESS;
1221     }
1222
1223     case 0x001D:  /* RegQueryInfoKey */
1224     {
1225         /* NOTE: This VxDCall takes only a subset of the parameters that the
1226                  corresponding Win32 API call does. The implementation in Win95
1227                  ADVAPI32 sets all output parameters not mentioned here to zero. */
1228
1229         HKEY    hkey              = (HKEY)   stack32_pop( context );
1230         LPDWORD lpcSubKeys        = (LPDWORD)stack32_pop( context );
1231         LPDWORD lpcchMaxSubKey    = (LPDWORD)stack32_pop( context );
1232         LPDWORD lpcValues         = (LPDWORD)stack32_pop( context );
1233         LPDWORD lpcchMaxValueName = (LPDWORD)stack32_pop( context );
1234         LPDWORD lpcchMaxValueData = (LPDWORD)stack32_pop( context );
1235         return VMM_RegQueryInfoKeyA( hkey, lpcSubKeys, lpcchMaxSubKey,
1236                                      lpcValues, lpcchMaxValueName, lpcchMaxValueData );
1237     }
1238
1239     case 0x0021:  /* RegLoadKey */
1240     {
1241         HKEY    hkey       = (HKEY)  stack32_pop( context );
1242         LPCSTR  lpszSubKey = (LPCSTR)stack32_pop( context );
1243         LPCSTR  lpszFile   = (LPCSTR)stack32_pop( context );
1244         FIXME("RegLoadKey(%p,%s,%s): stub\n",hkey, debugstr_a(lpszSubKey), debugstr_a(lpszFile));
1245         return ERROR_SUCCESS;
1246     }
1247
1248     case 0x0022:  /* RegUnLoadKey */
1249     {
1250         HKEY    hkey       = (HKEY)  stack32_pop( context );
1251         LPCSTR  lpszSubKey = (LPCSTR)stack32_pop( context );
1252         FIXME("RegUnLoadKey(%p,%s): stub\n",hkey, debugstr_a(lpszSubKey));
1253         return ERROR_SUCCESS;
1254     }
1255
1256     case 0x0023:  /* RegSaveKey */
1257     {
1258         HKEY    hkey       = (HKEY)  stack32_pop( context );
1259         LPCSTR  lpszFile   = (LPCSTR)stack32_pop( context );
1260         LPSECURITY_ATTRIBUTES sa = (LPSECURITY_ATTRIBUTES)stack32_pop( context );
1261         FIXME("RegSaveKey(%p,%s,%p): stub\n",hkey, debugstr_a(lpszFile),sa);
1262         return ERROR_SUCCESS;
1263     }
1264
1265 #if 0 /* Functions are not yet implemented in misc/registry.c */
1266     case 0x0024:  /* RegRemapPreDefKey */
1267     case 0x0026:  /* RegQueryMultipleValues */
1268 #endif
1269
1270     case 0x0027:  /* RegReplaceKey */
1271     {
1272         HKEY    hkey       = (HKEY)  stack32_pop( context );
1273         LPCSTR  lpszSubKey = (LPCSTR)stack32_pop( context );
1274         LPCSTR  lpszNewFile= (LPCSTR)stack32_pop( context );
1275         LPCSTR  lpszOldFile= (LPCSTR)stack32_pop( context );
1276         FIXME("RegReplaceKey(%p,%s,%s,%s): stub\n", hkey, debugstr_a(lpszSubKey),
1277               debugstr_a(lpszNewFile),debugstr_a(lpszOldFile));
1278         return ERROR_SUCCESS;
1279     }
1280
1281     case 0x0000: /* PageReserve */
1282       {
1283         LPVOID address;
1284         LPVOID ret;
1285         DWORD psize = getpagesize();
1286         ULONG page   = (ULONG) stack32_pop( context );
1287         ULONG npages = (ULONG) stack32_pop( context );
1288         ULONG flags  = (ULONG) stack32_pop( context );
1289
1290         TRACE("PageReserve: page: %08lx, npages: %08lx, flags: %08lx partial stub!\n",
1291               page, npages, flags );
1292
1293         if ( page == PR_SYSTEM ) {
1294           ERR("Can't reserve ring 1 memory\n");
1295           return -1;
1296         }
1297         /* FIXME: This has to be handled separately for the separate
1298            address-spaces we now have */
1299         if ( page == PR_PRIVATE || page == PR_SHARED ) page = 0;
1300         /* FIXME: Handle flags in some way */
1301         address = (LPVOID )(page * psize);
1302         ret = VirtualAlloc ( address, ( npages * psize ), MEM_RESERVE, 0 );
1303         TRACE("PageReserve: returning: %08lx\n", (DWORD )ret );
1304         if ( ret == NULL )
1305           return -1;
1306         else
1307           return (DWORD )ret;
1308       }
1309
1310     case 0x0001: /* PageCommit */
1311       {
1312         LPVOID address;
1313         LPVOID ret;
1314         DWORD virt_perm;
1315         DWORD psize = getpagesize();
1316         ULONG page   = (ULONG) stack32_pop( context );
1317         ULONG npages = (ULONG) stack32_pop( context );
1318         ULONG hpd  = (ULONG) stack32_pop( context );
1319         ULONG pagerdata   = (ULONG) stack32_pop( context );
1320         ULONG flags  = (ULONG) stack32_pop( context );
1321
1322         TRACE("PageCommit: page: %08lx, npages: %08lx, hpd: %08lx pagerdata: "
1323               "%08lx, flags: %08lx partial stub\n",
1324               page, npages, hpd, pagerdata, flags );
1325
1326         if ( flags & PC_USER )
1327           if ( flags & PC_WRITEABLE )
1328             virt_perm = PAGE_EXECUTE_READWRITE;
1329           else
1330             virt_perm = PAGE_EXECUTE_READ;
1331         else
1332           virt_perm = PAGE_NOACCESS;
1333
1334         address = (LPVOID )(page * psize);
1335         ret = VirtualAlloc ( address, ( npages * psize ), MEM_COMMIT, virt_perm );
1336         TRACE("PageCommit: Returning: %08lx\n", (DWORD )ret );
1337         return (DWORD )ret;
1338
1339       }
1340     case 0x0002: /* PageDecommit */
1341       {
1342         LPVOID address;
1343         BOOL ret;
1344         DWORD psize = getpagesize();
1345         ULONG page = (ULONG) stack32_pop( context );
1346         ULONG npages = (ULONG) stack32_pop( context );
1347         ULONG flags = (ULONG) stack32_pop( context );
1348
1349         TRACE("PageDecommit: page: %08lx, npages: %08lx, flags: %08lx partial stub\n",
1350               page, npages, flags );
1351         address = (LPVOID )( page * psize );
1352         ret = VirtualFree ( address, ( npages * psize ), MEM_DECOMMIT );
1353         TRACE("PageDecommit: Returning: %s\n", ret ? "TRUE" : "FALSE" );
1354         return ret;
1355       }
1356     case 0x000d: /* PageModifyPermissions */
1357       {
1358         DWORD pg_old_perm;
1359         DWORD pg_new_perm;
1360         DWORD virt_old_perm;
1361         DWORD virt_new_perm;
1362         MEMORY_BASIC_INFORMATION mbi;
1363         LPVOID address;
1364         DWORD psize = getpagesize();
1365         ULONG page = stack32_pop ( context );
1366         ULONG npages = stack32_pop ( context );
1367         ULONG permand = stack32_pop ( context );
1368         ULONG permor = stack32_pop ( context );
1369
1370         TRACE("PageModifyPermissions %08lx %08lx %08lx %08lx partial stub\n",
1371               page, npages, permand, permor );
1372         address = (LPVOID )( page * psize );
1373
1374         VirtualQuery ( address, &mbi, sizeof ( MEMORY_BASIC_INFORMATION ));
1375         virt_old_perm = mbi.Protect;
1376
1377         switch ( virt_old_perm & mbi.Protect ) {
1378         case PAGE_READONLY:
1379         case PAGE_EXECUTE:
1380         case PAGE_EXECUTE_READ:
1381           pg_old_perm = PC_USER;
1382           break;
1383         case PAGE_READWRITE:
1384         case PAGE_WRITECOPY:
1385         case PAGE_EXECUTE_READWRITE:
1386         case PAGE_EXECUTE_WRITECOPY:
1387           pg_old_perm = PC_USER | PC_WRITEABLE;
1388           break;
1389         case PAGE_NOACCESS:
1390         default:
1391           pg_old_perm = 0;
1392           break;
1393         }
1394         pg_new_perm = pg_old_perm;
1395         pg_new_perm &= permand & ~PC_STATIC;
1396         pg_new_perm |= permor  & ~PC_STATIC;
1397
1398         virt_new_perm = ( virt_old_perm )  & ~0xff;
1399         if ( pg_new_perm & PC_USER )
1400         {
1401           if ( pg_new_perm & PC_WRITEABLE )
1402             virt_new_perm |= PAGE_EXECUTE_READWRITE;
1403           else
1404             virt_new_perm |= PAGE_EXECUTE_READ;
1405         }
1406
1407         if ( ! VirtualProtect ( address, ( npages * psize ), virt_new_perm, &virt_old_perm ) ) {
1408           ERR("Can't change page permissions for %08lx\n", (DWORD )address );
1409           return 0xffffffff;
1410         }
1411         TRACE("Returning: %08lx\n", pg_old_perm );
1412         return pg_old_perm;
1413       }
1414     case 0x000a: /* PageFree */
1415       {
1416         BOOL ret;
1417         LPVOID hmem = (LPVOID) stack32_pop( context );
1418         DWORD flags = (DWORD ) stack32_pop( context );
1419
1420         TRACE("PageFree: hmem: %08lx, flags: %08lx partial stub\n",
1421               (DWORD )hmem, flags );
1422
1423         ret = VirtualFree ( hmem, 0, MEM_RELEASE );
1424         context->Eax = ret;
1425         TRACE("Returning: %d\n", ret );
1426
1427         return 0;
1428       }
1429     case 0x001e: /* GetDemandPageInfo */
1430       {
1431          DWORD dinfo = (DWORD)stack32_pop( context );
1432          DWORD flags = (DWORD)stack32_pop( context );
1433
1434          /* GetDemandPageInfo is supposed to fill out the struct at
1435           * "dinfo" with various low-level memory management information.
1436           * Apps are certainly not supposed to call this, although it's
1437           * demoed and documented by Pietrek on pages 441-443 of "Windows
1438           * 95 System Programming Secrets" if any program needs a real
1439           * implementation of this.
1440           */
1441
1442          FIXME("GetDemandPageInfo(%08lx %08lx): stub!\n", dinfo, flags);
1443
1444          return 0;
1445       }
1446     default:
1447         if (LOWORD(service) < N_VMM_SERVICE)
1448             FIXME( "Unimplemented service %s (%08lx)\n",
1449                           VMM_Service_Name[LOWORD(service)], service);
1450         else
1451             FIXME( "Unknown service %08lx\n", service);
1452         break;
1453     }
1454
1455     return 0xffffffff;  /* FIXME */
1456 }
1457
1458 /***********************************************************************
1459  *           DeviceIo_IFSMgr
1460  * NOTES
1461  *   These ioctls are used by 'MSNET32.DLL'.
1462  *
1463  *   I have been unable to uncover any documentation about the ioctls so
1464  *   the implementation of the cases IFS_IOCTL_21 and IFS_IOCTL_2F are
1465  *   based on reasonable guesses on information found in the Windows 95 DDK.
1466  *
1467  */
1468
1469 /*
1470  * IFSMgr DeviceIO service
1471  */
1472
1473 #define IFS_IOCTL_21                100
1474 #define IFS_IOCTL_2F                101
1475 #define IFS_IOCTL_GET_RES           102
1476 #define IFS_IOCTL_GET_NETPRO_NAME_A 103
1477
1478 struct win32apireq {
1479         unsigned long   ar_proid;
1480         unsigned long   ar_eax;
1481         unsigned long   ar_ebx;
1482         unsigned long   ar_ecx;
1483         unsigned long   ar_edx;
1484         unsigned long   ar_esi;
1485         unsigned long   ar_edi;
1486         unsigned long   ar_ebp;
1487         unsigned short  ar_error;
1488         unsigned short  ar_pad;
1489 };
1490
1491 static void win32apieq_2_CONTEXT(struct win32apireq *pIn,CONTEXT86 *pCxt)
1492 {
1493         memset(pCxt,0,sizeof(*pCxt));
1494
1495         pCxt->ContextFlags=CONTEXT86_INTEGER|CONTEXT86_CONTROL;
1496         pCxt->Eax = pIn->ar_eax;
1497         pCxt->Ebx = pIn->ar_ebx;
1498         pCxt->Ecx = pIn->ar_ecx;
1499         pCxt->Edx = pIn->ar_edx;
1500         pCxt->Esi = pIn->ar_esi;
1501         pCxt->Edi = pIn->ar_edi;
1502
1503         /* FIXME: Only partial CONTEXT86_CONTROL */
1504         pCxt->Ebp = pIn->ar_ebp;
1505
1506         /* FIXME: pIn->ar_proid ignored */
1507         /* FIXME: pIn->ar_error ignored */
1508         /* FIXME: pIn->ar_pad ignored */
1509 }
1510
1511 static void CONTEXT_2_win32apieq(CONTEXT86 *pCxt,struct win32apireq *pOut)
1512 {
1513         memset(pOut,0,sizeof(struct win32apireq));
1514
1515         pOut->ar_eax = pCxt->Eax;
1516         pOut->ar_ebx = pCxt->Ebx;
1517         pOut->ar_ecx = pCxt->Ecx;
1518         pOut->ar_edx = pCxt->Edx;
1519         pOut->ar_esi = pCxt->Esi;
1520         pOut->ar_edi = pCxt->Edi;
1521
1522         /* FIXME: Only partial CONTEXT86_CONTROL */
1523         pOut->ar_ebp = pCxt->Ebp;
1524
1525         /* FIXME: pOut->ar_proid ignored */
1526         /* FIXME: pOut->ar_error ignored */
1527         /* FIXME: pOut->ar_pad ignored */
1528 }
1529
1530 static BOOL DeviceIo_IFSMgr(DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer,
1531                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
1532                               LPDWORD lpcbBytesReturned,
1533                               LPOVERLAPPED lpOverlapped)
1534 {
1535     BOOL retv = TRUE;
1536         TRACE("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
1537                         dwIoControlCode,
1538                         lpvInBuffer,cbInBuffer,
1539                         lpvOutBuffer,cbOutBuffer,
1540                         lpcbBytesReturned,
1541                         lpOverlapped);
1542
1543     switch (dwIoControlCode)
1544     {
1545         case IFS_IOCTL_21:
1546         case IFS_IOCTL_2F:{
1547                 CONTEXT86 cxt;
1548                 struct win32apireq *pIn=(struct win32apireq *) lpvInBuffer;
1549                 struct win32apireq *pOut=(struct win32apireq *) lpvOutBuffer;
1550
1551                 TRACE(
1552                         "Control '%s': "
1553                         "proid=0x%08lx, eax=0x%08lx, ebx=0x%08lx, ecx=0x%08lx, "
1554                         "edx=0x%08lx, esi=0x%08lx, edi=0x%08lx, ebp=0x%08lx, "
1555                         "error=0x%04x, pad=0x%04x\n",
1556                         (dwIoControlCode==IFS_IOCTL_21)?"IFS_IOCTL_21":"IFS_IOCTL_2F",
1557                         pIn->ar_proid, pIn->ar_eax, pIn->ar_ebx, pIn->ar_ecx,
1558                         pIn->ar_edx, pIn->ar_esi, pIn->ar_edi, pIn->ar_ebp,
1559                         pIn->ar_error, pIn->ar_pad
1560                 );
1561
1562                 win32apieq_2_CONTEXT(pIn,&cxt);
1563
1564                 if(dwIoControlCode==IFS_IOCTL_21)
1565                 {
1566                     if(Dosvm.CallBuiltinHandler || DPMI_LoadDosSystem())
1567                         Dosvm.CallBuiltinHandler( &cxt, 0x21 );
1568                } 
1569                 else 
1570                 {
1571                     if(Dosvm.CallBuiltinHandler || DPMI_LoadDosSystem())
1572                         Dosvm.CallBuiltinHandler( &cxt, 0x2f );
1573                 }
1574
1575                 CONTEXT_2_win32apieq(&cxt,pOut);
1576
1577         retv = TRUE;
1578         } break;
1579         case IFS_IOCTL_GET_RES:{
1580         FIXME( "Control 'IFS_IOCTL_GET_RES' not implemented\n");
1581         retv = FALSE;
1582         } break;
1583         case IFS_IOCTL_GET_NETPRO_NAME_A:{
1584         FIXME( "Control 'IFS_IOCTL_GET_NETPRO_NAME_A' not implemented\n");
1585         retv = FALSE;
1586         } break;
1587     default:
1588         FIXME( "Control %ld not implemented\n", dwIoControlCode);
1589         retv = FALSE;
1590     }
1591
1592     return retv;
1593 }
1594
1595 /********************************************************************************
1596  *      VxDCall_VWin32
1597  *
1598  *  Service numbers taken from page 448 of Pietrek's "Windows 95 System
1599  *  Programming Secrets".  Parameters from experimentation on real Win98.
1600  *
1601  */
1602
1603 static DWORD VxDCall_VWin32( DWORD service, CONTEXT86 *context )
1604 {
1605   switch ( LOWORD(service) )
1606     {
1607     case 0x0000: /* GetVersion */
1608     {
1609         DWORD vers = GetVersion();
1610         return (LOBYTE(vers) << 8) | HIBYTE(vers);
1611     }
1612     break;
1613
1614     case 0x0020: /* Get VMCPD Version */
1615     {
1616         DWORD parm = (DWORD) stack32_pop(context);
1617
1618         FIXME("Get VMCPD Version(%08lx): partial stub!\n", parm);
1619
1620         /* FIXME: This is what Win98 returns, it may
1621          *        not be correct in all situations.
1622          *        It makes Bleem! happy though.
1623          */
1624
1625         return 0x0405;
1626     }
1627
1628     case 0x0029: /* Int31/DPMI dispatch */
1629     {
1630         DWORD callnum = (DWORD) stack32_pop(context);
1631         DWORD parm    = (DWORD) stack32_pop(context);
1632
1633         TRACE("Int31/DPMI dispatch(%08lx)\n", callnum);
1634
1635         SET_AX( context, callnum );
1636         SET_CX( context, parm );
1637         if(Dosvm.CallBuiltinHandler || DPMI_LoadDosSystem())
1638             Dosvm.CallBuiltinHandler( context, 0x31 );
1639
1640         return LOWORD(context->Eax);
1641     }
1642     break;
1643
1644     case 0x002a: /* Int41 dispatch - parm = int41 service number */
1645     {
1646         DWORD callnum = (DWORD) stack32_pop(context);
1647
1648         return callnum; /* FIXME: should really call INT_Int41Handler() */
1649     }
1650     break;
1651
1652     default:
1653       FIXME("Unknown VWin32 service %08lx\n", service);
1654       break;
1655     }
1656
1657   return 0xffffffff;
1658 }
1659
1660
1661 /***********************************************************************
1662  *           DeviceIo_VCD
1663  */
1664 static BOOL DeviceIo_VCD(DWORD dwIoControlCode,
1665                               LPVOID lpvInBuffer, DWORD cbInBuffer,
1666                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
1667                               LPDWORD lpcbBytesReturned,
1668                               LPOVERLAPPED lpOverlapped)
1669 {
1670     BOOL retv = TRUE;
1671
1672     switch (dwIoControlCode)
1673     {
1674     case IOCTL_SERIAL_LSRMST_INSERT:
1675     {
1676         FIXME( "IOCTL_SERIAL_LSRMST_INSERT NIY !\n");
1677         retv = FALSE;
1678     }
1679     break;
1680
1681     default:
1682         FIXME( "Unknown Control %ld\n", dwIoControlCode);
1683         retv = FALSE;
1684         break;
1685     }
1686
1687     return retv;
1688 }
1689
1690
1691 /***********************************************************************
1692  *           DeviceIo_VWin32
1693  */
1694
1695 static void DIOCRegs_2_CONTEXT( DIOC_REGISTERS *pIn, CONTEXT86 *pCxt )
1696 {
1697     memset( pCxt, 0, sizeof(*pCxt) );
1698     /* Note: segment registers == 0 means that CTX_SEG_OFF_TO_LIN
1699              will interpret 32-bit register contents as linear pointers */
1700
1701     pCxt->ContextFlags=CONTEXT86_INTEGER|CONTEXT86_CONTROL;
1702     pCxt->Eax = pIn->reg_EAX;
1703     pCxt->Ebx = pIn->reg_EBX;
1704     pCxt->Ecx = pIn->reg_ECX;
1705     pCxt->Edx = pIn->reg_EDX;
1706     pCxt->Esi = pIn->reg_ESI;
1707     pCxt->Edi = pIn->reg_EDI;
1708
1709     /* FIXME: Only partial CONTEXT86_CONTROL */
1710     pCxt->EFlags = pIn->reg_Flags;
1711 }
1712
1713 static void CONTEXT_2_DIOCRegs( CONTEXT86 *pCxt, DIOC_REGISTERS *pOut )
1714 {
1715     memset( pOut, 0, sizeof(DIOC_REGISTERS) );
1716
1717     pOut->reg_EAX = pCxt->Eax;
1718     pOut->reg_EBX = pCxt->Ebx;
1719     pOut->reg_ECX = pCxt->Ecx;
1720     pOut->reg_EDX = pCxt->Edx;
1721     pOut->reg_ESI = pCxt->Esi;
1722     pOut->reg_EDI = pCxt->Edi;
1723
1724     /* FIXME: Only partial CONTEXT86_CONTROL */
1725     pOut->reg_Flags = pCxt->EFlags;
1726 }
1727
1728 #define DIOC_AH(regs) (((unsigned char*)&((regs)->reg_EAX))[1])
1729 #define DIOC_AL(regs) (((unsigned char*)&((regs)->reg_EAX))[0])
1730 #define DIOC_BH(regs) (((unsigned char*)&((regs)->reg_EBX))[1])
1731 #define DIOC_BL(regs) (((unsigned char*)&((regs)->reg_EBX))[0])
1732 #define DIOC_DH(regs) (((unsigned char*)&((regs)->reg_EDX))[1])
1733 #define DIOC_DL(regs) (((unsigned char*)&((regs)->reg_EDX))[0])
1734
1735 #define DIOC_AX(regs) (((unsigned short*)&((regs)->reg_EAX))[0])
1736 #define DIOC_BX(regs) (((unsigned short*)&((regs)->reg_EBX))[0])
1737 #define DIOC_CX(regs) (((unsigned short*)&((regs)->reg_ECX))[0])
1738 #define DIOC_DX(regs) (((unsigned short*)&((regs)->reg_EDX))[0])
1739
1740 #define DIOC_SET_CARRY(regs) (((regs)->reg_Flags)|=0x00000001)
1741
1742 static BOOL DeviceIo_VWin32(DWORD dwIoControlCode,
1743                               LPVOID lpvInBuffer, DWORD cbInBuffer,
1744                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
1745                               LPDWORD lpcbBytesReturned,
1746                               LPOVERLAPPED lpOverlapped)
1747 {
1748     BOOL retv = TRUE;
1749
1750     switch (dwIoControlCode)
1751     {
1752     case VWIN32_DIOC_DOS_IOCTL:
1753     case 0x10: /* Int 0x21 call, call it VWIN_DIOC_INT21 ? */
1754     case VWIN32_DIOC_DOS_INT13:
1755     case VWIN32_DIOC_DOS_INT25:
1756     case VWIN32_DIOC_DOS_INT26:
1757     case 0x29: /* Int 0x31 call, call it VWIN_DIOC_INT31 ? */
1758     case VWIN32_DIOC_DOS_DRIVEINFO:
1759     {
1760         CONTEXT86 cxt;
1761         DIOC_REGISTERS *pIn  = (DIOC_REGISTERS *)lpvInBuffer;
1762         DIOC_REGISTERS *pOut = (DIOC_REGISTERS *)lpvOutBuffer;
1763         BYTE intnum = 0;
1764
1765         TRACE( "Control '%s': "
1766                "eax=0x%08lx, ebx=0x%08lx, ecx=0x%08lx, "
1767                "edx=0x%08lx, esi=0x%08lx, edi=0x%08lx \n",
1768                (dwIoControlCode == VWIN32_DIOC_DOS_IOCTL)? "VWIN32_DIOC_DOS_IOCTL" :
1769                (dwIoControlCode == VWIN32_DIOC_DOS_INT25)? "VWIN32_DIOC_DOS_INT25" :
1770                (dwIoControlCode == VWIN32_DIOC_DOS_INT26)? "VWIN32_DIOC_DOS_INT26" :
1771                (dwIoControlCode == VWIN32_DIOC_DOS_DRIVEINFO)? "VWIN32_DIOC_DOS_DRIVEINFO" :  "???",
1772                pIn->reg_EAX, pIn->reg_EBX, pIn->reg_ECX,
1773                pIn->reg_EDX, pIn->reg_ESI, pIn->reg_EDI );
1774
1775         DIOCRegs_2_CONTEXT( pIn, &cxt );
1776
1777         switch (dwIoControlCode)
1778         {
1779         case VWIN32_DIOC_DOS_IOCTL: /* Call int 21h */
1780         case 0x10: /* Int 0x21 call, call it VWIN_DIOC_INT21 ? */
1781         case VWIN32_DIOC_DOS_DRIVEINFO:        /* Call int 21h 730x */
1782             intnum = 0x21;
1783             break;
1784         case VWIN32_DIOC_DOS_INT13:
1785             intnum = 0x13;
1786             break;
1787         case VWIN32_DIOC_DOS_INT25: 
1788             intnum = 0x25;
1789             break;
1790         case VWIN32_DIOC_DOS_INT26:
1791             intnum = 0x26;
1792             break;
1793         case 0x29: /* Int 0x31 call, call it VWIN_DIOC_INT31 ? */
1794             intnum = 0x31;
1795             break;
1796         }
1797
1798         if(Dosvm.CallBuiltinHandler || DPMI_LoadDosSystem())
1799             Dosvm.CallBuiltinHandler( &cxt, intnum );
1800
1801         CONTEXT_2_DIOCRegs( &cxt, pOut );
1802     }
1803     break;
1804
1805     case VWIN32_DIOC_SIMCTRLC:
1806         FIXME( "Control VWIN32_DIOC_SIMCTRLC not implemented\n");
1807         retv = FALSE;
1808         break;
1809
1810     default:
1811         FIXME( "Unknown Control %ld\n", dwIoControlCode);
1812         retv = FALSE;
1813         break;
1814     }
1815
1816     return retv;
1817 }
1818
1819 /* this is the main multimedia device loader */
1820 static BOOL DeviceIo_MMDEVLDR(DWORD dwIoControlCode,
1821                               LPVOID lpvInBuffer, DWORD cbInBuffer,
1822                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
1823                               LPDWORD lpcbBytesReturned,
1824                               LPOVERLAPPED lpOverlapped)
1825 {
1826         FIXME("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
1827             dwIoControlCode,
1828             lpvInBuffer,cbInBuffer,
1829             lpvOutBuffer,cbOutBuffer,
1830             lpcbBytesReturned,
1831             lpOverlapped
1832         );
1833         switch (dwIoControlCode) {
1834         case 5:
1835                 /* Hmm. */
1836                 *(DWORD*)lpvOutBuffer=0;
1837                 *lpcbBytesReturned=4;
1838                 return TRUE;
1839         }
1840         return FALSE;
1841 }
1842 /* this is used by some Origin games */
1843 static BOOL DeviceIo_MONODEBG(DWORD dwIoControlCode,
1844                               LPVOID lpvInBuffer, DWORD cbInBuffer,
1845                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
1846                               LPDWORD lpcbBytesReturned,
1847                               LPOVERLAPPED lpOverlapped)
1848 {
1849         switch (dwIoControlCode) {
1850         case 1: /* version */
1851                 *(LPDWORD)lpvOutBuffer = 0x20004; /* WC SecretOps */
1852                 break;
1853         case 9: /* debug output */
1854                 ERR("MONODEBG: %s\n",debugstr_a(lpvInBuffer));
1855                 break;
1856         default:
1857                 FIXME("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
1858                         dwIoControlCode,
1859                         lpvInBuffer,cbInBuffer,
1860                         lpvOutBuffer,cbOutBuffer,
1861                         lpcbBytesReturned,
1862                         lpOverlapped
1863                 );
1864                 break;
1865         }
1866         return TRUE;
1867 }
1868 /* pccard */
1869 static BOOL DeviceIo_PCCARD (DWORD dwIoControlCode,
1870                               LPVOID lpvInBuffer, DWORD cbInBuffer,
1871                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
1872                               LPDWORD lpcbBytesReturned,
1873                               LPOVERLAPPED lpOverlapped)
1874 {
1875         switch (dwIoControlCode) {
1876         case 0x0000: /* PCCARD_Get_Version */
1877         case 0x0001: /* PCCARD_Card_Services */
1878         default:
1879                 FIXME( "(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
1880                         dwIoControlCode,
1881                         lpvInBuffer,cbInBuffer,
1882                         lpvOutBuffer,cbOutBuffer,
1883                         lpcbBytesReturned,
1884                         lpOverlapped
1885                 );
1886                 break;
1887         }
1888         return FALSE;
1889 }
1890
1891 /***********************************************************************
1892  *              OpenVxDHandle (KERNEL32.@)
1893  *
1894  *      This function is supposed to return the corresponding Ring 0
1895  *      ("kernel") handle for a Ring 3 handle in Win9x.
1896  *      Evidently, Wine will have problems with this. But we try anyway,
1897  *      maybe it helps...
1898  */
1899 HANDLE  WINAPI  OpenVxDHandle(HANDLE hHandleRing3)
1900 {
1901         FIXME( "(%p), stub! (returning Ring 3 handle instead of Ring 0)\n", hHandleRing3);
1902         return hHandleRing3;
1903 }
1904
1905 static BOOL DeviceIo_HASP(DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer,
1906                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
1907                               LPDWORD lpcbBytesReturned,
1908                               LPOVERLAPPED lpOverlapped)
1909 {
1910     BOOL retv = TRUE;
1911         FIXME("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
1912                         dwIoControlCode,
1913                         lpvInBuffer,cbInBuffer,
1914                         lpvOutBuffer,cbOutBuffer,
1915                         lpcbBytesReturned,
1916                         lpOverlapped);
1917
1918     return retv;
1919 }