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