Fixed undefined operation compiler warning.
[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_file_info )
363     {
364         req->handle = handle;
365         if (!wine_server_call( req ) && (reply->type == FILE_TYPE_UNKNOWN))
366             ret = reply->attr;
367     }
368     SERVER_END_REQ;
369     return ret;
370 }
371
372 static const struct VxDInfo *DEVICE_GetInfo( DWORD clientID )
373 {
374     const struct VxDInfo *info = NULL;
375
376     if (clientID & 0x10000)
377     {
378         for (info = VxDList; info->name; info++)
379             if (info->id == LOWORD(clientID)) break;
380     }
381     return info;
382 }
383
384 /****************************************************************************
385  *              DeviceIoControl (KERNEL32.@)
386  * This is one of those big ugly nasty procedure which can do
387  * a million and one things when it comes to devices. It can also be
388  * used for VxD communication.
389  *
390  * A return value of FALSE indicates that something has gone wrong which
391  * GetLastError can decipher.
392  */
393 BOOL WINAPI DeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode,
394                               LPVOID lpvInBuffer, DWORD cbInBuffer,
395                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
396                               LPDWORD lpcbBytesReturned,
397                               LPOVERLAPPED lpOverlapped)
398 {
399         DWORD clientID;
400
401         TRACE( "(%p,%ld,%p,%ld,%p,%ld,%p,%p)\n",
402                hDevice,dwIoControlCode,lpvInBuffer,cbInBuffer,
403                lpvOutBuffer,cbOutBuffer,lpcbBytesReturned,lpOverlapped  );
404
405         if (!(clientID = DEVICE_GetClientID( hDevice )))
406         {
407                 SetLastError( ERROR_INVALID_PARAMETER );
408                 return FALSE;
409         }
410
411         /* Check if this is a user defined control code for a VxD */
412         if( HIWORD( dwIoControlCode ) == 0 )
413         {
414                 const struct VxDInfo *info;
415                 if (!(info = DEVICE_GetInfo( clientID )))
416                 {
417                         FIXME( "No device found for id %lx\n", clientID);
418                 }
419                 else if ( info->deviceio )
420                 {
421                         return info->deviceio( dwIoControlCode,
422                                         lpvInBuffer, cbInBuffer,
423                                         lpvOutBuffer, cbOutBuffer,
424                                         lpcbBytesReturned, lpOverlapped );
425                 }
426                 else
427                 {
428                         FIXME( "Unimplemented control %ld for VxD device %s\n",
429                                dwIoControlCode, info->name ? info->name : "???" );
430                         /* FIXME: this is for invalid calls on W98SE,
431                          * but maybe we should use ERROR_CALL_NOT_IMPLEMENTED
432                          * instead ? */
433                         SetLastError( ERROR_INVALID_FUNCTION );
434                 }
435         }
436         else
437         {
438                 char str[3];
439
440                 strcpy(str,  "A:");
441                 str[0] += LOBYTE(clientID);
442                 if (GetDriveTypeA(str) == DRIVE_CDROM)
443                     return CDROM_DeviceIoControl(clientID, hDevice, dwIoControlCode, lpvInBuffer, cbInBuffer,
444                                                  lpvOutBuffer, cbOutBuffer, lpcbBytesReturned,
445                                                  lpOverlapped);
446                 else switch( dwIoControlCode )
447                 {
448                 case FSCTL_DELETE_REPARSE_POINT:
449                 case FSCTL_DISMOUNT_VOLUME:
450                 case FSCTL_GET_COMPRESSION:
451                 case FSCTL_GET_REPARSE_POINT:
452                 case FSCTL_LOCK_VOLUME:
453                 case FSCTL_QUERY_ALLOCATED_RANGES:
454                 case FSCTL_SET_COMPRESSION:
455                 case FSCTL_SET_REPARSE_POINT:
456                 case FSCTL_SET_SPARSE:
457                 case FSCTL_SET_ZERO_DATA:
458                 case FSCTL_UNLOCK_VOLUME:
459                 case IOCTL_DISK_CHECK_VERIFY:
460                 case IOCTL_DISK_EJECT_MEDIA:
461                 case IOCTL_DISK_FORMAT_TRACKS:
462                 case IOCTL_DISK_GET_DRIVE_GEOMETRY:
463                 case IOCTL_DISK_GET_DRIVE_LAYOUT:
464                 case IOCTL_DISK_GET_MEDIA_TYPES:
465                 case IOCTL_DISK_GET_PARTITION_INFO:
466                 case IOCTL_DISK_LOAD_MEDIA:
467                 case IOCTL_DISK_MEDIA_REMOVAL:
468                 case IOCTL_DISK_PERFORMANCE:
469                 case IOCTL_DISK_REASSIGN_BLOCKS:
470                 case IOCTL_DISK_SET_DRIVE_LAYOUT:
471                 case IOCTL_DISK_SET_PARTITION_INFO:
472                 case IOCTL_DISK_VERIFY:
473                 case IOCTL_SERIAL_LSRMST_INSERT:
474                 case IOCTL_STORAGE_CHECK_VERIFY:
475                 case IOCTL_STORAGE_EJECT_MEDIA:
476                 case IOCTL_STORAGE_GET_MEDIA_TYPES:
477                 case IOCTL_STORAGE_LOAD_MEDIA:
478                 case IOCTL_STORAGE_MEDIA_REMOVAL:
479                         FIXME( "unimplemented dwIoControlCode=%08lx\n", dwIoControlCode);
480                         SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
481                         return FALSE;
482                         break;
483                 default:
484                         FIXME( "ignored dwIoControlCode=%08lx\n",dwIoControlCode);
485                         SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
486                         return FALSE;
487                         break;
488                 }
489         }
490         return FALSE;
491 }
492
493 /***********************************************************************
494  *           DeviceIo_VTDAPI
495  */
496 static BOOL DeviceIo_VTDAPI(DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer,
497                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
498                               LPDWORD lpcbBytesReturned,
499                               LPOVERLAPPED lpOverlapped)
500 {
501     BOOL retv = TRUE;
502
503     switch (dwIoControlCode)
504     {
505     case 5:
506         if (lpvOutBuffer && (cbOutBuffer>=4))
507             *(DWORD*)lpvOutBuffer = GetTickCount();
508
509         if (lpcbBytesReturned)
510             *lpcbBytesReturned = 4;
511
512         break;
513
514     default:
515         FIXME( "Control %ld not implemented\n", dwIoControlCode);
516         retv = FALSE;
517         break;
518     }
519
520     return retv;
521 }
522
523 /***********************************************************************
524  *              VxDCall0 (KERNEL32.1)
525  *              VxDCall1 (KERNEL32.2)
526  *              VxDCall2 (KERNEL32.3)
527  *              VxDCall3 (KERNEL32.4)
528  *              VxDCall4 (KERNEL32.5)
529  *              VxDCall5 (KERNEL32.6)
530  *              VxDCall6 (KERNEL32.7)
531  *              VxDCall7 (KERNEL32.8)
532  *              VxDCall8 (KERNEL32.9)
533  */
534 void VxDCall( DWORD service, CONTEXT86 *context )
535 {
536     DWORD ret = 0xffffffff; /* FIXME */
537     int i;
538
539     TRACE( "(%08lx, ...)\n", service);
540
541     for (i = 0; VxDList[i].name; i++)
542         if (VxDList[i].id == HIWORD(service))
543             break;
544
545     if (!VxDList[i].name)
546         FIXME( "Unknown VxD (%08lx)\n", service);
547     else if (!VxDList[i].vxdcall)
548         FIXME( "Unimplemented VxD (%08lx)\n", service);
549     else
550         ret = VxDList[i].vxdcall( service, context );
551
552     context->Eax = ret;
553 }
554
555
556 /******************************************************************************
557  * The following is a massive duplication of the advapi32 code.
558  * Unfortunately sharing the code is not possible since the native
559  * Win95 advapi32 depends on it. Someday we should probably stop
560  * supporting native Win95 advapi32 altogether...
561  */
562
563
564 #define HKEY_SPECIAL_ROOT_FIRST   HKEY_CLASSES_ROOT
565 #define HKEY_SPECIAL_ROOT_LAST    HKEY_DYN_DATA
566 #define NB_SPECIAL_ROOT_KEYS      ((UINT)HKEY_SPECIAL_ROOT_LAST - (UINT)HKEY_SPECIAL_ROOT_FIRST + 1)
567
568 static HKEY special_root_keys[NB_SPECIAL_ROOT_KEYS];
569
570 static const WCHAR name_CLASSES_ROOT[] =
571     {'M','a','c','h','i','n','e','\\',
572      'S','o','f','t','w','a','r','e','\\',
573      'C','l','a','s','s','e','s',0};
574 static const WCHAR name_LOCAL_MACHINE[] =
575     {'M','a','c','h','i','n','e',0};
576 static const WCHAR name_USERS[] =
577     {'U','s','e','r',0};
578 static const WCHAR name_PERFORMANCE_DATA[] =
579     {'P','e','r','f','D','a','t','a',0};
580 static const WCHAR name_CURRENT_CONFIG[] =
581     {'M','a','c','h','i','n','e','\\',
582      'S','y','s','t','e','m','\\',
583      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
584      'H','a','r','d','w','a','r','e','P','r','o','f','i','l','e','s','\\',
585      'C','u','r','r','e','n','t',0};
586 static const WCHAR name_DYN_DATA[] =
587     {'D','y','n','D','a','t','a',0};
588
589 #define DECL_STR(key) { sizeof(name_##key)-sizeof(WCHAR), sizeof(name_##key), (LPWSTR)name_##key }
590 static UNICODE_STRING root_key_names[NB_SPECIAL_ROOT_KEYS] =
591 {
592     DECL_STR(CLASSES_ROOT),
593     { 0, 0, NULL },         /* HKEY_CURRENT_USER is determined dynamically */
594     DECL_STR(LOCAL_MACHINE),
595     DECL_STR(USERS),
596     DECL_STR(PERFORMANCE_DATA),
597     DECL_STR(CURRENT_CONFIG),
598     DECL_STR(DYN_DATA)
599 };
600 #undef DECL_STR
601
602
603 /* check if value type needs string conversion (Ansi<->Unicode) */
604 inline static int is_string( DWORD type )
605 {
606     return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
607 }
608
609 /* create one of the HKEY_* special root keys */
610 static HKEY create_special_root_hkey( HKEY hkey, DWORD access )
611 {
612     HKEY ret = 0;
613     int idx = (UINT)hkey - (UINT)HKEY_SPECIAL_ROOT_FIRST;
614
615     if (hkey == HKEY_CURRENT_USER)
616     {
617         if (RtlOpenCurrentUser( access, &hkey )) return 0;
618     }
619     else
620     {
621         OBJECT_ATTRIBUTES attr;
622
623         attr.Length = sizeof(attr);
624         attr.RootDirectory = 0;
625         attr.ObjectName = &root_key_names[idx];
626         attr.Attributes = 0;
627         attr.SecurityDescriptor = NULL;
628         attr.SecurityQualityOfService = NULL;
629         if (NtCreateKey( &hkey, access, &attr, 0, NULL, 0, NULL )) return 0;
630     }
631
632     if (!(ret = InterlockedCompareExchangePointer( (PVOID) &special_root_keys[idx], hkey, 0 )))
633         ret = hkey;
634     else
635         NtClose( hkey );  /* somebody beat us to it */
636     return ret;
637 }
638
639 /* map the hkey from special root to normal key if necessary */
640 inline static HKEY get_special_root_hkey( HKEY hkey )
641 {
642     HKEY ret = hkey;
643
644     if ((hkey >= HKEY_SPECIAL_ROOT_FIRST) && (hkey <= HKEY_SPECIAL_ROOT_LAST))
645     {
646         if (!(ret = special_root_keys[(UINT)hkey - (UINT)HKEY_SPECIAL_ROOT_FIRST]))
647             ret = create_special_root_hkey( hkey, KEY_ALL_ACCESS );
648     }
649     return ret;
650 }
651
652
653 /******************************************************************************
654  *           VMM_RegCreateKeyA
655  */
656 static DWORD VMM_RegCreateKeyA( HKEY hkey, LPCSTR name, PHKEY retkey )
657 {
658     OBJECT_ATTRIBUTES attr;
659     UNICODE_STRING nameW;
660     ANSI_STRING nameA;
661     NTSTATUS status;
662
663     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
664
665     attr.Length = sizeof(attr);
666     attr.RootDirectory = hkey;
667     attr.ObjectName = &nameW;
668     attr.Attributes = 0;
669     attr.SecurityDescriptor = NULL;
670     attr.SecurityQualityOfService = NULL;
671     RtlInitAnsiString( &nameA, name );
672
673     if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
674     {
675         status = NtCreateKey( retkey, KEY_ALL_ACCESS, &attr, 0, NULL,
676                               REG_OPTION_NON_VOLATILE, NULL );
677         RtlFreeUnicodeString( &nameW );
678     }
679     return RtlNtStatusToDosError( status );
680 }
681
682
683 /******************************************************************************
684  *           VMM_RegOpenKeyExA
685  */
686 DWORD WINAPI VMM_RegOpenKeyExA(HKEY hkey, LPCSTR name, DWORD reserved, REGSAM access, PHKEY retkey)
687 {
688     OBJECT_ATTRIBUTES attr;
689     UNICODE_STRING nameW;
690     STRING nameA;
691     NTSTATUS status;
692
693     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
694
695     attr.Length = sizeof(attr);
696     attr.RootDirectory = hkey;
697     attr.ObjectName = &nameW;
698     attr.Attributes = 0;
699     attr.SecurityDescriptor = NULL;
700     attr.SecurityQualityOfService = NULL;
701
702     RtlInitAnsiString( &nameA, name );
703     if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
704     {
705         status = NtOpenKey( retkey, access, &attr );
706         RtlFreeUnicodeString( &nameW );
707     }
708     return RtlNtStatusToDosError( status );
709 }
710
711
712 /******************************************************************************
713  *           VMM_RegCloseKey
714  */
715 static DWORD VMM_RegCloseKey( HKEY hkey )
716 {
717     if (!hkey || hkey >= (HKEY)0x80000000) return ERROR_SUCCESS;
718     return RtlNtStatusToDosError( NtClose( hkey ) );
719 }
720
721
722 /******************************************************************************
723  *           VMM_RegDeleteKeyA
724  */
725 static DWORD VMM_RegDeleteKeyA( HKEY hkey, LPCSTR name )
726 {
727     DWORD ret;
728     HKEY tmp;
729
730     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
731
732     if (!name || !*name) return RtlNtStatusToDosError( NtDeleteKey( hkey ) );
733     if (!(ret = VMM_RegOpenKeyExA( hkey, name, 0, 0, &tmp )))
734     {
735         ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
736         NtClose( tmp );
737     }
738     return ret;
739 }
740
741
742 /******************************************************************************
743  *           VMM_RegSetValueExA
744  */
745 static DWORD VMM_RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
746                                  CONST BYTE *data, DWORD count )
747 {
748     UNICODE_STRING nameW;
749     ANSI_STRING nameA;
750     WCHAR *dataW = NULL;
751     NTSTATUS status;
752
753     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
754
755     if (is_string(type))
756     {
757         DWORD lenW;
758
759         if (count)
760         {
761             /* if user forgot to count terminating null, add it (yes NT does this) */
762             if (data[count-1] && !data[count]) count++;
763         }
764         RtlMultiByteToUnicodeSize( &lenW, data, count );
765         if (!(dataW = HeapAlloc( GetProcessHeap(), 0, lenW ))) return ERROR_OUTOFMEMORY;
766         RtlMultiByteToUnicodeN( dataW, lenW, NULL, data, count );
767         count = lenW;
768         data = (BYTE *)dataW;
769     }
770
771     RtlInitAnsiString( &nameA, name );
772     if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
773     {
774         status = NtSetValueKey( hkey, &nameW, 0, type, data, count );
775         RtlFreeUnicodeString( &nameW );
776     }
777     if (dataW) HeapFree( GetProcessHeap(), 0, dataW );
778     return RtlNtStatusToDosError( status );
779 }
780
781
782 /******************************************************************************
783  *           VMM_RegSetValueA
784  */
785 static DWORD VMM_RegSetValueA( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
786 {
787     HKEY subkey = hkey;
788     DWORD ret;
789
790     if (type != REG_SZ) return ERROR_INVALID_PARAMETER;
791
792     if (name && name[0])  /* need to create the subkey */
793     {
794         if ((ret = VMM_RegCreateKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
795     }
796     ret = VMM_RegSetValueExA( subkey, NULL, 0, REG_SZ, (LPBYTE)data, strlen(data)+1 );
797     if (subkey != hkey) NtClose( subkey );
798     return ret;
799 }
800
801
802 /******************************************************************************
803  *           VMM_RegDeleteValueA
804  */
805 static DWORD VMM_RegDeleteValueA( HKEY hkey, LPCSTR name )
806 {
807     UNICODE_STRING nameW;
808     STRING nameA;
809     NTSTATUS status;
810
811     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
812
813     RtlInitAnsiString( &nameA, name );
814     if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
815     {
816         status = NtDeleteValueKey( hkey, &nameW );
817         RtlFreeUnicodeString( &nameW );
818     }
819     return RtlNtStatusToDosError( status );
820 }
821
822
823 /******************************************************************************
824  *           VMM_RegQueryValueExA
825  */
826 static DWORD VMM_RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
827                                    LPBYTE data, LPDWORD count )
828 {
829     NTSTATUS status;
830     ANSI_STRING nameA;
831     UNICODE_STRING nameW;
832     DWORD total_size;
833     char buffer[256], *buf_ptr = buffer;
834     KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
835     static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
836
837     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
838     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
839
840     RtlInitAnsiString( &nameA, name );
841     if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
842         return RtlNtStatusToDosError(status);
843
844     status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
845                               buffer, sizeof(buffer), &total_size );
846     if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
847
848     /* we need to fetch the contents for a string type even if not requested,
849      * because we need to compute the length of the ASCII string. */
850     if (data || is_string(info->Type))
851     {
852         /* retry with a dynamically allocated buffer */
853         while (status == STATUS_BUFFER_OVERFLOW)
854         {
855             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
856             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
857             {
858                 status = STATUS_NO_MEMORY;
859                 goto done;
860             }
861             info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
862             status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
863                                       buf_ptr, total_size, &total_size );
864         }
865
866         if (!status)
867         {
868             if (is_string(info->Type))
869             {
870                 DWORD len = WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info_size),
871                                                  (total_size - info_size) /sizeof(WCHAR),
872                                                  NULL, 0, NULL, NULL );
873                 if (data && len)
874                 {
875                     if (len > *count) status = STATUS_BUFFER_OVERFLOW;
876                     else
877                     {
878                         WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info_size),
879                                              (total_size - info_size) /sizeof(WCHAR),
880                                              data, len, NULL, NULL );
881                         /* if the type is REG_SZ and data is not 0-terminated
882                          * and there is enough space in the buffer NT appends a \0 */
883                         if (len < *count && data[len-1]) data[len] = 0;
884                     }
885                 }
886                 total_size = len + info_size;
887             }
888             else if (data)
889             {
890                 if (total_size - info_size > *count) status = STATUS_BUFFER_OVERFLOW;
891                 else memcpy( data, buf_ptr + info_size, total_size - info_size );
892             }
893         }
894         else if (status != STATUS_BUFFER_OVERFLOW) goto done;
895     }
896
897     if (type) *type = info->Type;
898     if (count) *count = total_size - info_size;
899
900  done:
901     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
902     RtlFreeUnicodeString( &nameW );
903     return RtlNtStatusToDosError(status);
904 }
905
906
907 /******************************************************************************
908  *           VMM_RegQueryValueA
909  */
910 static DWORD VMM_RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
911 {
912     DWORD ret;
913     HKEY subkey = hkey;
914
915     if (name && name[0])
916     {
917         if ((ret = VMM_RegOpenKeyExA( hkey, name, 0, KEY_ALL_ACCESS, &subkey )) != ERROR_SUCCESS)
918             return ret;
919     }
920     ret = VMM_RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, count );
921     if (subkey != hkey) NtClose( subkey );
922     if (ret == ERROR_FILE_NOT_FOUND)
923     {
924         /* return empty string if default value not found */
925         if (data) *data = 0;
926         if (count) *count = 1;
927         ret = ERROR_SUCCESS;
928     }
929     return ret;
930 }
931
932
933 /******************************************************************************
934  *           VMM_RegEnumValueA
935  */
936 static DWORD VMM_RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
937                                 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
938 {
939     NTSTATUS status;
940     DWORD total_size;
941     char buffer[256], *buf_ptr = buffer;
942     KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
943     static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
944
945     TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
946           hkey, index, value, val_count, reserved, type, data, count );
947
948     /* NT only checks count, not val_count */
949     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
950     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
951
952     total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
953     if (data) total_size += *count;
954     total_size = min( sizeof(buffer), total_size );
955
956     status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
957                                   buffer, total_size, &total_size );
958     if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
959
960     /* we need to fetch the contents for a string type even if not requested,
961      * because we need to compute the length of the ASCII string. */
962     if (value || data || is_string(info->Type))
963     {
964         /* retry with a dynamically allocated buffer */
965         while (status == STATUS_BUFFER_OVERFLOW)
966         {
967             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
968             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
969                 return ERROR_NOT_ENOUGH_MEMORY;
970             info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
971             status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
972                                           buf_ptr, total_size, &total_size );
973         }
974
975         if (status) goto done;
976
977         if (is_string(info->Type))
978         {
979             DWORD len;
980             RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
981                                        total_size - info->DataOffset );
982             if (data && len)
983             {
984                 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
985                 else
986                 {
987                     RtlUnicodeToMultiByteN( data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
988                                             total_size - info->DataOffset );
989                     /* if the type is REG_SZ and data is not 0-terminated
990                      * and there is enough space in the buffer NT appends a \0 */
991                     if (len < *count && data[len-1]) data[len] = 0;
992                 }
993             }
994             info->DataLength = len;
995         }
996         else if (data)
997         {
998             if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
999             else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1000         }
1001
1002         if (value && !status)
1003         {
1004             DWORD len;
1005
1006             RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
1007             if (len >= *val_count)
1008             {
1009                 status = STATUS_BUFFER_OVERFLOW;
1010                 if (*val_count)
1011                 {
1012                     len = *val_count - 1;
1013                     RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
1014                     value[len] = 0;
1015                 }
1016             }
1017             else
1018             {
1019                 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
1020                 value[len] = 0;
1021                 *val_count = len;
1022             }
1023         }
1024     }
1025     else status = STATUS_SUCCESS;
1026
1027     if (type) *type = info->Type;
1028     if (count) *count = info->DataLength;
1029
1030  done:
1031     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1032     return RtlNtStatusToDosError(status);
1033 }
1034
1035
1036 /******************************************************************************
1037  *           VMM_RegEnumKeyA
1038  */
1039 static DWORD VMM_RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
1040 {
1041     NTSTATUS status;
1042     char buffer[256], *buf_ptr = buffer;
1043     KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
1044     DWORD total_size;
1045
1046     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1047
1048     status = NtEnumerateKey( hkey, index, KeyNodeInformation,
1049                              buffer, sizeof(buffer), &total_size );
1050
1051     while (status == STATUS_BUFFER_OVERFLOW)
1052     {
1053         /* retry with a dynamically allocated buffer */
1054         if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1055         if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1056             return ERROR_NOT_ENOUGH_MEMORY;
1057         info = (KEY_NODE_INFORMATION *)buf_ptr;
1058         status = NtEnumerateKey( hkey, index, KeyNodeInformation,
1059                                  buf_ptr, total_size, &total_size );
1060     }
1061
1062     if (!status)
1063     {
1064         DWORD len;
1065
1066         RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
1067         if (len >= name_len) status = STATUS_BUFFER_OVERFLOW;
1068         else
1069         {
1070             RtlUnicodeToMultiByteN( name, len, NULL, info->Name, info->NameLength );
1071             name[len] = 0;
1072         }
1073     }
1074
1075     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1076     return RtlNtStatusToDosError( status );
1077 }
1078
1079
1080 /******************************************************************************
1081  *           VMM_RegQueryInfoKeyA
1082  *
1083  * NOTE: This VxDCall takes only a subset of the parameters that the
1084  * corresponding Win32 API call does. The implementation in Win95
1085  * ADVAPI32 sets all output parameters not mentioned here to zero.
1086  */
1087 static DWORD VMM_RegQueryInfoKeyA( HKEY hkey, LPDWORD subkeys, LPDWORD max_subkey,
1088                                    LPDWORD values, LPDWORD max_value, LPDWORD max_data )
1089 {
1090     NTSTATUS status;
1091     KEY_FULL_INFORMATION info;
1092     DWORD total_size;
1093
1094     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1095
1096     status = NtQueryKey( hkey, KeyFullInformation, &info, sizeof(info), &total_size );
1097     if (status && status != STATUS_BUFFER_OVERFLOW) return RtlNtStatusToDosError( status );
1098
1099     if (subkeys) *subkeys = info.SubKeys;
1100     if (max_subkey) *max_subkey = info.MaxNameLen;
1101     if (values) *values = info.Values;
1102     if (max_value) *max_value = info.MaxValueNameLen;
1103     if (max_data) *max_data = info.MaxValueDataLen;
1104     return ERROR_SUCCESS;
1105 }
1106
1107
1108 /***********************************************************************
1109  *           VxDCall_VMM
1110  */
1111 static DWORD VxDCall_VMM( DWORD service, CONTEXT86 *context )
1112 {
1113     switch ( LOWORD(service) )
1114     {
1115     case 0x0011:  /* RegOpenKey */
1116     {
1117         HKEY    hkey       = (HKEY)  stack32_pop( context );
1118         LPCSTR  lpszSubKey = (LPCSTR)stack32_pop( context );
1119         PHKEY   retkey     = (PHKEY)stack32_pop( context );
1120         return VMM_RegOpenKeyExA( hkey, lpszSubKey, 0, KEY_ALL_ACCESS, retkey );
1121     }
1122
1123     case 0x0012:  /* RegCreateKey */
1124     {
1125         HKEY    hkey       = (HKEY)  stack32_pop( context );
1126         LPCSTR  lpszSubKey = (LPCSTR)stack32_pop( context );
1127         PHKEY   retkey     = (PHKEY)stack32_pop( context );
1128         return VMM_RegCreateKeyA( hkey, lpszSubKey, retkey );
1129     }
1130
1131     case 0x0013:  /* RegCloseKey */
1132     {
1133         HKEY    hkey       = (HKEY)stack32_pop( context );
1134         return VMM_RegCloseKey( hkey );
1135     }
1136
1137     case 0x0014:  /* RegDeleteKey */
1138     {
1139         HKEY    hkey       = (HKEY)  stack32_pop( context );
1140         LPCSTR  lpszSubKey = (LPCSTR)stack32_pop( context );
1141         return VMM_RegDeleteKeyA( hkey, lpszSubKey );
1142     }
1143
1144     case 0x0015:  /* RegSetValue */
1145     {
1146         HKEY    hkey       = (HKEY)  stack32_pop( context );
1147         LPCSTR  lpszSubKey = (LPCSTR)stack32_pop( context );
1148         DWORD   dwType     = (DWORD) stack32_pop( context );
1149         LPCSTR  lpszData   = (LPCSTR)stack32_pop( context );
1150         DWORD   cbData     = (DWORD) stack32_pop( context );
1151         return VMM_RegSetValueA( hkey, lpszSubKey, dwType, lpszData, cbData );
1152     }
1153
1154     case 0x0016:  /* RegDeleteValue */
1155     {
1156         HKEY    hkey       = (HKEY) stack32_pop( context );
1157         LPSTR   lpszValue  = (LPSTR)stack32_pop( context );
1158         return VMM_RegDeleteValueA( hkey, lpszValue );
1159     }
1160
1161     case 0x0017:  /* RegQueryValue */
1162     {
1163         HKEY    hkey       = (HKEY)   stack32_pop( context );
1164         LPSTR   lpszSubKey = (LPSTR)  stack32_pop( context );
1165         LPSTR   lpszData   = (LPSTR)  stack32_pop( context );
1166         LPDWORD lpcbData   = (LPDWORD)stack32_pop( context );
1167         return VMM_RegQueryValueA( hkey, lpszSubKey, lpszData, lpcbData );
1168     }
1169
1170     case 0x0018:  /* RegEnumKey */
1171     {
1172         HKEY    hkey       = (HKEY) stack32_pop( context );
1173         DWORD   iSubkey    = (DWORD)stack32_pop( context );
1174         LPSTR   lpszName   = (LPSTR)stack32_pop( context );
1175         DWORD   lpcchName  = (DWORD)stack32_pop( context );
1176         return VMM_RegEnumKeyA( hkey, iSubkey, lpszName, lpcchName );
1177     }
1178
1179     case 0x0019:  /* RegEnumValue */
1180     {
1181         HKEY    hkey       = (HKEY)   stack32_pop( context );
1182         DWORD   iValue     = (DWORD)  stack32_pop( context );
1183         LPSTR   lpszValue  = (LPSTR)  stack32_pop( context );
1184         LPDWORD lpcchValue = (LPDWORD)stack32_pop( context );
1185         LPDWORD lpReserved = (LPDWORD)stack32_pop( context );
1186         LPDWORD lpdwType   = (LPDWORD)stack32_pop( context );
1187         LPBYTE  lpbData    = (LPBYTE) stack32_pop( context );
1188         LPDWORD lpcbData   = (LPDWORD)stack32_pop( context );
1189         return VMM_RegEnumValueA( hkey, iValue, lpszValue, lpcchValue,
1190                                   lpReserved, lpdwType, lpbData, lpcbData );
1191     }
1192
1193     case 0x001A:  /* RegQueryValueEx */
1194     {
1195         HKEY    hkey       = (HKEY)   stack32_pop( context );
1196         LPSTR   lpszValue  = (LPSTR)  stack32_pop( context );
1197         LPDWORD lpReserved = (LPDWORD)stack32_pop( context );
1198         LPDWORD lpdwType   = (LPDWORD)stack32_pop( context );
1199         LPBYTE  lpbData    = (LPBYTE) stack32_pop( context );
1200         LPDWORD lpcbData   = (LPDWORD)stack32_pop( context );
1201         return VMM_RegQueryValueExA( hkey, lpszValue, lpReserved,
1202                                      lpdwType, lpbData, lpcbData );
1203     }
1204
1205     case 0x001B:  /* RegSetValueEx */
1206     {
1207         HKEY    hkey       = (HKEY)  stack32_pop( context );
1208         LPSTR   lpszValue  = (LPSTR) stack32_pop( context );
1209         DWORD   dwReserved = (DWORD) stack32_pop( context );
1210         DWORD   dwType     = (DWORD) stack32_pop( context );
1211         LPBYTE  lpbData    = (LPBYTE)stack32_pop( context );
1212         DWORD   cbData     = (DWORD) stack32_pop( context );
1213         return VMM_RegSetValueExA( hkey, lpszValue, dwReserved,
1214                                    dwType, lpbData, cbData );
1215     }
1216
1217     case 0x001C:  /* RegFlushKey */
1218     {
1219         HKEY hkey = (HKEY)stack32_pop( context );
1220         FIXME( "RegFlushKey(%p): stub\n", hkey );
1221         return ERROR_SUCCESS;
1222     }
1223
1224     case 0x001D:  /* RegQueryInfoKey */
1225     {
1226         /* NOTE: This VxDCall takes only a subset of the parameters that the
1227                  corresponding Win32 API call does. The implementation in Win95
1228                  ADVAPI32 sets all output parameters not mentioned here to zero. */
1229
1230         HKEY    hkey              = (HKEY)   stack32_pop( context );
1231         LPDWORD lpcSubKeys        = (LPDWORD)stack32_pop( context );
1232         LPDWORD lpcchMaxSubKey    = (LPDWORD)stack32_pop( context );
1233         LPDWORD lpcValues         = (LPDWORD)stack32_pop( context );
1234         LPDWORD lpcchMaxValueName = (LPDWORD)stack32_pop( context );
1235         LPDWORD lpcchMaxValueData = (LPDWORD)stack32_pop( context );
1236         return VMM_RegQueryInfoKeyA( hkey, lpcSubKeys, lpcchMaxSubKey,
1237                                      lpcValues, lpcchMaxValueName, lpcchMaxValueData );
1238     }
1239
1240     case 0x0021:  /* RegLoadKey */
1241     {
1242         HKEY    hkey       = (HKEY)  stack32_pop( context );
1243         LPCSTR  lpszSubKey = (LPCSTR)stack32_pop( context );
1244         LPCSTR  lpszFile   = (LPCSTR)stack32_pop( context );
1245         FIXME("RegLoadKey(%p,%s,%s): stub\n",hkey, debugstr_a(lpszSubKey), debugstr_a(lpszFile));
1246         return ERROR_SUCCESS;
1247     }
1248
1249     case 0x0022:  /* RegUnLoadKey */
1250     {
1251         HKEY    hkey       = (HKEY)  stack32_pop( context );
1252         LPCSTR  lpszSubKey = (LPCSTR)stack32_pop( context );
1253         FIXME("RegUnLoadKey(%p,%s): stub\n",hkey, debugstr_a(lpszSubKey));
1254         return ERROR_SUCCESS;
1255     }
1256
1257     case 0x0023:  /* RegSaveKey */
1258     {
1259         HKEY    hkey       = (HKEY)  stack32_pop( context );
1260         LPCSTR  lpszFile   = (LPCSTR)stack32_pop( context );
1261         LPSECURITY_ATTRIBUTES sa = (LPSECURITY_ATTRIBUTES)stack32_pop( context );
1262         FIXME("RegSaveKey(%p,%s,%p): stub\n",hkey, debugstr_a(lpszFile),sa);
1263         return ERROR_SUCCESS;
1264     }
1265
1266 #if 0 /* Functions are not yet implemented in misc/registry.c */
1267     case 0x0024:  /* RegRemapPreDefKey */
1268     case 0x0026:  /* RegQueryMultipleValues */
1269 #endif
1270
1271     case 0x0027:  /* RegReplaceKey */
1272     {
1273         HKEY    hkey       = (HKEY)  stack32_pop( context );
1274         LPCSTR  lpszSubKey = (LPCSTR)stack32_pop( context );
1275         LPCSTR  lpszNewFile= (LPCSTR)stack32_pop( context );
1276         LPCSTR  lpszOldFile= (LPCSTR)stack32_pop( context );
1277         FIXME("RegReplaceKey(%p,%s,%s,%s): stub\n", hkey, debugstr_a(lpszSubKey),
1278               debugstr_a(lpszNewFile),debugstr_a(lpszOldFile));
1279         return ERROR_SUCCESS;
1280     }
1281
1282     case 0x0000: /* PageReserve */
1283       {
1284         LPVOID address;
1285         LPVOID ret;
1286         DWORD psize = getpagesize();
1287         ULONG page   = (ULONG) stack32_pop( context );
1288         ULONG npages = (ULONG) stack32_pop( context );
1289         ULONG flags  = (ULONG) stack32_pop( context );
1290
1291         TRACE("PageReserve: page: %08lx, npages: %08lx, flags: %08lx partial stub!\n",
1292               page, npages, flags );
1293
1294         if ( page == PR_SYSTEM ) {
1295           ERR("Can't reserve ring 1 memory\n");
1296           return -1;
1297         }
1298         /* FIXME: This has to be handled separately for the separate
1299            address-spaces we now have */
1300         if ( page == PR_PRIVATE || page == PR_SHARED ) page = 0;
1301         /* FIXME: Handle flags in some way */
1302         address = (LPVOID )(page * psize);
1303         ret = VirtualAlloc ( address, ( npages * psize ), MEM_RESERVE, 0 );
1304         TRACE("PageReserve: returning: %08lx\n", (DWORD )ret );
1305         if ( ret == NULL )
1306           return -1;
1307         else
1308           return (DWORD )ret;
1309       }
1310
1311     case 0x0001: /* PageCommit */
1312       {
1313         LPVOID address;
1314         LPVOID ret;
1315         DWORD virt_perm;
1316         DWORD psize = getpagesize();
1317         ULONG page   = (ULONG) stack32_pop( context );
1318         ULONG npages = (ULONG) stack32_pop( context );
1319         ULONG hpd  = (ULONG) stack32_pop( context );
1320         ULONG pagerdata   = (ULONG) stack32_pop( context );
1321         ULONG flags  = (ULONG) stack32_pop( context );
1322
1323         TRACE("PageCommit: page: %08lx, npages: %08lx, hpd: %08lx pagerdata: "
1324               "%08lx, flags: %08lx partial stub\n",
1325               page, npages, hpd, pagerdata, flags );
1326
1327         if ( flags & PC_USER )
1328           if ( flags & PC_WRITEABLE )
1329             virt_perm = PAGE_EXECUTE_READWRITE;
1330           else
1331             virt_perm = PAGE_EXECUTE_READ;
1332         else
1333           virt_perm = PAGE_NOACCESS;
1334
1335         address = (LPVOID )(page * psize);
1336         ret = VirtualAlloc ( address, ( npages * psize ), MEM_COMMIT, virt_perm );
1337         TRACE("PageCommit: Returning: %08lx\n", (DWORD )ret );
1338         return (DWORD )ret;
1339
1340       }
1341     case 0x0002: /* PageDecommit */
1342       {
1343         LPVOID address;
1344         BOOL ret;
1345         DWORD psize = getpagesize();
1346         ULONG page = (ULONG) stack32_pop( context );
1347         ULONG npages = (ULONG) stack32_pop( context );
1348         ULONG flags = (ULONG) stack32_pop( context );
1349
1350         TRACE("PageDecommit: page: %08lx, npages: %08lx, flags: %08lx partial stub\n",
1351               page, npages, flags );
1352         address = (LPVOID )( page * psize );
1353         ret = VirtualFree ( address, ( npages * psize ), MEM_DECOMMIT );
1354         TRACE("PageDecommit: Returning: %s\n", ret ? "TRUE" : "FALSE" );
1355         return ret;
1356       }
1357     case 0x000d: /* PageModifyPermissions */
1358       {
1359         DWORD pg_old_perm;
1360         DWORD pg_new_perm;
1361         DWORD virt_old_perm;
1362         DWORD virt_new_perm;
1363         MEMORY_BASIC_INFORMATION mbi;
1364         LPVOID address;
1365         DWORD psize = getpagesize();
1366         ULONG page = stack32_pop ( context );
1367         ULONG npages = stack32_pop ( context );
1368         ULONG permand = stack32_pop ( context );
1369         ULONG permor = stack32_pop ( context );
1370
1371         TRACE("PageModifyPermissions %08lx %08lx %08lx %08lx partial stub\n",
1372               page, npages, permand, permor );
1373         address = (LPVOID )( page * psize );
1374
1375         VirtualQuery ( address, &mbi, sizeof ( MEMORY_BASIC_INFORMATION ));
1376         virt_old_perm = mbi.Protect;
1377
1378         switch ( virt_old_perm & mbi.Protect ) {
1379         case PAGE_READONLY:
1380         case PAGE_EXECUTE:
1381         case PAGE_EXECUTE_READ:
1382           pg_old_perm = PC_USER;
1383           break;
1384         case PAGE_READWRITE:
1385         case PAGE_WRITECOPY:
1386         case PAGE_EXECUTE_READWRITE:
1387         case PAGE_EXECUTE_WRITECOPY:
1388           pg_old_perm = PC_USER | PC_WRITEABLE;
1389           break;
1390         case PAGE_NOACCESS:
1391         default:
1392           pg_old_perm = 0;
1393           break;
1394         }
1395         pg_new_perm = pg_old_perm;
1396         pg_new_perm &= permand & ~PC_STATIC;
1397         pg_new_perm |= permor  & ~PC_STATIC;
1398
1399         virt_new_perm = ( virt_old_perm )  & ~0xff;
1400         if ( pg_new_perm & PC_USER )
1401         {
1402           if ( pg_new_perm & PC_WRITEABLE )
1403             virt_new_perm |= PAGE_EXECUTE_READWRITE;
1404           else
1405             virt_new_perm |= PAGE_EXECUTE_READ;
1406         }
1407
1408         if ( ! VirtualProtect ( address, ( npages * psize ), virt_new_perm, &virt_old_perm ) ) {
1409           ERR("Can't change page permissions for %08lx\n", (DWORD )address );
1410           return 0xffffffff;
1411         }
1412         TRACE("Returning: %08lx\n", pg_old_perm );
1413         return pg_old_perm;
1414       }
1415     case 0x000a: /* PageFree */
1416       {
1417         BOOL ret;
1418         LPVOID hmem = (LPVOID) stack32_pop( context );
1419         DWORD flags = (DWORD ) stack32_pop( context );
1420
1421         TRACE("PageFree: hmem: %08lx, flags: %08lx partial stub\n",
1422               (DWORD )hmem, flags );
1423
1424         ret = VirtualFree ( hmem, 0, MEM_RELEASE );
1425         context->Eax = ret;
1426         TRACE("Returning: %d\n", ret );
1427
1428         return 0;
1429       }
1430     case 0x001e: /* GetDemandPageInfo */
1431       {
1432          DWORD dinfo = (DWORD)stack32_pop( context );
1433          DWORD flags = (DWORD)stack32_pop( context );
1434
1435          /* GetDemandPageInfo is supposed to fill out the struct at
1436           * "dinfo" with various low-level memory management information.
1437           * Apps are certainly not supposed to call this, although it's
1438           * demoed and documented by Pietrek on pages 441-443 of "Windows
1439           * 95 System Programming Secrets" if any program needs a real
1440           * implementation of this.
1441           */
1442
1443          FIXME("GetDemandPageInfo(%08lx %08lx): stub!\n", dinfo, flags);
1444
1445          return 0;
1446       }
1447     default:
1448         if (LOWORD(service) < N_VMM_SERVICE)
1449             FIXME( "Unimplemented service %s (%08lx)\n",
1450                           VMM_Service_Name[LOWORD(service)], service);
1451         else
1452             FIXME( "Unknown service %08lx\n", service);
1453         break;
1454     }
1455
1456     return 0xffffffff;  /* FIXME */
1457 }
1458
1459 /***********************************************************************
1460  *           DeviceIo_IFSMgr
1461  * NOTES
1462  *   These ioctls are used by 'MSNET32.DLL'.
1463  *
1464  *   I have been unable to uncover any documentation about the ioctls so
1465  *   the implementation of the cases IFS_IOCTL_21 and IFS_IOCTL_2F are
1466  *   based on reasonable guesses on information found in the Windows 95 DDK.
1467  *
1468  */
1469
1470 /*
1471  * IFSMgr DeviceIO service
1472  */
1473
1474 #define IFS_IOCTL_21                100
1475 #define IFS_IOCTL_2F                101
1476 #define IFS_IOCTL_GET_RES           102
1477 #define IFS_IOCTL_GET_NETPRO_NAME_A 103
1478
1479 struct win32apireq {
1480         unsigned long   ar_proid;
1481         unsigned long   ar_eax;
1482         unsigned long   ar_ebx;
1483         unsigned long   ar_ecx;
1484         unsigned long   ar_edx;
1485         unsigned long   ar_esi;
1486         unsigned long   ar_edi;
1487         unsigned long   ar_ebp;
1488         unsigned short  ar_error;
1489         unsigned short  ar_pad;
1490 };
1491
1492 static void win32apieq_2_CONTEXT(struct win32apireq *pIn,CONTEXT86 *pCxt)
1493 {
1494         memset(pCxt,0,sizeof(*pCxt));
1495
1496         pCxt->ContextFlags=CONTEXT86_INTEGER|CONTEXT86_CONTROL;
1497         pCxt->Eax = pIn->ar_eax;
1498         pCxt->Ebx = pIn->ar_ebx;
1499         pCxt->Ecx = pIn->ar_ecx;
1500         pCxt->Edx = pIn->ar_edx;
1501         pCxt->Esi = pIn->ar_esi;
1502         pCxt->Edi = pIn->ar_edi;
1503
1504         /* FIXME: Only partial CONTEXT86_CONTROL */
1505         pCxt->Ebp = pIn->ar_ebp;
1506
1507         /* FIXME: pIn->ar_proid ignored */
1508         /* FIXME: pIn->ar_error ignored */
1509         /* FIXME: pIn->ar_pad ignored */
1510 }
1511
1512 static void CONTEXT_2_win32apieq(CONTEXT86 *pCxt,struct win32apireq *pOut)
1513 {
1514         memset(pOut,0,sizeof(struct win32apireq));
1515
1516         pOut->ar_eax = pCxt->Eax;
1517         pOut->ar_ebx = pCxt->Ebx;
1518         pOut->ar_ecx = pCxt->Ecx;
1519         pOut->ar_edx = pCxt->Edx;
1520         pOut->ar_esi = pCxt->Esi;
1521         pOut->ar_edi = pCxt->Edi;
1522
1523         /* FIXME: Only partial CONTEXT86_CONTROL */
1524         pOut->ar_ebp = pCxt->Ebp;
1525
1526         /* FIXME: pOut->ar_proid ignored */
1527         /* FIXME: pOut->ar_error ignored */
1528         /* FIXME: pOut->ar_pad ignored */
1529 }
1530
1531 static BOOL DeviceIo_IFSMgr(DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer,
1532                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
1533                               LPDWORD lpcbBytesReturned,
1534                               LPOVERLAPPED lpOverlapped)
1535 {
1536     BOOL retv = TRUE;
1537         TRACE("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
1538                         dwIoControlCode,
1539                         lpvInBuffer,cbInBuffer,
1540                         lpvOutBuffer,cbOutBuffer,
1541                         lpcbBytesReturned,
1542                         lpOverlapped);
1543
1544     switch (dwIoControlCode)
1545     {
1546         case IFS_IOCTL_21:
1547         case IFS_IOCTL_2F:{
1548                 CONTEXT86 cxt;
1549                 struct win32apireq *pIn=(struct win32apireq *) lpvInBuffer;
1550                 struct win32apireq *pOut=(struct win32apireq *) lpvOutBuffer;
1551
1552                 TRACE(
1553                         "Control '%s': "
1554                         "proid=0x%08lx, eax=0x%08lx, ebx=0x%08lx, ecx=0x%08lx, "
1555                         "edx=0x%08lx, esi=0x%08lx, edi=0x%08lx, ebp=0x%08lx, "
1556                         "error=0x%04x, pad=0x%04x\n",
1557                         (dwIoControlCode==IFS_IOCTL_21)?"IFS_IOCTL_21":"IFS_IOCTL_2F",
1558                         pIn->ar_proid, pIn->ar_eax, pIn->ar_ebx, pIn->ar_ecx,
1559                         pIn->ar_edx, pIn->ar_esi, pIn->ar_edi, pIn->ar_ebp,
1560                         pIn->ar_error, pIn->ar_pad
1561                 );
1562
1563                 win32apieq_2_CONTEXT(pIn,&cxt);
1564
1565                 if(dwIoControlCode==IFS_IOCTL_21)
1566                 {
1567                     if(Dosvm.CallBuiltinHandler || DPMI_LoadDosSystem())
1568                         Dosvm.CallBuiltinHandler( &cxt, 0x21 );
1569                } 
1570                 else 
1571                 {
1572                     if(Dosvm.CallBuiltinHandler || DPMI_LoadDosSystem())
1573                         Dosvm.CallBuiltinHandler( &cxt, 0x2f );
1574                 }
1575
1576                 CONTEXT_2_win32apieq(&cxt,pOut);
1577
1578         retv = TRUE;
1579         } break;
1580         case IFS_IOCTL_GET_RES:{
1581         FIXME( "Control 'IFS_IOCTL_GET_RES' not implemented\n");
1582         retv = FALSE;
1583         } break;
1584         case IFS_IOCTL_GET_NETPRO_NAME_A:{
1585         FIXME( "Control 'IFS_IOCTL_GET_NETPRO_NAME_A' not implemented\n");
1586         retv = FALSE;
1587         } break;
1588     default:
1589         FIXME( "Control %ld not implemented\n", dwIoControlCode);
1590         retv = FALSE;
1591     }
1592
1593     return retv;
1594 }
1595
1596 /********************************************************************************
1597  *      VxDCall_VWin32
1598  *
1599  *  Service numbers taken from page 448 of Pietrek's "Windows 95 System
1600  *  Programming Secrets".  Parameters from experimentation on real Win98.
1601  *
1602  */
1603
1604 static DWORD VxDCall_VWin32( DWORD service, CONTEXT86 *context )
1605 {
1606   switch ( LOWORD(service) )
1607     {
1608     case 0x0000: /* GetVersion */
1609     {
1610         DWORD vers = GetVersion();
1611         return (LOBYTE(vers) << 8) | HIBYTE(vers);
1612     }
1613     break;
1614
1615     case 0x0020: /* Get VMCPD Version */
1616     {
1617         DWORD parm = (DWORD) stack32_pop(context);
1618
1619         FIXME("Get VMCPD Version(%08lx): partial stub!\n", parm);
1620
1621         /* FIXME: This is what Win98 returns, it may
1622          *        not be correct in all situations.
1623          *        It makes Bleem! happy though.
1624          */
1625
1626         return 0x0405;
1627     }
1628
1629     case 0x0029: /* Int31/DPMI dispatch */
1630     {
1631         DWORD callnum = (DWORD) stack32_pop(context);
1632         DWORD parm    = (DWORD) stack32_pop(context);
1633
1634         TRACE("Int31/DPMI dispatch(%08lx)\n", callnum);
1635
1636         SET_AX( context, callnum );
1637         SET_CX( context, parm );
1638         if(Dosvm.CallBuiltinHandler || DPMI_LoadDosSystem())
1639             Dosvm.CallBuiltinHandler( context, 0x31 );
1640
1641         return LOWORD(context->Eax);
1642     }
1643     break;
1644
1645     case 0x002a: /* Int41 dispatch - parm = int41 service number */
1646     {
1647         DWORD callnum = (DWORD) stack32_pop(context);
1648
1649         return callnum; /* FIXME: should really call INT_Int41Handler() */
1650     }
1651     break;
1652
1653     default:
1654       FIXME("Unknown VWin32 service %08lx\n", service);
1655       break;
1656     }
1657
1658   return 0xffffffff;
1659 }
1660
1661
1662 /***********************************************************************
1663  *           DeviceIo_VCD
1664  */
1665 static BOOL DeviceIo_VCD(DWORD dwIoControlCode,
1666                               LPVOID lpvInBuffer, DWORD cbInBuffer,
1667                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
1668                               LPDWORD lpcbBytesReturned,
1669                               LPOVERLAPPED lpOverlapped)
1670 {
1671     BOOL retv = TRUE;
1672
1673     switch (dwIoControlCode)
1674     {
1675     case IOCTL_SERIAL_LSRMST_INSERT:
1676     {
1677         FIXME( "IOCTL_SERIAL_LSRMST_INSERT NIY !\n");
1678         retv = FALSE;
1679     }
1680     break;
1681
1682     default:
1683         FIXME( "Unknown Control %ld\n", dwIoControlCode);
1684         retv = FALSE;
1685         break;
1686     }
1687
1688     return retv;
1689 }
1690
1691
1692 /***********************************************************************
1693  *           DeviceIo_VWin32
1694  */
1695
1696 static void DIOCRegs_2_CONTEXT( DIOC_REGISTERS *pIn, CONTEXT86 *pCxt )
1697 {
1698     memset( pCxt, 0, sizeof(*pCxt) );
1699     /* Note: segment registers == 0 means that CTX_SEG_OFF_TO_LIN
1700              will interpret 32-bit register contents as linear pointers */
1701
1702     pCxt->ContextFlags=CONTEXT86_INTEGER|CONTEXT86_CONTROL;
1703     pCxt->Eax = pIn->reg_EAX;
1704     pCxt->Ebx = pIn->reg_EBX;
1705     pCxt->Ecx = pIn->reg_ECX;
1706     pCxt->Edx = pIn->reg_EDX;
1707     pCxt->Esi = pIn->reg_ESI;
1708     pCxt->Edi = pIn->reg_EDI;
1709
1710     /* FIXME: Only partial CONTEXT86_CONTROL */
1711     pCxt->EFlags = pIn->reg_Flags;
1712 }
1713
1714 static void CONTEXT_2_DIOCRegs( CONTEXT86 *pCxt, DIOC_REGISTERS *pOut )
1715 {
1716     memset( pOut, 0, sizeof(DIOC_REGISTERS) );
1717
1718     pOut->reg_EAX = pCxt->Eax;
1719     pOut->reg_EBX = pCxt->Ebx;
1720     pOut->reg_ECX = pCxt->Ecx;
1721     pOut->reg_EDX = pCxt->Edx;
1722     pOut->reg_ESI = pCxt->Esi;
1723     pOut->reg_EDI = pCxt->Edi;
1724
1725     /* FIXME: Only partial CONTEXT86_CONTROL */
1726     pOut->reg_Flags = pCxt->EFlags;
1727 }
1728
1729 #define DIOC_AH(regs) (((unsigned char*)&((regs)->reg_EAX))[1])
1730 #define DIOC_AL(regs) (((unsigned char*)&((regs)->reg_EAX))[0])
1731 #define DIOC_BH(regs) (((unsigned char*)&((regs)->reg_EBX))[1])
1732 #define DIOC_BL(regs) (((unsigned char*)&((regs)->reg_EBX))[0])
1733 #define DIOC_DH(regs) (((unsigned char*)&((regs)->reg_EDX))[1])
1734 #define DIOC_DL(regs) (((unsigned char*)&((regs)->reg_EDX))[0])
1735
1736 #define DIOC_AX(regs) (((unsigned short*)&((regs)->reg_EAX))[0])
1737 #define DIOC_BX(regs) (((unsigned short*)&((regs)->reg_EBX))[0])
1738 #define DIOC_CX(regs) (((unsigned short*)&((regs)->reg_ECX))[0])
1739 #define DIOC_DX(regs) (((unsigned short*)&((regs)->reg_EDX))[0])
1740
1741 #define DIOC_SET_CARRY(regs) (((regs)->reg_Flags)|=0x00000001)
1742
1743 static BOOL DeviceIo_VWin32(DWORD dwIoControlCode,
1744                               LPVOID lpvInBuffer, DWORD cbInBuffer,
1745                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
1746                               LPDWORD lpcbBytesReturned,
1747                               LPOVERLAPPED lpOverlapped)
1748 {
1749     BOOL retv = TRUE;
1750
1751     switch (dwIoControlCode)
1752     {
1753     case VWIN32_DIOC_DOS_IOCTL:
1754     case 0x10: /* Int 0x21 call, call it VWIN_DIOC_INT21 ? */
1755     case VWIN32_DIOC_DOS_INT13:
1756     case VWIN32_DIOC_DOS_INT25:
1757     case VWIN32_DIOC_DOS_INT26:
1758     case 0x29: /* Int 0x31 call, call it VWIN_DIOC_INT31 ? */
1759     case VWIN32_DIOC_DOS_DRIVEINFO:
1760     {
1761         CONTEXT86 cxt;
1762         DIOC_REGISTERS *pIn  = (DIOC_REGISTERS *)lpvInBuffer;
1763         DIOC_REGISTERS *pOut = (DIOC_REGISTERS *)lpvOutBuffer;
1764         BYTE intnum = 0;
1765
1766         TRACE( "Control '%s': "
1767                "eax=0x%08lx, ebx=0x%08lx, ecx=0x%08lx, "
1768                "edx=0x%08lx, esi=0x%08lx, edi=0x%08lx \n",
1769                (dwIoControlCode == VWIN32_DIOC_DOS_IOCTL)? "VWIN32_DIOC_DOS_IOCTL" :
1770                (dwIoControlCode == VWIN32_DIOC_DOS_INT25)? "VWIN32_DIOC_DOS_INT25" :
1771                (dwIoControlCode == VWIN32_DIOC_DOS_INT26)? "VWIN32_DIOC_DOS_INT26" :
1772                (dwIoControlCode == VWIN32_DIOC_DOS_DRIVEINFO)? "VWIN32_DIOC_DOS_DRIVEINFO" :  "???",
1773                pIn->reg_EAX, pIn->reg_EBX, pIn->reg_ECX,
1774                pIn->reg_EDX, pIn->reg_ESI, pIn->reg_EDI );
1775
1776         DIOCRegs_2_CONTEXT( pIn, &cxt );
1777
1778         switch (dwIoControlCode)
1779         {
1780         case VWIN32_DIOC_DOS_IOCTL: /* Call int 21h */
1781         case 0x10: /* Int 0x21 call, call it VWIN_DIOC_INT21 ? */
1782         case VWIN32_DIOC_DOS_DRIVEINFO:        /* Call int 21h 730x */
1783             intnum = 0x21;
1784             break;
1785         case VWIN32_DIOC_DOS_INT13:
1786             intnum = 0x13;
1787             break;
1788         case VWIN32_DIOC_DOS_INT25: 
1789             intnum = 0x25;
1790             break;
1791         case VWIN32_DIOC_DOS_INT26:
1792             intnum = 0x26;
1793             break;
1794         case 0x29: /* Int 0x31 call, call it VWIN_DIOC_INT31 ? */
1795             intnum = 0x31;
1796             break;
1797         }
1798
1799         if(Dosvm.CallBuiltinHandler || DPMI_LoadDosSystem())
1800             Dosvm.CallBuiltinHandler( &cxt, intnum );
1801
1802         CONTEXT_2_DIOCRegs( &cxt, pOut );
1803     }
1804     break;
1805
1806     case VWIN32_DIOC_SIMCTRLC:
1807         FIXME( "Control VWIN32_DIOC_SIMCTRLC not implemented\n");
1808         retv = FALSE;
1809         break;
1810
1811     default:
1812         FIXME( "Unknown Control %ld\n", dwIoControlCode);
1813         retv = FALSE;
1814         break;
1815     }
1816
1817     return retv;
1818 }
1819
1820 /* this is the main multimedia device loader */
1821 static BOOL DeviceIo_MMDEVLDR(DWORD dwIoControlCode,
1822                               LPVOID lpvInBuffer, DWORD cbInBuffer,
1823                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
1824                               LPDWORD lpcbBytesReturned,
1825                               LPOVERLAPPED lpOverlapped)
1826 {
1827         FIXME("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
1828             dwIoControlCode,
1829             lpvInBuffer,cbInBuffer,
1830             lpvOutBuffer,cbOutBuffer,
1831             lpcbBytesReturned,
1832             lpOverlapped
1833         );
1834         switch (dwIoControlCode) {
1835         case 5:
1836                 /* Hmm. */
1837                 *(DWORD*)lpvOutBuffer=0;
1838                 *lpcbBytesReturned=4;
1839                 return TRUE;
1840         }
1841         return FALSE;
1842 }
1843 /* this is used by some Origin games */
1844 static BOOL DeviceIo_MONODEBG(DWORD dwIoControlCode,
1845                               LPVOID lpvInBuffer, DWORD cbInBuffer,
1846                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
1847                               LPDWORD lpcbBytesReturned,
1848                               LPOVERLAPPED lpOverlapped)
1849 {
1850         switch (dwIoControlCode) {
1851         case 1: /* version */
1852                 *(LPDWORD)lpvOutBuffer = 0x20004; /* WC SecretOps */
1853                 break;
1854         case 9: /* debug output */
1855                 ERR("MONODEBG: %s\n",debugstr_a(lpvInBuffer));
1856                 break;
1857         default:
1858                 FIXME("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
1859                         dwIoControlCode,
1860                         lpvInBuffer,cbInBuffer,
1861                         lpvOutBuffer,cbOutBuffer,
1862                         lpcbBytesReturned,
1863                         lpOverlapped
1864                 );
1865                 break;
1866         }
1867         return TRUE;
1868 }
1869 /* pccard */
1870 static BOOL DeviceIo_PCCARD (DWORD dwIoControlCode,
1871                               LPVOID lpvInBuffer, DWORD cbInBuffer,
1872                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
1873                               LPDWORD lpcbBytesReturned,
1874                               LPOVERLAPPED lpOverlapped)
1875 {
1876         switch (dwIoControlCode) {
1877         case 0x0000: /* PCCARD_Get_Version */
1878         case 0x0001: /* PCCARD_Card_Services */
1879         default:
1880                 FIXME( "(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
1881                         dwIoControlCode,
1882                         lpvInBuffer,cbInBuffer,
1883                         lpvOutBuffer,cbOutBuffer,
1884                         lpcbBytesReturned,
1885                         lpOverlapped
1886                 );
1887                 break;
1888         }
1889         return FALSE;
1890 }
1891
1892 /***********************************************************************
1893  *              OpenVxDHandle (KERNEL32.@)
1894  *
1895  *      This function is supposed to return the corresponding Ring 0
1896  *      ("kernel") handle for a Ring 3 handle in Win9x.
1897  *      Evidently, Wine will have problems with this. But we try anyway,
1898  *      maybe it helps...
1899  */
1900 HANDLE  WINAPI  OpenVxDHandle(HANDLE hHandleRing3)
1901 {
1902         FIXME( "(%p), stub! (returning Ring 3 handle instead of Ring 0)\n", hHandleRing3);
1903         return hHandleRing3;
1904 }
1905
1906 static BOOL DeviceIo_HASP(DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer,
1907                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
1908                               LPDWORD lpcbBytesReturned,
1909                               LPOVERLAPPED lpOverlapped)
1910 {
1911     BOOL retv = TRUE;
1912         FIXME("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
1913                         dwIoControlCode,
1914                         lpvInBuffer,cbInBuffer,
1915                         lpvOutBuffer,cbOutBuffer,
1916                         lpcbBytesReturned,
1917                         lpOverlapped);
1918
1919     return retv;
1920 }