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