Allow the implementation of the VxDCall entry points to be moved to
separate VxD dlls.
Moved VMM code to a separate dll, and removed the registry calls to
get rid of the code duplication with advapi32.
diff --git a/configure b/configure
index c2f8f81..a058176 100755
--- a/configure
+++ b/configure
@@ -19116,7 +19116,7 @@
MAKE_PROG_RULES=programs/Makeprog.rules
- ac_config_files="$ac_config_files Make.rules dlls/Makedll.rules dlls/Maketest.rules libs/Makelib.rules programs/Makeprog.rules Makefile dlls/Makefile dlls/advapi32/Makefile dlls/advapi32/tests/Makefile dlls/avicap32/Makefile dlls/avifil32/Makefile dlls/cabinet/Makefile dlls/capi2032/Makefile dlls/cfgmgr32/Makefile dlls/comcat/Makefile dlls/comctl32/Makefile dlls/comctl32/tests/Makefile dlls/commdlg/Makefile dlls/crtdll/Makefile dlls/crypt32/Makefile dlls/ctl3d/Makefile dlls/d3d8/Makefile dlls/d3d9/Makefile dlls/d3dim/Makefile dlls/d3dx8/Makefile dlls/dciman32/Makefile dlls/ddraw/Makefile dlls/ddraw/tests/Makefile dlls/devenum/Makefile dlls/dinput/Makefile dlls/dinput8/Makefile dlls/dmband/Makefile dlls/dmcompos/Makefile dlls/dmime/Makefile dlls/dmloader/Makefile dlls/dmscript/Makefile dlls/dmstyle/Makefile dlls/dmsynth/Makefile dlls/dmusic/Makefile dlls/dmusic32/Makefile dlls/dplay/Makefile dlls/dplayx/Makefile dlls/dpnhpast/Makefile dlls/dsound/Makefile dlls/dsound/tests/Makefile dlls/dswave/Makefile dlls/dxguid/Makefile dlls/gdi/Makefile dlls/gdi/tests/Makefile dlls/glu32/Makefile dlls/glut32/Makefile dlls/iccvid/Makefile dlls/icmp/Makefile dlls/ifsmgr.vxd/Makefile dlls/imagehlp/Makefile dlls/imm32/Makefile dlls/iphlpapi/Makefile dlls/iphlpapi/tests/Makefile dlls/kernel/Makefile dlls/kernel/tests/Makefile dlls/lzexpand/Makefile dlls/mapi32/Makefile dlls/mmdevldr.vxd/Makefile dlls/monodebg.vxd/Makefile dlls/mpr/Makefile dlls/msacm/Makefile dlls/msacm/imaadp32/Makefile dlls/msacm/msadp32/Makefile dlls/msacm/msg711/Makefile dlls/msacm/winemp3/Makefile dlls/msdmo/Makefile dlls/mshtml/Makefile dlls/msi/Makefile dlls/msimg32/Makefile dlls/msisys/Makefile dlls/msnet32/Makefile dlls/msvcrt/Makefile dlls/msvcrt/tests/Makefile dlls/msvcrt20/Makefile dlls/msvcrt40/Makefile dlls/msvcrtd/Makefile dlls/msvidc32/Makefile dlls/msvideo/Makefile dlls/msvideo/msrle32/Makefile dlls/mswsock/Makefile dlls/netapi32/Makefile dlls/netapi32/tests/Makefile dlls/newdev/Makefile dlls/ntdll/Makefile dlls/ntdll/tests/Makefile dlls/odbc32/Makefile dlls/ole32/Makefile dlls/oleacc/Makefile dlls/oleaut32/Makefile dlls/oleaut32/tests/Makefile dlls/olecli/Makefile dlls/oledlg/Makefile dlls/olepro32/Makefile dlls/olesvr/Makefile dlls/opengl32/Makefile dlls/psapi/Makefile dlls/qcap/Makefile dlls/quartz/Makefile dlls/rasapi32/Makefile dlls/richedit/Makefile dlls/rpcrt4/Makefile dlls/rpcrt4/tests/Makefile dlls/rsabase/Makefile dlls/serialui/Makefile dlls/setupapi/Makefile dlls/shdocvw/Makefile dlls/shell32/Makefile dlls/shell32/tests/Makefile dlls/shfolder/Makefile dlls/shlwapi/Makefile dlls/shlwapi/tests/Makefile dlls/snmpapi/Makefile dlls/sti/Makefile dlls/tapi32/Makefile dlls/ttydrv/Makefile dlls/twain/Makefile dlls/unicows/Makefile dlls/url/Makefile dlls/urlmon/Makefile dlls/urlmon/tests/Makefile dlls/user/Makefile dlls/user/tests/Makefile dlls/uuid/Makefile dlls/uxtheme/Makefile dlls/vdhcp.vxd/Makefile dlls/version/Makefile dlls/vnb.vxd/Makefile dlls/vnetbios.vxd/Makefile dlls/vtdapi.vxd/Makefile dlls/vwin32.vxd/Makefile dlls/win32s/Makefile dlls/winaspi/Makefile dlls/wined3d/Makefile dlls/winedos/Makefile dlls/wineps/Makefile dlls/wininet/Makefile dlls/wininet/tests/Makefile dlls/winmm/Makefile dlls/winmm/joystick/Makefile dlls/winmm/mcianim/Makefile dlls/winmm/mciavi/Makefile dlls/winmm/mcicda/Makefile dlls/winmm/mciseq/Makefile dlls/winmm/mciwave/Makefile dlls/winmm/midimap/Makefile dlls/winmm/tests/Makefile dlls/winmm/wavemap/Makefile dlls/winmm/winealsa/Makefile dlls/winmm/winearts/Makefile dlls/winmm/wineaudioio/Makefile dlls/winmm/winejack/Makefile dlls/winmm/winenas/Makefile dlls/winmm/wineoss/Makefile dlls/winnls/Makefile dlls/winsock/Makefile dlls/winsock/tests/Makefile dlls/winspool/Makefile dlls/winspool/tests/Makefile dlls/wintab32/Makefile dlls/wintrust/Makefile dlls/wow32/Makefile dlls/wsock32/Makefile dlls/x11drv/Makefile documentation/Makefile include/Makefile libs/Makefile libs/port/Makefile libs/unicode/Makefile libs/wine/Makefile libs/wpp/Makefile loader/Makefile programs/Makefile programs/avitools/Makefile programs/clock/Makefile programs/cmdlgtst/Makefile programs/control/Makefile programs/expand/Makefile programs/notepad/Makefile programs/progman/Makefile programs/regedit/Makefile programs/regsvr32/Makefile programs/rpcss/Makefile programs/rundll32/Makefile programs/start/Makefile programs/uninstaller/Makefile programs/view/Makefile programs/wcmd/Makefile programs/wineboot/Makefile programs/winebrowser/Makefile programs/winecfg/Makefile programs/wineconsole/Makefile programs/winedbg/Makefile programs/winefile/Makefile programs/winemenubuilder/Makefile programs/winemine/Makefile programs/winepath/Makefile programs/winetest/Makefile programs/winevdm/Makefile programs/winhelp/Makefile programs/winver/Makefile server/Makefile tools/Makefile tools/widl/Makefile tools/winapi/Makefile tools/winebuild/Makefile tools/winedump/Makefile tools/winegcc/Makefile tools/wmc/Makefile tools/wrc/Makefile"
+ ac_config_files="$ac_config_files Make.rules dlls/Makedll.rules dlls/Maketest.rules libs/Makelib.rules programs/Makeprog.rules Makefile dlls/Makefile dlls/advapi32/Makefile dlls/advapi32/tests/Makefile dlls/avicap32/Makefile dlls/avifil32/Makefile dlls/cabinet/Makefile dlls/capi2032/Makefile dlls/cfgmgr32/Makefile dlls/comcat/Makefile dlls/comctl32/Makefile dlls/comctl32/tests/Makefile dlls/commdlg/Makefile dlls/crtdll/Makefile dlls/crypt32/Makefile dlls/ctl3d/Makefile dlls/d3d8/Makefile dlls/d3d9/Makefile dlls/d3dim/Makefile dlls/d3dx8/Makefile dlls/dciman32/Makefile dlls/ddraw/Makefile dlls/ddraw/tests/Makefile dlls/devenum/Makefile dlls/dinput/Makefile dlls/dinput8/Makefile dlls/dmband/Makefile dlls/dmcompos/Makefile dlls/dmime/Makefile dlls/dmloader/Makefile dlls/dmscript/Makefile dlls/dmstyle/Makefile dlls/dmsynth/Makefile dlls/dmusic/Makefile dlls/dmusic32/Makefile dlls/dplay/Makefile dlls/dplayx/Makefile dlls/dpnhpast/Makefile dlls/dsound/Makefile dlls/dsound/tests/Makefile dlls/dswave/Makefile dlls/dxguid/Makefile dlls/gdi/Makefile dlls/gdi/tests/Makefile dlls/glu32/Makefile dlls/glut32/Makefile dlls/iccvid/Makefile dlls/icmp/Makefile dlls/ifsmgr.vxd/Makefile dlls/imagehlp/Makefile dlls/imm32/Makefile dlls/iphlpapi/Makefile dlls/iphlpapi/tests/Makefile dlls/kernel/Makefile dlls/kernel/tests/Makefile dlls/lzexpand/Makefile dlls/mapi32/Makefile dlls/mmdevldr.vxd/Makefile dlls/monodebg.vxd/Makefile dlls/mpr/Makefile dlls/msacm/Makefile dlls/msacm/imaadp32/Makefile dlls/msacm/msadp32/Makefile dlls/msacm/msg711/Makefile dlls/msacm/winemp3/Makefile dlls/msdmo/Makefile dlls/mshtml/Makefile dlls/msi/Makefile dlls/msimg32/Makefile dlls/msisys/Makefile dlls/msnet32/Makefile dlls/msvcrt/Makefile dlls/msvcrt/tests/Makefile dlls/msvcrt20/Makefile dlls/msvcrt40/Makefile dlls/msvcrtd/Makefile dlls/msvidc32/Makefile dlls/msvideo/Makefile dlls/msvideo/msrle32/Makefile dlls/mswsock/Makefile dlls/netapi32/Makefile dlls/netapi32/tests/Makefile dlls/newdev/Makefile dlls/ntdll/Makefile dlls/ntdll/tests/Makefile dlls/odbc32/Makefile dlls/ole32/Makefile dlls/oleacc/Makefile dlls/oleaut32/Makefile dlls/oleaut32/tests/Makefile dlls/olecli/Makefile dlls/oledlg/Makefile dlls/olepro32/Makefile dlls/olesvr/Makefile dlls/opengl32/Makefile dlls/psapi/Makefile dlls/qcap/Makefile dlls/quartz/Makefile dlls/rasapi32/Makefile dlls/richedit/Makefile dlls/rpcrt4/Makefile dlls/rpcrt4/tests/Makefile dlls/rsabase/Makefile dlls/serialui/Makefile dlls/setupapi/Makefile dlls/shdocvw/Makefile dlls/shell32/Makefile dlls/shell32/tests/Makefile dlls/shfolder/Makefile dlls/shlwapi/Makefile dlls/shlwapi/tests/Makefile dlls/snmpapi/Makefile dlls/sti/Makefile dlls/tapi32/Makefile dlls/ttydrv/Makefile dlls/twain/Makefile dlls/unicows/Makefile dlls/url/Makefile dlls/urlmon/Makefile dlls/urlmon/tests/Makefile dlls/user/Makefile dlls/user/tests/Makefile dlls/uuid/Makefile dlls/uxtheme/Makefile dlls/vdhcp.vxd/Makefile dlls/version/Makefile dlls/vmm.vxd/Makefile dlls/vnb.vxd/Makefile dlls/vnetbios.vxd/Makefile dlls/vtdapi.vxd/Makefile dlls/vwin32.vxd/Makefile dlls/win32s/Makefile dlls/winaspi/Makefile dlls/wined3d/Makefile dlls/winedos/Makefile dlls/wineps/Makefile dlls/wininet/Makefile dlls/wininet/tests/Makefile dlls/winmm/Makefile dlls/winmm/joystick/Makefile dlls/winmm/mcianim/Makefile dlls/winmm/mciavi/Makefile dlls/winmm/mcicda/Makefile dlls/winmm/mciseq/Makefile dlls/winmm/mciwave/Makefile dlls/winmm/midimap/Makefile dlls/winmm/tests/Makefile dlls/winmm/wavemap/Makefile dlls/winmm/winealsa/Makefile dlls/winmm/winearts/Makefile dlls/winmm/wineaudioio/Makefile dlls/winmm/winejack/Makefile dlls/winmm/winenas/Makefile dlls/winmm/wineoss/Makefile dlls/winnls/Makefile dlls/winsock/Makefile dlls/winsock/tests/Makefile dlls/winspool/Makefile dlls/winspool/tests/Makefile dlls/wintab32/Makefile dlls/wintrust/Makefile dlls/wow32/Makefile dlls/wsock32/Makefile dlls/x11drv/Makefile documentation/Makefile include/Makefile libs/Makefile libs/port/Makefile libs/unicode/Makefile libs/wine/Makefile libs/wpp/Makefile loader/Makefile programs/Makefile programs/avitools/Makefile programs/clock/Makefile programs/cmdlgtst/Makefile programs/control/Makefile programs/expand/Makefile programs/notepad/Makefile programs/progman/Makefile programs/regedit/Makefile programs/regsvr32/Makefile programs/rpcss/Makefile programs/rundll32/Makefile programs/start/Makefile programs/uninstaller/Makefile programs/view/Makefile programs/wcmd/Makefile programs/wineboot/Makefile programs/winebrowser/Makefile programs/winecfg/Makefile programs/wineconsole/Makefile programs/winedbg/Makefile programs/winefile/Makefile programs/winemenubuilder/Makefile programs/winemine/Makefile programs/winepath/Makefile programs/winetest/Makefile programs/winevdm/Makefile programs/winhelp/Makefile programs/winver/Makefile server/Makefile tools/Makefile tools/widl/Makefile tools/winapi/Makefile tools/winebuild/Makefile tools/winedump/Makefile tools/winegcc/Makefile tools/wmc/Makefile tools/wrc/Makefile"
cat >confcache <<\_ACEOF
@@ -19778,6 +19778,7 @@
"dlls/uxtheme/Makefile" ) CONFIG_FILES="$CONFIG_FILES dlls/uxtheme/Makefile" ;;
"dlls/vdhcp.vxd/Makefile" ) CONFIG_FILES="$CONFIG_FILES dlls/vdhcp.vxd/Makefile" ;;
"dlls/version/Makefile" ) CONFIG_FILES="$CONFIG_FILES dlls/version/Makefile" ;;
+ "dlls/vmm.vxd/Makefile" ) CONFIG_FILES="$CONFIG_FILES dlls/vmm.vxd/Makefile" ;;
"dlls/vnb.vxd/Makefile" ) CONFIG_FILES="$CONFIG_FILES dlls/vnb.vxd/Makefile" ;;
"dlls/vnetbios.vxd/Makefile" ) CONFIG_FILES="$CONFIG_FILES dlls/vnetbios.vxd/Makefile" ;;
"dlls/vtdapi.vxd/Makefile" ) CONFIG_FILES="$CONFIG_FILES dlls/vtdapi.vxd/Makefile" ;;
diff --git a/configure.ac b/configure.ac
index e7c77dd..12e8fc7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1591,6 +1591,7 @@
dlls/uxtheme/Makefile
dlls/vdhcp.vxd/Makefile
dlls/version/Makefile
+dlls/vmm.vxd/Makefile
dlls/vnb.vxd/Makefile
dlls/vnetbios.vxd/Makefile
dlls/vtdapi.vxd/Makefile
diff --git a/dlls/Makefile.in b/dlls/Makefile.in
index a6abe53..923c366 100644
--- a/dlls/Makefile.in
+++ b/dlls/Makefile.in
@@ -115,6 +115,7 @@
uxtheme \
vdhcp.vxd \
version \
+ vmm.vxd \
vnb.vxd \
vnetbios.vxd \
vtdapi.vxd \
@@ -330,6 +331,7 @@
uxtheme.dll$(DLLEXT) \
vdhcp.vxd$(DLLEXT) \
version.dll$(DLLEXT) \
+ vmm.vxd$(DLLEXT) \
vnb.vxd$(DLLEXT) \
vnetbios.vxd$(DLLEXT) \
vtdapi.vxd$(DLLEXT) \
@@ -759,6 +761,9 @@
ver.dll$(DLLEXT) : version.dll$(DLLEXT)
$(RM) $@ && $(LN_S) version.dll$(DLLEXT) $@
+vmm.vxd$(DLLEXT): vmm.vxd/vmm.vxd$(DLLEXT)
+ $(RM) $@ && $(LN_S) vmm.vxd/vmm.vxd$(DLLEXT) $@
+
vnb.vxd$(DLLEXT): vnb.vxd/vnb.vxd$(DLLEXT)
$(RM) $@ && $(LN_S) vnb.vxd/vnb.vxd$(DLLEXT) $@
@@ -1780,6 +1785,7 @@
uxtheme/uxtheme.dll$(DLLEXT): uxtheme
vdhcp.vxd/vdhcp.vxd$(DLLEXT): vdhcp.vxd
version/version.dll$(DLLEXT): version
+vmm.vxd/vmm.vxd$(DLLEXT): vmm.vxd
vnb.vxd/vnb.vxd$(DLLEXT): vnb.vxd
vnetbios.vxd/vnetbios.vxd$(DLLEXT): vnetbios.vxd
vtdapi.vxd/vtdapi.vxd$(DLLEXT): vtdapi.vxd
diff --git a/dlls/kernel/vxd.c b/dlls/kernel/vxd.c
index ad14e64..e0bffe8 100644
--- a/dlls/kernel/vxd.c
+++ b/dlls/kernel/vxd.c
@@ -36,13 +36,9 @@
#include "winbase.h"
#include "winreg.h"
#include "winerror.h"
-#include "winnls.h"
-#include "ntstatus.h"
-#include "winnt.h"
-#include "winternl.h"
-#include "wine/winbase16.h"
#include "file.h"
#include "kernel_private.h"
+#include "wine/library.h"
#include "wine/unicode.h"
#include "wine/server.h"
#include "wine/debug.h"
@@ -50,6 +46,7 @@
WINE_DEFAULT_DEBUG_CHANNEL(vxd);
typedef BOOL (WINAPI *DeviceIoProc)(DWORD, LPVOID, DWORD, LPVOID, DWORD, LPDWORD, LPOVERLAPPED);
+typedef DWORD (WINAPI *VxDCallProc)(DWORD, CONTEXT86 *);
struct vxd_module
{
@@ -60,10 +57,26 @@
DeviceIoProc proc;
};
+struct vxdcall_service
+{
+ WCHAR name[12];
+ DWORD service;
+ HMODULE module;
+ VxDCallProc proc;
+};
+
#define MAX_VXD_MODULES 32
static struct vxd_module vxd_modules[MAX_VXD_MODULES];
+static struct vxdcall_service vxd_services[] =
+{
+ { {'v','m','m','.','v','x','d',0}, 0x0001, NULL, NULL },
+ { {'v','w','i','n','3','2','.','v','x','d',0}, 0x002a, NULL, NULL }
+};
+
+#define NB_VXD_SERVICES (sizeof(vxd_services)/sizeof(vxd_services[0]))
+
static CRITICAL_SECTION vxd_section;
static CRITICAL_SECTION_DEBUG critsect_debug =
{
@@ -117,6 +130,7 @@
SetLastError( ERROR_INVALID_HANDLE );
return NULL;
}
+ wine_server_release_fd( handle, fd );
RtlEnterCriticalSection( &vxd_section );
@@ -233,1078 +247,6 @@
}
-/*
- * VMM VxDCall service names are (mostly) taken from Stan Mitchell's
- * "Inside the Windows 95 File System"
- */
-
-#define N_VMM_SERVICE 41
-
-static const char * const VMM_Service_Name[N_VMM_SERVICE] =
-{
- "PageReserve", /* 0x0000 */
- "PageCommit", /* 0x0001 */
- "PageDecommit", /* 0x0002 */
- "PagerRegister", /* 0x0003 */
- "PagerQuery", /* 0x0004 */
- "HeapAllocate", /* 0x0005 */
- "ContextCreate", /* 0x0006 */
- "ContextDestroy", /* 0x0007 */
- "PageAttach", /* 0x0008 */
- "PageFlush", /* 0x0009 */
- "PageFree", /* 0x000A */
- "ContextSwitch", /* 0x000B */
- "HeapReAllocate", /* 0x000C */
- "PageModifyPermissions", /* 0x000D */
- "PageQuery", /* 0x000E */
- "GetCurrentContext", /* 0x000F */
- "HeapFree", /* 0x0010 */
- "RegOpenKey", /* 0x0011 */
- "RegCreateKey", /* 0x0012 */
- "RegCloseKey", /* 0x0013 */
- "RegDeleteKey", /* 0x0014 */
- "RegSetValue", /* 0x0015 */
- "RegDeleteValue", /* 0x0016 */
- "RegQueryValue", /* 0x0017 */
- "RegEnumKey", /* 0x0018 */
- "RegEnumValue", /* 0x0019 */
- "RegQueryValueEx", /* 0x001A */
- "RegSetValueEx", /* 0x001B */
- "RegFlushKey", /* 0x001C */
- "RegQueryInfoKey", /* 0x001D */
- "GetDemandPageInfo", /* 0x001E */
- "BlockOnID", /* 0x001F */
- "SignalID", /* 0x0020 */
- "RegLoadKey", /* 0x0021 */
- "RegUnLoadKey", /* 0x0022 */
- "RegSaveKey", /* 0x0023 */
- "RegRemapPreDefKey", /* 0x0024 */
- "PageChangePager", /* 0x0025 */
- "RegQueryMultipleValues", /* 0x0026 */
- "RegReplaceKey", /* 0x0027 */
- "<KERNEL32.101>" /* 0x0028 -- What does this do??? */
-};
-
-/* PageReserve arena values */
-#define PR_PRIVATE 0x80000400 /* anywhere in private arena */
-#define PR_SHARED 0x80060000 /* anywhere in shared arena */
-#define PR_SYSTEM 0x80080000 /* anywhere in system arena */
-
-/* PageReserve flags */
-#define PR_FIXED 0x00000008 /* don't move during PageReAllocate */
-#define PR_4MEG 0x00000001 /* allocate on 4mb boundary */
-#define PR_STATIC 0x00000010 /* see PageReserve documentation */
-
-/* PageCommit default pager handle values */
-#define PD_ZEROINIT 0x00000001 /* swappable zero-initialized pages */
-#define PD_NOINIT 0x00000002 /* swappable uninitialized pages */
-#define PD_FIXEDZERO 0x00000003 /* fixed zero-initialized pages */
-#define PD_FIXED 0x00000004 /* fixed uninitialized pages */
-
-/* PageCommit flags */
-#define PC_FIXED 0x00000008 /* pages are permanently locked */
-#define PC_LOCKED 0x00000080 /* pages are made present and locked */
-#define PC_LOCKEDIFDP 0x00000100 /* pages are locked if swap via DOS */
-#define PC_WRITEABLE 0x00020000 /* make the pages writeable */
-#define PC_USER 0x00040000 /* make the pages ring 3 accessible */
-#define PC_INCR 0x40000000 /* increment "pagerdata" each page */
-#define PC_PRESENT 0x80000000 /* make pages initially present */
-#define PC_STATIC 0x20000000 /* allow commit in PR_STATIC object */
-#define PC_DIRTY 0x08000000 /* make pages initially dirty */
-#define PC_CACHEDIS 0x00100000 /* Allocate uncached pages - new for WDM */
-#define PC_CACHEWT 0x00080000 /* Allocate write through cache pages - new for WDM */
-#define PC_PAGEFLUSH 0x00008000 /* Touch device mapped pages on alloc - new for WDM */
-
-/* PageCommitContig additional flags */
-#define PCC_ZEROINIT 0x00000001 /* zero-initialize new pages */
-#define PCC_NOLIN 0x10000000 /* don't map to any linear address */
-
-
-/* Pop a DWORD from the 32-bit stack */
-static inline DWORD stack32_pop( CONTEXT86 *context )
-{
- DWORD ret = *(DWORD *)context->Esp;
- context->Esp += sizeof(DWORD);
- return ret;
-}
-
-
-/******************************************************************************
- * The following is a massive duplication of the advapi32 code.
- * Unfortunately sharing the code is not possible since the native
- * Win95 advapi32 depends on it. Someday we should probably stop
- * supporting native Win95 advapi32 altogether...
- */
-
-
-#define HKEY_SPECIAL_ROOT_FIRST HKEY_CLASSES_ROOT
-#define HKEY_SPECIAL_ROOT_LAST HKEY_DYN_DATA
-#define NB_SPECIAL_ROOT_KEYS ((UINT)HKEY_SPECIAL_ROOT_LAST - (UINT)HKEY_SPECIAL_ROOT_FIRST + 1)
-
-static HKEY special_root_keys[NB_SPECIAL_ROOT_KEYS];
-
-static const WCHAR name_CLASSES_ROOT[] =
- {'M','a','c','h','i','n','e','\\',
- 'S','o','f','t','w','a','r','e','\\',
- 'C','l','a','s','s','e','s',0};
-static const WCHAR name_LOCAL_MACHINE[] =
- {'M','a','c','h','i','n','e',0};
-static const WCHAR name_USERS[] =
- {'U','s','e','r',0};
-static const WCHAR name_PERFORMANCE_DATA[] =
- {'P','e','r','f','D','a','t','a',0};
-static const WCHAR name_CURRENT_CONFIG[] =
- {'M','a','c','h','i','n','e','\\',
- 'S','y','s','t','e','m','\\',
- 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
- 'H','a','r','d','w','a','r','e','P','r','o','f','i','l','e','s','\\',
- 'C','u','r','r','e','n','t',0};
-static const WCHAR name_DYN_DATA[] =
- {'D','y','n','D','a','t','a',0};
-
-#define DECL_STR(key) { sizeof(name_##key)-sizeof(WCHAR), sizeof(name_##key), (LPWSTR)name_##key }
-static UNICODE_STRING root_key_names[NB_SPECIAL_ROOT_KEYS] =
-{
- DECL_STR(CLASSES_ROOT),
- { 0, 0, NULL }, /* HKEY_CURRENT_USER is determined dynamically */
- DECL_STR(LOCAL_MACHINE),
- DECL_STR(USERS),
- DECL_STR(PERFORMANCE_DATA),
- DECL_STR(CURRENT_CONFIG),
- DECL_STR(DYN_DATA)
-};
-#undef DECL_STR
-
-
-/* check if value type needs string conversion (Ansi<->Unicode) */
-inline static int is_string( DWORD type )
-{
- return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
-}
-
-/* create one of the HKEY_* special root keys */
-static HKEY create_special_root_hkey( HKEY hkey, DWORD access )
-{
- HKEY ret = 0;
- int idx = (UINT)hkey - (UINT)HKEY_SPECIAL_ROOT_FIRST;
-
- if (hkey == HKEY_CURRENT_USER)
- {
- if (RtlOpenCurrentUser( access, &hkey )) return 0;
- }
- else
- {
- OBJECT_ATTRIBUTES attr;
-
- attr.Length = sizeof(attr);
- attr.RootDirectory = 0;
- attr.ObjectName = &root_key_names[idx];
- attr.Attributes = 0;
- attr.SecurityDescriptor = NULL;
- attr.SecurityQualityOfService = NULL;
- if (NtCreateKey( &hkey, access, &attr, 0, NULL, 0, NULL )) return 0;
- }
-
- if (!(ret = InterlockedCompareExchangePointer( (PVOID) &special_root_keys[idx], hkey, 0 )))
- ret = hkey;
- else
- NtClose( hkey ); /* somebody beat us to it */
- return ret;
-}
-
-/* map the hkey from special root to normal key if necessary */
-inline static HKEY get_special_root_hkey( HKEY hkey )
-{
- HKEY ret = hkey;
-
- if ((hkey >= HKEY_SPECIAL_ROOT_FIRST) && (hkey <= HKEY_SPECIAL_ROOT_LAST))
- {
- if (!(ret = special_root_keys[(UINT)hkey - (UINT)HKEY_SPECIAL_ROOT_FIRST]))
- ret = create_special_root_hkey( hkey, KEY_ALL_ACCESS );
- }
- return ret;
-}
-
-
-/******************************************************************************
- * VMM_RegCreateKeyA
- */
-static DWORD VMM_RegCreateKeyA( HKEY hkey, LPCSTR name, PHKEY retkey )
-{
- OBJECT_ATTRIBUTES attr;
- UNICODE_STRING nameW;
- ANSI_STRING nameA;
- NTSTATUS status;
-
- if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
-
- attr.Length = sizeof(attr);
- attr.RootDirectory = hkey;
- attr.ObjectName = &nameW;
- attr.Attributes = 0;
- attr.SecurityDescriptor = NULL;
- attr.SecurityQualityOfService = NULL;
- RtlInitAnsiString( &nameA, name );
-
- if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
- {
- status = NtCreateKey( retkey, KEY_ALL_ACCESS, &attr, 0, NULL,
- REG_OPTION_NON_VOLATILE, NULL );
- RtlFreeUnicodeString( &nameW );
- }
- return RtlNtStatusToDosError( status );
-}
-
-
-/******************************************************************************
- * VMM_RegOpenKeyExA
- */
-DWORD WINAPI VMM_RegOpenKeyExA(HKEY hkey, LPCSTR name, DWORD reserved, REGSAM access, PHKEY retkey)
-{
- OBJECT_ATTRIBUTES attr;
- UNICODE_STRING nameW;
- STRING nameA;
- NTSTATUS status;
-
- if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
-
- attr.Length = sizeof(attr);
- attr.RootDirectory = hkey;
- attr.ObjectName = &nameW;
- attr.Attributes = 0;
- attr.SecurityDescriptor = NULL;
- attr.SecurityQualityOfService = NULL;
-
- RtlInitAnsiString( &nameA, name );
- if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
- {
- status = NtOpenKey( retkey, access, &attr );
- RtlFreeUnicodeString( &nameW );
- }
- return RtlNtStatusToDosError( status );
-}
-
-
-/******************************************************************************
- * VMM_RegCloseKey
- */
-static DWORD VMM_RegCloseKey( HKEY hkey )
-{
- if (!hkey || hkey >= (HKEY)0x80000000) return ERROR_SUCCESS;
- return RtlNtStatusToDosError( NtClose( hkey ) );
-}
-
-/******************************************************************************
- * VMM_RegFlushKey
- */
-static DWORD VMM_RegFlushKey( HKEY hkey )
-{
- return RtlNtStatusToDosError( NtFlushKey( hkey ) );
-}
-
-
-/******************************************************************************
- * VMM_RegDeleteKeyA
- */
-static DWORD VMM_RegDeleteKeyA( HKEY hkey, LPCSTR name )
-{
- DWORD ret;
- HKEY tmp;
-
- if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
-
- if (!name || !*name) return RtlNtStatusToDosError( NtDeleteKey( hkey ) );
- if (!(ret = VMM_RegOpenKeyExA( hkey, name, 0, 0, &tmp )))
- {
- ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
- NtClose( tmp );
- }
- return ret;
-}
-
-
-/******************************************************************************
- * VMM_RegSetValueExA
- */
-static DWORD VMM_RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
- CONST BYTE *data, DWORD count )
-{
- UNICODE_STRING nameW;
- ANSI_STRING nameA;
- WCHAR *dataW = NULL;
- NTSTATUS status;
-
- if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
-
- if (is_string(type))
- {
- DWORD lenW;
-
- if (count)
- {
- /* if user forgot to count terminating null, add it (yes NT does this) */
- if (data[count-1] && !data[count]) count++;
- }
- RtlMultiByteToUnicodeSize( &lenW, data, count );
- if (!(dataW = HeapAlloc( GetProcessHeap(), 0, lenW ))) return ERROR_OUTOFMEMORY;
- RtlMultiByteToUnicodeN( dataW, lenW, NULL, data, count );
- count = lenW;
- data = (BYTE *)dataW;
- }
-
- RtlInitAnsiString( &nameA, name );
- if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
- {
- status = NtSetValueKey( hkey, &nameW, 0, type, data, count );
- RtlFreeUnicodeString( &nameW );
- }
- if (dataW) HeapFree( GetProcessHeap(), 0, dataW );
- return RtlNtStatusToDosError( status );
-}
-
-
-/******************************************************************************
- * VMM_RegSetValueA
- */
-static DWORD VMM_RegSetValueA( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
-{
- HKEY subkey = hkey;
- DWORD ret;
-
- if (type != REG_SZ) return ERROR_INVALID_PARAMETER;
-
- if (name && name[0]) /* need to create the subkey */
- {
- if ((ret = VMM_RegCreateKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
- }
- ret = VMM_RegSetValueExA( subkey, NULL, 0, REG_SZ, (LPBYTE)data, strlen(data)+1 );
- if (subkey != hkey) NtClose( subkey );
- return ret;
-}
-
-
-/******************************************************************************
- * VMM_RegDeleteValueA
- */
-static DWORD VMM_RegDeleteValueA( HKEY hkey, LPCSTR name )
-{
- UNICODE_STRING nameW;
- STRING nameA;
- NTSTATUS status;
-
- if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
-
- RtlInitAnsiString( &nameA, name );
- if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
- {
- status = NtDeleteValueKey( hkey, &nameW );
- RtlFreeUnicodeString( &nameW );
- }
- return RtlNtStatusToDosError( status );
-}
-
-
-/******************************************************************************
- * VMM_RegQueryValueExA
- */
-static DWORD VMM_RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
- LPBYTE data, LPDWORD count )
-{
- NTSTATUS status;
- ANSI_STRING nameA;
- UNICODE_STRING nameW;
- DWORD total_size;
- char buffer[256], *buf_ptr = buffer;
- KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
- static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
-
- if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
- if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
-
- RtlInitAnsiString( &nameA, name );
- if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
- return RtlNtStatusToDosError(status);
-
- status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
- buffer, sizeof(buffer), &total_size );
- if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
-
- /* we need to fetch the contents for a string type even if not requested,
- * because we need to compute the length of the ASCII string. */
- if (data || is_string(info->Type))
- {
- /* retry with a dynamically allocated buffer */
- while (status == STATUS_BUFFER_OVERFLOW)
- {
- if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
- if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
- {
- status = STATUS_NO_MEMORY;
- goto done;
- }
- info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
- status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
- buf_ptr, total_size, &total_size );
- }
-
- if (!status)
- {
- if (is_string(info->Type))
- {
- DWORD len = WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info_size),
- (total_size - info_size) /sizeof(WCHAR),
- NULL, 0, NULL, NULL );
- if (data && len)
- {
- if (len > *count) status = STATUS_BUFFER_OVERFLOW;
- else
- {
- WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info_size),
- (total_size - info_size) /sizeof(WCHAR),
- data, len, NULL, NULL );
- /* if the type is REG_SZ and data is not 0-terminated
- * and there is enough space in the buffer NT appends a \0 */
- if (len < *count && data[len-1]) data[len] = 0;
- }
- }
- total_size = len + info_size;
- }
- else if (data)
- {
- if (total_size - info_size > *count) status = STATUS_BUFFER_OVERFLOW;
- else memcpy( data, buf_ptr + info_size, total_size - info_size );
- }
- }
- else if (status != STATUS_BUFFER_OVERFLOW) goto done;
- }
-
- if (type) *type = info->Type;
- if (count) *count = total_size - info_size;
-
- done:
- if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
- RtlFreeUnicodeString( &nameW );
- return RtlNtStatusToDosError(status);
-}
-
-
-/******************************************************************************
- * VMM_RegQueryValueA
- */
-static DWORD VMM_RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
-{
- DWORD ret;
- HKEY subkey = hkey;
-
- if (name && name[0])
- {
- if ((ret = VMM_RegOpenKeyExA( hkey, name, 0, KEY_ALL_ACCESS, &subkey )) != ERROR_SUCCESS)
- return ret;
- }
- ret = VMM_RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, count );
- if (subkey != hkey) NtClose( subkey );
- if (ret == ERROR_FILE_NOT_FOUND)
- {
- /* return empty string if default value not found */
- if (data) *data = 0;
- if (count) *count = 1;
- ret = ERROR_SUCCESS;
- }
- return ret;
-}
-
-
-/******************************************************************************
- * VMM_RegEnumValueA
- */
-static DWORD VMM_RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
- LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
-{
- NTSTATUS status;
- DWORD total_size;
- char buffer[256], *buf_ptr = buffer;
- KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
- static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
-
- TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
- hkey, index, value, val_count, reserved, type, data, count );
-
- /* NT only checks count, not val_count */
- if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
- if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
-
- total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
- if (data) total_size += *count;
- total_size = min( sizeof(buffer), total_size );
-
- status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
- buffer, total_size, &total_size );
- if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
-
- /* we need to fetch the contents for a string type even if not requested,
- * because we need to compute the length of the ASCII string. */
- if (value || data || is_string(info->Type))
- {
- /* retry with a dynamically allocated buffer */
- while (status == STATUS_BUFFER_OVERFLOW)
- {
- if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
- if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
- return ERROR_NOT_ENOUGH_MEMORY;
- info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
- status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
- buf_ptr, total_size, &total_size );
- }
-
- if (status) goto done;
-
- if (is_string(info->Type))
- {
- DWORD len;
- RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
- total_size - info->DataOffset );
- if (data && len)
- {
- if (len > *count) status = STATUS_BUFFER_OVERFLOW;
- else
- {
- RtlUnicodeToMultiByteN( data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
- total_size - info->DataOffset );
- /* if the type is REG_SZ and data is not 0-terminated
- * and there is enough space in the buffer NT appends a \0 */
- if (len < *count && data[len-1]) data[len] = 0;
- }
- }
- info->DataLength = len;
- }
- else if (data)
- {
- if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
- else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
- }
-
- if (value && !status)
- {
- DWORD len;
-
- RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
- if (len >= *val_count)
- {
- status = STATUS_BUFFER_OVERFLOW;
- if (*val_count)
- {
- len = *val_count - 1;
- RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
- value[len] = 0;
- }
- }
- else
- {
- RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
- value[len] = 0;
- *val_count = len;
- }
- }
- }
- else status = STATUS_SUCCESS;
-
- if (type) *type = info->Type;
- if (count) *count = info->DataLength;
-
- done:
- if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
- return RtlNtStatusToDosError(status);
-}
-
-
-/******************************************************************************
- * VMM_RegEnumKeyA
- */
-static DWORD VMM_RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
-{
- NTSTATUS status;
- char buffer[256], *buf_ptr = buffer;
- KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
- DWORD total_size;
-
- if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
-
- status = NtEnumerateKey( hkey, index, KeyNodeInformation,
- buffer, sizeof(buffer), &total_size );
-
- while (status == STATUS_BUFFER_OVERFLOW)
- {
- /* retry with a dynamically allocated buffer */
- if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
- if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
- return ERROR_NOT_ENOUGH_MEMORY;
- info = (KEY_NODE_INFORMATION *)buf_ptr;
- status = NtEnumerateKey( hkey, index, KeyNodeInformation,
- buf_ptr, total_size, &total_size );
- }
-
- if (!status)
- {
- DWORD len;
-
- RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
- if (len >= name_len) status = STATUS_BUFFER_OVERFLOW;
- else
- {
- RtlUnicodeToMultiByteN( name, len, NULL, info->Name, info->NameLength );
- name[len] = 0;
- }
- }
-
- if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
- return RtlNtStatusToDosError( status );
-}
-
-
-/******************************************************************************
- * VMM_RegQueryInfoKeyA
- *
- * NOTE: This VxDCall takes only a subset of the parameters that the
- * corresponding Win32 API call does. The implementation in Win95
- * ADVAPI32 sets all output parameters not mentioned here to zero.
- */
-static DWORD VMM_RegQueryInfoKeyA( HKEY hkey, LPDWORD subkeys, LPDWORD max_subkey,
- LPDWORD values, LPDWORD max_value, LPDWORD max_data )
-{
- NTSTATUS status;
- KEY_FULL_INFORMATION info;
- DWORD total_size;
-
- if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
-
- status = NtQueryKey( hkey, KeyFullInformation, &info, sizeof(info), &total_size );
- if (status && status != STATUS_BUFFER_OVERFLOW) return RtlNtStatusToDosError( status );
-
- if (subkeys) *subkeys = info.SubKeys;
- if (max_subkey) *max_subkey = info.MaxNameLen;
- if (values) *values = info.Values;
- if (max_value) *max_value = info.MaxValueNameLen;
- if (max_data) *max_data = info.MaxValueDataLen;
- return ERROR_SUCCESS;
-}
-
-
-/***********************************************************************
- * VxDCall_VMM
- */
-static DWORD VxDCall_VMM( DWORD service, CONTEXT86 *context )
-{
- switch ( LOWORD(service) )
- {
- case 0x0011: /* RegOpenKey */
- {
- HKEY hkey = (HKEY) stack32_pop( context );
- LPCSTR lpszSubKey = (LPCSTR)stack32_pop( context );
- PHKEY retkey = (PHKEY)stack32_pop( context );
- return VMM_RegOpenKeyExA( hkey, lpszSubKey, 0, KEY_ALL_ACCESS, retkey );
- }
-
- case 0x0012: /* RegCreateKey */
- {
- HKEY hkey = (HKEY) stack32_pop( context );
- LPCSTR lpszSubKey = (LPCSTR)stack32_pop( context );
- PHKEY retkey = (PHKEY)stack32_pop( context );
- return VMM_RegCreateKeyA( hkey, lpszSubKey, retkey );
- }
-
- case 0x0013: /* RegCloseKey */
- {
- HKEY hkey = (HKEY)stack32_pop( context );
- return VMM_RegCloseKey( hkey );
- }
-
- case 0x0014: /* RegDeleteKey */
- {
- HKEY hkey = (HKEY) stack32_pop( context );
- LPCSTR lpszSubKey = (LPCSTR)stack32_pop( context );
- return VMM_RegDeleteKeyA( hkey, lpszSubKey );
- }
-
- case 0x0015: /* RegSetValue */
- {
- HKEY hkey = (HKEY) stack32_pop( context );
- LPCSTR lpszSubKey = (LPCSTR)stack32_pop( context );
- DWORD dwType = (DWORD) stack32_pop( context );
- LPCSTR lpszData = (LPCSTR)stack32_pop( context );
- DWORD cbData = (DWORD) stack32_pop( context );
- return VMM_RegSetValueA( hkey, lpszSubKey, dwType, lpszData, cbData );
- }
-
- case 0x0016: /* RegDeleteValue */
- {
- HKEY hkey = (HKEY) stack32_pop( context );
- LPSTR lpszValue = (LPSTR)stack32_pop( context );
- return VMM_RegDeleteValueA( hkey, lpszValue );
- }
-
- case 0x0017: /* RegQueryValue */
- {
- HKEY hkey = (HKEY) stack32_pop( context );
- LPSTR lpszSubKey = (LPSTR) stack32_pop( context );
- LPSTR lpszData = (LPSTR) stack32_pop( context );
- LPDWORD lpcbData = (LPDWORD)stack32_pop( context );
- return VMM_RegQueryValueA( hkey, lpszSubKey, lpszData, lpcbData );
- }
-
- case 0x0018: /* RegEnumKey */
- {
- HKEY hkey = (HKEY) stack32_pop( context );
- DWORD iSubkey = (DWORD)stack32_pop( context );
- LPSTR lpszName = (LPSTR)stack32_pop( context );
- DWORD lpcchName = (DWORD)stack32_pop( context );
- return VMM_RegEnumKeyA( hkey, iSubkey, lpszName, lpcchName );
- }
-
- case 0x0019: /* RegEnumValue */
- {
- HKEY hkey = (HKEY) stack32_pop( context );
- DWORD iValue = (DWORD) stack32_pop( context );
- LPSTR lpszValue = (LPSTR) stack32_pop( context );
- LPDWORD lpcchValue = (LPDWORD)stack32_pop( context );
- LPDWORD lpReserved = (LPDWORD)stack32_pop( context );
- LPDWORD lpdwType = (LPDWORD)stack32_pop( context );
- LPBYTE lpbData = (LPBYTE) stack32_pop( context );
- LPDWORD lpcbData = (LPDWORD)stack32_pop( context );
- return VMM_RegEnumValueA( hkey, iValue, lpszValue, lpcchValue,
- lpReserved, lpdwType, lpbData, lpcbData );
- }
-
- case 0x001A: /* RegQueryValueEx */
- {
- HKEY hkey = (HKEY) stack32_pop( context );
- LPSTR lpszValue = (LPSTR) stack32_pop( context );
- LPDWORD lpReserved = (LPDWORD)stack32_pop( context );
- LPDWORD lpdwType = (LPDWORD)stack32_pop( context );
- LPBYTE lpbData = (LPBYTE) stack32_pop( context );
- LPDWORD lpcbData = (LPDWORD)stack32_pop( context );
- return VMM_RegQueryValueExA( hkey, lpszValue, lpReserved,
- lpdwType, lpbData, lpcbData );
- }
-
- case 0x001B: /* RegSetValueEx */
- {
- HKEY hkey = (HKEY) stack32_pop( context );
- LPSTR lpszValue = (LPSTR) stack32_pop( context );
- DWORD dwReserved = (DWORD) stack32_pop( context );
- DWORD dwType = (DWORD) stack32_pop( context );
- LPBYTE lpbData = (LPBYTE)stack32_pop( context );
- DWORD cbData = (DWORD) stack32_pop( context );
- return VMM_RegSetValueExA( hkey, lpszValue, dwReserved,
- dwType, lpbData, cbData );
- }
-
- case 0x001C: /* RegFlushKey */
- {
- HKEY hkey = (HKEY)stack32_pop( context );
- return VMM_RegFlushKey( hkey );
- }
-
- case 0x001D: /* RegQueryInfoKey */
- {
- /* NOTE: This VxDCall takes only a subset of the parameters that the
- corresponding Win32 API call does. The implementation in Win95
- ADVAPI32 sets all output parameters not mentioned here to zero. */
-
- HKEY hkey = (HKEY) stack32_pop( context );
- LPDWORD lpcSubKeys = (LPDWORD)stack32_pop( context );
- LPDWORD lpcchMaxSubKey = (LPDWORD)stack32_pop( context );
- LPDWORD lpcValues = (LPDWORD)stack32_pop( context );
- LPDWORD lpcchMaxValueName = (LPDWORD)stack32_pop( context );
- LPDWORD lpcchMaxValueData = (LPDWORD)stack32_pop( context );
- return VMM_RegQueryInfoKeyA( hkey, lpcSubKeys, lpcchMaxSubKey,
- lpcValues, lpcchMaxValueName, lpcchMaxValueData );
- }
-
- case 0x0021: /* RegLoadKey */
- {
- HKEY hkey = (HKEY) stack32_pop( context );
- LPCSTR lpszSubKey = (LPCSTR)stack32_pop( context );
- LPCSTR lpszFile = (LPCSTR)stack32_pop( context );
- FIXME("RegLoadKey(%p,%s,%s): stub\n",hkey, debugstr_a(lpszSubKey), debugstr_a(lpszFile));
- return ERROR_SUCCESS;
- }
-
- case 0x0022: /* RegUnLoadKey */
- {
- HKEY hkey = (HKEY) stack32_pop( context );
- LPCSTR lpszSubKey = (LPCSTR)stack32_pop( context );
- FIXME("RegUnLoadKey(%p,%s): stub\n",hkey, debugstr_a(lpszSubKey));
- return ERROR_SUCCESS;
- }
-
- case 0x0023: /* RegSaveKey */
- {
- HKEY hkey = (HKEY) stack32_pop( context );
- LPCSTR lpszFile = (LPCSTR)stack32_pop( context );
- LPSECURITY_ATTRIBUTES sa = (LPSECURITY_ATTRIBUTES)stack32_pop( context );
- FIXME("RegSaveKey(%p,%s,%p): stub\n",hkey, debugstr_a(lpszFile),sa);
- return ERROR_SUCCESS;
- }
-
-#if 0 /* Functions are not yet implemented in misc/registry.c */
- case 0x0024: /* RegRemapPreDefKey */
- case 0x0026: /* RegQueryMultipleValues */
-#endif
-
- case 0x0027: /* RegReplaceKey */
- {
- HKEY hkey = (HKEY) stack32_pop( context );
- LPCSTR lpszSubKey = (LPCSTR)stack32_pop( context );
- LPCSTR lpszNewFile= (LPCSTR)stack32_pop( context );
- LPCSTR lpszOldFile= (LPCSTR)stack32_pop( context );
- FIXME("RegReplaceKey(%p,%s,%s,%s): stub\n", hkey, debugstr_a(lpszSubKey),
- debugstr_a(lpszNewFile),debugstr_a(lpszOldFile));
- return ERROR_SUCCESS;
- }
-
- case 0x0000: /* PageReserve */
- {
- LPVOID address;
- LPVOID ret;
- DWORD psize = getpagesize();
- ULONG page = (ULONG) stack32_pop( context );
- ULONG npages = (ULONG) stack32_pop( context );
- ULONG flags = (ULONG) stack32_pop( context );
-
- TRACE("PageReserve: page: %08lx, npages: %08lx, flags: %08lx partial stub!\n",
- page, npages, flags );
-
- if ( page == PR_SYSTEM ) {
- ERR("Can't reserve ring 1 memory\n");
- return -1;
- }
- /* FIXME: This has to be handled separately for the separate
- address-spaces we now have */
- if ( page == PR_PRIVATE || page == PR_SHARED ) page = 0;
- /* FIXME: Handle flags in some way */
- address = (LPVOID )(page * psize);
- ret = VirtualAlloc ( address, ( npages * psize ), MEM_RESERVE, 0 );
- TRACE("PageReserve: returning: %08lx\n", (DWORD )ret );
- if ( ret == NULL )
- return -1;
- else
- return (DWORD )ret;
- }
-
- case 0x0001: /* PageCommit */
- {
- LPVOID address;
- LPVOID ret;
- DWORD virt_perm;
- DWORD psize = getpagesize();
- ULONG page = (ULONG) stack32_pop( context );
- ULONG npages = (ULONG) stack32_pop( context );
- ULONG hpd = (ULONG) stack32_pop( context );
- ULONG pagerdata = (ULONG) stack32_pop( context );
- ULONG flags = (ULONG) stack32_pop( context );
-
- TRACE("PageCommit: page: %08lx, npages: %08lx, hpd: %08lx pagerdata: "
- "%08lx, flags: %08lx partial stub\n",
- page, npages, hpd, pagerdata, flags );
-
- if ( flags & PC_USER )
- if ( flags & PC_WRITEABLE )
- virt_perm = PAGE_EXECUTE_READWRITE;
- else
- virt_perm = PAGE_EXECUTE_READ;
- else
- virt_perm = PAGE_NOACCESS;
-
- address = (LPVOID )(page * psize);
- ret = VirtualAlloc ( address, ( npages * psize ), MEM_COMMIT, virt_perm );
- TRACE("PageCommit: Returning: %08lx\n", (DWORD )ret );
- return (DWORD )ret;
-
- }
- case 0x0002: /* PageDecommit */
- {
- LPVOID address;
- BOOL ret;
- DWORD psize = getpagesize();
- ULONG page = (ULONG) stack32_pop( context );
- ULONG npages = (ULONG) stack32_pop( context );
- ULONG flags = (ULONG) stack32_pop( context );
-
- TRACE("PageDecommit: page: %08lx, npages: %08lx, flags: %08lx partial stub\n",
- page, npages, flags );
- address = (LPVOID )( page * psize );
- ret = VirtualFree ( address, ( npages * psize ), MEM_DECOMMIT );
- TRACE("PageDecommit: Returning: %s\n", ret ? "TRUE" : "FALSE" );
- return ret;
- }
- case 0x000d: /* PageModifyPermissions */
- {
- DWORD pg_old_perm;
- DWORD pg_new_perm;
- DWORD virt_old_perm;
- DWORD virt_new_perm;
- MEMORY_BASIC_INFORMATION mbi;
- LPVOID address;
- DWORD psize = getpagesize();
- ULONG page = stack32_pop ( context );
- ULONG npages = stack32_pop ( context );
- ULONG permand = stack32_pop ( context );
- ULONG permor = stack32_pop ( context );
-
- TRACE("PageModifyPermissions %08lx %08lx %08lx %08lx partial stub\n",
- page, npages, permand, permor );
- address = (LPVOID )( page * psize );
-
- VirtualQuery ( address, &mbi, sizeof ( MEMORY_BASIC_INFORMATION ));
- virt_old_perm = mbi.Protect;
-
- switch ( virt_old_perm & mbi.Protect ) {
- case PAGE_READONLY:
- case PAGE_EXECUTE:
- case PAGE_EXECUTE_READ:
- pg_old_perm = PC_USER;
- break;
- case PAGE_READWRITE:
- case PAGE_WRITECOPY:
- case PAGE_EXECUTE_READWRITE:
- case PAGE_EXECUTE_WRITECOPY:
- pg_old_perm = PC_USER | PC_WRITEABLE;
- break;
- case PAGE_NOACCESS:
- default:
- pg_old_perm = 0;
- break;
- }
- pg_new_perm = pg_old_perm;
- pg_new_perm &= permand & ~PC_STATIC;
- pg_new_perm |= permor & ~PC_STATIC;
-
- virt_new_perm = ( virt_old_perm ) & ~0xff;
- if ( pg_new_perm & PC_USER )
- {
- if ( pg_new_perm & PC_WRITEABLE )
- virt_new_perm |= PAGE_EXECUTE_READWRITE;
- else
- virt_new_perm |= PAGE_EXECUTE_READ;
- }
-
- if ( ! VirtualProtect ( address, ( npages * psize ), virt_new_perm, &virt_old_perm ) ) {
- ERR("Can't change page permissions for %08lx\n", (DWORD )address );
- return 0xffffffff;
- }
- TRACE("Returning: %08lx\n", pg_old_perm );
- return pg_old_perm;
- }
- case 0x000a: /* PageFree */
- {
- BOOL ret;
- LPVOID hmem = (LPVOID) stack32_pop( context );
- DWORD flags = (DWORD ) stack32_pop( context );
-
- TRACE("PageFree: hmem: %08lx, flags: %08lx partial stub\n",
- (DWORD )hmem, flags );
-
- ret = VirtualFree ( hmem, 0, MEM_RELEASE );
- context->Eax = ret;
- TRACE("Returning: %d\n", ret );
-
- return 0;
- }
- case 0x001e: /* GetDemandPageInfo */
- {
- DWORD dinfo = (DWORD)stack32_pop( context );
- DWORD flags = (DWORD)stack32_pop( context );
-
- /* GetDemandPageInfo is supposed to fill out the struct at
- * "dinfo" with various low-level memory management information.
- * Apps are certainly not supposed to call this, although it's
- * demoed and documented by Pietrek on pages 441-443 of "Windows
- * 95 System Programming Secrets" if any program needs a real
- * implementation of this.
- */
-
- FIXME("GetDemandPageInfo(%08lx %08lx): stub!\n", dinfo, flags);
-
- return 0;
- }
- default:
- if (LOWORD(service) < N_VMM_SERVICE)
- FIXME( "Unimplemented service %s (%08lx)\n",
- VMM_Service_Name[LOWORD(service)], service);
- else
- FIXME( "Unknown service %08lx\n", service);
- break;
- }
-
- return 0xffffffff; /* FIXME */
-}
-
-
-/********************************************************************************
- * VxDCall_VWin32
- *
- * Service numbers taken from page 448 of Pietrek's "Windows 95 System
- * Programming Secrets". Parameters from experimentation on real Win98.
- *
- */
-
-static DWORD VxDCall_VWin32( DWORD service, CONTEXT86 *context )
-{
- switch ( LOWORD(service) )
- {
- case 0x0000: /* GetVersion */
- {
- DWORD vers = GetVersion();
- return (LOBYTE(vers) << 8) | HIBYTE(vers);
- }
- break;
-
- case 0x0020: /* Get VMCPD Version */
- {
- DWORD parm = (DWORD) stack32_pop(context);
-
- FIXME("Get VMCPD Version(%08lx): partial stub!\n", parm);
-
- /* FIXME: This is what Win98 returns, it may
- * not be correct in all situations.
- * It makes Bleem! happy though.
- */
-
- return 0x0405;
- }
-
- case 0x0029: /* Int31/DPMI dispatch */
- {
- DWORD callnum = (DWORD) stack32_pop(context);
- DWORD parm = (DWORD) stack32_pop(context);
-
- TRACE("Int31/DPMI dispatch(%08lx)\n", callnum);
-
- context->Eax = callnum;
- context->Ecx = parm;
- INSTR_CallBuiltinHandler( context, 0x31 );
-
- return LOWORD(context->Eax);
- }
- break;
-
- case 0x002a: /* Int41 dispatch - parm = int41 service number */
- {
- DWORD callnum = (DWORD) stack32_pop(context);
-
- return callnum; /* FIXME: should really call INT_Int41Handler() */
- }
- break;
-
- default:
- FIXME("Unknown VWin32 service %08lx\n", service);
- break;
- }
-
- return 0xffffffff;
-}
-
-
/***********************************************************************
* VxDCall0 (KERNEL32.1)
* VxDCall1 (KERNEL32.2)
@@ -1318,24 +260,29 @@
*/
void VxDCall( DWORD service, CONTEXT86 *context )
{
- DWORD ret;
+ int i;
+ VxDCallProc proc = NULL;
- TRACE( "(%08lx, ...)\n", service);
-
- switch(HIWORD(service))
+ RtlEnterCriticalSection( &vxd_section );
+ for (i = 0; i < NB_VXD_SERVICES; i++)
{
- case 0x0001: /* VMM */
- ret = VxDCall_VMM( service, context );
- break;
- case 0x002a: /* VWIN32 */
- ret = VxDCall_VWin32( service, context );
- break;
- default:
- FIXME( "Unknown/unimplemented VxD (%08lx)\n", service);
- ret = 0xffffffff; /* FIXME */
+ if (HIWORD(service) != vxd_services[i].service) continue;
+ if (!vxd_services[i].module) /* need to load it */
+ {
+ if ((vxd_services[i].module = LoadLibraryW( vxd_services[i].name )))
+ vxd_services[i].proc = (VxDCallProc)GetProcAddress( vxd_services[i].module, "VxDCall" );
+ }
+ proc = vxd_services[i].proc;
break;
}
- context->Eax = ret;
+ RtlLeaveCriticalSection( &vxd_section );
+
+ if (proc) context->Eax = proc( service, context );
+ else
+ {
+ FIXME( "Unknown/unimplemented VxD (%08lx)\n", service);
+ context->Eax = 0xffffffff; /* FIXME */
+ }
}
diff --git a/dlls/vmm.vxd/.cvsignore b/dlls/vmm.vxd/.cvsignore
new file mode 100644
index 0000000..37818fe
--- /dev/null
+++ b/dlls/vmm.vxd/.cvsignore
@@ -0,0 +1,3 @@
+Makefile
+vmm.vxd.dbg.c
+vmm.vxd.spec.c
diff --git a/dlls/vmm.vxd/Makefile.in b/dlls/vmm.vxd/Makefile.in
new file mode 100644
index 0000000..7378531
--- /dev/null
+++ b/dlls/vmm.vxd/Makefile.in
@@ -0,0 +1,13 @@
+TOPSRCDIR = @top_srcdir@
+TOPOBJDIR = ../..
+SRCDIR = @srcdir@
+VPATH = @srcdir@
+MODULE = vmm.vxd
+IMPORTS = kernel32 ntdll
+
+C_SRCS = \
+ vmm.c
+
+@MAKE_DLL_RULES@
+
+### Dependencies:
diff --git a/dlls/vmm.vxd/vmm.c b/dlls/vmm.vxd/vmm.c
new file mode 100644
index 0000000..1a5e195
--- /dev/null
+++ b/dlls/vmm.vxd/vmm.c
@@ -0,0 +1,479 @@
+/*
+ * VMM VxD implementation
+ *
+ * Copyright 1998 Marcus Meissner
+ * Copyright 1998 Ulrich Weigand
+ * Copyright 1998 Patrik Stridvall
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "config.h"
+#include "wine/port.h"
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winreg.h"
+#include "winnls.h"
+#include "ntstatus.h"
+#include "winternl.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(vxd);
+
+/*
+ * VMM VxDCall service names are (mostly) taken from Stan Mitchell's
+ * "Inside the Windows 95 File System"
+ */
+
+#define N_VMM_SERVICE 41
+
+static const char * const VMM_Service_Name[N_VMM_SERVICE] =
+{
+ "PageReserve", /* 0x0000 */
+ "PageCommit", /* 0x0001 */
+ "PageDecommit", /* 0x0002 */
+ "PagerRegister", /* 0x0003 */
+ "PagerQuery", /* 0x0004 */
+ "HeapAllocate", /* 0x0005 */
+ "ContextCreate", /* 0x0006 */
+ "ContextDestroy", /* 0x0007 */
+ "PageAttach", /* 0x0008 */
+ "PageFlush", /* 0x0009 */
+ "PageFree", /* 0x000A */
+ "ContextSwitch", /* 0x000B */
+ "HeapReAllocate", /* 0x000C */
+ "PageModifyPermissions", /* 0x000D */
+ "PageQuery", /* 0x000E */
+ "GetCurrentContext", /* 0x000F */
+ "HeapFree", /* 0x0010 */
+ "RegOpenKey", /* 0x0011 */
+ "RegCreateKey", /* 0x0012 */
+ "RegCloseKey", /* 0x0013 */
+ "RegDeleteKey", /* 0x0014 */
+ "RegSetValue", /* 0x0015 */
+ "RegDeleteValue", /* 0x0016 */
+ "RegQueryValue", /* 0x0017 */
+ "RegEnumKey", /* 0x0018 */
+ "RegEnumValue", /* 0x0019 */
+ "RegQueryValueEx", /* 0x001A */
+ "RegSetValueEx", /* 0x001B */
+ "RegFlushKey", /* 0x001C */
+ "RegQueryInfoKey", /* 0x001D */
+ "GetDemandPageInfo", /* 0x001E */
+ "BlockOnID", /* 0x001F */
+ "SignalID", /* 0x0020 */
+ "RegLoadKey", /* 0x0021 */
+ "RegUnLoadKey", /* 0x0022 */
+ "RegSaveKey", /* 0x0023 */
+ "RegRemapPreDefKey", /* 0x0024 */
+ "PageChangePager", /* 0x0025 */
+ "RegQueryMultipleValues", /* 0x0026 */
+ "RegReplaceKey", /* 0x0027 */
+ "<KERNEL32.101>" /* 0x0028 -- What does this do??? */
+};
+
+/* PageReserve arena values */
+#define PR_PRIVATE 0x80000400 /* anywhere in private arena */
+#define PR_SHARED 0x80060000 /* anywhere in shared arena */
+#define PR_SYSTEM 0x80080000 /* anywhere in system arena */
+
+/* PageReserve flags */
+#define PR_FIXED 0x00000008 /* don't move during PageReAllocate */
+#define PR_4MEG 0x00000001 /* allocate on 4mb boundary */
+#define PR_STATIC 0x00000010 /* see PageReserve documentation */
+
+/* PageCommit default pager handle values */
+#define PD_ZEROINIT 0x00000001 /* swappable zero-initialized pages */
+#define PD_NOINIT 0x00000002 /* swappable uninitialized pages */
+#define PD_FIXEDZERO 0x00000003 /* fixed zero-initialized pages */
+#define PD_FIXED 0x00000004 /* fixed uninitialized pages */
+
+/* PageCommit flags */
+#define PC_FIXED 0x00000008 /* pages are permanently locked */
+#define PC_LOCKED 0x00000080 /* pages are made present and locked */
+#define PC_LOCKEDIFDP 0x00000100 /* pages are locked if swap via DOS */
+#define PC_WRITEABLE 0x00020000 /* make the pages writeable */
+#define PC_USER 0x00040000 /* make the pages ring 3 accessible */
+#define PC_INCR 0x40000000 /* increment "pagerdata" each page */
+#define PC_PRESENT 0x80000000 /* make pages initially present */
+#define PC_STATIC 0x20000000 /* allow commit in PR_STATIC object */
+#define PC_DIRTY 0x08000000 /* make pages initially dirty */
+#define PC_CACHEDIS 0x00100000 /* Allocate uncached pages - new for WDM */
+#define PC_CACHEWT 0x00080000 /* Allocate write through cache pages - new for WDM */
+#define PC_PAGEFLUSH 0x00008000 /* Touch device mapped pages on alloc - new for WDM */
+
+/* PageCommitContig additional flags */
+#define PCC_ZEROINIT 0x00000001 /* zero-initialize new pages */
+#define PCC_NOLIN 0x10000000 /* don't map to any linear address */
+
+
+/* Pop a DWORD from the 32-bit stack */
+static inline DWORD stack32_pop( CONTEXT86 *context )
+{
+ DWORD ret = *(DWORD *)context->Esp;
+ context->Esp += sizeof(DWORD);
+ return ret;
+}
+
+
+/***********************************************************************
+ * VxDCall (VMM.VXD.@)
+ */
+DWORD WINAPI VMM_VxDCall( DWORD service, CONTEXT86 *context )
+{
+ static int warned;
+
+ switch ( LOWORD(service) )
+ {
+ case 0x0000: /* PageReserve */
+ {
+ LPVOID address;
+ LPVOID ret;
+ DWORD psize = getpagesize();
+ ULONG page = (ULONG) stack32_pop( context );
+ ULONG npages = (ULONG) stack32_pop( context );
+ ULONG flags = (ULONG) stack32_pop( context );
+
+ TRACE("PageReserve: page: %08lx, npages: %08lx, flags: %08lx partial stub!\n",
+ page, npages, flags );
+
+ if ( page == PR_SYSTEM ) {
+ ERR("Can't reserve ring 1 memory\n");
+ return -1;
+ }
+ /* FIXME: This has to be handled separately for the separate
+ address-spaces we now have */
+ if ( page == PR_PRIVATE || page == PR_SHARED ) page = 0;
+ /* FIXME: Handle flags in some way */
+ address = (LPVOID )(page * psize);
+ ret = VirtualAlloc ( address, ( npages * psize ), MEM_RESERVE, 0 );
+ TRACE("PageReserve: returning: %08lx\n", (DWORD )ret );
+ if ( ret == NULL )
+ return -1;
+ else
+ return (DWORD )ret;
+ }
+
+ case 0x0001: /* PageCommit */
+ {
+ LPVOID address;
+ LPVOID ret;
+ DWORD virt_perm;
+ DWORD psize = getpagesize();
+ ULONG page = (ULONG) stack32_pop( context );
+ ULONG npages = (ULONG) stack32_pop( context );
+ ULONG hpd = (ULONG) stack32_pop( context );
+ ULONG pagerdata = (ULONG) stack32_pop( context );
+ ULONG flags = (ULONG) stack32_pop( context );
+
+ TRACE("PageCommit: page: %08lx, npages: %08lx, hpd: %08lx pagerdata: "
+ "%08lx, flags: %08lx partial stub\n",
+ page, npages, hpd, pagerdata, flags );
+
+ if ( flags & PC_USER )
+ if ( flags & PC_WRITEABLE )
+ virt_perm = PAGE_EXECUTE_READWRITE;
+ else
+ virt_perm = PAGE_EXECUTE_READ;
+ else
+ virt_perm = PAGE_NOACCESS;
+
+ address = (LPVOID )(page * psize);
+ ret = VirtualAlloc ( address, ( npages * psize ), MEM_COMMIT, virt_perm );
+ TRACE("PageCommit: Returning: %08lx\n", (DWORD )ret );
+ return (DWORD )ret;
+
+ }
+
+ case 0x0002: /* PageDecommit */
+ {
+ LPVOID address;
+ BOOL ret;
+ DWORD psize = getpagesize();
+ ULONG page = (ULONG) stack32_pop( context );
+ ULONG npages = (ULONG) stack32_pop( context );
+ ULONG flags = (ULONG) stack32_pop( context );
+
+ TRACE("PageDecommit: page: %08lx, npages: %08lx, flags: %08lx partial stub\n",
+ page, npages, flags );
+ address = (LPVOID )( page * psize );
+ ret = VirtualFree ( address, ( npages * psize ), MEM_DECOMMIT );
+ TRACE("PageDecommit: Returning: %s\n", ret ? "TRUE" : "FALSE" );
+ return ret;
+ }
+
+ case 0x000d: /* PageModifyPermissions */
+ {
+ DWORD pg_old_perm;
+ DWORD pg_new_perm;
+ DWORD virt_old_perm;
+ DWORD virt_new_perm;
+ MEMORY_BASIC_INFORMATION mbi;
+ LPVOID address;
+ DWORD psize = getpagesize();
+ ULONG page = stack32_pop ( context );
+ ULONG npages = stack32_pop ( context );
+ ULONG permand = stack32_pop ( context );
+ ULONG permor = stack32_pop ( context );
+
+ TRACE("PageModifyPermissions %08lx %08lx %08lx %08lx partial stub\n",
+ page, npages, permand, permor );
+ address = (LPVOID )( page * psize );
+
+ VirtualQuery ( address, &mbi, sizeof ( MEMORY_BASIC_INFORMATION ));
+ virt_old_perm = mbi.Protect;
+
+ switch ( virt_old_perm & mbi.Protect ) {
+ case PAGE_READONLY:
+ case PAGE_EXECUTE:
+ case PAGE_EXECUTE_READ:
+ pg_old_perm = PC_USER;
+ break;
+ case PAGE_READWRITE:
+ case PAGE_WRITECOPY:
+ case PAGE_EXECUTE_READWRITE:
+ case PAGE_EXECUTE_WRITECOPY:
+ pg_old_perm = PC_USER | PC_WRITEABLE;
+ break;
+ case PAGE_NOACCESS:
+ default:
+ pg_old_perm = 0;
+ break;
+ }
+ pg_new_perm = pg_old_perm;
+ pg_new_perm &= permand & ~PC_STATIC;
+ pg_new_perm |= permor & ~PC_STATIC;
+
+ virt_new_perm = ( virt_old_perm ) & ~0xff;
+ if ( pg_new_perm & PC_USER )
+ {
+ if ( pg_new_perm & PC_WRITEABLE )
+ virt_new_perm |= PAGE_EXECUTE_READWRITE;
+ else
+ virt_new_perm |= PAGE_EXECUTE_READ;
+ }
+
+ if ( ! VirtualProtect ( address, ( npages * psize ), virt_new_perm, &virt_old_perm ) ) {
+ ERR("Can't change page permissions for %08lx\n", (DWORD )address );
+ return 0xffffffff;
+ }
+ TRACE("Returning: %08lx\n", pg_old_perm );
+ return pg_old_perm;
+ }
+
+ case 0x000a: /* PageFree */
+ {
+ BOOL ret;
+ LPVOID hmem = (LPVOID) stack32_pop( context );
+ DWORD flags = (DWORD ) stack32_pop( context );
+
+ TRACE("PageFree: hmem: %08lx, flags: %08lx partial stub\n",
+ (DWORD )hmem, flags );
+
+ ret = VirtualFree ( hmem, 0, MEM_RELEASE );
+ TRACE("Returning: %d\n", ret );
+ return ret;
+ }
+
+ case 0x0011: /* RegOpenKey */
+ stack32_pop( context ); /* kkey */
+ stack32_pop( context ); /* lpszSubKey */
+ stack32_pop( context ); /* retkey */
+ /* return RegOpenKeyExA( hkey, lpszSubKey, 0, KEY_ALL_ACCESS, retkey ); */
+ if (!warned)
+ {
+ ERR( "Using the native Win95 advapi32.dll is no longer supported.\n" );
+ ERR( "Please configure advapi32 to builtin.\n" );
+ warned++;
+ }
+ return ERROR_CALL_NOT_IMPLEMENTED;
+
+ case 0x0012: /* RegCreateKey */
+ stack32_pop( context ); /* hkey */
+ stack32_pop( context ); /* lpszSubKey */
+ stack32_pop( context ); /* retkey */
+ /* return RegCreateKeyA( hkey, lpszSubKey, retkey ); */
+ if (!warned)
+ {
+ ERR( "Using the native Win95 advapi32.dll is no longer supported.\n" );
+ ERR( "Please configure advapi32 to builtin.\n" );
+ warned++;
+ }
+ return ERROR_CALL_NOT_IMPLEMENTED;
+
+ case 0x0013: /* RegCloseKey */
+ stack32_pop( context ); /* hkey */
+ /* return RegCloseKey( hkey ); */
+ return ERROR_CALL_NOT_IMPLEMENTED;
+
+ case 0x0014: /* RegDeleteKey */
+ stack32_pop( context ); /* hkey */
+ stack32_pop( context ); /* lpszSubKey */
+ /* return RegDeleteKeyA( hkey, lpszSubKey ); */
+ return ERROR_CALL_NOT_IMPLEMENTED;
+
+ case 0x0015: /* RegSetValue */
+ stack32_pop( context ); /* hkey */
+ stack32_pop( context ); /* lpszSubKey */
+ stack32_pop( context ); /* dwType */
+ stack32_pop( context ); /* lpszData */
+ stack32_pop( context ); /* cbData */
+ /* return RegSetValueA( hkey, lpszSubKey, dwType, lpszData, cbData ); */
+ return ERROR_CALL_NOT_IMPLEMENTED;
+
+ case 0x0016: /* RegDeleteValue */
+ stack32_pop( context ); /* hkey */
+ stack32_pop( context ); /* lpszValue */
+ /* return RegDeleteValueA( hkey, lpszValue ); */
+ return ERROR_CALL_NOT_IMPLEMENTED;
+
+ case 0x0017: /* RegQueryValue */
+ stack32_pop( context ); /* hkey */
+ stack32_pop( context ); /* lpszSubKey */
+ stack32_pop( context ); /* lpszData */
+ stack32_pop( context ); /* lpcbData */
+ /* return RegQueryValueA( hkey, lpszSubKey, lpszData, lpcbData ); */
+ return ERROR_CALL_NOT_IMPLEMENTED;
+
+ case 0x0018: /* RegEnumKey */
+ stack32_pop( context ); /* hkey */
+ stack32_pop( context ); /* iSubkey */
+ stack32_pop( context ); /* lpszName */
+ stack32_pop( context ); /* lpcchName */
+ /* return RegEnumKeyA( hkey, iSubkey, lpszName, lpcchName ); */
+ return ERROR_CALL_NOT_IMPLEMENTED;
+
+ case 0x0019: /* RegEnumValue */
+ stack32_pop( context ); /* hkey */
+ stack32_pop( context ); /* iValue */
+ stack32_pop( context ); /* lpszValue */
+ stack32_pop( context ); /* lpcchValue */
+ stack32_pop( context ); /* lpReserved */
+ stack32_pop( context ); /* lpdwType */
+ stack32_pop( context ); /* lpbData */
+ stack32_pop( context ); /* lpcbData */
+ /* return RegEnumValueA( hkey, iValue, lpszValue, lpcchValue, lpReserved, lpdwType, lpbData, lpcbData ); */
+ return ERROR_CALL_NOT_IMPLEMENTED;
+
+ case 0x001A: /* RegQueryValueEx */
+ stack32_pop( context ); /* hkey */
+ stack32_pop( context ); /* lpszValue */
+ stack32_pop( context ); /* lpReserved */
+ stack32_pop( context ); /* lpdwType */
+ stack32_pop( context ); /* lpbData */
+ stack32_pop( context ); /* lpcbData */
+ /* return RegQueryValueExA( hkey, lpszValue, lpReserved, lpdwType, lpbData, lpcbData ); */
+ return ERROR_CALL_NOT_IMPLEMENTED;
+
+ case 0x001B: /* RegSetValueEx */
+ stack32_pop( context ); /* hkey */
+ stack32_pop( context ); /* lpszValue */
+ stack32_pop( context ); /* dwReserved */
+ stack32_pop( context ); /* dwType */
+ stack32_pop( context ); /* lpbData */
+ stack32_pop( context ); /* cbData */
+ /* return RegSetValueExA( hkey, lpszValue, dwReserved, dwType, lpbData, cbData ); */
+ return ERROR_CALL_NOT_IMPLEMENTED;
+
+ case 0x001C: /* RegFlushKey */
+ stack32_pop( context ); /* hkey */
+ /* return RegFlushKey( hkey ); */
+ return ERROR_CALL_NOT_IMPLEMENTED;
+
+ case 0x001D: /* RegQueryInfoKey */
+ /* NOTE: This VxDCall takes only a subset of the parameters that the
+ corresponding Win32 API call does. The implementation in Win95
+ ADVAPI32 sets all output parameters not mentioned here to zero. */
+ stack32_pop( context ); /* hkey */
+ stack32_pop( context ); /* lpcSubKeys */
+ stack32_pop( context ); /* lpcchMaxSubKey */
+ stack32_pop( context ); /* lpcValues */
+ stack32_pop( context ); /* lpcchMaxValueName */
+ stack32_pop( context ); /* lpcchMaxValueData */
+ /* return RegQueryInfoKeyA( hkey, lpcSubKeys, lpcchMaxSubKey, lpcValues, lpcchMaxValueName, lpcchMaxValueData ); */
+ return ERROR_CALL_NOT_IMPLEMENTED;
+
+ case 0x001e: /* GetDemandPageInfo */
+ {
+ DWORD dinfo = (DWORD)stack32_pop( context );
+ DWORD flags = (DWORD)stack32_pop( context );
+
+ /* GetDemandPageInfo is supposed to fill out the struct at
+ * "dinfo" with various low-level memory management information.
+ * Apps are certainly not supposed to call this, although it's
+ * demoed and documented by Pietrek on pages 441-443 of "Windows
+ * 95 System Programming Secrets" if any program needs a real
+ * implementation of this.
+ */
+
+ FIXME("GetDemandPageInfo(%08lx %08lx): stub!\n", dinfo, flags);
+
+ return 0;
+ }
+
+ case 0x0021: /* RegLoadKey */
+ {
+ HKEY hkey = (HKEY) stack32_pop( context );
+ LPCSTR lpszSubKey = (LPCSTR)stack32_pop( context );
+ LPCSTR lpszFile = (LPCSTR)stack32_pop( context );
+ FIXME("RegLoadKey(%p,%s,%s): stub\n",hkey, debugstr_a(lpszSubKey), debugstr_a(lpszFile));
+ return ERROR_CALL_NOT_IMPLEMENTED;
+ }
+
+ case 0x0022: /* RegUnLoadKey */
+ {
+ HKEY hkey = (HKEY) stack32_pop( context );
+ LPCSTR lpszSubKey = (LPCSTR)stack32_pop( context );
+ FIXME("RegUnLoadKey(%p,%s): stub\n",hkey, debugstr_a(lpszSubKey));
+ return ERROR_CALL_NOT_IMPLEMENTED;
+ }
+
+ case 0x0023: /* RegSaveKey */
+ {
+ HKEY hkey = (HKEY) stack32_pop( context );
+ LPCSTR lpszFile = (LPCSTR)stack32_pop( context );
+ LPSECURITY_ATTRIBUTES sa = (LPSECURITY_ATTRIBUTES)stack32_pop( context );
+ FIXME("RegSaveKey(%p,%s,%p): stub\n",hkey, debugstr_a(lpszFile),sa);
+ return ERROR_CALL_NOT_IMPLEMENTED;
+ }
+
+#if 0 /* Functions are not yet implemented in misc/registry.c */
+ case 0x0024: /* RegRemapPreDefKey */
+ case 0x0026: /* RegQueryMultipleValues */
+#endif
+
+ case 0x0027: /* RegReplaceKey */
+ {
+ HKEY hkey = (HKEY) stack32_pop( context );
+ LPCSTR lpszSubKey = (LPCSTR)stack32_pop( context );
+ LPCSTR lpszNewFile= (LPCSTR)stack32_pop( context );
+ LPCSTR lpszOldFile= (LPCSTR)stack32_pop( context );
+ FIXME("RegReplaceKey(%p,%s,%s,%s): stub\n", hkey, debugstr_a(lpszSubKey),
+ debugstr_a(lpszNewFile),debugstr_a(lpszOldFile));
+ return ERROR_CALL_NOT_IMPLEMENTED;
+ }
+
+ default:
+ if (LOWORD(service) < N_VMM_SERVICE)
+ FIXME( "Unimplemented service %s (%08lx)\n",
+ VMM_Service_Name[LOWORD(service)], service);
+ else
+ FIXME( "Unknown service %08lx\n", service);
+ return 0xffffffff; /* FIXME */
+ }
+}
diff --git a/dlls/vmm.vxd/vmm.vxd.spec b/dlls/vmm.vxd/vmm.vxd.spec
new file mode 100644
index 0000000..1bf324b
--- /dev/null
+++ b/dlls/vmm.vxd/vmm.vxd.spec
@@ -0,0 +1 @@
+@ stdcall VxDCall(long ptr) VMM_VxDCall
diff --git a/dlls/vwin32.vxd/vwin32.c b/dlls/vwin32.vxd/vwin32.c
index adeccf9..ee192ae 100644
--- a/dlls/vwin32.vxd/vwin32.c
+++ b/dlls/vwin32.vxd/vwin32.c
@@ -31,6 +31,13 @@
extern void WINAPI CallBuiltinHandler( CONTEXT86 *context, BYTE intnum ); /* from winedos */
+/* Pop a DWORD from the 32-bit stack */
+static inline DWORD stack32_pop( CONTEXT86 *context )
+{
+ DWORD ret = *(DWORD *)context->Esp;
+ context->Esp += sizeof(DWORD);
+ return ret;
+}
static void DIOCRegs_2_CONTEXT( DIOC_REGISTERS *pIn, CONTEXT86 *pCxt )
{
@@ -150,3 +157,55 @@
return FALSE;
}
}
+
+
+/***********************************************************************
+ * VxDCall (VWIN32.VXD.@)
+ *
+ * Service numbers taken from page 448 of Pietrek's "Windows 95 System
+ * Programming Secrets". Parameters from experimentation on real Win98.
+ *
+ */
+DWORD WINAPI VWIN32_VxDCall( DWORD service, CONTEXT86 *context )
+{
+ switch ( LOWORD(service) )
+ {
+ case 0x0000: /* GetVersion */
+ {
+ DWORD vers = GetVersion();
+ return (LOBYTE(vers) << 8) | HIBYTE(vers);
+ }
+ case 0x0020: /* Get VMCPD Version */
+ {
+ DWORD parm = stack32_pop(context);
+
+ FIXME("Get VMCPD Version(%08lx): partial stub!\n", parm);
+
+ /* FIXME: This is what Win98 returns, it may
+ * not be correct in all situations.
+ * It makes Bleem! happy though.
+ */
+ return 0x0405;
+ }
+ case 0x0029: /* Int31/DPMI dispatch */
+ {
+ DWORD callnum = stack32_pop(context);
+ DWORD parm = stack32_pop(context);
+
+ TRACE("Int31/DPMI dispatch(%08lx)\n", callnum);
+
+ context->Eax = callnum;
+ context->Ecx = parm;
+ CallBuiltinHandler( context, 0x31 );
+ return LOWORD(context->Eax);
+ }
+ case 0x002a: /* Int41 dispatch - parm = int41 service number */
+ {
+ DWORD callnum = stack32_pop(context);
+ return callnum; /* FIXME: should really call INT_Int41Handler() */
+ }
+ default:
+ FIXME("Unknown service %08lx\n", service);
+ return 0xffffffff;
+ }
+}
diff --git a/dlls/vwin32.vxd/vwin32.vxd.spec b/dlls/vwin32.vxd/vwin32.vxd.spec
index 4a07ea1..8cd3059 100644
--- a/dlls/vwin32.vxd/vwin32.vxd.spec
+++ b/dlls/vwin32.vxd/vwin32.vxd.spec
@@ -1 +1,2 @@
@ stdcall DeviceIoControl(long ptr long ptr long ptr ptr) VWIN32_DeviceIoControl
+@ stdcall VxDCall(long ptr) VWIN32_VxDCall