Repository: otya128/winevdm
Branch: master
Commit: bd4c7b6cd0da
Files: 1307
Total size: 21.0 MB
Directory structure:
gitextract__5xouun8/
├── .gitattributes
├── .github/
│ └── ISSUE_TEMPLATE/
│ └── bug_report.md
├── .gitignore
├── BuildToolProperty.props
├── CMakeLists.txt
├── LICENSE
├── PropertySheet.props
├── README.md
├── READMEJP.md
├── appveyor.yml
├── avifile/
│ ├── CMakeLists.txt
│ ├── Makefile.in
│ ├── avifile.def
│ ├── avifile.dll16.spec
│ ├── avifile.vcxproj
│ └── main.c
├── comm/
│ ├── CMakeLists.txt
│ ├── Makefile.in
│ ├── comm.def
│ ├── comm.drv16.spec
│ └── comm.vcxproj
├── commctrl/
│ ├── CMakeLists.txt
│ ├── commctrl.c
│ ├── commctrl.def
│ ├── commctrl.dll16.spec
│ └── commctrl.vcxproj
├── commdlg/
│ ├── CMakeLists.txt
│ ├── cdlg16.h
│ ├── colordlg.c
│ ├── commdlg.def
│ ├── commdlg.dll16.spec
│ ├── commdlg.rc
│ ├── commdlg.vcxproj
│ ├── commdlg.vcxproj.filters
│ ├── filedlg.c
│ ├── finddlg.c
│ ├── fontdlg.c
│ ├── printdlg.c
│ └── resource.h
├── compobj/
│ ├── CMakeLists.txt
│ ├── Makefile.in
│ ├── compobj.c
│ ├── compobj.def
│ ├── compobj.dll16.spec
│ └── compobj.vcxproj
├── convertwinefile/
│ ├── convertwinefile.vcxproj
│ ├── convertwinefile.vcxproj.filters
│ └── main.c
├── convspec/
│ ├── CMakeLists.txt
│ ├── build.h
│ ├── convspec.c
│ ├── convspec.vcxproj
│ ├── convspec.vcxproj.filters
│ ├── import.c
│ ├── main.c.h
│ ├── parser.c
│ ├── relay.c
│ ├── res16.c
│ ├── res32.c
│ ├── spec16.c
│ ├── spec32.c
│ ├── utils.c
│ └── ver.h
├── ctl3d/
│ ├── CMakeLists.txt
│ ├── Makefile.in
│ ├── ctl3d.c
│ ├── ctl3d.def
│ ├── ctl3d.dll16.spec
│ └── ctl3d.vcxproj
├── ctl3dv2/
│ ├── CMakeLists.txt
│ ├── Makefile.in
│ ├── ctl3d.c
│ ├── ctl3dv2.def
│ ├── ctl3dv2.dll16.spec
│ └── ctl3dv2.vcxproj
├── ddeml/
│ ├── CMakeLists.txt
│ ├── Makefile.in
│ ├── ddeml.c
│ ├── ddeml.def
│ ├── ddeml.dll16.spec
│ └── ddeml.vcxproj
├── dispdib/
│ ├── CMakeLists.txt
│ ├── Makefile.in
│ ├── dispdib.c
│ ├── dispdib.def
│ ├── dispdib.dll16.spec
│ └── dispdib.vcxproj
├── display/
│ ├── CMakeLists.txt
│ ├── Makefile.in
│ ├── display.c
│ ├── display.def
│ ├── display.drv16.spec
│ ├── display.rc
│ └── display.vcxproj
├── dummy.c
├── dummydll/
│ └── vgaoem.fon
├── gdi/
│ ├── CMakeLists.txt
│ ├── bidi.c
│ ├── env.c
│ ├── gdi.c
│ ├── gdi.def
│ ├── gdi.exe16.spec
│ ├── gdi.vcxproj
│ ├── gdi.vcxproj.filters
│ ├── metafile.c
│ └── printdrv.c
├── gvm/
│ ├── CMakeLists.txt
│ ├── gvm-interface.h
│ ├── gvm.c
│ ├── gvm.def
│ ├── gvm.h
│ ├── gvm.vcxproj
│ └── gvm.vcxproj.filters
├── haxmvm/
│ ├── CMakeLists.txt
│ ├── haxmvm.c
│ ├── haxmvm.h
│ ├── haxmvm.vcxproj
│ └── haxmvm.vcxproj.filters
├── install (no console).lnk
├── install.inf
├── install.lnk
├── installw.inf
├── keyboard/
│ ├── CMakeLists.txt
│ ├── keyboard.c
│ ├── keyboard.def
│ ├── keyboard.drv16.spec
│ ├── keyboard.vcxproj
│ └── keyboard.vcxproj.filters
├── krnl386/
│ ├── CMakeLists.txt
│ ├── Makefile.in
│ ├── atom.c
│ ├── compat.c
│ ├── conf.c
│ ├── dma.c
│ ├── dosaspi.c
│ ├── dosdev.c
│ ├── dosexe.c
│ ├── dosexe.h
│ ├── dosmem.c
│ ├── dosvm.c
│ ├── error.c
│ ├── file.c
│ ├── fpu.c
│ ├── global.c
│ ├── instr.c
│ ├── int09.c
│ ├── int10.c
│ ├── int13.c
│ ├── int15.c
│ ├── int16.c
│ ├── int21.c
│ ├── int25.c
│ ├── int26.c
│ ├── int2f.c
│ ├── int31.c
│ ├── int33.c
│ ├── int67.c
│ ├── interrupts.c
│ ├── ioports.c
│ ├── kernel.c
│ ├── kernel16_private.h
│ ├── krnl386.def
│ ├── krnl386.exe16.spec
│ ├── krnl386.vcxproj
│ ├── krnl386.vcxproj.filters
│ ├── local.c
│ ├── ne_module.c
│ ├── ne_segment.c
│ ├── registry.c
│ ├── relay.c
│ ├── resource.c
│ ├── selector.c
│ ├── snoop.c
│ ├── soundblaster.c
│ ├── stub.c
│ ├── syslevel.c
│ ├── task.c
│ ├── thunk.c
│ ├── timer.c
│ ├── utthunk.c
│ ├── vdd.c
│ ├── version.rc
│ ├── vga.c
│ ├── vga.h
│ ├── vxd.c
│ ├── wow_handle.c
│ └── wowthunk.c
├── lzexpand/
│ ├── CMakeLists.txt
│ ├── lzexpand.c
│ ├── lzexpand.def
│ ├── lzexpand.dll16.spec
│ ├── lzexpand.vcxproj
│ ├── lzexpand.vcxproj.filters
│ └── wine_lzexpand.c
├── mmsystem/
│ ├── CMakeLists.txt
│ ├── Makefile.in
│ ├── driver.c
│ ├── mci16.c
│ ├── message16.c
│ ├── mmio16.c
│ ├── mmsystem.c
│ ├── mmsystem.def
│ ├── mmsystem.dll16.spec
│ ├── mmsystem.vcxproj
│ ├── playsound.c
│ └── winemm16.h
├── mouse/
│ ├── CMakeLists.txt
│ ├── Makefile.in
│ ├── mouse.c
│ ├── mouse.def
│ ├── mouse.drv16.spec
│ ├── mouse.rc
│ └── mouse.vcxproj
├── msacm/
│ ├── CMakeLists.txt
│ ├── Makefile.in
│ ├── msacm.c
│ ├── msacm.def
│ ├── msacm.dll16.spec
│ ├── msacm.vcxproj
│ └── wineacm16.h
├── msvideo/
│ ├── CMakeLists.txt
│ ├── Makefile.in
│ ├── msvideo.def
│ ├── msvideo.dll16.spec
│ ├── msvideo.vcxproj
│ ├── msvideo16.c
│ └── vfw16.h
├── nddeapi/
│ ├── CMakeLists.txt
│ ├── nddeapi.c
│ ├── nddeapi.def
│ ├── nddeapi.dll16.spec
│ └── nddeapi.vcxproj
├── netapi/
│ ├── CMakeLists.txt
│ ├── Makefile.in
│ ├── netapi.c
│ ├── netapi.def
│ ├── netapi.dll16.spec
│ └── netapi.vcxproj
├── ntvdm/
│ ├── CMakeLists.txt
│ ├── main.c
│ ├── ntvdm.def
│ ├── ntvdm.dll.spec
│ └── ntvdm.vcxproj
├── ole2/
│ ├── .gitignore
│ ├── CMakeLists.txt
│ ├── Makefile.in
│ ├── hglobalstream.c
│ ├── ifs.h
│ ├── ifs.idl
│ ├── ifs_thunk.c
│ ├── ifs_thunk.h
│ ├── memlockbytes.c
│ ├── ole2.c
│ ├── ole2.def
│ ├── ole2.dll16.spec
│ └── ole2.vcxproj
├── ole2conv/
│ ├── CMakeLists.txt
│ ├── Makefile.in
│ ├── ole2conv.def
│ ├── ole2conv.dll16.spec
│ └── ole2conv.vcxproj
├── ole2disp/
│ ├── CMakeLists.txt
│ ├── Makefile.in
│ ├── ole2disp.c
│ ├── ole2disp.def
│ ├── ole2disp.dll16.spec
│ ├── ole2disp.h
│ ├── ole2disp.vcxproj
│ ├── var/
│ │ ├── resource.h
│ │ ├── varformat.c
│ │ ├── variant.c
│ │ ├── variant.h
│ │ └── vartype.c
│ ├── wine_typelib.c
│ └── wine_typelib.h
├── ole2nls/
│ ├── CMakeLists.txt
│ ├── Makefile.in
│ ├── ole2nls.c
│ ├── ole2nls.def
│ ├── ole2nls.dll16.spec
│ ├── ole2nls.vcxproj
│ └── version.rc
├── ole2prox/
│ ├── CMakeLists.txt
│ ├── Makefile.in
│ ├── ole2prox.def
│ ├── ole2prox.dll16.spec
│ └── ole2prox.vcxproj
├── ole2thk/
│ ├── CMakeLists.txt
│ ├── Makefile.in
│ ├── ole2thk.def
│ ├── ole2thk.dll16.spec
│ └── ole2thk.vcxproj
├── olecli/
│ ├── CMakeLists.txt
│ ├── Makefile.in
│ ├── olecli.c
│ ├── olecli.def
│ ├── olecli.dll16.spec
│ ├── olecli.h
│ └── olecli.vcxproj
├── olesvr/
│ ├── CMakeLists.txt
│ ├── Makefile.in
│ ├── olesvr.c
│ ├── olesvr.def
│ ├── olesvr.dll16.spec
│ ├── olesvr.vcxproj
│ └── olesvr.vcxproj.filters
├── otvdm/
│ ├── CMakeLists.txt
│ ├── otvdm.rc
│ ├── otvdm.vcxproj
│ ├── otvdm.vcxproj.filters
│ ├── otvdmw.vcxproj
│ ├── otvdmw.vcxproj.filters
│ ├── resource.h
│ ├── visualstyle.manifest
│ └── winevdm.c
├── otvdm.ini
├── otvdm.sln
├── regedit/
│ ├── CMakeLists.txt
│ ├── Makefile.in
│ ├── regedit.c
│ ├── regedit.def
│ ├── regedit.exe16.spec
│ └── regedit.vcxproj
├── rmpatch/
│ ├── CMakeLists.txt
│ ├── Makefile.in
│ ├── instr.c
│ ├── rmpatch.c
│ ├── rmpatch.def
│ ├── rmpatch.dll16.spec
│ └── rmpatch.vcxproj
├── shell/
│ ├── CMakeLists.txt
│ ├── shell.c
│ ├── shell.def
│ ├── shell.dll16.spec
│ ├── shell.vcxproj
│ └── shell.vcxproj.filters
├── sound/
│ ├── CMakeLists.txt
│ ├── Makefile.in
│ ├── sound.c
│ ├── sound.def
│ ├── sound.drv16.spec
│ └── sound.vcxproj
├── storage/
│ ├── CMakeLists.txt
│ ├── Makefile.in
│ ├── ifs.h
│ ├── storage.c
│ ├── storage.def
│ ├── storage.dll16.spec
│ └── storage.vcxproj
├── system/
│ ├── CMakeLists.txt
│ ├── Makefile.in
│ ├── system.c
│ ├── system.def
│ ├── system.drv16.spec
│ └── system.vcxproj
├── timer/
│ ├── CMakeLists.txt
│ ├── timer.c
│ ├── timer.def
│ ├── timer.drv16.spec
│ └── timer.vcxproj
├── toolhelp/
│ ├── CMakeLists.txt
│ ├── Makefile.in
│ ├── toolhelp.c
│ ├── toolhelp.def
│ ├── toolhelp.dll16.spec
│ ├── toolhelp.h
│ └── toolhelp.vcxproj
├── tools/
│ └── package.ps1
├── typelib/
│ ├── CMakeLists.txt
│ ├── Makefile.in
│ ├── typelib.c
│ ├── typelib.def
│ ├── typelib.dll16.spec
│ └── typelib.vcxproj
├── uninstall.reg
├── user/
│ ├── CMakeLists.txt
│ ├── bidi.c
│ ├── comm.c
│ ├── dde.c
│ ├── dialog.c
│ ├── hook.c
│ ├── message.c
│ ├── message_table.h
│ ├── network.c
│ ├── stub.c
│ ├── user.c
│ ├── user.def
│ ├── user.exe16.spec
│ ├── user.rc
│ ├── user.vcxproj
│ ├── user.vcxproj.filters
│ ├── user_private.h
│ ├── window.c
│ └── winhelp.c
├── ver/
│ ├── CMakeLists.txt
│ ├── Makefile.in
│ ├── ver.def
│ ├── ver.dll16.spec
│ ├── ver.vcxproj
│ └── version.c
├── vm86/
│ ├── CMakeLists.txt
│ ├── COPYING.txt
│ ├── mame/
│ │ ├── emu/
│ │ │ └── cpu/
│ │ │ ├── i386/
│ │ │ │ ├── cycles.h
│ │ │ │ ├── i386.c
│ │ │ │ ├── i386.h
│ │ │ │ ├── i386dasm.c
│ │ │ │ ├── i386op16.c
│ │ │ │ ├── i386op32.c
│ │ │ │ ├── i386ops.c
│ │ │ │ ├── i386ops.h
│ │ │ │ ├── i386priv.h
│ │ │ │ ├── i486ops.c
│ │ │ │ ├── pentops.c
│ │ │ │ ├── readme_msdos_player.txt
│ │ │ │ └── x87ops.c
│ │ │ ├── i386.old/
│ │ │ │ ├── cycles.h
│ │ │ │ ├── i386.c
│ │ │ │ ├── i386.h
│ │ │ │ ├── i386dasm.c
│ │ │ │ ├── i386op16.c
│ │ │ │ ├── i386op32.c
│ │ │ │ ├── i386ops.c
│ │ │ │ ├── i386ops.h
│ │ │ │ ├── i386priv.h
│ │ │ │ ├── i486ops.c
│ │ │ │ ├── pentops.c
│ │ │ │ ├── readme_msdos_player.txt
│ │ │ │ └── x87ops.c
│ │ │ ├── i86/
│ │ │ │ ├── ea.h
│ │ │ │ ├── host.h
│ │ │ │ ├── i286.c
│ │ │ │ ├── i286.h
│ │ │ │ ├── i86.c
│ │ │ │ ├── i86.h
│ │ │ │ ├── i86.txt
│ │ │ │ ├── i86priv.h
│ │ │ │ ├── i86time.c
│ │ │ │ ├── instr186.c
│ │ │ │ ├── instr186.h
│ │ │ │ ├── instr286.c
│ │ │ │ ├── instr286.h
│ │ │ │ ├── instr86.c
│ │ │ │ ├── instr86.h
│ │ │ │ ├── modrm.h
│ │ │ │ ├── modrm286.h
│ │ │ │ ├── readme_msdos_player.txt
│ │ │ │ ├── table186.h
│ │ │ │ ├── table286.h
│ │ │ │ └── table86.h
│ │ │ ├── readme_msdos_player.txt
│ │ │ ├── vtlb.c
│ │ │ └── vtlb.h
│ │ └── lib/
│ │ └── softfloat/
│ │ ├── README.txt
│ │ ├── f2xm1.c
│ │ ├── fpatan.c
│ │ ├── fpu_constant.h
│ │ ├── fsincos.c
│ │ ├── fyl2x.c
│ │ ├── mamesf.h
│ │ ├── milieu.h
│ │ ├── readme_msdos_player.txt
│ │ ├── softfloat-macros
│ │ ├── softfloat-specialize
│ │ ├── softfloat.c
│ │ └── softfloat.h
│ ├── msdos.cpp
│ ├── msdos.h
│ ├── vm86.def
│ ├── vm86.vcxproj
│ └── vm86.vcxproj.filters
├── whpxvm/
│ ├── CMakeLists.txt
│ ├── whpxvm.c
│ ├── whpxvm.def
│ ├── whpxvm.h
│ └── whpxvm.vcxproj
├── widl/
│ ├── CMakeLists.txt
│ ├── client.c
│ ├── expr.c
│ ├── expr.h
│ ├── getopt.c
│ ├── getopt_msvc.h
│ ├── hash.c
│ ├── hash.h
│ ├── header.c
│ ├── header.h
│ ├── parser.h
│ ├── parser.l
│ ├── parser.y
│ ├── proxy.c
│ ├── register.c
│ ├── relay16.c
│ ├── server.c
│ ├── typegen.c
│ ├── typegen.h
│ ├── typelib.c
│ ├── typelib.h
│ ├── typelib_struct.h
│ ├── typetree.c
│ ├── typetree.h
│ ├── utils.c
│ ├── utils.h
│ ├── widl.c
│ ├── widl.h
│ ├── widl.vcxproj
│ ├── widltypes.h
│ └── write_msft.c
├── wifeman/
│ ├── CMakeLists.txt
│ ├── Makefile.in
│ ├── wifeman.c
│ ├── wifeman.def
│ ├── wifeman.dll16.spec
│ └── wifeman.vcxproj
├── win87em/
│ ├── CMakeLists.txt
│ ├── win87em.c
│ ├── win87em.def
│ ├── win87em.dll16.spec
│ ├── win87em.vcxproj
│ └── win87em.vcxproj.filters
├── wine/
│ ├── CMakeLists.txt
│ ├── casemap.c
│ ├── config.c
│ ├── config.h
│ ├── debug.c
│ ├── ldt.c
│ ├── ldt2.c
│ ├── port.h
│ ├── string.c
│ ├── wctype.c
│ ├── windows/
│ │ ├── Makefile.in
│ │ ├── accctrl.h
│ │ ├── access.idl
│ │ ├── aclapi.h
│ │ ├── aclui.h
│ │ ├── activation.idl
│ │ ├── activaut.idl
│ │ ├── activdbg.idl
│ │ ├── activscp.idl
│ │ ├── adshlp.h
│ │ ├── advpub.h
│ │ ├── af_irda.h
│ │ ├── amaudio.h
│ │ ├── amstream.idl
│ │ ├── amvideo.idl
│ │ ├── appcompatapi.h
│ │ ├── appmgmt.h
│ │ ├── appmodel.h
│ │ ├── asptlb.idl
│ │ ├── asynot.idl
│ │ ├── asysta.idl
│ │ ├── atlbase.h
│ │ ├── atlcom.h
│ │ ├── atliface.idl
│ │ ├── atlwin.h
│ │ ├── audevcod.h
│ │ ├── audioclient.idl
│ │ ├── audiopolicy.idl
│ │ ├── audiosessiontypes.h
│ │ ├── austream.idl
│ │ ├── authz.h
│ │ ├── aviriff.h
│ │ ├── avrt.h
│ │ ├── axcore.idl
│ │ ├── axextend.idl
│ │ ├── basetsd.h
│ │ ├── basetyps.h
│ │ ├── bcrypt.h
│ │ ├── bdaiface.idl
│ │ ├── bdaiface_enums.h
│ │ ├── bdatypes.h
│ │ ├── binres.idl
│ │ ├── bits.idl
│ │ ├── bits1_5.idl
│ │ ├── bits2_0.idl
│ │ ├── bits2_5.idl
│ │ ├── bits3_0.idl
│ │ ├── bitsmsg.h
│ │ ├── bluetoothapis.h
│ │ ├── bthsdpdef.h
│ │ ├── cderr.h
│ │ ├── cfgmgr32.h
│ │ ├── cguid.h
│ │ ├── chprst.idl
│ │ ├── cierror.h
│ │ ├── clusapi.h
│ │ ├── cmdbas.idl
│ │ ├── cmdtxt.idl
│ │ ├── cmnquery.idl
│ │ ├── colinf.idl
│ │ ├── comcat.idl
│ │ ├── commctrl.h
│ │ ├── commctrl.rh
│ │ ├── commdlg.h
│ │ ├── commoncontrols.idl
│ │ ├── compobj.h
│ │ ├── comsvcs.idl
│ │ ├── config.h
│ │ ├── config.h.in
│ │ ├── control.idl
│ │ ├── cor.idl
│ │ ├── cordebug.idl
│ │ ├── corerror.h
│ │ ├── corhdr.h
│ │ ├── cpl.h
│ │ ├── crtrow.idl
│ │ ├── cryptdlg.h
│ │ ├── cryptuiapi.h
│ │ ├── ctfutb.idl
│ │ ├── ctxtcall.idl
│ │ ├── custcntl.h
│ │ ├── cvconst.h
│ │ ├── d2d1.idl
│ │ ├── d2d1_1.idl
│ │ ├── d2dbasetypes.h
│ │ ├── d2derr.h
│ │ ├── d3d.h
│ │ ├── d3d10.idl
│ │ ├── d3d10_1.idl
│ │ ├── d3d10_1shader.h
│ │ ├── d3d10effect.h
│ │ ├── d3d10misc.h
│ │ ├── d3d10sdklayers.idl
│ │ ├── d3d10shader.h
│ │ ├── d3d11.idl
│ │ ├── d3d11_1.idl
│ │ ├── d3d11_2.idl
│ │ ├── d3d11_3.idl
│ │ ├── d3d11_4.idl
│ │ ├── d3d11on12.idl
│ │ ├── d3d11sdklayers.idl
│ │ ├── d3d11shader.h
│ │ ├── d3d12.idl
│ │ ├── d3d8.h
│ │ ├── d3d8caps.h
│ │ ├── d3d8types.h
│ │ ├── d3d9.h
│ │ ├── d3d9caps.h
│ │ ├── d3d9types.h
│ │ ├── d3dcaps.h
│ │ ├── d3dcommon.idl
│ │ ├── d3dcompiler.h
│ │ ├── d3dhal.h
│ │ ├── d3drm.h
│ │ ├── d3drmdef.h
│ │ ├── d3drmobj.h
│ │ ├── d3drmwin.h
│ │ ├── d3dtypes.h
│ │ ├── d3dukmdt.h
│ │ ├── d3dvec.inl
│ │ ├── d3dx10.h
│ │ ├── d3dx10async.h
│ │ ├── d3dx10core.idl
│ │ ├── d3dx10math.h
│ │ ├── d3dx10tex.h
│ │ ├── d3dx11.h
│ │ ├── d3dx11async.h
│ │ ├── d3dx11core.idl
│ │ ├── d3dx11tex.h
│ │ ├── d3dx9.h
│ │ ├── d3dx9anim.h
│ │ ├── d3dx9core.h
│ │ ├── d3dx9effect.h
│ │ ├── d3dx9math.h
│ │ ├── d3dx9math.inl
│ │ ├── d3dx9mesh.h
│ │ ├── d3dx9shader.h
│ │ ├── d3dx9shape.h
│ │ ├── d3dx9tex.h
│ │ ├── d3dx9xof.h
│ │ ├── davclnt.h
│ │ ├── dbccmd.idl
│ │ ├── dbcses.idl
│ │ ├── dbdsad.idl
│ │ ├── dbghelp.h
│ │ ├── dbinit.idl
│ │ ├── dbprop.idl
│ │ ├── dbs.idl
│ │ ├── dbt.h
│ │ ├── dciddi.h
│ │ ├── dciman.h
│ │ ├── dcommon.idl
│ │ ├── dde.h
│ │ ├── dde.rh
│ │ ├── ddeml.h
│ │ ├── ddraw.h
│ │ ├── ddrawgdi.h
│ │ ├── ddrawi.h
│ │ ├── ddstream.idl
│ │ ├── delayloadhandler.h
│ │ ├── devenum.idl
│ │ ├── devguid.h
│ │ ├── devicetopology.idl
│ │ ├── devpkey.h
│ │ ├── devpropdef.h
│ │ ├── dhcpcsdk.h
│ │ ├── dhtmldid.h
│ │ ├── dhtmled.idl
│ │ ├── difxapi.h
│ │ ├── digitalv.h
│ │ ├── dimm.idl
│ │ ├── dinput.h
│ │ ├── dinputd.h
│ │ ├── dispdib.h
│ │ ├── dispex.idl
│ │ ├── dlgs.h
│ │ ├── dls1.h
│ │ ├── dls2.h
│ │ ├── dmdls.h
│ │ ├── dmerror.h
│ │ ├── dmksctrl.h
│ │ ├── dmo.h
│ │ ├── dmoreg.h
│ │ ├── dmort.h
│ │ ├── dmplugin.h
│ │ ├── dmusbuff.h
│ │ ├── dmusicc.h
│ │ ├── dmusicf.h
│ │ ├── dmusici.h
│ │ ├── dmusics.h
│ │ ├── docobj.idl
│ │ ├── docobjectservice.idl
│ │ ├── downloadmgr.idl
│ │ ├── dpaddr.h
│ │ ├── dplay.h
│ │ ├── dplay8.h
│ │ ├── dplobby.h
│ │ ├── dplobby8.h
│ │ ├── dpnathlp.h
│ │ ├── drmexternals.idl
│ │ ├── dsconf.h
│ │ ├── dsgetdc.h
│ │ ├── dshow.h
│ │ ├── dsound.h
│ │ ├── dsrole.h
│ │ ├── dvdmedia.h
│ │ ├── dvoice.h
│ │ ├── dwmapi.h
│ │ ├── dwrite.idl
│ │ ├── dwrite_1.idl
│ │ ├── dwrite_2.idl
│ │ ├── dwrite_3.idl
│ │ ├── dxdiag.h
│ │ ├── dxerr8.h
│ │ ├── dxerr9.h
│ │ ├── dxfile.h
│ │ ├── dxgi.idl
│ │ ├── dxgi1_2.idl
│ │ ├── dxgi1_3.idl
│ │ ├── dxgi1_4.idl
│ │ ├── dxgi1_5.idl
│ │ ├── dxgi1_6.idl
│ │ ├── dxgicommon.idl
│ │ ├── dxgiformat.idl
│ │ ├── dxgitype.idl
│ │ ├── dxva2api.idl
│ │ ├── dyngraph.idl
│ │ ├── endpointvolume.idl
│ │ ├── errorrep.h
│ │ ├── errors.h
│ │ ├── errrec.idl
│ │ ├── evcode.h
│ │ ├── evntprov.h
│ │ ├── evntrace.h
│ │ ├── evr.idl
│ │ ├── excpt.h
│ │ ├── exdisp.idl
│ │ ├── exdispid.h
│ │ ├── fci.h
│ │ ├── fdi.h
│ │ ├── fileapi.h
│ │ ├── fltdefs.h
│ │ ├── fontsub.h
│ │ ├── fusion.idl
│ │ ├── gameux.idl
│ │ ├── gdiplus.h
│ │ ├── gdipluscolor.h
│ │ ├── gdipluscolormatrix.h
│ │ ├── gdipluseffects.h
│ │ ├── gdiplusenums.h
│ │ ├── gdiplusflat.h
│ │ ├── gdiplusgpstubs.h
│ │ ├── gdiplusimaging.h
│ │ ├── gdiplusinit.h
│ │ ├── gdiplusmem.h
│ │ ├── gdiplusmetaheader.h
│ │ ├── gdipluspixelformats.h
│ │ ├── gdiplustypes.h
│ │ ├── guiddef.h
│ │ ├── hidusage.h
│ │ ├── highlevelmonitorconfigurationapi.h
│ │ ├── hlguids.h
│ │ ├── hlink.idl
│ │ ├── hstring.idl
│ │ ├── htiface.idl
│ │ ├── htiframe.idl
│ │ ├── htmlhelp.h
│ │ ├── http.h
│ │ ├── httprequest.idl
│ │ ├── httprequestid.h
│ │ ├── i_cryptasn1tls.h
│ │ ├── iads.idl
│ │ ├── icftypes.idl
│ │ ├── icm.h
│ │ ├── icmpapi.h
│ │ ├── idispids.h
│ │ ├── ieautomation.idl
│ │ ├── iextag.idl
│ │ ├── ifdef.h
│ │ ├── ifmib.h
│ │ ├── iimgctx.idl
│ │ ├── imagehlp.h
│ │ ├── ime.h
│ │ ├── imm.h
│ │ ├── imnact.idl
│ │ ├── imnxport.idl
│ │ ├── in6addr.h
│ │ ├── inaddr.h
│ │ ├── indexsrv.idl
│ │ ├── initguid.h
│ │ ├── inputscope.idl
│ │ ├── inseng.idl
│ │ ├── inspectable.idl
│ │ ├── interactioncontext.h
│ │ ├── intshcut.h
│ │ ├── ipexport.h
│ │ ├── iphlpapi.h
│ │ ├── ipifcons.h
│ │ ├── ipmib.h
│ │ ├── iprtrmib.h
│ │ ├── iptypes.h
│ │ ├── isguids.h
│ │ ├── knownfolders.h
│ │ ├── ks.h
│ │ ├── ksguid.h
│ │ ├── ksmedia.h
│ │ ├── ksuuids.h
│ │ ├── libloaderapi.h
│ │ ├── lm.h
│ │ ├── lmaccess.h
│ │ ├── lmapibuf.h
│ │ ├── lmat.h
│ │ ├── lmbrowsr.h
│ │ ├── lmcons.h
│ │ ├── lmerr.h
│ │ ├── lmjoin.h
│ │ ├── lmmsg.h
│ │ ├── lmserver.h
│ │ ├── lmshare.h
│ │ ├── lmstats.h
│ │ ├── lmuse.h
│ │ ├── lmuseflg.h
│ │ ├── lmwksta.h
│ │ ├── loadperf.h
│ │ ├── lowlevelmonitorconfigurationapi.h
│ │ ├── lzexpand.h
│ │ ├── mapi.h
│ │ ├── mapicode.h
│ │ ├── mapidefs.h
│ │ ├── mapiform.h
│ │ ├── mapiguid.h
│ │ ├── mapitags.h
│ │ ├── mapiutil.h
│ │ ├── mapival.h
│ │ ├── mapix.h
│ │ ├── mciavi.h
│ │ ├── mcx.h
│ │ ├── mediaerr.h
│ │ ├── mediaobj.idl
│ │ ├── metahost.idl
│ │ ├── mfapi.h
│ │ ├── mferror.h
│ │ ├── mfidl.idl
│ │ ├── mfobjects.idl
│ │ ├── mfreadwrite.idl
│ │ ├── mftransform.idl
│ │ ├── midles.h
│ │ ├── mimeinfo.idl
│ │ ├── mimeole.idl
│ │ ├── minmax.h
│ │ ├── mlang.idl
│ │ ├── mmc.idl
│ │ ├── mmddk.h
│ │ ├── mmdeviceapi.idl
│ │ ├── mmreg.h
│ │ ├── mmstream.idl
│ │ ├── mmsystem.h
│ │ ├── mprapi.h
│ │ ├── mprerror.h
│ │ ├── msacm.h
│ │ ├── msacmdlg.h
│ │ ├── msacmdrv.h
│ │ ├── msasn1.h
│ │ ├── mscat.h
│ │ ├── mscoree.idl
│ │ ├── msctf.idl
│ │ ├── msdadc.idl
│ │ ├── msdaguid.h
│ │ ├── msdasc.idl
│ │ ├── mshtmcid.h
│ │ ├── mshtmdid.h
│ │ ├── mshtmhst.idl
│ │ ├── mshtml.idl
│ │ ├── msi.h
│ │ ├── msidefs.h
│ │ ├── msident.idl
│ │ ├── msinkaut.idl
│ │ ├── msiquery.h
│ │ ├── msopc.idl
│ │ ├── mssip.h
│ │ ├── msstkppg.h
│ │ ├── mstask.idl
│ │ ├── mstcpip.h
│ │ ├── mswsock.h
│ │ ├── msxml.idl
│ │ ├── msxml2.idl
│ │ ├── msxml2did.h
│ │ ├── msxml6.idl
│ │ ├── msxml6did.h
│ │ ├── msxmldid.h
│ │ ├── mtxdm.h
│ │ ├── multimon.h
│ │ ├── nb30.h
│ │ ├── ncrypt.h
│ │ ├── ndrtypes.h
│ │ ├── netcfgx.idl
│ │ ├── netcon.idl
│ │ ├── netfw.idl
│ │ ├── netioapi.h
│ │ ├── netlistmgr.idl
│ │ ├── nldef.h
│ │ ├── npapi.h
│ │ ├── nserror.h
│ │ ├── nspapi.h
│ │ ├── ntddcdrm.h
│ │ ├── ntddndis.h
│ │ ├── ntddscsi.h
│ │ ├── ntddstor.h
│ │ ├── ntdef.h
│ │ ├── ntdsapi.h
│ │ ├── ntlsa.h
│ │ ├── ntquery.h
│ │ ├── ntsecapi.h
│ │ ├── ntsecpkg.h
│ │ ├── ntstatus.h
│ │ ├── oaidl.idl
│ │ ├── objbase.h
│ │ ├── objectarray.idl
│ │ ├── objidl.idl
│ │ ├── objsafe.idl
│ │ ├── objsel.h
│ │ ├── ocidl.idl
│ │ ├── ocmm.idl
│ │ ├── odbcinst.h
│ │ ├── ole2.h
│ │ ├── ole2ver.h
│ │ ├── oleacc.idl
│ │ ├── oleauto.h
│ │ ├── olectl.h
│ │ ├── oledb.idl
│ │ ├── oledberr.h
│ │ ├── oledlg.h
│ │ ├── oleidl.idl
│ │ ├── opcbase.idl
│ │ ├── opcobjectmodel.idl
│ │ ├── opcparturi.idl
│ │ ├── opnrst.idl
│ │ ├── optary.idl
│ │ ├── patchapi.h
│ │ ├── pathcch.h
│ │ ├── pdh.h
│ │ ├── pdhmsg.h
│ │ ├── perflib.h
│ │ ├── perhist.idl
│ │ ├── physicalmonitorenumerationapi.h
│ │ ├── pktdef.h
│ │ ├── poppack.h
│ │ ├── powrprof.h
│ │ ├── prntvpt.h
│ │ ├── profinfo.h
│ │ ├── propidl.idl
│ │ ├── propkey.h
│ │ ├── propkeydef.h
│ │ ├── propsys.idl
│ │ ├── propvarutil.h
│ │ ├── prsht.h
│ │ ├── psapi.h
│ │ ├── pshpack1.h
│ │ ├── pshpack2.h
│ │ ├── pshpack4.h
│ │ ├── pshpack8.h
│ │ ├── pstore.idl
│ │ ├── qedit.idl
│ │ ├── ras.h
│ │ ├── rasdlg.h
│ │ ├── raserror.h
│ │ ├── reason.h
│ │ ├── regstr.h
│ │ ├── restartmanager.h
│ │ ├── richedit.h
│ │ ├── richole.idl
│ │ ├── rmxfguid.h
│ │ ├── rmxftmpl.x
│ │ ├── roapi.h
│ │ ├── roparameterizediid.idl
│ │ ├── row.idl
│ │ ├── rowchg.idl
│ │ ├── rowpos.idl
│ │ ├── rowpsc.idl
│ │ ├── rpc.h
│ │ ├── rpcasync.h
│ │ ├── rpcdce.h
│ │ ├── rpcdcep.h
│ │ ├── rpcndr.h
│ │ ├── rpcnterr.h
│ │ ├── rpcproxy.h
│ │ ├── rpcsal.h
│ │ ├── rstbas.idl
│ │ ├── rstinf.idl
│ │ ├── rstloc.idl
│ │ ├── rstnot.idl
│ │ ├── rtutils.h
│ │ ├── sal.h
│ │ ├── sapi.idl
│ │ ├── sapiddk.idl
│ │ ├── scarderr.h
│ │ ├── schannel.h
│ │ ├── schemadef.h
│ │ ├── schnlsp.h
│ │ ├── sddl.h
│ │ ├── secext.h
│ │ ├── security.h
│ │ ├── sensapi.h
│ │ ├── sensevts.idl
│ │ ├── servprov.idl
│ │ ├── sesprp.idl
│ │ ├── setupapi.h
│ │ ├── sfc.h
│ │ ├── shdeprecated.idl
│ │ ├── shdispid.h
│ │ ├── shellapi.h
│ │ ├── shellscalingapi.h
│ │ ├── shimgdata.idl
│ │ ├── shldisp.idl
│ │ ├── shlguid.h
│ │ ├── shlobj.h
│ │ ├── shlwapi.h
│ │ ├── shobjidl.idl
│ │ ├── shtypes.idl
│ │ ├── sipbase.h
│ │ ├── slerror.h
│ │ ├── slpublic.h
│ │ ├── snmp.h
│ │ ├── softpub.h
│ │ ├── sperror.h
│ │ ├── sql.h
│ │ ├── sqlext.h
│ │ ├── sqltypes.h
│ │ ├── sqlucode.h
│ │ ├── srcrst.idl
│ │ ├── srrestoreptapi.h
│ │ ├── sspi.h
│ │ ├── stamp-h
│ │ ├── stamp-h.in
│ │ ├── stdole2.idl
│ │ ├── stgprop.h
│ │ ├── sti.h
│ │ ├── storage.h
│ │ ├── strmif.idl
│ │ ├── strsafe.h
│ │ ├── structuredquerycondition.idl
│ │ ├── svrapi.h
│ │ ├── t2embapi.h
│ │ ├── tapi.h
│ │ ├── taskschd.idl
│ │ ├── tchar.h
│ │ ├── tcpestats.h
│ │ ├── tcpmib.h
│ │ ├── textserv.h
│ │ ├── textstor.idl
│ │ ├── tlhelp32.h
│ │ ├── tlogstg.idl
│ │ ├── tmschema.h
│ │ ├── tom.idl
│ │ ├── traffic.h
│ │ ├── transact.idl
│ │ ├── twain.h
│ │ ├── txcoord.idl
│ │ ├── txdtc.idl
│ │ ├── udpmib.h
│ │ ├── uianimation.idl
│ │ ├── uiautomation.h
│ │ ├── uiautomationclient.idl
│ │ ├── uiautomationcore.idl
│ │ ├── uiautomationcoreapi.h
│ │ ├── uiribbon.idl
│ │ ├── unknwn.idl
│ │ ├── urlhist.idl
│ │ ├── urlmon.idl
│ │ ├── userenv.h
│ │ ├── usp10.h
│ │ ├── uuids.h
│ │ ├── uxtheme.h
│ │ ├── vdmdbg.h
│ │ ├── ver.h
│ │ ├── verrsrc.h
│ │ ├── vfw.h
│ │ ├── vfwmsgs.h
│ │ ├── virtdisk.h
│ │ ├── vmr9.idl
│ │ ├── vmrender.idl
│ │ ├── vss.idl
│ │ ├── vsstyle.h
│ │ ├── vssym32.h
│ │ ├── vswriter.h
│ │ ├── wbemcli.idl
│ │ ├── wbemdisp.idl
│ │ ├── wbemprov.idl
│ │ ├── wct.h
│ │ ├── webservices.h
│ │ ├── werapi.h
│ │ ├── wfext.h
│ │ ├── wia.h
│ │ ├── wia_lh.idl
│ │ ├── wia_xp.idl
│ │ ├── wiadef.h
│ │ ├── wimgapi.h
│ │ ├── winbase.h
│ │ ├── wincodec.idl
│ │ ├── wincodecsdk.idl
│ │ ├── wincon.h
│ │ ├── wincred.h
│ │ ├── wincrypt.h
│ │ ├── windef.h
│ │ ├── windns.h
│ │ ├── windows.foundation.idl
│ │ ├── windows.h
│ │ ├── windowsx.h
│ │ ├── winerror.h
│ │ ├── winevt.h
│ │ ├── wingdi.h
│ │ ├── winhttp.h
│ │ ├── wininet.h
│ │ ├── winineti.h
│ │ ├── winioctl.h
│ │ ├── winldap.h
│ │ ├── winnetwk.h
│ │ ├── winnls.h
│ │ ├── winnls32.h
│ │ ├── winnt.h
│ │ ├── winnt.rh
│ │ ├── winperf.h
│ │ ├── winreg.h
│ │ ├── winresrc.h
│ │ ├── winsafer.h
│ │ ├── winscard.h
│ │ ├── winsmcrd.h
│ │ ├── winsnmp.h
│ │ ├── winsock.h
│ │ ├── winsock2.h
│ │ ├── winspool.h
│ │ ├── winstring.h
│ │ ├── winsvc.h
│ │ ├── winsxs.idl
│ │ ├── wintab.h
│ │ ├── wintabx.h
│ │ ├── winternl.h
│ │ ├── wintrust.h
│ │ ├── winuser.h
│ │ ├── winuser.rh
│ │ ├── winver.h
│ │ ├── wlanapi.h
│ │ ├── wmcodecdsp.idl
│ │ ├── wmdrmsdk.idl
│ │ ├── wmistr.h
│ │ ├── wmium.h
│ │ ├── wmiutils.idl
│ │ ├── wmp.idl
│ │ ├── wmpids.h
│ │ ├── wmsbuffer.idl
│ │ ├── wmsdk.h
│ │ ├── wmsdkidl.idl
│ │ ├── wnaspi32.h
│ │ ├── wownt32.h
│ │ ├── wpcapi.idl
│ │ ├── ws2def.h
│ │ ├── ws2ipdef.h
│ │ ├── ws2spi.h
│ │ ├── ws2tcpip.h
│ │ ├── wsdapi.h
│ │ ├── wsdbase.idl
│ │ ├── wsddisco.idl
│ │ ├── wsdtypes.h
│ │ ├── wsdutil.h
│ │ ├── wsdxml.idl
│ │ ├── wsdxmldom.h
│ │ ├── wshisotp.h
│ │ ├── wsipx.h
│ │ ├── wsnwlink.h
│ │ ├── wtsapi32.h
│ │ ├── wtypes.idl
│ │ ├── wuapi.idl
│ │ ├── x3daudio.h
│ │ ├── xapo.idl
│ │ ├── xapofx.h
│ │ ├── xaudio2.idl
│ │ ├── xaudio2fx.idl
│ │ ├── xcmc.h
│ │ ├── xinput.h
│ │ ├── xmldom.h
│ │ ├── xmldom.idl
│ │ ├── xmldomdid.h
│ │ ├── xmldso.idl
│ │ ├── xmldsodid.h
│ │ ├── xmllite.idl
│ │ └── zmouse.h
│ ├── wine/
│ │ ├── config.h
│ │ ├── debug.h
│ │ ├── exception.h
│ │ ├── heap.h
│ │ ├── library.h
│ │ ├── list.h
│ │ ├── mmsystem16.h
│ │ ├── port.h
│ │ ├── server.h
│ │ ├── server_protocol.h
│ │ ├── unicode.h
│ │ ├── winaspi.h
│ │ ├── winbase16.h
│ │ ├── windef16.h
│ │ ├── wine_common_ver.rc
│ │ ├── wingdi16.h
│ │ ├── winnet16.h
│ │ ├── winuser16.h
│ │ └── wpp.h
│ ├── wine.def
│ ├── wine.vcxproj
│ ├── wine.vcxproj.filters
│ └── winuser.rh
├── winecrt0/
│ ├── CMakeLists.txt
│ ├── crt0_private.h
│ ├── dll_entry.c
│ ├── exception.c
│ ├── exe16_entry.c
│ ├── init.c
│ ├── stub.c
│ ├── winecrt0.vcxproj
│ └── winecrt0.vcxproj.filters
├── wing/
│ ├── CMakeLists.txt
│ ├── Makefile.in
│ ├── wing.c
│ ├── wing.def
│ ├── wing.dll16.spec
│ └── wing.vcxproj
├── winhlp32/
│ ├── CMakeLists.txt
│ ├── Makefile.in
│ ├── REOLEStorage1
│ ├── callback.c
│ ├── hlpfile.c
│ ├── hlpfile.h
│ ├── macro.c
│ ├── macro.h
│ ├── macro.lex.l
│ ├── string.c
│ ├── tom.h
│ ├── winhelp.c
│ ├── winhelp.h
│ ├── winhelp_res.h
│ ├── winhlp32.rc
│ ├── winhlp32.vcxproj
│ └── winhlp32.vcxproj.filters
├── winnls/
│ ├── CMakeLists.txt
│ ├── winnls.c
│ ├── winnls.def
│ ├── winnls.dll16.spec
│ ├── winnls.vcxproj
│ └── winnls.vcxproj.filters
├── winoldap/
│ ├── CMakeLists.txt
│ ├── Makefile.in
│ ├── winoldap.c
│ ├── winoldap.def
│ ├── winoldap.mod16.spec
│ └── winoldap.vcxproj
├── winsock/
│ ├── CMakeLists.txt
│ ├── Makefile.in
│ ├── socket.c
│ ├── winsock.def
│ ├── winsock.dll16.spec
│ ├── winsock.vcxproj
│ └── winsock16.h
├── winspool/
│ ├── CMakeLists.txt
│ ├── winspool.c
│ ├── winspool.def
│ ├── winspool.drv16.spec
│ └── winspool.vcxproj
├── wow32/
│ ├── CMakeLists.txt
│ ├── wow32.def
│ ├── wow32.spec
│ ├── wow32.vcxproj
│ ├── wow32.vcxproj.filters
│ ├── wow_main.c
│ └── wownt32.h
└── wpp/
├── CMakeLists.txt
├── ppl.l
├── ppy.y
├── preproc.c
├── wpp.c
├── wpp.vcxproj
└── wpp_private.h
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitattributes
================================================
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain
*.reg text eol=crlf
*.ini text eol=crlf
README.md text eol=crlf
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
Try the latest version first.
Go [here](https://ci.appveyor.com/project/otya128/winevdm) and click `Environment: THIS_BUILD_IS_RECOMMENDED__VCXPROJ_BUILD=1`-> `Artifacts 1`-> `zip` to download the latest version.
**Describe the bug**
A clear and concise description of what the bug is.
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Environment (please complete the following information):**
- OS: [e.g. Windows 10 1903]
- Version [e.g. version: 1523]
**Additional context**
Add any other context about the problem here.
It is very helpful to provide a trace file if possible.
Please note that this file contains detailed information about the program.
**Procedure**
1. Run the command prompt.
2. Set the environment variable:
```cmd
set WINEDEBUG=+all,-snoop,-ldt,-fixup,-module,-global,-local,-disasm,-syslevel,-thunk
```
3.
```cmd
*old-executable-file* 2> trace.txt
```
4. Upload trace.txt here.
================================================
FILE: .gitignore
================================================
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.sln.docstates
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
w[Dd]ebug/
x64/
build/
bld/
[Bb]in/
[Oo]bj/
# Roslyn cache directories
*.ide/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
#NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opensdf
*.sdf
*.cachefile
# Visual Studio profiler
*.psess
*.vsp
*.vspx
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding addin-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
_NCrunch_*
.*crunch*.local.xml
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
## TODO: Comment the next line if you want to checkin your
## web deploy settings but do note that will include unencrypted
## passwords
#*.pubxml
# NuGet Packages Directory
packages/*
## TODO: If the tool you use requires repositories.config
## uncomment the next line
#!packages/repositories.config
# Enable "build/" folder in the NuGet Packages folder since
# NuGet packages use it for MSBuild targets.
# This line needs to be after the ignore of the build folder
# (and the packages folder if the line above has been uncommented)
!packages/build/
# Windows Azure Build Output
csx/
*.build.csdef
# Windows Store app package directory
AppPackages/
# Others
sql/
*.Cache
ClientBin/
[Ss]tyle[Cc]op.*
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.pfx
*.publishsettings
node_modules/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# LightSwitch generated files
GeneratedArtifacts/
_Pvt_Extensions/
ModelManifest.xml
*.db
*.opendb
*.tlog
/.vs
*16.asm
*.i
================================================
FILE: BuildToolProperty.props
================================================
$(AsmPath)
$(AsmPath)
<_PropertySheetDisplayName>BuildToolProperty
$(BisonPath)
$(FlexPath)
================================================
FILE: CMakeLists.txt
================================================
cmake_minimum_required(VERSION 3.10.2)
#-Dinline=__inline
project(winevdm)
set(ASM_TOOL_DIR )
# prevent wine error
if (NOT(MSVC))
string(APPEND CMAKE_CXX_FLAGS " -Wno-narrowing ")
else()
add_definitions(-DUSE_COMPILER_EXCEPTIONS -Dinline=__inline)
endif()
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
macro(def_file_build32 file)
get_filename_component(name_we ${file} NAME_WE)
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${name_we}.def
DEPENDS ${file}.spec convspec
COMMAND convspec ${CMAKE_CURRENT_LIST_DIR}/${file}.spec -DEF -32 > ${CMAKE_CURRENT_BINARY_DIR}/${name_we}.def)
add_custom_target(generate_def_${name_we} DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${name_we}.def)
endmacro()
macro(def_file_build file)
get_filename_component(name_we ${file} NAME_WE)
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${name_we}.def
DEPENDS ${file}.spec convspec
COMMAND convspec ${CMAKE_CURRENT_LIST_DIR}/${file}.spec -DEF > ${CMAKE_CURRENT_BINARY_DIR}/${name_we}.def)
add_custom_target(generate_def_${name_we} DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${name_we}.def)
endmacro()
macro(spec_build file modname)
string(TOUPPER modname modname)
get_filename_component(name_we ${file} NAME_WE)
cmake_parse_arguments(SPEC_BUILD "" "" "ARG" ${ARGN})
add_custom_command(OUTPUT ${file}.obj ${file}.asm
DEPENDS ${file}.spec convspec
COMMAND convspec ${CMAKE_CURRENT_LIST_DIR}/${file}.spec ${SPEC_BUILD_ARG} ${modname} > ${file}.asm && ${ASM_TOOL_DIR}as --32 -o ${file}.obj ${file}.asm)
add_custom_target(generate_asm_${name_we} DEPENDS ${file}.obj)
if (MSVC)
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /SAFESEH:NO")
endif()
def_file_build(${file})
add_dependencies(${name_we} generate_asm_${name_we})
add_dependencies(${name_we} generate_def_${name_we})
set_target_properties(${name_we} PROPERTIES PREFIX "")
endmacro()
macro(widl_build file_idl file_c file_h)
get_filename_component(name_we ${file_idl} NAME_WE)
add_custom_command(OUTPUT ${file_c} ${file_h}
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${file_idl} widl
COMMAND $/widl.exe ${CMAKE_CURRENT_SOURCE_DIR}/${file_idl} -o ${file_c} && $/widl.exe ${CMAKE_CURRENT_SOURCE_DIR}/${file_idl} -o ${file_h}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
add_custom_target(generate_ifs_${name_we} DEPENDS ${file_c} ${file_h})
endmacro()
INCLUDE(CheckIncludeFiles)
CHECK_INCLUDE_FILES(WinHvPlatform.h HAVE_WINHVPLATFORM_H)
include_directories(BEFORE wow32)
find_package(BISON)
find_package(FLEX)
add_subdirectory(wine)
add_subdirectory(convspec)
add_subdirectory(winecrt0)
add_subdirectory(wow32)
add_subdirectory(krnl386)
add_subdirectory(user)
add_subdirectory(gdi)
add_subdirectory(win87em)
add_subdirectory(shell)
add_subdirectory(vm86)
add_subdirectory(avifile)
add_subdirectory(comm)
add_subdirectory(commctrl)
add_subdirectory(commdlg)
add_subdirectory(compobj)
add_subdirectory(ctl3d)
add_subdirectory(ctl3dv2)
add_subdirectory(ddeml)
add_subdirectory(dispdib)
add_subdirectory(display)
add_subdirectory(haxmvm)
add_subdirectory(keyboard)
add_subdirectory(lzexpand)
add_subdirectory(mmsystem)
add_subdirectory(mouse)
add_subdirectory(msacm)
add_subdirectory(msvideo)
add_subdirectory(nddeapi)
add_subdirectory(ole2)
add_subdirectory(ole2conv)
add_subdirectory(ole2disp)
add_subdirectory(ole2nls)
add_subdirectory(ole2prox)
add_subdirectory(ole2thk)
add_subdirectory(olecli)
add_subdirectory(olesvr)
add_subdirectory(regedit)
add_subdirectory(rmpatch)
add_subdirectory(sound)
add_subdirectory(storage)
add_subdirectory(system)
add_subdirectory(timer)
add_subdirectory(toolhelp)
add_subdirectory(typelib)
add_subdirectory(ver)
add_subdirectory(widl)
add_subdirectory(wifeman)
add_subdirectory(wing)
add_subdirectory(winhlp32)
add_subdirectory(winnls)
add_subdirectory(winoldap)
add_subdirectory(winsock)
add_subdirectory(winspool)
add_subdirectory(wpp)
add_subdirectory(otvdm)
add_subdirectory(gvm)
add_subdirectory(ntvdm)
if (HAVE_WINHVPLATFORM_H)
add_subdirectory(whpxvm)
endif()
================================================
FILE: LICENSE
================================================
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
Copyright (C)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.
================================================
FILE: PropertySheet.props
================================================
C:\msys32\usr\bin\
<_PropertySheetDisplayName>MacroPropertySheet
$(SolutionDir)wow32;$(IncludePath)
$(AsmPath)
================================================
FILE: README.md
================================================
# winevdm on 64-bit Windows

[Download stable version](https://github.com/otya128/winevdm/releases)
[Download latest version (unstable)](https://ci.appveyor.com/project/otya128/winevdm/)
16-bit Windows (Windows 1.x, 2.x, 3.0, 3.1, etc.) on 64-bit Windows
An altered version of winevdm (a 16-bit Windows emulator), ported to 64-bit Windows.
# How to run
+ If you get an error that VCRUNTIME140.dll is missing, install [Microsoft Visual C++ Redistributable for Visual Studio 2017 (32-bit)](https://aka.ms/vs/15/release/vc_redist.x86.exe)
+ Drag and drop Win16 executable file to otvdm.exe or execute otvdmw.exe.
# How to install
+ Download or compile
+ Run "install" shortcut or right-click on install.inf and select "Install"
+ You can execute Win16 binaries directly!
If the registry is initialized by Windows Update, perform the above procedure again.
You can uninstall it by running uninstall.reg.
# Configuration
See [otvdm.ini](otvdm.ini).
# How to compile(Visual Studio)
+ Install Visual Studio 2017
+ Edit PropertySheet.props
+ Compile
# How to compile(cmake)
```sh
git clone https://github.com/otya128/winevdm.git
cd winevdm
mkdir build
cd build
cmake ..
make
```
# How does it work?
This program contains the following items
+ CPU Emulator
+ 64-bit Windows cannot modify LDT(NtSetInformationProcess(,ProcessLdtInformation,,) always returns error)
+ wine based Win16->Win32 conversion codes:
```c
BOOL16 WINAPI DestroyWindow16( HWND16 hwnd )
{
return DestroyWindow( WIN_Handle32(hwnd) );
}
```
Relay routines from 16-bit to 32-bit are autogenerated by convspec
```spec
53 pascal -ret16 DestroyWindow(word) DestroyWindow16
```
+ DOS emulation for Win16
+ 16-bit <=> native HANDLE conversion
+ Fix compatibility problems, fix compatibility problems
## install.inf
When 64-bit Windows detects a 16-bit installer, it has a mechanism to start an alternative installer which is not 16-bit.
This program uses it.
## WINDOWS directory redirection
Some Win16 programs try to save their settings in %WINDIR%\.ini
In recent Windows, it is not allowed to save to %WINDIR%, so it redirects.
# winevdm
```bat
winevdm.exe [--app-name app.exe] command line
winevdm.exe CALC.EXE
```
It can also run DOS executables (DOS emulator-like).
You can set the DOS version with the VDMDOSVER environment variable.
DOS emulation is incomplete and it is recommended to use DOSBox or [MS-DOS Player](http://takeda-toshiya.my.coocan.jp/msdos/).
================================================
FILE: READMEJP.md
================================================
# winevdm on windows(64bit)
[Download](https://github.com/otya128/winevdm/releases)
winevdm on windows(64bit)
16bit用Windowsのプログラムを動かすプログラム
winevdmの移植版
# コンパイルに必要そうなもの
+ VC++
+ gas
# winevdm
```bat
winevdm.exe [--app-name app.exe] command line
winevdm.exe CALC.EXE
```
DOS実行ファイルを実行することも可能(ただしDOSエミュレータは他に存在するためそれを使った方が確実)
VDMDOSVER環境変数を設定するとDOSのバージョンを指定できる
# convspec
convert wine spec file
winebuildから必要な部分を取り出しVC++で動かせるようにし、関数名の扱いなどを変え出力されたassemblyをVC++で扱えるようにした
```bat
convspec .specfile modulename > asm
convspec .specfile -DEF > def
convspec commdlg.dll16.spec COMMDLG > commdlg.dll16.asm
convspec commdlg.dll16.spec -DEF > commdlg.def
as --32 -o commdlg.dll16.obj commdlg.dll16.asm
```
# gdi
GDI.EXE
# krnl386
KRNL386.EXE
# user
USER.EXE
# vm86
CPU emulator
# wine
libwine
# wow32
wow32.dll
================================================
FILE: appveyor.yml
================================================
version: dev{build}
image: Visual Studio 2017
configuration: Release
environment:
matrix:
- THIS_BUILD_IS_RECOMMENDED__VCXPROJ_BUILD: 1
- THIS_BUILD_IS_NOT_RECOMMENDED__GCC_CMAKE_BUILD: 1
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
build:
parallel: true
verbosity: quiet
for:
-
matrix:
only:
- THIS_BUILD_IS_NOT_RECOMMENDED__GCC_CMAKE_BUILD: 1
build_script:
ps: |
mkdir build
cd build
$env:MSYSTEM = "MINGW32"
$env:MSYSTEM_CARCH = "i686"
$env:MSYSTEM_CHOST = "i686-w64-mingw32"
$env:MSYSTEM_PREFIX = "C:/msys64/mingw32"
$env:Path = "C:\msys64\mingw32\bin;C:\msys64\usr\local\bin;C:\msys64\usr\bin;" + $env:Path
cmake -G"MSYS Makefiles" .. -DCMAKE_CXX_FLAGS=-w -DCMAKE_C_FLAGS=-w
if (0 -ne $LastExitCode)
{
throw "Failed to execute cmake"
}
make -j 2
if (0 -ne $LastExitCode)
{
throw "Failed to execute make"
}
mkdir otvdm-cmake-gcc-${env:APPVEYOR_REPO_BRANCH}-${env:APPVEYOR_BUILD_NUMBER}
..\tools\package.ps1 -root ..\ -src .\ -dst otvdm-cmake-gcc-${env:APPVEYOR_REPO_BRANCH}-${env:APPVEYOR_BUILD_NUMBER} -objcopy "C:\msys64\usr\bin\objcopy.exe" -as "as.exe" -dll otvdm-cmake-gcc-${env:APPVEYOR_REPO_BRANCH}-${env:APPVEYOR_BUILD_NUMBER}
copy C:\msys64\mingw32\bin\libgcc_s_dw2-1.dll otvdm-cmake-gcc-${env:APPVEYOR_REPO_BRANCH}-${env:APPVEYOR_BUILD_NUMBER}\
copy C:\msys64\mingw32\bin\libstdc++-6.dll otvdm-cmake-gcc-${env:APPVEYOR_REPO_BRANCH}-${env:APPVEYOR_BUILD_NUMBER}\
copy C:\mingw-w64\i686-5.3.0-posix-dwarf-rt_v4-rev0\mingw32\bin\libwinpthread-1.dll otvdm-cmake-gcc-${env:APPVEYOR_REPO_BRANCH}-${env:APPVEYOR_BUILD_NUMBER}\
7z a ..\otvdm-cmake-gcc-${env:APPVEYOR_REPO_BRANCH}-${env:APPVEYOR_BUILD_NUMBER}.zip otvdm-cmake-gcc-${env:APPVEYOR_REPO_BRANCH}-${env:APPVEYOR_BUILD_NUMBER}
-
matrix:
only:
- THIS_BUILD_IS_RECOMMENDED__VCXPROJ_BUILD: 1
before_build:
ps: |
C:\msys64\usr\bin\as --version
echo "
C:\msys64\usr\bin\
`$(UniversalCRTSdkDir)Lib\10.0.17134.0\um\x86\
<_PropertySheetDisplayName>MacroPropertySheet
`$(SolutionDir)wow32;`$(IncludePath)
MultiThreadedDLL
__CI_VERSION=${env:APPVEYOR_BUILD_NUMBER};%(PreprocessorDefinitions)
TurnOffAllWarnings
`$(AsmPath)
`$(NtDllLibPath)
" > C:\projects\winevdm\PropertySheet.props
before_package:
ps: |
.\tools\package.ps1 -root .\ -src Release -dst otvdm-${env:APPVEYOR_REPO_BRANCH}-${env:APPVEYOR_BUILD_NUMBER} -objcopy "C:\msys64\usr\bin\objcopy.exe" -as "C:\msys64\usr\bin\as.exe"
7z a otvdm-${env:APPVEYOR_REPO_BRANCH}-${env:APPVEYOR_BUILD_NUMBER}.zip otvdm-${env:APPVEYOR_REPO_BRANCH}-${env:APPVEYOR_BUILD_NUMBER}
artifacts:
- path: '*.zip'
name: otvdm-Debug
================================================
FILE: avifile/CMakeLists.txt
================================================
file(GLOB SOURCE *.c *.cpp *.rc)
add_library(avifile SHARED ${SOURCE} ${CMAKE_SOURCE_DIR}/dummy.c ${CMAKE_CURRENT_BINARY_DIR}/avifile.def avifile.dll16.obj)
include_directories(../wine)
add_definitions(-D_X86_ -D__WINESRC__ -D__i386__ -DHAVE_STRNCASECMP -DHAVE__STRNICMP -D_WINTERNL_ -DNtCurrentTeb=NtCurrentTeb__ -DDECLSPEC_HIDDEN= -Dstrncasecmp=_strnicmp)
spec_build(avifile.dll16 avifile)
target_link_libraries(avifile libwine winecrt0 krnl386 avifil32.lib)
set_target_properties(avifile PROPERTIES SUFFIX ".dll16")
================================================
FILE: avifile/Makefile.in
================================================
MODULE = avifile.dll16
IMPORTS = avifil32
EXTRADLLFLAGS = -m16 -Wb,--main-module,avifil32.dll
================================================
FILE: avifile/avifile.def
================================================
; File generated automatically from avifile\avifile.dll16.spec; do not edit!
LIBRARY avifile.dll16
EXPORTS
_wine_spec_dos_header @1 DATA
================================================
FILE: avifile/avifile.dll16.spec
================================================
# I'm just using "long" instead of "ptr" for the interface pointers,
# because they are 32-bit pointers, not converted to 16-bit format,
# but the app doesn't really need to know, it should never need to
# dereference the interface pointer itself (if we're lucky)...
#1 stub WEP
2 stub DLLGETCLASSOBJECT
3 stub DLLCANUNLOADNOW
4 stub ___EXPORTEDSTUB
10 variable _IID_IAVIStream(0x00020021 0x00000000 0x000000c0 0x46000000)
11 variable _IID_IAVIFile(0x00020020 0x00000000 0x000000c0 0x46000000)
12 variable _IID_IAVIEditStream(0x00020024 0x00000000 0x000000c0 0x46000000)
13 variable _IID_IGetFrame(0x00020023 0x00000000 0x000000c0 0x46000000)
14 variable _CLSID_AVISimpleUnMarshal(0x00020009 0x00000000 0x000000c0 0x46000000)
100 pascal AVIFileInit() AVIFileInit
101 pascal AVIFileExit() AVIFileExit
102 pascal AVIFileOpen(ptr str word ptr) AVIFileOpenA
103 pascal AVIStreamOpenFromFile(ptr str long long word ptr) AVIStreamOpenFromFileA
104 pascal AVIStreamCreate(ptr long long ptr) AVIStreamCreate
105 stub AVIMAKECOMPRESSEDSTREAM
106 stub AVIMAKEFILEFROMSTREAMS
107 stub AVIMAKESTREAMFROMCLIPBOARD
110 pascal AVIStreamGetFrame(long long) AVIStreamGetFrame16
111 pascal AVIStreamGetFrameClose(long) AVIStreamGetFrameClose16
112 pascal AVIStreamGetFrameOpen(long ptr) AVIStreamGetFrameOpen16
120 stub _AVISAVE
121 stub AVISAVEV
122 stub AVISAVEOPTIONS
123 pascal AVIBuildFilter(str long word) AVIBuildFilterA
124 pascal AVISaveOptionsFree(word ptr) AVISaveOptionsFree
130 pascal AVIStreamStart(long) AVIStreamStart
131 pascal AVIStreamLength(long) AVIStreamLength
132 pascal AVIStreamTimeToSample(long long) AVIStreamTimeToSample
133 pascal AVIStreamSampleToTime(long long) AVIStreamSampleToTime
140 pascal AVIFileAddRef(long) AVIFileAddRef
141 pascal AVIFileRelease(long) AVIFileRelease
142 pascal AVIFileInfo(long ptr long) AVIFileInfoA
143 pascal AVIFileGetStream(long ptr long long) AVIFileGetStream
144 pascal AVIFileCreateStream(long ptr ptr) AVIFileCreateStream16
146 pascal AVIFileWriteData(long long ptr long) AVIFileWriteData
147 pascal AVIFileReadData(long long ptr ptr) AVIFileReadData
148 pascal AVIFileEndRecord(long) AVIFileEndRecord
160 pascal AVIStreamAddRef(long) AVIStreamAddRef
161 pascal AVIStreamRelease(long) AVIStreamRelease
162 pascal AVIStreamInfo(long ptr long) AVIStreamInfo16
163 pascal AVIStreamFindSample(long long long) AVIStreamFindSample
164 pascal AVIStreamReadFormat(long long ptr ptr) AVIStreamReadFormat
165 pascal AVIStreamReadData(long long ptr ptr) AVIStreamReadData
166 pascal AVIStreamWriteData(long long ptr long) AVIStreamWriteData
167 pascal AVIStreamRead(long long long ptr long ptr ptr) AVIStreamRead
168 pascal AVIStreamWrite(long long long ptr long long ptr ptr) AVIStreamWrite
169 pascal AVIStreamSetFormat(long long ptr long) AVIStreamSetFormat
180 stub EDITSTREAMCOPY
181 stub EDITSTREAMCUT
182 stub EDITSTREAMPASTE
184 stub CREATEEDITABLESTREAM
185 stub AVIPUTFILEONCLIPBOARD
187 stub AVIGETFROMCLIPBOARD
188 stub AVICLEARCLIPBOARD
190 stub EDITSTREAMCLONE
191 stub EDITSTREAMSETNAME
192 stub EDITSTREAMSETINFO
200 stub AVISTREAMBEGINSTREAMING
201 stub AVISTREAMENDSTREAMING
================================================
FILE: avifile/avifile.vcxproj
================================================
Debug
Win32
Release
Win32
Win32Proj
10.0.17134.0
avifile
{3825B17A-681F-48CF-B9AD-5337B1F521C8}
DynamicLibrary
true
v141
Unicode
DynamicLibrary
false
v141
true
Unicode
true
.dll16
false
Release
.dll16
Level3
Disabled
WIN32;_DEBUG;_WINDOWS;_USRDLL;_X86_;__WINESRC__;__i386__;USE_COMPILER_EXCEPTIONS;HAVE_STRNCASECMP;HAVE__STRNICMP;_WINTERNL_;NtCurrentTeb=NtCurrentTeb__;inline=__inline;%(PreprocessorDefinitions)
../wine
Windows
true
$(OutDir)winecrt0.lib;$(OutDir)libwine.lib;$(OutDir)krnl386.lib;
avifil32.lib
true
avifile.def
Level3
MaxSpeed
true
true
WIN32;NDEBUG;_WINDOWS;_USRDLL;_X86_;__WINESRC__;__i386__;USE_COMPILER_EXCEPTIONS;HAVE_STRNCASECMP;HAVE__STRNICMP;_WINTERNL_;NtCurrentTeb=NtCurrentTeb__;inline=__inline;DECLSPEC_HIDDEN=;%(PreprocessorDefinitions)
../wine
Windows
true
true
true
false
avifile.def
$(OutDir)winecrt0.lib;$(OutDir)libwine.lib;$(OutDir)krnl386.lib;
avifil32.lib
Document
"$(OutDir)convspec" "%(Filename).spec" AVIFILE > "%(Filename).asm" && "$(AsmPath)as" --32 -o "%(Filename).obj" "%(Filename).asm"
%(Filename).obj
================================================
FILE: avifile/main.c
================================================
/*
* Wrapper for 16 bit avifile functions
*
* Copyright 2016 Michael Müller
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "wine/winbase16.h"
#include "winternl.h"
#include "wingdi.h"
#include "vfw.h"
typedef struct _AVISTREAMINFO16 {
DWORD fccType;
DWORD fccHandler;
DWORD dwFlags;
DWORD dwCaps;
WORD wPriority;
WORD wLanguage;
DWORD dwScale;
DWORD dwRate;
DWORD dwStart;
DWORD dwLength;
DWORD dwInitialFrames;
DWORD dwSuggestedBufferSize;
DWORD dwQuality;
DWORD dwSampleSize;
RECT16 rcFrame;
DWORD dwEditCount;
DWORD dwFormatChangeCount;
CHAR szName[64];
} AVISTREAMINFO16, *LPAVISTREAMINFO16, *PAVISTREAMINFO16;
struct frame_wrapper16
{
PGETFRAME pg;
PVOID ptr;
DWORD size;
WORD sel;
WORD count;
};
static void free_segptr_frame(struct frame_wrapper16 *wrapper)
{
int i;
if (!wrapper->sel)
return;
for (i = 0; i < wrapper->count; i++)
FreeSelector16(wrapper->sel + (i << __AHSHIFT));
wrapper->sel = 0;
}
static SEGPTR alloc_segptr_frame(struct frame_wrapper16 *wrapper, void *ptr, DWORD size)
{
int i;
if (wrapper->sel)
{
if (wrapper->ptr == ptr && wrapper->size == size)
return MAKESEGPTR(wrapper->sel, 0);
free_segptr_frame(wrapper);
}
wrapper->ptr = ptr;
wrapper->size = size;
wrapper->count = (size + 0xffff) / 0x10000;
wrapper->sel = AllocSelectorArray16(wrapper->count);
if (!wrapper->sel)
return 0;
for (i = 0; i < wrapper->count; i++)
{
SetSelectorBase(wrapper->sel + (i << __AHSHIFT), (DWORD)ptr + i * 0x10000);
SetSelectorLimit16(wrapper->sel + (i << __AHSHIFT), size - 1);
size -= 0x10000;
}
return MAKESEGPTR(wrapper->sel, 0);
}
/***********************************************************************
* AVIStreamGetFrameOpen (AVIFILE.112)
*/
PGETFRAME WINAPI AVIStreamGetFrameOpen16(PAVISTREAM pstream, LPBITMAPINFOHEADER lpbiWanted)
{
struct frame_wrapper16 *wrapper;
PGETFRAME pg;
pg = AVIStreamGetFrameOpen(pstream, lpbiWanted);
if (!pg) return NULL;
wrapper = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wrapper));
if (!wrapper)
{
AVIStreamGetFrameClose(pg);
return NULL;
}
wrapper->pg = pg;
return (PGETFRAME)wrapper;
}
/***********************************************************************
* AVIStreamGetFrame (AVIFILE.110)
*/
SEGPTR WINAPI AVIStreamGetFrame16(PGETFRAME pg, LONG pos)
{
struct frame_wrapper16 *wrapper = (void *)pg;
BITMAPINFOHEADER *bih;
if (!pg) return 0;
bih = AVIStreamGetFrame(wrapper->pg, pos);
if (bih)
{
DWORD size = bih->biSize + bih->biSizeImage;
return alloc_segptr_frame(wrapper, bih, size);
}
return 0;
}
/***********************************************************************
* AVIStreamGetFrameClose (AVIFILE.111)
*/
HRESULT WINAPI AVIStreamGetFrameClose16(PGETFRAME pg)
{
struct frame_wrapper16 *wrapper = (void *)pg;
HRESULT hr;
if (!pg) return S_OK;
hr = AVIStreamGetFrameClose(wrapper->pg);
free_segptr_frame(wrapper);
HeapFree(GetProcessHeap(), 0, wrapper);
return hr;
}
/***********************************************************************
* AVIFileCreateStream (AVIFILE.144)
*/
HRESULT WINAPI AVIFileCreateStream16(PAVIFILE pfile, PAVISTREAM *ppavi, LPAVISTREAMINFO16 asi16)
{
AVISTREAMINFOA asi;
if (!asi16)
return AVIFileCreateStreamA(pfile, ppavi, NULL);
asi.fccType = asi16->fccType;
asi.fccHandler = asi16->fccHandler;
asi.dwFlags = asi16->dwFlags;
asi.dwCaps = asi16->dwCaps;
asi.wPriority = asi16->wPriority;
asi.wLanguage = asi16->wLanguage;
asi.dwScale = asi16->dwScale;
asi.dwRate = asi16->dwRate;
asi.dwStart = asi16->dwStart;
asi.dwLength = asi16->dwLength;
asi.dwInitialFrames = asi16->dwInitialFrames;
asi.dwSuggestedBufferSize = asi16->dwSuggestedBufferSize;
asi.dwQuality = asi16->dwQuality;
asi.dwSampleSize = asi16->dwSampleSize;
asi.rcFrame.left = asi16->rcFrame.left;
asi.rcFrame.top = asi16->rcFrame.top;
asi.rcFrame.right = asi16->rcFrame.right;
asi.rcFrame.bottom = asi16->rcFrame.bottom;
asi.dwEditCount = asi16->dwEditCount;
asi.dwFormatChangeCount = asi16->dwFormatChangeCount;
strcpy( asi.szName, asi16->szName );
return AVIFileCreateStreamA(pfile, ppavi, &asi);
}
/***********************************************************************
* AVIStreamInfo (AVIFILE.162)
*/
HRESULT WINAPI AVIStreamInfo16(PAVISTREAM pstream, LPAVISTREAMINFO16 asi16, LONG size)
{
AVISTREAMINFOA asi;
HRESULT hr;
if (!asi16)
return AVIStreamInfoA(pstream, NULL, size);
if (size < sizeof(AVISTREAMINFO16))
return AVIERR_BADSIZE;
hr = AVIStreamInfoA(pstream, &asi, sizeof(asi));
if (SUCCEEDED(hr))
{
asi16->fccType = asi.fccType;
asi16->fccHandler = asi.fccHandler;
asi16->dwFlags = asi.dwFlags;
asi16->dwCaps = asi.dwCaps;
asi16->wPriority = asi.wPriority;
asi16->wLanguage = asi.wLanguage;
asi16->dwScale = asi.dwScale;
asi16->dwRate = asi.dwRate;
asi16->dwStart = asi.dwStart;
asi16->dwLength = asi.dwLength;
asi16->dwInitialFrames = asi.dwInitialFrames;
asi16->dwSuggestedBufferSize = asi.dwSuggestedBufferSize;
asi16->dwQuality = asi.dwQuality;
asi16->dwSampleSize = asi.dwSampleSize;
asi16->rcFrame.left = asi.rcFrame.left;
asi16->rcFrame.top = asi.rcFrame.top;
asi16->rcFrame.right = asi.rcFrame.right;
asi16->rcFrame.bottom = asi.rcFrame.bottom;
asi16->dwEditCount = asi.dwEditCount;
asi16->dwFormatChangeCount = asi.dwFormatChangeCount;
strcpy( asi16->szName, asi.szName );
}
return hr;
}
================================================
FILE: comm/CMakeLists.txt
================================================
file(GLOB SOURCE *.c *.cpp *.rc)
add_library(comm SHARED ${SOURCE} ${PROJECT_SOURCE_DIR}/dummy.c ${CMAKE_CURRENT_BINARY_DIR}/comm.def comm.drv16.obj)
include_directories(../wine)
add_definitions(-D_X86_ -D__WINESRC__ -D__i386__ -DHAVE_STRNCASECMP -DHAVE__STRNICMP -D_WINTERNL_ -DNtCurrentTeb=NtCurrentTeb__ -DDECLSPEC_HIDDEN= -Dstrncasecmp=_strnicmp)
spec_build(comm.drv16 comm)
target_link_libraries(comm libwine winecrt0 krnl386)
set_target_properties(comm PROPERTIES SUFFIX ".drv16")
================================================
FILE: comm/Makefile.in
================================================
MODULE = comm.drv16
EXTRADLLFLAGS = -m16
================================================
FILE: comm/comm.def
================================================
; File generated automatically from comm\comm.drv16.spec; do not edit!
LIBRARY comm.drv16
EXPORTS
_wine_spec_dos_header; @1 DATA PRIVATE
================================================
FILE: comm/comm.drv16.spec
================================================
1 stub INICOM
2 stub SETCOM
3 stub SETQUE
4 stub RECCOM
5 stub SNDCOM
6 stub CTX
7 stub TRMCOM
8 stub STACOM
9 stub CEXTFCN
10 stub CFLUSH
11 stub CEVT
12 stub CEVTGET
13 stub CSETBRK
14 stub CCLRBRK
15 stub GETDCB
#16 stub WEP
17 stub SUSPENDOPENCOMMPORTS # win3.1
18 stub REACTIVATEOPENCOMMPORTS # win3.1
19 stub COMMWRITESTRING
20 stub READCOMMSTRING
100 stub ENABLENOTIFICATION
101 stub ordinal_only__win31
================================================
FILE: comm/comm.vcxproj
================================================
Debug
Win32
Release
Win32
Win32Proj
comm
{3D889B37-09C8-4030-B815-830566CD57A3}
10.0.17134.0
DynamicLibrary
true
v141
Unicode
DynamicLibrary
false
v141
true
Unicode
true
.drv16
false
Release
.drv16
Level3
Disabled
WIN32;_DEBUG;_WINDOWS;_USRDLL;_X86_;__WINESRC__;__i386__;USE_COMPILER_EXCEPTIONS;HAVE_STRNCASECMP;HAVE__STRNICMP;_WINTERNL_;NtCurrentTeb=NtCurrentTeb__;inline=__inline;%(PreprocessorDefinitions)
../wine
Windows
true
$(OutDir)winecrt0.lib;$(OutDir)libwine.lib;$(OutDir)krnl386.lib;
true
comm.def
Level3
MaxSpeed
true
true
WIN32;NDEBUG;_WINDOWS;_USRDLL;_X86_;__WINESRC__;__i386__;USE_COMPILER_EXCEPTIONS;HAVE_STRNCASECMP;HAVE__STRNICMP;_WINTERNL_;NtCurrentTeb=NtCurrentTeb__;inline=__inline;DECLSPEC_HIDDEN=;%(PreprocessorDefinitions)
../wine
Windows
true
true
true
false
comm.def
$(OutDir)winecrt0.lib;$(OutDir)libwine.lib;$(OutDir)krnl386.lib;
Document
"$(OutDir)convspec" "%(Filename).spec" COMM > "%(Filename).asm" && "$(AsmPath)as" --32 -o "%(Filename).obj" "%(Filename).asm"
%(Filename).obj
"$(OutDir)convspec" "%(Filename).spec" COMM > "%(Filename).asm" && "$(AsmPath)as" --32 -o "%(Filename).obj" "%(Filename).asm"
%(Filename).obj
================================================
FILE: commctrl/CMakeLists.txt
================================================
file(GLOB SOURCE *.c *.cpp *.rc)
add_library(commctrl SHARED ${SOURCE} ${CMAKE_CURRENT_BINARY_DIR}/commctrl.def commctrl.dll16.obj)
include_directories(../wine)
add_definitions(-D_X86_ -D__WINESRC__ -D__i386__ -DHAVE_STRNCASECMP -DHAVE__STRNICMP -D_WINTERNL_ -DNtCurrentTeb=NtCurrentTeb__ -DDECLSPEC_HIDDEN= -Dstrncasecmp=_strnicmp)
spec_build(commctrl.dll16 commctrl)
target_link_libraries(commctrl libwine winecrt0 krnl386 user comctl32.lib)
set_target_properties(commctrl PROPERTIES SUFFIX ".dll16")
================================================
FILE: commctrl/commctrl.c
================================================
#include
#include
#include "wine/windef16.h"
#include "wine/winbase16.h"
#include "wine/winuser16.h"
#include "wine/debug.h"
#include
WINE_DEFAULT_DEBUG_CHANNEL(commctrl);
/* FIXME: CreateWindow("ToolbarWindow") fail */
#include
typedef struct {
INT16 iBitmap;
INT16 idCommand;
BYTE fsState;
BYTE fsStyle;
INT16 idsHelp; /* ? */
} TBBUTTON16, NEAR* PTBBUTTON16, *LPTBBUTTON16;
typedef struct {
SEGPTR ini_section;
SEGPTR ini_file;
} TBSAVEPARAMS16, *LPTBSAVEPARAMS16;
#include
#define TOOLBARCLASSNAME16 "ToolbarWindow"
#define STATUSCLASSNAME16 "msctls_statusbar"
HINSTANCE16 hInstance16;
WNDCLASSEXA toolbar_window_class = { sizeof(WNDCLASSEXA) };
WNDCLASSEXA status_window_class = { sizeof(WNDCLASSEXA) };
LRESULT WINAPI ToolbarWindowProc16(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
LRESULT WINAPI StatusWindowProc16(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
void WINAPI InitCommonControls16(void)
{
static BOOL init;
if (init)
return;
init = TRUE;
InitCommonControls();
if (GetClassInfoExA(NULL, TOOLBARCLASSNAMEA, &toolbar_window_class))
{
WNDCLASSEXA cls16 = toolbar_window_class;
cls16.hInstance = hInstance16 = LoadLibrary16("COMMCTRL");
cls16.lpszClassName = TOOLBARCLASSNAME16;
cls16.lpfnWndProc = ToolbarWindowProc16;
if (!RegisterClassExA(&cls16))
{
ERR("\n");
}
}
if (GetClassInfoExA(NULL, STATUSCLASSNAMEA, &status_window_class))
{
WNDCLASSEXA cls16 = status_window_class;
cls16.hInstance = hInstance16;
cls16.lpszClassName = STATUSCLASSNAME16;
cls16.lpfnWndProc = StatusWindowProc16;
if (!RegisterClassExA(&cls16))
{
ERR("\n");
}
}
}
LRESULT WINAPI StatusWindowProc16(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case SB_GETTEXTA:
case SB_SETTEXTA:
{
LPCSTR str = (LPCSTR)MapSL(lParam);
if (!HIWORD(str))
{
str = (LPCSTR)lParam;
}
return CallWindowProcA(status_window_class.lpfnWndProc, hwnd, msg, wParam, (LPARAM)str);
}
case SB_GETPARTS:
case SB_SETPARTS:
{
LPINT16 ary = (LPINT16)MapSL(lParam);
LRESULT result;
INT ary32[256];
if (wParam > 256)
return FALSE;
if (!HIWORD(ary))
{
break;
}
for (int i = 0; i < wParam; i++)
{
ary32[i] = ary[i];
}
result = CallWindowProcA(status_window_class.lpfnWndProc, hwnd, msg, wParam, (LPARAM)&ary32);
for (int i = 0; i < wParam; i++)
{
ary[i] = ary32[i];
}
return result;
}
case SB_GETBORDERS:
{
INT borders32[3];
INT16 *borders = MapSL(lParam);
LRESULT result;
int i;
if (!HIWORD(borders))
break;
result = CallWindowProcA(status_window_class.lpfnWndProc, hwnd, msg, wParam, (LPARAM)&borders32);
for (i = 0; i < 3; i++)
borders[i] = borders32[i];
return result;
}
}
return CallWindowProcA(status_window_class.lpfnWndProc, hwnd, msg, wParam, lParam);
}
void TBBUTTON16_32(LPTBBUTTON btn32, LPTBBUTTON16 lpButtons)
{
btn32->iBitmap = lpButtons->iBitmap;
btn32->idCommand = lpButtons->idCommand;
btn32->fsState = lpButtons->fsState;
btn32->fsStyle = lpButtons->fsStyle;
btn32->dwData = lpButtons->idsHelp;
btn32->iString = 0;
}
void TBBUTTON32_16(LPTBBUTTON btn32, LPTBBUTTON16 lpButtons)
{
lpButtons->iBitmap = btn32->iBitmap;
lpButtons->idCommand = btn32->idCommand;
lpButtons->fsState = btn32->fsState;
lpButtons->fsStyle = btn32->fsStyle;
lpButtons->idsHelp = btn32->dwData;
}
LRESULT WINAPI ToolbarWindowProc16(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
LRESULT result;
switch (msg)
{
case TB_BUTTONSTRUCTSIZE:
{
SetPropW(hwnd, L"TB_BUTTONSTRUCTSIZE", wParam);
wParam = sizeof(TBBUTTON);
break;
}
break;
case TB_ADDBITMAP:
{
HINSTANCE16 hInst16 = LOWORD(lParam);
WORD nID16 = HIWORD(lParam);
TBADDBITMAP tb32 = { 0 };
if (!hInst16)
{
tb32.nID = HBITMAP_32(nID16);
}
else
{
tb32.nID = HBITMAP_32(LoadBitmap16(hInst16, (LPCSTR)nID16));
}
lParam = &tb32;
return CallWindowProcA(toolbar_window_class.lpfnWndProc, hwnd, msg, wParam, lParam);
}
case TB_ADDBUTTONSA:
{
LPTBBUTTON16 btn = (LPTBBUTTON16)MapSL(lParam);
LPTBBUTTON btn32;
SIZE_T button_struct_size;
if (!HIWORD(btn))
break;
button_struct_size = GetPropW(hwnd, L"TB_BUTTONSTRUCTSIZE");
btn32 = HeapAlloc(GetProcessHeap(), 0, sizeof(TBBUTTON) * wParam);
for (int i = 0; i < wParam; i++)
{
TBBUTTON16_32(btn32 + i, (LPTBBUTTON16)((LPBYTE)btn + button_struct_size * i));
}
result = CallWindowProcA(toolbar_window_class.lpfnWndProc, hwnd, msg, wParam, (LPARAM)btn32);
HeapFree(GetProcessHeap(), 0, btn32);
return result;
}
case TB_SAVERESTOREA:
{
LPTBSAVEPARAMS16 sp = (LPTBSAVEPARAMS16)MapSL(lParam);
TBSAVEPARAMSA sp32 = { 0 };
if (!HIWORD(sp))
break;
if (!wParam)
{
sp32.hkr = NULL;
sp32.pszSubKey = (LPCSTR)MapSL(sp->ini_section);
sp32.pszValueName = (LPCSTR)MapSL(sp->ini_file);
}
/* ini file?? */
FIXME("TB_SAVERESTORE\n");
result = 0;
/* result = CallWindowProcA(toolbar_window_class.lpfnWndProc, hwnd, msg, wParam, (LPARAM)&sp32); */
if (wParam)
{
sp->ini_section = MapLS(sp32.pszSubKey);
sp->ini_file = MapLS(sp32.pszValueName);
}
return result;
}
case TB_INSERTBUTTONA:
{
TBBUTTON btn;
TBBUTTON16_32(&btn, (LPTBBUTTON16)MapSL(lParam));
result = CallWindowProcA(toolbar_window_class.lpfnWndProc, hwnd, msg, wParam, (LPARAM)&btn);
return result;
}
case TB_GETBUTTON:
{
TBBUTTON btn;
result = CallWindowProcA(toolbar_window_class.lpfnWndProc, hwnd, msg, wParam, (LPARAM)&btn);
TBBUTTON32_16(&btn, (LPTBBUTTON16)MapSL(lParam));
return result;
}
case TB_GETBUTTONTEXTA:
return CallWindowProcA(toolbar_window_class.lpfnWndProc, hwnd, msg, wParam, (LPARAM)MapSL(lParam));
default:
break;
}
return CallWindowProcA(toolbar_window_class.lpfnWndProc, hwnd, msg, wParam, lParam);
}
/* based on wine */
HWND16 WINAPI CreateToolbarEx16(HWND16 hwnd, DWORD style /* window style */, UINT16 wID /* control id */, INT16 nBitmaps,
HINSTANCE16 hBMInst, WORD wBMID /* bitmap resource id or bitmap handle(hBMInst == NULL) */, LPTBBUTTON16 lpButtons,
INT16 iNumButtons, INT16 dxButton, INT16 dyButton,
INT16 dxBitmap, INT16 dyBitmap, UINT16 uStructSize)
{
TBBUTTON buttons32 = { 0 };
HWND hwndTB;
HBITMAP bitmap32 = NULL;
InitCommonControls16();
hwndTB =
CreateWindowExA(0, TOOLBARCLASSNAME16, NULL, style|WS_CHILD, 0,0,100,30,
HWND_32(hwnd), (HMENU)(DWORD_PTR)wID, hInstance16, NULL);
if(hwndTB) {
SendMessageA (hwndTB, TB_BUTTONSTRUCTSIZE, uStructSize, 0);
/* set bitmap and button size */
/*If CreateToolbarEx receives 0, windows sets default values*/
if (dxBitmap < 0)
dxBitmap = 16;
if (dyBitmap < 0)
dyBitmap = 16;
if (dxBitmap == 0 || dyBitmap == 0)
dxBitmap = dyBitmap = 16;
SendMessageA(hwndTB, TB_SETBITMAPSIZE, 0, MAKELPARAM(dxBitmap, dyBitmap));
if (dxButton < 0)
dxButton = dxBitmap;
if (dyButton < 0)
dyButton = dyBitmap;
/* TB_SETBUTTONSIZE -> TB_SETBITMAPSIZE bug introduced for Windows compatibility */
if (dxButton != 0 && dyButton != 0)
SendMessageA(hwndTB, TB_SETBITMAPSIZE, 0, MAKELPARAM(dxButton, dyButton));
/* add bitmaps */
if (nBitmaps > 0 || hBMInst == HINST_COMMCTRL)
{
SendMessageA (hwndTB, TB_ADDBITMAP, nBitmaps, MAKELONG(hBMInst, wBMID));
}
/* add buttons */
if(iNumButtons > 0)
SendMessageA (hwndTB, TB_ADDBUTTONSA, iNumButtons, (LPARAM)MapLS(lpButtons));
}
return HWND_16(hwndTB);
}
HWND16 WINAPI CreateStatusWindow16(LONG style, LPCSTR text, HWND16 hwndParent, UINT16 wid)
{
HWND parent = HWND_32(hwndParent);
return HWND_16(CreateWindowA(STATUSCLASSNAME16, text, style,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
parent, (HMENU)(DWORD_PTR)wid, 0, 0));
}
LPRECT RECT16_32(LPRECT rect32, LPRECT16 lprc)
{
if (!lprc)
return NULL;
rect32->left = lprc->left;
rect32->right = lprc->right;
rect32->top = lprc->top;
rect32->bottom = lprc->bottom;
return rect32;
}
LPRECT16 RECT32_16(LPRECT rect32, LPRECT16 lprc)
{
if (!lprc)
return NULL;
lprc->left = rect32->left;
lprc->right = rect32->right;
lprc->top = rect32->top;
lprc->bottom = rect32->bottom;
return lprc;
}
void WINAPI GetEffectiveClientRect16(HWND16 hWnd, LPRECT16 lprc, const INT16 *lpInfo)
{
HWND hWnd32 = HWND_32(hWnd);
RECT rect32;
SIZE_T len = 0;
LPINT info32;
const INT16 *lpRun = lpInfo;
do
{
lpRun += 2;
if (*lpRun == 0)
break;
lpRun += 2;
} while (*lpRun);
len = (lpRun - lpInfo) + 1;
info32 = (LPINT)HeapAlloc(GetProcessHeap(), 0, len * sizeof(INT));
for (int i = 0; i < len; i++)
{
info32[i] = lpInfo[i];
}
GetEffectiveClientRect(hWnd32, RECT16_32(&rect32, lprc), info32);
RECT32_16(&rect32, lprc);
HeapFree(GetProcessHeap(), 0, info32);
}
static int find_sub_menu( HMENU *hmenu, HMENU16 target )
{
int i, pos, count = GetMenuItemCount( *hmenu );
for (i = 0; i < count; i++)
{
HMENU sub = GetSubMenu( *hmenu, i );
if (!sub) continue;
if (HMENU_16(sub) == target) return i;
if ((pos = find_sub_menu( &sub, target )) != -1)
{
*hmenu = sub;
return pos;
}
}
return -1;
}
#include
typedef struct
{
WORD command_id_off;
WORD menu_id_off;
struct
{
WORD popup_id;
HMENU16 hPopup;
} popup_ids[1];
} MENUHELP16;
#include
static int get_menu_off(HMENU hMainMenu, HMENU hSubMenu)
{
int i = 0;
int count = GetMenuItemCount(hMainMenu);
for (i = 0; i < count; i++)
{
HMENU s = GetSubMenu(hMainMenu, i);
if (s == hSubMenu)
{
return i;
}
}
return -1;
}
/* based on wine */
VOID WINAPI
MenuHelp16 (UINT16 uMsg, WPARAM16 wParam, LPARAM lParam, HMENU16 hMainMenu, HINSTANCE16 hInst, HWND16 hwndStatus, MENUHELP16 *lpwIDs)
{
UINT uMenuID = 0;
WORD wIDItem = wParam;
WORD fwMenu = LOWORD(lParam);
HMENU hMenu = HMENU_32(HIWORD(lParam));
if (!IsWindow (HWND_32(hwndStatus)))
return;
switch (uMsg) {
case WM_MENUSELECT:
TRACE("WM_MENUSELECT wParam=0x%lX lParam=0x%lX\n",
wParam, lParam);
if ((fwMenu == 0xFFFF) && (hMenu == 0)) {
/* menu was closed */
TRACE("menu was closed!\n");
SendMessageA (HWND_32(hwndStatus), SB_SIMPLE, FALSE, 0);
}
else {
/* menu item was selected */
if (fwMenu & MF_POPUP)
{
if (!uMenuID)
{
int i = 0;
HMENU hMainMenu32 = HMENU_32(hMainMenu);
HMENU hSubMenu = HMENU_32(wParam);
int off = get_menu_off(hMainMenu32, hSubMenu);
if (off != -1)
{
uMenuID = off + lpwIDs->menu_id_off;
}
else
{
while (TRUE)
{
if (lpwIDs->popup_ids[i].hPopup == 0 && lpwIDs->popup_ids[i].popup_id == 0)
break;
if (lpwIDs->popup_ids[i].hPopup == wIDItem)
{
uMenuID = lpwIDs->popup_ids[i].popup_id;
break;
}
i++;
}
}
}
}
else
uMenuID = lpwIDs->command_id_off + (UINT)wIDItem;
TRACE("uMenuID = %u\n", uMenuID);
if (uMenuID) {
CHAR szText[256];
if (!LoadString16 (hInst, uMenuID, szText, ARRAYSIZE(szText)))
szText[0] = '\0';
SendMessageA (HWND_32(hwndStatus), SB_SETTEXTA,
255 | SBT_NOBORDERS, (LPARAM)szText);
SendMessageA (HWND_32(hwndStatus), SB_SIMPLE, TRUE, 0);
}
}
break;
case WM_COMMAND :
TRACE("WM_COMMAND wParam=0x%lX lParam=0x%lX\n",
wParam, lParam);
/* WM_COMMAND is not invalid since it is documented
* in the windows api reference. So don't output
* any FIXME for WM_COMMAND
*/
WARN("We don't care about the WM_COMMAND\n");
break;
default:
FIXME("Invalid Message 0x%x!\n", uMsg);
break;
}
}
HBITMAP16 WINAPI CreateMappedBitmap16(HINSTANCE16 hInstance, INT16 idBitmap, UINT16 wFlags, LPCOLORMAP lpColorMap, INT16 iNumMaps)
{
/* wine */
HGLOBAL16 hglb;
HRSRC16 hRsrc;
const BITMAPINFOHEADER *lpBitmap;
LPBITMAPINFOHEADER lpBitmapInfo;
UINT nSize, nColorTableSize, iColor;
RGBQUAD *pColorTable;
INT i, iMaps, nWidth, nHeight;
HDC hdcScreen;
HBITMAP hbm;
LPCOLORMAP sysColorMap;
COLORREF cRef;
COLORMAP internalColorMap[4] =
{{0x000000, 0}, {0x808080, 0}, {0xC0C0C0, 0}, {0xFFFFFF, 0}};
/* initialize pointer to colortable and default color table */
if (lpColorMap) {
iMaps = iNumMaps;
sysColorMap = lpColorMap;
}
else {
internalColorMap[0].to = GetSysColor (COLOR_BTNTEXT);
internalColorMap[1].to = GetSysColor (COLOR_BTNSHADOW);
internalColorMap[2].to = GetSysColor (COLOR_BTNFACE);
internalColorMap[3].to = GetSysColor (COLOR_BTNHIGHLIGHT);
iMaps = 4;
sysColorMap = internalColorMap;
}
hRsrc = FindResource16 (hInstance, (LPSTR)idBitmap, (LPSTR)RT_BITMAP);
if (hRsrc == 0)
return 0;
hglb = LoadResource16 (hInstance, hRsrc);
if (hglb == 0)
return 0;
lpBitmap = LockResource16 (hglb);
if (lpBitmap == NULL)
return 0;
if (lpBitmap->biSize >= sizeof(BITMAPINFOHEADER) && lpBitmap->biClrUsed)
nColorTableSize = lpBitmap->biClrUsed;
else if (lpBitmap->biBitCount <= 8)
nColorTableSize = (1 << lpBitmap->biBitCount);
else
nColorTableSize = 0;
nSize = lpBitmap->biSize;
if (nSize == sizeof(BITMAPINFOHEADER) && lpBitmap->biCompression == BI_BITFIELDS)
nSize += 3 * sizeof(DWORD);
nSize += nColorTableSize * sizeof(RGBQUAD);
lpBitmapInfo = GlobalAlloc (GMEM_FIXED, nSize);
if (lpBitmapInfo == NULL)
return 0;
RtlMoveMemory (lpBitmapInfo, lpBitmap, nSize);
pColorTable = (RGBQUAD*)(((LPBYTE)lpBitmapInfo) + lpBitmapInfo->biSize);
for (iColor = 0; iColor < nColorTableSize; iColor++) {
for (i = 0; i < iMaps; i++) {
cRef = RGB(pColorTable[iColor].rgbRed,
pColorTable[iColor].rgbGreen,
pColorTable[iColor].rgbBlue);
if ( cRef == sysColorMap[i].from) {
#if 0
if (wFlags & CBS_MASKED) {
if (sysColorMap[i].to != COLOR_BTNTEXT)
pColorTable[iColor] = RGB(255, 255, 255);
}
else
#endif
pColorTable[iColor].rgbBlue = GetBValue(sysColorMap[i].to);
pColorTable[iColor].rgbGreen = GetGValue(sysColorMap[i].to);
pColorTable[iColor].rgbRed = GetRValue(sysColorMap[i].to);
break;
}
}
}
nWidth = lpBitmapInfo->biWidth;
nHeight = lpBitmapInfo->biHeight;
hdcScreen = GetDC (NULL);
hbm = CreateCompatibleBitmap (hdcScreen, nWidth, nHeight);
if (hbm) {
HDC hdcDst = CreateCompatibleDC (hdcScreen);
HBITMAP hbmOld = SelectObject (hdcDst, hbm);
const BYTE *lpBits = (const BYTE *)lpBitmap + nSize;
StretchDIBits (hdcDst, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight,
lpBits, (LPBITMAPINFO)lpBitmapInfo, DIB_RGB_COLORS,
SRCCOPY);
SelectObject (hdcDst, hbmOld);
DeleteDC (hdcDst);
}
ReleaseDC (NULL, hdcScreen);
GlobalFree (lpBitmapInfo);
FreeResource16 (hglb);
return HBITMAP_16(hbm);
}
HWND16 WINAPI CreateToolbar16(HWND16 hwnd, DWORD style, UINT16 wID, INT16 nBitmaps, HINSTANCE16 hBMInst, UINT16 wBMID, LPTBBUTTON16 lpButtons, INT16 iNumButtons)
{
return CreateToolbarEx16(hwnd, style | CCS_NODIVIDER, wID, nBitmaps,
hBMInst, wBMID, lpButtons,
iNumButtons, 0, 0, 0, 0, sizeof(TBBUTTON16));
}
BOOL16 WINAPI MakeDragList16(HWND16 hLB)
{
return MakeDragList(HWND_32(hLB));
}
HWND16 WINAPI CreateHeaderWindow16(LONG a1, LPSTR a2, HWND16 a3, WORD a4)
{
FIXME("(%08x,%s,%04x,%04x)\n", a1, debugstr_a(a2), a3, a4);
return 0;
}
================================================
FILE: commctrl/commctrl.def
================================================
; File generated automatically from commctrl\commctrl.dll16.spec; do not edit!
LIBRARY commctrl.dll16
EXPORTS
_wine_spec_dos_header @1 DATA
================================================
FILE: commctrl/commctrl.dll16.spec
================================================
16 stub CREATEUPDOWNCONTROL
44 stub IMAGELIST_SETBKCOLOR
339 stub DPA_SEARCH
332 stub DPA_GETPTR
336 stub DPA_DELETEPTR
329 stub DPA_DESTROY
334 stub DPA_INSERTPTR
13 pascal -ret16 MakeDragList(word) MakeDragList16
15 stub DRAWINSERT
335 stub DPA_SETPTR
20 pascal -ret16 CreateToolbarEx(word long word word word word ptr word word word word word word) CreateToolbarEx16
328 stub DPA_CREATE
4 pascal -ret16 GetEffectiveClientRect(word ptr ptr) GetEffectiveClientRect16
45 stub IMAGELIST_GETBKCOLOR
42 stub IMAGELIST_GETIMAGECOUNT
333 stub DPA_GETPTRINDEX
40 stub IMAGELIST_CREATE
2 pascal -ret16 MenuHelp(word word long word word word ptr) MenuHelp16
49 stub IMAGELIST_DRAW
43 stub IMAGELIST_SETOVERLAYIMAGE
160 stub CREATEPROPERTYSHEETPAGE
5 stub DRAWSTATUSTEXT
338 stub DPA_SORT
8 pascal -ret16 CreateMappedBitmap(word word word ptr word) CreateMappedBitmap16
3 stub SHOWHIDEMENUCTL
161 stub DESTROYPROPERTYSHEETPAGE
41 stub IMAGELIST_DESTROY
17 pascal -ret16 InitCommonControls() InitCommonControls16
14 stub LBITEMFROMPT
6 pascal -ret16 CreateStatusWindow(long str word word) CreateStatusWindow16
159 stub PROPERTYSHEET
7 pascal -ret16 CreateToolbar(word long word word word word ptr word) CreateToolbar16
331 stub DPA_CLONE
54 stub IMAGELIST_REPLACEICON
337 stub DPA_DELETEALLPTRS
330 stub DPA_GROW
46 stub IMAGELIST_ADD
53 stub IMAGELIST_ADDICON
9 pascal -ret16 CreateHeaderWindow(long str word word) CreateHeaderWindow16
10 pascal -ret16 WritePrivateProfileStruct(str str ptr word str) WritePrivateProfileStruct16
11 pascal -ret16 GetPrivateProfileStruct(str str ptr word str) GetPrivateProfileStruct16
================================================
FILE: commctrl/commctrl.vcxproj
================================================
Debug
Win32
Release
Win32
Win32Proj
10.0.17134.0
commctrl
{CB9C6113-15AB-4DB9-A323-C2094A9A6E92}
DynamicLibrary
true
v141
Unicode
DynamicLibrary
false
v141
true
Unicode
true
.dll16
false
Release
.dll16
Level3
Disabled
WIN32;_DEBUG;_WINDOWS;_USRDLL;_X86_;__WINESRC__;__i386__;USE_COMPILER_EXCEPTIONS;HAVE_STRNCASECMP;HAVE__STRNICMP;_WINTERNL_;NtCurrentTeb=NtCurrentTeb__;inline=__inline;%(PreprocessorDefinitions)
../wine
Windows
true
$(OutDir)winecrt0.lib;$(OutDir)libwine.lib;$(OutDir)krnl386.lib;
$(OutDir)user.lib;comctl32.lib;user32.lib;gdi32.lib
true
commctrl.def
Level3
MaxSpeed
true
true
WIN32;NDEBUG;_WINDOWS;_USRDLL;_X86_;__WINESRC__;__i386__;USE_COMPILER_EXCEPTIONS;HAVE_STRNCASECMP;HAVE__STRNICMP;_WINTERNL_;NtCurrentTeb=NtCurrentTeb__;inline=__inline;DECLSPEC_HIDDEN=;%(PreprocessorDefinitions)
../wine
Windows
true
true
true
false
commctrl.def
$(OutDir)winecrt0.lib;$(OutDir)libwine.lib;$(OutDir)krnl386.lib;
$(OutDir)user.lib;comctl32.lib;user32.lib;gdi32.lib
Document
"$(OutDir)convspec" "%(Filename).spec" COMMCTRL > "%(Filename).asm" && "$(AsmPath)as" --32 -o "%(Filename).obj" "%(Filename).asm"
%(Filename).obj
================================================
FILE: commdlg/CMakeLists.txt
================================================
file(GLOB SOURCE *.c *.cpp *.rc)
add_library(commdlg SHARED ${SOURCE} ${CMAKE_CURRENT_BINARY_DIR}/commdlg.def commdlg.dll16.obj)
include_directories(../wine)
add_definitions(-D_X86_ -D__WINESRC__ -D__i386__ -DHAVE_STRNCASECMP -DHAVE__STRNICMP -D_WINTERNL_ -DNtCurrentTeb=NtCurrentTeb__ -DDECLSPEC_HIDDEN= -Dstrncasecmp=_strnicmp)
spec_build(commdlg.dll16 commdlg)
target_link_libraries(commdlg libwine winecrt0 krnl386 user comdlg32.lib)
set_target_properties(commdlg PROPERTIES SUFFIX ".dll16")
================================================
FILE: commdlg/cdlg16.h
================================================
/*
* Common Dialog Boxes interface (16 bit implementation)
*
* Copyright 1994 Martin Ayotte
* Copyright 1996 Albrecht Kleine
* Copyright 1998 Bertho A. Stultiens
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef _WINE_DLL_CDLG16_H
#define _WINE_DLL_CDLG16_H
#include "dlgs.h"
#include "wine/windef16.h"
#include "wine/winbase16.h"
#include "wine/winuser16.h"
#include "wownt32.h"
/* 16 bit api */
#include "pshpack1.h"
typedef UINT16 (CALLBACK *LPOFNHOOKPROC16)(HWND16,UINT16,WPARAM16,LPARAM);
typedef struct {
DWORD lStructSize;
HWND16 hwndOwner;
HINSTANCE16 hInstance;
SEGPTR lpstrFilter;
SEGPTR lpstrCustomFilter;
DWORD nMaxCustFilter;
DWORD nFilterIndex;
SEGPTR lpstrFile;
DWORD nMaxFile;
SEGPTR lpstrFileTitle;
DWORD nMaxFileTitle;
SEGPTR lpstrInitialDir;
SEGPTR lpstrTitle;
DWORD Flags;
UINT16 nFileOffset;
UINT16 nFileExtension;
SEGPTR lpstrDefExt;
LPARAM lCustData;
LPOFNHOOKPROC16 lpfnHook;
SEGPTR lpTemplateName;
} OPENFILENAME16,*LPOPENFILENAME16;
typedef UINT16 (CALLBACK *LPCCHOOKPROC16) (HWND16, UINT16, WPARAM16, LPARAM);
typedef struct {
DWORD lStructSize;
HWND16 hwndOwner;
HWND16 hInstance;
COLORREF rgbResult;
SEGPTR lpCustColors;
DWORD Flags;
LPARAM lCustData;
LPCCHOOKPROC16 lpfnHook;
SEGPTR lpTemplateName;
} CHOOSECOLOR16;
typedef CHOOSECOLOR16 *LPCHOOSECOLOR16;
typedef UINT16 (CALLBACK *LPFRHOOKPROC16)(HWND16,UINT16,WPARAM16,LPARAM);
typedef struct {
DWORD lStructSize; /* size of this struct 0x20 */
HWND16 hwndOwner; /* handle to owner's window */
HINSTANCE16 hInstance; /* instance handle of.EXE that */
/* contains cust. dlg. template */
DWORD Flags; /* one or more of the FR_?? */
SEGPTR lpstrFindWhat; /* ptr. to search string */
SEGPTR lpstrReplaceWith; /* ptr. to replace string */
UINT16 wFindWhatLen; /* size of find buffer */
UINT16 wReplaceWithLen; /* size of replace buffer */
LPARAM lCustData; /* data passed to hook fn. */
LPFRHOOKPROC16 lpfnHook;
SEGPTR lpTemplateName; /* custom template name */
} FINDREPLACE16, *LPFINDREPLACE16;
typedef UINT16 (CALLBACK *LPCFHOOKPROC16)(HWND16,UINT16,WPARAM16,LPARAM);
typedef struct
{
DWORD lStructSize;
HWND16 hwndOwner; /* caller's window handle */
HDC16 hDC; /* printer DC/IC or NULL */
SEGPTR lpLogFont; /* ptr. to a LOGFONT struct */
short iPointSize; /* 10 * size in points of selected font */
DWORD Flags; /* enum. type flags */
COLORREF rgbColors; /* returned text color */
LPARAM lCustData; /* data passed to hook fn. */
LPCFHOOKPROC16 lpfnHook;
SEGPTR lpTemplateName; /* custom template name */
HINSTANCE16 hInstance; /* instance handle of.EXE that */
/* contains cust. dlg. template */
SEGPTR lpszStyle; /* return the style field here */
/* must be LF_FACESIZE or bigger */
UINT16 nFontType; /* same value reported to the */
/* EnumFonts callback with the */
/* extra FONTTYPE_ bits added */
short nSizeMin; /* minimum pt size allowed & */
short nSizeMax; /* max pt size allowed if */
/* CF_LIMITSIZE is used */
} CHOOSEFONT16, *LPCHOOSEFONT16;
typedef UINT16 (CALLBACK *LPPRINTHOOKPROC16) (HWND16, UINT16, WPARAM16, LPARAM);
typedef UINT16 (CALLBACK *LPSETUPHOOKPROC16) (HWND16, UINT16, WPARAM16, LPARAM);
typedef struct
{
DWORD lStructSize;
HWND16 hwndOwner;
HGLOBAL16 hDevMode;
HGLOBAL16 hDevNames;
HDC16 hDC;
DWORD Flags;
WORD nFromPage;
WORD nToPage;
WORD nMinPage;
WORD nMaxPage;
WORD nCopies;
HINSTANCE16 hInstance;
LPARAM lCustData;
LPPRINTHOOKPROC16 lpfnPrintHook;
LPSETUPHOOKPROC16 lpfnSetupHook;
SEGPTR lpPrintTemplateName;
SEGPTR lpSetupTemplateName;
HGLOBAL16 hPrintTemplate;
HGLOBAL16 hSetupTemplate;
} PRINTDLG16, *LPPRINTDLG16;
BOOL16 WINAPI ChooseColor16(LPCHOOSECOLOR16 lpChCol);
HWND16 WINAPI FindText16( SEGPTR find);
BOOL16 WINAPI GetOpenFileName16(SEGPTR ofn);
BOOL16 WINAPI GetSaveFileName16(SEGPTR ofn);
BOOL16 WINAPI PrintDlg16( SEGPTR print);
HWND16 WINAPI ReplaceText16( SEGPTR find);
BOOL16 WINAPI ChooseFont16(SEGPTR);
BOOL16 CALLBACK ColorDlgProc16( HWND16 hDlg16, UINT16 message, WPARAM16 wParam, LPARAM lParam );
BOOL16 CALLBACK FileSaveDlgProc16(HWND16 hWnd16, UINT16 wMsg, WPARAM16 wParam, LPARAM lParam);
BOOL16 CALLBACK FileOpenDlgProc16(HWND16 hWnd16, UINT16 wMsg, WPARAM16 wParam, LPARAM lParam);
INT16 WINAPI FontFamilyEnumProc16( SEGPTR logfont, SEGPTR metrics, UINT16 nFontType, LPARAM lParam );
INT16 WINAPI FontStyleEnumProc16( SEGPTR logfont, SEGPTR metrics, UINT16 nFontType, LPARAM lParam);
BOOL16 CALLBACK FormatCharDlgProc16(HWND16 hDlg16, UINT16 message, WPARAM16 wParam, LPARAM lParam);
short WINAPI GetFileTitle16(LPCSTR lpFile, LPSTR lpTitle, UINT16 cbBuf);
BOOL16 CALLBACK PrintDlgProc16(HWND16 hDlg16, UINT16 uMsg, WPARAM16 wParam, LPARAM lParam);
BOOL16 CALLBACK PrintSetupDlgProc16(HWND16 hWnd16, UINT16 wMsg, WPARAM16 wParam, LPARAM lParam);
typedef struct
{
BYTE pop_eax; //58
BYTE push; //68
DWORD this_;
BYTE push_eax; //50
BYTE mov_eax; //B8
DWORD address;
BYTE jmp; //FF E0
BYTE eax; //E0
BOOL used;
SEGPTR segofn16;
SEGPTR func;
union
{
OPENFILENAME16 ofn16;
PRINTDLGA pd;
};
} COMMDLGTHUNK;
COMMDLGTHUNK *allocate_thunk(SEGPTR ofnseg, SEGPTR func);
void delete_thunk(LPVOID func);
#include "poppack.h"
typedef struct
{
HMENU16 hMenu16;
DLGPROC16 dlgProc;
} dialog_data;
DLGTEMPLATE *WINAPI dialog_template16_to_template32(HINSTANCE16 hInst, SEGPTR dlgTemplate16, DWORD *size, dialog_data *paramd);
#endif /* _WINE_DLL_CDLG16_H */
================================================
FILE: commdlg/colordlg.c
================================================
/*
* COMMDLG - Color Dialog
*
* Copyright 1994 Martin Ayotte
* Copyright 1996 Albrecht Kleine
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
/* BUGS : still seems to not refresh correctly
sometimes, especially when 2 instances of the
dialog are loaded at the same time */
#include
#include
#include
#include
#include
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "commdlg.h"
#include "wine/debug.h"
#include "cdlg16.h"
WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
/***********************************************************************
* ColorDlgProc (COMMDLG.8)
*/
BOOL16 CALLBACK ColorDlgProc16( HWND16 hDlg16, UINT16 message, WPARAM16 wParam, LPARAM lParam )
{
FIXME( "%04x %04x %04x %08lx: stub\n", hDlg16, message, wParam, lParam );
return FALSE;
}
/***********************************************************************
* ChooseColor (COMMDLG.5)
*/
BOOL16 WINAPI ChooseColor16( LPCHOOSECOLOR16 cc16 )
{
CHOOSECOLORA cc32;
BOOL ret;
cc32.lStructSize = sizeof(cc32);
cc32.hwndOwner = HWND_32( cc16->hwndOwner );
cc32.rgbResult = cc16->rgbResult;
cc32.lpCustColors = MapSL( cc16->lpCustColors );
cc32.Flags = cc16->Flags & ~(CC_ENABLETEMPLATE | CC_ENABLETEMPLATEHANDLE | CC_ENABLEHOOK);
cc32.lCustData = cc16->lCustData;
cc32.hInstance = NULL;
cc32.lpfnHook = NULL;
cc32.lpTemplateName = NULL;
if (cc16->Flags & (CC_ENABLETEMPLATE | CC_ENABLETEMPLATEHANDLE))
FIXME( "custom templates no longer supported, using default\n" );
if (cc16->Flags & CC_ENABLEHOOK)
FIXME( "custom hook %p no longer supported\n", cc16->lpfnHook );
if ((ret = ChooseColorA( &cc32 )))
{
cc16->rgbResult = cc32.rgbResult;
}
return ret;
}
================================================
FILE: commdlg/commdlg.def
================================================
; File generated automatically from commdlg.dll16.spec; do not edit!
LIBRARY commdlg.dll16
EXPORTS
_wine_spec_dos_header;=.L__wine_spec_dos_header @1 DATA PRIVATE
================================================
FILE: commdlg/commdlg.dll16.spec
================================================
1 pascal -ret16 GetOpenFileName(segptr) GetOpenFileName16
2 pascal -ret16 GetSaveFileName(segptr) GetSaveFileName16
5 pascal -ret16 ChooseColor(ptr) ChooseColor16
6 pascal FileOpenDlgProc(word word word long) FileOpenDlgProc16
7 pascal FileSaveDlgProc(word word word long) FileSaveDlgProc16
8 pascal ColorDlgProc(word word word long) ColorDlgProc16
#9 pascal LOADALTERBITMAP exported, shared data
11 pascal -ret16 FindText(segptr) FindText16
12 pascal -ret16 ReplaceText(segptr) ReplaceText16
13 pascal FindTextDlgProc(word word word long) FindTextDlgProc16
14 pascal ReplaceTextDlgProc(word word word long) ReplaceTextDlgProc16
15 pascal -ret16 ChooseFont(segptr) ChooseFont16
16 pascal -ret16 FormatCharDlgProc(word word word long) FormatCharDlgProc16
18 pascal -ret16 FontStyleEnumProc(ptr ptr word long) FontStyleEnumProc16
19 pascal -ret16 FontFamilyEnumProc(ptr ptr word long) FontFamilyEnumProc16
20 pascal -ret16 PrintDlg(segptr) PrintDlg16
21 pascal PrintDlgProc(word word word long) PrintDlgProc16
22 pascal PrintSetupDlgProc(word word word long) PrintSetupDlgProc16
#23 pascal EDITINTEGERONLY exported, shared data
#25 pascal WANTARROWS exported, shared data
26 pascal CommDlgExtendedError() CommDlgExtendedError16
27 pascal -ret16 GetFileTitle(str ptr word) GetFileTitle16
#28 pascal WEP exported, shared data
#29 pascal DWLBSUBCLASS exported, shared data
#30 pascal DWUPARROWHACK exported, shared data
#31 pascal DWOKSUBCLASS exported, shared data
================================================
FILE: commdlg/commdlg.rc
================================================
#include "resource.h"
#include "winresrc.h"
/* 64 KiB dummy resource */
IDB_BITMAP1 BITMAP "dummy.bmp"
#define OPEN_FILE 1536
#define SAVE_FILE 1537
#define PRINT 1538
#define PRINT_SETUP 1539
#define FIND 1540
#define REPLACE 1541
#define CHOOSE_FONT 1543
#define CHOOSE_COLOR CHOOSECOLOR
OPEN_FILE DIALOG 36, 24, 275, 134
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Open"
FONT 8, "MS Shell Dlg"
{
LTEXT "File &Name:", stc3, 6, 6, 76, 9
EDITTEXT edt1, 6, 16, 90, 12, ES_AUTOHSCROLL | ES_OEMCONVERT | WS_BORDER | WS_TABSTOP
LISTBOX lst1, 6, 32, 90, 68, LBS_STANDARD | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_DISABLENOSCROLL | WS_TABSTOP
LTEXT "&Directories:", -1, 110, 6, 92, 9
LTEXT "", stc1, 110, 18, 92, 9, SS_NOPREFIX | WS_GROUP
LISTBOX lst2, 110, 32, 92, 68, LBS_STANDARD | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_DISABLENOSCROLL | WS_TABSTOP
LTEXT "List Files of &Type:", stc2, 6, 104, 90, 9
COMBOBOX cmb1, 6, 114, 90, 60, CBS_DROPDOWNLIST | CBS_AUTOHSCROLL | WS_BORDER | WS_VSCROLL | WS_TABSTOP
LTEXT "Dri&ves:", stc4, 110, 104, 92, 9
COMBOBOX cmb2, 110, 114, 92, 68, CBS_DROPDOWNLIST | CBS_OWNERDRAWFIXED | CBS_AUTOHSCROLL | CBS_SORT | CBS_HASSTRINGS | WS_BORDER | WS_VSCROLL | WS_TABSTOP
DEFPUSHBUTTON "Open", IDOK, 208, 6, 60, 14, BS_DEFPUSHBUTTON | WS_GROUP | WS_TABSTOP
PUSHBUTTON "Cancel", IDCANCEL, 208, 24, 60, 14, WS_GROUP | WS_TABSTOP
PUSHBUTTON "&Help", pshHelp, 208, 46, 60, 14, WS_GROUP | WS_TABSTOP
CHECKBOX "&Read Only", chx1, 208, 68, 65, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP
}
SAVE_FILE DIALOG 36, 24, 275, 134
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Save As..."
FONT 8, "MS Shell Dlg"
{
LTEXT "File &Name:", stc3, 6, 6, 76, 9
EDITTEXT edt1, 6, 16, 90, 12, ES_AUTOHSCROLL | ES_OEMCONVERT | WS_BORDER | WS_TABSTOP
LISTBOX lst1, 6, 32, 90, 68, LBS_STANDARD | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_DISABLENOSCROLL | WS_TABSTOP
LTEXT "&Directories:", -1, 110, 6, 92, 9
LTEXT "", stc1, 110, 18, 92, 9, SS_NOPREFIX | WS_GROUP
LISTBOX lst2, 110, 32, 92, 68, LBS_STANDARD | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_DISABLENOSCROLL | WS_TABSTOP
LTEXT "List Files of &Type:", stc2, 6, 104, 90, 9
COMBOBOX cmb1, 6, 114, 90, 60, CBS_DROPDOWNLIST | CBS_AUTOHSCROLL | WS_BORDER | WS_VSCROLL | WS_TABSTOP
LTEXT "Dri&ves:", stc4, 110, 104, 92, 9
COMBOBOX cmb2, 110, 114, 92, 68, CBS_DROPDOWNLIST | CBS_OWNERDRAWFIXED | CBS_AUTOHSCROLL | CBS_SORT | CBS_HASSTRINGS | WS_BORDER | WS_VSCROLL | WS_TABSTOP
DEFPUSHBUTTON "Save As", IDOK, 208, 6, 60, 14, BS_DEFPUSHBUTTON | WS_GROUP | WS_TABSTOP
PUSHBUTTON "Cancel", IDCANCEL, 208, 24, 60, 14, WS_GROUP | WS_TABSTOP
PUSHBUTTON "&Help", pshHelp, 208, 46, 60, 14, WS_GROUP | WS_TABSTOP
CHECKBOX "&Read Only", chx1, 208, 68, 65, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP
}
PRINT DIALOG 36, 24, 264, 134
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Print"
FONT 8, "MS Shell Dlg"
{
LTEXT "Printer:", stc6, 6, 6, 40, 9
LTEXT "", stc1, 60, 6, 150, 9
GROUPBOX "Print range", grp1, 6, 30, 160, 65, BS_GROUPBOX
RADIOBUTTON "&All", rad1, 16, 45, 60, 12
RADIOBUTTON "S&election", rad2, 16, 60, 60, 12
RADIOBUTTON "&Pages", rad4, 16, 75, 60, 12
DEFPUSHBUTTON "Print", IDOK, 206, 6, 56, 14, BS_DEFPUSHBUTTON | WS_GROUP | WS_TABSTOP
PUSHBUTTON "Cancel", IDCANCEL, 206, 24, 56, 14, WS_GROUP | WS_TABSTOP
PUSHBUTTON "&Setup", psh1, 206, 46, 56, 14, WS_GROUP | WS_TABSTOP
PUSHBUTTON "&Help", psh15, 206, 75, 56, 14, WS_GROUP | WS_TABSTOP
LTEXT "&From:", stc2, 60, 80, 30, 9
EDITTEXT edt1, 80, 78, 26, 12, ES_RIGHT | WS_BORDER | WS_TABSTOP
LTEXT "&To:", stc3, 120, 80, 30, 9
EDITTEXT edt2, 135, 78, 26, 12, ES_RIGHT | WS_BORDER | WS_TABSTOP
LTEXT "Print &Quality:", stc4, 6, 100, 76, 9
LTEXT "&Copies:", stc5, 180, 100, 29, 9
EDITTEXT edt3, 205, 98, 26, 12, ES_RIGHT | WS_BORDER | WS_TABSTOP
COMBOBOX cmb1, 80, 100, 92, 68, CBS_DROPDOWNLIST | CBS_OWNERDRAWFIXED | CBS_AUTOHSCROLL | CBS_SORT | CBS_HASSTRINGS | WS_BORDER | WS_VSCROLL | WS_TABSTOP
CHECKBOX "Print to Fi&le", chx1, 20, 120, 50, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP
CHECKBOX "Condensed", chx2, 160, 120, 50, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP
}
PRINT_SETUP DIALOG 36, 24, 264, 134
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Print Setup"
FONT 8, "MS Shell Dlg"
{
GROUPBOX "Printer", grp3, 6, 6, 180, 72, BS_GROUPBOX
RADIOBUTTON "&Default Printer", rad3, 16, 16, 150, 12
LTEXT "[none]", stc1, 35, 30, 120, 9
RADIOBUTTON "Specific &Printer", rad4, 16, 44, 150, 12
COMBOBOX cmb1, 35, 58, 145, 68, CBS_DROPDOWNLIST | CBS_OWNERDRAWFIXED | CBS_AUTOHSCROLL | CBS_SORT | CBS_HASSTRINGS | WS_BORDER | WS_VSCROLL | WS_TABSTOP
DEFPUSHBUTTON "OK", IDOK, 206, 6, 56, 14, BS_DEFPUSHBUTTON | WS_GROUP | WS_TABSTOP
PUSHBUTTON "Cancel", IDCANCEL, 206, 24, 56, 14, WS_GROUP | WS_TABSTOP
PUSHBUTTON "&Setup", psh1, 206, 46, 56, 14, WS_GROUP | WS_TABSTOP
GROUPBOX "Orientation", grp1, 6, 82, 100, 50, BS_GROUPBOX
RADIOBUTTON "Po&rtrait", rad1, 50, 95, 50, 12
RADIOBUTTON "&Landscape", rad2, 50, 110, 50, 12
ICON "LANDSCAP", ico1, 10, 95, 32, 32
GROUPBOX "Paper", grp2, 116, 82, 178, 50, BS_GROUPBOX
LTEXT "Si&ze", stc2, 126, 95, 35, 9
LTEXT "&Source", stc3, 126, 110, 35, 9
COMBOBOX cmb2, 155, 95, 92, 68, CBS_DROPDOWNLIST | CBS_OWNERDRAWFIXED | CBS_AUTOHSCROLL | CBS_SORT | CBS_HASSTRINGS | WS_BORDER | WS_VSCROLL | WS_TABSTOP
COMBOBOX cmb3, 155, 110, 92, 68, CBS_DROPDOWNLIST | CBS_OWNERDRAWFIXED | CBS_AUTOHSCROLL | CBS_SORT | CBS_HASSTRINGS | WS_BORDER | WS_VSCROLL | WS_TABSTOP
}
CHOOSE_FONT DIALOG 13, 54, 274, 147
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Font"
FONT 8, "MS Shell Dlg"
{
LTEXT "&Font:",stc1 ,6,3,90,9
COMBOBOX cmb1, 6,13,94,54, CBS_OWNERDRAWFIXED | CBS_HASSTRINGS | CBS_DISABLENOSCROLL |
CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP | CBS_SIMPLE
LTEXT "Font St&yle:",stc2 ,108,3,60,9
COMBOBOX cmb2,108,13,64,54, CBS_OWNERDRAWFIXED | CBS_HASSTRINGS | CBS_DISABLENOSCROLL |
WS_VSCROLL | WS_TABSTOP | CBS_SIMPLE
LTEXT "&Size:",stc3,179,3,32,9
COMBOBOX cmb3,179,13,32,54, CBS_OWNERDRAWFIXED | CBS_HASSTRINGS | CBS_DISABLENOSCROLL |
WS_VSCROLL | WS_TABSTOP | CBS_SIMPLE | CBS_SORT
DEFPUSHBUTTON "OK",IDOK,218,6,50,14, WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON
PUSHBUTTON "Cancel",IDCANCEL,218,23,50,14,WS_GROUP | WS_TABSTOP
PUSHBUTTON "&Apply", psh3,218,40,50,14,WS_GROUP | WS_TABSTOP
PUSHBUTTON "&Help" , pshHelp,218,57,50,14,WS_GROUP | WS_TABSTOP
GROUPBOX "Effects",grp1,6,72,84,36,WS_GROUP
CHECKBOX "Stri&keout", chx1, 10,82,78,10, BS_AUTOCHECKBOX | WS_TABSTOP
CHECKBOX "&Underline", chx2, 10,94,78,10, BS_AUTOCHECKBOX
LTEXT "&Color:", stc4 ,6,114,80,9
COMBOBOX cmb4,6,124,84,100,CBS_DROPDOWNLIST | CBS_OWNERDRAWFIXED | CBS_HASSTRINGS |
CBS_AUTOHSCROLL | WS_BORDER | WS_VSCROLL | WS_TABSTOP
GROUPBOX "Sample",grp2,98,72,120,36,WS_GROUP
CTEXT "",stc5,103,81,109,24,SS_NOPREFIX | NOT WS_VISIBLE
CTEXT "",stc6,98,123,120,90,SS_NOPREFIX | NOT WS_GROUP
// LTEXT "Scr&ipt:",stc7 ,98,114,40,9
// COMBOBOX cmb5,98,124,120,90,CBS_DROPDOWNLIST | CBS_HASSTRINGS |
// CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP
}
/* Color dialog controls */
#define IDC_COLOR_LUMBAR 702
#define IDC_COLOR_EDIT_H 703
#define IDC_COLOR_EDIT_S 704
#define IDC_COLOR_EDIT_L 705
#define IDC_COLOR_EDIT_R 706
#define IDC_COLOR_EDIT_G 707
#define IDC_COLOR_EDIT_B 708
#define IDC_COLOR_RESULT 709
#define IDC_COLOR_GRAPH 710
#define IDC_COLOR_ADD 712
#define IDC_COLOR_RES 713
#define IDC_COLOR_DEFINE 719
#define IDC_COLOR_PREDEF 720
#define IDC_COLOR_USRDEF 721
#define IDC_COLOR_HL 723
#define IDC_COLOR_SL 724
#define IDC_COLOR_LL 725
#define IDC_COLOR_RL 726
#define IDC_COLOR_GL 727
#define IDC_COLOR_BL 728
CHOOSE_COLOR DIALOG 36, 24, 300, 185
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Color"
FONT 8, "MS Shell Dlg"
{
LTEXT "&Basic Colors:", stc1, 4, 4, 140, 10
LTEXT "&Custom Colors:", stc2, 4, 106, 140, 10
LTEXT "Color | Sol&id", stc3, 150, 151, 48, 10
LTEXT "&Red:", IDC_COLOR_RL /*1094*/,247,126,27,10
EDITTEXT IDC_COLOR_EDIT_R, 275,124,21,12, WS_BORDER | WS_GROUP | WS_TABSTOP
LTEXT "&Green:", IDC_COLOR_GL /*1095*/,247,140,27,10
EDITTEXT IDC_COLOR_EDIT_G, 275,138,21,12, WS_BORDER | WS_GROUP | WS_TABSTOP
LTEXT "&Blue:", IDC_COLOR_BL /*1096*/,247,154,27,10
EDITTEXT IDC_COLOR_EDIT_B, 275,152,21,12, WS_BORDER | WS_GROUP | WS_TABSTOP
LTEXT "&Hue:" , IDC_COLOR_HL /*1091*/,200,126,24,10
EDITTEXT IDC_COLOR_EDIT_H, 224,124,21,12, WS_BORDER | WS_GROUP | WS_TABSTOP
LTEXT "#msgctxt#Saturation#&Sat:", IDC_COLOR_SL /*1092*/,200,140,24,10
EDITTEXT IDC_COLOR_EDIT_S, 224,138,21,12, WS_BORDER | WS_GROUP | WS_TABSTOP
LTEXT "#msgctxt#Luminance#&Lum:", IDC_COLOR_LL /*1093*/,200,154,24,10
EDITTEXT IDC_COLOR_EDIT_L, 224,152,21,12, WS_BORDER | WS_GROUP | WS_TABSTOP
CONTROL "" , IDC_COLOR_PREDEF, "STATIC",SS_SIMPLE|WS_TABSTOP|WS_GROUP,4,14,140,86
CONTROL "" , IDC_COLOR_USRDEF, "STATIC",SS_SIMPLE|WS_TABSTOP|WS_GROUP,4,116,140,28
CONTROL "" , IDC_COLOR_GRAPH, "STATIC",WS_BORDER|SS_SIMPLE|WS_TABSTOP|WS_GROUP, 152,4,118,116
CONTROL "" , IDC_COLOR_LUMBAR, "STATIC",SS_SIMPLE|WS_TABSTOP|WS_GROUP, 278,4,8,116
CONTROL "" , IDC_COLOR_RESULT, "STATIC",SS_SIMPLE|WS_TABSTOP|WS_GROUP, 152,124,40,26
DEFPUSHBUTTON "OK", IDOK, 4, 167, 50, 14, BS_DEFPUSHBUTTON | WS_GROUP | WS_TABSTOP
PUSHBUTTON "Cancel", IDCANCEL, 58, 167, 50, 14, WS_GROUP | WS_TABSTOP
PUSHBUTTON "Help", pshHelp,100,166, 44, 14
PUSHBUTTON "&Add to Custom Colors", IDC_COLOR_ADD /*1024*/, 152, 167, 144, 14, WS_GROUP | WS_TABSTOP
PUSHBUTTON "&Define Custom Colors >>", IDC_COLOR_DEFINE /*1025*/, 4, 149, 142, 14, WS_GROUP | WS_TABSTOP
PUSHBUTTON "Color | Sol&id", IDC_COLOR_RES, 300,200,4,14 /* just a dummy */
}
================================================
FILE: commdlg/commdlg.vcxproj
================================================
Debug
Win32
Release
Win32
{8914D84A-84BD-4F85-99AC-723F8AEABAEB}
Win32Proj
commdlg
10.0.17134.0
DynamicLibrary
true
v141
Unicode
DynamicLibrary
false
v141
true
Unicode
true
.dll16
false
.dll16
Level3
Disabled
WIN32;_DEBUG;_WINDOWS;_USRDLL;COMMDLG_EXPORTS;_X86_;__WINESRC__;__i386__;USE_COMPILER_EXCEPTIONS;HAVE_STRNCASECMP;HAVE__STRNICMP;_WINTERNL_;NtCurrentTeb=NtCurrentTeb__;inline=__inline;DECLSPEC_HIDDEN=;%(PreprocessorDefinitions)
../wine
Windows
true
$(OutDir)user.lib;$(OutDir)winecrt0.lib;$(OutDir)libwine.lib;$(OutDir)krnl386.lib;comdlg32.lib;user32.lib
commdlg.def
Level3
MaxSpeed
true
true
WIN32;NDEBUG;_WINDOWS;_USRDLL;COMMDLG_EXPORTS;_X86_;__WINESRC__;__i386__;USE_COMPILER_EXCEPTIONS;HAVE_STRNCASECMP;HAVE__STRNICMP;_WINTERNL_;NtCurrentTeb=NtCurrentTeb__;inline=__inline;DECLSPEC_HIDDEN=;%(PreprocessorDefinitions)
../wine
Windows
true
true
true
commdlg.def
$(OutDir)user.lib;$(OutDir)winecrt0.lib;$(OutDir)libwine.lib;$(OutDir)krnl386.lib;comdlg32.lib;user32.lib
false
Document
"$(OutDir)convspec" "%(Filename).spec" COMMDLG > "%(Filename).asm" && "$(AsmPath)as" --32 -o "%(Filename).obj" "%(Filename).asm"
%(Filename).obj
"$(OutDir)convspec" "%(Filename).spec" COMMDLG > "%(Filename).asm" && "$(AsmPath)as" --32 -o "%(Filename).obj" "%(Filename).asm"
%(Filename).obj
================================================
FILE: commdlg/commdlg.vcxproj.filters
================================================
{4FC737F1-C7A5-4376-A066-2A32D752A2FF}
cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
{93995380-89BD-4b04-88EB-625FBE52EBFB}
h;hh;hpp;hxx;hm;inl;inc;xsd
{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
ソース ファイル
ソース ファイル
ソース ファイル
ソース ファイル
ソース ファイル
ヘッダー ファイル
ヘッダー ファイル
ソース ファイル
ソース ファイル
リソース ファイル
リソース ファイル
================================================
FILE: commdlg/filedlg.c
================================================
/*
* COMMDLG - File Dialogs
*
* Copyright 1994 Martin Ayotte
* Copyright 1996 Albrecht Kleine
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include
#include
#include "windef.h"
#include "winbase.h"
#include "wine/winbase16.h"
#include "wingdi.h"
#include "winuser.h"
#include "winternl.h"
#include "commdlg.h"
#include "cdlg16.h"
#include "wine/debug.h"
#include
#include "resource.h"
#include
WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
#define MAX_THUNK 5
COMMDLGTHUNK *thunk_array;
UINT WMFILEOK;
UINT WMHELPMSG;
UINT WMFINDMSG;
UINT WMCOLOROK;
UINT WMSHAREVI;
UINT WMWOWDirChange;
LPDLGTEMPLATEA resource_to_dialog32(HINSTANCE16 hInst, LPCSTR name, WORD *res);
LPDLGTEMPLATEA handle_to_dialog32(HGLOBAL16 hg, WORD *res);
LRESULT WINAPI DIALOG_CallDialogProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, WNDPROC16 proc);
static UINT_PTR CALLBACK thunk_hook(COMMDLGTHUNK *thunk, HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
/* window message hook? */
if (msg == WM_INITDIALOG || msg == WMFILEOK || msg == WMHELPMSG || msg == WMFINDMSG || msg == WMCOLOROK || msg == WMSHAREVI)
{
lp = thunk->segofn16;
}
UINT_PTR result = DIALOG_CallDialogProc(hwnd, msg, wp, lp, (WNDPROC16)thunk->func);
return result;
}
static void init_thunk()
{
if (thunk_array)
return;
WMFILEOK = RegisterWindowMessageW(FILEOKSTRINGW);
WMHELPMSG = RegisterWindowMessageW(HELPMSGSTRINGW);
WMFINDMSG = RegisterWindowMessageW(FINDMSGSTRINGW);
WMCOLOROK = RegisterWindowMessageW(COLOROKSTRINGW);
WMSHAREVI = RegisterWindowMessageW(SHAREVISTRINGW);
/* undocumented */
WMWOWDirChange = RegisterWindowMessageW(L"WOWDirChange");
thunk_array = VirtualAlloc(NULL, MAX_THUNK * sizeof(COMMDLGTHUNK), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
}
void delete_thunk(LPVOID func)
{
if (func && (SIZE_T)thunk_array <= (SIZE_T)func && (SIZE_T)func <= (SIZE_T)(thunk_array + MAX_THUNK))
{
((COMMDLGTHUNK*)func)->used = FALSE;
}
}
COMMDLGTHUNK *allocate_thunk(SEGPTR ofnseg, SEGPTR func)
{
init_thunk();
for (int i = 0; i < MAX_THUNK; i++)
{
if (!thunk_array[i].used)
{
thunk_array[i].pop_eax = 0x58;
thunk_array[i].push = 0x68;
thunk_array[i].this_ = (DWORD)(thunk_array + i);
thunk_array[i].push_eax = 0x50;
thunk_array[i].mov_eax = 0xB8;
thunk_array[i].address = (DWORD)thunk_hook;
thunk_array[i].jmp = 0xFF;
thunk_array[i].eax = 0xE0;
thunk_array[i].used = TRUE;
thunk_array[i].func = func;
thunk_array[i].segofn16 = ofnseg;
return thunk_array + i;
}
}
return NULL;
}
static inline WORD get_word( const char **ptr )
{
WORD ret = *(WORD *)*ptr;
*ptr += sizeof(WORD);
return ret;
}
static inline void copy_string( WORD **out, const char **in, DWORD maxlen )
{
DWORD len = MultiByteToWideChar( CP_ACP, 0, *in, -1, *out, maxlen );
*in += strlen(*in) + 1;
*out += len;
}
static inline void copy_dword( WORD **out, const char **in )
{
*(DWORD *)*out = *(DWORD *)*in;
*in += sizeof(DWORD);
*out += sizeof(DWORD) / sizeof(WORD);
}
static LPDLGTEMPLATEA convert_dialog( const char *p, DWORD size )
{
LPDLGTEMPLATEA dlg;
WORD len, count, *out, *end;
if (!(dlg = HeapAlloc( GetProcessHeap(), 0, size * 2 ))) return NULL;
out = (WORD *)dlg;
end = out + size;
copy_dword( &out, &p ); /* style */
*out++ = 0; *out++ = 0; /* exstyle */
*out++ = count = (BYTE)*p++; /* count */
*out++ = get_word( &p ); /* x */
*out++ = get_word( &p ); /* y */
*out++ = get_word( &p ); /* cx */
*out++ = get_word( &p ); /* cy */
if ((BYTE)*p == 0xff) /* menu */
{
p++;
*out++ = 0xffff;
*out++ = get_word( &p );
}
else copy_string( &out, &p, end - out );
copy_string( &out, &p, end - out ); /* class */
copy_string( &out, &p, end - out ); /* caption */
if (dlg->style & DS_SETFONT)
{
*out++ = get_word( &p ); /* point size */
copy_string( &out, &p, end - out ); /* face name */
}
/* controls */
while (count--)
{
WORD x = get_word( &p );
WORD y = get_word( &p );
WORD cx = get_word( &p );
WORD cy = get_word( &p );
WORD id = get_word( &p );
out = (WORD *)(((UINT_PTR)out + 3) & ~3);
copy_dword( &out, &p ); /* style */
*out++ = 0; *out++ = 0; /* exstyle */
*out++ = x;
*out++ = y;
*out++ = cx;
*out++ = cy;
*out++ = id;
if (*p & 0x80) /* class */
{
*out++ = 0xffff;
*out++ = (BYTE)*p++;
}
else copy_string( &out, &p, end - out );
if (*p & 0x80) /* window */
{
*out++ = 0xffff;
*out++ = get_word( &p );
}
else copy_string( &out, &p, end - out );
len = (BYTE)*p++; /* data */
*out++ = (len + 1) & ~1;
memcpy( out, p, len );
p += len;
out += (len + 1) / sizeof(WORD);
}
assert( out <= end );
return dlg;
}
static UINT_PTR CALLBACK dummy_hook( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
{
return FALSE;
}
/***********************************************************************
* FileOpenDlgProc (COMMDLG.6)
*/
BOOL16 CALLBACK FileOpenDlgProc16(HWND16 hWnd16, UINT16 wMsg, WPARAM16 wParam, LPARAM lParam)
{
FIXME( "%04x %04x %04x %08lx: stub\n", hWnd16, wMsg, wParam, lParam );
return FALSE;
}
/***********************************************************************
* FileSaveDlgProc (COMMDLG.7)
*/
BOOL16 CALLBACK FileSaveDlgProc16(HWND16 hWnd16, UINT16 wMsg, WPARAM16 wParam, LPARAM lParam)
{
FIXME( "%04x %04x %04x %08lx: stub\n", hWnd16, wMsg, wParam, lParam );
return FALSE;
}
DWORD get_ofn_flag(DWORD flag)
{
return (flag | OFN_NOLONGNAMES) & ~OFN_ENABLETEMPLATE;
}
/***********************************************************************
* GetOpenFileName (COMMDLG.1)
*
* Creates a dialog box for the user to select a file to open.
*
* RETURNS
* TRUE on success: user selected a valid file
* FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
*
* BUGS
* unknown, there are some FIXMEs left.
*/
BOOL16 WINAPI GetOpenFileName16( SEGPTR ofn ) /* [in/out] address of structure with data*/
{
LPOPENFILENAME16 lpofn = MapSL(ofn);
LPDLGTEMPLATEA template = NULL;
OPENFILENAMEA ofn32;
BOOL ret;
DWORD count;
WORD res = NULL;
if (!lpofn) return FALSE;
OPENFILENAME16 ofn16 = *lpofn;
ofn32.lStructSize = OPENFILENAME_SIZE_VERSION_400A;
ofn32.hwndOwner = HWND_32( lpofn->hwndOwner );
ofn32.lpstrFilter = MapSL( lpofn->lpstrFilter );
ofn32.lpstrCustomFilter = MapSL( lpofn->lpstrCustomFilter );
ofn32.nMaxCustFilter = lpofn->nMaxCustFilter;
ofn32.nFilterIndex = lpofn->nFilterIndex;
ofn32.lpstrFile = MapSL( lpofn->lpstrFile );
ofn32.nMaxFile = lpofn->nMaxFile;
ofn32.lpstrFileTitle = MapSL( lpofn->lpstrFileTitle );
ofn32.nMaxFileTitle = lpofn->nMaxFileTitle;
ofn32.lpstrInitialDir = MapSL( lpofn->lpstrInitialDir );
ofn32.lpstrTitle = MapSL( lpofn->lpstrTitle );
ofn32.Flags = get_ofn_flag(lpofn->Flags | OFN_ENABLEHOOK);
ofn32.nFileOffset = lpofn->nFileOffset;
ofn32.nFileExtension = lpofn->nFileExtension;
ofn32.lpstrDefExt = MapSL( lpofn->lpstrDefExt );
ofn32.lCustData = lpofn->lCustData;
ofn32.lpfnHook = dummy_hook; /* this is to force old 3.1 dialog style */
ofn32.lpTemplateName = NULL;
ofn32.hInstance = GetModuleHandleW(L"commdlg.dll16");
if ((lpofn->Flags & OFN_ENABLETEMPLATE) || (lpofn->Flags & OFN_ENABLETEMPLATEHANDLE))
{
if (lpofn->Flags & OFN_ENABLETEMPLATE)
template = resource_to_dialog32(lpofn->hInstance, MapSL(lpofn->lpTemplateName), &res);
else
template = handle_to_dialog32(lpofn->hInstance, &res);
ofn32.hInstance = template;
ofn32.Flags |= OFN_ENABLETEMPLATEHANDLE;
}
if (lpofn->Flags & OFN_ENABLEHOOK)
{
ofn32.lpfnHook = (LPOFNHOOKPROC)allocate_thunk(ofn, (SEGPTR)lpofn->lpfnHook);
((COMMDLGTHUNK*)ofn32.lpfnHook)->ofn16 = ofn16;
if (!ofn32.lpfnHook)
{
ERR("could not allocate GetOpenFileName16 thunk\n");
ofn32.lpfnHook = dummy_hook;
}
}
if (ofn32.lpstrFile && ofn32.lpstrFile[0])
CharUpperBuffA(ofn32.lpstrFile, min(strlen(ofn32.lpstrFile), ofn32.nMaxFile));
ReleaseThunkLock(&count);
if ((ret = GetOpenFileNameA( &ofn32 )))
{
lpofn->nFilterIndex = ofn32.nFilterIndex;
lpofn->nFileOffset = ofn32.nFileOffset;
lpofn->nFileExtension = ofn32.nFileExtension;
if (ofn32.lpstrFile && ofn32.lpstrFile[0])
CharUpperBuffA(ofn32.lpstrFile, min(strlen(ofn32.lpstrFile), ofn32.nMaxFile));
}
RestoreThunkLock(count);
if (res)
{
if (lpofn->Flags & OFN_ENABLETEMPLATE)
FreeResource16(res);
else if (lpofn->Flags & OFN_ENABLETEMPLATEHANDLE)
WOWGlobalUnlock16(res);
}
delete_thunk(ofn32.lpfnHook);
HeapFree( GetProcessHeap(), 0, template );
return ret;
}
/***********************************************************************
* GetSaveFileName (COMMDLG.2)
*
* Creates a dialog box for the user to select a file to save.
*
* RETURNS
* TRUE on success: user enters a valid file
* FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
*
* BUGS
* unknown. There are some FIXMEs left.
*/
BOOL16 WINAPI GetSaveFileName16( SEGPTR ofn ) /* [in/out] address of structure with data*/
{
LPOPENFILENAME16 lpofn = MapSL(ofn);
LPDLGTEMPLATEA template = NULL;
OPENFILENAMEA ofn32;
BOOL ret;
DWORD count;
WORD res = NULL;
if (!lpofn) return FALSE;
OPENFILENAME16 ofn16 = *lpofn;
ofn32.lStructSize = OPENFILENAME_SIZE_VERSION_400A;
ofn32.hwndOwner = HWND_32( lpofn->hwndOwner );
ofn32.lpstrFilter = MapSL( lpofn->lpstrFilter );
ofn32.lpstrCustomFilter = MapSL( lpofn->lpstrCustomFilter );
ofn32.nMaxCustFilter = lpofn->nMaxCustFilter;
ofn32.nFilterIndex = lpofn->nFilterIndex;
ofn32.lpstrFile = MapSL( lpofn->lpstrFile );
ofn32.nMaxFile = lpofn->nMaxFile;
ofn32.lpstrFileTitle = MapSL( lpofn->lpstrFileTitle );
ofn32.nMaxFileTitle = lpofn->nMaxFileTitle;
ofn32.lpstrInitialDir = MapSL( lpofn->lpstrInitialDir );
ofn32.lpstrTitle = MapSL( lpofn->lpstrTitle );
ofn32.Flags = get_ofn_flag(lpofn->Flags | OFN_ENABLEHOOK);
ofn32.nFileOffset = lpofn->nFileOffset;
ofn32.nFileExtension = lpofn->nFileExtension;
ofn32.lpstrDefExt = MapSL( lpofn->lpstrDefExt );
ofn32.lCustData = lpofn->lCustData;
ofn32.lpfnHook = dummy_hook; /* this is to force old 3.1 dialog style */
ofn32.lpTemplateName = NULL;
ofn32.hInstance = GetModuleHandleW(L"commdlg.dll16");
if ((lpofn->Flags & OFN_ENABLETEMPLATE) || (lpofn->Flags & OFN_ENABLETEMPLATEHANDLE))
{
if (lpofn->Flags & OFN_ENABLETEMPLATE)
template = resource_to_dialog32(lpofn->hInstance, MapSL(lpofn->lpTemplateName), &res);
else
template = handle_to_dialog32(lpofn->hInstance, &res);
ofn32.hInstance = template;
ofn32.Flags |= OFN_ENABLETEMPLATEHANDLE;
}
if (lpofn->Flags & OFN_ENABLEHOOK)
{
ofn32.lpfnHook = (LPOFNHOOKPROC)allocate_thunk(ofn, (SEGPTR)lpofn->lpfnHook);
((COMMDLGTHUNK*)ofn32.lpfnHook)->ofn16 = ofn16;
if (!ofn32.lpfnHook)
{
ERR("could not allocate GetOpenFileName16 thunk\n");
ofn32.lpfnHook = dummy_hook;
}
}
if (ofn32.lpstrFile && ofn32.lpstrFile[0])
CharUpperBuffA(ofn32.lpstrFile, min(strlen(ofn32.lpstrFile), ofn32.nMaxFile));
ReleaseThunkLock(&count);
if ((ret = GetSaveFileNameA( &ofn32 )))
{
lpofn->nFilterIndex = ofn32.nFilterIndex;
lpofn->nFileOffset = ofn32.nFileOffset;
lpofn->nFileExtension = ofn32.nFileExtension;
if (ofn32.lpstrFile && ofn32.lpstrFile[0])
CharUpperBuffA(ofn32.lpstrFile, min(strlen(ofn32.lpstrFile), ofn32.nMaxFile));
}
RestoreThunkLock(count);
if (res)
{
if (lpofn->Flags & OFN_ENABLETEMPLATE)
FreeResource16(res);
else if (lpofn->Flags & OFN_ENABLETEMPLATEHANDLE)
WOWGlobalUnlock16(res);
}
delete_thunk(ofn32.lpfnHook);
HeapFree( GetProcessHeap(), 0, template );
return ret;
}
/***********************************************************************
* GetFileTitle (COMMDLG.27)
*/
short WINAPI GetFileTitle16(LPCSTR lpFile, LPSTR lpTitle, UINT16 cbBuf)
{
return GetFileTitleA(lpFile, lpTitle, cbBuf);
}
================================================
FILE: commdlg/finddlg.c
================================================
/*
* COMMDLG - 16 bits Find & Replace Text Dialogs
*
* Copyright 1994 Martin Ayotte
* Copyright 1996 Albrecht Kleine
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include
#include
#include
#include
#include "windef.h"
#include "winbase.h"
#include "wine/winbase16.h"
#include "wine/winuser16.h"
#include "wingdi.h"
#include "winuser.h"
#include "commdlg.h"
#include "cderr.h"
#include "cdlg16.h"
LRESULT WINAPI DIALOG_CallDialogProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, WNDPROC16 proc);
LPDLGTEMPLATEA resource_to_dialog32(HINSTANCE16 hInst, LPCSTR name, WORD *res);
LPDLGTEMPLATEA handle_to_dialog32(HGLOBAL16 hg, WORD *res);
/***********************************************************************
* FINDDLG_WMCommand [internal]
*/
static LRESULT FINDDLG_WMCommand(HWND hWnd, WPARAM wParam,
HWND hwndOwner, LPDWORD lpFlags,
LPSTR lpstrFindWhat, WORD wFindWhatLen)
{
int uFindReplaceMessage = RegisterWindowMessageA( FINDMSGSTRINGA );
int uHelpMessage = RegisterWindowMessageA( HELPMSGSTRINGA );
switch (LOWORD(wParam)) {
case IDOK:
GetDlgItemTextA(hWnd, edt1, lpstrFindWhat, wFindWhatLen);
if (IsDlgButtonChecked(hWnd, rad2))
*lpFlags |= FR_DOWN;
else *lpFlags &= ~FR_DOWN;
if (IsDlgButtonChecked(hWnd, chx1))
*lpFlags |= FR_WHOLEWORD;
else *lpFlags &= ~FR_WHOLEWORD;
if (IsDlgButtonChecked(hWnd, chx2))
*lpFlags |= FR_MATCHCASE;
else *lpFlags &= ~FR_MATCHCASE;
*lpFlags &= ~(FR_REPLACE | FR_REPLACEALL | FR_DIALOGTERM);
*lpFlags |= FR_FINDNEXT;
SendMessageW( hwndOwner, uFindReplaceMessage, 0,
GetWindowLongPtrW(hWnd, DWLP_USER) );
return TRUE;
case IDCANCEL:
*lpFlags &= ~(FR_FINDNEXT | FR_REPLACE | FR_REPLACEALL);
*lpFlags |= FR_DIALOGTERM;
SendMessageW( hwndOwner, uFindReplaceMessage, 0,
GetWindowLongPtrW(hWnd, DWLP_USER) );
DestroyWindow(hWnd);
return TRUE;
case pshHelp:
/* FIXME : should lpfr structure be passed as an argument ??? */
SendMessageA(hwndOwner, uHelpMessage, 0, 0);
return TRUE;
}
return FALSE;
}
/***********************************************************************
* find_text_dlgproc (internal)
*/
static INT_PTR CALLBACK find_text_dlgproc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
{
LPFINDREPLACE16 lpfr;
DWORD lpFlags;
LRESULT ret = FALSE;
if (wMsg == WM_INITDIALOG)
{
lpfr = MapSL(lParam);
SetWindowLongPtrW(hWnd, DWLP_USER, lParam);
lpfr->Flags &= ~(FR_FINDNEXT | FR_REPLACE | FR_REPLACEALL | FR_DIALOGTERM);
lpFlags = lpfr->Flags;
/*
* FIXME : If the initial FindWhat string is empty, we should disable the
* FindNext (IDOK) button. Only after typing some text, the button should be
* enabled.
*/
SetDlgItemTextA(hWnd, edt1, lpfr->lpstrFindWhat);
CheckRadioButton(hWnd, rad1, rad2, (lpFlags & FR_DOWN) ? rad2 : rad1);
if (lpFlags & (FR_HIDEUPDOWN | FR_NOUPDOWN)) {
EnableWindow(GetDlgItem(hWnd, rad1), FALSE);
EnableWindow(GetDlgItem(hWnd, rad2), FALSE);
}
if (lpFlags & FR_HIDEUPDOWN) {
ShowWindow(GetDlgItem(hWnd, rad1), SW_HIDE);
ShowWindow(GetDlgItem(hWnd, rad2), SW_HIDE);
ShowWindow(GetDlgItem(hWnd, grp1), SW_HIDE);
}
CheckDlgButton(hWnd, chx1, (lpFlags & FR_WHOLEWORD) ? 1 : 0);
if (lpFlags & (FR_HIDEWHOLEWORD | FR_NOWHOLEWORD))
EnableWindow(GetDlgItem(hWnd, chx1), FALSE);
if (lpFlags & FR_HIDEWHOLEWORD)
ShowWindow(GetDlgItem(hWnd, chx1), SW_HIDE);
CheckDlgButton(hWnd, chx2, (lpFlags & FR_MATCHCASE) ? 1 : 0);
if (lpFlags & (FR_HIDEMATCHCASE | FR_NOMATCHCASE))
EnableWindow(GetDlgItem(hWnd, chx2), FALSE);
if (lpFlags & FR_HIDEMATCHCASE)
ShowWindow(GetDlgItem(hWnd, chx2), SW_HIDE);
if (!(lpFlags & FR_SHOWHELP)) {
EnableWindow(GetDlgItem(hWnd, pshHelp), FALSE);
ShowWindow(GetDlgItem(hWnd, pshHelp), SW_HIDE);
}
ret = TRUE;
if (lpFlags & FR_ENABLEHOOK)
ret = DIALOG_CallDialogProc(hWnd, wMsg, wParam, lParam, lpfr->lpfnHook);
if (ret) ShowWindow(hWnd, SW_SHOWNORMAL);
return TRUE;
}
lpfr = MapSL(GetWindowLongPtrW(hWnd, DWLP_USER));
if (lpfr && (lpfr->Flags & FR_ENABLEHOOK))
ret = DIALOG_CallDialogProc(hWnd, wMsg, wParam, lParam, lpfr->lpfnHook);
if (!ret)
{
switch (wMsg)
{
case WM_COMMAND:
return FINDDLG_WMCommand(hWnd, wParam, HWND_32(lpfr->hwndOwner),
&lpfr->Flags, MapSL(lpfr->lpstrFindWhat), lpfr->wFindWhatLen);
}
}
return FALSE;
}
/***********************************************************************
* FindText (COMMDLG.11)
*/
HWND16 WINAPI FindText16( SEGPTR find )
{
FINDREPLACE16 *fr16 = MapSL( find );
LPDLGTEMPLATEA template = NULL;
HWND16 ret;
if ((fr16->Flags & FR_ENABLETEMPLATE) || (fr16->Flags & FR_ENABLETEMPLATEHANDLE))
{
if (fr16->Flags & FR_ENABLETEMPLATE)
template = resource_to_dialog32(fr16->hInstance, MapSL(fr16->lpTemplateName), NULL);
else
template = handle_to_dialog32(fr16->hInstance, NULL);
ret = HWND_16(CreateDialogIndirectParamA(fr16->hInstance, template,
HWND_32(fr16->hwndOwner), find_text_dlgproc, find));
HeapFree(GetProcessHeap(), 0, template);
}
else
ret = HWND_16( CreateDialogParamA( GetModuleHandleA("comdlg32.dll"), MAKEINTRESOURCEA(FINDDLGORD),
HWND_32(fr16->hwndOwner), find_text_dlgproc, find ));
return ret;
}
/***********************************************************************
* FindTextDlgProc (COMMDLG.13)
*/
BOOL16 CALLBACK FindTextDlgProc16(HWND16 hWnd16, UINT16 wMsg, WPARAM16 wParam,
LPARAM lParam)
{
return find_text_dlgproc( HWND_32(hWnd16), wMsg, wParam, lParam );
}
/***********************************************************************
* REPLACEDLG_WMInitDialog [internal]
*/
static LRESULT REPLACEDLG_WMInitDialog(HWND hWnd, LPARAM lParam,
LPDWORD lpFlags, LPCSTR lpstrFindWhat,
LPCSTR lpstrReplaceWith)
{
}
/***********************************************************************
* REPLACEDLG_WMCommand [internal]
*/
static LRESULT REPLACEDLG_WMCommand(HWND hWnd, WPARAM wParam,
HWND hwndOwner, LPDWORD lpFlags,
LPSTR lpstrFindWhat, WORD wFindWhatLen,
LPSTR lpstrReplaceWith, WORD wReplaceWithLen)
{
int uFindReplaceMessage = RegisterWindowMessageA( FINDMSGSTRINGA );
int uHelpMessage = RegisterWindowMessageA( HELPMSGSTRINGA );
switch (LOWORD(wParam)) {
case IDOK:
GetDlgItemTextA(hWnd, edt1, lpstrFindWhat, wFindWhatLen);
GetDlgItemTextA(hWnd, edt2, lpstrReplaceWith, wReplaceWithLen);
if (IsDlgButtonChecked(hWnd, chx1))
*lpFlags |= FR_WHOLEWORD;
else *lpFlags &= ~FR_WHOLEWORD;
if (IsDlgButtonChecked(hWnd, chx2))
*lpFlags |= FR_MATCHCASE;
else *lpFlags &= ~FR_MATCHCASE;
*lpFlags &= ~(FR_REPLACE | FR_REPLACEALL | FR_DIALOGTERM);
*lpFlags |= FR_FINDNEXT;
SendMessageW( hwndOwner, uFindReplaceMessage, 0,
GetWindowLongPtrW(hWnd, DWLP_USER) );
return TRUE;
case IDCANCEL:
*lpFlags &= ~(FR_FINDNEXT | FR_REPLACE | FR_REPLACEALL);
*lpFlags |= FR_DIALOGTERM;
SendMessageW( hwndOwner, uFindReplaceMessage, 0,
GetWindowLongPtrW(hWnd, DWLP_USER) );
DestroyWindow(hWnd);
return TRUE;
case psh1:
GetDlgItemTextA(hWnd, edt1, lpstrFindWhat, wFindWhatLen);
GetDlgItemTextA(hWnd, edt2, lpstrReplaceWith, wReplaceWithLen);
if (IsDlgButtonChecked(hWnd, chx1))
*lpFlags |= FR_WHOLEWORD;
else *lpFlags &= ~FR_WHOLEWORD;
if (IsDlgButtonChecked(hWnd, chx2))
*lpFlags |= FR_MATCHCASE;
else *lpFlags &= ~FR_MATCHCASE;
*lpFlags &= ~(FR_FINDNEXT | FR_REPLACEALL | FR_DIALOGTERM);
*lpFlags |= FR_REPLACE;
SendMessageW( hwndOwner, uFindReplaceMessage, 0,
GetWindowLongPtrW(hWnd, DWLP_USER) );
return TRUE;
case psh2:
GetDlgItemTextA(hWnd, edt1, lpstrFindWhat, wFindWhatLen);
GetDlgItemTextA(hWnd, edt2, lpstrReplaceWith, wReplaceWithLen);
if (IsDlgButtonChecked(hWnd, chx1))
*lpFlags |= FR_WHOLEWORD;
else *lpFlags &= ~FR_WHOLEWORD;
if (IsDlgButtonChecked(hWnd, chx2))
*lpFlags |= FR_MATCHCASE;
else *lpFlags &= ~FR_MATCHCASE;
*lpFlags &= ~(FR_FINDNEXT | FR_REPLACE | FR_DIALOGTERM);
*lpFlags |= FR_REPLACEALL;
SendMessageW( hwndOwner, uFindReplaceMessage, 0,
GetWindowLongPtrW(hWnd, DWLP_USER) );
return TRUE;
case pshHelp:
/* FIXME : should lpfr structure be passed as an argument ??? */
SendMessageA(hwndOwner, uHelpMessage, 0, 0);
return TRUE;
}
return FALSE;
}
/***********************************************************************
* replace_text_dlgproc
*/
static INT_PTR CALLBACK replace_text_dlgproc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
{
LPFINDREPLACE16 lpfr;
DWORD lpFlags;
LRESULT ret = FALSE;
if (wMsg == WM_INITDIALOG)
{
lpfr=MapSL(lParam);
SetWindowLongPtrW(hWnd, DWLP_USER, lParam);
lpfr->Flags &= ~(FR_FINDNEXT | FR_REPLACE | FR_REPLACEALL | FR_DIALOGTERM);
lpFlags = lpfr->Flags;
/*
* FIXME : If the initial FindWhat string is empty, we should disable the FindNext /
* Replace / ReplaceAll buttons. Only after typing some text, the buttons should be
* enabled.
*/
SetDlgItemTextA(hWnd, edt1, lpfr->lpstrFindWhat);
SetDlgItemTextA(hWnd, edt2, lpfr->lpstrReplaceWith);
CheckDlgButton(hWnd, chx1, (lpFlags & FR_WHOLEWORD) ? 1 : 0);
if (lpFlags & (FR_HIDEWHOLEWORD | FR_NOWHOLEWORD))
EnableWindow(GetDlgItem(hWnd, chx1), FALSE);
if (lpFlags & FR_HIDEWHOLEWORD)
ShowWindow(GetDlgItem(hWnd, chx1), SW_HIDE);
CheckDlgButton(hWnd, chx2, (lpFlags & FR_MATCHCASE) ? 1 : 0);
if (lpFlags & (FR_HIDEMATCHCASE | FR_NOMATCHCASE))
EnableWindow(GetDlgItem(hWnd, chx2), FALSE);
if (lpFlags & FR_HIDEMATCHCASE)
ShowWindow(GetDlgItem(hWnd, chx2), SW_HIDE);
if (!(lpFlags & FR_SHOWHELP)) {
EnableWindow(GetDlgItem(hWnd, pshHelp), FALSE);
ShowWindow(GetDlgItem(hWnd, pshHelp), SW_HIDE);
}
ret = TRUE;
if (lpFlags & FR_ENABLEHOOK)
ret = DIALOG_CallDialogProc(hWnd, wMsg, wParam, lParam, lpfr->lpfnHook);
if (ret) ShowWindow(hWnd, SW_SHOWNORMAL);
return TRUE;
}
lpfr = MapSL(GetWindowLongPtrW(hWnd, DWLP_USER));
if (lpfr && (lpfr->Flags & FR_ENABLEHOOK))
ret = DIALOG_CallDialogProc(hWnd, wMsg, wParam, lParam, lpfr->lpfnHook);
if (!ret)
{
switch (wMsg)
{
case WM_COMMAND:
return REPLACEDLG_WMCommand(hWnd, wParam, HWND_32(lpfr->hwndOwner),
&lpfr->Flags, MapSL(lpfr->lpstrFindWhat),
lpfr->wFindWhatLen, MapSL(lpfr->lpstrReplaceWith),
lpfr->wReplaceWithLen);
}
}
return FALSE;
}
/***********************************************************************
* ReplaceText (COMMDLG.12)
*/
HWND16 WINAPI ReplaceText16( SEGPTR find )
{
FINDREPLACE16 *fr16 = MapSL( find );
LPDLGTEMPLATEA template = NULL;
HWND16 ret;
if ((fr16->Flags & FR_ENABLETEMPLATE) || (fr16->Flags & FR_ENABLETEMPLATEHANDLE))
{
if (fr16->Flags & FR_ENABLETEMPLATE)
template = resource_to_dialog32(fr16->hInstance, MapSL(fr16->lpTemplateName), NULL);
else
template = handle_to_dialog32(fr16->hInstance, NULL);
ret = HWND_16(CreateDialogIndirectParamA(fr16->hInstance, template,
HWND_32(fr16->hwndOwner), replace_text_dlgproc, find));
HeapFree(GetProcessHeap(), 0, template);
}
else
ret = HWND_16( CreateDialogParamA( GetModuleHandleA("comdlg32.dll"), MAKEINTRESOURCEA(FINDDLGORD),
HWND_32(fr16->hwndOwner), replace_text_dlgproc, find ));
return ret;
}
/***********************************************************************
* ReplaceTextDlgProc (COMMDLG.14)
*/
BOOL16 CALLBACK ReplaceTextDlgProc16(HWND16 hWnd16, UINT16 wMsg, WPARAM16 wParam,
LPARAM lParam)
{
return replace_text_dlgproc( HWND_32(hWnd16), wMsg, wParam, lParam );
}
/***********************************************************************
* CommDlgExtendedError (COMMDLG.26)
*/
DWORD WINAPI CommDlgExtendedError16(void)
{
return CommDlgExtendedError();
}
================================================
FILE: commdlg/fontdlg.c
================================================
/*
* COMMDLG - Font Dialog
*
* Copyright 1994 Martin Ayotte
* Copyright 1996 Albrecht Kleine
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include
#include
#include
#include
#include
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "wine/winbase16.h"
#include "wine/winuser16.h"
#include "commdlg.h"
#include "wine/debug.h"
#include "cderr.h"
#include "cdlg16.h"
WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
LPDLGTEMPLATEA resource_to_dialog32(HINSTANCE16 hInst, LPCSTR name, WORD *res);
LPDLGTEMPLATEA handle_to_dialog32(HGLOBAL16 hg, WORD *res);
/***********************************************************************
* FontFamilyEnumProc (COMMDLG.19)
*/
INT16 WINAPI FontFamilyEnumProc16( SEGPTR logfont, SEGPTR metrics,
UINT16 nFontType, LPARAM lParam )
{
FIXME( "%08x %08x %u %lx\n", logfont, metrics, nFontType, lParam );
return 0;
}
/***********************************************************************
* FontStyleEnumProc (COMMDLG.18)
*/
INT16 WINAPI FontStyleEnumProc16( SEGPTR logfont, SEGPTR metrics,
UINT16 nFontType, LPARAM lParam )
{
FIXME( "%08x %08x %u %lx\n", logfont, metrics, nFontType, lParam );
return 0;
}
/***********************************************************************
* ChooseFont (COMMDLG.15)
*/
BOOL16 WINAPI ChooseFont16(SEGPTR cf)
{
LPCHOOSEFONT16 lpChFont = MapSL(cf);
CHOOSEFONTA cf32;
LOGFONTA lf32;
LOGFONT16 *font16;
LPDLGTEMPLATEA template = NULL;
if (!lpChFont) return FALSE;
font16 = MapSL(lpChFont->lpLogFont);
cf32.lStructSize = sizeof(CHOOSEFONTA);
cf32.hwndOwner = HWND_32(lpChFont->hwndOwner);
cf32.hDC = HDC_32(lpChFont->hDC);
cf32.iPointSize = lpChFont->iPointSize;
cf32.Flags = lpChFont->Flags & ~(CF_ENABLETEMPLATEHANDLE | CF_ENABLETEMPLATE | CF_ENABLEHOOK);
cf32.rgbColors = lpChFont->rgbColors;
cf32.lCustData = lpChFont->lCustData;
cf32.lpfnHook = NULL;
cf32.hInstance = GetModuleHandleA("comdlg32.dll");
cf32.nFontType = lpChFont->nFontType;
cf32.nSizeMax = lpChFont->nSizeMax;
cf32.nSizeMin = lpChFont->nSizeMin;
cf32.lpLogFont = &lf32;
lf32.lfHeight = font16->lfHeight;
lf32.lfWidth = font16->lfWidth;
lf32.lfEscapement = font16->lfEscapement;
lf32.lfOrientation = font16->lfOrientation;
lf32.lfWeight = font16->lfWeight;
lf32.lfItalic = font16->lfItalic;
lf32.lfUnderline = font16->lfUnderline;
lf32.lfStrikeOut = font16->lfStrikeOut;
lf32.lfCharSet = font16->lfCharSet;
lf32.lfOutPrecision = font16->lfOutPrecision;
lf32.lfClipPrecision = font16->lfClipPrecision;
lf32.lfQuality = font16->lfQuality;
lf32.lfPitchAndFamily = font16->lfPitchAndFamily;
lstrcpynA( lf32.lfFaceName, font16->lfFaceName, LF_FACESIZE );
if ((lpChFont->Flags & CF_ENABLETEMPLATE) || (lpChFont->Flags & CF_ENABLETEMPLATEHANDLE))
{
if (lpChFont->Flags & CF_ENABLETEMPLATE)
template = resource_to_dialog32(lpChFont->hInstance, MapSL(lpChFont->lpTemplateName), NULL);
else
template = handle_to_dialog32(lpChFont->hInstance, NULL);
cf32.hInstance = (HGLOBAL)template;
cf32.Flags |= CF_ENABLETEMPLATEHANDLE;
}
if (lpChFont->Flags & CF_ENABLEHOOK)
{
COMMDLGTHUNK *thunk = allocate_thunk(cf, (SEGPTR)lpChFont->lpfnHook);
cf32.Flags |= CF_ENABLEHOOK;
cf32.lpfnHook = (LPCFHOOKPROC)thunk;
}
if (!ChooseFontA( &cf32 )) return FALSE;
lpChFont->iPointSize = cf32.iPointSize;
lpChFont->Flags = cf32.Flags;
lpChFont->rgbColors = cf32.rgbColors;
lpChFont->lCustData = cf32.lCustData;
lpChFont->nFontType = cf32.nFontType;
font16->lfHeight = lf32.lfHeight;
font16->lfWidth = lf32.lfWidth;
font16->lfEscapement = lf32.lfEscapement;
font16->lfOrientation = lf32.lfOrientation;
font16->lfWeight = lf32.lfWeight;
font16->lfItalic = lf32.lfItalic;
font16->lfUnderline = lf32.lfUnderline;
font16->lfStrikeOut = lf32.lfStrikeOut;
font16->lfCharSet = lf32.lfCharSet;
font16->lfOutPrecision = lf32.lfOutPrecision;
font16->lfClipPrecision = lf32.lfClipPrecision;
font16->lfQuality = lf32.lfQuality;
font16->lfPitchAndFamily = lf32.lfPitchAndFamily;
lstrcpynA( font16->lfFaceName, lf32.lfFaceName, LF_FACESIZE );
delete_thunk(cf32.lpfnHook);
HeapFree(GetProcessHeap(), 0, template);
return TRUE;
}
/***********************************************************************
* FormatCharDlgProc (COMMDLG.16)
FIXME: 1. some strings are "hardcoded", but it's better load from sysres
2. some CF_.. flags are not supported
3. some TType extensions
*/
BOOL16 CALLBACK FormatCharDlgProc16(HWND16 hDlg16, UINT16 message,
WPARAM16 wParam, LPARAM lParam)
{
FIXME( "%04x %04x %04x %08lx: stub\n", hDlg16, message, wParam, lParam );
return FALSE;
}
================================================
FILE: commdlg/printdlg.c
================================================
/*
* COMMDLG - Print Dialog
*
* Copyright 1994 Martin Ayotte
* Copyright 1996 Albrecht Kleine
* Copyright 1999 Klaas van Gend
* Copyright 2000 Huw D M Davies
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include
#include
#include
#include
#include
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "wine/wingdi16.h"
#include "winuser.h"
#include "wine/winuser16.h"
#include "commdlg.h"
#include "dlgs.h"
#include "wine/debug.h"
#include "cderr.h"
#include "winspool.h"
#include "cdlg16.h"
WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
/* Maximum length of a device name */
#define CCHDEVICENAME16 32
/* Maximum length of a paper name */
#define CCHPAPERNAME16 64
#pragma pack(push, 1)
typedef struct {
char dmDeviceName[CCHDEVICENAME16];
UINT16 dmSpecVersion;
UINT16 dmDriverVersion;
UINT16 dmSize;
UINT16 dmDriverExtra;
DWORD dmFields;
INT16 dmOrientation;
INT16 dmPaperSize;
INT16 dmPaperLength;
INT16 dmPaperWidth;
INT16 dmScale;
INT16 dmCopies;
INT16 dmDefaultSource;
INT16 dmPrintQuality;
INT16 dmColor;
INT16 dmDuplex;
INT16 dmYResolution;
INT16 dmTTOption;
} DEVMODE16, *LPDEVMODE16;
#pragma pack(pop)
//sizeof(DEVMODE16) != sizeof(DEVMODEA)
void DEVMODE16To32(CONST DEVMODE16 *src, LPDEVMODEA dst)
{
memcpy(dst->dmDeviceName, src->dmDeviceName, min(CCHDEVICENAME16, CCHDEVICENAME));
dst->dmDeviceName[CCHDEVICENAME - 1] = 0;
dst->dmSpecVersion = 0x30a;
dst->dmDriverVersion = src->dmDriverVersion;
dst->dmSize = sizeof(DEVMODEA);
dst->dmDriverExtra = 0;
dst->dmFields = src->dmFields & 0x7fbf;
dst->dmOrientation = src->dmOrientation;
dst->dmPaperSize = src->dmPaperSize;
dst->dmPaperLength = src->dmPaperLength;
dst->dmPaperWidth = src->dmPaperWidth;
dst->dmScale = src->dmScale;
dst->dmCopies = src->dmCopies;
dst->dmDefaultSource = src->dmDefaultSource;
dst->dmPrintQuality = src->dmPrintQuality;
dst->dmColor = src->dmColor;
dst->dmDuplex = src->dmDuplex;
dst->dmYResolution = src->dmYResolution;
dst->dmTTOption = src->dmTTOption;
}
void DEVMODE32To16(LPDEVMODE16 dst, const LPDEVMODEA src)
{
memcpy(dst->dmDeviceName, src->dmDeviceName, min(CCHDEVICENAME16, CCHDEVICENAME));
dst->dmDeviceName[CCHDEVICENAME16 - 1] = 0;
dst->dmSpecVersion = 0x30a;
dst->dmDriverVersion = src->dmDriverVersion;
dst->dmSize = sizeof(DEVMODE16);
dst->dmDriverExtra = 0;
dst->dmFields = src->dmFields & 0x7fbf;
dst->dmOrientation = src->dmOrientation;
dst->dmPaperSize = src->dmPaperSize;
dst->dmPaperLength = src->dmPaperLength;
dst->dmPaperWidth = src->dmPaperWidth;
dst->dmScale = src->dmScale;
dst->dmCopies = src->dmCopies;
dst->dmDefaultSource = src->dmDefaultSource;
dst->dmPrintQuality = src->dmPrintQuality;
dst->dmColor = src->dmColor;
dst->dmDuplex = src->dmDuplex;
dst->dmYResolution = src->dmYResolution;
dst->dmTTOption = src->dmTTOption;
}
static void global_handle_to_16( HGLOBAL16 *h16, HGLOBAL handle )
{
DWORD size;
HGLOBAL16 ret;
if (!handle) return;
size = GlobalSize( handle );
if (*h16) ret = GlobalReAlloc16( *h16, size, GMEM_MOVEABLE );
else ret = GlobalAlloc16( GMEM_MOVEABLE, size );
if (ret)
{
void *src = GlobalLock( handle );
void *dst = GlobalLock16( ret );
memcpy( dst, src, size );
GlobalUnlock( handle );
GlobalUnlock16( ret );
*h16 = ret;
}
}
static HGLOBAL global_handle_from_16( HGLOBAL16 handle )
{
DWORD size;
HGLOBAL ret;
if (!handle) return 0;
size = GlobalSize16( handle );
if ((ret = GlobalAlloc( GMEM_MOVEABLE, size )))
{
void *src = GlobalLock16( handle );
void *dst = GlobalLock( ret );
memcpy( dst, src, size );
GlobalUnlock16( handle );
GlobalUnlock( ret );
}
return ret;
}
LPDLGTEMPLATEA resource_to_dialog32(HINSTANCE16 hInst, LPCSTR name, WORD *res)
{
HRSRC16 reso = FindResource16(hInst, name, (LPCSTR)RT_DIALOG);
HGLOBAL16 handle = LoadResource16(hInst, reso);
DWORD size = SizeofResource16(hInst, reso);
SEGPTR ptr16 = WOWGlobalLock16(handle);
DWORD size2;
LPDLGTEMPLATEA r = dialog_template16_to_template32(hInst, ptr16, &size2, NULL);
if (!res)
FreeResource16(handle);
else
res = ptr16;
return r;
}
LPDLGTEMPLATEA handle_to_dialog32(HGLOBAL16 hg, WORD *res)
{
DWORD size2;
SEGPTR ptr16 = WOWGlobalLock16(hg);
LPDLGTEMPLATEA r = dialog_template16_to_template32(NULL, ptr16, &size2, NULL);
if (!res)
WOWGlobalUnlock16(hg);
else
res = ptr16;
return r;
}
/**********************************************************************
*
* 16 bit commdlg
*/
/***********************************************************************
* PrintDlg (COMMDLG.20)
*
* Displays the PRINT dialog box, which enables the user to specify
* specific properties of the print job.
*
* RETURNS
* nonzero if the user pressed the OK button
* zero if the user cancelled the window or an error occurred
*
* BUGS
* * calls up to the 32-bit versions of the Dialogs, which look different
* * Customizing is *not* implemented.
*/
BOOL16 WINAPI PrintDlg16( SEGPTR pd )
{
LPPRINTDLG16 lppd = MapSL(pd);
PRINTDLGA pd32;
BOOL ret;
HINSTANCE16 hInst;
LPDLGTEMPLATEA template_setup = NULL;
LPDLGTEMPLATEA template_print = NULL;
HGLOBAL *hdma = NULL;
if (lppd->hDevMode)
{
hdma = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof(DEVMODEA));
DEVMODE16To32(GlobalLock16(lppd->hDevMode), GlobalLock(hdma));
GlobalUnlock(hdma);
GlobalUnlock16(lppd->hDevMode);
}
if (!lppd) return PrintDlgA(NULL); /* generate failure with CDERR_INITIALIZATION */
pd32.lStructSize = sizeof(pd32);
pd32.Flags = lppd->Flags & ~(PD_ENABLEPRINTTEMPLATE | PD_ENABLEPRINTTEMPLATEHANDLE |
PD_ENABLESETUPTEMPLATE | PD_ENABLESETUPTEMPLATEHANDLE |
PD_ENABLEPRINTHOOK | PD_ENABLESETUPHOOK);
pd32.hwndOwner = HWND_32(lppd->hwndOwner);
pd32.hDevMode = hdma;
pd32.hDevNames = global_handle_from_16( lppd->hDevNames );
pd32.nFromPage = lppd->nFromPage;
pd32.nToPage = lppd->nToPage;
pd32.nMinPage = lppd->nMinPage;
pd32.nMaxPage = lppd->nMaxPage;
pd32.nCopies = lppd->nCopies;
pd32.lpfnPrintHook = NULL;
pd32.lpfnSetupHook = NULL;
hInst = lppd->hInstance;
if ((lppd->Flags & PD_ENABLEPRINTTEMPLATE) || (lppd->Flags & PD_ENABLEPRINTTEMPLATEHANDLE))
{
if (lppd->Flags & PD_ENABLEPRINTTEMPLATE)
template_print = resource_to_dialog32(hInst, MapSL(lppd->lpPrintTemplateName), NULL);
else
template_print = handle_to_dialog32(lppd->hPrintTemplate, NULL);
pd32.hPrintTemplate = (HGLOBAL)template_print;
pd32.Flags |= PD_ENABLEPRINTTEMPLATEHANDLE;
}
if ((lppd->Flags & PD_ENABLESETUPTEMPLATE) || (lppd->Flags & PD_ENABLESETUPTEMPLATEHANDLE))
{
if (lppd->Flags & PD_ENABLESETUPTEMPLATE)
template_setup = resource_to_dialog32(hInst, MapSL(lppd->lpSetupTemplateName), NULL);
else
template_setup = handle_to_dialog32(lppd->hSetupTemplate, NULL);
pd32.hSetupTemplate = (HGLOBAL)template_setup;
pd32.Flags |= PD_ENABLESETUPTEMPLATEHANDLE;
}
if (lppd->Flags & PD_ENABLEPRINTHOOK)
{
COMMDLGTHUNK *thunk = allocate_thunk(pd, (SEGPTR)lppd->lpfnPrintHook);
pd32.Flags |= PD_ENABLEPRINTHOOK;
pd32.lpfnPrintHook = (LPPRINTHOOKPROC)thunk;
}
if (lppd->Flags & PD_ENABLESETUPHOOK)
{
COMMDLGTHUNK *thunk = allocate_thunk(pd, (SEGPTR)lppd->lpfnSetupHook);
pd32.Flags |= PD_ENABLESETUPHOOK;
pd32.lpfnSetupHook = (LPSETUPHOOKPROC)thunk;
}
/* Generate failure with CDERR_STRUCTSIZE, when needed */
if (lppd->lStructSize != sizeof(PRINTDLG16)) pd32.lStructSize--;
if ((ret = PrintDlgA( &pd32 )))
{
lppd->hDC = HDC_16( pd32.hDC );
global_handle_to_16( &lppd->hDevNames, pd32.hDevNames );
lppd->nFromPage = pd32.nFromPage;
lppd->nToPage = pd32.nToPage;
lppd->nMinPage = pd32.nMinPage;
lppd->nMaxPage = pd32.nMaxPage;
lppd->nCopies = pd32.nCopies;
if (pd32.hDevMode)
{
if (!lppd->hDevMode)
lppd->hDevMode = GlobalAlloc16(GMEM_MOVEABLE, sizeof(DEVMODE16));
DEVMODE32To16(GlobalLock16(lppd->hDevMode), GlobalLock(pd32.hDevMode));
GlobalUnlock(pd32.hDevMode);
GlobalUnlock16(lppd->hDevMode);
}
}
GlobalFree( pd32.hDevNames );
GlobalFree( pd32.hDevMode );
delete_thunk(pd32.lpfnPrintHook);
delete_thunk(pd32.lpfnSetupHook);
HeapFree(GetProcessHeap(), 0, template_setup);
HeapFree(GetProcessHeap(), 0, template_print);
return ret;
}
/***********************************************************************
* PrintDlgProc (COMMDLG.21)
*/
BOOL16 CALLBACK PrintDlgProc16(HWND16 hDlg16, UINT16 uMsg, WPARAM16 wParam, LPARAM lParam)
{
FIXME( "%04x %04x %04x %08lx: stub\n", hDlg16, uMsg, wParam, lParam );
return FALSE;
}
/***********************************************************************
* PrintSetupDlgProc (COMMDLG.22)
*/
BOOL16 CALLBACK PrintSetupDlgProc16(HWND16 hWnd16, UINT16 wMsg, WPARAM16 wParam,
LPARAM lParam)
{
HWND hWnd = HWND_32(hWnd16);
switch (wMsg)
{
case WM_INITDIALOG:
TRACE("WM_INITDIALOG lParam=%08lX\n", lParam);
ShowWindow(hWnd, SW_SHOWNORMAL);
return (TRUE);
case WM_COMMAND:
switch (wParam) {
case IDOK:
EndDialog(hWnd, TRUE);
return(TRUE);
case IDCANCEL:
EndDialog(hWnd, FALSE);
return(TRUE);
}
return(FALSE);
}
return FALSE;
}
================================================
FILE: commdlg/resource.h
================================================
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ ŐꂽCN[h t@CB
// commdlg.rc Ŏgp
//
#define IDB_BITMAP1 101
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 102
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
================================================
FILE: compobj/CMakeLists.txt
================================================
file(GLOB SOURCE *.c *.cpp *.rc)
add_library(compobj SHARED ${SOURCE} ${CMAKE_CURRENT_BINARY_DIR}/compobj.def compobj.dll16.obj)
include_directories(../wine ${CMAKE_BINARY_DIR})
add_definitions(-D_X86_ -D__WINESRC__ -D__i386__ -DHAVE_STRNCASECMP -DHAVE__STRNICMP -D_WINTERNL_ -DNtCurrentTeb=NtCurrentTeb__ -DDECLSPEC_HIDDEN= -Dstrncasecmp=_strnicmp)
spec_build(compobj.dll16 compobj)
target_link_libraries(compobj libwine winecrt0 krnl386 ole2 ole32.lib)
set_target_properties(compobj PROPERTIES SUFFIX ".dll16")
================================================
FILE: compobj/Makefile.in
================================================
MODULE = compobj.dll16
IMPORTS = uuid ole32 advapi32
EXTRADLLFLAGS = -m16 -Wb,--main-module,ole32.dll
C_SRCS = compobj.c
================================================
FILE: compobj/compobj.c
================================================
/*
* 16 bit ole functions
*
* Copyright 1995 Martin von Loewis
* Copyright 1998 Justin Bradford
* Copyright 1999 Francis Beaudet
* Copyright 1999 Sylvain St-Germain
* Copyright 2002 Marcus Meissner
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#include
#include
#include
#include
#include
#include "windef.h"
#include "winbase.h"
#include "winuser.h"
#include "objbase.h"
#include "ole2.h"
#include "rpc.h"
#include "winerror.h"
#include "winreg.h"
#include "wownt32.h"
#include "wtypes.h"
#include "wine/unicode.h"
#include "wine/winbase16.h"
#include "wine/debug.h"
#include "../ole2/ifs.h"
WINE_DEFAULT_DEBUG_CHANNEL(ole);
WINE_DECLARE_DEBUG_CHANNEL(olemalloc);
#define CHARS_IN_GUID 39
static HTASK16 hETask = 0;
static WORD Table_ETask[62];
static LPMALLOC16 currentMalloc16=NULL;
/* --- IMalloc16 implementation */
typedef struct
{
IMalloc16 IMalloc16_iface;
DWORD ref;
} IMalloc16Impl;
static inline IMalloc16Impl *impl_from_IMalloc16(IMalloc16 *iface)
{
return CONTAINING_RECORD(iface, IMalloc16Impl, IMalloc16_iface);
}
/******************************************************************************
* IMalloc16_QueryInterface [COMPOBJ.500]
*/
HRESULT CDECL IMalloc16_fnQueryInterface(IMalloc16* iface,REFIID refiid,LPVOID *obj) {
IMalloc16Impl *This = impl_from_IMalloc16(iface);
TRACE_(olemalloc)("(%p)->QueryInterface(%s,%p)\n",This,debugstr_guid(refiid),obj);
if ( !memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown)) ||
!memcmp(&IID_IMalloc,refiid,sizeof(IID_IMalloc))
) {
*obj = This;
return 0;
}
return OLE_E_ENUM_NOMORE;
}
/******************************************************************************
* IMalloc16_AddRef [COMPOBJ.501]
*/
ULONG CDECL IMalloc16_fnAddRef(IMalloc16* iface) {
IMalloc16Impl *This = impl_from_IMalloc16(iface);
TRACE_(olemalloc)("(%p)->AddRef()\n",This);
return 1; /* cannot be freed */
}
/******************************************************************************
* IMalloc16_Release [COMPOBJ.502]
*/
ULONG CDECL IMalloc16_fnRelease(IMalloc16* iface) {
IMalloc16Impl *This = impl_from_IMalloc16(iface);
TRACE_(olemalloc)("(%p)->Release()\n",This);
return 1; /* cannot be freed */
}
/******************************************************************************
* IMalloc16_Alloc [COMPOBJ.503]
*/
SEGPTR CDECL IMalloc16_fnAlloc(IMalloc16* iface,DWORD cb) {
IMalloc16Impl *This = impl_from_IMalloc16(iface);
LPVOID a = HeapAlloc( GetProcessHeap(), 0, cb );
SEGPTR s = MapLS(a);
TRACE_(olemalloc)("(%p)->Alloc(%d)=>%p(%04x:%04x)\n",This,cb,a,SELECTOROF(s),OFFSETOF(s));
return s;
}
/******************************************************************************
* IMalloc16_Free [COMPOBJ.505]
*/
VOID CDECL IMalloc16_fnFree(IMalloc16* iface,SEGPTR pv)
{
void *ptr = MapSL(pv);
IMalloc16Impl *This = impl_from_IMalloc16(iface);
TRACE_(olemalloc)("(%p)->Free(%p(%04x:%04x))\n",This,ptr,SELECTOROF(pv),OFFSETOF(pv));
// UnMapLS(pv);
/*
* Corel Move 5.0 passes the allocated pointer plus 4 bytes.
* https://support.microsoft.com/en-us/help/286470/how-to-use-pageheap-exe-in-windows-xp-windows-2000-and-windows-server
* The Windows heap managers (all versions) have always guaranteed that the
* heap allocations have a start address that is 8-byte aligned (on 64-bit
* platforms the alignment is 16-bytes).
*/
HeapFree( GetProcessHeap(), 0, (LPVOID)((SIZE_T)ptr & ~7) );
}
/******************************************************************************
* IMalloc16_Realloc [COMPOBJ.504]
*/
SEGPTR CDECL IMalloc16_fnRealloc(IMalloc16* iface,SEGPTR pv,DWORD cb)
{
SEGPTR ret;
IMalloc16Impl *This = impl_from_IMalloc16(iface);
TRACE_(olemalloc)("(%p)->Realloc(%08x,%d)\n",This,pv,cb);
if (!pv)
ret = IMalloc16_fnAlloc(iface, cb);
else if (cb) {
ret = MapLS( HeapReAlloc( GetProcessHeap(), 0, MapSL(pv), cb ) );
UnMapLS(pv);
} else {
IMalloc16_fnFree(iface, pv);
ret = 0;
}
return ret;
}
/******************************************************************************
* IMalloc16_GetSize [COMPOBJ.506]
*/
DWORD CDECL IMalloc16_fnGetSize(IMalloc16* iface,SEGPTR pv)
{
IMalloc16Impl *This = impl_from_IMalloc16(iface);
TRACE_(olemalloc)("(%p)->GetSize(%08x)\n",This,pv);
return HeapSize( GetProcessHeap(), 0, MapSL(pv) );
}
/******************************************************************************
* IMalloc16_DidAlloc [COMPOBJ.507]
*/
INT16 CDECL IMalloc16_fnDidAlloc(IMalloc16* iface,LPVOID pv) {
IMalloc16Impl *This = impl_from_IMalloc16(iface);
TRACE_(olemalloc)("(%p)->DidAlloc(%p)\n",This,pv);
return (INT16)-1;
}
/******************************************************************************
* IMalloc16_HeapMinimize [COMPOBJ.508]
*/
LPVOID CDECL IMalloc16_fnHeapMinimize(IMalloc16* iface) {
IMalloc16Impl *This = impl_from_IMalloc16(iface);
TRACE_(olemalloc)("(%p)->HeapMinimize()\n",This);
return NULL;
}
/******************************************************************************
* IMalloc16_Constructor [VTABLE]
*/
static LPMALLOC16
IMalloc16_Constructor(void)
{
static IMalloc16Vtbl vt16;
static SEGPTR msegvt16;
IMalloc16Impl* This;
HMODULE16 hcomp = GetModuleHandle16("COMPOBJ");
This = HeapAlloc( GetProcessHeap(), 0, sizeof(IMalloc16Impl) );
if (!msegvt16)
{
#define VTENT(x) vt16.x = (void*)GetProcAddress16(hcomp,"IMalloc16_"#x);assert(vt16.x)
VTENT(QueryInterface);
VTENT(AddRef);
VTENT(Release);
VTENT(Alloc);
VTENT(Realloc);
VTENT(Free);
VTENT(GetSize);
VTENT(DidAlloc);
VTENT(HeapMinimize);
#undef VTENT
msegvt16 = MapLS( &vt16 );
}
This->IMalloc16_iface.lpVtbl = (const IMalloc16Vtbl*)msegvt16;
This->ref = 1;
return (LPMALLOC16)MapLS( This );
}
/******************************************************************************
* CoBuildVersion [COMPOBJ.1]
*/
DWORD WINAPI CoBuildVersion16(void)
{
return CoBuildVersion();
}
typedef struct
{
SEGPTR malloc16;
} ole16_task_data;
static BOOL init_current_task_tls;
static DWORD current_task_tls;
static ole16_task_data *get_current_task_data()
{
ole16_task_data *d;
if (!init_current_task_tls)
{
current_task_tls = TlsAlloc();
init_current_task_tls = TRUE;
}
d = (ole16_task_data*)TlsGetValue(current_task_tls);
if (!d)
{
d = (ole16_task_data*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ole16_task_data));
TlsSetValue(current_task_tls, d);
}
return d;
}
SEGPTR shared_malloc16;
HRESULT WINAPI get_task_imalloc16(SEGPTR *lpMalloc)
{
ole16_task_data *d = get_current_task_data();
if (!d->malloc16)
{
*lpMalloc = 0;
ERR("CO_E_NOTINITIALIZED\n");
return CO_E_NOTINITIALIZED;
}
*lpMalloc = d->malloc16;
return S_OK;
}
/***********************************************************************
* CoGetMalloc [COMPOBJ.4]
*
* Retrieve the current win16 IMalloc interface.
*
* RETURNS
* The current win16 IMalloc
*/
HRESULT WINAPI CoGetMalloc16(
MEMCTX dwMemContext, /* [in] memory context */
SEGPTR * lpMalloc /* [out] current win16 malloc interface */
) {
ole16_task_data *d;
if (dwMemContext == MEMCTX_SHARED)
{
if (!shared_malloc16)
{
shared_malloc16 = IMalloc16_Constructor();
}
*lpMalloc = shared_malloc16;
return S_OK;
}
d = get_current_task_data();
if (!d->malloc16)
{
*lpMalloc = 0;
ERR("CO_E_NOTINITIALIZED\n");
return CO_E_NOTINITIALIZED;
}
if (dwMemContext == MEMCTX_TASK)
{
*lpMalloc = d->malloc16;
IMalloc16_AddRef(d->malloc16);
return S_OK;
}
*lpMalloc = 0;
return E_INVALIDARG16;
}
/***********************************************************************
* CoCreateStandardMalloc [COMPOBJ.71]
*/
HRESULT WINAPI CoCreateStandardMalloc16(MEMCTX dwMemContext,
SEGPTR *lpMalloc)
{
/* FIXME: docu says we shouldn't return the same allocator as in
* CoGetMalloc16 */
*lpMalloc = IMalloc16_Constructor();
return S_OK;
}
/******************************************************************************
* CoInitialize [COMPOBJ.2]
* Set the win16 IMalloc used for memory management
*/
HRESULT WINAPI CoInitialize16(
SEGPTR lpReserved /* [in] pointer to win16 malloc interface */
) {
ole16_task_data *d = get_current_task_data();
if (d->malloc16)
return S_FALSE;
if (!lpReserved)
{
lpReserved = IMalloc16_Constructor();
}
d->malloc16 = (LPMALLOC16)lpReserved;
TRACE("IMalloc->QueryInterface: %08x\n", GET_SEGPTR_METHOD_ADDR(IMalloc16, lpReserved, QueryInterface));
TRACE("IMalloc->AddRef: %08x\n", GET_SEGPTR_METHOD_ADDR(IMalloc16, lpReserved, AddRef));
TRACE("IMalloc->Release: %08x\n", GET_SEGPTR_METHOD_ADDR(IMalloc16, lpReserved, Release));
TRACE("IMalloc->Alloc: %08x\n", GET_SEGPTR_METHOD_ADDR(IMalloc16, lpReserved, Alloc));
TRACE("IMalloc->Realloc: %08x\n", GET_SEGPTR_METHOD_ADDR(IMalloc16, lpReserved, Realloc));
TRACE("IMalloc->Free: %08x\n", GET_SEGPTR_METHOD_ADDR(IMalloc16, lpReserved, Free));
TRACE("IMalloc->GetSize: %08x\n", GET_SEGPTR_METHOD_ADDR(IMalloc16, lpReserved, GetSize));
TRACE("IMalloc->DidAlloc: %08x\n", GET_SEGPTR_METHOD_ADDR(IMalloc16, lpReserved, DidAlloc));
TRACE("IMalloc->HeapMinimize: %08x\n", GET_SEGPTR_METHOD_ADDR(IMalloc16, lpReserved, HeapMinimize));
IMalloc16_AddRef(d->malloc16);
return S_OK;
}
/***********************************************************************
* CoUninitialize [COMPOBJ.3]
* Don't know what it does.
* 3-Nov-98 -- this was originally misspelled, I changed it to what I
* believe is the correct spelling
*/
void WINAPI CoUninitialize16(void)
{
ole16_task_data *d = get_current_task_data();
TRACE("()\n");
if (d->malloc16)
{
IMalloc16_Release(d->malloc16);
}
CoFreeAllLibraries();
}
/***********************************************************************
* CoFreeUnusedLibraries [COMPOBJ.17]
*/
void WINAPI CoFreeUnusedLibraries16(void)
{
CoFreeUnusedLibraries();
}
/***********************************************************************
* IsEqualGUID [COMPOBJ.18]
*
* Compares two Unique Identifiers.
*
* RETURNS
* TRUE if equal
*/
BOOL16 WINAPI IsEqualGUID16(
GUID* g1, /* [in] unique id 1 */
GUID* g2) /* [in] unique id 2 */
{
return !memcmp( g1, g2, sizeof(GUID) );
}
HRESULT WINAPI guid_str_to_clsid(LPCOLESTR16 idstr, CLSID *id);
HRESULT WINAPI progid_to_clsid(LPCOLESTR16 idstr, CLSID *id);
HRESULT WINAPI IIDFromString16(LPSTR lpsz, LPIID lpiid)
{
HRESULT r;
if (!lpiid)
return E_INVALIDARG16;
if (!lpsz)
{
memset(lpiid, 0, sizeof(CLSID));
return S_OK;
}
r = guid_str_to_clsid((LPCOLESTR16)lpsz, (CLSID*)lpiid);
if (r == CO_E_CLASSSTRING)
r = CO_E_IIDSTRING;
return r;
}
/******************************************************************************
* CLSIDFromString [COMPOBJ.20]
* Converts a unique identifier from its string representation into
* the GUID struct.
*
* Class id: DWORD-WORD-WORD-BYTES[2]-BYTES[6]
*
* RETURNS
* the converted GUID
*/
HRESULT WINAPI CLSIDFromString16(
LPCOLESTR16 idstr, /* [in] string representation of (guid or ProgId) */
CLSID *id) /* [out] GUID converted from string */
{
HRESULT r = guid_str_to_clsid(idstr, id);
if (SUCCEEDED(r))
return r;
return progid_to_clsid(idstr, id);
}
HRESULT WINAPI guid_str_to_clsid(LPCOLESTR16 idstr, CLSID *id)
{
const BYTE *s;
int i;
BYTE table[256];
/* validate the CLSID string */
if (strlen(idstr) != 38)
goto invalid_guid;
s = (const BYTE *) idstr;
if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
goto invalid_guid;
for (i=1; i<37; i++) {
if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
if (!(((s[i] >= '0') && (s[i] <= '9')) ||
((s[i] >= 'a') && (s[i] <= 'f')) ||
((s[i] >= 'A') && (s[i] <= 'F'))))
goto invalid_guid;
}
TRACE("%s -> %p\n", s, id);
/* quick lookup table */
memset(table, 0, 256);
for (i = 0; i < 10; i++) {
table['0' + i] = i;
}
for (i = 0; i < 6; i++) {
table['A' + i] = i+10;
table['a' + i] = i+10;
}
/* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]);
id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
/* these are just sequential bytes */
id->Data4[0] = table[s[20]] << 4 | table[s[21]];
id->Data4[1] = table[s[22]] << 4 | table[s[23]];
id->Data4[2] = table[s[25]] << 4 | table[s[26]];
id->Data4[3] = table[s[27]] << 4 | table[s[28]];
id->Data4[4] = table[s[29]] << 4 | table[s[30]];
id->Data4[5] = table[s[31]] << 4 | table[s[32]];
id->Data4[6] = table[s[33]] << 4 | table[s[34]];
id->Data4[7] = table[s[35]] << 4 | table[s[36]];
return S_OK;
invalid_guid:
return CO_E_CLASSSTRING;
}
HRESULT WINAPI progid_to_clsid(LPCOLESTR16 idstr, CLSID *id)
{
HKEY hkey = NULL;
CHAR clsid[50];
DWORD cbclsid = sizeof(clsid);
LPOLESTR w;
HRESULT r;
if (RegOpenKey16(HKEY_CLASSES_ROOT, idstr, &hkey))
{
goto error;
}
if (RegQueryValue16(hkey, "CLSID", clsid, &cbclsid))
{
RegCloseKey16(hkey);
goto error;
}
RegCloseKey16(hkey);
return guid_str_to_clsid(clsid, id);
error:
w = strdupAtoW(idstr);
r = CLSIDFromString(w, id);
HeapFree(GetProcessHeap(), 0, w);
return hresult32_16(r);
}
/******************************************************************************
* _xmalloc16 [internal]
* Allocates size bytes from the standard ole16 allocator.
*
* RETURNS
* the allocated segmented pointer and a HRESULT
*/
static HRESULT
_xmalloc16(DWORD size, SEGPTR *ptr) {
LPMALLOC16 mllc;
DWORD args[2];
if (get_task_imalloc16(&mllc))
return E_OUTOFMEMORY;
args[0] = (DWORD)mllc;
args[1] = size;
/* No need for a Callback entry, we have WOWCallback16Ex which does
* everything we need.
*/
if (!WOWCallback16Ex(
(DWORD)((const IMalloc16Vtbl*)MapSL(
(SEGPTR)((LPMALLOC16)MapSL((SEGPTR)mllc))->lpVtbl )
)->Alloc,
WCB16_CDECL,
2*sizeof(DWORD),
(LPVOID)args,
(LPDWORD)ptr
)) {
ERR("CallTo16 IMalloc16 (%d) failed\n",size);
return E_FAIL;
}
return S_OK;
}
/******************************************************************************
* StringFromCLSID [COMPOBJ.19]
* StringFromIID [COMPOBJ.14]
* Converts a GUID into the respective string representation.
* The target string is allocated using the OLE IMalloc.
*
* RETURNS
* the string representation and HRESULT
*/
HRESULT WINAPI StringFromCLSID16(
REFCLSID id, /* [in] the GUID to be converted */
LPOLESTR16 *idstr ) /* [out] a pointer to a to-be-allocated segmented pointer pointing to the resulting string */
{
WCHAR buffer[40];
HRESULT ret;
ret = _xmalloc16(40,(SEGPTR*)idstr);
if (ret != S_OK)
return ret;
StringFromGUID2( id, buffer, 40 );
WideCharToMultiByte( CP_ACP, 0, buffer, -1, MapSL((SEGPTR)*idstr), 40, NULL, NULL );
return ret;
}
/******************************************************************************
* ProgIDFromCLSID [COMPOBJ.62]
*
* Converts a class id into the respective Program ID. (By using a registry lookup)
*
* RETURNS
* S_OK on success
* riid associated with the progid
*/
HRESULT WINAPI ProgIDFromCLSID16(
REFCLSID clsid, /* [in] class id as found in registry */
LPOLESTR16 *lplpszProgID )/* [out] associated Program ID */
{
LPOLESTR progid;
HRESULT ret;
if (!lplpszProgID)
{
return E_INVALIDARG16;
}
ret = ProgIDFromCLSID( clsid, &progid );
if (ret == S_OK)
{
INT len = WideCharToMultiByte( CP_ACP, 0, progid, -1, NULL, 0, NULL, NULL );
ret = _xmalloc16(len, (SEGPTR*)lplpszProgID);
if (ret == S_OK)
WideCharToMultiByte( CP_ACP, 0, progid, -1, MapSL((SEGPTR)*lplpszProgID), len, NULL, NULL );
CoTaskMemFree( progid );
}
else
{
*lplpszProgID = 0;
}
return ret;
}
/***********************************************************************
* LookupETask (COMPOBJ.94)
*/
HRESULT WINAPI LookupETask16(HTASK16 *hTask,LPVOID p) {
FIXME("(%p,%p),stub!\n",hTask,p);
if ((*hTask = GetCurrentTask()) == hETask) {
memcpy(p, Table_ETask, sizeof(Table_ETask));
}
return 0;
}
/***********************************************************************
* SetETask (COMPOBJ.95)
*/
HRESULT WINAPI SetETask16(HTASK16 hTask, LPVOID p) {
FIXME("(%04x,%p),stub!\n",hTask,p);
hETask = hTask;
return 0;
}
/***********************************************************************
* CALLOBJECTINWOW (COMPOBJ.201)
*/
HRESULT WINAPI CallObjectInWOW(LPVOID p1,LPVOID p2) {
FIXME("(%p,%p),stub!\n",p1,p2);
return 0;
}
/******************************************************************************
* CoRegisterClassObject [COMPOBJ.5]
*
* Don't know where it registers it ...
*/
HRESULT WINAPI CoRegisterClassObject16(
REFCLSID rclsid,
/*LPUNKNOWN16*/SEGPTR pUnk,
DWORD dwClsContext, /* [in] CLSCTX flags indicating the context in which to run the executable */
DWORD flags, /* [in] REGCLS flags indicating how connections are made */
LPDWORD lpdwRegister
) {
HRESULT result;
TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister
);
result = hresult32_16(CoRegisterClassObject(rclsid, (IUnknown*)iface16_32(&IID_IUnknown, pUnk), dwClsContext, flags, lpdwRegister));
TRACE("%08x\n", result);
return result;
}
/******************************************************************************
* CoRevokeClassObject [COMPOBJ.6]
*
*/
HRESULT WINAPI CoRevokeClassObject16(DWORD dwRegister) /* [in] token on class obj */
{
TRACE("(0x%08x)\n", dwRegister);
return hresult32_16(CoRevokeClassObject(dwRegister));
}
/******************************************************************************
* IsValidInterface [COMPOBJ.23]
*
* Determines whether a pointer is a valid interface.
*
* PARAMS
* punk [I] Interface to be tested.
*
* RETURNS
* TRUE, if the passed pointer is a valid interface, or FALSE otherwise.
*/
BOOL WINAPI IsValidInterface16(SEGPTR punk)
{
DWORD **ptr;
if (IsBadReadPtr16(punk,4))
return FALSE;
ptr = MapSL(punk);
if (IsBadReadPtr16((SEGPTR)ptr[0],4)) /* check vtable ptr */
return FALSE;
ptr = MapSL((SEGPTR)ptr[0]); /* ptr to first method */
if (IsBadReadPtr16((SEGPTR)ptr[0],2))
return FALSE;
return TRUE;
}
/******************************************************************************
* CoFileTimeToDosDateTime [COMPOBJ.30]
*/
BOOL16 WINAPI CoFileTimeToDosDateTime16(const FILETIME *ft, LPWORD lpDosDate, LPWORD lpDosTime)
{
return FileTimeToDosDateTime(ft, lpDosDate, lpDosTime);
}
/******************************************************************************
* CoDosDateTimeToFileTime [COMPOBJ.31]
*/
BOOL16 WINAPI CoDosDateTimeToFileTime16(WORD wDosDate, WORD wDosTime, FILETIME *ft)
{
return DosDateTimeToFileTime(wDosDate, wDosTime, ft);
}
/******************************************************************************
* CoGetCurrentProcess [COMPOBJ.34]
*/
DWORD WINAPI CoGetCurrentProcess16(void)
{
return CoGetCurrentProcess();
}
/******************************************************************************
* CoRegisterMessageFilter [COMPOBJ.27]
*/
HRESULT WINAPI CoRegisterMessageFilter16(
SEGPTR lpMessageFilter,
SEGPTR *lplpMessageFilter
) {
HRESULT result;
LPMESSAGEFILTER lpmsgf = NULL;
TRACE("(%p,%p)\n",lpMessageFilter,lplpMessageFilter);
result = hresult32_16(CoRegisterMessageFilter((IMessageFilter*)iface16_32(&IID_IMessageFilter, lpMessageFilter), lplpMessageFilter ? &lpmsgf : NULL));
if (lplpMessageFilter)
*lplpMessageFilter = iface32_16(&IID_IMessageFilter, lpmsgf);
return result;
}
/******************************************************************************
* CoLockObjectExternal [COMPOBJ.63]
*/
HRESULT WINAPI CoLockObjectExternal16(
/*LPUNKNOWN*/SEGPTR pUnk, /* [in] object to be locked */
BOOL16 fLock, /* [in] do lock */
BOOL16 fLastUnlockReleases /* [in] ? */
) {
TRACE("(%p,%d,%d)\n",pUnk,fLock,fLastUnlockReleases);
return CoLockObjectExternal((IUnknown*)iface16_32(&IID_IUnknown, pUnk), fLock, fLastUnlockReleases);
}
/***********************************************************************
* CoGetState [COMPOBJ.115]
*/
HRESULT WINAPI CoGetState16(LPDWORD state)
{
FIXME("(%p),stub!\n", state);
*state = 0;
return S_OK;
}
/***********************************************************************
* DllEntryPoint [COMPOBJ.116]
*
* Initialization code for the COMPOBJ DLL
*
* RETURNS:
*/
BOOL WINAPI COMPOBJ_DllEntryPoint(DWORD Reason, HINSTANCE16 hInst, WORD ds, WORD HeapSize, DWORD res1, WORD res2)
{
TRACE("(%08x, %04x, %04x, %04x, %08x, %04x)\n", Reason, hInst, ds, HeapSize, res1, res2);
return TRUE;
}
/***********************************************************************
* CoMemAlloc [COMPOBJ.151]
*/
SEGPTR WINAPI CoMemAlloc(DWORD size, MEMCTX dwMemContext, DWORD x) {
HRESULT hres;
SEGPTR segptr;
/* FIXME: check context handling */
TRACE("(%d, 0x%08x, 0x%08x)\n", size, dwMemContext, x);
hres = _xmalloc16(size, &segptr);
if (hres != S_OK)
return 0;
return segptr;
}
/******************************************************************************
* CLSIDFromProgID [COMPOBJ.61]
*
* Converts a program ID into the respective GUID.
*
* PARAMS
* progid [I] program id as found in registry
* riid [O] associated CLSID
*
* RETURNS
* Success: S_OK
* Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
*/
HRESULT WINAPI CLSIDFromProgID16(LPCOLESTR16 progid, LPCLSID riid)
{
char *buf,buf2[80];
LONG buf2len;
HKEY xhkey;
buf = HeapAlloc(GetProcessHeap(),0,strlen(progid)+8);
sprintf(buf,"%s\\CLSID",progid);
if (RegOpenKey16(HKEY_CLASSES_ROOT,buf,&xhkey)) {
HeapFree(GetProcessHeap(),0,buf);
return CO_E_CLASSSTRING;
}
HeapFree(GetProcessHeap(),0,buf);
buf2len = sizeof(buf2);
if (RegQueryValue16(xhkey,NULL,buf2,&buf2len)) {
RegCloseKey(xhkey);
return CO_E_CLASSSTRING;
}
RegCloseKey(xhkey);
return CLSIDFromString16(buf2,riid);
}
/******************************************************************************
* StringFromGUID2 [COMPOBJ.76]
*/
INT16 WINAPI StringFromGUID216(REFGUID id, LPOLESTR16 str, INT16 cmax)
{
static const char format[] = "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}";
if (!id || cmax < CHARS_IN_GUID) return 0;
sprintf( str, format, id->Data1, id->Data2, id->Data3,
id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] );
return CHARS_IN_GUID;
}
/***********************************************************************
* CoFileTimeNow [COMPOBJ.82]
*/
HRESULT WINAPI CoFileTimeNow16( FILETIME *lpFileTime )
{
return CoFileTimeNow( lpFileTime );
}
/***********************************************************************
* CoGetClassObject [COMPOBJ.7]
*
*/
HRESULT WINAPI CoGetClassObject16(
SEGPTR rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
SEGPTR riid, SEGPTR ppv)
{
LPVOID *ppvl = MapSL(ppv);
char idstr[CHARS_IN_GUID];
char buf_key[CHARS_IN_GUID+190], dllpath[MAX_PATH+1];
LONG dllpath_len = sizeof(dllpath);
HRESULT err_last = E_NOTIMPL16;
TRACE("CLSID: %s, IID: %s\n", debugstr_guid(MapSL(rclsid)), debugstr_guid(MapSL(riid)));
*ppvl = NULL;
StringFromGUID216(MapSL(rclsid), idstr, CHARS_IN_GUID);
if (pServerInfo) {
FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
debugstr_w(pServerInfo->pwszName), pServerInfo->pAuthInfo);
}
if (CLSCTX_INPROC_SERVER & dwClsContext)
{
HMODULE16 dll;
FARPROC16 DllGetClassObject;
WORD args[6];
DWORD dwRet;
sprintf(buf_key, "CLSID\\%s\\InprocServer", idstr);
if (RegQueryValue16(HKEY_CLASSES_ROOT, buf_key, dllpath, &dllpath_len))
{
/* 64-bit COM...? */
sprintf(buf_key, "CLSID\\%s\\InprocServer32", idstr);
dllpath_len = sizeof(dllpath);
if (!RegQueryValue16(HKEY_CLASSES_ROOT, buf_key, dllpath, &dllpath_len))
{
PVOID pv = NULL;
HRESULT result;
result = CoGetClassObject((REFCLSID)MapSL(rclsid), CLSCTX_INPROC_SERVER, pServerInfo, (REFIID)MapSL(riid), &pv);
*(SEGPTR*)MapSL(ppv) = iface32_16((REFIID)MapSL(riid), pv);
return hresult32_16(result);
}
ERR("class %s not registered\n", debugstr_guid(MapSL(rclsid)));
err_last = REGDB_E_CLASSNOTREG;
goto fail_inproc;
}
dll = LoadLibrary16(dllpath);
if (dll < 32)
{
ERR("couldn't load in-process dll %s\n", debugstr_a(dllpath));
err_last = E_ACCESSDENIED16; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
goto fail_inproc;
}
DllGetClassObject = GetProcAddress16(dll, "DllGetClassObject");
if (!DllGetClassObject)
{
ERR("couldn't find function DllGetClassObject in %s\n", debugstr_a(dllpath));
FreeLibrary16(dll);
err_last = CO_E_DLLNOTFOUND;
goto fail_inproc;
}
TRACE("calling DllGetClassObject %p\n", DllGetClassObject);
args[5] = SELECTOROF(rclsid);
args[4] = OFFSETOF(rclsid);
args[3] = SELECTOROF(riid);
args[2] = OFFSETOF(riid);
args[1] = SELECTOROF(ppv);
args[0] = OFFSETOF(ppv);
WOWCallback16Ex((DWORD) DllGetClassObject, WCB16_PASCAL, sizeof(args), args, &dwRet);
if (dwRet != S_OK)
{
ERR("DllGetClassObject returned error 0x%08x\n", dwRet);
FreeLibrary16(dll);
return dwRet;
}
return S_OK;
}
fail_inproc:
if (CLSCTX_LOCAL_SERVER & dwClsContext)
{
HRESULT result;
PVOID pv = NULL;
result = CoGetClassObject((REFCLSID)MapSL(rclsid), dwClsContext, pServerInfo, (REFIID)MapSL(riid), &pv);
*(SEGPTR*)MapSL(ppv) = iface32_16((REFCLSID)MapSL(riid), pv);
return hresult32_16(result);
}
fail_svr:
FIXME("semi-stub\n");
return err_last;
}
/******************************************************************************
* CoCreateGuid [COMPOBJ.73]
*/
HRESULT WINAPI CoCreateGuid16(GUID *pguid)
{
return CoCreateGuid( pguid );
}
/***********************************************************************
* CoCreateInstance [COMPOBJ.13]
*/
HRESULT WINAPI CoCreateInstance16(
/* REFCLSID */SEGPTR srclsid,
SEGPTR pUnkOuter,
DWORD dwClsContext,
/* REFIID */SEGPTR siid,
/* SEGPTR* */SEGPTR sppv)
{
LPVOID pv;
HRESULT result;
REFCLSID rclsid = (REFCLSID)MapSL(srclsid);
REFIID iid = (REFIID)MapSL(siid);
SEGPTR *ppv = (SEGPTR*)MapSL(sppv);
TRACE("(%s, %p, %x, %s, %p)\n",
debugstr_guid(rclsid), pUnkOuter, dwClsContext, debugstr_guid(iid),
ppv
);
result = CoCreateInstance(rclsid, (IUnknown*)iface16_32(&IID_IUnknown, pUnkOuter), dwClsContext, iid, &pv);
if (result == REGDB_E_CLASSNOTREG)
{
SEGPTR cf;
result = CoGetClassObject16(srclsid, dwClsContext, NULL, MapLS(&IID_IClassFactory), MapLS(&cf));
if (SUCCEEDED(result))
{
result = IClassFactory16_CreateInstance(cf, pUnkOuter, siid, sppv);
IClassFactory16_Release(cf);
return result;
}
return hresult32_16(result);
}
*ppv = iface32_16(iid, pv);
return hresult32_16(result);
}
/***********************************************************************
* CoDisconnectObject [COMPOBJ.15]
*/
HRESULT WINAPI CoDisconnectObject16( /*LPUNKNOWN*/SEGPTR lpUnk, DWORD reserved )
{
TRACE("(%p, 0x%08x)\n", lpUnk, reserved);
return hresult32_16(CoDisconnectObject((IUnknown*)iface16_32(&IID_IUnknown, lpUnk), reserved));
}
HRESULT WINAPI CoIsOle1Class16(REFCLSID rclsid)
{
TRACE("(%p)\n", rclsid);
return hresult32_16(CoIsOle1Class(rclsid));
}
HRESULT WINAPI FnAssert16(LPCSTR expr, LPCSTR msg, LPCSTR file, WORD line)
{
TRACE("(%s,%s,%s,%d)\n", debugstr_a(expr), debugstr_a(msg), debugstr_a(msg), line);
return S_OK;
}
HRESULT WINAPI CoGetTreatAsClass16(REFCLSID clsidOld, LPCLSID pClsidNew)
{
HRESULT r;
TRACE("(%s,%p)\n", debugstr_guid(clsidOld), pClsidNew);
r = CoGetTreatAsClass(clsidOld, pClsidNew);
return hresult32_16(r);
}
HRESULT WINAPI CoTreatAsClass16(REFCLSID clsidOld, REFCLSID clsidNew)
{
HRESULT r;
TRACE("(%s,%p)\n", debugstr_guid(clsidOld), debugstr_guid(clsidNew));
r = CoTreatAsClass(clsidOld, clsidNew);
if (r == REGDB_E_WRITEREGDB)
{
ERR("REGDB_E_WRITEREGDB\n");
}
return hresult32_16(r);
}
================================================
FILE: compobj/compobj.def
================================================
; File generated automatically from ..\compobj\compobj.dll16.spec; do not edit!
LIBRARY compobj.dll16
EXPORTS
_wine_spec_dos_header @1 DATA
get_task_imalloc16 @2
CoInitialize16 @3
CoUninitialize16 @4
StringFromGUID216 @5
CoCreateInstance16
================================================
FILE: compobj/compobj.dll16.spec
================================================
1 pascal CoBuildVersion() CoBuildVersion16
2 pascal CoInitialize(long) CoInitialize16
3 pascal CoUninitialize() CoUninitialize16
4 pascal CoGetMalloc(long ptr) CoGetMalloc16
5 pascal CoRegisterClassObject(ptr segptr long long ptr) CoRegisterClassObject16
6 pascal CoRevokeClassObject(long) CoRevokeClassObject16
7 pascal CoGetClassObject(segptr long ptr segptr segptr) CoGetClassObject16
8 stub COMARSHALINTERFACE
9 stub COUNMARSHALINTERFACE
10 stub COLOADLIBRARY
11 stub COFREELIBRARY
12 stub COFREEALLLIBRARIES
13 pascal CoCreateInstance(segptr segptr long segptr segptr) CoCreateInstance16
14 pascal StringFromIID(ptr ptr) StringFromCLSID16
15 pascal CoDisconnectObject(segptr long) CoDisconnectObject16
16 stub CORELEASEMARSHALDATA
17 pascal -ret16 CoFreeUnusedLibraries() CoFreeUnusedLibraries16
18 pascal -ret16 IsEqualGUID(ptr ptr) IsEqualGUID16
19 pascal StringFromCLSID(ptr ptr) StringFromCLSID16
20 pascal CLSIDFromString(str ptr) CLSIDFromString16
21 stub ISVALIDPTRIN
22 stub ISVALIDPTROUT
23 pascal IsValidInterface(segptr) IsValidInterface16
24 stub ISVALIDIID
25 stub RESULTFROMSCODE
26 stub GETSCODE
27 pascal CoRegisterMessageFilter(segptr ptr) CoRegisterMessageFilter16
28 stub COISHANDLERCONNECTED
29 stub SHRADDREF
30 pascal -ret16 CoFileTimeToDosDateTime(ptr ptr ptr) CoFileTimeToDosDateTime16
31 pascal -ret16 CoDosDateTimeToFileTime(word word ptr) CoDosDateTimeToFileTime16
32 stub COMARSHALHRESULT
33 stub COUNMARSHALHRESULT
34 pascal CoGetCurrentProcess() CoGetCurrentProcess16
35 stub SHRCREATE
36 pascal CoIsOle1Class(ptr) CoIsOle1Class16
37 variable _GUID_NULL(0x00000000 0x00000000 0x00000000 0x00000000)
38 variable _IID_IUnknown(0x00000000 0x00000000 0x000000c0 0x46000000)
39 variable _IID_IClassFactory(0x00000001 0x00000000 0x000000c0 0x46000000)
40 variable _IID_IMalloc(0x00000002 0x00000000 0x000000c0 0x46000000)
41 variable _IID_IMarshal(0x00000003 0x00000000 0x000000c0 0x46000000)
42 variable _IID_IRpcChannel(0x00000004 0x00000000 0x000000c0 0x46000000)
43 variable _IID_IRpcStub(0x00000005 0x00000000 0x000000c0 0x46000000)
44 variable _IID_IStubManager(0x00000006 0x00000000 0x000000c0 0x46000000)
45 variable _IID_IRpcProxy(0x00000007 0x00000000 0x000000c0 0x46000000)
46 variable _IID_IProxyManager(0x00000008 0x00000000 0x000000c0 0x46000000)
47 variable _IID_IPSFactory(0x00000009 0x00000000 0x000000c0 0x46000000)
48 variable _IID_ILockBytes(0x0000000a 0x00000000 0x000000c0 0x46000000)
49 variable _IID_IStorage(0x0000000b 0x00000000 0x000000c0 0x46000000)
50 variable _IID_IStream(0x0000000c 0x00000000 0x000000c0 0x46000000)
51 variable _IID_IEnumSTATSTG(0x0000000d 0x00000000 0x000000c0 0x46000000)
52 variable _IID_IBindCtx(0x0000000e 0x00000000 0x000000c0 0x46000000)
53 variable _IID_IMoniker(0x0000000f 0x00000000 0x000000c0 0x46000000)
54 variable _IID_IRunningObjectTable(0x00000010 0x00000000 0x000000c0 0x46000000)
55 variable _IID_IInternalMoniker(0x00000011 0x00000000 0x000000c0 0x46000000)
56 variable _IID_IRootStorage(0x00000012 0x00000000 0x000000c0 0x46000000)
57 variable _IID_IDfReserved1(0x00000013 0x00000000 0x000000c0 0x46000000)
58 variable _IID_IDfReserved2(0x00000014 0x00000000 0x000000c0 0x46000000)
59 variable _IID_IDfReserved3(0x00000015 0x00000000 0x000000c0 0x46000000)
60 variable _IID_IMessageFilter(0x00000016 0x00000000 0x000000c0 0x46000000)
61 pascal CLSIDFromProgID(str ptr) CLSIDFromProgID16
62 pascal ProgIDFromCLSID(ptr ptr) ProgIDFromCLSID16
63 pascal CoLockObjectExternal(segptr word word) CoLockObjectExternal16
64 variable _CLSID_StdMarshal(0x00000017 0x00000000 0x000000c0 0x46000000)
65 pascal CoGetTreatAsClass(ptr ptr) CoGetTreatAsClass16
66 pascal CoTreatAsClass(ptr ptr) CoTreatAsClass16
67 stub COGETSTANDARDMARSHAL
68 stub PROPAGATERESULT
69 pascal IIDFromString(str ptr) IIDFromString16
70 variable _IID_IStdMarshalInfo(0x00000018 0x00000000 0x000000c0 0x46000000)
71 pascal CoCreateStandardMalloc(long ptr) CoCreateStandardMalloc16
72 variable _IID_IExternalConnection(0x00000019 0x00000000 0x000000c0 0x46000000)
73 pascal CoCreateGuid(ptr) CoCreateGuid16
75 pascal FnAssert(str str str word) FnAssert16
76 pascal -ret16 StringFromGUID2(ptr ptr word) StringFromGUID216
77 stub COGETCLASSEXT
78 stub OLE1CLASSFROMCLSID2
79 stub CLSIDFROMOLE1CLASS
80 stub COOPENCLASSKEY
81 stub GUIDFROMSTRING
82 pascal CoFileTimeNow(ptr) CoFileTimeNow16
83 stub REMALLOCOID
84 stub REMFREEOID
85 stub REMCREATEREMOTEHANDLER
86 stub REMCONNECTTOOBJECT
87 stub REMGETINFOFORCID
88 stub LRPCCALL
89 stub LRPCDISPATCH
90 stub LRPCREGISTERMONITOR
91 stub LRPCREVOKEMONITOR
92 stub LRPCGETTHREADWINDOW
93 stub TIMERCALLBACKPROC
94 pascal LookupETask(ptr ptr) LookupETask16
95 pascal -ret16 SetETask(word ptr) SetETask16
96 stub LRPCFREEMONITORDATA
97 stub REMLOOKUPSHUNK
98 stub SHRGETSIZE
99 stub CALLTHKMGRUNINITIALIZE
100 stub ??0CARRAYFVALUE@@REC@KI@Z
101 stub ??1CARRAYFVALUE@@REC@XZ
102 stub ?ASSERTVALID@CARRAYFVALUE@@RFCXXZ
103 stub ?FREEEXTRA@CARRAYFVALUE@@RECXXZ
104 stub ?_GETAT@CARRAYFVALUE@@RFCPEXH@Z
105 stub ?GETSIZE@CARRAYFVALUE@@RFCHXZ
106 stub ?REMOVEALL@CARRAYFVALUE@@RECXXZ
107 stub SHRDESTROY
108 stub ?INDEXOF@CARRAYFVALUE@@RECHPEXII@Z
109 stub ?INSERTAT@CARRAYFVALUE@@RECHHPEXH@Z
110 stub COSETSTATE
111 stub ?REMOVEAT@CARRAYFVALUE@@RECXHH@Z
112 stub ?SETAT@CARRAYFVALUE@@RECXHPEX@Z
113 stub ?SETATGROW@CARRAYFVALUE@@RECHHPEX@Z
114 stub ?SETSIZE@CARRAYFVALUE@@RECHHH@Z
115 pascal CoGetState(ptr) CoGetState16
116 pascal DllEntryPoint(long word word word long word) COMPOBJ_DllEntryPoint
117 stub ?RELEASE@CSTDMALLOC@@VEAKXZ
118 stub ?ALLOC@CSTDMALLOC@@VEAPEXK@Z
119 stub SHRRELEASE
120 stub ?GETASSOCAT@CMAPKEYTOVALUE@@BFCPEUCASSOC@1@PEXIAEI@Z
121 stub ?SETASSOCKEY@CMAPKEYTOVALUE@@BFCHPEUCASSOC@1@PEXI@Z
122 stub ??1CMAPKEYTOVALUE@@REC@XZ
123 stub ?GETASSOCKEYPTR@CMAPKEYTOVALUE@@BFCXPEUCASSOC@1@PEPEXPEI@Z
124 stub ?NEWASSOC@CMAPKEYTOVALUE@@BECPEUCASSOC@1@IPEXI0@Z
125 stub ?SIZEASSOC@CMAPKEYTOVALUE@@BFCIXZ
126 stub ?FREEASSOC@CMAPKEYTOVALUE@@BECXPEUCASSOC@1@@Z
127 stub ?GETSTARTPOSITION@CMAPKEYTOVALUE@@RFCPEXXZ
128 stub ?GETNEXTASSOC@CMAPKEYTOVALUE@@RFCXPEPEXPEXPEI1@Z
129 stub ?COMPAREASSOCKEY@CMAPKEYTOVALUE@@BFCHPEUCASSOC@1@PEXI@Z
130 stub ?REMOVEHKEY@CMAPKEYTOVALUE@@RECHK@Z
131 stub ?GETHKEY@CMAPKEYTOVALUE@@RFCKPEXI@Z
132 stub ?GETCOUNT@CMAPKEYTOVALUE@@RFCHXZ
133 stub ?LOOKUP@CMAPKEYTOVALUE@@RFCHPEXI0@Z
134 stub ?GETASSOCVALUE@CMAPKEYTOVALUE@@BFCXPEUCASSOC@1@PEX@Z
135 stub ?REMOVEKEY@CMAPKEYTOVALUE@@RECHPEXI@Z
136 stub ?REMOVEALL@CMAPKEYTOVALUE@@RECXXZ
137 stub SHRALLOC
138 stub ?FREEASSOCKEY@CMAPKEYTOVALUE@@BFCXPEUCASSOC@1@@Z
139 stub ?SETAT@CMAPKEYTOVALUE@@RECHPEXI0@Z
140 stub ?LOOKUPHKEY@CMAPKEYTOVALUE@@RFCHKPEX@Z
141 stub ?ASSERTVALID@CMAPKEYTOVALUE@@RFCXXZ
142 stub ?SETASSOCVALUE@CMAPKEYTOVALUE@@BFCXPEUCASSOC@1@PEX@Z
143 stub ?SETATHKEY@CMAPKEYTOVALUE@@RECHKPEX@Z
144 stub ??0CMAPKEYTOVALUE@@REC@KIIHP7CIPEXI@ZI@Z
145 stub ?INITHASHTABLE@CMAPKEYTOVALUE@@BECHXZ
146 stub ?GETASSOCVALUEPTR@CMAPKEYTOVALUE@@BFCXPEUCASSOC@1@PEPEX@Z
147 stub ?LOOKUPADD@CMAPKEYTOVALUE@@RFCHPEXI0@Z
148 stub MKVDEFAULTHASHKEY
149 stub DELETE16
150 stub COMEMCTXOF
151 pascal CoMemAlloc(long long long)
152 stub COMEMFREE
153 stub SHRREALLOC
154 stub ___EXPORTEDSTUB
155 stub LRPCREGISTERWIN32SMONITOR
156 stub MYREMGETINFOFORCID
157 stub SHRFREE
158 stub OPNEW16
159 stub ADDCOINFO
160 stub CORUNMODALLOOP
161 stub COHANDLEINCOMINGCALL
162 stub COSETACKSTATE
163 stub SHRDIDALLOC
164 stub ?GETAT@CARRAYFVALUE@@RFCPEXH@Z
165 stub ?GETUPPERBOUND@CARRAYFVALUE@@RFCHXZ
166 stub OPDELETE16
167 stub ?GETSIZEVALUE@CARRAYFVALUE@@RFCHXZ
168 stub ?PROXY1632ADDREF@@ZAKPEVCPROXY1632@@@Z
# FIXME: 169 is a duplicate of 97
169 stub REMLOOKUPSHUNK_dup
170 stub ?ISEMPTY@CMAPKEYTOVALUE@@RFCHXZ
171 stub ?FREE@CSTDMALLOC@@VEAXPEX@Z
172 stub CALLTHKMGRINITIALIZE
173 stub ?REALLOC@CSTDMALLOC@@VEAPEXPEXK@Z
174 stub ?SM16RHQI@@ZAPEXPEVCSM16RELEASEHANDLER@@AFUGUID@@PEPEX@Z
175 stub ?PROXY1632METHOD10@@ZAKPEVCPROXY1632@@@Z
# FIXME: 176 is a duplicate of 154
176 stub ___EXPORTEDSTUB_dup
177 stub ?PROXY1632METHOD20@@ZAKPEVCPROXY1632@@@Z
178 stub ?PROXY1632METHOD11@@ZAKPEVCPROXY1632@@@Z
179 stub ?PROXY1632METHOD30@@ZAKPEVCPROXY1632@@@Z
180 stub ?PROXY1632METHOD21@@ZAKPEVCPROXY1632@@@Z
181 stub ?PROXY1632METHOD12@@ZAKPEVCPROXY1632@@@Z
182 stub ?PROXY1632METHOD31@@ZAKPEVCPROXY1632@@@Z
183 stub ?PROXY1632METHOD22@@ZAKPEVCPROXY1632@@@Z
184 stub ?PROXY1632METHOD13@@ZAKPEVCPROXY1632@@@Z
185 stub ?GETSIZE@CSTDMALLOC@@VEAKPEX@Z
186 stub ?PROXY1632METHOD23@@ZAKPEVCPROXY1632@@@Z
187 stub ?PROXY1632METHOD14@@ZAKPEVCPROXY1632@@@Z
188 stub ?PROXY1632METHOD24@@ZAKPEVCPROXY1632@@@Z
189 stub ?PROXY1632METHOD15@@ZAKPEVCPROXY1632@@@Z
190 stub ?PROXY1632METHOD25@@ZAKPEVCPROXY1632@@@Z
191 stub ?PROXY1632METHOD16@@ZAKPEVCPROXY1632@@@Z
192 stub ?PROXY1632METHOD26@@ZAKPEVCPROXY1632@@@Z
193 stub ?PROXY1632METHOD17@@ZAKPEVCPROXY1632@@@Z
194 stub ?PROXY1632METHOD27@@ZAKPEVCPROXY1632@@@Z
195 stub ?PROXY1632METHOD18@@ZAKPEVCPROXY1632@@@Z
196 stub ?PROXY1632METHOD28@@ZAKPEVCPROXY1632@@@Z
197 stub ?ADDREF@CSTDMALLOC@@VEAKXZ
198 stub ?PROXY1632METHOD19@@ZAKPEVCPROXY1632@@@Z
199 stub ?PROXY1632METHOD29@@ZAKPEVCPROXY1632@@@Z
200 stub CALL32INITIALIZE
201 pascal CALLOBJECTINWOW(ptr ptr) CallObjectInWOW
203 stub CALLOBJECTINWOWCHECKINIT
204 stub CALLOBJECTINWOWCHECKTHKMGR
205 stub CONVERTHR1632
206 stub CONVERTHR3216
207 stub ADDAPPCOMPATFLAG
# WINE internal relays (for Win16 interfaces)
500 cdecl IMalloc16_QueryInterface(ptr ptr ptr) IMalloc16_fnQueryInterface
501 cdecl IMalloc16_AddRef(ptr) IMalloc16_fnAddRef
502 cdecl IMalloc16_Release(ptr) IMalloc16_fnRelease
503 cdecl IMalloc16_Alloc(ptr long) IMalloc16_fnAlloc
504 cdecl IMalloc16_Realloc(ptr segptr long) IMalloc16_fnRealloc
505 cdecl IMalloc16_Free(ptr segptr) IMalloc16_fnFree
506 cdecl IMalloc16_GetSize(ptr segptr) IMalloc16_fnGetSize
507 cdecl IMalloc16_DidAlloc(ptr segptr) IMalloc16_fnDidAlloc
508 cdecl IMalloc16_HeapMinimize(ptr) IMalloc16_fnHeapMinimize
@ stdcall -arch=win32 get_task_imalloc16(ptr)
@ stdcall -arch=win32 CoInitialize16(long)
@ stdcall -arch=win32 CoUninitialize16()
@ stdcall -arch=win32 StringFromGUID216(ptr ptr long)
@ stdcall -arch=win32 CoCreateInstance16(long long long long long)
================================================
FILE: compobj/compobj.vcxproj
================================================
Debug
Win32
Release
Win32
Win32Proj
10.0.17134.0
compobj
{B88A001B-29A3-45C1-8FF9-A75CB7C7DCCF}
DynamicLibrary
true
v141
Unicode
DynamicLibrary
false
v141
true
Unicode
true
.dll16
false
Release
.dll16
Level3
Disabled
WIN32;_DEBUG;_WINDOWS;_USRDLL;_X86_;__WINESRC__;__i386__;USE_COMPILER_EXCEPTIONS;HAVE_STRNCASECMP;HAVE__STRNICMP;_WINTERNL_;NtCurrentTeb=NtCurrentTeb__;inline=__inline;%(PreprocessorDefinitions)
../wine
Windows
true
$(OutDir)ole2.lib;$(OutDir)winecrt0.lib;$(OutDir)libwine.lib;$(OutDir)krnl386.lib;
uuid.lib;ole32.lib;advapi32.lib;%(AdditionalDependencies)
true
compobj.def
Level3
MaxSpeed
true
true
WIN32;NDEBUG;_WINDOWS;_USRDLL;_X86_;__WINESRC__;__i386__;USE_COMPILER_EXCEPTIONS;HAVE_STRNCASECMP;HAVE__STRNICMP;_WINTERNL_;NtCurrentTeb=NtCurrentTeb__;inline=__inline;DECLSPEC_HIDDEN=;%(PreprocessorDefinitions)
../wine
Windows
true
true
true
false
compobj.def
$(OutDir)ole2.lib;$(OutDir)winecrt0.lib;$(OutDir)libwine.lib;$(OutDir)krnl386.lib;
uuid.lib;ole32.lib;advapi32.lib;%(AdditionalDependencies)
Document
"$(OutDir)convspec" "%(Filename).spec" COMPOBJ > "%(Filename).asm" && "$(AsmPath)as" --32 -o "%(Filename).obj" "%(Filename).asm"
%(Filename).obj
================================================
FILE: convertwinefile/convertwinefile.vcxproj
================================================
Debug
Win32
Release
Win32
Debug
x64
Release
x64
{782AFA35-AE4C-4BC1-9AC9-6D0075AF6AB7}
Win32Proj
convertwinefile
10.0.17134.0
Application
true
v141
Unicode
Application
false
v141
true
Unicode
Application
true
v141
Unicode
Application
false
v141
true
Unicode
true
.exe
$(ProjectName)
true
false
false
Level3
Disabled
WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
Console
true
shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
Level3
Disabled
_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
Console
true
Level3
MaxSpeed
true
true
WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
Console
true
true
true
shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
Level3
MaxSpeed
true
true
NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
Console
true
true
true
================================================
FILE: convertwinefile/convertwinefile.vcxproj.filters
================================================
{4FC737F1-C7A5-4376-A066-2A32D752A2FF}
cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
{93995380-89BD-4b04-88EB-625FBE52EBFB}
h;hh;hpp;hxx;hm;inl;inc;xsd
{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
ソース ファイル
================================================
FILE: convertwinefile/main.c
================================================
/*
* Converts wine DLL source Makefiles to MSVC projects.
*
* Copyright (C) 2017 otya
*/
#include
#include
#include
#include
#include
#include
const char * getdirname(const char *path)
{
const char *a = strpbrk(path, "\\/");
if (!a) return path;
while (1)
{
a++;
path = a;
if (!*a) return path;
a = strpbrk(path, "\\/");
if (!a) return path;
}
}
inline static size_t memcount(const char* begin, char c, size_t n) {
size_t r = 0;
for (size_t i = 0; i < n; i++)
if (begin[i] == c)
r++;
return r;
}
/** Escape for cmd and xcopy MSVCRT command-line
* JS: `"${arg.replace(/(\\*)($|")/g, '$1$1$2').replace(/"/g, '""')}"`;
*/
char * escape(const char* op)
{
// estimate size
size_t l = strlen(op);
size_t bufsz = 2 + l + memcount(op, '\\', l) + memcount(op, '"', l) + 1;
char* ret = malloc(bufsz);
if (!ret) return ret;
size_t spos = 0, tpos = 0;
ret[tpos++]='"';
// find quotes or end
const char* quote = NULL;
while ((quote = memchr(&op[spos], '"', l)) ||
(quote = op + l)) {
// Count consec backslash
const char* k;
for (k = quote - 1; *k == '\\'; k--) {
/* PASS */
}
// Copy up to and including k
size_t stertch = (k - op) - spos + 1;
memcpy(&ret[tpos], &op[spos], stertch);
spos += stertch;
tpos += stertch;
// Double backslashes
for (const char* s = k + 1; s < quote; s++) {
ret[tpos++]='\\';
ret[tpos++]='\\';
spos++;
}
assert(&op[spos] == quote);
// Double the quote
if (spos != l) {
ret[tpos++] = '"';
ret[tpos++] = '"';
spos++;
} else {
break;
}
}
ret[tpos++] = '"';
ret[tpos] = '\0';
return ret;
}
#define ESCAPE(Var) const char* e ## Var = escape(Var)
#define E(Var) (e ## Var)
#define FESC(Var) free(e ## Var)
void copy(const char * src, const char *dst)
{
char buf[512];
ESCAPE(src); ESCAPE(dst);
int c = snprintf(buf, sizeof(buf), "xcopy %s %s /I", E(src), E(dst));
FESC(src); FESC(dst);
assert(c < sizeof(buf) - 1);
system(buf);
}
typedef struct
{
char module[100];
char imports[32][32];
char csrcs[32][32];
char rcsrcs[32][32];
} makein;
char *fgetsex(char *buffer, size_t bufsiz, FILE *fp)
{
if (!fgets(buffer, bufsiz, fp))
return NULL;
size_t len = strlen(buffer);
if (buffer[len - 2] == '\\')
{
fgetsex(buffer + len - 3, bufsiz - len - 1, fp);
return buffer;
}
return buffer;
}
const char *skipspaces(const char *in)
{
while (*in)
{
if (!isspace(*in))
return in;
in++;
}
return in;
}
const char *getitem(const char *in, char *buf, size_t bufsiz)
{
in = skipspaces(in);
if (*in == '\0')
return 0;
size_t buflen = 0;
while (1)
{
if (isspace(*in))
break;
buflen++;
if (buflen < bufsiz)
{
buf[buflen - 1] = *in;
}
in++;
}
if (buflen < bufsiz)
{
buf[buflen] = '\0';
}
else
{
buf[bufsiz - 1] = '\0';
}
in = skipspaces(in);
return in;
}
void parsemakein(FILE *fp, makein *in)
{
char line[2048];
while (fgetsex(line, sizeof(line), fp))
{
const char *linebuf = line;
char buf[128];
linebuf = getitem(linebuf, buf, sizeof(buf));
if (!linebuf)
continue;
if (*linebuf != '=')
{
continue;
}
linebuf++;
linebuf = skipspaces(linebuf);
if (!strcmp(buf, "MODULE"))
{
linebuf = getitem(linebuf, buf, sizeof(buf));
strncpy(in->module, buf, sizeof(in->module));
}
if (!strcmp(buf, "IMPORTS"))
{
for (int i = 0; i < sizeof(in->imports); i++)
{
linebuf = getitem(linebuf, buf, sizeof(buf));
if (!linebuf) break;
strncpy(in->imports[i], buf, sizeof(in->imports[0]));
}
}
if (!strcmp(buf, "C_SRCS"))
{
for (int i = 0; i < sizeof(in->csrcs); i++)
{
linebuf = getitem(linebuf, buf, sizeof(buf));
if (!linebuf) break;
strncpy(in->csrcs[i], buf, sizeof(in->csrcs[0]));
}
}
if (!strcmp(buf, "RC_SRCS"))
{
for (int i = 0; i < sizeof(in->rcsrcs); i++)
{
linebuf = getitem(linebuf, buf, sizeof(buf));
if (!linebuf) break;
strncpy(in->rcsrcs[i], buf, sizeof(in->rcsrcs[0]));
}
}
}
}
typedef enum
{
TEMPLATE_NONE,
TEMPLATE_TargetExt,
TEMPLATE_ClCompile_PreprocessorDefinitions,
TEMPLATE_Link_AdditionalDependencies,
TEMPLATE_C_SRCS, TEMPLATE_DEF_FILE, TEMPLATE_OBJ_FILE, TEMPLATE_RootNamespace,
TEMPLATE_CUSTOM_SPEC, TEMPLATE_CUSTOM_COMMAND, TEMPLATE_DEF_FILE2
} vcxpojlineattr;
typedef struct
{
vcxpojlineattr attr;
const char *line;
}vcxpojline;
vcxpojline vcxtemplate[] = {
{ TEMPLATE_NONE,"" },
{ TEMPLATE_NONE,"" },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE," Debug" },
{ TEMPLATE_NONE," Win32" },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE," Release" },
{ TEMPLATE_NONE," Win32" },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE," " },
//{ TEMPLATE_NONE," {B83EEE1C-F8DE-4F82-8928-67F1B142E5F2}" },
{ TEMPLATE_NONE," Win32Proj" },
{ TEMPLATE_NONE," 10.0.17134.0"},
{ TEMPLATE_RootNamespace," keyboard" },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE," DynamicLibrary" },
{ TEMPLATE_NONE," true" },
{ TEMPLATE_NONE," v141" },
{ TEMPLATE_NONE," Unicode" },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE," DynamicLibrary" },
{ TEMPLATE_NONE," false" },
{ TEMPLATE_NONE," v141" },
{ TEMPLATE_NONE," true" },
{ TEMPLATE_NONE," Unicode" },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE," "},
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE," true" },
{ TEMPLATE_TargetExt,"" },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE," false" },
{ TEMPLATE_NONE," Release\" },
{ TEMPLATE_TargetExt,"" },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE," Level3" },
{ TEMPLATE_NONE," Disabled" },
{ TEMPLATE_ClCompile_PreprocessorDefinitions," WIN32;_DEBUG;_WINDOWS;_USRDLL;_X86_;__WINESRC__;__i386__;USE_COMPILER_EXCEPTIONS;HAVE_STRNCASECMP;HAVE__STRNICMP;_WINTERNL_;NtCurrentTeb=NtCurrentTeb__;inline=__inline;%(PreprocessorDefinitions)" },
{ TEMPLATE_NONE," ../wine" },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE," Windows" },
{ TEMPLATE_NONE," true" },
{ TEMPLATE_NONE," $(OutDir)winecrt0.lib;$(OutDir)libwine.lib;$(OutDir)wow32.lib;$(OutDir)krnl386.lib;" },
{ TEMPLATE_Link_AdditionalDependencies,"" },
{ TEMPLATE_NONE,"%(AdditionalDependencies)" },
{ TEMPLATE_NONE," true" },
{ TEMPLATE_NONE," " },
{ TEMPLATE_DEF_FILE,"" },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE," Level3" },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE," MaxSpeed" },
{ TEMPLATE_NONE," true" },
{ TEMPLATE_NONE," true" },
{ TEMPLATE_ClCompile_PreprocessorDefinitions," WIN32;NDEBUG;_WINDOWS;_USRDLL;_X86_;__WINESRC__;__i386__;USE_COMPILER_EXCEPTIONS;HAVE_STRNCASECMP;HAVE__STRNICMP;_WINTERNL_;NtCurrentTeb=NtCurrentTeb__;inline=__inline;DECLSPEC_HIDDEN=;%(PreprocessorDefinitions)" },
{ TEMPLATE_NONE," ../wine" },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE," Windows" },
{ TEMPLATE_NONE," true" },
{ TEMPLATE_NONE," true" },
{ TEMPLATE_NONE," true" },
{ TEMPLATE_NONE," false" },
{ TEMPLATE_NONE," " },
{ TEMPLATE_DEF_FILE,"" },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE," $(OutDir)winecrt0.lib;$(OutDir)libwine.lib;$(OutDir)wow32.lib;$(OutDir)krnl386.lib;" },
{ TEMPLATE_Link_AdditionalDependencies,"" },
{ TEMPLATE_NONE,"%(AdditionalDependencies)" },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE," " },
{ TEMPLATE_C_SRCS," " },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE," " },
{ TEMPLATE_OBJ_FILE," " },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE, " " },
{ TEMPLATE_CUSTOM_SPEC, " " },
{ TEMPLATE_NONE, " Document" },
{ TEMPLATE_CUSTOM_COMMAND, " \"$(OutDir)convspec\" \"%%(Filename).spec\" %s > \"%%(Filename).asm\" && \"$(AsmPath)as\" --32 -o \"%%(Filename).obj\" \"%%(Filename).asm\"" },
{ TEMPLATE_NONE, " %(Filename).obj" },
{ TEMPLATE_NONE, " " },
{ TEMPLATE_NONE, " " },
{ TEMPLATE_NONE, " " },
{ TEMPLATE_DEF_FILE2, " \n" },
{ TEMPLATE_NONE, " " },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE," " },
{ TEMPLATE_NONE,"" }
};
#define GetArrayLength(A) (sizeof(A) / sizeof(A[0]))
void generateVCproject(makein *in, FILE *out)
{
const char * targetext = PathFindExtensionA(in->module);
const char target[128] = { 0 };
strncpy(target, in->module, strlen(in->module) - strlen(targetext));
for (int i = 0; i < GetArrayLength(vcxtemplate); i++)
{
if (vcxtemplate[i].attr == TEMPLATE_RootNamespace)
{
fprintf(out, " %s\n", target);
}
else if (vcxtemplate[i].attr == TEMPLATE_TargetExt)
{
fprintf(out, "%s\n", targetext);
}
else if (vcxtemplate[i].attr == TEMPLATE_Link_AdditionalDependencies)
{
for (int j = 0; j < GetArrayLength(in->imports); j++)
{
if (!strlen(in->imports[j]))
break;
fprintf(out, "%s.lib;", in->imports[j]);
}
}
else if (vcxtemplate[i].attr == TEMPLATE_C_SRCS)
{
for (int j = 0; j < GetArrayLength(in->csrcs); j++)
{
if (!strlen(in->csrcs[j]))
break;
fprintf(out, " \n", in->csrcs[j]);
}
}
else if (vcxtemplate[i].attr == TEMPLATE_DEF_FILE)
{
fprintf(out, "%s.def\n", target);
}
else if (vcxtemplate[i].attr == TEMPLATE_OBJ_FILE)
{
fprintf(out, " \n", in->module);
}
else if (vcxtemplate[i].attr == TEMPLATE_CUSTOM_SPEC)
{
fprintf(out, vcxtemplate[i].line, in->module);
fprintf(out, "\n");
}
else if (vcxtemplate[i].attr == TEMPLATE_CUSTOM_COMMAND)
{
char mod[2445];
for (int j = 0; target[j]; j++)
{
mod[j] = toupper(target[j]);
if (!target[j + 1])
mod[j + 1] = 0;
}
fprintf(out, vcxtemplate[i].line, mod);
fprintf(out, "\n");
}
else if (vcxtemplate[i].attr == TEMPLATE_DEF_FILE2)
{
fprintf(out, vcxtemplate[i].line, target);
}
else
{
fprintf(out, "%s\n", vcxtemplate[i].line);
}
}
}
void generateDEF(makein *makedata, const char *spec, const char *path)
{
char buf[512];
ESCAPE(spec);
int c = snprintf(buf, sizeof(buf), "convspec %s -DEF > \"%s\"", E(spec), path);
FESC(spec);
assert(c < sizeof(buf) - 1);
system(buf);
}
void generateASM(makein *makedata, const char *spec, const char *path, const char *mod)
{
char buf[512];
ESCAPE(spec); ESCAPE(mod);
int c = snprintf(buf, sizeof(buf), "convspec %s %s > \"%s\"", E(spec), E(mod), path);
FESC(spec); FESC(mod);
assert(c < sizeof(buf) - 1);
system(buf);
}
int main(int argc, char **argv)
{
if (argc != 3)
{
puts("Converts wine DLL source Makefiles to MSVC projects.");
puts("usage: convertwinefile <2>");
return 0;
}
char *dir = argv[1];
char *dir2 = argv[2];
copy(dir, dir2);
makein makedata = { 0 };
char makefile_in_path[MAX_PATH] = { 0 };
strncpy(makefile_in_path, dir2, sizeof(makefile_in_path));
strncat(makefile_in_path, "/Makefile.in", sizeof(makefile_in_path));
FILE *makefile_in = fopen(makefile_in_path, "r");
parsemakein(makefile_in, &makedata);
fclose(makefile_in);
char proj_in_path[MAX_PATH] = { 0 };
strncpy(proj_in_path, dir2, sizeof(proj_in_path));
strncat(makefile_in_path, "/", sizeof(makefile_in_path));
strncat(makefile_in_path, "/Makefile.in", sizeof(makefile_in_path));
char projname[MAX_PATH] = { 0 };
strncpy(projname, PathFindFileNameA(dir2), sizeof(projname));
PathRemoveExtensionA(projname);
char projpath[MAX_PATH] = { 0 };
strncpy(projpath, dir2, sizeof(projpath));
PathAddBackslashA(projpath);
strncat(projpath, projname, MAX_PATH);//PathAppendA(projpath, projpath, projname);
PathAddExtensionA(projpath, ".vcxproj");
FILE *proj = fopen(projpath, "w+");
generateVCproject(&makedata, proj);
fclose(proj);
char specpath[MAX_PATH] = { 0 };
strncpy(specpath, dir2, sizeof(specpath));
PathAddBackslashA(specpath);
strncat(specpath, makedata.module, MAX_PATH);// PathAppendA(asmpath, asmpath, makedata.module);
strncat(specpath, ".spec", MAX_PATH);
char defpath[MAX_PATH] = { 0 };
strncpy(defpath, dir2, sizeof(defpath));
PathAddBackslashA(defpath);
strncat(defpath, projname, MAX_PATH);// PathAppendA(defpath, defpath, projname);
PathAddExtensionA(defpath, ".def");
generateDEF(&makedata, specpath, defpath);
return 0;
}
================================================
FILE: convspec/CMakeLists.txt
================================================
file(GLOB SOURCE *.c)
add_executable(convspec ${SOURCE})
include_directories(../wine)
add_definitions(-D__i386__ -Dpopen=_popen -Dpclose=_pclose
-Dstrncasecmp=_strnicmp -Dstrcasecmp=_stricmp)
if (MSVC)
add_definitions(-DWINEBUILD_MSVC)
endif()
================================================
FILE: convspec/build.h
================================================
/*
* Copyright 1993 Robert J. Amstadt
* Copyright 1995 Martin von Loewis
* Copyright 1995, 1996, 1997 Alexandre Julliard
* Copyright 1997 Eric Youngdale
* Copyright 1999 Ulrich Weigand
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef __WINE_BUILD_H
#define __WINE_BUILD_H
#ifndef __WINE_CONFIG_H
# error You must include config.h to use this header
#endif
#include
#include
#include
#ifndef max
#define max(a,b) (((a) > (b)) ? (a) : (b))
#endif
#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
typedef enum
{
TYPE_VARIABLE, /* variable */
TYPE_PASCAL, /* pascal function (Win16) */
TYPE_ABS, /* absolute value (Win16) */
TYPE_STUB, /* unimplemented stub */
TYPE_STDCALL, /* stdcall function (Win32) */
TYPE_CDECL, /* cdecl function (Win32) */
TYPE_VARARGS, /* varargs function (Win32) */
TYPE_THISCALL, /* thiscall function (Win32 on i386) */
TYPE_EXTERN, /* external symbol (Win32) */
TYPE_NBTYPES
} ORD_TYPE;
typedef enum
{
SPEC_WIN16,
SPEC_WIN32
} SPEC_TYPE;
enum arg_type
{
ARG_WORD, /* 16-bit word */
ARG_SWORD, /* 16-bit signed word */
ARG_SEGPTR, /* segmented pointer */
ARG_SEGSTR, /* segmented pointer to Ansi string */
ARG_LONG, /* long */
ARG_PTR, /* pointer */
ARG_STR, /* pointer to Ansi string */
ARG_WSTR, /* pointer to Unicode string */
ARG_INT64, /* 64-bit integer */
ARG_INT128, /* 128-bit integer */
ARG_FLOAT, /* 32-bit float */
ARG_DOUBLE, /* 64-bit float */
ARG_MAXARG = ARG_DOUBLE
};
#define MAX_ARGUMENTS 32
typedef struct
{
int n_values;
unsigned int *values;
} ORD_VARIABLE;
typedef struct
{
int nb_args;
int args_str_offset;
enum arg_type args[MAX_ARGUMENTS];
} ORD_FUNCTION;
typedef struct
{
unsigned short value;
} ORD_ABS;
typedef struct
{
ORD_TYPE type;
int ordinal;
int lineno;
int flags;
char *name; /* public name of this function */
char *link_name; /* name of the C symbol to link to */
char *export_name; /* name exported under for noname exports */
union
{
ORD_VARIABLE var;
ORD_FUNCTION func;
ORD_ABS abs;
} u;
} ORDDEF;
typedef struct
{
char *src_name; /* file name of the source spec file */
char *file_name; /* file name of the dll */
char *dll_name; /* internal name of the dll */
char *c_name; /* internal name of the dll, as a C-compatible identifier */
char *init_func; /* initialization routine */
char *main_module; /* main Win32 module for Win16 specs */
SPEC_TYPE type; /* type of dll (Win16/Win32) */
int base; /* ordinal base */
int limit; /* ordinal limit */
int stack_size; /* exe stack size */
int heap_size; /* exe heap size */
int nb_entry_points; /* number of used entry points */
int alloc_entry_points; /* number of allocated entry points */
int nb_names; /* number of entry points with names */
unsigned int nb_resources; /* number of resources */
int characteristics; /* characteristics for the PE header */
int dll_characteristics;/* DLL characteristics for the PE header */
int subsystem; /* subsystem id */
int subsystem_major; /* subsystem version major number */
int subsystem_minor; /* subsystem version minor number */
ORDDEF *entry_points; /* dll entry points */
ORDDEF **names; /* array of entry point names (points into entry_points) */
ORDDEF **ordinals; /* array of dll ordinals (points into entry_points) */
struct resource *resources; /* array of dll resources (format differs between Win16/Win32) */
} DLLSPEC;
enum target_cpu
{
CPU_x86, CPU_x86_64, CPU_POWERPC, CPU_ARM, CPU_ARM64, CPU_LAST = CPU_ARM64
};
enum target_platform
{
PLATFORM_UNSPECIFIED,
PLATFORM_APPLE,
PLATFORM_FREEBSD,
PLATFORM_SOLARIS,
PLATFORM_WINDOWS
};
extern char *target_alias;
extern enum target_cpu target_cpu;
extern enum target_platform target_platform;
struct strarray
{
const char **str;
unsigned int count;
unsigned int max;
};
/* entry point flags */
#define FLAG_NORELAY 0x01 /* don't use relay debugging for this function */
#define FLAG_NONAME 0x02 /* don't export function by name */
#define FLAG_RET16 0x04 /* function returns a 16-bit value */
#define FLAG_RET64 0x08 /* function returns a 64-bit value */
#define FLAG_REGISTER 0x10 /* use register calling convention */
#define FLAG_PRIVATE 0x20 /* function is private (cannot be imported) */
#define FLAG_ORDINAL 0x40 /* function should be imported by ordinal */
#define FLAG_STKPROLOG 0x80 /* add stack adjust prolog for programs that hook exports */
#define FLAG_FORWARD 0x100 /* function is a forwarded name */
#define FLAG_EXT_LINK 0x200 /* function links to an external symbol */
#define FLAG_EXPORT32 0x400 /* 32-bit export in 16-bit spec file */
#define FLAG_CPU(cpu) (0x01000 << (cpu))
#define FLAG_CPU_MASK (FLAG_CPU(CPU_LAST + 1) - FLAG_CPU(0))
#define FLAG_CPU_WIN64 (FLAG_CPU(CPU_x86_64) | FLAG_CPU(CPU_ARM64))
#define FLAG_CPU_WIN32 (FLAG_CPU_MASK & ~FLAG_CPU_WIN64)
#define MAX_ORDINALS 65535
/* some Windows constants */
#define IMAGE_FILE_RELOCS_STRIPPED 0x0001 /* No relocation info */
#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002
#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004
#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008
#define IMAGE_FILE_AGGRESIVE_WS_TRIM 0x0010
#define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020
#define IMAGE_FILE_16BIT_MACHINE 0x0040
#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080
#define IMAGE_FILE_32BIT_MACHINE 0x0100
#define IMAGE_FILE_DEBUG_STRIPPED 0x0200
#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400
#define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800
#define IMAGE_FILE_SYSTEM 0x1000
#define IMAGE_FILE_DLL 0x2000
#define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000
#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000
#define IMAGE_DLLCHARACTERISTICS_NX_COMPAT 0x0100
#define IMAGE_SUBSYSTEM_NATIVE 1
#define IMAGE_SUBSYSTEM_WINDOWS_GUI 2
#define IMAGE_SUBSYSTEM_WINDOWS_CUI 3
#define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI 9
/* global functions */
#ifndef __GNUC__
#define __attribute__(X)
#endif
#ifndef DECLSPEC_NORETURN
# if defined(_MSC_VER) && (_MSC_VER >= 1200) && !defined(MIDL_PASS)
# define DECLSPEC_NORETURN __declspec(noreturn)
# else
# define DECLSPEC_NORETURN __attribute__((noreturn))
# endif
#endif
extern void *xmalloc (size_t size);
extern void *xrealloc (void *ptr, size_t size);
extern char *xstrdup( const char *str );
extern char *strupper(char *s);
extern int strendswith(const char* str, const char* end);
extern char *strmake(const char* fmt, ...) __attribute__((__format__ (__printf__, 1, 2 )));
extern struct strarray strarray_fromstring( const char *str, const char *delim );
extern void strarray_add( struct strarray *array, ... );
extern void strarray_addv( struct strarray *array, char * const *argv );
extern void strarray_addall( struct strarray *array, struct strarray args );
extern DECLSPEC_NORETURN void fatal_error( const char *msg, ... )
__attribute__ ((__format__ (__printf__, 1, 2)));
extern DECLSPEC_NORETURN void fatal_perror( const char *msg, ... )
__attribute__ ((__format__ (__printf__, 1, 2)));
extern void error( const char *msg, ... )
__attribute__ ((__format__ (__printf__, 1, 2)));
extern void warning( const char *msg, ... )
__attribute__ ((__format__ (__printf__, 1, 2)));
extern int output( const char *format, ... )
__attribute__ ((__format__ (__printf__, 1, 2)));
extern void output_cfi( const char *format, ... )
__attribute__ ((__format__ (__printf__, 1, 2)));
extern void spawn( struct strarray array );
extern struct strarray find_tool( const char *name, const char * const *names );
extern struct strarray get_as_command(void);
extern struct strarray get_ld_command(void);
extern const char *get_nm_command(void);
extern void cleanup_tmp_files(void);
extern char *get_temp_file_name( const char *prefix, const char *suffix );
extern void output_standard_file_header(void);
extern FILE *open_input_file( const char *srcdir, const char *name );
extern void close_input_file( FILE *file );
extern void dump_bytes( const void *buffer, unsigned int size );
extern int remove_stdcall_decoration( char *name );
extern void assemble_file( const char *src_file, const char *obj_file );
extern DLLSPEC *alloc_dll_spec(void);
extern void free_dll_spec( DLLSPEC *spec );
extern char *make_c_identifier( const char *str );
extern const char *get_stub_name( const ORDDEF *odp, const DLLSPEC *spec );
extern int get_cpu_from_name( const char *name );
extern unsigned int get_alignment(unsigned int align);
extern unsigned int get_page_size(void);
extern unsigned int get_ptr_size(void);
extern unsigned int get_args_size( const ORDDEF *odp );
extern const char *asm_name( const char *func );
extern const char *func_declaration( const char *func );
extern const char *asm_globl( const char *func );
extern const char *get_asm_ptr_keyword(void);
extern const char *get_asm_string_keyword(void);
extern const char *get_asm_rodata_section(void);
extern const char *get_asm_string_section(void);
extern void output_function_size( const char *name );
extern void output_gnu_stack_note(void);
extern void add_import_dll( const char *name, const char *filename );
extern void add_delayed_import( const char *name );
extern void add_extra_ld_symbol( const char *name );
extern void read_undef_symbols( DLLSPEC *spec, char **argv );
extern void resolve_imports( DLLSPEC *spec );
extern int is_undefined( const char *name );
extern int has_imports(void);
extern void output_get_pc_thunk(void);
extern void output_module( DLLSPEC *spec );
extern void output_stubs( DLLSPEC *spec );
extern void output_imports( DLLSPEC *spec );
extern void output_import_lib( DLLSPEC *spec, char **argv );
extern void output_exports( DLLSPEC *spec );
extern int load_res32_file( const char *name, DLLSPEC *spec );
extern void output_resources( DLLSPEC *spec );
extern void output_bin_resources( DLLSPEC *spec, unsigned int start_rva );
extern void output_fake_module( DLLSPEC *spec );
extern void output_def_file( DLLSPEC *spec, int include_private );
extern void load_res16_file( const char *name, DLLSPEC *spec );
extern void load_res16_from_buf( const unsigned char *buf, int size, DLLSPEC *spec );
extern void output_res16_data( DLLSPEC *spec );
extern void output_bin_res16_data( DLLSPEC *spec );
extern void output_res16_directory( DLLSPEC *spec );
extern void output_bin_res16_directory( DLLSPEC *spec, unsigned int data_offset );
extern void output_spec16_file( DLLSPEC *spec );
extern void output_fake_module16( DLLSPEC *spec16 );
extern void output_res_o_file( DLLSPEC *spec );
extern void output_asm_relays16(void);
extern void BuildSpec32File( DLLSPEC *spec );
extern void add_16bit_exports( DLLSPEC *spec32, DLLSPEC *spec16 );
extern int parse_spec_file( FILE *file, DLLSPEC *spec );
extern int parse_def_file( FILE *file, DLLSPEC *spec );
/* buffer management */
extern int byte_swapped;
extern const char *input_buffer_filename;
extern const unsigned char *input_buffer;
extern size_t input_buffer_pos;
extern size_t input_buffer_size;
extern unsigned char *output_buffer;
extern size_t output_buffer_pos;
extern size_t output_buffer_size;
extern void init_input_buffer( const char *file );
extern void init_output_buffer(void);
extern void flush_output_buffer(void);
extern unsigned char get_byte(void);
extern unsigned short get_word(void);
extern unsigned int get_dword(void);
extern void put_data( const void *data, size_t size );
extern void put_byte( unsigned char val );
extern void put_word( unsigned short val );
extern void put_dword( unsigned int val );
extern void put_qword( unsigned int val );
extern void put_pword( unsigned int val );
extern void align_output( unsigned int align );
/* global variables */
extern int current_line;
extern int UsePIC;
extern int nb_errors;
extern int display_warnings;
extern int kill_at;
extern int verbose;
extern int link_ext_symbols;
extern int force_pointer_size;
extern int unwind_tables;
extern char *input_file_name;
extern char *spec_file_name;
extern FILE *output_file;
extern const char *output_file_name;
extern struct strarray lib_path;
extern struct strarray as_command;
extern struct strarray cc_command;
extern struct strarray ld_command;
extern struct strarray nm_command;
extern char *cpu_option;
extern char *arch_option;
extern const char *float_abi_option;
extern int thumb_mode;
extern int needs_get_pc_thunk;
extern const char *asm_name_stdcall16(const char *sym, ORDDEF *ord);
const char *asm_name_stdcall32(const char *sym, ORDDEF *ord);
#endif /* __WINE_BUILD_H */
================================================
FILE: convspec/convspec.c
================================================
// -*- tab-width: 4 -*-
// # vim: set expandtab: ts=4
// Converts Win32 wine spec files to Win16 specs. Based on winebuild.
// otya 2018
#include
/* Stubs */
static char *optarg;
static int optind;
static int opterr;
static int optopt;
struct option;
struct option
{
const char *name;
int has_arg;
int *flag;
int val;
};
static int getopt_long(int ___argc, char *const *___argv,
const char *__shortopts,
const struct option *__longopts, int *__longind)
{
fprintf(stderr, "getopt_long: stub\n");
return 0;
}
static int getopt_long_only(int ___argc, char *const *___argv,
const char *__shortopts,
const struct option *__longopts, int *__longind)
{
fprintf(stderr, "getopt_long_only: stub\n");
return 0;
}
int mkstemps(char *template, int suffix_len)
{
fprintf(stderr, "mkstemps: stub\n");
return 0;
}
#define main __main
#include "main.c.h"
#include "ver.h"
char *nb_lib_paths;
#undef main
static int parse_input_file(DLLSPEC *spec);
int main(int argc, char* argv[])
{
int add_ver = 0;
if (argc <= 1)
{
printf("wine spec file convert tool\nusage: %s specfile(16bit only) module name [-EXE]\n%s specfile(16bit only) -DEF\n", argv[0], argv[0]);
fatal_error("file argument '%s' not allowed in this mode\n", argv[0]);
}
DLLSPEC *spec = alloc_dll_spec();
spec_file_name = argv[1];
exec_mode = MODE_DLL;
spec->type = SPEC_WIN16;
spec->file_name = spec_file_name;
/* remove dir */
if (strrchr(spec->file_name, '\\'))
{
spec->file_name = strrchr(spec->file_name, '\\') + 1;
}
if (strrchr(spec->file_name, '/'))
{
spec->file_name = strrchr(spec->file_name, '/') + 1;
}
/* remove spec extension */
if (strstr(spec->file_name, ".spec"))
{
spec->file_name = xstrdup(spec->file_name);
strstr(spec->file_name, ".spec")[0] = '\0';
}
output_file = stdout;
target_cpu = CPU_x86;
init_dll_name(spec);
if (argc > 2)
{
for (int i = 2; i < argc; i++)
{
if (!strcmp(argv[i], "--heap") && argc > i + 1)
{
spec->heap_size = atoi(argv[++i]);
}
else if (!strcmp(argv[i], "-DEF"))
{
exec_mode = MODE_DEF;
}
else if (!strcmp(argv[i], "-EXE"))
{
exec_mode = MODE_EXE;
}
else if (!strcmp(argv[i], "-32"))
{
spec->type = SPEC_WIN32;
}
else if (!strcmp(argv[i], "-ver"))
{
add_ver = 1;
}
else if (argv[i][0] != '-')
{
spec->main_module = xstrdup(argv[i]);
spec->dll_name = xstrdup(argv[i]);
}
}
}
else
{
init_dll_name(spec);
}
switch (exec_mode)
{
case MODE_DEF:
if (!spec_file_name) fatal_error("missing .spec file\n");
if (!parse_input_file(spec)) break;
output_def_file(spec, 1);
break;
case MODE_DLL:
if (spec->subsystem != IMAGE_SUBSYSTEM_NATIVE)
spec->characteristics |= IMAGE_FILE_DLL;
/* fall through */
case MODE_EXE:
load_resources(argv, spec);
load_import_libs(argv);
if (spec_file_name && !parse_input_file(spec)) break;
if (add_ver)
{
char outname[13] = {0};
strncpy(outname, spec->dll_name, 12);
strcpy(ver_res + 0x144, outname);
load_res16_from_buf(ver_res, ver_res_len, spec);
}
if (fake_module)
{
if (spec->type == SPEC_WIN16) output_fake_module16(spec);
else output_fake_module(spec);
break;
}
//read_undef_symbols(spec, argv);
if (spec->type == SPEC_WIN16 && exec_mode == MODE_EXE)
spec->init_func = xstrdup("__wine_spec_exe16_entry");
switch (spec->type)
{
case SPEC_WIN16:
output_spec16_file(spec);
break;
case SPEC_WIN32:
BuildSpec32File(spec);
break;
default: assert(0);
}
break;
}
if (nb_errors) exit(1);
return EXIT_SUCCESS;
}
================================================
FILE: convspec/convspec.vcxproj
================================================
Debug
Win32
Release
Win32
{DC6BA231-C318-436F-8F5C-5E2CC73779E2}
Win32Proj
convspec
10.0.17134.0
Application
true
v141
Unicode
Application
false
v141
true
Unicode
true
false
Level3
Disabled
WINEBUILD_MSVC;WIN32;_DEBUG;_CONSOLE;_LIB;__i386__;popen=_popen;pclose=_pclose
;strncasecmp=_strnicmp;strcasecmp=_stricmp;%(PreprocessorDefinitions)
../wine
Console
true
$(OutDir)libwine.lib;%(AdditionalDependencies)
Level3
MaxSpeed
true
true
WINEBUILD_MSVC;WIN32;NDEBUG;_CONSOLE;_LIB;__i386__;popen=_popen;pclose=_pclose
;strncasecmp=_strnicmp;strcasecmp=_stricmp;%(PreprocessorDefinitions)
../wine
Console
true
true
true
kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
================================================
FILE: convspec/convspec.vcxproj.filters
================================================
{4FC737F1-C7A5-4376-A066-2A32D752A2FF}
cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
{93995380-89BD-4b04-88EB-625FBE52EBFB}
h;hh;hpp;hxx;hm;inl;inc;xsd
{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
ヘッダー ファイル
ヘッダー ファイル
ソース ファイル
ソース ファイル
ソース ファイル
ソース ファイル
ソース ファイル
ソース ファイル
ソース ファイル
ソース ファイル
ソース ファイル
================================================
FILE: convspec/import.c
================================================
/*
* DLL imports support
*
* Copyright 2000, 2004 Alexandre Julliard
* Copyright 2000 Eric Pouech
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#include "wine/port.h"
#include
#include
#include
#include
#include
#include
#ifdef HAVE_SYS_STAT_H
# include
#endif
#ifdef HAVE_UNISTD_H
# include
#endif
#include "wine/list.h"
#include "build.h"
struct import_func
{
const char *name;
const char *export_name;
int ordinal;
};
struct import
{
struct list entry; /* entry in global dll list */
char *dll_name; /* exported file name of the dll */
char *c_name; /* dll name as a C-compatible identifier */
char *full_name; /* full name of the input file */
dev_t dev; /* device/inode of the input file */
ino_t ino;
ORDDEF **exports; /* functions exported from this dll */
int nb_exports; /* number of exported functions */
struct import_func *imports; /* functions we want to import from this dll */
int nb_imports; /* number of imported functions */
int max_imports; /* size of imports array */
};
static struct strarray undef_symbols; /* list of undefined symbols */
static struct strarray extra_ld_symbols; /* list of extra symbols that ld should resolve */
static struct strarray delayed_imports; /* list of delayed import dlls */
static struct strarray ext_link_imports; /* list of external symbols to link to */
static struct list dll_imports = LIST_INIT( dll_imports );
static struct list dll_delayed = LIST_INIT( dll_delayed );
static struct strarray as_files;
static const char import_func_prefix[] = "__wine$func$";
static const char import_ord_prefix[] = "__wine$ord$";
static inline const char *ppc_reg( int reg )
{
static const char * const ppc_regs[32] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
"r8", "r9", "r10","r11","r12","r13","r14","r15",
"r16","r17","r18","r19","r20","r21","r22","r23",
"r24","r25","r26","r27","r28","r29","r30","r31" };
if (target_platform == PLATFORM_APPLE) return ppc_regs[reg];
return ppc_regs[reg] + 1; /* skip the 'r' */
}
/* compare function names; helper for resolve_imports */
static int name_cmp( const void *name, const void *entry )
{
return strcmp( *(const char* const *)name, *(const char* const *)entry );
}
/* compare function names; helper for resolve_imports */
static int func_cmp( const void *func1, const void *func2 )
{
const ORDDEF *odp1 = *(const ORDDEF * const *)func1;
const ORDDEF *odp2 = *(const ORDDEF * const *)func2;
return strcmp( odp1->name ? odp1->name : odp1->export_name,
odp2->name ? odp2->name : odp2->export_name );
}
/* remove a name from a name table */
static inline void remove_name( struct strarray *table, unsigned int idx )
{
assert( idx < table->count );
memmove( table->str + idx, table->str + idx + 1,
(table->count - idx - 1) * sizeof(*table->str) );
table->count--;
}
/* locate a name in a (sorted) list */
static inline const char *find_name( const char *name, const struct strarray *table )
{
char **res = NULL;
if (table->count) res = bsearch( &name, table->str, table->count, sizeof(*table->str), name_cmp );
return res ? *res : NULL;
}
/* sort a name table */
static inline void sort_names( struct strarray *table )
{
if (table->count) qsort( table->str, table->count, sizeof(*table->str), name_cmp );
}
/* locate an export in a (sorted) export list */
static inline ORDDEF *find_export( const char *name, ORDDEF **table, int size )
{
ORDDEF func, *odp, **res = NULL;
func.name = xstrdup(name);
func.ordinal = -1;
odp = &func;
if (table) res = bsearch( &odp, table, size, sizeof(*table), func_cmp );
free( func.name );
return res ? *res : NULL;
}
/* free an import structure */
static void free_imports( struct import *imp )
{
free( imp->exports );
free( imp->imports );
free( imp->dll_name );
free( imp->c_name );
free( imp->full_name );
free( imp );
}
/* check whether a given dll is imported in delayed mode */
static int is_delayed_import( const char *name )
{
unsigned int i;
for (i = 0; i < delayed_imports.count; i++)
{
if (!strcmp( delayed_imports.str[i], name )) return 1;
}
return 0;
}
/* find an imported dll from its name */
static struct import *find_import_dll( const char *name )
{
struct import *import;
LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
if (!strcasecmp( import->dll_name, name )) return import;
LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
if (!strcasecmp( import->dll_name, name )) return import;
return NULL;
}
/* open the .so library for a given dll in a specified path */
static char *try_library_path( const char *path, const char *name )
{
char *buffer;
int fd;
buffer = strmake( "%s/lib%s.def", path, name );
/* check if the file exists */
if ((fd = open( buffer, O_RDONLY )) != -1)
{
close( fd );
return buffer;
}
free( buffer );
return NULL;
}
/* find the .def import library for a given dll */
static char *find_library( const char *name )
{
char *fullname;
unsigned int i;
for (i = 0; i < lib_path.count; i++)
{
if ((fullname = try_library_path( lib_path.str[i], name ))) return fullname;
}
fatal_error( "could not open .def file for %s\n", name );
return NULL;
}
/* read in the list of exported symbols of an import library */
static DLLSPEC *read_import_lib( struct import *imp )
{
FILE *f;
int i;
struct stat stat;
struct import *prev_imp;
DLLSPEC *spec = alloc_dll_spec();
f = open_input_file( NULL, imp->full_name );
fstat( fileno(f), &stat );
imp->dev = stat.st_dev;
imp->ino = stat.st_ino;
if (!parse_def_file( f, spec )) exit( 1 );
close_input_file( f );
/* check if we already imported that library from a different file */
if ((prev_imp = find_import_dll( spec->file_name )))
{
if (prev_imp->dev != imp->dev || prev_imp->ino != imp->ino)
fatal_error( "%s and %s have the same export name '%s'\n",
prev_imp->full_name, imp->full_name, spec->file_name );
free_dll_spec( spec );
return NULL; /* the same file was already loaded, ignore this one */
}
if (spec->nb_entry_points)
{
imp->exports = xmalloc( spec->nb_entry_points * sizeof(*imp->exports) );
for (i = 0; i < spec->nb_entry_points; i++)
imp->exports[imp->nb_exports++] = &spec->entry_points[i];
qsort( imp->exports, imp->nb_exports, sizeof(*imp->exports), func_cmp );
}
return spec;
}
/* build the dll exported name from the import lib name or path */
static char *get_dll_name( const char *name, const char *filename )
{
char *ret;
if (filename)
{
const char *basename = strrchr( filename, '/' );
if (!basename) basename = filename;
else basename++;
if (!strncmp( basename, "lib", 3 )) basename += 3;
ret = xmalloc( strlen(basename) + 5 );
strcpy( ret, basename );
if (strendswith( ret, ".def" )) ret[strlen(ret)-4] = 0;
}
else
{
ret = xmalloc( strlen(name) + 5 );
strcpy( ret, name );
}
if (!strchr( ret, '.' )) strcat( ret, ".dll" );
return ret;
}
/* add a dll to the list of imports */
void add_import_dll( const char *name, const char *filename )
{
DLLSPEC *spec;
char *dll_name = get_dll_name( name, filename );
struct import *imp = xmalloc( sizeof(*imp) );
memset( imp, 0, sizeof(*imp) );
if (filename) imp->full_name = xstrdup( filename );
else imp->full_name = find_library( name );
if (!(spec = read_import_lib( imp )))
{
free_imports( imp );
return;
}
imp->dll_name = spec->file_name ? spec->file_name : dll_name;
imp->c_name = make_c_identifier( imp->dll_name );
if (is_delayed_import( dll_name ))
list_add_tail( &dll_delayed, &imp->entry );
else
list_add_tail( &dll_imports, &imp->entry );
}
/* add a library to the list of delayed imports */
void add_delayed_import( const char *name )
{
struct import *imp;
char *fullname = get_dll_name( name, NULL );
strarray_add( &delayed_imports, fullname, NULL );
if ((imp = find_import_dll( fullname )))
{
list_remove( &imp->entry );
list_add_tail( &dll_delayed, &imp->entry );
}
}
/* add a symbol to the list of extra symbols that ld must resolve */
void add_extra_ld_symbol( const char *name )
{
strarray_add( &extra_ld_symbols, name, NULL );
}
/* retrieve an imported dll, adding one if necessary */
struct import *add_static_import_dll( const char *name )
{
struct import *import;
char *dll_name = get_dll_name( name, NULL );
if ((import = find_import_dll( dll_name ))) return import;
import = xmalloc( sizeof(*import) );
memset( import, 0, sizeof(*import) );
import->dll_name = dll_name;
import->full_name = xstrdup( dll_name );
import->c_name = make_c_identifier( dll_name );
if (is_delayed_import( dll_name ))
list_add_tail( &dll_delayed, &import->entry );
else
list_add_tail( &dll_imports, &import->entry );
return import;
}
/* add a function to the list of imports from a given dll */
static void add_import_func( struct import *imp, const char *name, const char *export_name, int ordinal )
{
if (imp->nb_imports == imp->max_imports)
{
imp->max_imports *= 2;
if (imp->max_imports < 32) imp->max_imports = 32;
imp->imports = xrealloc( imp->imports, imp->max_imports * sizeof(*imp->imports) );
}
imp->imports[imp->nb_imports].name = name;
imp->imports[imp->nb_imports].export_name = export_name;
imp->imports[imp->nb_imports].ordinal = ordinal;
imp->nb_imports++;
}
/* add an import for an undefined function of the form __wine$func$ */
static void add_undef_import( const char *name, int is_ordinal )
{
char *p, *dll_name = xstrdup( name );
int ordinal = 0;
struct import *import;
if (!(p = strchr( dll_name, '$' ))) return;
*p++ = 0;
while (*p >= '0' && *p <= '9') ordinal = 10 * ordinal + *p++ - '0';
if (*p != '$') return;
p++;
import = add_static_import_dll( dll_name );
if (is_ordinal)
add_import_func( import, NULL, xstrdup( p ), ordinal );
else
add_import_func( import, xstrdup( p ), NULL, ordinal );
}
/* get the default entry point for a given spec file */
static const char *get_default_entry_point( const DLLSPEC *spec )
{
if (spec->characteristics & IMAGE_FILE_DLL) return "__wine_spec_dll_entry";
if (spec->subsystem == IMAGE_SUBSYSTEM_NATIVE) return "__wine_spec_drv_entry";
if (spec->type == SPEC_WIN16) return "__wine_spec_exe16_entry";
return "__wine_spec_exe_entry";
}
/* check if the spec file exports any stubs */
static int has_stubs( const DLLSPEC *spec )
{
int i;
for (i = 0; i < spec->nb_entry_points; i++)
{
ORDDEF *odp = &spec->entry_points[i];
if (odp->type == TYPE_STUB) return 1;
}
return 0;
}
/* add the extra undefined symbols that will be contained in the generated spec file itself */
static void add_extra_undef_symbols( DLLSPEC *spec )
{
if (!spec->init_func) spec->init_func = xstrdup( get_default_entry_point(spec) );
add_extra_ld_symbol( spec->init_func );
if (has_stubs( spec )) add_extra_ld_symbol( "__wine_spec_unimplemented_stub" );
if (delayed_imports.count) add_extra_ld_symbol( "__wine_spec_delay_load" );
}
/* check if a given imported dll is not needed, taking forwards into account */
static int check_unused( const struct import* imp, const DLLSPEC *spec )
{
int i;
const char *file_name = imp->dll_name;
size_t len = strlen( file_name );
const char *p = strchr( file_name, '.' );
if (p && !strcasecmp( p, ".dll" )) len = p - file_name;
for (i = spec->base; i <= spec->limit; i++)
{
ORDDEF *odp = spec->ordinals[i];
if (!odp || !(odp->flags & FLAG_FORWARD)) continue;
if (!strncasecmp( odp->link_name, file_name, len ) &&
odp->link_name[len] == '.')
return 0; /* found a forward, it is used */
}
return 1;
}
/* check if a given forward does exist in one of the imported dlls */
static void check_undefined_forwards( DLLSPEC *spec )
{
struct import *imp;
char *link_name, *api_name, *dll_name, *p;
int i;
for (i = 0; i < spec->nb_entry_points; i++)
{
ORDDEF *odp = &spec->entry_points[i];
if (!(odp->flags & FLAG_FORWARD)) continue;
link_name = xstrdup( odp->link_name );
p = strrchr( link_name, '.' );
*p = 0;
api_name = p + 1;
dll_name = get_dll_name( link_name, NULL );
if ((imp = find_import_dll( dll_name )))
{
if (!find_export( api_name, imp->exports, imp->nb_exports ))
warning( "%s:%d: forward '%s' not found in %s\n",
spec->src_name, odp->lineno, odp->link_name, imp->dll_name );
}
else warning( "%s:%d: forward '%s' not found in the imported dll list\n",
spec->src_name, odp->lineno, odp->link_name );
free( link_name );
free( dll_name );
}
}
/* flag the dll exports that link to an undefined symbol */
static void check_undefined_exports( DLLSPEC *spec )
{
int i;
for (i = 0; i < spec->nb_entry_points; i++)
{
ORDDEF *odp = &spec->entry_points[i];
if (odp->type == TYPE_STUB || odp->type == TYPE_ABS || odp->type == TYPE_VARIABLE) continue;
if (odp->flags & FLAG_FORWARD) continue;
if (find_name( odp->link_name, &undef_symbols ))
{
switch(odp->type)
{
case TYPE_PASCAL:
case TYPE_STDCALL:
case TYPE_CDECL:
case TYPE_VARARGS:
case TYPE_THISCALL:
if (link_ext_symbols)
{
odp->flags |= FLAG_EXT_LINK;
strarray_add( &ext_link_imports, odp->link_name, NULL );
}
else error( "%s:%d: function '%s' not defined\n",
spec->src_name, odp->lineno, odp->link_name );
break;
default:
error( "%s:%d: external symbol '%s' is not a function\n",
spec->src_name, odp->lineno, odp->link_name );
break;
}
}
}
}
/* create a .o file that references all the undefined symbols we want to resolve */
static char *create_undef_symbols_file( DLLSPEC *spec )
{
char *as_file, *obj_file;
int i;
unsigned int j;
FILE *f;
as_file = get_temp_file_name( output_file_name, ".s" );
if (!(f = fopen( as_file, "w" ))) fatal_error( "Cannot create %s\n", as_file );
fprintf( f, "\t.data\n" );
for (i = 0; i < spec->nb_entry_points; i++)
{
ORDDEF *odp = &spec->entry_points[i];
if (odp->type == TYPE_STUB || odp->type == TYPE_ABS || odp->type == TYPE_VARIABLE) continue;
if (odp->flags & FLAG_FORWARD) continue;
fprintf( f, "\t%s %s\n", get_asm_ptr_keyword(), asm_name(odp->link_name) );
}
for (j = 0; j < extra_ld_symbols.count; j++)
fprintf( f, "\t%s %s\n", get_asm_ptr_keyword(), asm_name(extra_ld_symbols.str[j]) );
fclose( f );
obj_file = get_temp_file_name( output_file_name, ".o" );
assemble_file( as_file, obj_file );
return obj_file;
}
/* combine a list of object files with ld into a single object file */
/* returns the name of the combined file */
static const char *ldcombine_files( DLLSPEC *spec, char **argv )
{
char *ld_tmp_file, *undef_file;
struct strarray args = get_ld_command();
undef_file = create_undef_symbols_file( spec );
ld_tmp_file = get_temp_file_name( output_file_name, ".o" );
strarray_add( &args, "-r", "-o", ld_tmp_file, undef_file, NULL );
strarray_addv( &args, argv );
spawn( args );
return ld_tmp_file;
}
/* read in the list of undefined symbols */
void read_undef_symbols( DLLSPEC *spec, char **argv )
{
size_t prefix_len;
FILE *f;
const char *prog = get_nm_command();
char *cmd, buffer[1024], name_prefix[16];
int err;
const char *name;
if (!argv[0]) return;
add_extra_undef_symbols( spec );
strcpy( name_prefix, asm_name("") );
prefix_len = strlen( name_prefix );
name = ldcombine_files( spec, argv );
cmd = strmake( "%s -u %s", prog, name );
if (!(f = popen( cmd, "r" )))
fatal_error( "Cannot execute '%s'\n", cmd );
while (fgets( buffer, sizeof(buffer), f ))
{
char *p = buffer + strlen(buffer) - 1;
if (p < buffer) continue;
if (*p == '\n') *p-- = 0;
p = buffer;
while (*p == ' ') p++;
if (p[0] == 'U' && p[1] == ' ' && p[2]) p += 2;
if (prefix_len && !strncmp( p, name_prefix, prefix_len )) p += prefix_len;
if (!strncmp( p, import_func_prefix, strlen(import_func_prefix) ))
add_undef_import( p + strlen( import_func_prefix ), 0 );
else if (!strncmp( p, import_ord_prefix, strlen(import_ord_prefix) ))
add_undef_import( p + strlen( import_ord_prefix ), 1 );
else strarray_add( &undef_symbols, xstrdup( p ), NULL );
}
if ((err = pclose( f ))) warning( "%s failed with status %d\n", cmd, err );
free( cmd );
}
void resolve_dll_imports( DLLSPEC *spec, struct list *list )
{
unsigned int j;
struct import *imp, *next;
ORDDEF *odp;
LIST_FOR_EACH_ENTRY_SAFE( imp, next, list, struct import, entry )
{
for (j = 0; j < undef_symbols.count; j++)
{
odp = find_export( undef_symbols.str[j], imp->exports, imp->nb_exports );
if (odp)
{
if (odp->flags & FLAG_PRIVATE) continue;
if (odp->type != TYPE_STDCALL && odp->type != TYPE_CDECL)
warning( "winebuild: Data export '%s' cannot be imported from %s\n",
odp->link_name, imp->dll_name );
else
{
add_import_func( imp, (odp->flags & FLAG_NONAME) ? NULL : odp->name,
odp->export_name, odp->ordinal );
remove_name( &undef_symbols, j-- );
}
}
}
if (!imp->nb_imports)
{
/* the dll is not used, get rid of it */
if (check_unused( imp, spec ))
warning( "winebuild: %s imported but no symbols used\n", imp->dll_name );
list_remove( &imp->entry );
free_imports( imp );
}
}
}
/* resolve the imports for a Win32 module */
void resolve_imports( DLLSPEC *spec )
{
check_undefined_forwards( spec );
resolve_dll_imports( spec, &dll_imports );
resolve_dll_imports( spec, &dll_delayed );
sort_names( &undef_symbols );
check_undefined_exports( spec );
}
/* check if symbol is still undefined */
int is_undefined( const char *name )
{
return find_name( name, &undef_symbols ) != NULL;
}
/* output the get_pc thunk if needed */
void output_get_pc_thunk(void)
{
assert( target_cpu == CPU_x86 );
output( "\n\t.text\n" );
output( "\t.align %d\n", get_alignment(4) );
output( "\t%s\n", func_declaration("__wine_spec_get_pc_thunk_eax") );
output( "%s:\n", asm_name("__wine_spec_get_pc_thunk_eax") );
output_cfi( ".cfi_startproc" );
output( "\tmovl (%%esp),%%eax\n" );
output( "\tret\n" );
output_cfi( ".cfi_endproc" );
output_function_size( "__wine_spec_get_pc_thunk_eax" );
}
/* output a single import thunk */
static void output_import_thunk( const char *name, const char *table, int pos )
{
output( "\n\t.align %d\n", get_alignment(4) );
output( "\t%s\n", func_declaration(name) );
output( "%s\n", asm_globl(name) );
output_cfi( ".cfi_startproc" );
switch(target_cpu)
{
case CPU_x86:
if (!UsePIC)
{
output( "\tjmp *(%s+%d)\n", table, pos );
}
else
{
output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
output( "1:\tjmp *%s+%d-1b(%%eax)\n", table, pos );
needs_get_pc_thunk = 1;
}
break;
case CPU_x86_64:
output( "\tjmpq *%s+%d(%%rip)\n", table, pos );
break;
case CPU_ARM:
output( "\tldr IP,1f\n");
output( "\tldr PC,[PC,IP]\n" );
output( "1:\t.long %s+%u-(1b+4)\n", table, pos );
break;
case CPU_ARM64:
output( "\tadrp x9, %s\n", table );
output( "\tadd x9, x9, #:lo12:%s\n", table );
if (pos & 0xf000) output( "\tadd x9, x9, #%u\n", pos & 0xf000 );
if (pos & 0x0f00) output( "\tadd x9, x9, #%u\n", pos & 0x0f00 );
if (pos & 0x00f0) output( "\tadd x9, x9, #%u\n", pos & 0x00f0 );
if (pos & 0x000f) output( "\tadd x9, x9, #%u\n", pos & 0x000f );
output( "\tldur x9, [x9, #0]\n" );
output( "\tbr x9\n" );
break;
case CPU_POWERPC:
output( "\tmr %s, %s\n", ppc_reg(0), ppc_reg(31) );
if (target_platform == PLATFORM_APPLE)
{
output( "\tlis %s, ha16(%s+%d+32768)\n", ppc_reg(31), table, pos );
output( "\tla %s, lo16(%s+%d)(%s)\n", ppc_reg(31), table, pos, ppc_reg(31) );
}
else
{
output( "\tlis %s, (%s+%d+32768)@h\n", ppc_reg(31), table, pos );
output( "\tla %s, (%s+%d)@l(%s)\n", ppc_reg(31), table, pos, ppc_reg(31) );
}
output( "\tlwz %s, 0(%s)\n", ppc_reg(31), ppc_reg(31) );
output( "\tmtctr %s\n", ppc_reg(31) );
output( "\tmr %s, %s\n", ppc_reg(31), ppc_reg(0) );
output( "\tbctr\n" );
break;
}
output_cfi( ".cfi_endproc" );
output_function_size( name );
}
/* check if we need an import directory */
int has_imports(void)
{
return !list_empty( &dll_imports );
}
/* output the import table of a Win32 module */
static void output_immediate_imports(void)
{
int i, j;
struct import *import;
if (list_empty( &dll_imports )) return; /* no immediate imports */
/* main import header */
output( "\n/* import table */\n" );
output( "\n\t.data\n" );
output( "\t.align %d\n", get_alignment(4) );
output( ".L__wine_spec_imports:\n" );
/* list of dlls */
j = 0;
LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
{
output( "\t.long .L__wine_spec_import_data_names+%d-.L__wine_spec_rva_base\n", /* OriginalFirstThunk */
j * get_ptr_size() );
output( "\t.long 0\n" ); /* TimeDateStamp */
output( "\t.long 0\n" ); /* ForwarderChain */
output( "\t.long .L__wine_spec_import_name_%s-.L__wine_spec_rva_base\n", /* Name */
import->c_name );
output( "\t.long .L__wine_spec_import_data_ptrs+%d-.L__wine_spec_rva_base\n", /* FirstThunk */
j * get_ptr_size() );
j += import->nb_imports + 1;
}
output( "\t.long 0\n" ); /* OriginalFirstThunk */
output( "\t.long 0\n" ); /* TimeDateStamp */
output( "\t.long 0\n" ); /* ForwarderChain */
output( "\t.long 0\n" ); /* Name */
output( "\t.long 0\n" ); /* FirstThunk */
output( "\n\t.align %d\n", get_alignment(get_ptr_size()) );
/* output the names twice, once for OriginalFirstThunk and once for FirstThunk */
for (i = 0; i < 2; i++)
{
output( ".L__wine_spec_import_data_%s:\n", i ? "ptrs" : "names" );
LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
{
for (j = 0; j < import->nb_imports; j++)
{
struct import_func *func = &import->imports[j];
if (func->name)
output( "\t%s .L__wine_spec_import_data_%s_%s-.L__wine_spec_rva_base\n",
get_asm_ptr_keyword(), import->c_name, func->name );
else
{
if (get_ptr_size() == 8)
output( "\t.quad 0x800000000000%04x\n", func->ordinal );
else
output( "\t.long 0x8000%04x\n", func->ordinal );
}
}
output( "\t%s 0\n", get_asm_ptr_keyword() );
}
}
output( ".L__wine_spec_imports_end:\n" );
LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
{
for (j = 0; j < import->nb_imports; j++)
{
struct import_func *func = &import->imports[j];
if (!func->name) continue;
output( "\t.align %d\n", get_alignment(2) );
output( ".L__wine_spec_import_data_%s_%s:\n", import->c_name, func->name );
output( "\t.short %d\n", func->ordinal );
output( "\t%s \"%s\"\n", get_asm_string_keyword(), func->name );
}
}
LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
{
output( ".L__wine_spec_import_name_%s:\n\t%s \"%s\"\n",
import->c_name, get_asm_string_keyword(), import->dll_name );
}
}
/* output the import thunks of a Win32 module */
static void output_immediate_import_thunks(void)
{
int j, pos;
struct import *import;
static const char import_thunks[] = "__wine_spec_import_thunks";
if (list_empty( &dll_imports )) return;
output( "\n/* immediate import thunks */\n\n" );
output( "\t.text\n" );
output( "\t.align %d\n", get_alignment(8) );
output( "%s:\n", asm_name(import_thunks));
pos = 0;
LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
{
for (j = 0; j < import->nb_imports; j++, pos += get_ptr_size())
{
struct import_func *func = &import->imports[j];
output_import_thunk( func->name ? func->name : func->export_name,
".L__wine_spec_import_data_ptrs", pos );
}
pos += get_ptr_size();
}
output_function_size( import_thunks );
}
/* output the delayed import table of a Win32 module */
static void output_delayed_imports( const DLLSPEC *spec )
{
int j, mod;
struct import *import;
if (list_empty( &dll_delayed )) return;
output( "\n/* delayed imports */\n\n" );
output( "\t.data\n" );
output( "\t.align %d\n", get_alignment(get_ptr_size()) );
output( "%s\n", asm_globl("__wine_spec_delay_imports") );
/* list of dlls */
j = mod = 0;
LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
{
output( "\t%s 0\n", get_asm_ptr_keyword() ); /* grAttrs */
output( "\t%s .L__wine_delay_name_%s\n", /* szName */
get_asm_ptr_keyword(), import->c_name );
output( "\t%s .L__wine_delay_modules+%d\n", /* phmod */
get_asm_ptr_keyword(), mod * get_ptr_size() );
output( "\t%s .L__wine_delay_IAT+%d\n", /* pIAT */
get_asm_ptr_keyword(), j * get_ptr_size() );
output( "\t%s .L__wine_delay_INT+%d\n", /* pINT */
get_asm_ptr_keyword(), j * get_ptr_size() );
output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pBoundIAT */
output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pUnloadIAT */
output( "\t%s 0\n", get_asm_ptr_keyword() ); /* dwTimeStamp */
j += import->nb_imports;
mod++;
}
output( "\t%s 0\n", get_asm_ptr_keyword() ); /* grAttrs */
output( "\t%s 0\n", get_asm_ptr_keyword() ); /* szName */
output( "\t%s 0\n", get_asm_ptr_keyword() ); /* phmod */
output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pIAT */
output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pINT */
output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pBoundIAT */
output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pUnloadIAT */
output( "\t%s 0\n", get_asm_ptr_keyword() ); /* dwTimeStamp */
output( "\n.L__wine_delay_IAT:\n" );
LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
{
for (j = 0; j < import->nb_imports; j++)
{
struct import_func *func = &import->imports[j];
const char *name = func->name ? func->name : func->export_name;
output( "\t%s .L__wine_delay_imp_%s_%s\n",
get_asm_ptr_keyword(), import->c_name, name );
}
}
output( "\n.L__wine_delay_INT:\n" );
LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
{
for (j = 0; j < import->nb_imports; j++)
{
struct import_func *func = &import->imports[j];
if (!func->name)
output( "\t%s %d\n", get_asm_ptr_keyword(), func->ordinal );
else
output( "\t%s .L__wine_delay_data_%s_%s\n",
get_asm_ptr_keyword(), import->c_name, func->name );
}
}
output( "\n.L__wine_delay_modules:\n" );
LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
{
output( "\t%s 0\n", get_asm_ptr_keyword() );
}
LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
{
output( ".L__wine_delay_name_%s:\n", import->c_name );
output( "\t%s \"%s\"\n", get_asm_string_keyword(), import->dll_name );
}
LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
{
for (j = 0; j < import->nb_imports; j++)
{
struct import_func *func = &import->imports[j];
if (!func->name) continue;
output( ".L__wine_delay_data_%s_%s:\n", import->c_name, func->name );
output( "\t%s \"%s\"\n", get_asm_string_keyword(), func->name );
}
}
output_function_size( "__wine_spec_delay_imports" );
}
/* output the delayed import thunks of a Win32 module */
static void output_delayed_import_thunks( const DLLSPEC *spec )
{
int idx, j, pos, extra_stack_storage = 0;
struct import *import;
static const char delayed_import_loaders[] = "__wine_spec_delayed_import_loaders";
static const char delayed_import_thunks[] = "__wine_spec_delayed_import_thunks";
if (list_empty( &dll_delayed )) return;
output( "\n/* delayed import thunks */\n\n" );
output( "\t.text\n" );
output( "\t.align %d\n", get_alignment(8) );
output( "%s:\n", asm_name(delayed_import_loaders));
output( "\t%s\n", func_declaration("__wine_delay_load_asm") );
output( "%s:\n", asm_name("__wine_delay_load_asm") );
output_cfi( ".cfi_startproc" );
switch(target_cpu)
{
case CPU_x86:
output( "\tpushl %%ecx\n" );
output_cfi( ".cfi_adjust_cfa_offset 4" );
output( "\tpushl %%edx\n" );
output_cfi( ".cfi_adjust_cfa_offset 4" );
output( "\tpushl %%eax\n" );
output_cfi( ".cfi_adjust_cfa_offset 4" );
output( "\tcall %s\n", asm_name("__wine_spec_delay_load") );
output_cfi( ".cfi_adjust_cfa_offset -4" );
output( "\tpopl %%edx\n" );
output_cfi( ".cfi_adjust_cfa_offset -4" );
output( "\tpopl %%ecx\n" );
output_cfi( ".cfi_adjust_cfa_offset -4" );
output( "\tjmp *%%eax\n" );
break;
case CPU_x86_64:
output( "\tsubq $0x98,%%rsp\n" );
output_cfi( ".cfi_adjust_cfa_offset 0x98" );
output( "\tmovq %%rdx,0x88(%%rsp)\n" );
output( "\tmovq %%rcx,0x80(%%rsp)\n" );
output( "\tmovq %%r8,0x78(%%rsp)\n" );
output( "\tmovq %%r9,0x70(%%rsp)\n" );
output( "\tmovq %%r10,0x68(%%rsp)\n" );
output( "\tmovq %%r11,0x60(%%rsp)\n" );
output( "\tmovups %%xmm0,0x50(%%rsp)\n" );
output( "\tmovups %%xmm1,0x40(%%rsp)\n" );
output( "\tmovups %%xmm2,0x30(%%rsp)\n" );
output( "\tmovups %%xmm3,0x20(%%rsp)\n" );
output( "\tmovq %%rax,%%rcx\n" );
output( "\tcall %s\n", asm_name("__wine_spec_delay_load") );
output( "\tmovups 0x20(%%rsp),%%xmm3\n" );
output( "\tmovups 0x30(%%rsp),%%xmm2\n" );
output( "\tmovups 0x40(%%rsp),%%xmm1\n" );
output( "\tmovups 0x50(%%rsp),%%xmm0\n" );
output( "\tmovq 0x60(%%rsp),%%r11\n" );
output( "\tmovq 0x68(%%rsp),%%r10\n" );
output( "\tmovq 0x70(%%rsp),%%r9\n" );
output( "\tmovq 0x78(%%rsp),%%r8\n" );
output( "\tmovq 0x80(%%rsp),%%rcx\n" );
output( "\tmovq 0x88(%%rsp),%%rdx\n" );
output( "\taddq $0x98,%%rsp\n" );
output_cfi( ".cfi_adjust_cfa_offset -0x98" );
output( "\tjmp *%%rax\n" );
break;
case CPU_ARM:
output( "\tpush {r0-r3,FP,LR}\n" );
output( "\tmov r0,IP\n" );
output( "\tldr IP,2f\n");
output( "\tadd IP,PC\n");
output( "\tblx IP\n");
output( "1:\tmov IP,r0\n");
output( "\tpop {r0-r3,FP,LR}\n" );
output( "\tbx IP\n");
output( "2:\t.long %s-1b\n", asm_name("__wine_spec_delay_load") );
break;
case CPU_ARM64:
output( "\tstp x29, x30, [sp,#-16]!\n" );
output( "\tmov x29, sp\n" );
output( "\tadrp x9, %s\n", asm_name("__wine_spec_delay_load") );
output( "\tadd x9, x9, #:lo12:%s\n", asm_name("__wine_spec_delay_load") );
output( "\tblr x9\n" );
output( "\tmov x9, x0\n" );
output( "\tldp x29, x30, [sp],#16\n" );
output( "\tldp x0, x1, [sp,#16]\n" );
output( "\tldp x2, x3, [sp,#32]\n" );
output( "\tldp x4, x5, [sp,#48]\n" );
output( "\tldp x6, x7, [sp],#80\n" );
output( "\tbr x9\n" ); /* or "ret x9" */
break;
case CPU_POWERPC:
if (target_platform == PLATFORM_APPLE) extra_stack_storage = 56;
/* Save all callee saved registers into a stackframe. */
output( "\tstwu %s, -%d(%s)\n",ppc_reg(1), 48+extra_stack_storage, ppc_reg(1));
output( "\tstw %s, %d(%s)\n", ppc_reg(3), 4+extra_stack_storage, ppc_reg(1));
output( "\tstw %s, %d(%s)\n", ppc_reg(4), 8+extra_stack_storage, ppc_reg(1));
output( "\tstw %s, %d(%s)\n", ppc_reg(5), 12+extra_stack_storage, ppc_reg(1));
output( "\tstw %s, %d(%s)\n", ppc_reg(6), 16+extra_stack_storage, ppc_reg(1));
output( "\tstw %s, %d(%s)\n", ppc_reg(7), 20+extra_stack_storage, ppc_reg(1));
output( "\tstw %s, %d(%s)\n", ppc_reg(8), 24+extra_stack_storage, ppc_reg(1));
output( "\tstw %s, %d(%s)\n", ppc_reg(9), 28+extra_stack_storage, ppc_reg(1));
output( "\tstw %s, %d(%s)\n", ppc_reg(10),32+extra_stack_storage, ppc_reg(1));
output( "\tstw %s, %d(%s)\n", ppc_reg(11),36+extra_stack_storage, ppc_reg(1));
output( "\tstw %s, %d(%s)\n", ppc_reg(12),40+extra_stack_storage, ppc_reg(1));
/* r0 -> r3 (arg1) */
output( "\tmr %s, %s\n", ppc_reg(3), ppc_reg(0));
/* save return address */
output( "\tmflr %s\n", ppc_reg(0));
output( "\tstw %s, %d(%s)\n", ppc_reg(0), 44+extra_stack_storage, ppc_reg(1));
/* Call the __wine_delay_load function, arg1 is arg1. */
output( "\tbl %s\n", asm_name("__wine_spec_delay_load") );
/* Load return value from call into ctr register */
output( "\tmtctr %s\n", ppc_reg(3));
/* restore all saved registers and drop stackframe. */
output( "\tlwz %s, %d(%s)\n", ppc_reg(3), 4+extra_stack_storage, ppc_reg(1));
output( "\tlwz %s, %d(%s)\n", ppc_reg(4), 8+extra_stack_storage, ppc_reg(1));
output( "\tlwz %s, %d(%s)\n", ppc_reg(5), 12+extra_stack_storage, ppc_reg(1));
output( "\tlwz %s, %d(%s)\n", ppc_reg(6), 16+extra_stack_storage, ppc_reg(1));
output( "\tlwz %s, %d(%s)\n", ppc_reg(7), 20+extra_stack_storage, ppc_reg(1));
output( "\tlwz %s, %d(%s)\n", ppc_reg(8), 24+extra_stack_storage, ppc_reg(1));
output( "\tlwz %s, %d(%s)\n", ppc_reg(9), 28+extra_stack_storage, ppc_reg(1));
output( "\tlwz %s, %d(%s)\n", ppc_reg(10),32+extra_stack_storage, ppc_reg(1));
output( "\tlwz %s, %d(%s)\n", ppc_reg(11),36+extra_stack_storage, ppc_reg(1));
output( "\tlwz %s, %d(%s)\n", ppc_reg(12),40+extra_stack_storage, ppc_reg(1));
/* Load return value from call into return register */
output( "\tlwz %s, %d(%s)\n", ppc_reg(0), 44+extra_stack_storage, ppc_reg(1));
output( "\tmtlr %s\n", ppc_reg(0));
output( "\taddi %s, %s, %d\n", ppc_reg(1), ppc_reg(1), 48+extra_stack_storage);
/* branch to ctr register. */
output( "\tbctr\n");
break;
}
output_cfi( ".cfi_endproc" );
output_function_size( "__wine_delay_load_asm" );
output( "\n" );
idx = 0;
LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
{
for (j = 0; j < import->nb_imports; j++)
{
struct import_func *func = &import->imports[j];
const char *name = func->name ? func->name : func->export_name;
output( ".L__wine_delay_imp_%s_%s:\n", import->c_name, name );
output_cfi( ".cfi_startproc" );
switch(target_cpu)
{
case CPU_x86:
output( "\tmovl $%d, %%eax\n", (idx << 16) | j );
output( "\tjmp %s\n", asm_name("__wine_delay_load_asm") );
break;
case CPU_x86_64:
output( "\tmovq $%d,%%rax\n", (idx << 16) | j );
output( "\tjmp %s\n", asm_name("__wine_delay_load_asm") );
break;
case CPU_ARM:
{
unsigned int mask, count = 0, val = (idx << 16) | j;
for (mask = 0xff; mask; mask <<= 8)
if (val & mask) output( "\t%s IP,#%u\n", count++ ? "add" : "mov", val & mask );
if (!count) output( "\tmov IP,#0\n" );
output( "\tb %s\n", asm_name("__wine_delay_load_asm") );
break;
}
case CPU_ARM64:
output( "\tstp x6, x7, [sp,#-80]!\n" );
output( "\tstp x4, x5, [sp,#48]\n" );
output( "\tstp x2, x3, [sp,#32]\n" );
output( "\tstp x0, x1, [sp,#16]\n" );
output( "\tmov x0, #%d\n", idx );
output( "\tmov x1, #16384\n" );
output( "\tmul x1, x0, x1\n" );
output( "\tmov x0, x1\n" );
output( "\tmov x1, #4\n" );
output( "\tmul x1, x0, x1\n" );
output( "\tmov x0, x1\n" );
output( "\tadd x0, x0, #%d\n", j );
output( "\tadr x9, %s\n", asm_name("__wine_delay_load_asm") );
output( "\tbr x9\n" );
break;
case CPU_POWERPC:
switch(target_platform)
{
case PLATFORM_APPLE:
/* On Darwin we can use r0 and r2 */
/* Upper part in r2 */
output( "\tlis %s, %d\n", ppc_reg(2), idx);
/* Lower part + r2 -> r0, Note we can't use r0 directly */
output( "\taddi %s, %s, %d\n", ppc_reg(0), ppc_reg(2), j);
output( "\tb %s\n", asm_name("__wine_delay_load_asm") );
break;
default:
/* On linux we can't use r2 since r2 is not a scratch register (hold the TOC) */
/* Save r13 on the stack */
output( "\taddi %s, %s, -0x4\n", ppc_reg(1), ppc_reg(1));
output( "\tstw %s, 0(%s)\n", ppc_reg(13), ppc_reg(1));
/* Upper part in r13 */
output( "\tlis %s, %d\n", ppc_reg(13), idx);
/* Lower part + r13 -> r0, Note we can't use r0 directly */
output( "\taddi %s, %s, %d\n", ppc_reg(0), ppc_reg(13), j);
/* Restore r13 */
output( "\tstw %s, 0(%s)\n", ppc_reg(13), ppc_reg(1));
output( "\taddic %s, %s, 0x4\n", ppc_reg(1), ppc_reg(1));
output( "\tb %s\n", asm_name("__wine_delay_load_asm") );
break;
}
break;
}
output_cfi( ".cfi_endproc" );
}
idx++;
}
output_function_size( delayed_import_loaders );
output( "\n\t.align %d\n", get_alignment(get_ptr_size()) );
output( "%s:\n", asm_name(delayed_import_thunks));
pos = 0;
LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
{
for (j = 0; j < import->nb_imports; j++, pos += get_ptr_size())
{
struct import_func *func = &import->imports[j];
output_import_thunk( func->name ? func->name : func->export_name,
".L__wine_delay_IAT", pos );
}
}
output_function_size( delayed_import_thunks );
}
/* output import stubs for exported entry points that link to external symbols */
static void output_external_link_imports( DLLSPEC *spec )
{
unsigned int i, pos;
if (!ext_link_imports.count) return; /* nothing to do */
sort_names( &ext_link_imports );
/* get rid of duplicate names */
for (i = 1; i < ext_link_imports.count; i++)
{
if (!strcmp( ext_link_imports.str[i-1], ext_link_imports.str[i] ))
remove_name( &ext_link_imports, i-- );
}
output( "\n/* external link thunks */\n\n" );
output( "\t.data\n" );
output( "\t.align %d\n", get_alignment(get_ptr_size()) );
output( ".L__wine_spec_external_links:\n" );
for (i = 0; i < ext_link_imports.count; i++)
output( "\t%s %s\n", get_asm_ptr_keyword(), asm_name(ext_link_imports.str[i]) );
output( "\n\t.text\n" );
output( "\t.align %d\n", get_alignment(get_ptr_size()) );
output( "%s:\n", asm_name("__wine_spec_external_link_thunks") );
for (i = pos = 0; i < ext_link_imports.count; i++)
{
char *buffer = strmake( "__wine_spec_ext_link_%s", ext_link_imports.str[i] );
output_import_thunk( buffer, ".L__wine_spec_external_links", pos );
free( buffer );
pos += get_ptr_size();
}
output_function_size( "__wine_spec_external_link_thunks" );
}
/*******************************************************************
* output_stubs
*
* Output the functions for stub entry points
*/
void output_stubs( DLLSPEC *spec )
{
const char *name, *exp_name;
int i, count;
if (!has_stubs( spec )) return;
output( "\n/* stub functions */\n\n" );
output( "\t.text\n" );
for (i = count = 0; i < spec->nb_entry_points; i++)
{
ORDDEF *odp = &spec->entry_points[i];
if (odp->type != TYPE_STUB) continue;
name = get_stub_name( odp, spec );
exp_name = odp->name ? odp->name : odp->export_name;
output( "\t.align %d\n", get_alignment(4) );
output( "\t%s\n", func_declaration(name) );
output( "%s:\n", (name) );
output_cfi( ".cfi_startproc" );
switch (target_cpu)
{
case CPU_x86:
/* flesh out the stub a bit to make safedisc happy */
output(" \tnop\n" );
output(" \tnop\n" );
output(" \tnop\n" );
output(" \tnop\n" );
output(" \tnop\n" );
output(" \tnop\n" );
output(" \tnop\n" );
output(" \tnop\n" );
output(" \tnop\n" );
output( "\tsubl $12,%%esp\n" );
output_cfi( ".cfi_adjust_cfa_offset 12" );
if (UsePIC)
{
output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
output( "1:" );
needs_get_pc_thunk = 1;
if (exp_name)
{
output( "\tleal .L%s_string-1b(%%eax),%%ecx\n", name );
output( "\tmovl %%ecx,4(%%esp)\n" );
count++;
}
else
output( "\tmovl $%d,4(%%esp)\n", odp->ordinal );
output( "\tleal .L__wine_spec_file_name-1b(%%eax),%%ecx\n" );
output( "\tmovl %%ecx,(%%esp)\n" );
}
else
{
if (exp_name)
{
output( "\tmovl $.L%s_string,4(%%esp)\n", name );
count++;
}
else
output( "\tmovl $%d,4(%%esp)\n", odp->ordinal );
output( "\tmovl $.L__wine_spec_file_name,(%%esp)\n" );
}
output( "\tcall %s\n", asm_name("__wine_spec_unimplemented_stub") );
break;
case CPU_x86_64:
output( "\tsubq $8,%%rsp\n" );
output_cfi( ".cfi_adjust_cfa_offset 8" );
output( "\tleaq .L__wine_spec_file_name(%%rip),%%rdi\n" );
if (exp_name)
{
output( "leaq .L%s_string(%%rip),%%rsi\n", name );
count++;
}
else
output( "\tmovq $%d,%%rsi\n", odp->ordinal );
output( "\tcall %s\n", asm_name("__wine_spec_unimplemented_stub") );
break;
case CPU_ARM:
output( "\tldr r0,2f\n");
output( "\tadd r0,PC\n");
output( "\tldr r1,2f+4\n");
output( "1:" );
if (exp_name)
{
output( "\tadd r1,PC\n");
count++;
}
output( "\tbl %s\n", asm_name("__wine_spec_unimplemented_stub") );
output( "2:\t.long .L__wine_spec_file_name-1b\n" );
if (exp_name) output( "\t.long .L%s_string-2b\n", name );
else output( "\t.long %u\n", odp->ordinal );
break;
case CPU_ARM64:
output( "\tadrp x0, %s\n", asm_name("__wine_spec_file_name") );
output( "\tadd x0, x0, #:lo12:%s\n", asm_name("__wine_spec_file_name") );
if (exp_name)
{
output( "\tadrp x1, .L%s_string\n", name );
output( "\tadd x1, x1, #:lo12:.L%s_string\n", name );
count++;
}
else
output( "\tmov x1, %u\n", odp->ordinal );
output( "\tadrp x2, %s\n", asm_name("__wine_spec_unimplemented_stub") );
output( "\tadd x2, x2, #:lo12:%s\n", asm_name("__wine_spec_unimplemented_stub") );
output( "\tblr x2\n" );
break;
default:
assert(0);
}
output_cfi( ".cfi_endproc" );
output_function_size( name );
}
if (count)
{
output( "\t%s\n", get_asm_string_section() );
for (i = 0; i < spec->nb_entry_points; i++)
{
ORDDEF *odp = &spec->entry_points[i];
if (odp->type != TYPE_STUB) continue;
exp_name = odp->name ? odp->name : odp->export_name;
if (exp_name)
{
name = get_stub_name( odp, spec );
output( ".L%s_string:\n", name );
output( "\t%s \"%s\"\n", get_asm_string_keyword(), exp_name );
}
}
}
}
/* output the import and delayed import tables of a Win32 module */
void output_imports( DLLSPEC *spec )
{
output_immediate_imports();
output_delayed_imports( spec );
output_immediate_import_thunks();
output_delayed_import_thunks( spec );
output_external_link_imports( spec );
}
/* create a new asm temp file */
static void new_output_as_file( const char *prefix )
{
char *name = get_temp_file_name( prefix, ".s" );
if (output_file) fclose( output_file );
if (!(output_file = fopen( name, "w" )))
fatal_error( "Unable to create output file '%s'\n", name );
strarray_add( &as_files, name, NULL );
}
/* assemble all the asm files */
static void assemble_files( const char *prefix )
{
unsigned int i;
if (output_file) fclose( output_file );
output_file = NULL;
for (i = 0; i < as_files.count; i++)
{
char *obj = get_temp_file_name( prefix, ".o" );
assemble_file( as_files.str[i], obj );
as_files.str[i] = obj;
}
}
/* build a library from the current asm files and any additional object files in argv */
static void build_library( const char *output_name, char **argv, int create )
{
struct strarray args = find_tool( "ar", NULL );
struct strarray ranlib = find_tool( "ranlib", NULL );
strarray_add( &args, create ? "rc" : "r", output_name, NULL );
strarray_addall( &args, as_files );
strarray_addv( &args, argv );
if (create) unlink( output_name );
spawn( args );
strarray_add( &ranlib, output_name, NULL );
spawn( ranlib );
}
/* create a Windows-style import library */
static void build_windows_import_lib( DLLSPEC *spec )
{
struct strarray args;
char *def_file;
const char *as_flags, *m_flag;
def_file = get_temp_file_name( output_file_name, ".def" );
fclose( output_file );
if (!(output_file = fopen( def_file, "w" )))
fatal_error( "Unable to create output file '%s'\n", def_file );
output_def_file( spec, 0 );
fclose( output_file );
output_file = NULL;
args = find_tool( "dlltool", NULL );
switch (target_cpu)
{
case CPU_x86:
m_flag = "i386";
as_flags = "--as-flags=--32";
break;
case CPU_x86_64:
m_flag = "i386:x86-64";
as_flags = "--as-flags=--64";
break;
default:
m_flag = NULL;
break;
}
strarray_add( &args, "-k", "-l", output_file_name, "-d", def_file, NULL );
if (m_flag)
strarray_add( &args, "-m", m_flag, as_flags, NULL );
spawn( args );
}
/* create a Unix-style import library */
static void build_unix_import_lib( DLLSPEC *spec )
{
static const char valid_chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789._@";
int i, total;
const char *name, *prefix;
char *dll_name = xstrdup( spec->file_name );
if (strendswith( dll_name, ".dll" )) dll_name[strlen(dll_name) - 4] = 0;
if (strspn( dll_name, valid_chars ) < strlen( dll_name ))
fatal_error( "%s contains invalid characters\n", spec->file_name );
/* entry points */
for (i = total = 0; i < spec->nb_entry_points; i++)
{
const ORDDEF *odp = &spec->entry_points[i];
if (odp->name) name = odp->name;
else if (odp->export_name) name = odp->export_name;
else continue;
if (odp->flags & FLAG_PRIVATE) continue;
total++;
/* C++ mangled names cannot be imported */
if (strpbrk( name, "?@" )) continue;
switch(odp->type)
{
case TYPE_VARARGS:
case TYPE_CDECL:
case TYPE_STDCALL:
case TYPE_THISCALL:
prefix = (!odp->name || (odp->flags & FLAG_ORDINAL)) ? import_ord_prefix : import_func_prefix;
new_output_as_file( spec->file_name );
output( "\t.text\n" );
output( "\n\t.align %d\n", get_alignment( get_ptr_size() ));
output( "\t%s\n", func_declaration( name ) );
output( "%s\n", asm_globl( name ) );
output( "\t%s %s%s$%u$%s\n", get_asm_ptr_keyword(),
asm_name( prefix ), dll_name, odp->ordinal, name );
output_function_size( name );
output_gnu_stack_note();
break;
default:
break;
}
}
if (!total) warning( "%s: Import library doesn't export anything\n", spec->file_name );
if (!as_files.count) /* create a dummy file to avoid empty import libraries */
{
new_output_as_file( spec->file_name );
output( "\t.text\n" );
}
assemble_files( spec->file_name );
free( dll_name );
}
/* output an import library for a Win32 module and additional object files */
void output_import_lib( DLLSPEC *spec, char **argv )
{
if (target_platform == PLATFORM_WINDOWS)
{
build_windows_import_lib( spec );
if (argv[0]) build_library( output_file_name, argv, 0 );
}
else
{
build_unix_import_lib( spec );
build_library( output_file_name, argv, 1 );
}
output_file_name = NULL;
}
================================================
FILE: convspec/main.c.h
================================================
/*
* winebuild main function
*
* Copyright 1993 Robert J. Amstadt
* Copyright 1995 Martin von Loewis
* Copyright 1995, 1996, 1997 Alexandre Julliard
* Copyright 1997 Eric Youngdale
* Copyright 1999 Ulrich Weigand
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#include "wine/port.h"
#include
#include
#include
#include
#include
#include
#include
#ifdef HAVE_GETOPT_H
# include
#endif
#include "build.h"
int UsePIC = 0;
int nb_errors = 0;
int display_warnings = 0;
int kill_at = 0;
int verbose = 0;
int link_ext_symbols = 0;
int force_pointer_size = 0;
int unwind_tables = 0;
#ifdef __i386__
enum target_cpu target_cpu = CPU_x86;
#elif defined(__x86_64__)
enum target_cpu target_cpu = CPU_x86_64;
#elif defined(__powerpc__)
enum target_cpu target_cpu = CPU_POWERPC;
#elif defined(__arm__)
enum target_cpu target_cpu = CPU_ARM;
#elif defined(__aarch64__)
enum target_cpu target_cpu = CPU_ARM64;
#else
#error Unsupported CPU
#endif
#ifdef __APPLE__
enum target_platform target_platform = PLATFORM_APPLE;
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
enum target_platform target_platform = PLATFORM_FREEBSD;
#elif defined(__sun)
enum target_platform target_platform = PLATFORM_SOLARIS;
#elif defined(_WIN32)
enum target_platform target_platform = PLATFORM_WINDOWS;
#else
enum target_platform target_platform = PLATFORM_UNSPECIFIED;
#endif
char *target_alias = NULL;
char *input_file_name = NULL;
char *spec_file_name = NULL;
FILE *output_file = NULL;
const char *output_file_name = NULL;
static const char *output_file_source_name;
static int fake_module;
struct strarray lib_path = { 0 };
struct strarray as_command = { 0 };
struct strarray cc_command = { 0 };
struct strarray ld_command = { 0 };
struct strarray nm_command = { 0 };
char *cpu_option = NULL;
char *arch_option = NULL;
#ifdef __SOFTFP__
const char *float_abi_option = "soft";
#else
const char *float_abi_option = "softfp";
#endif
#ifdef __thumb__
int thumb_mode = 1;
#else
int thumb_mode = 0;
#endif
static struct strarray res_files;
/* execution mode */
enum exec_mode_values
{
MODE_NONE,
MODE_DLL,
MODE_EXE,
MODE_DEF,
MODE_IMPLIB,
MODE_RESOURCES
};
static enum exec_mode_values exec_mode = MODE_NONE;
static const struct
{
const char *name;
enum target_platform platform;
} platform_names[] =
{
{ "macos", PLATFORM_APPLE },
{ "darwin", PLATFORM_APPLE },
{ "freebsd", PLATFORM_FREEBSD },
{ "solaris", PLATFORM_SOLARIS },
{ "mingw32", PLATFORM_WINDOWS },
{ "windows", PLATFORM_WINDOWS },
{ "winnt", PLATFORM_WINDOWS }
};
/* set the dll file name from the input file name */
static void set_dll_file_name( const char *name, DLLSPEC *spec )
{
char *p;
if (spec->file_name) return;
if ((p = strrchr( name, '\\' ))) name = p + 1;
if ((p = strrchr( name, '/' ))) name = p + 1;
spec->file_name = xmalloc( strlen(name) + 5 );
strcpy( spec->file_name, name );
if ((p = strrchr( spec->file_name, '.' )))
{
if (!strcmp( p, ".spec" ) || !strcmp( p, ".def" )) *p = 0;
}
}
/* set the dll name from the file name */
static void init_dll_name( DLLSPEC *spec )
{
if (!spec->file_name && output_file_name)
{
char *p;
spec->file_name = xstrdup( output_file_name );
if ((p = strrchr( spec->file_name, '.' ))) *p = 0;
}
if (!spec->dll_name && spec->file_name) /* set default name from file name */
{
char *p;
spec->dll_name = xstrdup( spec->file_name );
if ((p = strrchr( spec->dll_name, '.' ))) *p = 0;
}
spec->c_name = make_c_identifier( spec->dll_name );
}
/* set the dll subsystem */
static void set_subsystem( const char *subsystem, DLLSPEC *spec )
{
char *major, *minor, *str = xstrdup( subsystem );
if ((major = strchr( str, ':' ))) *major++ = 0;
if (!strcmp( str, "native" )) spec->subsystem = IMAGE_SUBSYSTEM_NATIVE;
else if (!strcmp( str, "windows" )) spec->subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI;
else if (!strcmp( str, "console" )) spec->subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI;
else if (!strcmp( str, "wince" )) spec->subsystem = IMAGE_SUBSYSTEM_WINDOWS_CE_GUI;
else if (!strcmp( str, "win16" )) spec->type = SPEC_WIN16;
else fatal_error( "Invalid subsystem name '%s'\n", subsystem );
if (major)
{
if ((minor = strchr( major, '.' )))
{
*minor++ = 0;
spec->subsystem_minor = atoi( minor );
}
spec->subsystem_major = atoi( major );
}
free( str );
}
/* set the target CPU and platform */
static void set_target( const char *target )
{
unsigned int i;
char *p, *platform, *spec = xstrdup( target );
/* target specification is in the form CPU-MANUFACTURER-OS or CPU-MANUFACTURER-KERNEL-OS */
target_alias = xstrdup( target );
/* get the CPU part */
if ((p = strchr( spec, '-' )))
{
int cpu;
*p++ = 0;
cpu = get_cpu_from_name( spec );
if (cpu == -1) fatal_error( "Unrecognized CPU '%s'\n", spec );
target_cpu = cpu;
platform = p;
if ((p = strrchr( p, '-' ))) platform = p + 1;
}
else if (!strcmp( spec, "mingw32" ))
{
target_cpu = CPU_x86;
platform = spec;
}
else
fatal_error( "Invalid target specification '%s'\n", target );
/* get the OS part */
target_platform = PLATFORM_UNSPECIFIED; /* default value */
for (i = 0; i < sizeof(platform_names)/sizeof(platform_names[0]); i++)
{
if (!strncmp( platform_names[i].name, platform, strlen(platform_names[i].name) ))
{
target_platform = platform_names[i].platform;
break;
}
}
free( spec );
}
/* cleanup on program exit */
static void cleanup(void)
{
if (output_file_name) unlink( output_file_name );
}
/* clean things up when aborting on a signal */
static void exit_on_signal( int sig )
{
exit(1); /* this will call atexit functions */
}
/*******************************************************************
* command-line option handling
*/
static const char usage_str[] =
"Usage: winebuild [OPTIONS] [FILES]\n\n"
"Options:\n"
" --as-cmd=AS Command to use for assembling (default: as)\n"
" -b, --target=TARGET Specify target CPU and platform for cross-compiling\n"
" --cc-cmd=CC C compiler to use for assembling (default: fall back to --as-cmd)\n"
" -d, --delay-lib=LIB Import the specified library in delayed mode\n"
" -D SYM Ignored for C flags compatibility\n"
" -e, --entry=FUNC Set the DLL entry point function (default: DllMain)\n"
" -E, --export=FILE Export the symbols defined in the .spec or .def file\n"
" --external-symbols Allow linking to external symbols\n"
" -f FLAGS Compiler flags (-fPIC and -fasynchronous-unwind-tables are supported)\n"
" -F, --filename=DLLFILE Set the DLL filename (default: from input file name)\n"
" --fake-module Create a fake binary module\n"
" -h, --help Display this help message\n"
" -H, --heap=SIZE Set the heap size for a Win16 dll\n"
" -I DIR Ignored for C flags compatibility\n"
" -k, --kill-at Kill stdcall decorations in generated .def files\n"
" -K, FLAGS Compiler flags (only -KPIC is supported)\n"
" --large-address-aware Support an address space larger than 2Gb\n"
" --ld-cmd=LD Command to use for linking (default: ld)\n"
" -l, --library=LIB Import the specified library\n"
" -L, --library-path=DIR Look for imports libraries in DIR\n"
" -m16, -m32, -m64 Force building 16-bit, 32-bit resp. 64-bit code\n"
" -M, --main-module=MODULE Set the name of the main module for a Win16 dll\n"
" --nm-cmd=NM Command to use to get undefined symbols (default: nm)\n"
" --nxcompat=y|n Set the NX compatibility flag (default: yes)\n"
" -N, --dll-name=DLLNAME Set the DLL name (default: from input file name)\n"
" -o, --output=NAME Set the output file name (default: stdout)\n"
" -r, --res=RSRC.RES Load resources from RSRC.RES\n"
" --save-temps Do not delete the generated intermediate files\n"
" --subsystem=SUBSYS Set the subsystem (one of native, windows, console, wince)\n"
" -u, --undefined=SYMBOL Add an undefined reference to SYMBOL when linking\n"
" -v, --verbose Display the programs invoked\n"
" --version Print the version and exit\n"
" -w, --warnings Turn on warnings\n"
"\nMode options:\n"
" --dll Build a .c file from a .spec or .def file\n"
" --def Build a .def file from a .spec file\n"
" --exe Build a .c file for an executable\n"
" --implib Build an import library\n"
" --resources Build a .o file for the resource files\n\n"
"The mode options are mutually exclusive; you must specify one and only one.\n\n";
enum long_options_values
{
LONG_OPT_DLL = 1,
LONG_OPT_DEF,
LONG_OPT_EXE,
LONG_OPT_IMPLIB,
LONG_OPT_ASCMD,
LONG_OPT_CCCMD,
LONG_OPT_EXTERNAL_SYMS,
LONG_OPT_FAKE_MODULE,
LONG_OPT_LARGE_ADDRESS_AWARE,
LONG_OPT_LDCMD,
LONG_OPT_NMCMD,
LONG_OPT_NXCOMPAT,
LONG_OPT_RESOURCES,
LONG_OPT_SAVE_TEMPS,
LONG_OPT_SUBSYSTEM,
LONG_OPT_VERSION
};
static const char short_options[] = "C:D:E:F:H:I:K:L:M:N:b:d:e:f:hkl:m:o:r:u:vw";
static const struct option long_options[] =
{
{ "dll", 0, 0, LONG_OPT_DLL },
{ "def", 0, 0, LONG_OPT_DEF },
{ "exe", 0, 0, LONG_OPT_EXE },
{ "implib", 0, 0, LONG_OPT_IMPLIB },
{ "as-cmd", 1, 0, LONG_OPT_ASCMD },
{ "cc-cmd", 1, 0, LONG_OPT_CCCMD },
{ "external-symbols", 0, 0, LONG_OPT_EXTERNAL_SYMS },
{ "fake-module", 0, 0, LONG_OPT_FAKE_MODULE },
{ "large-address-aware", 0, 0, LONG_OPT_LARGE_ADDRESS_AWARE },
{ "ld-cmd", 1, 0, LONG_OPT_LDCMD },
{ "nm-cmd", 1, 0, LONG_OPT_NMCMD },
{ "nxcompat", 1, 0, LONG_OPT_NXCOMPAT },
{ "resources", 0, 0, LONG_OPT_RESOURCES },
{ "save-temps", 0, 0, LONG_OPT_SAVE_TEMPS },
{ "subsystem", 1, 0, LONG_OPT_SUBSYSTEM },
{ "version", 0, 0, LONG_OPT_VERSION },
/* aliases for short options */
{ "target", 1, 0, 'b' },
{ "delay-lib", 1, 0, 'd' },
{ "export", 1, 0, 'E' },
{ "entry", 1, 0, 'e' },
{ "filename", 1, 0, 'F' },
{ "help", 0, 0, 'h' },
{ "heap", 1, 0, 'H' },
{ "kill-at", 0, 0, 'k' },
{ "library", 1, 0, 'l' },
{ "library-path", 1, 0, 'L' },
{ "main-module", 1, 0, 'M' },
{ "dll-name", 1, 0, 'N' },
{ "output", 1, 0, 'o' },
{ "res", 1, 0, 'r' },
{ "undefined", 1, 0, 'u' },
{ "verbose", 0, 0, 'v' },
{ "warnings", 0, 0, 'w' },
{ NULL, 0, 0, 0 }
};
static void usage( int exit_code )
{
fprintf( stderr, "%s", usage_str );
exit( exit_code );
}
static void set_exec_mode( enum exec_mode_values mode )
{
if (exec_mode != MODE_NONE) usage(1);
exec_mode = mode;
}
/* parse options from the argv array and remove all the recognized ones */
static char **parse_options( int argc, char **argv, DLLSPEC *spec )
{
char *p;
int optc;
int save_temps = 0;
while ((optc = getopt_long( argc, argv, short_options, long_options, NULL )) != -1)
{
switch(optc)
{
case 'D':
/* ignored */
break;
case 'E':
spec_file_name = xstrdup( optarg );
set_dll_file_name( optarg, spec );
break;
case 'F':
spec->file_name = xstrdup( optarg );
break;
case 'H':
if (!isdigit(optarg[0]))
fatal_error( "Expected number argument with -H option instead of '%s'\n", optarg );
spec->heap_size = atoi(optarg);
if (spec->heap_size > 65535)
fatal_error( "Invalid heap size %d, maximum is 65535\n", spec->heap_size );
break;
case 'I':
/* ignored */
break;
case 'K':
/* ignored, because cc generates correct code. */
break;
case 'L':
strarray_add( &lib_path, xstrdup( optarg ), NULL );
break;
case 'm':
if (!strcmp( optarg, "16" )) spec->type = SPEC_WIN16;
else if (!strcmp( optarg, "32" )) force_pointer_size = 4;
else if (!strcmp( optarg, "64" )) force_pointer_size = 8;
else if (!strcmp( optarg, "arm" )) thumb_mode = 0;
else if (!strcmp( optarg, "thumb" )) thumb_mode = 1;
else if (!strncmp( optarg, "cpu=", 4 )) cpu_option = xstrdup( optarg + 4 );
else if (!strncmp( optarg, "arch=", 5 )) arch_option = xstrdup( optarg + 5 );
else if (!strncmp( optarg, "float-abi=", 10 )) float_abi_option = xstrdup( optarg + 10 );
else fatal_error( "Unknown -m option '%s'\n", optarg );
break;
case 'M':
spec->main_module = xstrdup( optarg );
break;
case 'N':
spec->dll_name = xstrdup( optarg );
break;
case 'b':
set_target( optarg );
break;
case 'd':
add_delayed_import( optarg );
break;
case 'e':
spec->init_func = xstrdup( optarg );
if ((p = strchr( spec->init_func, '@' ))) *p = 0; /* kill stdcall decoration */
break;
case 'f':
if (!strcmp( optarg, "PIC") || !strcmp( optarg, "pic")) UsePIC = 1;
else if (!strcmp( optarg, "asynchronous-unwind-tables")) unwind_tables = 1;
else if (!strcmp( optarg, "no-asynchronous-unwind-tables")) unwind_tables = 0;
/* ignore all other flags */
break;
case 'h':
usage(0);
break;
case 'k':
kill_at = 1;
break;
case 'l':
add_import_dll( optarg, NULL );
break;
case 'o':
{
char *ext = strrchr( optarg, '.' );
if (unlink( optarg ) == -1 && errno != ENOENT)
fatal_error( "Unable to create output file '%s'\n", optarg );
if (ext && !strcmp( ext, ".o" ))
{
output_file_source_name = get_temp_file_name( optarg, ".s" );
if (!(output_file = fopen( output_file_source_name, "w" )))
fatal_error( "Unable to create output file '%s'\n", optarg );
}
else
{
if (!(output_file = fopen( optarg, "w" )))
fatal_error( "Unable to create output file '%s'\n", optarg );
}
output_file_name = xstrdup(optarg);
atexit( cleanup ); /* make sure we remove the output file on exit */
}
break;
case 'r':
strarray_add( &res_files, xstrdup( optarg ), NULL );
break;
case 'u':
add_extra_ld_symbol( optarg );
break;
case 'v':
verbose++;
break;
case 'w':
display_warnings = 1;
break;
case LONG_OPT_DLL:
set_exec_mode( MODE_DLL );
break;
case LONG_OPT_DEF:
set_exec_mode( MODE_DEF );
break;
case LONG_OPT_EXE:
set_exec_mode( MODE_EXE );
if (!spec->subsystem) spec->subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI;
break;
case LONG_OPT_IMPLIB:
set_exec_mode( MODE_IMPLIB );
break;
case LONG_OPT_ASCMD:
as_command = strarray_fromstring( optarg, " " );
break;
case LONG_OPT_CCCMD:
cc_command = strarray_fromstring( optarg, " " );
break;
case LONG_OPT_FAKE_MODULE:
fake_module = 1;
break;
case LONG_OPT_EXTERNAL_SYMS:
link_ext_symbols = 1;
break;
case LONG_OPT_LARGE_ADDRESS_AWARE:
spec->characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE;
break;
case LONG_OPT_LDCMD:
ld_command = strarray_fromstring( optarg, " " );
break;
case LONG_OPT_NMCMD:
nm_command = strarray_fromstring( optarg, " " );
break;
case LONG_OPT_NXCOMPAT:
if (optarg[0] == 'n' || optarg[0] == 'N')
spec->dll_characteristics &= ~IMAGE_DLLCHARACTERISTICS_NX_COMPAT;
break;
case LONG_OPT_RESOURCES:
set_exec_mode( MODE_RESOURCES );
break;
case LONG_OPT_SAVE_TEMPS:
save_temps = 1;
break;
case LONG_OPT_SUBSYSTEM:
set_subsystem( optarg, spec );
break;
case LONG_OPT_VERSION:
printf( "winebuild version " PACKAGE_VERSION "\n" );
exit(0);
case '?':
usage(1);
break;
}
}
if (!save_temps) atexit( cleanup_tmp_files );
if (spec->file_name && !strchr( spec->file_name, '.' ))
strcat( spec->file_name, exec_mode == MODE_EXE ? ".exe" : ".dll" );
init_dll_name( spec );
switch (target_cpu)
{
case CPU_x86:
if (force_pointer_size == 8) target_cpu = CPU_x86_64;
break;
case CPU_x86_64:
if (force_pointer_size == 4) target_cpu = CPU_x86;
break;
default:
if (force_pointer_size == 8)
fatal_error( "Cannot build 64-bit code for this CPU\n" );
break;
}
return &argv[optind];
}
/* load all specified resource files */
static void load_resources( char *argv[], DLLSPEC *spec )
{
int i;
char **ptr, **last;
switch (spec->type)
{
case SPEC_WIN16:
for (i = 0; i < res_files.count; i++) load_res16_file( res_files.str[i], spec );
break;
case SPEC_WIN32:
for (i = 0; i < res_files.count; i++)
{
if (!load_res32_file( res_files.str[i], spec ))
fatal_error( "%s is not a valid Win32 resource file\n", res_files.str[i] );
}
/* load any resource file found in the remaining arguments */
for (ptr = last = argv; *ptr; ptr++)
{
if (!load_res32_file( *ptr, spec ))
*last++ = *ptr; /* not a resource file, keep it in the list */
}
*last = NULL;
break;
}
}
/* add input files that look like import libs to the import list */
static void load_import_libs( char *argv[] )
{
char **ptr, **last;
for (ptr = last = argv; *ptr; ptr++)
{
if (strendswith( *ptr, ".def" ))
add_import_dll( NULL, *ptr );
else
*last++ = *ptr; /* not an import dll, keep it in the list */
}
*last = NULL;
}
static int parse_input_file( DLLSPEC *spec )
{
FILE *input_file = open_input_file( NULL, spec_file_name );
char *extension = strrchr( spec_file_name, '.' );
int result;
spec->src_name = xstrdup( input_file_name );
if (extension && !strcmp( extension, ".def" ))
result = parse_def_file( input_file, spec );
else
result = parse_spec_file( input_file, spec );
close_input_file( input_file );
return result;
}
/*******************************************************************
* main
*/
int maiAn(int argc, char **argv)
{
DLLSPEC *spec = alloc_dll_spec();
#ifdef SIGHUP
signal( SIGHUP, exit_on_signal );
#endif
signal( SIGTERM, exit_on_signal );
signal( SIGINT, exit_on_signal );
output_file = stdout;
argv = parse_options( argc, argv, spec );
switch(exec_mode)
{
case MODE_DLL:
if (spec->subsystem != IMAGE_SUBSYSTEM_NATIVE)
spec->characteristics |= IMAGE_FILE_DLL;
/* fall through */
case MODE_EXE:
load_resources( argv, spec );
load_import_libs( argv );
if (spec_file_name && !parse_input_file( spec )) break;
if (fake_module)
{
if (spec->type == SPEC_WIN16) output_fake_module16( spec );
else output_fake_module( spec );
break;
}
read_undef_symbols( spec, argv );
switch (spec->type)
{
case SPEC_WIN16:
output_spec16_file( spec );
break;
case SPEC_WIN32:
BuildSpec32File( spec );
break;
default: assert(0);
}
break;
case MODE_DEF:
if (argv[0]) fatal_error( "file argument '%s' not allowed in this mode\n", argv[0] );
if (!spec_file_name) fatal_error( "missing .spec file\n" );
if (!parse_input_file( spec )) break;
output_def_file( spec, 1 );
break;
case MODE_IMPLIB:
if (!spec_file_name) fatal_error( "missing .spec file\n" );
if (!parse_input_file( spec )) break;
output_import_lib( spec, argv );
break;
case MODE_RESOURCES:
load_resources( argv, spec );
output_res_o_file( spec );
break;
default:
usage(1);
break;
}
if (nb_errors) exit(1);
if (output_file_name)
{
if (fclose( output_file ) < 0) fatal_perror( "fclose" );
if (output_file_source_name) assemble_file( output_file_source_name, output_file_name );
output_file_name = NULL;
}
return 0;
}
================================================
FILE: convspec/parser.c
================================================
/*
* Spec file parser
*
* Copyright 1993 Robert J. Amstadt
* Copyright 1995 Martin von Loewis
* Copyright 1995, 1996, 1997, 2004 Alexandre Julliard
* Copyright 1997 Eric Youngdale
* Copyright 1999 Ulrich Weigand
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#include "wine/port.h"
#include
#include
#include
#include
#include
#include
#include "build.h"
int current_line = 0;
static char ParseBuffer[512];
static char TokenBuffer[512];
static char *ParseNext = ParseBuffer;
static FILE *input_file;
static const char *separator_chars;
static const char *comment_chars;
/* valid characters in ordinal names */
static const char valid_ordname_chars[] = "/$:-_@?<>abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
static const char * const TypeNames[TYPE_NBTYPES] =
{
"variable", /* TYPE_VARIABLE */
"pascal", /* TYPE_PASCAL */
"equate", /* TYPE_ABS */
"stub", /* TYPE_STUB */
"stdcall", /* TYPE_STDCALL */
"cdecl", /* TYPE_CDECL */
"varargs", /* TYPE_VARARGS */
"thiscall", /* TYPE_THISCALL */
"extern" /* TYPE_EXTERN */
};
static const char * const FlagNames[] =
{
"norelay", /* FLAG_NORELAY */
"noname", /* FLAG_NONAME */
"ret16", /* FLAG_RET16 */
"ret64", /* FLAG_RET64 */
"register", /* FLAG_REGISTER */
"private", /* FLAG_PRIVATE */
"ordinal", /* FLAG_ORDINAL */
"stkprolog", /* FLAG_STKPROLOG */
NULL
};
static const char * const ArgNames[ARG_MAXARG + 1] =
{
"word", /* ARG_WORD */
"s_word", /* ARG_SWORD */
"segptr", /* ARG_SEGPTR */
"segstr", /* ARG_SEGSTR */
"long", /* ARG_LONG */
"ptr", /* ARG_PTR */
"str", /* ARG_STR */
"wstr", /* ARG_WSTR */
"int64", /* ARG_INT64 */
"int128", /* ARG_INT128 */
"float", /* ARG_FLOAT */
"double" /* ARG_DOUBLE */
};
static int IsNumberString(const char *s)
{
while (*s) if (!isdigit(*s++)) return 0;
return 1;
}
static inline int is_token_separator( char ch )
{
return strchr( separator_chars, ch ) != NULL;
}
static inline int is_token_comment( char ch )
{
return strchr( comment_chars, ch ) != NULL;
}
/* get the next line from the input file, or return 0 if at eof */
static int get_next_line(void)
{
ParseNext = ParseBuffer;
current_line++;
return (fgets(ParseBuffer, sizeof(ParseBuffer), input_file) != NULL);
}
static const char * GetToken( int allow_eol )
{
char *p;
char *token = TokenBuffer;
for (;;)
{
/* remove initial white space */
p = ParseNext;
while (isspace(*p)) p++;
if (*p == '\\' && p[1] == '\n') /* line continuation */
{
if (!get_next_line())
{
if (!allow_eol) error( "Unexpected end of file\n" );
return NULL;
}
}
else break;
}
if ((*p == '\0') || is_token_comment(*p))
{
if (!allow_eol) error( "Declaration not terminated properly\n" );
return NULL;
}
/*
* Find end of token.
*/
if (is_token_separator(*p))
{
/* a separator is always a complete token */
*token++ = *p++;
}
else while (*p != '\0' && !is_token_separator(*p) && !isspace(*p))
{
if (*p == '\\') p++;
if (*p) *token++ = *p++;
}
*token = '\0';
ParseNext = p;
return TokenBuffer;
}
static ORDDEF *add_entry_point( DLLSPEC *spec )
{
ORDDEF *ret;
if (spec->nb_entry_points == spec->alloc_entry_points)
{
spec->alloc_entry_points += 128;
spec->entry_points = xrealloc( spec->entry_points,
spec->alloc_entry_points * sizeof(*spec->entry_points) );
}
ret = &spec->entry_points[spec->nb_entry_points++];
memset( ret, 0, sizeof(*ret) );
return ret;
}
/*******************************************************************
* parse_spec_variable
*
* Parse a variable definition in a .spec file.
*/
static int parse_spec_variable( ORDDEF *odp, DLLSPEC *spec )
{
char *endptr;
unsigned int *value_array;
int n_values;
int value_array_size;
const char *token;
if (spec->type == SPEC_WIN32)
{
error( "'variable' not supported in Win32, use 'extern' instead\n" );
return 0;
}
if (!(token = GetToken(0))) return 0;
if (*token != '(')
{
error( "Expected '(' got '%s'\n", token );
return 0;
}
n_values = 0;
value_array_size = 25;
value_array = xmalloc(sizeof(*value_array) * value_array_size);
for (;;)
{
if (!(token = GetToken(0)))
{
free( value_array );
return 0;
}
if (*token == ')')
break;
value_array[n_values++] = strtoul(token, &endptr, 0);
if (n_values == value_array_size)
{
value_array_size += 25;
value_array = xrealloc(value_array,
sizeof(*value_array) * value_array_size);
}
if (endptr == NULL || *endptr != '\0')
{
error( "Expected number value, got '%s'\n", token );
free( value_array );
return 0;
}
}
odp->u.var.n_values = n_values;
odp->u.var.values = xrealloc(value_array, sizeof(*value_array) * n_values);
return 1;
}
/*******************************************************************
* parse_spec_arguments
*
* Parse the arguments of an entry point.
*/
static int parse_spec_arguments( ORDDEF *odp, DLLSPEC *spec, int optional )
{
const char *token;
unsigned int i, arg;
int is_win32 = (spec->type == SPEC_WIN32) || (odp->flags & FLAG_EXPORT32);
if (!(token = GetToken( optional ))) return optional;
if (*token != '(')
{
error( "Expected '(' got '%s'\n", token );
return 0;
}
odp->u.func.nb_args = 0;
for (i = 0; i < MAX_ARGUMENTS; i++)
{
if (!(token = GetToken(0))) return 0;
if (*token == ')')
break;
for (arg = 0; arg <= ARG_MAXARG; arg++)
if (!strcmp( ArgNames[arg], token )) break;
if (arg > ARG_MAXARG)
{
error( "Unknown argument type '%s'\n", token );
return 0;
}
if (is_win32) switch (arg)
{
case ARG_WORD:
case ARG_SWORD:
case ARG_SEGPTR:
case ARG_SEGSTR:
error( "Argument type '%s' only allowed for Win16\n", token );
return 0;
}
odp->u.func.args[i] = arg;
}
if (*token != ')')
{
error( "Too many arguments\n" );
return 0;
}
odp->u.func.nb_args = i;
if (odp->type == TYPE_THISCALL && (!i || odp->u.func.args[0] != ARG_PTR))
{
error( "First argument of a thiscall function must be a pointer\n" );
return 0;
}
return 1;
}
/*******************************************************************
* parse_spec_export
*
* Parse an exported function definition in a .spec file.
*/
static int parse_spec_export( ORDDEF *odp, DLLSPEC *spec )
{
const char *token;
int is_win32 = (spec->type == SPEC_WIN32) || (odp->flags & FLAG_EXPORT32);
if (!is_win32 && odp->type == TYPE_STDCALL)
{
error( "'stdcall' not supported for Win16\n" );
return 0;
}
if (!is_win32 && odp->type == TYPE_THISCALL)
{
error( "'thiscall' not supported for Win16\n" );
return 0;
}
if (is_win32 && odp->type == TYPE_PASCAL)
{
error( "'pascal' not supported for Win32\n" );
return 0;
}
if (!parse_spec_arguments( odp, spec, 0 )) return 0;
if (odp->type == TYPE_VARARGS)
odp->flags |= FLAG_NORELAY; /* no relay debug possible for varags entry point */
if (!(token = GetToken(1)))
{
if (!strcmp( odp->name, "@" ))
{
error( "Missing handler name for anonymous function\n" );
return 0;
}
odp->link_name = xstrdup( odp->name );
}
else
{
odp->link_name = xstrdup( token );
if (strchr( odp->link_name, '.' ))
{
if (!is_win32)
{
error( "Forwarded functions not supported for Win16\n" );
return 0;
}
odp->flags |= FLAG_FORWARD;
}
}
if (target_cpu == CPU_x86 && odp->type == TYPE_THISCALL && !(odp->flags & FLAG_FORWARD))
{
char *link_name = strmake( "__thiscall_%s", odp->link_name );
free( odp->link_name );
odp->link_name = link_name;
}
return 1;
}
/*******************************************************************
* parse_spec_equate
*
* Parse an 'equate' definition in a .spec file.
*/
static int parse_spec_equate( ORDDEF *odp, DLLSPEC *spec )
{
char *endptr;
int value;
const char *token;
if (spec->type == SPEC_WIN32)
{
error( "'equate' not supported for Win32\n" );
return 0;
}
if (!(token = GetToken(0))) return 0;
value = strtol(token, &endptr, 0);
if (endptr == NULL || *endptr != '\0')
{
error( "Expected number value, got '%s'\n", token );
return 0;
}
if (value < -0x8000 || value > 0xffff)
{
error( "Value %d for absolute symbol doesn't fit in 16 bits\n", value );
value = 0;
}
odp->u.abs.value = value;
return 1;
}
/*******************************************************************
* parse_spec_stub
*
* Parse a 'stub' definition in a .spec file
*/
static int parse_spec_stub( ORDDEF *odp, DLLSPEC *spec )
{
odp->u.func.nb_args = -1;
odp->link_name = xstrdup("");
/* don't bother generating stubs for Winelib */
if (odp->flags & FLAG_CPU_MASK)
odp->flags &= FLAG_CPU(CPU_x86) | FLAG_CPU(CPU_x86_64) | FLAG_CPU(CPU_ARM) | FLAG_CPU(CPU_ARM64);
else
odp->flags |= FLAG_CPU(CPU_x86) | FLAG_CPU(CPU_x86_64) | FLAG_CPU(CPU_ARM) | FLAG_CPU(CPU_ARM64);
return parse_spec_arguments( odp, spec, 1 );
}
/*******************************************************************
* parse_spec_extern
*
* Parse an 'extern' definition in a .spec file.
*/
static int parse_spec_extern( ORDDEF *odp, DLLSPEC *spec )
{
const char *token;
if (spec->type == SPEC_WIN16)
{
error( "'extern' not supported for Win16, use 'variable' instead\n" );
return 0;
}
if (!(token = GetToken(1)))
{
if (!strcmp( odp->name, "@" ))
{
error( "Missing handler name for anonymous extern\n" );
return 0;
}
odp->link_name = xstrdup( odp->name );
}
else
{
odp->link_name = xstrdup( token );
if (strchr( odp->link_name, '.' )) odp->flags |= FLAG_FORWARD;
}
return 1;
}
/*******************************************************************
* parse_spec_flags
*
* Parse the optional flags for an entry point in a .spec file.
*/
static const char *parse_spec_flags( DLLSPEC *spec, ORDDEF *odp )
{
unsigned int i;
const char *token;
do
{
if (!(token = GetToken(0))) break;
if (!strncmp( token, "arch=", 5))
{
char *args = xstrdup( token + 5 );
char *cpu_name = strtok( args, "," );
while (cpu_name)
{
if (!strcmp( cpu_name, "win32" ))
{
if (spec->type == SPEC_WIN32)
odp->flags |= FLAG_CPU_WIN32;
else
odp->flags |= FLAG_EXPORT32;
}
else if (!strcmp( cpu_name, "win64" ))
odp->flags |= FLAG_CPU_WIN64;
else
{
int cpu = get_cpu_from_name( cpu_name );
if (cpu == -1)
{
error( "Unknown architecture '%s'\n", cpu_name );
return NULL;
}
odp->flags |= FLAG_CPU( cpu );
}
cpu_name = strtok( NULL, "," );
}
free( args );
}
else if (!strcmp( token, "i386" )) /* backwards compatibility */
{
odp->flags |= FLAG_CPU(CPU_x86);
}
else
{
for (i = 0; FlagNames[i]; i++)
if (!strcmp( FlagNames[i], token )) break;
if (!FlagNames[i])
{
error( "Unknown flag '%s'\n", token );
return NULL;
}
switch (1 << i)
{
case FLAG_RET16:
case FLAG_REGISTER:
case FLAG_STKPROLOG:
if (spec->type == SPEC_WIN32)
error( "Flag '%s' is not supported in Win32\n", FlagNames[i] );
break;
case FLAG_RET64:
if (spec->type == SPEC_WIN16)
error( "Flag '%s' is not supported in Win16\n", FlagNames[i] );
break;
}
odp->flags |= 1 << i;
}
token = GetToken(0);
} while (token && *token == '-');
return token;
}
/*******************************************************************
* parse_spec_ordinal
*
* Parse an ordinal definition in a .spec file.
*/
static int parse_spec_ordinal( int ordinal, DLLSPEC *spec )
{
const char *token;
size_t len;
ORDDEF *odp = add_entry_point( spec );
if (!(token = GetToken(0))) goto error;
for (odp->type = 0; odp->type < TYPE_NBTYPES; odp->type++)
if (TypeNames[odp->type] && !strcmp( token, TypeNames[odp->type] ))
break;
if (odp->type >= TYPE_NBTYPES)
{
error( "Expected type after ordinal, found '%s' instead\n", token );
goto error;
}
if (!(token = GetToken(0))) goto error;
if (*token == '-' && !(token = parse_spec_flags( spec, odp ))) goto error;
if (ordinal == -1 && spec->type != SPEC_WIN32 && !(odp->flags & FLAG_EXPORT32))
{
error( "'@' ordinals not supported for Win16\n" );
goto error;
}
odp->name = xstrdup( token );
odp->lineno = current_line;
odp->ordinal = ordinal;
len = strspn( odp->name, valid_ordname_chars );
if (len < strlen( odp->name ))
{
error( "Character '%c' is not allowed in exported name '%s'\n", odp->name[len], odp->name );
goto error;
}
switch(odp->type)
{
case TYPE_VARIABLE:
if (!parse_spec_variable( odp, spec )) goto error;
break;
case TYPE_PASCAL:
case TYPE_STDCALL:
case TYPE_VARARGS:
case TYPE_CDECL:
case TYPE_THISCALL:
if (!parse_spec_export( odp, spec )) goto error;
break;
case TYPE_ABS:
if (!parse_spec_equate( odp, spec )) goto error;
break;
case TYPE_STUB:
if (!parse_spec_stub( odp, spec )) goto error;
break;
case TYPE_EXTERN:
if (!parse_spec_extern( odp, spec )) goto error;
break;
default:
assert( 0 );
}
if ((odp->flags & FLAG_CPU_MASK) && !(odp->flags & FLAG_CPU(target_cpu)))
{
/* ignore this entry point */
spec->nb_entry_points--;
return 1;
}
if (ordinal != -1)
{
if (!ordinal)
{
error( "Ordinal 0 is not valid\n" );
goto error;
}
if (ordinal >= MAX_ORDINALS)
{
error( "Ordinal number %d too large\n", ordinal );
goto error;
}
if (ordinal > spec->limit) spec->limit = ordinal;
if (ordinal < spec->base) spec->base = ordinal;
odp->ordinal = ordinal;
}
if (odp->type == TYPE_STDCALL && !(odp->flags & FLAG_PRIVATE))
{
if (!strcmp( odp->name, "DllRegisterServer" ) ||
!strcmp( odp->name, "DllUnregisterServer" ) ||
!strcmp( odp->name, "DllMain" ) ||
!strcmp( odp->name, "DllGetClassObject" ) ||
!strcmp( odp->name, "DllGetVersion" ) ||
!strcmp( odp->name, "DllInstall" ) ||
!strcmp( odp->name, "DllCanUnloadNow" ))
{
warning( "Function %s should be marked private\n", odp->name );
if (strcmp( odp->name, odp->link_name ))
warning( "Function %s should not use a different internal name (%s)\n",
odp->name, odp->link_name );
}
}
if (!strcmp( odp->name, "@" ) || odp->flags & (FLAG_NONAME | FLAG_ORDINAL))
{
if (ordinal == -1)
{
if (!strcmp( odp->name, "@" ))
error( "Nameless function needs an explicit ordinal number\n" );
else
error( "Function imported by ordinal needs an explicit ordinal number\n" );
goto error;
}
if (spec->type != SPEC_WIN32)
{
error( "Nameless functions not supported for Win16\n" );
goto error;
}
if (!strcmp( odp->name, "@" ))
{
free( odp->name );
odp->name = NULL;
}
else if (!(odp->flags & FLAG_ORDINAL)) /* -ordinal only affects the import library */
{
odp->export_name = odp->name;
odp->name = NULL;
}
}
return 1;
error:
spec->nb_entry_points--;
free( odp->name );
return 0;
}
static int name_compare( const void *ptr1, const void *ptr2 )
{
const ORDDEF *odp1 = *(const ORDDEF * const *)ptr1;
const ORDDEF *odp2 = *(const ORDDEF * const *)ptr2;
const char *name1 = odp1->name ? odp1->name : odp1->export_name;
const char *name2 = odp2->name ? odp2->name : odp2->export_name;
return strcmp( name1, name2 );
}
/*******************************************************************
* assign_names
*
* Build the name array and catch duplicates.
*/
static void assign_names( DLLSPEC *spec )
{
int i, j, nb_exp_names = 0;
ORDDEF **all_names;
spec->nb_names = 0;
for (i = 0; i < spec->nb_entry_points; i++)
if (spec->entry_points[i].name) spec->nb_names++;
else if (spec->entry_points[i].export_name) nb_exp_names++;
if (!spec->nb_names && !nb_exp_names) return;
/* check for duplicates */
all_names = xmalloc( (spec->nb_names + nb_exp_names) * sizeof(all_names[0]) );
for (i = j = 0; i < spec->nb_entry_points; i++)
if (spec->entry_points[i].name || spec->entry_points[i].export_name)
all_names[j++] = &spec->entry_points[i];
qsort( all_names, j, sizeof(all_names[0]), name_compare );
for (i = 0; i < j - 1; i++)
{
const char *name1 = all_names[i]->name ? all_names[i]->name : all_names[i]->export_name;
const char *name2 = all_names[i+1]->name ? all_names[i+1]->name : all_names[i+1]->export_name;
if (!strcmp( name1, name2 ) &&
!((all_names[i]->flags ^ all_names[i+1]->flags) & FLAG_EXPORT32))
{
current_line = max( all_names[i]->lineno, all_names[i+1]->lineno );
error( "'%s' redefined\n%s:%d: First defined here\n",
name1, input_file_name,
min( all_names[i]->lineno, all_names[i+1]->lineno ) );
}
}
free( all_names );
if (spec->nb_names)
{
spec->names = xmalloc( spec->nb_names * sizeof(spec->names[0]) );
for (i = j = 0; i < spec->nb_entry_points; i++)
if (spec->entry_points[i].name) spec->names[j++] = &spec->entry_points[i];
/* sort the list of names */
qsort( spec->names, spec->nb_names, sizeof(spec->names[0]), name_compare );
}
}
/*******************************************************************
* assign_ordinals
*
* Build the ordinal array.
*/
static void assign_ordinals( DLLSPEC *spec )
{
int i, count, ordinal;
/* start assigning from base, or from 1 if no ordinal defined yet */
spec->base = MAX_ORDINALS;
spec->limit = 0;
for (i = 0; i < spec->nb_entry_points; i++)
{
ordinal = spec->entry_points[i].ordinal;
if (ordinal == -1) continue;
if (ordinal > spec->limit) spec->limit = ordinal;
if (ordinal < spec->base) spec->base = ordinal;
}
if (spec->base == MAX_ORDINALS) spec->base = 1;
if (spec->limit < spec->base) spec->limit = spec->base;
count = max( spec->limit + 1, spec->base + spec->nb_entry_points );
spec->ordinals = xmalloc( count * sizeof(spec->ordinals[0]) );
memset( spec->ordinals, 0, count * sizeof(spec->ordinals[0]) );
/* fill in all explicitly specified ordinals */
for (i = 0; i < spec->nb_entry_points; i++)
{
ordinal = spec->entry_points[i].ordinal;
if (ordinal == -1) continue;
if (spec->ordinals[ordinal])
{
current_line = max( spec->entry_points[i].lineno, spec->ordinals[ordinal]->lineno );
error( "ordinal %d redefined\n%s:%d: First defined here\n",
ordinal, input_file_name,
min( spec->entry_points[i].lineno, spec->ordinals[ordinal]->lineno ) );
}
else spec->ordinals[ordinal] = &spec->entry_points[i];
}
/* now assign ordinals to the rest */
for (i = 0, ordinal = spec->base; i < spec->nb_entry_points; i++)
{
if (spec->entry_points[i].ordinal != -1) continue;
while (spec->ordinals[ordinal]) ordinal++;
if (ordinal >= MAX_ORDINALS)
{
current_line = spec->entry_points[i].lineno;
fatal_error( "Too many functions defined (max %d)\n", MAX_ORDINALS );
}
spec->entry_points[i].ordinal = ordinal;
spec->ordinals[ordinal] = &spec->entry_points[i];
}
if (ordinal > spec->limit) spec->limit = ordinal;
}
/*******************************************************************
* add_16bit_exports
*
* Add the necessary exports to the 32-bit counterpart of a 16-bit module.
*/
void add_16bit_exports( DLLSPEC *spec32, DLLSPEC *spec16 )
{
int i;
ORDDEF *odp;
spec32->file_name = xstrdup( spec16->file_name );
if (spec16->characteristics & IMAGE_FILE_DLL)
{
spec32->characteristics = IMAGE_FILE_DLL;
spec32->init_func = xstrdup( "__wine_spec_dll_entry" );
}
/* add an export for the NE module */
odp = add_entry_point( spec32 );
odp->type = TYPE_EXTERN;
odp->flags = FLAG_PRIVATE;
odp->name = xstrdup( "__wine_spec_dos_header" );
odp->lineno = 0;
odp->ordinal = 1;
odp->link_name = xstrdup( ".L__wine_spec_dos_header" );
if (spec16->main_module)
{
odp = add_entry_point( spec32 );
odp->type = TYPE_EXTERN;
odp->flags = FLAG_PRIVATE;
odp->name = xstrdup( "__wine_spec_main_module" );
odp->lineno = 0;
odp->ordinal = 2;
odp->link_name = xstrdup( ".L__wine_spec_main_module" );
}
/* add the explicit win32 exports */
for (i = 1; i <= spec16->limit; i++)
{
ORDDEF *odp16 = spec16->ordinals[i];
if (!odp16 || !odp16->name) continue;
if (!(odp16->flags & FLAG_EXPORT32)) continue;
odp = add_entry_point( spec32 );
odp->flags = odp16->flags & ~FLAG_EXPORT32;
odp->type = odp16->type;
odp->name = xstrdup( odp16->name );
odp->lineno = odp16->lineno;
odp->ordinal = -1;
odp->link_name = xstrdup( odp16->link_name );
odp->u.func.nb_args = odp16->u.func.nb_args;
if (odp->u.func.nb_args > 0) memcpy( odp->u.func.args, odp16->u.func.args,
odp->u.func.nb_args * sizeof(odp->u.func.args[0]) );
}
assign_names( spec32 );
assign_ordinals( spec32 );
}
/*******************************************************************
* parse_spec_file
*
* Parse a .spec file.
*/
int parse_spec_file( FILE *file, DLLSPEC *spec )
{
const char *token;
input_file = file;
current_line = 0;
comment_chars = "#;";
separator_chars = "()-";
while (get_next_line())
{
if (!(token = GetToken(1))) continue;
if (strcmp(token, "@") == 0)
{
if (!parse_spec_ordinal( -1, spec )) continue;
}
else if (IsNumberString(token))
{
if (!parse_spec_ordinal( atoi(token), spec )) continue;
}
else
{
error( "Expected ordinal declaration, got '%s'\n", token );
continue;
}
if ((token = GetToken(1))) error( "Syntax error near '%s'\n", token );
}
current_line = 0; /* no longer parsing the input file */
assign_names( spec );
assign_ordinals( spec );
return !nb_errors;
}
/*******************************************************************
* parse_def_library
*
* Parse a LIBRARY declaration in a .def file.
*/
static int parse_def_library( DLLSPEC *spec )
{
const char *token = GetToken(1);
if (!token) return 1;
if (strcmp( token, "BASE" ))
{
free( spec->file_name );
spec->file_name = xstrdup( token );
if (!(token = GetToken(1))) return 1;
}
if (strcmp( token, "BASE" ))
{
error( "Expected library name or BASE= declaration, got '%s'\n", token );
return 0;
}
if (!(token = GetToken(0))) return 0;
if (strcmp( token, "=" ))
{
error( "Expected '=' after BASE, got '%s'\n", token );
return 0;
}
if (!(token = GetToken(0))) return 0;
/* FIXME: do something with base address */
return 1;
}
/*******************************************************************
* parse_def_stack_heap_size
*
* Parse a STACKSIZE or HEAPSIZE declaration in a .def file.
*/
static int parse_def_stack_heap_size( int is_stack, DLLSPEC *spec )
{
const char *token = GetToken(0);
char *end;
unsigned long size;
if (!token) return 0;
size = strtoul( token, &end, 0 );
if (*end)
{
error( "Invalid number '%s'\n", token );
return 0;
}
if (is_stack) spec->stack_size = size / 1024;
else spec->heap_size = size / 1024;
if (!(token = GetToken(1))) return 1;
if (strcmp( token, "," ))
{
error( "Expected ',' after size, got '%s'\n", token );
return 0;
}
if (!(token = GetToken(0))) return 0;
/* FIXME: do something with reserve size */
return 1;
}
/*******************************************************************
* parse_def_export
*
* Parse an export declaration in a .def file.
*/
static int parse_def_export( char *name, DLLSPEC *spec )
{
int i, args;
const char *token = GetToken(1);
ORDDEF *odp = add_entry_point( spec );
odp->lineno = current_line;
odp->ordinal = -1;
odp->name = name;
args = remove_stdcall_decoration( odp->name );
if (args == -1)
{
odp->type = TYPE_CDECL;
args = 0;
}
else
{
odp->type = TYPE_STDCALL;
args /= get_ptr_size();
if (args >= MAX_ARGUMENTS)
{
error( "Too many arguments in stdcall function '%s'\n", odp->name );
return 0;
}
for (i = 0; i < args; i++) odp->u.func.args[i] = ARG_LONG;
}
odp->u.func.nb_args = args;
/* check for optional internal name */
if (token && !strcmp( token, "=" ))
{
if (!(token = GetToken(0))) goto error;
odp->link_name = xstrdup( token );
remove_stdcall_decoration( odp->link_name );
token = GetToken(1);
}
else
{
odp->link_name = xstrdup( name );
}
/* check for optional ordinal */
if (token && token[0] == '@')
{
int ordinal;
if (!IsNumberString( token+1 ))
{
error( "Expected number after '@', got '%s'\n", token+1 );
goto error;
}
ordinal = atoi( token+1 );
if (!ordinal)
{
error( "Ordinal 0 is not valid\n" );
goto error;
}
if (ordinal >= MAX_ORDINALS)
{
error( "Ordinal number %d too large\n", ordinal );
goto error;
}
odp->ordinal = ordinal;
token = GetToken(1);
}
/* check for other optional keywords */
while (token)
{
if (!strcmp( token, "NONAME" ))
{
if (odp->ordinal == -1)
{
error( "NONAME requires an ordinal\n" );
goto error;
}
odp->export_name = odp->name;
odp->name = NULL;
odp->flags |= FLAG_NONAME;
}
else if (!strcmp( token, "PRIVATE" ))
{
odp->flags |= FLAG_PRIVATE;
}
else if (!strcmp( token, "DATA" ))
{
odp->type = TYPE_EXTERN;
}
else
{
error( "Garbage text '%s' found at end of export declaration\n", token );
goto error;
}
token = GetToken(1);
}
return 1;
error:
spec->nb_entry_points--;
free( odp->name );
return 0;
}
/*******************************************************************
* parse_def_file
*
* Parse a .def file.
*/
int parse_def_file( FILE *file, DLLSPEC *spec )
{
const char *token;
int in_exports = 0;
input_file = file;
current_line = 0;
comment_chars = ";";
separator_chars = ",=";
while (get_next_line())
{
if (!(token = GetToken(1))) continue;
if (!strcmp( token, "LIBRARY" ) || !strcmp( token, "NAME" ))
{
if (!parse_def_library( spec )) continue;
goto end_of_line;
}
else if (!strcmp( token, "STACKSIZE" ))
{
if (!parse_def_stack_heap_size( 1, spec )) continue;
goto end_of_line;
}
else if (!strcmp( token, "HEAPSIZE" ))
{
if (!parse_def_stack_heap_size( 0, spec )) continue;
goto end_of_line;
}
else if (!strcmp( token, "EXPORTS" ))
{
in_exports = 1;
if (!(token = GetToken(1))) continue;
}
else if (!strcmp( token, "IMPORTS" ))
{
in_exports = 0;
if (!(token = GetToken(1))) continue;
}
else if (!strcmp( token, "SECTIONS" ))
{
in_exports = 0;
if (!(token = GetToken(1))) continue;
}
if (!in_exports) continue; /* ignore this line */
if (!parse_def_export( xstrdup(token), spec )) continue;
end_of_line:
if ((token = GetToken(1))) error( "Syntax error near '%s'\n", token );
}
current_line = 0; /* no longer parsing the input file */
assign_names( spec );
assign_ordinals( spec );
return !nb_errors;
}
================================================
FILE: convspec/relay.c
================================================
/*
* Relay calls helper routines
*
* Copyright 1993 Robert J. Amstadt
* Copyright 1995 Martin von Loewis
* Copyright 1995, 1996, 1997 Alexandre Julliard
* Copyright 1997 Eric Youngdale
* Copyright 1999 Ulrich Weigand
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#include "wine/port.h"
#include
#include
#include "build.h"
/* offset of the stack pointer relative to %fs:(0) */
#define STACKOFFSET (0xe10 + 0x20 * 0x4) /* FIELD_OFFSET(TEB,TlsSlots) + WOW32RESERVED_TLS_INDEX * 4*/ /* 0xc0 */ /* FIELD_OFFSET(TEB,WOW32Reserved) */
/* fix this if the x86_thread_data structure is changed */
#define GS_OFFSET 0x1d8 /* FIELD_OFFSET(TEB,SystemReserved2) + FIELD_OFFSET(struct x86_thread_data,gs) */
static void function_header( const char *name )
{
output( "\n\t.align %d\n", get_alignment(4) );
output( "\t%s\n", func_declaration(strmake("_%s", name)) );
output( "%s\n", asm_globl(name) );
}
/*******************************************************************
* BuildCallFrom16Core
*
* This routine builds the core routines used in 16->32 thunks:
* CallFrom16Word, CallFrom16Long, CallFrom16Register, and CallFrom16Thunk.
*
* These routines are intended to be called via a far call (with 32-bit
* operand size) from 16-bit code. The 16-bit code stub must push %bp,
* the 32-bit entry point to be called, and the argument conversion
* routine to be used (see stack layout below).
*
* The core routine completes the STACK16FRAME on the 16-bit stack and
* switches to the 32-bit stack. Then, the argument conversion routine
* is called; it gets passed the 32-bit entry point and a pointer to the
* 16-bit arguments (on the 16-bit stack) as parameters. (You can either
* use conversion routines automatically generated by BuildCallFrom16,
* or write your own for special purposes.)
*
* The conversion routine must call the 32-bit entry point, passing it
* the converted arguments, and return its return value to the core.
* After the conversion routine has returned, the core switches back
* to the 16-bit stack, converts the return value to the DX:AX format
* (CallFrom16Long), and returns to the 16-bit call stub. All parameters,
* including %bp, are popped off the stack.
*
* The 16-bit call stub now returns to the caller, popping the 16-bit
* arguments if necessary (pascal calling convention).
*
* In the case of a 'register' function, CallFrom16Register fills a
* CONTEXT86 structure with the values all registers had at the point
* the first instruction of the 16-bit call stub was about to be
* executed. A pointer to this CONTEXT86 is passed as third parameter
* to the argument conversion routine, which typically passes it on
* to the called 32-bit entry point.
*
* CallFrom16Thunk is a special variant used by the implementation of
* the Win95 16->32 thunk functions C16ThkSL and C16ThkSL01 and is
* implemented as follows:
* On entry, the EBX register is set up to contain a flat pointer to the
* 16-bit stack such that EBX+22 points to the first argument.
* Then, the entry point is called, while EBP is set up to point
* to the return address (on the 32-bit stack).
* The called function returns with CX set to the number of bytes
* to be popped of the caller's stack.
*
* Stack layout upon entry to the core routine (STACK16FRAME):
* ... ...
* (sp+24) word first 16-bit arg
* (sp+22) word cs
* (sp+20) word ip
* (sp+18) word bp
* (sp+14) long 32-bit entry point (reused for Win16 mutex recursion count)
* (sp+12) word ip of actual entry point (necessary for relay debugging)
* (sp+8) long relay (argument conversion) function entry point
* (sp+4) long cs of 16-bit entry point
* (sp) long ip of 16-bit entry point
*
* Added on the stack:
* (sp-2) word saved gs
* (sp-4) word saved fs
* (sp-6) word saved es
* (sp-8) word saved ds
* (sp-12) long saved ebp
* (sp-16) long saved ecx
* (sp-20) long saved edx
* (sp-24) long saved previous stack
*/
static void BuildCallFrom16Core( int reg_func, int thunk )
{
/* Function header */
if (thunk) function_header( "__wine_call_from_16_thunk" );
else if (reg_func) function_header( "__wine_call_from_16_regs" );
else function_header( "__wine_call_from_16" );
/* Create STACK16FRAME (except STACK32FRAME link) */
output( "\tpushw %%gs\n" );
output( "\tpushw %%fs\n" );
output( "\tpushw %%es\n" );
output( "\tpushw %%ds\n" );
output( "\tpushl %%ebp\n" );
output( "\tpushl %%ecx\n" );
output( "\tpushl %%edx\n" );
/* Save original EFlags register */
if (reg_func) output( "\tpushfl\n" );
if ( UsePIC )
{
output( "\tcall 1f\n" );
output( "1:\tpopl %%ecx\n" );
output( "\t.byte 0x2e\n\tmovl %s-1b(%%ecx),%%edx\n", asm_name("CallTo16_DataSelector") );
}
else
output( "\t.byte 0x2e\n\tmovl %s,%%edx\n", asm_name("CallTo16_DataSelector") );
/* Load 32-bit segment registers */
output( "\tmovw %%dx, %%ds\n" );
output( "\tmovw %%dx, %%es\n" );
if ( UsePIC )
output( "\tmovw %s-1b(%%ecx), %%fs\n", asm_name("CallTo16_TebSelector") );
else
output( "\tmovw %s, %%fs\n", asm_name("CallTo16_TebSelector") );
output( "\t.byte 0x64\n\tmov (%d),%%gs\n", GS_OFFSET );
/* Translate STACK16FRAME base to flat offset in %edx */
output( "\tmovw %%ss, %%dx\n" );
output( "\tandl $0xfff8, %%edx\n" );
output( "\tshrl $1, %%edx\n" );
if (UsePIC)
{
output( "\taddl wine_ldt_copy_ptr-1b(%%ecx),%%edx\n" );
output( "\tmovl (%%edx), %%edx\n" );
}
else
{
output( "\tmovl %s, %%ecx\n", asm_name("_imp__wine_ldt_copy") );
output( "\tmovl 0(%%ecx,%%edx), %%edx\n" );
}
output( "\tmovzwl %%sp, %%ebp\n" );
output( "\tleal %d(%%ebp,%%edx), %%edx\n", reg_func ? 0 : -4 );
/* Get saved flags into %ecx */
if (reg_func) output( "\tpopl %%ecx\n" );
/* Get the 32-bit stack pointer from the TEB and complete STACK16FRAME */
output( "\t.byte 0x64\n\tmovl (%d), %%ebp\n", STACKOFFSET );
output( "\tpushl %%ebp\n" );
/* Switch stacks */
output( "\t.byte 0x64\n\tmovw %%ss, (%d)\n", STACKOFFSET + 2 );
output( "\t.byte 0x64\n\tmovw %%sp, (%d)\n", STACKOFFSET );
output( "\tpushl %%ds\n" );
output( "\tpopl %%ss\n" );
output( "\tmovl %%ebp, %%esp\n" );
output( "\taddl $0x20,%%ebp\n"); /* FIELD_OFFSET(STACK32FRAME,ebp) */
/* At this point:
STACK16FRAME is completely set up
DS, ES, SS: flat data segment
FS: current TEB
ESP: points to last STACK32FRAME
EBP: points to ebp member of last STACK32FRAME
EDX: points to current STACK16FRAME
ECX: contains saved flags
all other registers: unchanged */
/* Special case: C16ThkSL stub */
if ( thunk )
{
/* Set up registers as expected and call thunk */
output( "\tleal 0x1a(%%edx),%%ebx\n" ); /* sizeof(STACK16FRAME)-22 */
output( "\tleal -4(%%esp), %%ebp\n" );
output( "\tcall *0x26(%%edx)\n"); /* FIELD_OFFSET(STACK16FRAME,entry_point) */
/* Switch stack back */
output( "\t.byte 0x64\n\tmovw (%d), %%ss\n", STACKOFFSET+2 );
output( "\t.byte 0x64\n\tmovzwl (%d), %%esp\n", STACKOFFSET );
output( "\t.byte 0x64\n\tpopl (%d)\n", STACKOFFSET );
/* Restore registers and return directly to caller */
output( "\taddl $8, %%esp\n" );
output( "\tpopl %%ebp\n" );
output( "\tpopw %%ds\n" );
output( "\tpopw %%es\n" );
output( "\tpopw %%fs\n" );
output( "\tpopw %%gs\n" );
output( "\taddl $20, %%esp\n" );
output( "\txorb %%ch, %%ch\n" );
output( "\tpopl %%ebx\n" );
output( "\taddw %%cx, %%sp\n" );
output( "\tpush %%ebx\n" );
output( "\t.byte 0x66\n" );
output( "\tlret\n" );
output_function_size( "__wine_call_from_16_thunk" );
return;
}
/* Build register CONTEXT */
if ( reg_func )
{
output( "\tsubl $0x2cc,%%esp\n" ); /* sizeof(CONTEXT86) */
output( "\tmovl %%ecx,0xc0(%%esp)\n" ); /* EFlags */
output( "\tmovl %%eax,0xb0(%%esp)\n" ); /* Eax */
output( "\tmovl %%ebx,0xa4(%%esp)\n" ); /* Ebx */
output( "\tmovl %%esi,0xa0(%%esp)\n" ); /* Esi */
output( "\tmovl %%edi,0x9c(%%esp)\n" ); /* Edi */
output( "\tmovl 0x0c(%%edx),%%eax\n"); /* FIELD_OFFSET(STACK16FRAME,ebp) */
output( "\tmovl %%eax,0xb4(%%esp)\n" ); /* Ebp */
output( "\tmovl 0x08(%%edx),%%eax\n"); /* FIELD_OFFSET(STACK16FRAME,ecx) */
output( "\tmovl %%eax,0xac(%%esp)\n" ); /* Ecx */
output( "\tmovl 0x04(%%edx),%%eax\n"); /* FIELD_OFFSET(STACK16FRAME,edx) */
output( "\tmovl %%eax,0xa8(%%esp)\n" ); /* Edx */
output( "\tmovzwl 0x10(%%edx),%%eax\n"); /* FIELD_OFFSET(STACK16FRAME,ds) */
output( "\tmovl %%eax,0x98(%%esp)\n" ); /* SegDs */
output( "\tmovzwl 0x12(%%edx),%%eax\n"); /* FIELD_OFFSET(STACK16FRAME,es) */
output( "\tmovl %%eax,0x94(%%esp)\n" ); /* SegEs */
output( "\tmovzwl 0x14(%%edx),%%eax\n"); /* FIELD_OFFSET(STACK16FRAME,fs) */
output( "\tmovl %%eax,0x90(%%esp)\n" ); /* SegFs */
output( "\tmovzwl 0x16(%%edx),%%eax\n"); /* FIELD_OFFSET(STACK16FRAME,gs) */
output( "\tmovl %%eax,0x8c(%%esp)\n" ); /* SegGs */
output( "\tmovzwl 0x2e(%%edx),%%eax\n"); /* FIELD_OFFSET(STACK16FRAME,cs) */
output( "\tmovl %%eax,0xbc(%%esp)\n" ); /* SegCs */
output( "\tmovzwl 0x2c(%%edx),%%eax\n"); /* FIELD_OFFSET(STACK16FRAME,ip) */
output( "\tmovl %%eax,0xb8(%%esp)\n" ); /* Eip */
output( "\t.byte 0x64\n\tmovzwl (%d), %%eax\n", STACKOFFSET+2 );
output( "\tmovl %%eax,0xc8(%%esp)\n" ); /* SegSs */
output( "\t.byte 0x64\n\tmovzwl (%d), %%eax\n", STACKOFFSET );
output( "\taddl $0x2c,%%eax\n"); /* FIELD_OFFSET(STACK16FRAME,ip) */
output( "\tmovl %%eax,0xc4(%%esp)\n" ); /* Esp */
#if 0
output( "\tfsave 0x1c(%%esp)\n" ); /* FloatSave */
#endif
/* Push address of CONTEXT86 structure -- popped by the relay routine */
output( "\tmovl %%esp,%%eax\n" );
output( "\tandl $~15,%%esp\n" );
output( "\tsubl $4,%%esp\n" );
output( "\tpushl %%eax\n" );
}
else
{
output( "\tsubl $8,%%esp\n" );
output( "\tandl $~15,%%esp\n" );
output( "\taddl $8,%%esp\n" );
}
/* Call relay routine (which will call the API entry point) */
output( "\tleal 0x30(%%edx),%%eax\n" ); /* sizeof(STACK16FRAME) */
output( "\tpushl %%eax\n" );
output( "\tpushl 0x26(%%edx)\n"); /* FIELD_OFFSET(STACK16FRAME,entry_point) */
output( "\tcall *0x20(%%edx)\n"); /* FIELD_OFFSET(STACK16FRAME,relay) */
if ( reg_func )
{
output( "\tleal -748(%%ebp),%%ebx\n" ); /* sizeof(CONTEXT) + FIELD_OFFSET(STACK32FRAME,ebp) */
/* Switch stack back */
output( "\t.byte 0x64\n\tmovw (%d), %%ss\n", STACKOFFSET+2 );
output( "\t.byte 0x64\n\tmovzwl (%d), %%esp\n", STACKOFFSET );
output( "\t.byte 0x64\n\tpopl (%d)\n", STACKOFFSET );
/* Get return address to CallFrom16 stub */
output( "\taddw $0x14,%%sp\n" ); /* FIELD_OFFSET(STACK16FRAME,callfrom_ip)-4 */
output( "\tpopl %%eax\n" );
output( "\tpopl %%edx\n" );
/* Restore all registers from CONTEXT */
output( "\tmovw 0xc8(%%ebx),%%ss\n"); /* SegSs */
output( "\tmovl 0xc4(%%ebx),%%esp\n"); /* Esp */
output( "\taddl $4, %%esp\n" ); /* room for final return address */
output( "\tpushw 0xbc(%%ebx)\n"); /* SegCs */
output( "\tpushw 0xb8(%%ebx)\n"); /* Eip */
output( "\tpushl %%edx\n" );
output( "\tpushl %%eax\n" );
output( "\tpushl 0xc0(%%ebx)\n"); /* EFlags */
output( "\tpushl 0x98(%%ebx)\n"); /* SegDs */
output( "\tpushl 0x94(%%ebx)\n"); /* SegEs */
output( "\tpopl %%es\n" );
output( "\tpushl 0x90(%%ebx)\n"); /* SegFs */
output( "\tpopl %%fs\n" );
output( "\tpushl 0x8c(%%ebx)\n"); /* SegGs */
output( "\tpopl %%gs\n" );
output( "\tmovl 0xb4(%%ebx),%%ebp\n"); /* Ebp */
output( "\tmovl 0xa0(%%ebx),%%esi\n"); /* Esi */
output( "\tmovl 0x9c(%%ebx),%%edi\n"); /* Edi */
output( "\tmovl 0xb0(%%ebx),%%eax\n"); /* Eax */
output( "\tmovl 0xa8(%%ebx),%%edx\n"); /* Edx */
output( "\tmovl 0xac(%%ebx),%%ecx\n"); /* Ecx */
output( "\tmovl 0xa4(%%ebx),%%ebx\n"); /* Ebx */
output( "\tpopl %%ds\n" );
output( "\tpopfl\n" );
output( "\tlret\n" );
output_function_size( "__wine_call_from_16_regs" );
}
else
{
/* Switch stack back */
output( "\t.byte 0x64\n\tmovw (%d), %%ss\n", STACKOFFSET+2 );
output( "\t.byte 0x64\n\tmovzwl (%d), %%esp\n", STACKOFFSET );
output( "\t.byte 0x64\n\tpopl (%d)\n", STACKOFFSET );
/* Restore registers */
output( "\tpopl %%edx\n" );
output( "\tpopl %%ecx\n" );
output( "\tpopl %%ebp\n" );
output( "\tpopw %%ds\n" );
output( "\tpopw %%es\n" );
output( "\tpopw %%fs\n" );
output( "\tpopw %%gs\n" );
/* Return to return stub which will return to caller */
output( "\tlret $12\n" );
output_function_size( "__wine_call_from_16" );
}
}
/*******************************************************************
* BuildCallTo16Core
*
* This routine builds the core routines used in 32->16 thunks:
*
* extern DWORD WINAPI wine_call_to_16( FARPROC16 target, DWORD cbArgs, PEXCEPTION_HANDLER handler );
* extern void WINAPI wine_call_to_16_regs( CONTEXT86 *context, DWORD cbArgs, PEXCEPTION_HANDLER handler );
*
* These routines can be called directly from 32-bit code.
*
* All routines expect that the 16-bit stack contents (arguments) and the
* return address (segptr to CallTo16_Ret) were already set up by the
* caller; nb_args must contain the number of bytes to be conserved. The
* 16-bit SS:SP will be set accordingly.
*
* All other registers are either taken from the CONTEXT86 structure
* or else set to default values. The target routine address is either
* given directly or taken from the CONTEXT86.
*/
static void BuildCallTo16Core( int reg_func )
{
const char *name = reg_func ? "__wine_call_to_16_regs" : "__wine_call_to_16";
/* Function header */
function_header( name );
/* Function entry sequence */
output_cfi( ".cfi_startproc" );
output( "\tpushl %%ebp\n" );
output_cfi( ".cfi_adjust_cfa_offset 4" );
output_cfi( ".cfi_rel_offset %%ebp,0" );
output( "\tmovl %%esp, %%ebp\n" );
output_cfi( ".cfi_def_cfa_register %%ebp" );
/* Save the 32-bit registers */
output( "\tpushl %%ebx\n" );
output_cfi( ".cfi_rel_offset %%ebx,-4" );
output( "\tpushl %%esi\n" );
output_cfi( ".cfi_rel_offset %%esi,-8" );
output( "\tpushl %%edi\n" );
output_cfi( ".cfi_rel_offset %%edi,-12" );
output( "\t.byte 0x64\n\tmov %%gs,(%d)\n", GS_OFFSET );
/* Setup exception frame */
output( "\t.byte 0x64\n\tpushl (%d)\n", STACKOFFSET );
output( "\tpushl 16(%%ebp)\n" ); /* handler */
output( "\t.byte 0x64\n\tpushl (0)\n" );
output( "\t.byte 0x64\n\tmovl %%esp,(0)\n" );
/* Call the actual CallTo16 routine (simulate a lcall) */
output( "\tpushl %%cs\n" );
output( "\tcall .L%s\n", name );
/* Remove exception frame */
output( "\t.byte 0x64\n\tpopl (0)\n" );
output( "\taddl $4, %%esp\n" );
output( "\t.byte 0x64\n\tpopl (%d)\n", STACKOFFSET );
if ( !reg_func )
{
/* Convert return value */
output( "\tandl $0xffff,%%eax\n" );
output( "\tshll $16,%%edx\n" );
output( "\torl %%edx,%%eax\n" );
}
else
{
/*
* Modify CONTEXT86 structure to contain new values
*
* NOTE: We restore only EAX, EBX, EDX, EDX, EBP, and ESP.
* The segment registers as well as ESI and EDI should
* not be modified by a well-behaved 16-bit routine in
* any case. [If necessary, we could restore them as well,
* at the cost of a somewhat less efficient return path.]
*/
output( "\tmovl 0x14(%%esp),%%edi\n" ); /* FIELD_OFFSET(STACK32FRAME,target) - FIELD_OFFSET(STACK32FRAME,edi) */
/* everything above edi has been popped already */
output( "\tmovl %%eax,0xb0(%%edi)\n"); /* Eax */
output( "\tmovl %%ebx,0xa4(%%edi)\n"); /* Ebx */
output( "\tmovl %%ecx,0xac(%%edi)\n"); /* Ecx */
output( "\tmovl %%edx,0xa8(%%edi)\n"); /* Edx */
output( "\tmovl %%ebp,0xb4(%%edi)\n"); /* Ebp */
output( "\tmovl %%esi,0xc4(%%edi)\n"); /* Esp */
/* The return glue code saved %esp into %esi */
}
/* Restore the 32-bit registers */
output( "\tpopl %%edi\n" );
output_cfi( ".cfi_same_value %%edi" );
output( "\tpopl %%esi\n" );
output_cfi( ".cfi_same_value %%esi" );
output( "\tpopl %%ebx\n" );
output_cfi( ".cfi_same_value %%ebx" );
/* Function exit sequence */
output( "\tpopl %%ebp\n" );
output_cfi( ".cfi_def_cfa %%esp,4" );
output_cfi( ".cfi_same_value %%ebp" );
output( "\tret $12\n" );
output_cfi( ".cfi_endproc" );
/* Start of the actual CallTo16 routine */
output( ".L%s:\n", name );
/* Switch to the 16-bit stack */
output( "\tmovl %%esp,%%edx\n" );
output( "\t.byte 0x64\n\tmovw (%d),%%ss\n", STACKOFFSET + 2);
output( "\t.byte 0x64\n\tmovw (%d),%%sp\n", STACKOFFSET );
output( "\t.byte 0x64\n\tmovl %%edx,(%d)\n", STACKOFFSET );
/* Make %bp point to the previous stackframe (built by CallFrom16) */
output( "\tmovzwl %%sp,%%ebp\n" );
output( "\tleal 0x2a(%%ebp),%%ebp\n"); /* FIELD_OFFSET(STACK16FRAME,bp) */
/* Add the specified offset to the new sp */
output( "\tsubw 0x2c(%%edx), %%sp\n"); /* FIELD_OFFSET(STACK32FRAME,nb_args) */
if (reg_func)
{
/* Push the called routine address */
output( "\tmovl 0x28(%%edx),%%edx\n"); /* FIELD_OFFSET(STACK32FRAME,target) */
output( "\tpushw 0xbc(%%edx)\n"); /* SegCs */
output( "\tpushw 0xb8(%%edx)\n"); /* Eip */
/* Get the registers */
output( "\tpushw 0x98(%%edx)\n"); /* SegDs */
output( "\tpushl 0x94(%%edx)\n"); /* SegEs */
output( "\tpopl %%es\n" );
output( "\tpushl 0x90(%%edx)\n"); /* SegFs */
output( "\tpopl %%fs\n" );
output( "\tpushl 0x8c(%%edx)\n"); /* SegGs */
output( "\tpopl %%gs\n" );
output( "\tmovl 0xb4(%%edx),%%ebp\n"); /* Ebp */
output( "\tmovl 0xa0(%%edx),%%esi\n"); /* Esi */
output( "\tmovl 0x9c(%%edx),%%edi\n"); /* Edi */
output( "\tmovl 0xb0(%%edx),%%eax\n"); /* Eax */
output( "\tmovl 0xa4(%%edx),%%ebx\n"); /* Ebx */
output( "\tmovl 0xac(%%edx),%%ecx\n"); /* Ecx */
output( "\tmovl 0xa8(%%edx),%%edx\n"); /* Edx */
/* Get the 16-bit ds */
output( "\tpopw %%ds\n" );
}
else /* not a register function */
{
/* Push the called routine address */
output( "\tpushl 0x28(%%edx)\n"); /* FIELD_OFFSET(STACK32FRAME,target) */
/* Set %fs and %gs to the value saved by the last CallFrom16 */
output( "\tpushw -22(%%ebp)\n" ); /* FIELD_OFFSET(STACK16FRAME,fs)-FIELD_OFFSET(STACK16FRAME,bp) */
output( "\tpopw %%fs\n" );
output( "\tpushw -20(%%ebp)\n" ); /* FIELD_OFFSET(STACK16FRAME,gs)-FIELD_OFFSET(STACK16FRAME,bp) */
output( "\tpopw %%gs\n" );
/* Set %ds and %es (and %ax just in case) equal to %ss */
output( "\tmovw %%ss,%%ax\n" );
output( "\tmovw %%ax,%%ds\n" );
output( "\tmovw %%ax,%%es\n" );
}
/* Jump to the called routine */
output( "\t.byte 0x66\n" );
output( "\tlret\n" );
/* Function footer */
output_function_size( name );
}
/*******************************************************************
* BuildRet16Func
*
* Build the return code for 16-bit callbacks
*/
static void BuildRet16Func(void)
{
function_header( "__wine_call_to_16_ret" );
/* Save %esp into %esi */
output( "\tmovl %%esp,%%esi\n" );
/* Restore 32-bit segment registers */
output( "\t.byte 0x2e\n\tmovl %s", asm_name("CallTo16_DataSelector") );
output( "-%s,%%edi\n", asm_name("__wine_call16_start") );
output( "\tmovw %%di,%%ds\n" );
output( "\tmovw %%di,%%es\n" );
output( "\t.byte 0x2e\n\tmov %s", asm_name("CallTo16_TebSelector") );
output( "-%s,%%fs\n", asm_name("__wine_call16_start") );
output( "\t.byte 0x64\n\tmov (%d),%%gs\n", GS_OFFSET );
/* Restore the 32-bit stack */
output( "\tmovw %%di,%%ss\n" );
output( "\t.byte 0x64\n\tmovl (%d),%%esp\n", STACKOFFSET );
/* Return to caller */
output( "\tlret\n" );
output_function_size( "__wine_call_to_16_ret" );
}
/*******************************************************************
* BuildCallTo32CBClient
*
* Call a CBClient relay stub from 32-bit code (KERNEL.620).
*
* Since the relay stub is itself 32-bit, this should not be a problem;
* unfortunately, the relay stubs are expected to switch back to a
* 16-bit stack (and 16-bit code) after completion :-(
*
* This would conflict with our 16- vs. 32-bit stack handling, so
* we simply switch *back* to our 32-bit stack before returning to
* the caller ...
*
* The CBClient relay stub expects to be called with the following
* 16-bit stack layout, and with ebp and ebx pointing into the 16-bit
* stack at the designated places:
*
* ...
* (ebp+14) original arguments to the callback routine
* (ebp+10) far return address to original caller
* (ebp+6) Thunklet target address
* (ebp+2) Thunklet relay ID code
* (ebp) BP (saved by CBClientGlueSL)
* (ebp-2) SI (saved by CBClientGlueSL)
* (ebp-4) DI (saved by CBClientGlueSL)
* (ebp-6) DS (saved by CBClientGlueSL)
*
* ... buffer space used by the 16-bit side glue for temp copies
*
* (ebx+4) far return address to 16-bit side glue code
* (ebx) saved 16-bit ss:sp (pointing to ebx+4)
*
* The 32-bit side glue code accesses both the original arguments (via ebp)
* and the temporary copies prepared by the 16-bit side glue (via ebx).
* After completion, the stub will load ss:sp from the buffer at ebx
* and perform a far return to 16-bit code.
*
* To trick the relay stub into returning to us, we replace the 16-bit
* return address to the glue code by a cs:ip pair pointing to our
* return entry point (the original return address is saved first).
* Our return stub thus called will then reload the 32-bit ss:esp and
* return to 32-bit code (by using and ss:esp value that we have also
* pushed onto the 16-bit stack before and a cs:eip values found at
* that position on the 32-bit stack). The ss:esp to be restored is
* found relative to the 16-bit stack pointer at:
*
* (ebx-4) ss (flat)
* (ebx-8) sp (32-bit stack pointer)
*
* The second variant of this routine, CALL32_CBClientEx, which is used
* to implement KERNEL.621, has to cope with yet another problem: Here,
* the 32-bit side directly returns to the caller of the CBClient thunklet,
* restoring registers saved by CBClientGlueSL and cleaning up the stack.
* As we have to return to our 32-bit code first, we have to adapt the
* layout of our temporary area so as to include values for the registers
* that are to be restored, and later (in the implementation of KERNEL.621)
* we *really* restore them. The return stub restores DS, DI, SI, and BP
* from the stack, skips the next 8 bytes (CBClient relay code / target),
* and then performs a lret NN, where NN is the number of arguments to be
* removed. Thus, we prepare our temporary area as follows:
*
* (ebx+22) 16-bit cs (this segment)
* (ebx+20) 16-bit ip ('16-bit' return entry point)
* (ebx+16) 32-bit ss (flat)
* (ebx+12) 32-bit sp (32-bit stack pointer)
* (ebx+10) 16-bit bp (points to ebx+24)
* (ebx+8) 16-bit si (ignored)
* (ebx+6) 16-bit di (ignored)
* (ebx+4) 16-bit ds (we actually use the flat DS here)
* (ebx+2) 16-bit ss (16-bit stack segment)
* (ebx+0) 16-bit sp (points to ebx+4)
*
* Note that we ensure that DS is not changed and remains the flat segment,
* and the 32-bit stack pointer our own return stub needs fits just
* perfectly into the 8 bytes that are skipped by the Windows stub.
* One problem is that we have to determine the number of removed arguments,
* as these have to be really removed in KERNEL.621. Thus, the BP value
* that we place in the temporary area to be restored, contains the value
* that SP would have if no arguments were removed. By comparing the actual
* value of SP with this value in our return stub we can compute the number
* of removed arguments. This is then returned to KERNEL.621.
*
* The stack layout of this function:
* (ebp+20) nArgs pointer to variable receiving nr. of args (Ex only)
* (ebp+16) esi pointer to caller's esi value
* (ebp+12) arg ebp value to be set for relay stub
* (ebp+8) func CBClient relay stub address
* (ebp+4) ret addr
* (ebp) ebp
*/
static void BuildCallTo32CBClient( int isEx )
{
function_header( isEx ? "CALL32_CBClientEx" : "CALL32_CBClient" );
/* Entry code */
output_cfi( ".cfi_startproc" );
output( "\tpushl %%ebp\n" );
output_cfi( ".cfi_adjust_cfa_offset 4" );
output_cfi( ".cfi_rel_offset %%ebp,0" );
output( "\tmovl %%esp,%%ebp\n" );
output_cfi( ".cfi_def_cfa_register %%ebp" );
output( "\tpushl %%edi\n" );
output_cfi( ".cfi_rel_offset %%edi,-4" );
output( "\tpushl %%esi\n" );
output_cfi( ".cfi_rel_offset %%esi,-8" );
output( "\tpushl %%ebx\n" );
output_cfi( ".cfi_rel_offset %%ebx,-12" );
/* Get pointer to temporary area and save the 32-bit stack pointer */
output( "\tmovl 16(%%ebp), %%ebx\n" );
output( "\tleal -8(%%esp), %%eax\n" );
if ( !isEx )
output( "\tmovl %%eax, -8(%%ebx)\n" );
else
output( "\tmovl %%eax, 12(%%ebx)\n" );
/* Set up registers and call CBClient relay stub (simulating a far call) */
output( "\tmovl 20(%%ebp), %%esi\n" );
output( "\tmovl (%%esi), %%esi\n" );
output( "\tmovl 8(%%ebp), %%eax\n" );
output( "\tmovl 12(%%ebp), %%ebp\n" );
output( "\tpushl %%cs\n" );
output( "\tcall *%%eax\n" );
/* Return new esi value to caller */
output( "\tmovl 32(%%esp), %%edi\n" );
output( "\tmovl %%esi, (%%edi)\n" );
/* Return argument size to caller */
if ( isEx )
{
output( "\tmovl 36(%%esp), %%ebx\n" );
output( "\tmovl %%ebp, (%%ebx)\n" );
}
/* Restore registers and return */
output( "\tpopl %%ebx\n" );
output_cfi( ".cfi_same_value %%ebx" );
output( "\tpopl %%esi\n" );
output_cfi( ".cfi_same_value %%esi" );
output( "\tpopl %%edi\n" );
output_cfi( ".cfi_same_value %%edi" );
output( "\tpopl %%ebp\n" );
output_cfi( ".cfi_def_cfa %%esp,4" );
output_cfi( ".cfi_same_value %%ebp" );
output( "\tret\n" );
output_cfi( ".cfi_endproc" );
output_function_size( isEx ? "CALL32_CBClientEx" : "CALL32_CBClient" );
/* '16-bit' return stub */
function_header( isEx ? "CALL32_CBClientEx_Ret" : "CALL32_CBClient_Ret" );
if ( !isEx )
{
output( "\tmovzwl %%sp, %%ebx\n" );
output( "\tlssl %%ss:-16(%%ebx), %%esp\n" );
}
else
{
output( "\tmovzwl %%bp, %%ebx\n" );
output( "\tsubw %%bp, %%sp\n" );
output( "\tmovzwl %%sp, %%ebp\n" );
output( "\tlssl %%ss:-12(%%ebx), %%esp\n" );
}
output( "\tlret\n" );
output_function_size( isEx ? "CALL32_CBClientEx_Ret" : "CALL32_CBClient_Ret" );
}
/*******************************************************************
* output_asm_relays16
*
* Build all the 16-bit relay callbacks
*/
void output_asm_relays16(void)
{
/* File header */
output( "\t.text\n" );
output( "%s:\n\n", asm_name("__wine_spec_thunk_text_16") );
output( "%s\n", asm_globl("__wine_call16_start") );
/* Standard CallFrom16 routine */
BuildCallFrom16Core( 0, 0 );
/* Register CallFrom16 routine */
BuildCallFrom16Core( 1, 0 );
/* C16ThkSL CallFrom16 routine */
BuildCallFrom16Core( 0, 1 );
/* Standard CallTo16 routine */
BuildCallTo16Core( 0 );
/* Register CallTo16 routine */
BuildCallTo16Core( 1 );
/* Standard CallTo16 return stub */
BuildRet16Func();
/* CBClientThunkSL routine */
BuildCallTo32CBClient( 0 );
/* CBClientThunkSLEx routine */
BuildCallTo32CBClient( 1 );
output( "%s\n", asm_globl("__wine_call16_end") );
output_function_size( "__wine_spec_thunk_text_16" );
/* Declare the return address and data selector variables */
output( "\n\t.data\n\t.align %d\n", get_alignment(4) );
output( "%s\n\t.long 0\n", asm_globl("CallTo16_DataSelector") );
output( "%s\n\t.long 0\n", asm_globl("CallTo16_TebSelector") );
output("%s\n\t.long %s\n", asm_globl("__wine_call16_start_p"), asm_name("__wine_call16_start") );
output("%s\n\t.long %s\n", asm_globl("__wine_call16_end_p"), asm_name("__wine_call16_end") );
output("%s\n\t.long %s\n", asm_globl("__wine_call_to_16_ret_p"), asm_name("__wine_call_to_16_ret") );
}
================================================
FILE: convspec/res16.c
================================================
/*
* Builtin dlls resource support
*
* Copyright 2000 Alexandre Julliard
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#include "wine/port.h"
#include
#include
#include
#include
#include
#include
#ifdef HAVE_SYS_TYPES_H
# include
#endif
#include
#include "build.h"
/* Unicode string or integer id */
struct string_id
{
char *str; /* ptr to string */
unsigned short id; /* integer id if str is NULL */
};
/* descriptor for a resource */
struct resource
{
struct string_id type;
struct string_id name;
const void *data;
unsigned int name_offset;
unsigned int data_size;
unsigned int memopt;
};
/* type level of the resource tree */
struct res_type
{
const struct string_id *type; /* type name */
struct resource *res; /* first resource of this type */
unsigned int name_offset; /* name offset if string */
unsigned int nb_names; /* total number of names */
};
/* top level of the resource tree */
struct res_tree
{
struct res_type *types; /* types array */
unsigned int nb_types; /* total number of types */
};
static inline struct resource *add_resource( DLLSPEC *spec )
{
spec->resources = xrealloc( spec->resources, (spec->nb_resources + 1) * sizeof(*spec->resources) );
return &spec->resources[spec->nb_resources++];
}
static struct res_type *add_type( struct res_tree *tree, struct resource *res )
{
struct res_type *type;
tree->types = xrealloc( tree->types, (tree->nb_types + 1) * sizeof(*tree->types) );
type = &tree->types[tree->nb_types++];
type->type = &res->type;
type->res = res;
type->nb_names = 0;
return type;
}
/* get a string from the current resource file */
static void get_string( struct string_id *str )
{
unsigned char c = get_byte();
if (c == 0xff)
{
str->str = NULL;
str->id = get_word();
}
else
{
str->str = (char *)input_buffer + input_buffer_pos - 1;
str->id = 0;
while (get_byte()) /* nothing */;
}
}
/* load the next resource from the current file */
static void load_next_resource( DLLSPEC *spec )
{
struct resource *res = add_resource( spec );
get_string( &res->type );
get_string( &res->name );
res->memopt = get_word();
res->data_size = get_dword();
res->data = input_buffer + input_buffer_pos;
input_buffer_pos += res->data_size;
if (input_buffer_pos > input_buffer_size)
fatal_error( "%s is a truncated/corrupted file\n", input_buffer_filename );
}
/* load a Win16 .res file */
void load_res16_file( const char *name, DLLSPEC *spec )
{
init_input_buffer( name );
while (input_buffer_pos < input_buffer_size) load_next_resource( spec );
}
void load_res16_from_buf( const unsigned char *buf, int size, DLLSPEC *spec )
{
input_buffer = buf;
input_buffer_size = size;
input_buffer_pos = 0;
while (input_buffer_pos < input_buffer_size) load_next_resource( spec );
}
/* compare two strings/ids */
static int cmp_string( const struct string_id *str1, const struct string_id *str2 )
{
if (!str1->str)
{
if (!str2->str) return str1->id - str2->id;
return 1; /* an id compares larger than a string */
}
if (!str2->str) return -1;
return strcasecmp( str1->str, str2->str );
}
/* compare two resources for sorting the resource directory */
/* resources are stored first by type, then by name */
static int cmp_res( const void *ptr1, const void *ptr2 )
{
const struct resource *res1 = ptr1;
const struct resource *res2 = ptr2;
int ret;
if ((ret = cmp_string( &res1->type, &res2->type ))) return ret;
return cmp_string( &res1->name, &res2->name );
}
/* build the 2-level (type,name) resource tree */
static struct res_tree *build_resource_tree( DLLSPEC *spec )
{
unsigned int i, j, offset;
struct res_tree *tree;
struct res_type *type = NULL;
struct resource *res;
qsort( spec->resources, spec->nb_resources, sizeof(*spec->resources), cmp_res );
offset = 2; /* alignment */
tree = xmalloc( sizeof(*tree) );
tree->types = NULL;
tree->nb_types = 0;
for (i = 0; i < spec->nb_resources; i++)
{
if (!i || cmp_string( &spec->resources[i].type, &spec->resources[i-1].type )) /* new type */
{
type = add_type( tree, &spec->resources[i] );
offset += 8;
}
type->nb_names++;
offset += 12;
}
offset += 2; /* terminator */
for (i = 0, type = tree->types; i < tree->nb_types; i++, type++)
{
if (type->type->str)
{
type->name_offset = offset;
offset += strlen(type->type->str) + 1;
}
else type->name_offset = type->type->id | 0x8000;
for (j = 0, res = type->res; j < type->nb_names; j++, res++)
{
if (res->name.str)
{
res->name_offset = offset;
offset += strlen(res->name.str) + 1;
}
else res->name_offset = res->name.id | 0x8000;
}
}
return tree;
}
/* free the resource tree */
static void free_resource_tree( struct res_tree *tree )
{
free( tree->types );
free( tree );
}
/* output a string preceded by its length */
static void output_string( const char *str )
{
unsigned int i, len = strlen(str);
output( "\t.byte 0x%02x", len );
for (i = 0; i < len; i++) output( ",0x%02x", (unsigned char)str[i] );
output( " /* %s */\n", str );
}
/* output a string preceded by its length in binary format*/
static void output_bin_string( const char *str )
{
put_byte( strlen(str) );
while (*str) put_byte( *str++ );
}
/* output the resource data */
void output_res16_data( DLLSPEC *spec )
{
const struct resource *res;
unsigned int i;
for (i = 0, res = spec->resources; i < spec->nb_resources; i++, res++)
{
output( ".L__wine_spec_resource_%u:\n", i );
dump_bytes( res->data, res->data_size );
}
}
/* output the resource definitions */
void output_res16_directory( DLLSPEC *spec )
{
unsigned int i, j;
struct res_tree *tree;
const struct res_type *type;
const struct resource *res;
tree = build_resource_tree( spec );
output( "\n.L__wine_spec_ne_rsrctab:\n" );
output( "\t.short 0\n" ); /* alignment */
/* type and name structures */
for (i = 0, type = tree->types; i < tree->nb_types; i++, type++)
{
output( "\t.short 0x%04x,%u,0,0\n", type->name_offset, type->nb_names );
for (j = 0, res = type->res; j < type->nb_names; j++, res++)
{
output( "\t.short .L__wine_spec_resource_%lu-.L__wine_spec_dos_header,%u\n",
(unsigned long)(res - spec->resources), res->data_size );
output( "\t.short 0x%04x,0x%04x,0,0\n", res->memopt, res->name_offset );
}
}
output( "\t.short 0\n" ); /* terminator */
/* name strings */
for (i = 0, type = tree->types; i < tree->nb_types; i++, type++)
{
if (type->type->str) output_string( type->type->str );
for (j = 0, res = type->res; j < type->nb_names; j++, res++)
if (res->name.str) output_string( res->name.str );
}
output( "\t.byte 0\n" ); /* names terminator */
free_resource_tree( tree );
}
/* output the resource data in binary format */
void output_bin_res16_data( DLLSPEC *spec )
{
const struct resource *res;
unsigned int i;
for (i = 0, res = spec->resources; i < spec->nb_resources; i++, res++)
put_data( res->data, res->data_size );
}
/* output the resource definitions in binary format */
void output_bin_res16_directory( DLLSPEC *spec, unsigned int data_offset )
{
unsigned int i, j;
struct res_tree *tree;
const struct res_type *type;
const struct resource *res;
tree = build_resource_tree( spec );
put_word( 0 ); /* alignment */
/* type and name structures */
for (i = 0, type = tree->types; i < tree->nb_types; i++, type++)
{
put_word( type->name_offset );
put_word( type->nb_names );
put_word( 0 );
put_word( 0 );
for (j = 0, res = type->res; j < type->nb_names; j++, res++)
{
put_word( data_offset );
put_word( res->data_size );
put_word( res->memopt );
put_word( res->name_offset );
put_word( 0 );
put_word( 0 );
data_offset += res->data_size;
}
}
put_word( 0 ); /* terminator */
/* name strings */
for (i = 0, type = tree->types; i < tree->nb_types; i++, type++)
{
if (type->type->str) output_bin_string( type->type->str );
for (j = 0, res = type->res; j < type->nb_names; j++, res++)
if (res->name.str) output_bin_string( res->name.str );
}
put_byte( 0 ); /* names terminator */
free_resource_tree( tree );
}
================================================
FILE: convspec/res32.c
================================================
/*
* Builtin dlls resource support
*
* Copyright 2000 Alexandre Julliard
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#include "wine/port.h"
#include
#include
#include
#include
#include
#include
#ifdef HAVE_SYS_TYPES_H
# include
#endif
#include
#include "build.h"
typedef unsigned short WCHAR;
/* Unicode string or integer id */
struct string_id
{
WCHAR *str; /* ptr to Unicode string */
unsigned short id; /* integer id if str is NULL */
};
/* descriptor for a resource */
struct resource
{
struct string_id type;
struct string_id name;
const void *data;
unsigned int data_size;
unsigned int data_offset;
unsigned short mem_options;
unsigned short lang;
unsigned int version;
};
/* name level of the resource tree */
struct res_name
{
const struct string_id *name; /* name */
struct resource *res; /* resource */
int nb_languages; /* number of languages */
unsigned int dir_offset; /* offset of directory in resource dir */
unsigned int name_offset; /* offset of name in resource dir */
};
/* type level of the resource tree */
struct res_type
{
const struct string_id *type; /* type name */
struct res_name *names; /* names array */
unsigned int nb_names; /* total number of names */
unsigned int nb_id_names; /* number of names that have a numeric id */
unsigned int dir_offset; /* offset of directory in resource dir */
unsigned int name_offset; /* offset of type name in resource dir */
};
/* top level of the resource tree */
struct res_tree
{
struct res_type *types; /* types array */
unsigned int nb_types; /* total number of types */
};
/* size of a resource directory with n entries */
#define RESOURCE_DIR_SIZE (4 * sizeof(unsigned int))
#define RESOURCE_DIR_ENTRY_SIZE (2 * sizeof(unsigned int))
#define RESOURCE_DATA_ENTRY_SIZE (4 * sizeof(unsigned int))
#define RESDIR_SIZE(n) (RESOURCE_DIR_SIZE + (n) * RESOURCE_DIR_ENTRY_SIZE)
static inline struct resource *add_resource( DLLSPEC *spec )
{
spec->resources = xrealloc( spec->resources, (spec->nb_resources + 1) * sizeof(spec->resources[0]) );
return &spec->resources[spec->nb_resources++];
}
static inline unsigned int strlenW( const WCHAR *str )
{
const WCHAR *s = str;
while (*s) s++;
return s - str;
}
static inline int strcmpW( const WCHAR *str1, const WCHAR *str2 )
{
while (*str1 && (*str1 == *str2)) { str1++; str2++; }
return *str1 - *str2;
}
static struct res_name *add_name( struct res_type *type, struct resource *res )
{
struct res_name *name;
type->names = xrealloc( type->names, (type->nb_names + 1) * sizeof(*type->names) );
name = &type->names[type->nb_names++];
name->name = &res->name;
name->res = res;
name->nb_languages = 1;
if (!name->name->str) type->nb_id_names++;
return name;
}
static struct res_type *add_type( struct res_tree *tree, struct resource *res )
{
struct res_type *type;
tree->types = xrealloc( tree->types, (tree->nb_types + 1) * sizeof(*tree->types) );
type = &tree->types[tree->nb_types++];
type->type = &res->type;
type->names = NULL;
type->nb_names = 0;
type->nb_id_names = 0;
return type;
}
/* get a string from the current resource file */
static void get_string( struct string_id *str )
{
WCHAR wc = get_word();
if (wc == 0xffff)
{
str->str = NULL;
str->id = get_word();
}
else
{
WCHAR *p = xmalloc( (strlenW( (const WCHAR *)(input_buffer + input_buffer_pos) - 1) + 1) * sizeof(WCHAR) );
str->str = p;
str->id = 0;
if ((*p++ = wc)) while ((*p++ = get_word()));
}
}
/* put a string into the resource file */
static void put_string( const struct string_id *str )
{
if (str->str)
{
const WCHAR *p = str->str;
while (*p) put_word( *p++ );
put_word( 0 );
}
else
{
put_word( 0xffff );
put_word( str->id );
}
}
static void dump_res_data( const struct resource *res )
{
unsigned int i = 0;
unsigned int size = (res->data_size + 3) & ~3;
if (!size) return;
input_buffer = res->data;
input_buffer_pos = 0;
input_buffer_size = size;
output( "\t.long " );
while (size > 4)
{
if ((i++ % 16) == 15) output( "0x%08x\n\t.long ", get_dword() );
else output( "0x%08x,", get_dword() );
size -= 4;
}
output( "0x%08x\n", get_dword() );
assert( input_buffer_pos == input_buffer_size );
}
/* check the file header */
/* all values must be zero except header size */
static int check_header(void)
{
unsigned int size;
if (get_dword()) return 0; /* data size */
size = get_dword(); /* header size */
if (size == 0x20000000) byte_swapped = 1;
else if (size != 0x20) return 0;
if (get_word() != 0xffff || get_word()) return 0; /* type, must be id 0 */
if (get_word() != 0xffff || get_word()) return 0; /* name, must be id 0 */
if (get_dword()) return 0; /* data version */
if (get_word()) return 0; /* mem options */
if (get_word()) return 0; /* language */
if (get_dword()) return 0; /* version */
if (get_dword()) return 0; /* characteristics */
return 1;
}
/* load the next resource from the current file */
static void load_next_resource( DLLSPEC *spec )
{
unsigned int hdr_size;
struct resource *res = add_resource( spec );
res->data_size = get_dword();
hdr_size = get_dword();
if (hdr_size & 3) fatal_error( "%s header size not aligned\n", input_buffer_filename );
if (hdr_size < 32) fatal_error( "%s invalid header size %u\n", input_buffer_filename, hdr_size );
res->data = input_buffer + input_buffer_pos - 2*sizeof(unsigned int) + hdr_size;
if ((const unsigned char *)res->data < input_buffer ||
(const unsigned char *)res->data >= input_buffer + input_buffer_size)
fatal_error( "%s invalid header size %u\n", input_buffer_filename, hdr_size );
get_string( &res->type );
get_string( &res->name );
if (input_buffer_pos & 2) get_word(); /* align to dword boundary */
get_dword(); /* skip data version */
res->mem_options = get_word();
res->lang = get_word();
res->version = get_dword();
get_dword(); /* skip characteristics */
input_buffer_pos = ((const unsigned char *)res->data - input_buffer) + ((res->data_size + 3) & ~3);
input_buffer_pos = (input_buffer_pos + 3) & ~3;
if (input_buffer_pos > input_buffer_size)
fatal_error( "%s is a truncated file\n", input_buffer_filename );
}
/* load a Win32 .res file */
int load_res32_file( const char *name, DLLSPEC *spec )
{
int ret;
init_input_buffer( name );
if ((ret = check_header()))
{
while (input_buffer_pos < input_buffer_size) load_next_resource( spec );
}
return ret;
}
/* compare two unicode strings/ids */
static int cmp_string( const struct string_id *str1, const struct string_id *str2 )
{
if (!str1->str)
{
if (!str2->str) return str1->id - str2->id;
return 1; /* an id compares larger than a string */
}
if (!str2->str) return -1;
return strcmpW( str1->str, str2->str );
}
/* compare two resources for sorting the resource directory */
/* resources are stored first by type, then by name, then by language */
static int cmp_res( const void *ptr1, const void *ptr2 )
{
const struct resource *res1 = ptr1;
const struct resource *res2 = ptr2;
int ret;
if ((ret = cmp_string( &res1->type, &res2->type ))) return ret;
if ((ret = cmp_string( &res1->name, &res2->name ))) return ret;
if ((ret = res1->lang - res2->lang)) return ret;
return res1->version - res2->version;
}
static char *format_res_string( const struct string_id *str )
{
int i, len = str->str ? strlenW(str->str) + 1 : 5;
char *ret = xmalloc( len );
if (!str->str) sprintf( ret, "%04x", str->id );
else for (i = 0; i < len; i++) ret[i] = str->str[i]; /* dumb W->A conversion */
return ret;
}
/* get rid of duplicate resources with different versions */
static void remove_duplicate_resources( DLLSPEC *spec )
{
unsigned int i, n;
for (i = n = 0; i < spec->nb_resources; i++, n++)
{
if (i && !cmp_string( &spec->resources[i].type, &spec->resources[i-1].type ) &&
!cmp_string( &spec->resources[i].name, &spec->resources[i-1].name ) &&
spec->resources[i].lang == spec->resources[i-1].lang)
{
if (spec->resources[i].version == spec->resources[i-1].version)
{
char *type_str = format_res_string( &spec->resources[i].type );
char *name_str = format_res_string( &spec->resources[i].name );
error( "winebuild: duplicate resource type %s name %s language %04x version %08x\n",
type_str, name_str, spec->resources[i].lang, spec->resources[i].version );
}
else n--; /* replace the previous one */
}
if (n < i) spec->resources[n] = spec->resources[i];
}
spec->nb_resources = n;
}
/* build the 3-level (type,name,language) resource tree */
static struct res_tree *build_resource_tree( DLLSPEC *spec, unsigned int *dir_size )
{
unsigned int i, k, n, offset, data_offset;
struct res_tree *tree;
struct res_type *type = NULL;
struct res_name *name = NULL;
struct resource *res;
qsort( spec->resources, spec->nb_resources, sizeof(*spec->resources), cmp_res );
remove_duplicate_resources( spec );
tree = xmalloc( sizeof(*tree) );
tree->types = NULL;
tree->nb_types = 0;
for (i = 0; i < spec->nb_resources; i++)
{
if (!i || cmp_string( &spec->resources[i].type, &spec->resources[i-1].type )) /* new type */
{
type = add_type( tree, &spec->resources[i] );
name = add_name( type, &spec->resources[i] );
}
else if (cmp_string( &spec->resources[i].name, &spec->resources[i-1].name )) /* new name */
{
name = add_name( type, &spec->resources[i] );
}
else
{
name->nb_languages++;
}
}
/* compute the offsets */
offset = RESDIR_SIZE( tree->nb_types );
for (i = 0, type = tree->types; i < tree->nb_types; i++, type++)
{
type->dir_offset = offset;
offset += RESDIR_SIZE( type->nb_names );
for (n = 0, name = type->names; n < type->nb_names; n++, name++)
{
name->dir_offset = offset;
offset += RESDIR_SIZE( name->nb_languages );
}
}
data_offset = offset;
offset += spec->nb_resources * RESOURCE_DATA_ENTRY_SIZE;
for (i = 0, type = tree->types; i < tree->nb_types; i++, type++)
{
if (type->type->str)
{
type->name_offset = offset | 0x80000000;
offset += (strlenW(type->type->str)+1) * sizeof(WCHAR);
}
else type->name_offset = type->type->id;
for (n = 0, name = type->names; n < type->nb_names; n++, name++)
{
if (name->name->str)
{
name->name_offset = offset | 0x80000000;
offset += (strlenW(name->name->str)+1) * sizeof(WCHAR);
}
else name->name_offset = name->name->id;
for (k = 0, res = name->res; k < name->nb_languages; k++, res++)
{
unsigned int entry_offset = (res - spec->resources) * RESOURCE_DATA_ENTRY_SIZE;
res->data_offset = data_offset + entry_offset;
}
}
}
if (dir_size) *dir_size = (offset + 3) & ~3;
return tree;
}
/* free the resource tree */
static void free_resource_tree( struct res_tree *tree )
{
unsigned int i;
for (i = 0; i < tree->nb_types; i++) free( tree->types[i].names );
free( tree->types );
free( tree );
}
/* output a Unicode string */
static void output_string( const WCHAR *name )
{
int i, len = strlenW(name);
output( "\t.short 0x%04x", len );
for (i = 0; i < len; i++) output( ",0x%04x", name[i] );
output( " /* " );
for (i = 0; i < len; i++) output( "%c", isprint((char)name[i]) ? (char)name[i] : '?' );
output( " */\n" );
}
/* output a resource directory */
static inline void output_res_dir( unsigned int nb_names, unsigned int nb_ids )
{
output( "\t.long 0\n" ); /* Characteristics */
output( "\t.long 0\n" ); /* TimeDateStamp */
output( "\t.short 0,0\n" ); /* Major/MinorVersion */
output( "\t.short %u,%u\n", /* NumberOfNamed/IdEntries */
nb_names, nb_ids );
}
/* output the resource definitions */
void output_resources( DLLSPEC *spec )
{
int k, nb_id_types;
unsigned int i, n;
struct res_tree *tree;
struct res_type *type;
struct res_name *name;
const struct resource *res;
if (!spec->nb_resources) return;
tree = build_resource_tree( spec, NULL );
/* output the resource directories */
output( "\n/* resources */\n\n" );
output( "\t.data\n" );
output( "\t.align %d\n", get_alignment(get_ptr_size()) );
output( ".L__wine_spec_resources:\n" );
for (i = nb_id_types = 0, type = tree->types; i < tree->nb_types; i++, type++)
if (!type->type->str) nb_id_types++;
output_res_dir( tree->nb_types - nb_id_types, nb_id_types );
/* dump the type directory */
for (i = 0, type = tree->types; i < tree->nb_types; i++, type++)
output( "\t.long 0x%08x,0x%08x\n",
type->name_offset, type->dir_offset | 0x80000000 );
/* dump the names and languages directories */
for (i = 0, type = tree->types; i < tree->nb_types; i++, type++)
{
output_res_dir( type->nb_names - type->nb_id_names, type->nb_id_names );
for (n = 0, name = type->names; n < type->nb_names; n++, name++)
output( "\t.long 0x%08x,0x%08x\n",
name->name_offset, name->dir_offset | 0x80000000 );
for (n = 0, name = type->names; n < type->nb_names; n++, name++)
{
output_res_dir( 0, name->nb_languages );
for (k = 0, res = name->res; k < name->nb_languages; k++, res++)
output( "\t.long 0x%08x,0x%08x\n", res->lang, res->data_offset );
}
}
/* dump the resource data entries */
for (i = 0, res = spec->resources; i < spec->nb_resources; i++, res++)
output( "\t.long .L__wine_spec_res_%d-.L__wine_spec_rva_base,%u,0,0\n",
i, res->data_size );
/* dump the name strings */
for (i = 0, type = tree->types; i < tree->nb_types; i++, type++)
{
if (type->type->str) output_string( type->type->str );
for (n = 0, name = type->names; n < type->nb_names; n++, name++)
if (name->name->str) output_string( name->name->str );
}
/* resource data */
for (i = 0, res = spec->resources; i < spec->nb_resources; i++, res++)
{
output( "\n\t.align %d\n", get_alignment(get_ptr_size()) );
output( ".L__wine_spec_res_%d:\n", i );
dump_res_data( res );
}
output( ".L__wine_spec_resources_end:\n" );
output( "\t.byte 0\n" );
free_resource_tree( tree );
}
/* output a Unicode string in binary format */
static void output_bin_string( const WCHAR *name )
{
int i, len = strlenW(name);
put_word( len );
for (i = 0; i < len; i++) put_word( name[i] );
}
/* output a resource directory in binary format */
static inline void output_bin_res_dir( unsigned int nb_names, unsigned int nb_ids )
{
put_dword( 0 ); /* Characteristics */
put_dword( 0 ); /* TimeDateStamp */
put_word( 0 ); /* MajorVersion */
put_word( 0 ); /* MinorVersion */
put_word( nb_names ); /* NumberOfNamedEntries */
put_word( nb_ids ); /* NumberOfIdEntries */
}
/* output the resource definitions in binary format */
void output_bin_resources( DLLSPEC *spec, unsigned int start_rva )
{
int k, nb_id_types;
unsigned int i, n, data_offset;
struct res_tree *tree;
struct res_type *type;
struct res_name *name;
const struct resource *res;
if (!spec->nb_resources) return;
tree = build_resource_tree( spec, &data_offset );
init_output_buffer();
/* output the resource directories */
for (i = nb_id_types = 0, type = tree->types; i < tree->nb_types; i++, type++)
if (!type->type->str) nb_id_types++;
output_bin_res_dir( tree->nb_types - nb_id_types, nb_id_types );
/* dump the type directory */
for (i = 0, type = tree->types; i < tree->nb_types; i++, type++)
{
put_dword( type->name_offset );
put_dword( type->dir_offset | 0x80000000 );
}
/* dump the names and languages directories */
for (i = 0, type = tree->types; i < tree->nb_types; i++, type++)
{
output_bin_res_dir( type->nb_names - type->nb_id_names, type->nb_id_names );
for (n = 0, name = type->names; n < type->nb_names; n++, name++)
{
put_dword( name->name_offset );
put_dword( name->dir_offset | 0x80000000 );
}
for (n = 0, name = type->names; n < type->nb_names; n++, name++)
{
output_bin_res_dir( 0, name->nb_languages );
for (k = 0, res = name->res; k < name->nb_languages; k++, res++)
{
put_dword( res->lang );
put_dword( res->data_offset );
}
}
}
/* dump the resource data entries */
for (i = 0, res = spec->resources; i < spec->nb_resources; i++, res++)
{
put_dword( data_offset + start_rva );
put_dword( res->data_size );
put_dword( 0 );
put_dword( 0 );
data_offset += (res->data_size + 3) & ~3;
}
/* dump the name strings */
for (i = 0, type = tree->types; i < tree->nb_types; i++, type++)
{
if (type->type->str) output_bin_string( type->type->str );
for (n = 0, name = type->names; n < type->nb_names; n++, name++)
if (name->name->str) output_bin_string( name->name->str );
}
/* resource data */
align_output( 4 );
for (i = 0, res = spec->resources; i < spec->nb_resources; i++, res++)
{
put_data( res->data, res->data_size );
align_output( 4 );
}
free_resource_tree( tree );
}
static unsigned int get_resource_header_size( const struct resource *res )
{
unsigned int size = 5 * sizeof(unsigned int) + 2 * sizeof(unsigned short);
if (!res->type.str) size += 2 * sizeof(unsigned short);
else size += (strlenW(res->type.str) + 1) * sizeof(WCHAR);
if (!res->name.str) size += 2 * sizeof(unsigned short);
else size += (strlenW(res->name.str) + 1) * sizeof(WCHAR);
return size;
}
/* output the resources into a .o file */
void output_res_o_file( DLLSPEC *spec )
{
unsigned int i;
char *res_file = NULL;
const char *format;
int fd;
struct strarray args;
if (!spec->nb_resources) fatal_error( "--resources mode needs at least one resource file as input\n" );
if (!output_file_name) fatal_error( "No output file name specified\n" );
qsort( spec->resources, spec->nb_resources, sizeof(*spec->resources), cmp_res );
remove_duplicate_resources( spec );
byte_swapped = 0;
init_output_buffer();
put_dword( 0 ); /* ResSize */
put_dword( 32 ); /* HeaderSize */
put_word( 0xffff ); /* ResType */
put_word( 0x0000 );
put_word( 0xffff ); /* ResName */
put_word( 0x0000 );
put_dword( 0 ); /* DataVersion */
put_word( 0 ); /* Memory options */
put_word( 0 ); /* Language */
put_dword( 0 ); /* Version */
put_dword( 0 ); /* Characteristics */
for (i = 0; i < spec->nb_resources; i++)
{
unsigned int header_size = get_resource_header_size( &spec->resources[i] );
put_dword( spec->resources[i].data_size );
put_dword( (header_size + 3) & ~3 );
put_string( &spec->resources[i].type );
put_string( &spec->resources[i].name );
align_output( 4 );
put_dword( 0 );
put_word( spec->resources[i].mem_options );
put_word( spec->resources[i].lang );
put_dword( spec->resources[i].version );
put_dword( 0 );
put_data( spec->resources[i].data, spec->resources[i].data_size );
align_output( 4 );
}
/* if the output file name is a .res too, don't run the results through windres */
if (strendswith( output_file_name, ".res"))
{
flush_output_buffer();
return;
}
res_file = get_temp_file_name( output_file_name, ".res" );
if ((fd = open( res_file, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0600 )) == -1)
fatal_error( "Cannot create %s\n", res_file );
if (write( fd, output_buffer, output_buffer_pos ) != output_buffer_pos)
fatal_error( "Error writing to %s\n", res_file );
close( fd );
free( output_buffer );
args = find_tool( "windres", NULL );
switch (target_cpu)
{
case CPU_x86:
format = "pe-i386";
break;
case CPU_x86_64:
format = "pe-x86-64";
break;
default:
format = NULL;
break;
}
strarray_add( &args, "-i", res_file, "-o", output_file_name, NULL );
if (format)
strarray_add( &args, "-F", format, NULL );
spawn( args );
output_file_name = NULL; /* so we don't try to assemble it */
}
================================================
FILE: convspec/spec16.c
================================================
/*
* 16-bit spec files
*
* Copyright 1993 Robert J. Amstadt
* Copyright 1995 Martin von Loewis
* Copyright 1995, 1996, 1997 Alexandre Julliard
* Copyright 1997 Eric Youngdale
* Copyright 1999 Ulrich Weigand
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#include "wine/port.h"
#include
#include
#include "build.h"
#define NE_FFLAGS_SINGLEDATA 0x0001
#define NE_FFLAGS_LIBMODULE 0x8000
/* argument type flags for relay debugging */
enum arg_types
{
ARG16_NONE = 0, /* indicates end of arg list */
ARG16_WORD, /* unsigned word */
ARG16_SWORD, /* signed word */
ARG16_LONG, /* long or segmented pointer */
ARG16_PTR, /* linear pointer */
ARG16_STR, /* linear pointer to null-terminated string */
ARG16_SEGSTR, /* segmented pointer to null-terminated string */
ARG16_VARARG /* start of varargs */
};
/* sequences of nops to fill a certain number of words */
static const char * const nop_sequence[5] =
{
".byte 0x89,0xf6", /* mov %esi,%esi */
".byte 0x8d,0x74,0x26,0x00", /* lea 0x00(%esi),%esi */
".byte 0x8d,0xb6,0x00,0x00,0x00,0x00", /* lea 0x00000000(%esi),%esi */
".byte 0x8d,0x74,0x26,0x00,0x8d,0x74,0x26,0x00", /* lea 0x00(%esi),%esi; lea 0x00(%esi),%esi */
".byte 0x8d,0x74,0x26,0x00,0x8d,0xb6,0x00,0x00,0x00,0x00" /* lea 0x00(%esi),%esi; lea 0x00000000(%esi),%esi */
};
static inline int is_function( const ORDDEF *odp )
{
if (odp->flags & FLAG_EXPORT32) return 0;
return (odp->type == TYPE_CDECL ||
odp->type == TYPE_PASCAL ||
odp->type == TYPE_VARARGS ||
odp->type == TYPE_STUB);
}
static const char *get_args_str( const ORDDEF *odp )
{
static char buffer[MAX_ARGUMENTS*2+1];
int i;
buffer[0] = 0;
for (i = 0; i < odp->u.func.nb_args; i++)
{
switch (odp->u.func.args[i])
{
case ARG_WORD: strcat( buffer, "w" ); break;
case ARG_SWORD: strcat( buffer, "s" ); break;
case ARG_SEGSTR: strcat( buffer, "T" ); break;
case ARG_STR: strcat( buffer, "t" ); break;
case ARG_LONG:
case ARG_FLOAT:
case ARG_SEGPTR: strcat( buffer, "l" ); break;
case ARG_PTR:
case ARG_WSTR:
case ARG_INT128: strcat( buffer, "p" ); break;
case ARG_INT64:
case ARG_DOUBLE: strcat( buffer, "ll" ); break;
}
}
return buffer;
}
/*******************************************************************
* output_entries
*
* Output entries for individual symbols in the entry table.
*/
static void output_entries( DLLSPEC *spec, int first, int count )
{
int i;
for (i = 0; i < count; i++)
{
ORDDEF *odp = spec->ordinals[first + i];
output( "\t.byte 0x03\n" ); /* flags: exported & public data */
switch (odp->type)
{
case TYPE_CDECL:
case TYPE_PASCAL:
case TYPE_VARARGS:
case TYPE_STUB:
output( "\t.short .L__wine_%s_%u-.L__wine_spec_code_segment\n", spec->c_name, first + i );
break;
case TYPE_VARIABLE:
output( "\t.short .L__wine_%s_%u-.L__wine_spec_data_segment\n", spec->c_name, first + i );
break;
case TYPE_ABS:
output( "\t.short 0x%04x /* %s */\n",
odp->u.abs.value, odp->name );
break;
default:
assert(0);
}
}
}
/*******************************************************************
* output_entry_table
*/
static void output_entry_table( DLLSPEC *spec )
{
int i, prev = 0, prev_sel = -1, bundle_count = 0;
for (i = 1; i <= spec->limit; i++)
{
int selector = 0;
ORDDEF *odp = spec->ordinals[i];
if (!odp) continue;
if (odp->flags & FLAG_EXPORT32) continue;
switch (odp->type)
{
case TYPE_CDECL:
case TYPE_PASCAL:
case TYPE_VARARGS:
case TYPE_STUB:
selector = 1; /* Code selector */
break;
case TYPE_VARIABLE:
selector = 2; /* Data selector */
break;
case TYPE_ABS:
selector = 0xfe; /* Constant selector */
break;
default:
continue;
}
if (prev + 1 != i || prev_sel != selector || bundle_count == 255)
{
/* need to start a new bundle */
/* flush previous bundle */
if (bundle_count)
{
output( "\t/* %s.%d - %s.%d */\n",
spec->dll_name, prev - bundle_count + 1, spec->dll_name, prev );
output( "\t.byte 0x%02x,0x%02x\n", bundle_count, prev_sel );
output_entries( spec, prev - bundle_count + 1, bundle_count );
}
if (prev + 1 != i)
{
int skip = i - (prev + 1);
while (skip > 255)
{
output( "\t.byte 0xff,0x00\n" );
skip -= 255;
}
output( "\t.byte 0x%02x,0x00\n", skip );
}
bundle_count = 0;
prev_sel = selector;
}
bundle_count++;
prev = i;
}
/* flush last bundle */
if (bundle_count)
{
output( "\t.byte 0x%02x,0x%02x\n", bundle_count, prev_sel );
output_entries( spec, prev - bundle_count + 1, bundle_count );
}
output( "\t.byte 0x00\n" );
}
/*******************************************************************
* output_resident_name
*/
static void output_resident_name( const char *string, int ordinal )
{
unsigned int i, len = strlen(string);
output( "\t.byte 0x%02x", len );
for (i = 0; i < len; i++) output( ",0x%02x", (unsigned char)toupper(string[i]) );
output( " /* %s */\n", string );
output( "\t.short %u\n", ordinal );
}
/*******************************************************************
* get_callfrom16_name
*/
static const char *get_callfrom16_name( const ORDDEF *odp )
{
static char *buffer;
free( buffer );
buffer = strmake( "%s_%s_%s_%d",
(odp->type == TYPE_PASCAL) ? "p" :
(odp->type == TYPE_VARARGS) ? "v" : "c",
(odp->flags & FLAG_REGISTER) ? "regs" :
(odp->flags & FLAG_RET16) ? "word" : "long",
get_args_str(odp),
odp->ordinal );
return buffer;
}
/*******************************************************************
* get_relay_name
*/
static const char *get_relay_name( const ORDDEF *odp )
{
static char buffer[80];
char *p;
switch(odp->type)
{
case TYPE_PASCAL:
strcpy( buffer, "p_" );
break;
case TYPE_VARARGS:
strcpy( buffer, "v_" );
break;
case TYPE_CDECL:
case TYPE_STUB:
strcpy( buffer, "c_" );
break;
default:
assert(0);
}
strcat( buffer, get_args_str(odp) );
for (p = buffer + 2; *p; p++)
{
/* map string types to the corresponding plain pointer type */
if (*p == 't') *p = 'p';
else if (*p == 'T') *p = 'l';
}
if (odp->flags & FLAG_REGISTER) strcat( buffer, "_regs" );
snprintf(buffer + strlen(buffer), sizeof(buffer) - strlen(buffer), "_%d", odp->ordinal);
return buffer;
}
/*******************************************************************
* get_function_argsize
*/
static int get_function_argsize( const ORDDEF *odp )
{
int i, argsize = 0;
for (i = 0; i < odp->u.func.nb_args; i++)
{
switch (odp->u.func.args[i])
{
case ARG_WORD:
case ARG_SWORD:
argsize += 2;
break;
case ARG_SEGPTR:
case ARG_SEGSTR:
case ARG_LONG:
case ARG_PTR:
case ARG_STR:
case ARG_WSTR:
case ARG_FLOAT:
case ARG_INT128:
argsize += 4;
break;
case ARG_INT64:
case ARG_DOUBLE:
argsize += 8;
break;
}
}
return argsize;
}
/*******************************************************************
* output_call16_function
*
* Build a 16-bit-to-Wine callback glue function.
*
* The generated routines are intended to be used as argument conversion
* routines to be called by the CallFrom16... core. Thus, the prototypes of
* the generated routines are (see also CallFrom16):
*
* extern WORD WINAPI __wine_spec_call16_C_xxx( FARPROC func, LPBYTE args );
* extern LONG WINAPI __wine_spec_call16_C_xxx( FARPROC func, LPBYTE args );
* extern void WINAPI __wine_spec_call16_C_xxx_regs( FARPROC func, LPBYTE args, CONTEXT86 *context );
*
* where 'C' is the calling convention ('p' for pascal or 'c' for cdecl),
* and each 'x' is an argument ('w'=word, 's'=signed word, 'l'=long,
* 'p'=linear pointer, 't'=linear pointer to null-terminated string,
* 'T'=segmented pointer to null-terminated string).
*
* The generated routines fetch the arguments from the 16-bit stack (pointed
* to by 'args'); the offsets of the single argument values are computed
* according to the calling convention and the argument types. Then, the
* 32-bit entry point is called with these arguments.
*
* For register functions, the arguments (if present) are converted just
* the same as for normal functions, but in addition the CONTEXT86 pointer
* filled with the current register values is passed to the 32-bit routine.
*/
static void output_call16_function( ORDDEF *odp )
{
char *name;
int i, pos, stack_words;
int argsize = get_function_argsize( odp );
int needs_ldt = (strpbrk( get_args_str( odp ), "pt" ) != NULL);
name = strmake( ".L__wine_spec_call16_%s", get_relay_name(odp) );
output( "\t.align %d\n", get_alignment(4) );
output( "\t%s\n", func_declaration(name) );
output( "%s:\n", name );
output_cfi( ".cfi_startproc" );
output( "\tpushl %%ebp\n" );
output_cfi( ".cfi_adjust_cfa_offset 4" );
output_cfi( ".cfi_rel_offset %%ebp,0" );
output( "\tmovl %%esp,%%ebp\n" );
output_cfi( ".cfi_def_cfa_register %%ebp" );
stack_words = 2;
if (needs_ldt)
{
output( "\tpushl %%esi\n" );
output_cfi( ".cfi_rel_offset %%esi,-4" );
stack_words++;
if (UsePIC)
{
output( "\tcalll %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
output( "1:\tmovl wine_ldt_copy_ptr-1b(%%eax),%%esi\n" );
needs_get_pc_thunk = 1;
}
else
output( "\tmovl $%s,%%esi\n", asm_name("_imp__wine_ldt_copy") );
}
/* preserve 16-byte stack alignment */
stack_words += odp->u.func.nb_args;
for (i = 0; i < odp->u.func.nb_args; i++)
if (odp->u.func.args[i] == ARG_DOUBLE || odp->u.func.args[i] == ARG_INT64) stack_words++;
if ((odp->flags & FLAG_REGISTER) || (odp->type == TYPE_VARARGS)) stack_words++;
if (stack_words % 4) output( "\tsubl $%d,%%esp\n", 16 - 4 * (stack_words % 4) );
if (odp->u.func.nb_args || odp->type == TYPE_VARARGS)
output( "\tmovl 12(%%ebp),%%ecx\n" ); /* args */
if (odp->flags & FLAG_REGISTER)
{
output( "\tpushl 16(%%ebp)\n" ); /* context */
}
else if (odp->type == TYPE_VARARGS)
{
output( "\tleal %d(%%ecx),%%eax\n", argsize );
output( "\tpushl %%eax\n" ); /* va_list16 */
}
pos = (odp->type == TYPE_PASCAL) ? 0 : argsize;
for (i = odp->u.func.nb_args - 1; i >= 0; i--)
{
switch (odp->u.func.args[i])
{
case ARG_WORD:
if (odp->type != TYPE_PASCAL) pos -= 2;
output( "\tmovzwl %d(%%ecx),%%eax\n", pos );
output( "\tpushl %%eax\n" );
if (odp->type == TYPE_PASCAL) pos += 2;
break;
case ARG_SWORD:
if (odp->type != TYPE_PASCAL) pos -= 2;
output( "\tmovswl %d(%%ecx),%%eax\n", pos );
output( "\tpushl %%eax\n" );
if (odp->type == TYPE_PASCAL) pos += 2;
break;
case ARG_INT64:
case ARG_DOUBLE:
if (odp->type != TYPE_PASCAL) pos -= 4;
output( "\tpushl %d(%%ecx)\n", pos );
if (odp->type == TYPE_PASCAL) pos += 4;
/* fall through */
case ARG_LONG:
case ARG_FLOAT:
case ARG_SEGPTR:
case ARG_SEGSTR:
if (odp->type != TYPE_PASCAL) pos -= 4;
output( "\tpushl %d(%%ecx)\n", pos );
if (odp->type == TYPE_PASCAL) pos += 4;
break;
case ARG_PTR:
case ARG_STR:
case ARG_WSTR:
case ARG_INT128:
if (odp->type != TYPE_PASCAL) pos -= 4;
output( "\tmovzwl %d(%%ecx),%%edx\n", pos + 2 ); /* sel */
output( "\tshr $3,%%edx\n" );
output( "\tmovzwl %d(%%ecx),%%eax\n", pos ); /* offset */
output( "\taddl (%%esi,%%edx,4),%%eax\n" );
output( "\tpushl %%eax\n" );
if (odp->type == TYPE_PASCAL) pos += 4;
break;
}
}
output( "\tcalll *8(%%ebp)\n" );
if (needs_ldt)
{
output( "\tmovl -4(%%ebp),%%esi\n" );
output_cfi( ".cfi_same_value %%esi" );
}
output( "\tleave\n" );
output_cfi( ".cfi_def_cfa %%esp,4" );
output_cfi( ".cfi_same_value %%ebp" );
output( "\tret\n" );
output_cfi( ".cfi_endproc" );
output_function_size( name );
free( name );
}
/*******************************************************************
* callfrom16_type_compare
*
* Compare two callfrom16 sequences.
*/
static int callfrom16_type_compare( const void *e1, const void *e2 )
{
const ORDDEF *odp1 = *(const ORDDEF * const *)e1;
const ORDDEF *odp2 = *(const ORDDEF * const *)e2;
int retval;
int type1 = odp1->type;
int type2 = odp2->type;
char args1[80];
if (type1 == TYPE_STUB) type1 = TYPE_CDECL;
if (type2 == TYPE_STUB) type2 = TYPE_CDECL;
if ((retval = type1 - type2) != 0) return retval;
type1 = odp1->flags & (FLAG_RET16|FLAG_REGISTER);
type2 = odp2->flags & (FLAG_RET16|FLAG_REGISTER);
if ((retval = type1 - type2) != 0) return retval;
strcpy( args1, get_args_str( odp1 ));
return strcmp( args1, get_args_str( odp2 ));
}
/*******************************************************************
* relay_type_compare
*
* Same as callfrom16_type_compare but ignores differences that don't affect the resulting relay function.
*/
static int relay_type_compare( const void *e1, const void *e2 )
{
const ORDDEF *odp1 = *(const ORDDEF * const *)e1;
const ORDDEF *odp2 = *(const ORDDEF * const *)e2;
char name1[80];
strcpy( name1, get_relay_name(odp1) );
return strcmp( name1, get_relay_name(odp2) );
}
/*******************************************************************
* sort_func_list
*
* Sort a list of functions, removing duplicates.
*/
static int sort_func_list( ORDDEF **list, int count,
int (*compare)(const void *, const void *) )
{
int i, j;
if (!count) return 0;
qsort( list, count, sizeof(*list), compare );
for (i = j = 0; i < count; i++)
{
if (compare( &list[j], &list[i] )) list[++j] = list[i];
}
return j + 1;
}
/*******************************************************************
* output_module16
*
* Output code for a 16-bit module.
*/
static void output_module16( DLLSPEC *spec )
{
ORDDEF **typelist;
ORDDEF *entry_point = NULL;
int i, j, nb_funcs;
/* store the main entry point as ordinal 0 */
if (!spec->ordinals)
{
assert(spec->limit == 0);
spec->ordinals = xmalloc( sizeof(spec->ordinals[0]) );
spec->ordinals[0] = NULL;
}
if (spec->init_func && !(spec->characteristics & IMAGE_FILE_DLL))
{
entry_point = xmalloc( sizeof(*entry_point) );
entry_point->type = TYPE_PASCAL;
entry_point->ordinal = 0;
entry_point->lineno = 0;
entry_point->flags = FLAG_REGISTER;
entry_point->name = NULL;
entry_point->link_name = xstrdup( spec->init_func );
entry_point->export_name = NULL;
entry_point->u.func.nb_args = 0;
assert( !spec->ordinals[0] );
spec->ordinals[0] = entry_point;
}
/* Build sorted list of all argument types, without duplicates */
typelist = xmalloc( (spec->limit + 1) * sizeof(*typelist) );
for (i = nb_funcs = 0; i <= spec->limit; i++)
{
ORDDEF *odp = spec->ordinals[i];
if (!odp) continue;
if (is_function( odp )) typelist[nb_funcs++] = odp;
}
/* nb_funcs = sort_func_list( typelist, nb_funcs, callfrom16_type_compare ); */
/* Output the module structure */
output( "\n/* module data */\n\n" );
output( "\t.data\n" );
output( "\t.align %d\n", get_alignment(4) );
output( "__wine_spec_dos_header:\n" );
#ifdef WINEBUILD_MSVC
output( "\t.globl __wine_spec_dos_header\n" );
output( ".L__wine_spec_dos_header:\n" );
output( "\t.globl ___wine_spec_dos_header\n" );
output( ".L___wine_spec_dos_header:\n" );
output( "___wine_spec_dos_header:\n" );
#else
output( ".globl ___wine_spec_dos_header\n" );
output( ".L__wine_spec_dos_header:\n" );
output( "___wine_spec_dos_header:\n" );
#endif
output( "\t.short 0x5a4d\n" ); /* e_magic */
output( "\t.short 0x0040\n" ); /* e_cblp */
output( "\t.short 0x0001\n" ); /* e_cp */
output( "\t.short (.L__wine_spec_ne_header-.L__wine_spec_dos_header)/16\n" );/* e_crlc */
output( "\t.short 0\n" ); /* e_cparhdr */
output( "\t.short 0xffff\n" ); /* e_minalloc */
output( "\t.short 0\n" ); /* e_maxalloc */
output( "\t.short 0x00b8\n" ); /* e_ss */
output( "\t.short 0\n" ); /* e_sp */
output( "\t.short 0\n" ); /* e_csum */
output( "\t.short 0\n" ); /* e_ip */
output( "\t.short 0\n" ); /* e_cs */
output( "\t.short .L__wine_spec_ne_header-.L__wine_spec_dos_header\n" );/* e_lfarlc */
output( "\t.short 0\n" ); /* e_ovno */
output( "\t.short 0,0,0,0\n" ); /* e_res */
output( "\t.short 0\n" ); /* e_oemid */
output( "\t.short 0\n" ); /* e_oeminfo */
output( "\t.short 0,0,0,0,0,0,0,0,0,0\n" ); /* e_res2 */
output( "\t.long .L__wine_spec_ne_header-.L__wine_spec_dos_header\n" );/* e_lfanew */
output( ".L__wine_spec_ne_header:\n" );
output( "\t.short 0x454e\n" ); /* ne_magic */
output( "\t.byte 0\n" ); /* ne_ver */
output( "\t.byte 0\n" ); /* ne_rev */
output( "\t.short .L__wine_spec_ne_enttab-.L__wine_spec_ne_header\n" );/* ne_enttab */
output( "\t.short .L__wine_spec_ne_enttab_end-.L__wine_spec_ne_enttab\n" );/* ne_cbenttab */
output( "\t.long 0\n" ); /* ne_crc */
output( "\t.short 0x%04x\n", NE_FFLAGS_SINGLEDATA | /* ne_flags */
((spec->characteristics & IMAGE_FILE_DLL) ? NE_FFLAGS_LIBMODULE : 0) );
output( "\t.short 2\n" ); /* ne_autodata */
output( "\t.short %u\n", spec->heap_size ); /* ne_heap */
output( "\t.short 0\n" ); /* ne_stack */
if (!entry_point) output( "\t.long 0\n" ); /* ne_csip */
else output( "\t.short .L__wine_%s_0-.L__wine_spec_code_segment,1\n", spec->c_name );
output( "\t.short 0,2\n" ); /* ne_sssp */
output( "\t.short 2\n" ); /* ne_cseg */
output( "\t.short 0\n" ); /* ne_cmod */
output( "\t.short 0\n" ); /* ne_cbnrestab */
output( "\t.short .L__wine_spec_ne_segtab-.L__wine_spec_ne_header\n" );/* ne_segtab */
output( "\t.short .L__wine_spec_ne_rsrctab-.L__wine_spec_ne_header\n" ); /* ne_rsrctab */
output( "\t.short .L__wine_spec_ne_restab-.L__wine_spec_ne_header\n" ); /* ne_restab */
output( "\t.short .L__wine_spec_ne_modtab-.L__wine_spec_ne_header\n" ); /* ne_modtab */
output( "\t.short .L__wine_spec_ne_imptab-.L__wine_spec_ne_header\n" ); /* ne_imptab */
output( "\t.long 0\n" ); /* ne_nrestab */
output( "\t.short 0\n" ); /* ne_cmovent */
output( "\t.short 0\n" ); /* ne_align */
output( "\t.short 0\n" ); /* ne_cres */
output( "\t.byte 0x02\n" ); /* ne_exetyp = NE_OSFLAGS_WINDOWS */
output( "\t.byte 0x08\n" ); /* ne_flagsothers = NE_AFLAGS_FASTLOAD */
output( "\t.short 0\n" ); /* ne_pretthunks */
output( "\t.short 0\n" ); /* ne_psegrefbytes */
output( "\t.short 0\n" ); /* ne_swaparea */
output( "\t.short 0\n" ); /* ne_expver */
/* segment table */
output( "\n.L__wine_spec_ne_segtab:\n" );
/* code segment entry */
output( "\t.short .L__wine_spec_code_segment-.L__wine_spec_dos_header\n" ); /* filepos */
output( "\t.short .L__wine_spec_code_segment_end-.L__wine_spec_code_segment\n" ); /* size */
output( "\t.short 0x0000\n" ); /* flags */
output( "\t.short .L__wine_spec_code_segment_end-.L__wine_spec_code_segment\n" ); /* minsize */
/* data segment entry */
output( "\t.short .L__wine_spec_data_segment-.L__wine_spec_dos_header\n" ); /* filepos */
output( "\t.short .L__wine_spec_data_segment_end-.L__wine_spec_data_segment\n" ); /* size */
output( "\t.short 0x0001\n" ); /* flags = NE_SEGFLAGS_DATA */
output( "\t.short .L__wine_spec_data_segment_end-.L__wine_spec_data_segment\n" ); /* minsize */
/* resource directory */
output_res16_directory( spec );
/* resident names table */
output( "\n\t.align %d\n", get_alignment(2) );
output( ".L__wine_spec_ne_restab:\n" );
output_resident_name( spec->dll_name, 0 );
for (i = 1; i <= spec->limit; i++)
{
ORDDEF *odp = spec->ordinals[i];
if (!odp || !odp->name[0]) continue;
if (odp->flags & FLAG_EXPORT32) continue;
output_resident_name( odp->name, i );
}
output( "\t.byte 0\n" );
/* imported names table */
output( "\n\t.align %d\n", get_alignment(2) );
output( ".L__wine_spec_ne_modtab:\n" );
output( ".L__wine_spec_ne_imptab:\n" );
output( "\t.byte 0,0\n" );
/* entry table */
output( "\n.L__wine_spec_ne_enttab:\n" );
output_entry_table( spec );
output( ".L__wine_spec_ne_enttab_end:\n" );
/* code segment */
output( "\n\t.align %d\n", get_alignment(2) );
output( ".code16\n" );
output( ".L__wine_spec_code_segment:\n" );
for ( i = 0; i < nb_funcs; i++ )
{
unsigned int arg_types[2];
int nop_words, pos, argsize = 0;
if ( typelist[i]->type == TYPE_PASCAL )
argsize = get_function_argsize( typelist[i] );
/* build the arg types bit fields */
arg_types[0] = arg_types[1] = 0;
for (j = pos = 0; j < typelist[i]->u.func.nb_args && pos < 20; j++, pos++)
{
int type = 0;
switch (typelist[i]->u.func.args[j])
{
case ARG_WORD: type = ARG16_WORD; break;
case ARG_SWORD: type = ARG16_SWORD; break;
case ARG_SEGPTR: type = ARG16_LONG; break;
case ARG_SEGSTR: type = ARG16_SEGSTR; break;
case ARG_LONG: type = ARG16_LONG; break;
case ARG_PTR: type = ARG16_PTR; break;
case ARG_STR: type = ARG16_STR; break;
case ARG_WSTR: type = ARG16_PTR; break;
case ARG_FLOAT: type = ARG16_LONG; break;
case ARG_INT128: type = ARG16_PTR; break;
case ARG_INT64:
case ARG_DOUBLE:
type = ARG16_LONG;
arg_types[pos / 10] |= type << (3 * (pos % 10));
pos++;
break;
}
if (pos < 20) arg_types[pos / 10] |= type << (3 * (pos % 10));
}
if (typelist[i]->type == TYPE_VARARGS && pos < 20)
arg_types[pos / 10] |= ARG16_VARARG << (3 * (pos % 10));
output( ".L__wine_spec_callfrom16_%s:\n", get_callfrom16_name(typelist[i]) );
output( "\tpushl $.L__wine_spec_call16_%s\n", get_relay_name(typelist[i]) );
output( "\tlcalll $0,$0\n" );
if (typelist[i]->flags & FLAG_REGISTER)
{
nop_words = 5;
}
else if (typelist[i]->flags & FLAG_RET16)
{
output( "\torw %%ax,%%ax\n" );
nop_words = 4;
}
else
{
output( "\tshld $16,%%eax,%%edx\n" );
output( "\torl %%eax,%%eax\n" );
nop_words = 1;
}
if (argsize)
{
output( "\tlretw $%u\n", argsize );
nop_words--;
}
else output( "\tlretw\n" );
output( "\tnop\n" ); /* so that the lretw is aligned */
if (nop_words) output( "\t%s\n", nop_sequence[nop_words-1] );
/* the movl is here so that the code contains only valid instructions, */
/* it's never actually executed, we only care about the arg_types[] values */
output( "\t.short 0x86c7\n" );
output( "\t.long 0x%08x,0x%08x\n", arg_types[0], arg_types[1] );
}
for (i = 0; i <= spec->limit; i++)
{
ORDDEF *odp = spec->ordinals[i];
if (!odp || !is_function( odp )) continue;
output( ".L__wine_%s_%u:\n", spec->c_name, i );
output( "\tpushw %%bp\n" );
if (odp->flags & FLAG_STKPROLOG)
{
output( "\tmovw %%sp, %%bp\n" );
output( "\tpushw $0x1234\n" );
output( "\tpopw %%bp\n" );
output( "\tpopw %%bp\n" );
output( "\tpushw %%bp\n" );
}
output( "\tpushl $%s\n",
odp->type == TYPE_PASCAL ? asm_name_stdcall16(odp->link_name, odp) : (odp->type == TYPE_STUB ? get_stub_name(odp, spec) : asm_name( odp->link_name )));
output( "\tcallw .L__wine_spec_callfrom16_%s\n", get_callfrom16_name( odp ) );
}
output( ".L__wine_spec_code_segment_end:\n" );
/* data segment */
output( "\n.L__wine_spec_data_segment:\n" );
output( "\t.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n" ); /* instance data */
for (i = 0; i <= spec->limit; i++)
{
ORDDEF *odp = spec->ordinals[i];
if (!odp || odp->type != TYPE_VARIABLE) continue;
output( ".L__wine_%s_%u:\n", spec->c_name, i );
output( "\t.long " );
for (j = 0; j < odp->u.var.n_values-1; j++)
output( "0x%08x,", odp->u.var.values[j] );
output( "0x%08x\n", odp->u.var.values[j] );
}
output( ".L__wine_spec_data_segment_end:\n" );
/* resource data */
if (spec->nb_resources)
{
output( "\n.L__wine_spec_resource_data:\n" );
output_res16_data( spec );
}
output( "\t.byte 0\n" ); /* make sure the last symbol points to something */
/* relay functions */
nb_funcs = sort_func_list( typelist, nb_funcs, relay_type_compare );
if (nb_funcs)
{
output( "\n/* relay functions */\n\n" );
output( "\t.text\n" );
for ( i = 0; i < nb_funcs; i++ ) output_call16_function( typelist[i] );
output( "\t.data\n" );
output( "wine_ldt_copy_ptr:\n" );
output( "\t.long %s\n", asm_name("_imp__wine_ldt_copy") );
}
output( ".code32\n" );
free( typelist );
}
/*******************************************************************
* output_spec16_file
*
* Output the complete data for a spec 16-bit file.
*/
void output_spec16_file( DLLSPEC *spec16 )
{
DLLSPEC *spec32 = alloc_dll_spec();
resolve_imports( spec16 );
add_16bit_exports( spec32, spec16 );
needs_get_pc_thunk = 0;
output_standard_file_header();
//output_module( spec32 );
output_module16( spec16 );
output_stubs( spec16 );
//output_exports( spec32 );
//output_imports( spec16 );
output( "\n\t%s\n", get_asm_string_section() );
output( "%s\n", asm_globl("__wine_spec_file_name") );
output( ".L__wine_spec_file_name:\n" );
output( "\t%s \"%s\"\n", get_asm_string_keyword(), spec16->file_name );
if (1||is_undefined( "__wine_call_from_16" )) output_asm_relays16();
if (needs_get_pc_thunk) output_get_pc_thunk();
if (spec16->main_module)
{
output( "\n\t%s\n", get_asm_string_section() );
output( ".L__wine_spec_main_module:\n" );
output( "\t%s \"%s\"\n", get_asm_string_keyword(), spec16->main_module );
}
output_gnu_stack_note();
free_dll_spec( spec32 );
output("%s:/*?*/\n", asm_name("_end"));
flush_output_buffer();
}
/*******************************************************************
* output_fake_module16
*
* Create a fake 16-bit binary module.
*/
void output_fake_module16( DLLSPEC *spec )
{
static const unsigned char code_segment[] = { 0x90, 0xc3 };
static const unsigned char data_segment[16] = { 0 };
static const char fakedll_signature[] = "Wine placeholder DLL";
const unsigned int cseg = 2;
const unsigned int lfanew = (0x40 + sizeof(fakedll_signature) + 15) & ~15;
const unsigned int segtab = lfanew + 0x40;
unsigned int i, rsrctab, restab, namelen, modtab, imptab, enttab, cbenttab, codeseg, dataseg, rsrcdata;
init_output_buffer();
rsrctab = lfanew;
restab = segtab + 8 * cseg;
if (spec->nb_resources)
{
output_bin_res16_directory( spec, 0 );
align_output( 2 );
rsrctab = restab;
restab += output_buffer_pos;
free( output_buffer );
init_output_buffer();
}
namelen = strlen( spec->dll_name );
modtab = restab + ((namelen + 3) & ~1);
imptab = modtab;
enttab = modtab + 2;
cbenttab = 1;
codeseg = (enttab + cbenttab + 1) & ~1;
dataseg = codeseg + sizeof(code_segment);
rsrcdata = dataseg + sizeof(data_segment);
init_output_buffer();
put_word( 0x5a4d ); /* e_magic */
put_word( 0x40 ); /* e_cblp */
put_word( 0x01 ); /* e_cp */
put_word( 0 ); /* e_crlc */
put_word( lfanew / 16 ); /* e_cparhdr */
put_word( 0x0000 ); /* e_minalloc */
put_word( 0xffff ); /* e_maxalloc */
put_word( 0x0000 ); /* e_ss */
put_word( 0x00b8 ); /* e_sp */
put_word( 0 ); /* e_csum */
put_word( 0 ); /* e_ip */
put_word( 0 ); /* e_cs */
put_word( lfanew ); /* e_lfarlc */
put_word( 0 ); /* e_ovno */
put_dword( 0 ); /* e_res */
put_dword( 0 );
put_word( 0 ); /* e_oemid */
put_word( 0 ); /* e_oeminfo */
put_dword( 0 ); /* e_res2 */
put_dword( 0 );
put_dword( 0 );
put_dword( 0 );
put_dword( 0 );
put_dword( lfanew );
put_data( fakedll_signature, sizeof(fakedll_signature) );
align_output( 16 );
put_word( 0x454e ); /* ne_magic */
put_byte( 0 ); /* ne_ver */
put_byte( 0 ); /* ne_rev */
put_word( enttab - lfanew ); /* ne_enttab */
put_word( cbenttab ); /* ne_cbenttab */
put_dword( 0 ); /* ne_crc */
put_word( NE_FFLAGS_SINGLEDATA | /* ne_flags */
((spec->characteristics & IMAGE_FILE_DLL) ? NE_FFLAGS_LIBMODULE : 0) );
put_word( 2 ); /* ne_autodata */
put_word( spec->heap_size ); /* ne_heap */
put_word( 0 ); /* ne_stack */
put_word( 0 ); put_word( 0 ); /* ne_csip */
put_word( 0 ); put_word( 2 ); /* ne_sssp */
put_word( cseg ); /* ne_cseg */
put_word( 0 ); /* ne_cmod */
put_word( 0 ); /* ne_cbnrestab */
put_word( segtab - lfanew ); /* ne_segtab */
put_word( rsrctab - lfanew ); /* ne_rsrctab */
put_word( restab - lfanew ); /* ne_restab */
put_word( modtab - lfanew ); /* ne_modtab */
put_word( imptab - lfanew ); /* ne_imptab */
put_dword( 0 ); /* ne_nrestab */
put_word( 0 ); /* ne_cmovent */
put_word( 0 ); /* ne_align */
put_word( 0 ); /* ne_cres */
put_byte( 2 /*NE_OSFLAGS_WINDOWS*/ ); /* ne_exetyp */
put_byte( 8 /*NE_AFLAGS_FASTLOAD*/ ); /* ne_flagsothers */
put_word( 0 ); /* ne_pretthunks */
put_word( 0 ); /* ne_psegrefbytes */
put_word( 0 ); /* ne_swaparea */
put_word( 0 ); /* ne_expver */
/* segment table */
put_word( codeseg );
put_word( sizeof(code_segment) );
put_word( 0x0000 );
put_word( sizeof(code_segment) );
put_word( dataseg );
put_word( sizeof(data_segment) );
put_word( 0x0001 /* NE_SEGFLAGS_DATA */ );
put_word( sizeof(data_segment) );
/* resource directory */
if (spec->nb_resources)
{
output_bin_res16_directory( spec, rsrcdata );
align_output( 2 );
}
/* resident names table */
put_byte( namelen );
for (i = 0; i < namelen; i++) put_byte( toupper(spec->dll_name[i]) );
put_byte( 0 );
align_output( 2 );
/* imported names table */
put_word( 0 );
/* entry table */
put_byte( 0 );
align_output( 2 );
/* code segment */
put_data( code_segment, sizeof(code_segment) );
/* data segment */
put_data( data_segment, sizeof(data_segment) );
/* resource data */
output_bin_res16_data( spec );
flush_output_buffer();
}
================================================
FILE: convspec/spec32.c
================================================
/*
* 32-bit spec files
*
* Copyright 1993 Robert J. Amstadt
* Copyright 1995 Martin von Loewis
* Copyright 1995, 1996, 1997 Alexandre Julliard
* Copyright 1997 Eric Youngdale
* Copyright 1999 Ulrich Weigand
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#include "wine/port.h"
#include
#include
#include
#include
#include "build.h"
#define IMAGE_FILE_MACHINE_UNKNOWN 0
#define IMAGE_FILE_MACHINE_I386 0x014c
#define IMAGE_FILE_MACHINE_POWERPC 0x01f0
#define IMAGE_FILE_MACHINE_AMD64 0x8664
#define IMAGE_FILE_MACHINE_ARMNT 0x01C4
#define IMAGE_FILE_MACHINE_ARM64 0xaa64
#define IMAGE_SIZEOF_NT_OPTIONAL32_HEADER 224
#define IMAGE_SIZEOF_NT_OPTIONAL64_HEADER 240
#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b
#define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b
#define IMAGE_ROM_OPTIONAL_HDR_MAGIC 0x107
int needs_get_pc_thunk = 0;
/* check if entry point needs a relay thunk */
static inline int needs_relay( const ORDDEF *odp )
{
/* skip nonexistent entry points */
if (!odp) return 0;
/* skip non-functions */
switch (odp->type)
{
case TYPE_STDCALL:
case TYPE_CDECL:
case TYPE_THISCALL:
break;
case TYPE_STUB:
if (odp->u.func.nb_args != -1) break;
/* fall through */
default:
return 0;
}
/* skip norelay and forward entry points */
if (odp->flags & (FLAG_NORELAY|FLAG_FORWARD)) return 0;
return 1;
}
static int is_float_arg( const ORDDEF *odp, int arg )
{
if (arg >= odp->u.func.nb_args) return 0;
return (odp->u.func.args[arg] == ARG_FLOAT || odp->u.func.args[arg] == ARG_DOUBLE);
}
/* check if dll will output relay thunks */
static int has_relays( DLLSPEC *spec )
{
int i;
if (target_cpu != CPU_x86 && target_cpu != CPU_x86_64 &&
target_cpu != CPU_ARM && target_cpu != CPU_ARM64)
return 0;
for (i = spec->base; i <= spec->limit; i++)
{
ORDDEF *odp = spec->ordinals[i];
if (needs_relay( odp )) return 1;
}
return 0;
}
static int cmp_func_args( const void *p1, const void *p2 )
{
const ORDDEF *odp1 = *(const ORDDEF **)p1;
const ORDDEF *odp2 = *(const ORDDEF **)p2;
return odp2->u.func.nb_args - odp1->u.func.nb_args;
}
static void get_arg_string( ORDDEF *odp, char str[MAX_ARGUMENTS + 1] )
{
int i;
for (i = 0; i < odp->u.func.nb_args; i++)
{
switch (odp->u.func.args[i])
{
case ARG_STR: str[i] = 's'; break;
case ARG_WSTR: str[i] = 'w'; break;
case ARG_FLOAT: str[i] = 'f'; break;
case ARG_DOUBLE: str[i] = 'd'; break;
case ARG_INT64:
case ARG_INT128:
if (get_ptr_size() == 4)
{
str[i] = (odp->u.func.args[i] == ARG_INT64) ? 'j' : 'k';
break;
}
/* fall through */
case ARG_LONG:
case ARG_PTR:
default:
str[i] = 'i';
break;
}
}
if (target_cpu == CPU_x86 && odp->type == TYPE_THISCALL) str[0] = 't';
/* append return value */
if (get_ptr_size() == 4 && (odp->flags & FLAG_RET64))
strcpy( str + i, "J" );
else
strcpy( str + i, "I" );
}
/*******************************************************************
* build_args_string
*/
static char *build_args_string( DLLSPEC *spec )
{
int i, count = 0, len = 1;
char *p, *buffer;
char str[MAX_ARGUMENTS + 2];
ORDDEF **funcs;
funcs = xmalloc( (spec->limit + 1 - spec->base) * sizeof(*funcs) );
for (i = spec->base; i <= spec->limit; i++)
{
ORDDEF *odp = spec->ordinals[i];
if (!needs_relay( odp )) continue;
funcs[count++] = odp;
len += odp->u.func.nb_args + 1;
}
/* sort functions by decreasing number of arguments */
qsort( funcs, count, sizeof(*funcs), cmp_func_args );
buffer = xmalloc( len );
buffer[0] = 0;
/* build the arguments string, reusing substrings where possible */
for (i = 0; i < count; i++)
{
get_arg_string( funcs[i], str );
if (!(p = strstr( buffer, str )))
{
p = buffer + strlen( buffer );
strcpy( p, str );
}
funcs[i]->u.func.args_str_offset = p - buffer;
}
free( funcs );
return buffer;
}
/*******************************************************************
* output_relay_debug
*
* Output entry points for relay debugging
*/
static void output_relay_debug( DLLSPEC *spec )
{
int i;
/* first the table of entry point offsets */
output( "\t%s\n", get_asm_rodata_section() );
output( "\t.align %d\n", get_alignment(4) );
output( ".L__wine_spec_relay_entry_point_offsets:\n" );
for (i = spec->base; i <= spec->limit; i++)
{
ORDDEF *odp = spec->ordinals[i];
if (needs_relay( odp ))
output( "\t.long .L__wine_spec_relay_entry_point_%d-__wine_spec_relay_entry_points\n", i );
else
output( "\t.long 0\n" );
}
/* then the strings of argument types */
output( ".L__wine_spec_relay_args_string:\n" );
output( "\t%s \"%s\"\n", get_asm_string_keyword(), build_args_string( spec ));
/* then the relay thunks */
output( "\t.text\n" );
output( "__wine_spec_relay_entry_points:\n" );
output( "\tnop\n" ); /* to avoid 0 offset */
for (i = spec->base; i <= spec->limit; i++)
{
ORDDEF *odp = spec->ordinals[i];
if (!needs_relay( odp )) continue;
output( "\t.align %d\n", get_alignment(4) );
output( ".L__wine_spec_relay_entry_point_%d:\n", i );
output_cfi( ".cfi_startproc" );
switch (target_cpu)
{
case CPU_x86:
if (odp->type == TYPE_THISCALL) /* add the this pointer */
{
output( "\tpopl %%eax\n" );
output( "\tpushl %%ecx\n" );
output( "\tpushl %%eax\n" );
}
output( "\tpushl $%u\n", (odp->u.func.args_str_offset << 16) | (i - spec->base) );
output_cfi( ".cfi_adjust_cfa_offset 4" );
if (UsePIC)
{
output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
output( "1:\tleal .L__wine_spec_relay_descr-1b(%%eax),%%eax\n" );
needs_get_pc_thunk = 1;
}
else output( "\tmovl $.L__wine_spec_relay_descr,%%eax\n" );
output( "\tpushl %%eax\n" );
output_cfi( ".cfi_adjust_cfa_offset 4" );
output( "\tcall *4(%%eax)\n" );
output_cfi( ".cfi_adjust_cfa_offset -8" );
if (odp->type == TYPE_STDCALL || odp->type == TYPE_THISCALL)
output( "\tret $%u\n", get_args_size( odp ));
else
output( "\tret\n" );
break;
case CPU_ARM:
{
unsigned int mask, val, count = 0;
int j, has_float = 0;
if (strcmp( float_abi_option, "soft" ))
for (j = 0; j < odp->u.func.nb_args && !has_float; j++)
has_float = is_float_arg( odp, j );
val = (odp->u.func.args_str_offset << 16) | (i - spec->base);
output( "\tpush {r0-r3}\n" );
output( "\tmov r2, SP\n");
if (has_float) output( "\tvpush {s0-s15}\n" );
output( "\tpush {LR}\n" );
output( "\tsub SP, #4\n");
for (mask = 0xff; mask; mask <<= 8)
if (val & mask) output( "\t%s r1,#%u\n", count++ ? "add" : "mov", val & mask );
if (!count) output( "\tmov r1,#0\n" );
output( "\tldr r0, 2f\n");
output( "\tadd r0, PC\n");
output( "\tldr IP, [r0, #4]\n");
output( "1:\tblx IP\n");
output( "\tldr IP, [SP, #4]\n" );
output( "\tadd SP, #%u\n", 24 + (has_float ? 64 : 0) );
output( "\tbx IP\n");
output( "2:\t.long .L__wine_spec_relay_descr-1b\n" );
break;
}
case CPU_ARM64:
switch (odp->u.func.nb_args)
{
default:
case 8:
case 7: output( "\tstp x6, x7, [SP,#-16]!\n" );
/* fall through */
case 6:
case 5: output( "\tstp x4, x5, [SP,#-16]!\n" );
/* fall through */
case 4:
case 3: output( "\tstp x2, x3, [SP,#-16]!\n" );
/* fall through */
case 2:
case 1: output( "\tstp x0, x1, [SP,#-16]!\n" );
/* fall through */
case 0: break;
}
output( "\tmov x2, SP\n");
output( "\tstp x29, x30, [SP,#-16]!\n" );
output( "\tstp x8, x9, [SP,#-16]!\n" );
output( "\tmov w1, #%u\n", odp->u.func.args_str_offset << 16 );
if (i - spec->base) output( "\tadd w1, w1, #%u\n", i - spec->base );
output( "\tadrp x0, .L__wine_spec_relay_descr\n");
output( "\tadd x0, x0, #:lo12:.L__wine_spec_relay_descr\n");
output( "\tldr x3, [x0, #8]\n");
output( "\tblr x3\n");
output( "\tadd SP, SP, #16\n" );
output( "\tldp x29, x30, [SP], #16\n" );
if (odp->u.func.nb_args)
output( "\tadd SP, SP, #%u\n", 8 * ((min(odp->u.func.nb_args, 8) + 1) & ~1) );
output( "\tret\n");
break;
case CPU_x86_64:
switch (odp->u.func.nb_args)
{
default: output( "\tmovq %%%s,32(%%rsp)\n", is_float_arg( odp, 3 ) ? "xmm3" : "r9" );
/* fall through */
case 3: output( "\tmovq %%%s,24(%%rsp)\n", is_float_arg( odp, 2 ) ? "xmm2" : "r8" );
/* fall through */
case 2: output( "\tmovq %%%s,16(%%rsp)\n", is_float_arg( odp, 1 ) ? "xmm1" : "rdx" );
/* fall through */
case 1: output( "\tmovq %%%s,8(%%rsp)\n", is_float_arg( odp, 0 ) ? "xmm0" : "rcx" );
/* fall through */
case 0: break;
}
output( "\tmovl $%u,%%edx\n", (odp->u.func.args_str_offset << 16) | (i - spec->base) );
output( "\tleaq .L__wine_spec_relay_descr(%%rip),%%rcx\n" );
output( "\tcallq *8(%%rcx)\n" );
output( "\tret\n" );
break;
default:
assert(0);
}
output_cfi( ".cfi_endproc" );
}
}
/*******************************************************************
* output_exports
*
* Output the export table for a Win32 module.
*/
void output_exports( DLLSPEC *spec )
{
int i, fwd_size = 0;
int nr_exports = spec->base <= spec->limit ? spec->limit - spec->base + 1 : 0;
if (!nr_exports) return;
output( "\n/* export table */\n\n" );
output( "\t.data\n" );
output( "\t.align %d\n", get_alignment(4) );
output( ".L__wine_spec_exports:\n" );
/* export directory header */
output( "\t.long 0\n" ); /* Characteristics */
output( "\t.long 0\n" ); /* TimeDateStamp */
output( "\t.long 0\n" ); /* MajorVersion/MinorVersion */
output( "\t.long .L__wine_spec_exp_names-.L__wine_spec_rva_base\n" ); /* Name */
output( "\t.long %u\n", spec->base ); /* Base */
output( "\t.long %u\n", nr_exports ); /* NumberOfFunctions */
output( "\t.long %u\n", spec->nb_names ); /* NumberOfNames */
output( "\t.long .L__wine_spec_exports_funcs-.L__wine_spec_rva_base\n" ); /* AddressOfFunctions */
if (spec->nb_names)
{
output( "\t.long .L__wine_spec_exp_name_ptrs-.L__wine_spec_rva_base\n" ); /* AddressOfNames */
output( "\t.long .L__wine_spec_exp_ordinals-.L__wine_spec_rva_base\n" ); /* AddressOfNameOrdinals */
}
else
{
output( "\t.long 0\n" ); /* AddressOfNames */
output( "\t.long 0\n" ); /* AddressOfNameOrdinals */
}
/* output the function pointers */
output( "\n.L__wine_spec_exports_funcs:\n" );
for (i = spec->base; i <= spec->limit; i++)
{
ORDDEF *odp = spec->ordinals[i];
if (!odp) output( "\t%s 0\n", get_asm_ptr_keyword() );
else switch(odp->type)
{
case TYPE_EXTERN:
case TYPE_STDCALL:
case TYPE_VARARGS:
case TYPE_CDECL:
case TYPE_THISCALL:
if (odp->flags & FLAG_FORWARD)
{
output( "\t%s .L__wine_spec_forwards+%u\n", get_asm_ptr_keyword(), fwd_size );
fwd_size += strlen(odp->link_name) + 1;
}
else if (odp->flags & FLAG_EXT_LINK)
{
output( "\t%s %s_%s\n",
get_asm_ptr_keyword(), asm_name("__wine_spec_ext_link"), odp->link_name );
}
else
{
output( "\t%s %s\n", get_asm_ptr_keyword(), odp->type == TYPE_STDCALL ? asm_name_stdcall32(odp->link_name, odp) : asm_name(odp->link_name) );
}
break;
case TYPE_STUB:
output( "\t%s %s\n", get_asm_ptr_keyword(),
asm_name( get_stub_name( odp, spec )) );
break;
default:
assert(0);
}
}
if (spec->nb_names)
{
/* output the function name pointers */
int namepos = strlen(spec->file_name) + 1;
output( "\n.L__wine_spec_exp_name_ptrs:\n" );
for (i = 0; i < spec->nb_names; i++)
{
output( "\t.long .L__wine_spec_exp_names+%u-.L__wine_spec_rva_base\n", namepos );
namepos += strlen(spec->names[i]->name) + 1;
}
/* output the function ordinals */
output( "\n.L__wine_spec_exp_ordinals:\n" );
for (i = 0; i < spec->nb_names; i++)
{
output( "\t.short %d\n", spec->names[i]->ordinal - spec->base );
}
if (spec->nb_names % 2)
{
output( "\t.short 0\n" );
}
}
/* output the export name strings */
output( "\n.L__wine_spec_exp_names:\n" );
output( "\t%s \"%s\"\n", get_asm_string_keyword(), spec->file_name );
for (i = 0; i < spec->nb_names; i++)
output( "\t%s \"%s\"\n",
get_asm_string_keyword(), spec->names[i]->name );
/* output forward strings */
if (fwd_size)
{
output( "\n.L__wine_spec_forwards:\n" );
for (i = spec->base; i <= spec->limit; i++)
{
ORDDEF *odp = spec->ordinals[i];
if (odp && (odp->flags & FLAG_FORWARD))
output( "\t%s \"%s\"\n", get_asm_string_keyword(), odp->link_name );
}
}
output( "\t.align %d\n", get_alignment(get_ptr_size()) );
output( ".L__wine_spec_exports_end:\n" );
/* output relays */
if (!has_relays( spec ))
{
output( "\t%s 0\n", get_asm_ptr_keyword() );
return;
}
output( ".L__wine_spec_relay_descr:\n" );
output( "\t%s 0xdeb90002\n", get_asm_ptr_keyword() ); /* magic */
output( "\t%s 0\n", get_asm_ptr_keyword() ); /* relay func */
output( "\t%s 0\n", get_asm_ptr_keyword() ); /* private data */
output( "\t%s __wine_spec_relay_entry_points\n", get_asm_ptr_keyword() );
output( "\t%s .L__wine_spec_relay_entry_point_offsets\n", get_asm_ptr_keyword() );
output( "\t%s .L__wine_spec_relay_args_string\n", get_asm_ptr_keyword() );
output_relay_debug( spec );
}
/*******************************************************************
* output_asm_constructor
*
* Output code for calling a dll constructor.
*/
static void output_asm_constructor( const char *constructor )
{
if (target_platform == PLATFORM_APPLE)
{
/* Mach-O doesn't have an init section */
output( "\n\t.mod_init_func\n" );
output( "\t.align %d\n", get_alignment(get_ptr_size()) );
output( "\t%s %s\n", get_asm_ptr_keyword(), asm_name(constructor) );
}
else
{
switch(target_cpu)
{
case CPU_x86:
case CPU_x86_64:
output( "\n\t.section \".init\",\"ax\"\n" );
output( "\tcall %s\n", asm_name(constructor) );
break;
case CPU_ARM:
output( "\n\t.section \".text\",\"ax\"\n" );
output( "\tblx %s\n", asm_name(constructor) );
break;
case CPU_ARM64:
case CPU_POWERPC:
output( "\n\t.section \".init\",\"ax\"\n" );
output( "\tbl %s\n", asm_name(constructor) );
break;
}
}
}
/*******************************************************************
* output_module
*
* Output the module data.
*/
void output_module( DLLSPEC *spec )
{
int machine = 0;
unsigned int page_size = get_page_size();
/* Reserve some space for the PE header */
switch (target_platform)
{
case PLATFORM_APPLE:
output( "\t.text\n" );
output( "\t.align %d\n", get_alignment(page_size) );
output( "__wine_spec_pe_header:\n" );
output( "\t.space 65536\n" );
break;
case PLATFORM_SOLARIS:
output( "\n\t.section \".text\",\"ax\"\n" );
output( "__wine_spec_pe_header:\n" );
output( "\t.skip %u\n", 65536 + page_size );
break;
default:
switch(target_cpu)
{
case CPU_x86:
case CPU_x86_64:
output( "\n\t.section \".init\",\"ax\"\n" );
output( "\tjmp 1f\n" );
break;
case CPU_ARM:
output( "\n\t.section \".text\",\"ax\"\n" );
output( "\tb 1f\n" );
break;
case CPU_ARM64:
case CPU_POWERPC:
output( "\n\t.section \".init\",\"ax\"\n" );
output( "\tb 1f\n" );
break;
}
output( "__wine_spec_pe_header:\n" );
output( "\t.skip %u\n", 65536 + page_size );
output( "1:\n" );
break;
}
/* Output the NT header */
output( "\n\t.data\n" );
output( "\t.align %d\n", get_alignment(get_ptr_size()) );
output( "%s\n", asm_globl("__wine_spec_nt_header") );
output( ".L__wine_spec_rva_base:\n" );
output( "\t.long 0x4550\n" ); /* Signature */
switch(target_cpu)
{
case CPU_x86: machine = IMAGE_FILE_MACHINE_I386; break;
case CPU_x86_64: machine = IMAGE_FILE_MACHINE_AMD64; break;
case CPU_POWERPC: machine = IMAGE_FILE_MACHINE_POWERPC; break;
case CPU_ARM: machine = IMAGE_FILE_MACHINE_ARMNT; break;
case CPU_ARM64: machine = IMAGE_FILE_MACHINE_ARM64; break;
}
output( "\t.short 0x%04x\n", /* Machine */
machine );
output( "\t.short 0\n" ); /* NumberOfSections */
output( "\t.long 0\n" ); /* TimeDateStamp */
output( "\t.long 0\n" ); /* PointerToSymbolTable */
output( "\t.long 0\n" ); /* NumberOfSymbols */
output( "\t.short %d\n", /* SizeOfOptionalHeader */
get_ptr_size() == 8 ? IMAGE_SIZEOF_NT_OPTIONAL64_HEADER : IMAGE_SIZEOF_NT_OPTIONAL32_HEADER );
output( "\t.short 0x%04x\n", /* Characteristics */
spec->characteristics );
output( "\t.short 0x%04x\n", /* Magic */
get_ptr_size() == 8 ? IMAGE_NT_OPTIONAL_HDR64_MAGIC : IMAGE_NT_OPTIONAL_HDR32_MAGIC );
output( "\t.byte 7\n" ); /* MajorLinkerVersion */
output( "\t.byte 10\n" ); /* MinorLinkerVersion */
output( "\t.long 0\n" ); /* SizeOfCode */
output( "\t.long 0\n" ); /* SizeOfInitializedData */
output( "\t.long 0\n" ); /* SizeOfUninitializedData */
/* note: we expand the AddressOfEntryPoint field on 64-bit by overwriting the BaseOfCode field */
output( "\t%s %s\n", /* AddressOfEntryPoint */
get_asm_ptr_keyword(), spec->init_func ? asm_name(spec->init_func) : "0" );
if (get_ptr_size() == 4)
{
output( "\t.long 0\n" ); /* BaseOfCode */
output( "\t.long 0\n" ); /* BaseOfData */
}
output( "\t%s __wine_spec_pe_header\n", /* ImageBase */
get_asm_ptr_keyword() );
output( "\t.long %u\n", page_size ); /* SectionAlignment */
output( "\t.long %u\n", page_size ); /* FileAlignment */
output( "\t.short 1,0\n" ); /* Major/MinorOperatingSystemVersion */
output( "\t.short 0,0\n" ); /* Major/MinorImageVersion */
output( "\t.short %u,%u\n", /* Major/MinorSubsystemVersion */
spec->subsystem_major, spec->subsystem_minor );
output( "\t.long 0\n" ); /* Win32VersionValue */
output( "\t.long %s-.L__wine_spec_rva_base\n", /* SizeOfImage */
asm_name("_end") );
output( "\t.long %u\n", page_size ); /* SizeOfHeaders */
output( "\t.long 0\n" ); /* CheckSum */
output( "\t.short 0x%04x\n", /* Subsystem */
spec->subsystem );
output( "\t.short 0x%04x\n", /* DllCharacteristics */
spec->dll_characteristics );
output( "\t%s %u,%u\n", /* SizeOfStackReserve/Commit */
get_asm_ptr_keyword(), (spec->stack_size ? spec->stack_size : 1024) * 1024, page_size );
output( "\t%s %u,%u\n", /* SizeOfHeapReserve/Commit */
get_asm_ptr_keyword(), (spec->heap_size ? spec->heap_size : 1024) * 1024, page_size );
output( "\t.long 0\n" ); /* LoaderFlags */
output( "\t.long 16\n" ); /* NumberOfRvaAndSizes */
if (spec->base <= spec->limit) /* DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT] */
output( "\t.long .L__wine_spec_exports-.L__wine_spec_rva_base,"
".L__wine_spec_exports_end-.L__wine_spec_exports\n" );
else
output( "\t.long 0,0\n" );
if (has_imports()) /* DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] */
output( "\t.long .L__wine_spec_imports-.L__wine_spec_rva_base,"
".L__wine_spec_imports_end-.L__wine_spec_imports\n" );
else
output( "\t.long 0,0\n" );
if (spec->nb_resources) /* DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE] */
output( "\t.long .L__wine_spec_resources-.L__wine_spec_rva_base,"
".L__wine_spec_resources_end-.L__wine_spec_resources\n" );
else
output( "\t.long 0,0\n" );
output( "\t.long 0,0\n" ); /* DataDirectory[3] */
output( "\t.long 0,0\n" ); /* DataDirectory[4] */
output( "\t.long 0,0\n" ); /* DataDirectory[5] */
output( "\t.long 0,0\n" ); /* DataDirectory[6] */
output( "\t.long 0,0\n" ); /* DataDirectory[7] */
output( "\t.long 0,0\n" ); /* DataDirectory[8] */
output( "\t.long 0,0\n" ); /* DataDirectory[9] */
output( "\t.long 0,0\n" ); /* DataDirectory[10] */
output( "\t.long 0,0\n" ); /* DataDirectory[11] */
output( "\t.long 0,0\n" ); /* DataDirectory[12] */
output( "\t.long 0,0\n" ); /* DataDirectory[13] */
output( "\t.long 0,0\n" ); /* DataDirectory[14] */
output( "\t.long 0,0\n" ); /* DataDirectory[15] */
output( "\n\t%s\n", get_asm_string_section() );
output( "%s\n", asm_globl("__wine_spec_file_name") );
output( ".L__wine_spec_file_name:\n" );
output( "\t%s \"%s\"\n", get_asm_string_keyword(), spec->file_name );
if (target_platform == PLATFORM_APPLE)
output( "\t.lcomm %s,4\n", asm_name("_end") );
output_asm_constructor( "__wine_spec_init_ctor" );
}
/*******************************************************************
* BuildSpec32File
*
* Build a Win32 C file from a spec file.
*/
void BuildSpec32File( DLLSPEC *spec )
{
needs_get_pc_thunk = 0;
resolve_imports( spec );
output_standard_file_header();
output_module( spec );
output_stubs( spec );
output_exports( spec );
output_imports( spec );
if (needs_get_pc_thunk) output_get_pc_thunk();
output_resources( spec );
output_gnu_stack_note();
}
/*******************************************************************
* output_fake_module
*
* Build a fake binary module from a spec file.
*/
void output_fake_module( DLLSPEC *spec )
{
static const unsigned char dll_code_section[] = { 0x31, 0xc0, /* xor %eax,%eax */
0xc2, 0x0c, 0x00 }; /* ret $12 */
static const unsigned char exe_code_section[] = { 0xb8, 0x01, 0x00, 0x00, 0x00, /* movl $1,%eax */
0xc2, 0x04, 0x00 }; /* ret $4 */
static const char fakedll_signature[] = "Wine placeholder DLL";
const unsigned int page_size = get_page_size();
const unsigned int section_align = page_size;
const unsigned int file_align = 0x200;
const unsigned int reloc_size = 8;
const unsigned int lfanew = (0x40 + sizeof(fakedll_signature) + 15) & ~15;
const unsigned int nb_sections = 2 + (spec->nb_resources != 0);
const unsigned int text_size = (spec->characteristics & IMAGE_FILE_DLL) ?
sizeof(dll_code_section) : sizeof(exe_code_section);
unsigned char *resources;
unsigned int resources_size;
unsigned int image_size = 3 * section_align;
resolve_imports( spec );
output_bin_resources( spec, 3 * section_align );
resources = output_buffer;
resources_size = output_buffer_pos;
if (resources_size) image_size += (resources_size + section_align - 1) & ~(section_align - 1);
init_output_buffer();
put_word( 0x5a4d ); /* e_magic */
put_word( 0x40 ); /* e_cblp */
put_word( 0x01 ); /* e_cp */
put_word( 0 ); /* e_crlc */
put_word( lfanew / 16 ); /* e_cparhdr */
put_word( 0x0000 ); /* e_minalloc */
put_word( 0xffff ); /* e_maxalloc */
put_word( 0x0000 ); /* e_ss */
put_word( 0x00b8 ); /* e_sp */
put_word( 0 ); /* e_csum */
put_word( 0 ); /* e_ip */
put_word( 0 ); /* e_cs */
put_word( lfanew ); /* e_lfarlc */
put_word( 0 ); /* e_ovno */
put_dword( 0 ); /* e_res */
put_dword( 0 );
put_word( 0 ); /* e_oemid */
put_word( 0 ); /* e_oeminfo */
put_dword( 0 ); /* e_res2 */
put_dword( 0 );
put_dword( 0 );
put_dword( 0 );
put_dword( 0 );
put_dword( lfanew );
put_data( fakedll_signature, sizeof(fakedll_signature) );
align_output( 16 );
put_dword( 0x4550 ); /* Signature */
switch(target_cpu)
{
case CPU_x86: put_word( IMAGE_FILE_MACHINE_I386 ); break;
case CPU_x86_64: put_word( IMAGE_FILE_MACHINE_AMD64 ); break;
case CPU_POWERPC: put_word( IMAGE_FILE_MACHINE_POWERPC ); break;
case CPU_ARM: put_word( IMAGE_FILE_MACHINE_ARMNT ); break;
case CPU_ARM64: put_word( IMAGE_FILE_MACHINE_ARM64 ); break;
}
put_word( nb_sections ); /* NumberOfSections */
put_dword( 0 ); /* TimeDateStamp */
put_dword( 0 ); /* PointerToSymbolTable */
put_dword( 0 ); /* NumberOfSymbols */
put_word( get_ptr_size() == 8 ?
IMAGE_SIZEOF_NT_OPTIONAL64_HEADER :
IMAGE_SIZEOF_NT_OPTIONAL32_HEADER ); /* SizeOfOptionalHeader */
put_word( spec->characteristics ); /* Characteristics */
put_word( get_ptr_size() == 8 ?
IMAGE_NT_OPTIONAL_HDR64_MAGIC :
IMAGE_NT_OPTIONAL_HDR32_MAGIC ); /* Magic */
put_byte( 7 ); /* MajorLinkerVersion */
put_byte( 10 ); /* MinorLinkerVersion */
put_dword( text_size ); /* SizeOfCode */
put_dword( 0 ); /* SizeOfInitializedData */
put_dword( 0 ); /* SizeOfUninitializedData */
put_dword( section_align ); /* AddressOfEntryPoint */
put_dword( section_align ); /* BaseOfCode */
if (get_ptr_size() == 4) put_dword( 0 ); /* BaseOfData */
put_pword( 0x10000000 ); /* ImageBase */
put_dword( section_align ); /* SectionAlignment */
put_dword( file_align ); /* FileAlignment */
put_word( 1 ); /* MajorOperatingSystemVersion */
put_word( 0 ); /* MinorOperatingSystemVersion */
put_word( 0 ); /* MajorImageVersion */
put_word( 0 ); /* MinorImageVersion */
put_word( spec->subsystem_major ); /* MajorSubsystemVersion */
put_word( spec->subsystem_minor ); /* MinorSubsystemVersion */
put_dword( 0 ); /* Win32VersionValue */
put_dword( image_size ); /* SizeOfImage */
put_dword( file_align ); /* SizeOfHeaders */
put_dword( 0 ); /* CheckSum */
put_word( spec->subsystem ); /* Subsystem */
put_word( spec->dll_characteristics ); /* DllCharacteristics */
put_pword( (spec->stack_size ? spec->stack_size : 1024) * 1024 ); /* SizeOfStackReserve */
put_pword( page_size ); /* SizeOfStackCommit */
put_pword( (spec->heap_size ? spec->heap_size : 1024) * 1024 ); /* SizeOfHeapReserve */
put_pword( page_size ); /* SizeOfHeapCommit */
put_dword( 0 ); /* LoaderFlags */
put_dword( 16 ); /* NumberOfRvaAndSizes */
put_dword( 0 ); put_dword( 0 ); /* DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT] */
put_dword( 0 ); put_dword( 0 ); /* DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] */
if (resources_size) /* DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE] */
{
put_dword( 3 * section_align );
put_dword( resources_size );
}
else
{
put_dword( 0 );
put_dword( 0 );
}
put_dword( 0 ); put_dword( 0 ); /* DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION] */
put_dword( 0 ); put_dword( 0 ); /* DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY] */
put_dword( 2 * section_align ); /* DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC] */
put_dword( reloc_size );
put_dword( 0 ); put_dword( 0 ); /* DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG] */
put_dword( 0 ); put_dword( 0 ); /* DataDirectory[IMAGE_DIRECTORY_ENTRY_COPYRIGHT] */
put_dword( 0 ); put_dword( 0 ); /* DataDirectory[IMAGE_DIRECTORY_ENTRY_GLOBALPTR] */
put_dword( 0 ); put_dword( 0 ); /* DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS] */
put_dword( 0 ); put_dword( 0 ); /* DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG] */
put_dword( 0 ); put_dword( 0 ); /* DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT] */
put_dword( 0 ); put_dword( 0 ); /* DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT] */
put_dword( 0 ); put_dword( 0 ); /* DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT] */
put_dword( 0 ); put_dword( 0 ); /* DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR] */
put_dword( 0 ); put_dword( 0 ); /* DataDirectory[15] */
/* .text section */
put_data( ".text\0\0", 8 ); /* Name */
put_dword( section_align ); /* VirtualSize */
put_dword( section_align ); /* VirtualAddress */
put_dword( text_size ); /* SizeOfRawData */
put_dword( file_align ); /* PointerToRawData */
put_dword( 0 ); /* PointerToRelocations */
put_dword( 0 ); /* PointerToLinenumbers */
put_word( 0 ); /* NumberOfRelocations */
put_word( 0 ); /* NumberOfLinenumbers */
put_dword( 0x60000020 /* CNT_CODE|MEM_EXECUTE|MEM_READ */ ); /* Characteristics */
/* .reloc section */
put_data( ".reloc\0", 8 ); /* Name */
put_dword( section_align ); /* VirtualSize */
put_dword( 2 * section_align );/* VirtualAddress */
put_dword( reloc_size ); /* SizeOfRawData */
put_dword( 2 * file_align ); /* PointerToRawData */
put_dword( 0 ); /* PointerToRelocations */
put_dword( 0 ); /* PointerToLinenumbers */
put_word( 0 ); /* NumberOfRelocations */
put_word( 0 ); /* NumberOfLinenumbers */
put_dword( 0x42000040 /* CNT_INITIALIZED_DATA|MEM_DISCARDABLE|MEM_READ */ ); /* Characteristics */
/* .rsrc section */
if (resources_size)
{
put_data( ".rsrc\0\0", 8 ); /* Name */
put_dword( (resources_size + section_align - 1) & ~(section_align - 1) ); /* VirtualSize */
put_dword( 3 * section_align );/* VirtualAddress */
put_dword( resources_size ); /* SizeOfRawData */
put_dword( 3 * file_align ); /* PointerToRawData */
put_dword( 0 ); /* PointerToRelocations */
put_dword( 0 ); /* PointerToLinenumbers */
put_word( 0 ); /* NumberOfRelocations */
put_word( 0 ); /* NumberOfLinenumbers */
put_dword( 0x40000040 /* CNT_INITIALIZED_DATA|MEM_READ */ ); /* Characteristics */
}
/* .text contents */
align_output( file_align );
if (spec->characteristics & IMAGE_FILE_DLL)
put_data( dll_code_section, sizeof(dll_code_section) );
else
put_data( exe_code_section, sizeof(exe_code_section) );
/* .reloc contents */
align_output( file_align );
put_dword( 0 ); /* VirtualAddress */
put_dword( 0 ); /* SizeOfBlock */
/* .rsrc contents */
if (resources_size)
{
align_output( file_align );
put_data( resources, resources_size );
}
flush_output_buffer();
}
/*******************************************************************
* output_def_file
*
* Build a Win32 def file from a spec file.
*/
void output_def_file( DLLSPEC *spec, int include_private )
{
DLLSPEC *spec32 = NULL;
const char *name;
int i, total;
if (spec->type == SPEC_WIN16)
{
spec32 = alloc_dll_spec();
add_16bit_exports( spec32, spec );
spec = spec32;
}
if (spec_file_name)
output( "; File generated automatically from %s; do not edit!\n\n",
spec_file_name );
else
output( "; File generated automatically; do not edit!\n\n" );
output( "LIBRARY %s\n\n", spec->file_name);
output( "EXPORTS\n");
#ifdef WINEBUILD_MSVC
kill_at = 1;
#endif
/* Output the exports and relay entry points */
for (i = total = 0; i < spec->nb_entry_points; i++)
{
const ORDDEF *odp = &spec->entry_points[i];
int is_data = 0;
if (odp->name) name = odp->name;
else if (odp->export_name) name = odp->export_name;
else continue;
if (!(odp->flags & FLAG_PRIVATE)) total++;
else if (!include_private) continue;
if (odp->type == TYPE_STUB) continue;
#ifndef WINEBUILD_MSVC
output( " %s", name );
#else
/* FIXME: workaround */
if (name && *name == '_')
{
output(" %s", name);
}
else
{
output(" %s", name);
}
#endif
switch(odp->type)
{
case TYPE_EXTERN:
is_data = 1;
/* fall through */
case TYPE_VARARGS:
case TYPE_CDECL:
case TYPE_THISCALL:
/* try to reduce output */
#ifndef WINEBUILD_MSVC
#if 0
if(strcmp(name, odp->link_name) || (odp->flags & FLAG_FORWARD))
output( "=%s", odp->link_name );
#endif
#endif
break;
case TYPE_STDCALL:
{
int at_param = get_args_size( odp );
if (!kill_at && target_cpu == CPU_x86) output( "@%d", at_param );
if (odp->flags & FLAG_FORWARD)
{
output( "=%s", odp->link_name );
}
else if (strcmp(name, odp->link_name)) /* try to reduce output */
{
output( "=%s", odp->link_name );
if (!kill_at && target_cpu == CPU_x86) output( "@%d", at_param );
}
else
{
#ifndef WINEBUILD_MSVC
/* add-stdcall-alias */
if (!odp->name || (odp->flags & FLAG_ORDINAL)) output( " NONAME" );
if (is_data) output( " DATA" );
/* PRIVATE */
#ifndef WINEBUILD_MSVC
if (odp->flags & FLAG_PRIVATE) output( " PRIVATE" );
#endif
output( "\n" );
output( " %s=%s", name, name );
if (!kill_at && target_cpu == CPU_x86) output( "@%d", at_param );
#endif
}
break;
}
default:
assert(0);
}
output( " @%d", odp->ordinal );
if (!odp->name || (odp->flags & FLAG_ORDINAL)) output( " NONAME" );
if (is_data) output( " DATA" );
/* PRIVATE */
#ifndef WINEBUILD_MSVC
if (odp->flags & FLAG_PRIVATE) output( " PRIVATE" );
#endif
output( "\n" );
}
if (!total) warning( "%s: Import library doesn't export anything\n", spec->file_name );
if (spec32) free_dll_spec( spec32 );
}
================================================
FILE: convspec/utils.c
================================================
/*
* Small utility functions for winebuild
*
* Copyright 2000 Alexandre Julliard
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#include "wine/port.h"
#include
#include
#include
#include
#include
#include
#ifdef HAVE_UNISTD_H
# include
#endif
#ifdef HAVE_SYS_STAT_H
# include
#endif
#ifdef HAVE_SYS_MMAN_H
#include
#endif
#include "build.h"
#if defined(_WIN32) && !defined(__CYGWIN__)
# define PATH_SEPARATOR ';'
#else
# define PATH_SEPARATOR ':'
#endif
static struct strarray tmp_files;
static struct strarray empty_strarray;
static const struct
{
const char *name;
enum target_cpu cpu;
} cpu_names[] =
{
{ "i386", CPU_x86 },
{ "i486", CPU_x86 },
{ "i586", CPU_x86 },
{ "i686", CPU_x86 },
{ "i786", CPU_x86 },
{ "amd64", CPU_x86_64 },
{ "x86_64", CPU_x86_64 },
{ "powerpc", CPU_POWERPC },
{ "arm", CPU_ARM },
{ "armv5", CPU_ARM },
{ "armv6", CPU_ARM },
{ "armv7", CPU_ARM },
{ "arm64", CPU_ARM64 },
{ "aarch64", CPU_ARM64 },
};
/* atexit handler to clean tmp files */
void cleanup_tmp_files(void)
{
unsigned int i;
for (i = 0; i < tmp_files.count; i++) if (tmp_files.str[i]) unlink( tmp_files.str[i] );
}
void *xmalloc (size_t size)
{
void *res;
res = malloc (size ? size : 1);
if (res == NULL)
{
fprintf (stderr, "Virtual memory exhausted.\n");
exit (1);
}
return res;
}
void *xrealloc (void *ptr, size_t size)
{
void *res = realloc (ptr, size);
if (size && res == NULL)
{
fprintf (stderr, "Virtual memory exhausted.\n");
exit (1);
}
return res;
}
char *xstrdup( const char *str )
{
char *res = strdup( str );
if (!res)
{
fprintf (stderr, "Virtual memory exhausted.\n");
exit (1);
}
return res;
}
char *strupper(char *s)
{
char *p;
for (p = s; *p; p++) *p = toupper(*p);
return s;
}
int strendswith(const char* str, const char* end)
{
int l = strlen(str);
int m = strlen(end);
return l >= m && strcmp(str + l - m, end) == 0;
}
char *strmake( const char* fmt, ... )
{
int n;
size_t size = 100;
va_list ap;
for (;;)
{
char *p = xmalloc( size );
va_start( ap, fmt );
n = vsnprintf( p, size, fmt, ap );
va_end( ap );
if (n == -1) size *= 2;
else if ((size_t)n >= size) size = n + 1;
else return p;
free( p );
}
}
static struct strarray strarray_copy( struct strarray src )
{
struct strarray array;
array.count = src.count;
array.max = src.max;
array.str = xmalloc( array.max * sizeof(*array.str) );
memcpy( array.str, src.str, array.count * sizeof(*array.str) );
return array;
}
static void strarray_add_one( struct strarray *array, const char *str )
{
if (array->count == array->max)
{
array->max *= 2;
if (array->max < 16) array->max = 16;
array->str = xrealloc( array->str, array->max * sizeof(*array->str) );
}
array->str[array->count++] = str;
}
void strarray_add( struct strarray *array, ... )
{
va_list valist;
const char *str;
va_start( valist, array );
while ((str = va_arg( valist, const char *))) strarray_add_one( array, str );
va_end( valist );
}
void strarray_addv( struct strarray *array, char * const *argv )
{
while (*argv) strarray_add_one( array, *argv++ );
}
void strarray_addall( struct strarray *array, struct strarray args )
{
unsigned int i;
for (i = 0; i < args.count; i++) strarray_add_one( array, args.str[i] );
}
struct strarray strarray_fromstring( const char *str, const char *delim )
{
const char *tok;
struct strarray array = empty_strarray;
char *buf = xstrdup( str );
for (tok = strtok( buf, delim ); tok; tok = strtok( NULL, delim ))
strarray_add_one( &array, strdup( tok ));
free( buf );
return array;
}
void fatal_error( const char *msg, ... )
{
va_list valist;
va_start( valist, msg );
if (input_file_name)
{
fprintf( stderr, "%s:", input_file_name );
if (current_line)
fprintf( stderr, "%d:", current_line );
fputc( ' ', stderr );
}
else fprintf( stderr, "winebuild: " );
vfprintf( stderr, msg, valist );
va_end( valist );
exit(1);
}
void fatal_perror( const char *msg, ... )
{
va_list valist;
va_start( valist, msg );
if (input_file_name)
{
fprintf( stderr, "%s:", input_file_name );
if (current_line)
fprintf( stderr, "%d:", current_line );
fputc( ' ', stderr );
}
vfprintf( stderr, msg, valist );
perror( " " );
va_end( valist );
exit(1);
}
void error( const char *msg, ... )
{
va_list valist;
va_start( valist, msg );
if (input_file_name)
{
fprintf( stderr, "%s:", input_file_name );
if (current_line)
fprintf( stderr, "%d:", current_line );
fputc( ' ', stderr );
}
vfprintf( stderr, msg, valist );
va_end( valist );
nb_errors++;
}
void warning( const char *msg, ... )
{
va_list valist;
if (!display_warnings) return;
va_start( valist, msg );
if (input_file_name)
{
fprintf( stderr, "%s:", input_file_name );
if (current_line)
fprintf( stderr, "%d:", current_line );
fputc( ' ', stderr );
}
fprintf( stderr, "warning: " );
vfprintf( stderr, msg, valist );
va_end( valist );
}
int output( const char *format, ... )
{
int ret;
va_list valist;
va_start( valist, format );
ret = vfprintf( output_file, format, valist );
va_end( valist );
if (ret < 0) fatal_perror( "Output error" );
return ret;
}
void spawn( struct strarray args )
{
unsigned int i;
int status;
strarray_add_one( &args, NULL );
if (verbose)
for (i = 0; args.str[i]; i++)
fprintf( stderr, "%s%c", args.str[i], args.str[i+1] ? ' ' : '\n' );
if ((status = _spawnvp( _P_WAIT, args.str[0], args.str )))
{
if (status > 0) fatal_error( "%s failed with status %u\n", args.str[0], status );
else fatal_perror( "winebuild" );
exit( 1 );
}
}
/* find a build tool in the path, trying the various names */
struct strarray find_tool( const char *name, const char * const *names )
{
static char **dirs;
static unsigned int count, maxlen;
char *p, *file;
const char *alt_names[2];
unsigned int i, len;
struct stat st;
if (!dirs)
{
char *path;
/* split the path in directories */
if (!getenv( "PATH" )) fatal_error( "PATH not set, cannot find required tools\n" );
path = xstrdup( getenv( "PATH" ));
for (p = path, count = 2; *p; p++) if (*p == PATH_SEPARATOR) count++;
dirs = xmalloc( count * sizeof(*dirs) );
count = 0;
dirs[count++] = p = path;
while (*p)
{
while (*p && *p != PATH_SEPARATOR) p++;
if (!*p) break;
*p++ = 0;
dirs[count++] = p;
}
for (i = 0; i < count; i++) maxlen = max( maxlen, strlen(dirs[i])+2 );
}
if (!names)
{
alt_names[0] = name;
alt_names[1] = NULL;
names = alt_names;
}
while (*names)
{
len = strlen(*names) + sizeof(EXEEXT) + 1;
if (target_alias)
len += strlen(target_alias) + 1;
file = xmalloc( maxlen + len );
for (i = 0; i < count; i++)
{
strcpy( file, dirs[i] );
p = file + strlen(file);
if (p == file) *p++ = '.';
if (p[-1] != '/') *p++ = '/';
if (target_alias)
{
strcpy( p, target_alias );
p += strlen(p);
*p++ = '-';
}
strcpy( p, *names );
strcat( p, EXEEXT );
if (!stat( file, &st ) && S_ISREG(st.st_mode) && (st.st_mode & 0111))
{
struct strarray ret = empty_strarray;
strarray_add_one( &ret, file );
return ret;
}
}
free( file );
names++;
}
fatal_error( "cannot find the '%s' tool\n", name );
}
struct strarray get_as_command(void)
{
struct strarray args;
if (cc_command.count)
{
args = strarray_copy( cc_command );
strarray_add( &args, "-xassembler", "-c", NULL );
if (force_pointer_size)
strarray_add_one( &args, (force_pointer_size == 8) ? "-m64" : "-m32" );
if (cpu_option) strarray_add_one( &args, strmake("-mcpu=%s", cpu_option) );
if (arch_option) strarray_add_one( &args, strmake("-march=%s", arch_option) );
return args;
}
if (!as_command.count)
{
static const char * const commands[] = { "gas", "as", NULL };
as_command = find_tool( "as", commands );
}
args = strarray_copy( as_command );
if (force_pointer_size)
{
switch (target_platform)
{
case PLATFORM_APPLE:
strarray_add( &args, "-arch", (force_pointer_size == 8) ? "x86_64" : "i386", NULL );
break;
default:
switch(target_cpu)
{
case CPU_POWERPC:
strarray_add_one( &args, (force_pointer_size == 8) ? "-a64" : "-a32" );
break;
default:
strarray_add_one( &args, (force_pointer_size == 8) ? "--64" : "--32" );
break;
}
break;
}
}
if (cpu_option) strarray_add_one( &args, strmake("-mcpu=%s", cpu_option) );
return args;
}
struct strarray get_ld_command(void)
{
struct strarray args;
if (!ld_command.count)
{
static const char * const commands[] = { "ld", "gld", NULL };
ld_command = find_tool( "ld", commands );
}
args = strarray_copy( ld_command );
if (force_pointer_size)
{
switch (target_platform)
{
case PLATFORM_APPLE:
strarray_add( &args, "-arch", (force_pointer_size == 8) ? "x86_64" : "i386", NULL );
break;
case PLATFORM_FREEBSD:
strarray_add( &args, "-m", (force_pointer_size == 8) ? "elf_x86_64_fbsd" : "elf_i386_fbsd", NULL );
break;
default:
switch(target_cpu)
{
case CPU_POWERPC:
strarray_add( &args, "-m", (force_pointer_size == 8) ? "elf64ppc" : "elf32ppc", NULL );
break;
default:
strarray_add( &args, "-m", (force_pointer_size == 8) ? "elf_x86_64" : "elf_i386", NULL );
break;
}
break;
}
}
return args;
}
const char *get_nm_command(void)
{
if (!nm_command.count)
{
static const char * const commands[] = { "nm", "gnm", NULL };
nm_command = find_tool( "nm", commands );
}
if (nm_command.count > 1)
fatal_error( "multiple arguments in nm command not supported yet\n" );
return nm_command.str[0];
}
/* get a name for a temp file, automatically cleaned up on exit */
char *get_temp_file_name( const char *prefix, const char *suffix )
{
char *name;
const char *ext, *basename;
int fd;
if (!prefix || !prefix[0]) prefix = "winebuild";
if (!suffix) suffix = "";
if ((basename = strrchr( prefix, '/' ))) basename++;
else basename = prefix;
if (!(ext = strchr( basename, '.' ))) ext = prefix + strlen(prefix);
name = xmalloc( sizeof("/tmp/") + (ext - prefix) + sizeof(".XXXXXX") + strlen(suffix) );
memcpy( name, prefix, ext - prefix );
strcpy( name + (ext - prefix), ".XXXXXX" );
strcat( name, suffix );
if ((fd = mkstemps( name, strlen(suffix) )) == -1)
{
strcpy( name, "/tmp/" );
memcpy( name + 5, basename, ext - basename );
strcpy( name + 5 + (ext - basename), ".XXXXXX" );
strcat( name, suffix );
if ((fd = mkstemps( name, strlen(suffix) )) == -1)
fatal_error( "could not generate a temp file\n" );
}
close( fd );
strarray_add_one( &tmp_files, name );
return name;
}
/*******************************************************************
* buffer management
*
* Function for reading from/writing to a memory buffer.
*/
int byte_swapped = 0;
const char *input_buffer_filename;
const unsigned char *input_buffer;
size_t input_buffer_pos;
size_t input_buffer_size;
unsigned char *output_buffer;
size_t output_buffer_pos;
size_t output_buffer_size;
static void check_output_buffer_space( size_t size )
{
if (output_buffer_pos + size >= output_buffer_size)
{
output_buffer_size = max( output_buffer_size * 2, output_buffer_pos + size );
output_buffer = xrealloc( output_buffer, output_buffer_size );
}
}
void init_input_buffer( const char *file )
{
int fd;
struct stat st;
if ((fd = open( file, O_RDONLY | O_BINARY )) == -1) fatal_perror( "Cannot open %s", file );
if ((fstat( fd, &st ) == -1)) fatal_perror( "Cannot stat %s", file );
if (!st.st_size) fatal_error( "%s is an empty file\n", file );
#ifdef HAVE_MMAP
if ((input_buffer = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 )) == (void*)-1)
#endif
{
unsigned char *buffer = xmalloc( st.st_size );
if (read( fd, buffer, st.st_size ) != st.st_size) fatal_error( "Cannot read %s\n", file );
input_buffer = buffer;
}
close( fd );
input_buffer_filename = xstrdup( file );
input_buffer_size = st.st_size;
input_buffer_pos = 0;
byte_swapped = 0;
}
void init_output_buffer(void)
{
output_buffer_size = 1024;
output_buffer_pos = 0;
output_buffer = xmalloc( output_buffer_size );
}
void flush_output_buffer(void)
{
if (fwrite( output_buffer, 1, output_buffer_pos, output_file ) != output_buffer_pos)
fatal_error( "Error writing to %s\n", output_file_name );
free( output_buffer );
}
unsigned char get_byte(void)
{
if (input_buffer_pos >= input_buffer_size)
fatal_error( "%s is a truncated file\n", input_buffer_filename );
return input_buffer[input_buffer_pos++];
}
unsigned short get_word(void)
{
unsigned short ret;
if (input_buffer_pos + sizeof(ret) > input_buffer_size)
fatal_error( "%s is a truncated file\n", input_buffer_filename );
memcpy( &ret, input_buffer + input_buffer_pos, sizeof(ret) );
if (byte_swapped) ret = (ret << 8) | (ret >> 8);
input_buffer_pos += sizeof(ret);
return ret;
}
unsigned int get_dword(void)
{
unsigned int ret;
if (input_buffer_pos + sizeof(ret) > input_buffer_size)
fatal_error( "%s is a truncated file\n", input_buffer_filename );
memcpy( &ret, input_buffer + input_buffer_pos, sizeof(ret) );
if (byte_swapped)
ret = ((ret << 24) | ((ret << 8) & 0x00ff0000) | ((ret >> 8) & 0x0000ff00) | (ret >> 24));
input_buffer_pos += sizeof(ret);
return ret;
}
void put_data( const void *data, size_t size )
{
check_output_buffer_space( size );
memcpy( output_buffer + output_buffer_pos, data, size );
output_buffer_pos += size;
}
void put_byte( unsigned char val )
{
check_output_buffer_space( 1 );
output_buffer[output_buffer_pos++] = val;
}
void put_word( unsigned short val )
{
if (byte_swapped) val = (val << 8) | (val >> 8);
put_data( &val, sizeof(val) );
}
void put_dword( unsigned int val )
{
if (byte_swapped)
val = ((val << 24) | ((val << 8) & 0x00ff0000) | ((val >> 8) & 0x0000ff00) | (val >> 24));
put_data( &val, sizeof(val) );
}
void put_qword( unsigned int val )
{
if (byte_swapped)
{
put_dword( 0 );
put_dword( val );
}
else
{
put_dword( val );
put_dword( 0 );
}
}
/* pointer-sized word */
void put_pword( unsigned int val )
{
if (get_ptr_size() == 8) put_qword( val );
else put_dword( val );
}
void align_output( unsigned int align )
{
size_t size = align - (output_buffer_pos % align);
if (size == align) return;
check_output_buffer_space( size );
memset( output_buffer + output_buffer_pos, 0, size );
output_buffer_pos += size;
}
/* output a standard header for generated files */
void output_standard_file_header(void)
{
if (spec_file_name)
output( "/* File generated automatically from %s; do not edit! */\n", spec_file_name );
else
output( "/* File generated automatically; do not edit! */\n" );
output( "/* This file can be copied, modified and distributed without restriction. */\n\n" );
}
/* dump a byte stream into the assembly code */
void dump_bytes( const void *buffer, unsigned int size )
{
unsigned int i;
const unsigned char *ptr = buffer;
if (!size) return;
output( "\t.byte " );
for (i = 0; i < size - 1; i++, ptr++)
{
if ((i % 16) == 15) output( "0x%02x\n\t.byte ", *ptr );
else output( "0x%02x,", *ptr );
}
output( "0x%02x\n", *ptr );
}
/*******************************************************************
* open_input_file
*
* Open a file in the given srcdir and set the input_file_name global variable.
*/
FILE *open_input_file( const char *srcdir, const char *name )
{
char *fullname;
FILE *file = fopen( name, "r" );
if (!file && srcdir)
{
fullname = strmake( "%s/%s", srcdir, name );
file = fopen( fullname, "r" );
}
else fullname = xstrdup( name );
if (!file) fatal_error( "Cannot open file '%s'\n", fullname );
input_file_name = fullname;
current_line = 1;
return file;
}
/*******************************************************************
* close_input_file
*
* Close the current input file (must have been opened with open_input_file).
*/
void close_input_file( FILE *file )
{
fclose( file );
free( input_file_name );
input_file_name = NULL;
current_line = 0;
}
/*******************************************************************
* remove_stdcall_decoration
*
* Remove a possible @xx suffix from a function name.
* Return the numerical value of the suffix, or -1 if none.
*/
int remove_stdcall_decoration( char *name )
{
char *p, *end = strrchr( name, '@' );
if (!end || !end[1] || end == name) return -1;
if (target_cpu != CPU_x86) return -1;
/* make sure all the rest is digits */
for (p = end + 1; *p; p++) if (!isdigit(*p)) return -1;
*end = 0;
return atoi( end + 1 );
}
/*******************************************************************
* assemble_file
*
* Run a file through the assembler.
*/
void assemble_file( const char *src_file, const char *obj_file )
{
struct strarray args = get_as_command();
strarray_add( &args, "-o", obj_file, src_file, NULL );
spawn( args );
}
/*******************************************************************
* alloc_dll_spec
*
* Create a new dll spec file descriptor
*/
DLLSPEC *alloc_dll_spec(void)
{
DLLSPEC *spec;
spec = xmalloc( sizeof(*spec) );
memset( spec, 0, sizeof(*spec) );
spec->type = SPEC_WIN32;
spec->base = MAX_ORDINALS;
spec->characteristics = IMAGE_FILE_EXECUTABLE_IMAGE;
spec->subsystem = 0;
spec->subsystem_major = 4;
spec->subsystem_minor = 0;
if (get_ptr_size() > 4)
spec->characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE;
else
spec->characteristics |= IMAGE_FILE_32BIT_MACHINE;
spec->dll_characteristics = IMAGE_DLLCHARACTERISTICS_NX_COMPAT;
return spec;
}
/*******************************************************************
* free_dll_spec
*
* Free dll spec file descriptor
*/
void free_dll_spec( DLLSPEC *spec )
{
int i;
for (i = 0; i < spec->nb_entry_points; i++)
{
ORDDEF *odp = &spec->entry_points[i];
free( odp->name );
free( odp->export_name );
free( odp->link_name );
}
free( spec->file_name );
free( spec->dll_name );
free( spec->c_name );
free( spec->init_func );
free( spec->entry_points );
free( spec->names );
free( spec->ordinals );
free( spec->resources );
free( spec );
}
/*******************************************************************
* make_c_identifier
*
* Map a string to a valid C identifier.
*/
char *make_c_identifier( const char *str )
{
char *p, buffer[256];
for (p = buffer; *str && p < buffer+sizeof(buffer)-1; p++, str++)
{
if (isalnum(*str)) *p = *str;
else *p = '_';
}
*p = 0;
return xstrdup( buffer );
}
/*******************************************************************
* get_stub_name
*
* Generate an internal name for a stub entry point.
*/
const char *get_stub_name( const ORDDEF *odp, const DLLSPEC *spec )
{
static char *buffer;
free( buffer );
if (odp->name || odp->export_name)
{
char *p;
buffer = strmake( "__wine_stub_%s", odp->name ? odp->name : odp->export_name );
/* make sure name is a legal C identifier */
for (p = buffer; *p; p++) if (!isalnum(*p) && *p != '_') break;
if (!*p) return buffer;
free( buffer );
}
buffer = strmake( "__wine_stub_%s_%d", make_c_identifier(spec->file_name), odp->ordinal );
return buffer;
}
/* parse a cpu name and return the corresponding value */
int get_cpu_from_name( const char *name )
{
unsigned int i;
for (i = 0; i < sizeof(cpu_names)/sizeof(cpu_names[0]); i++)
if (!strcmp( cpu_names[i].name, name )) return cpu_names[i].cpu;
return -1;
}
/*****************************************************************
* Function: get_alignment
*
* Description:
* According to the info page for gas, the .align directive behaves
* differently on different systems. On some architectures, the
* argument of a .align directive is the number of bytes to pad to, so
* to align on an 8-byte boundary you'd say
* .align 8
* On other systems, the argument is "the number of low-order zero bits
* that the location counter must have after advancement." So to
* align on an 8-byte boundary you'd say
* .align 3
*
* The reason gas is written this way is that it's trying to mimic
* native assemblers for the various architectures it runs on. gas
* provides other directives that work consistently across
* architectures, but of course we want to work on all arches with or
* without gas. Hence this function.
*
*
* Parameters:
* align -- the number of bytes to align to. Must be a power of 2.
*/
unsigned int get_alignment(unsigned int align)
{
unsigned int n;
assert( !(align & (align - 1)) );
switch(target_cpu)
{
case CPU_x86:
case CPU_x86_64:
if (target_platform != PLATFORM_APPLE) return align;
/* fall through */
case CPU_POWERPC:
case CPU_ARM:
case CPU_ARM64:
n = 0;
while ((1u << n) != align) n++;
return n;
}
/* unreached */
assert(0);
return 0;
}
/* return the page size for the target CPU */
unsigned int get_page_size(void)
{
switch(target_cpu)
{
case CPU_x86:
case CPU_x86_64:
case CPU_POWERPC:
case CPU_ARM:
return 0x1000;
case CPU_ARM64:
return 0x10000;
}
/* unreached */
assert(0);
return 0;
}
/* return the size of a pointer on the target CPU */
unsigned int get_ptr_size(void)
{
switch(target_cpu)
{
case CPU_x86:
case CPU_POWERPC:
case CPU_ARM:
return 4;
case CPU_x86_64:
case CPU_ARM64:
return 8;
}
/* unreached */
assert(0);
return 0;
}
/* return the total size in bytes of the arguments on the stack */
unsigned int get_args_size( const ORDDEF *odp )
{
int i, size;
for (i = size = 0; i < odp->u.func.nb_args; i++)
{
switch (odp->u.func.args[i])
{
case ARG_INT64:
case ARG_DOUBLE:
size += 8;
break;
case ARG_INT128:
/* int128 is passed as pointer on x86_64 */
if (target_cpu != CPU_x86_64)
{
size += 16;
break;
}
/* fall through */
default:
size += get_ptr_size();
break;
}
}
return size;
}
static int get_function_argsize16(const ORDDEF *odp)
{
int i, argsize = 0;
for (i = 0; i < odp->u.func.nb_args; i++)
{
switch (odp->u.func.args[i])
{
case ARG_WORD:
case ARG_SWORD:
argsize += 2 + 2;
break;
case ARG_SEGPTR:
case ARG_SEGSTR:
case ARG_LONG:
case ARG_PTR:
case ARG_STR:
case ARG_WSTR:
case ARG_FLOAT:
case ARG_INT128:
argsize += 4;
break;
case ARG_INT64:
case ARG_DOUBLE:
argsize += 8;
break;
}
}
if (odp->flags & FLAG_REGISTER)
return argsize + 4;//ARG_PTR
return argsize;
}
const char *asm_name_stdcall16(const char *sym, ORDDEF *ord)
{
static char *buffer;
switch (target_platform)
{
case PLATFORM_APPLE:
case PLATFORM_WINDOWS:
if (sym[0] == '.' && sym[1] == 'L') return sym;
free(buffer);
if (ord->type == TYPE_VARARGS || strstr(sym, "__wine_stub") == sym)
{
buffer = strmake("_%s", sym);
}
else
{
buffer = strmake("_%s@%d", sym, get_function_argsize16(ord));
}
return buffer;
default:
return sym;
}
}
const char *asm_name_stdcall32(const char *sym, ORDDEF *ord)
{
static char *buffer;
switch (target_platform)
{
case PLATFORM_APPLE:
case PLATFORM_WINDOWS:
if (sym[0] == '.' && sym[1] == 'L') return sym;
free(buffer);
if (ord->type == TYPE_VARARGS || strstr(sym, "__wine_stub") == sym)
{
buffer = strmake("_%s", sym);
}
else
{
buffer = strmake("_%s@%d", sym, get_function_argsize16(ord));
}
return buffer;
default:
return sym;
}
}
/* return the assembly name for a C symbol */
const char *asm_name( const char *sym )
{
static char *buffer;
switch (target_platform)
{
case PLATFORM_APPLE:
case PLATFORM_WINDOWS:
if (sym[0] == '.' && sym[1] == 'L') return sym;
free( buffer );
buffer = strmake( "_%s", sym );
return buffer;
default:
return sym;
}
}
/* return an assembly function declaration for a C function name */
const char *func_declaration( const char *func )
{
static char *buffer;
switch (target_platform)
{
case PLATFORM_APPLE:
return "";
case PLATFORM_WINDOWS:
free( buffer );
buffer = strmake( ".def %s; .scl 2; .type 32; .endef", func );
break;
default:
free( buffer );
switch(target_cpu)
{
case CPU_ARM:
case CPU_ARM64:
buffer = strmake( ".type %s,%%function", func );
break;
default:
buffer = strmake( ".type %s,@function", func );
break;
}
break;
}
return buffer;
}
/* output a size declaration for an assembly function */
void output_function_size( const char *name )
{
switch (target_platform)
{
case PLATFORM_APPLE:
case PLATFORM_WINDOWS:
break;
default:
output( "\t.size %s, .-%s\n", name, name );
break;
}
}
/* output a .cfi directive */
void output_cfi( const char *format, ... )
{
va_list valist;
if (!unwind_tables) return;
va_start( valist, format );
fputc( '\t', output_file );
vfprintf( output_file, format, valist );
fputc( '\n', output_file );
va_end( valist );
}
/* output the GNU note for non-exec stack */
void output_gnu_stack_note(void)
{
switch (target_platform)
{
case PLATFORM_WINDOWS:
case PLATFORM_APPLE:
break;
default:
switch(target_cpu)
{
case CPU_ARM:
case CPU_ARM64:
output( "\t.section .note.GNU-stack,\"\",%%progbits\n" );
break;
default:
output( "\t.section .note.GNU-stack,\"\",@progbits\n" );
break;
}
break;
}
}
/* return a global symbol declaration for an assembly symbol */
const char *asm_globl( const char *func )
{
static char *buffer;
free( buffer );
switch (target_platform)
{
case PLATFORM_APPLE:
buffer = strmake( "\t.globl _%s\n\t.private_extern _%s\n_%s:", func, func, func );
break;
case PLATFORM_WINDOWS:
buffer = strmake( "\t.globl _%s\n_%s:", func, func );
break;
default:
buffer = strmake( "\t.globl %s\n\t.hidden %s\n%s:", func, func, func );
break;
}
return buffer;
}
const char *get_asm_ptr_keyword(void)
{
switch(get_ptr_size())
{
case 4: return ".long";
case 8: return ".quad";
}
assert(0);
return NULL;
}
const char *get_asm_string_keyword(void)
{
switch (target_platform)
{
case PLATFORM_APPLE:
return ".asciz";
default:
return ".string";
}
}
const char *get_asm_rodata_section(void)
{
switch (target_platform)
{
case PLATFORM_APPLE: return ".const";
default: return ".section .rodata";
}
}
const char *get_asm_string_section(void)
{
switch (target_platform)
{
case PLATFORM_APPLE: return ".cstring";
default: return ".section .rodata";
}
}
================================================
FILE: convspec/ver.h
================================================
unsigned char ver_res[] = {
0xff, 0x10, 0x00, 0xff, 0x01, 0x00, 0x30, 0x00, 0xc0, 0x01, 0x00, 0x00,
0xc0, 0x01, 0x34, 0x00, 0x56, 0x53, 0x5f, 0x56, 0x45, 0x52, 0x53, 0x49,
0x4f, 0x4e, 0x5f, 0x49, 0x4e, 0x46, 0x4f, 0x00, 0xbd, 0x04, 0xef, 0xfe,
0x00, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x03, 0x00, 0xe7, 0x03, 0x00, 0x00,
0x0a, 0x00, 0x03, 0x00, 0xe7, 0x03, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c, 0xc6, 0xc0, 0x5b,
0x54, 0x01, 0x00, 0x00, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x46, 0x69,
0x6c, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00,
0x30, 0x34, 0x31, 0x31, 0x30, 0x33, 0x41, 0x34, 0x00, 0x00, 0x00, 0x00,
0x24, 0x00, 0x13, 0x00, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x4e,
0x61, 0x6d, 0x65, 0x00, 0x44, 0x75, 0x6d, 0x6d, 0x79, 0x20, 0x43, 0x6f,
0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00,
0x20, 0x00, 0x0a, 0x00, 0x46, 0x69, 0x6c, 0x65, 0x44, 0x65, 0x73, 0x63,
0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x44, 0x75, 0x6d, 0x6d,
0x79, 0x20, 0x44, 0x4c, 0x4c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x06, 0x00,
0x46, 0x69, 0x6c, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00,
0x33, 0x2e, 0x31, 0x30, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x06, 0x00,
0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x4e, 0x61, 0x6d, 0x65,
0x00, 0x00, 0x00, 0x00, 0x44, 0x55, 0x4d, 0x4d, 0x59, 0x00, 0x00, 0x00,
0x3c, 0x00, 0x25, 0x00, 0x4c, 0x65, 0x67, 0x61, 0x6c, 0x43, 0x6f, 0x70,
0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x00, 0x00, 0x43, 0x6f, 0x70, 0x79,
0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x28, 0x43, 0x29, 0x20, 0x44, 0x75,
0x6d, 0x6d, 0x79, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x2e, 0x20, 0x31, 0x39,
0x39, 0x31, 0x2d, 0x31, 0x39, 0x39, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00,
0x28, 0x00, 0x0d, 0x00, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c,
0x46, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x00, 0x00, 0x00, 0x00,
0x44, 0x55, 0x4d, 0x4d, 0x59, 0x44, 0x4c, 0x4c, 0x2e, 0x44, 0x4c, 0x4c,
0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x26, 0x00, 0x50, 0x72, 0x6f, 0x64,
0x75, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x00, 0x44, 0x75, 0x6d, 0x6d,
0x79, 0x20, 0x28, 0x52, 0x29, 0x20, 0x44, 0x75, 0x6d, 0x6d, 0x79, 0x28,
0x54, 0x4d, 0x29, 0x20, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6e,
0x67, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x00, 0x00, 0x00, 0x00,
0x1c, 0x00, 0x06, 0x00, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x56,
0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x33, 0x2e, 0x31, 0x30,
0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x56, 0x61, 0x72, 0x46,
0x69, 0x6c, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x00, 0x14, 0x00, 0x04, 0x00,
0x54, 0x72, 0x61, 0x6e, 0x73, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00,
0x11, 0x04, 0xa4, 0x03
};
unsigned int ver_res_len = 460;
================================================
FILE: ctl3d/CMakeLists.txt
================================================
file(GLOB SOURCE *.c *.cpp *.rc)
add_library(ctl3d SHARED ${SOURCE} ${CMAKE_CURRENT_BINARY_DIR}/ctl3d.def ctl3d.dll16.obj)
include_directories(../wine)
add_definitions(-D_X86_ -D__WINESRC__ -D__i386__ -DHAVE_STRNCASECMP -DHAVE__STRNICMP -D_WINTERNL_ -DNtCurrentTeb=NtCurrentTeb__ -DDECLSPEC_HIDDEN= -Dstrncasecmp=_strnicmp)
spec_build(ctl3d.dll16 ctl3d)
target_link_libraries(ctl3d libwine winecrt0 krnl386 ctl3dv2)
set_target_properties(ctl3d PROPERTIES SUFFIX ".dll16")
================================================
FILE: ctl3d/Makefile.in
================================================
MODULE = ctl3d.dll16
IMPORTS = user32
EXTRADLLFLAGS = -m16 -Wb,--main-module,ctl3d32.dll
C_SRCS = ctl3d.c
================================================
FILE: ctl3d/ctl3d.c
================================================
/*
* 16-bit CTL3D and CTL3DV2 API stubs.
*
* Copyright (c) 2003 Dmitry Timoshkov
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "wine/winbase16.h"
#include "wine/winuser16.h"
#include
================================================
FILE: ctl3d/ctl3d.def
================================================
; File generated automatically from ..\ctl3d\ctl3d.dll16.spec; do not edit!
LIBRARY ctl3d.dll16
EXPORTS
_wine_spec_dos_header @1 DATA
================================================
FILE: ctl3d/ctl3d.dll16.spec
================================================
1 pascal -ret16 Ctl3dGetVer() Ctl3dGetVer16
2 pascal -ret16 Ctl3dSubclassDlg(word word) Ctl3dSubclassDlg16
3 pascal -ret16 Ctl3dSubclassCtl(word) Ctl3dSubclassCtl16
4 pascal -ret16 Ctl3dCtlColor(word long) Ctl3dCtlColor16
5 pascal -ret16 Ctl3dEnabled() Ctl3dEnabled16
6 pascal -ret16 Ctl3dColorChange() Ctl3dColorChange16
7 pascal BtnWndProc3d(word word word long) BtnWndProc3d16
8 pascal EditWndProc3d(word word word long) EditWndProc3d16
9 pascal ListWndProc3d(word word word long) ListWndProc3d16
10 pascal ComboWndProc3d(word word word long) ComboWndProc3d16
11 pascal StaticWndProc3d(word word word long) StaticWndProc3d16
12 pascal -ret16 Ctl3dRegister(word) Ctl3dRegister16
13 pascal -ret16 Ctl3dUnregister(word) Ctl3dUnregister16
16 pascal -ret16 Ctl3dAutoSubclass(word) Ctl3dAutoSubclass16
17 pascal Ctl3dDlgProc(word word word long) Ctl3dDlgProc16
18 pascal -ret16 Ctl3dCtlColorEx(word word long) Ctl3dCtlColorEx16
19 pascal -ret16 Ctl3dSetStyle(word long word) Ctl3dSetStyle16
20 pascal Ctl3dDlgFramePaint(word word word long) Ctl3dDlgFramePaint16
21 pascal -ret16 Ctl3dSubclassDlgEx(word long) Ctl3dSubclassDlgEx16
22 pascal -ret16 Ctl3dWinIniChange() Ctl3dWinIniChange16
23 pascal -ret16 Ctl3dIsAutoSubclass() Ctl3dIsAutoSubclass16
24 pascal -ret16 Ctl3dUnAutoSubclass() Ctl3dUnAutoSubclass16
25 pascal -ret16 Ctl3dSubclassCtlEx(word word) Ctl3dSubclassCtlEx16
26 pascal -ret16 Ctl3dUnsubclassCtl(word) Ctl3dUnsubclassCtl16
27 pascal -ret16 Ctl3dAutoSubclassEx(word long) Ctl3dAutoSubclassEx16
================================================
FILE: ctl3d/ctl3d.vcxproj
================================================
Debug
Win32
Release
Win32
Win32Proj
ctl3d
{B1A8AC7F-6B94-4AD0-8471-2C44F3014B5A}
10.0.17134.0
DynamicLibrary
true
v141
Unicode
DynamicLibrary
false
v141
true
Unicode
true
.dll16
false
Release
.dll16
Level3
Disabled
WIN32;_DEBUG;_WINDOWS;_USRDLL;_X86_;__WINESRC__;__i386__;USE_COMPILER_EXCEPTIONS;HAVE_STRNCASECMP;HAVE__STRNICMP;_WINTERNL_;NtCurrentTeb=NtCurrentTeb__;inline=__inline;%(PreprocessorDefinitions)
../wine
Windows
true
$(OutDir)ctl3dv2.lib;$(OutDir)winecrt0.lib;$(OutDir)libwine.lib;$(OutDir)krnl386.lib;
user32.lib
true
ctl3d.def
Level3
MaxSpeed
true
true
WIN32;NDEBUG;_WINDOWS;_USRDLL;_X86_;__WINESRC__;__i386__;USE_COMPILER_EXCEPTIONS;HAVE_STRNCASECMP;HAVE__STRNICMP;_WINTERNL_;NtCurrentTeb=NtCurrentTeb__;inline=__inline;DECLSPEC_HIDDEN=;%(PreprocessorDefinitions)
../wine
Windows
true
true
true
false
ctl3d.def
$(OutDir)ctl3dv2.lib;$(OutDir)winecrt0.lib;$(OutDir)libwine.lib;$(OutDir)krnl386.lib;
user32.lib
Document
"$(OutDir)convspec" "%(Filename).spec" CTL3D > "%(Filename).asm" && "$(AsmPath)as" --32 -o "%(Filename).obj" "%(Filename).asm"
%(Filename).obj
"$(OutDir)convspec" "%(Filename).spec" CTL3D > "%(Filename).asm" && "$(AsmPath)as" --32 -o "%(Filename).obj" "%(Filename).asm"
%(Filename).obj
================================================
FILE: ctl3dv2/CMakeLists.txt
================================================
file(GLOB SOURCE *.c *.cpp *.rc)
add_library(ctl3dv2 SHARED ${SOURCE} ${CMAKE_CURRENT_BINARY_DIR}/ctl3dv2.def ctl3dv2.dll16.obj)
include_directories(../wine)
add_definitions(-D_X86_ -D__WINESRC__ -D__i386__ -DHAVE_STRNCASECMP -DHAVE__STRNICMP -D_WINTERNL_ -DNtCurrentTeb=NtCurrentTeb__ -DDECLSPEC_HIDDEN= -Dstrncasecmp=_strnicmp)
spec_build(ctl3dv2.dll16 ctl3dv2)
target_link_libraries(ctl3dv2 libwine winecrt0 krnl386 user)
set_target_properties(ctl3dv2 PROPERTIES SUFFIX ".dll16")
================================================
FILE: ctl3dv2/Makefile.in
================================================
MODULE = ctl3dv2.dll16
IMPORTS = user32
EXTRADLLFLAGS = -m16 -Wb,--main-module,ctl3d32.dll
C_SRCS = ctl3d.c
================================================
FILE: ctl3dv2/ctl3d.c
================================================
/*
* 16-bit CTL3D and CTL3DV2 API stubs.
*
* Copyright (c) 2003 Dmitry Timoshkov
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "wine/winbase16.h"
#include "wine/winuser16.h"
#include
/* Ctl3dSubclassDlg */
#define CTL3D_BUTTONS 0x0001
#define CTL3D_LISTBOXES 0x0002
#define CTL3D_EDITS 0x0004
#define CTL3D_COMBOS 0x0008
#define CTL3D_STATICTEXTS 0x0010
#define CTL3D_STATICFRAMES 0x0020
#define CTL3D_ALL 0xffff
/* resource */
#define CTL3D_3DCHECK 26567
/* Ctl3dSubclassDlgEx */
#define CTL3D_NODLGWINDOW 0x00010000
/* WM_DLGBORDER result */
#define WM_DLGBORDER (WM_USER + 3567)
#define CTL3D_NOBORDER 0
#define CTL3D_BORDER 1
/* WM_DLGSUBCLASS result */
#define WM_DLGSUBCLASS (WM_USER + 3568)
#define CTL3D_NOSUBCLASS 0
#define CTL3D_SUBCLASS 1
#define CTLMSGOFFSET 3569
#define CTL3D_CTLCOLOR (WM_USER + CTLMSGOFFSET)
struct autosubclass
{
HHOOK hook;
DWORD type;
};
static DWORD autosubclass_index = NULL;
static WNDPROC listbox_proc;
static WNDPROC button_proc;
static WNDPROC static_proc;
static WNDPROC combo_proc;
static WNDPROC edit_proc;
static WNDPROC dialog_proc;
LRESULT WINAPI __wine_call_wndproc(HWND16 hwnd, UINT16 msg, WPARAM16 wParam, LPARAM lParam, WNDPROC proc);
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD reason, LPVOID lpvReserved)
{
WNDCLASSA cls;
switch (reason)
{
case DLL_PROCESS_ATTACH:
if (GetClassInfoA(hinstDLL, "LISTBOX", &cls))
listbox_proc = cls.lpfnWndProc;
if (GetClassInfoA(hinstDLL, "BUTTON", &cls))
button_proc = cls.lpfnWndProc;
if (GetClassInfoA(hinstDLL, "STATIC", &cls))
static_proc = cls.lpfnWndProc;
if (GetClassInfoA(hinstDLL, "COMBOBOX", &cls))
combo_proc = cls.lpfnWndProc;
if (GetClassInfoA(hinstDLL, "EDIT", &cls))
edit_proc = cls.lpfnWndProc;
if (GetClassInfoA(hinstDLL, "#32770", &cls))
dialog_proc = cls.lpfnWndProc;
autosubclass_index = TlsAlloc();
break;
case DLL_PROCESS_DETACH:
TlsFree(autosubclass_index);
break;
case DLL_THREAD_DETACH:
{
struct autosubclass *asc = TlsGetValue(autosubclass_index);
if (asc)
{
UnhookWindowsHookEx(asc->hook);
HeapFree(GetProcessHeap(), 0, asc);
}
break;
}
}
return TRUE;
}
static void ctl3d_static(DWORD type, DWORD *style, DWORD *exstyle)
{
switch (*style & 0xf)
{
case SS_BLACKFRAME:
if (type & CTL3D_STATICFRAMES)
{
*style &= ~SS_BLACKFRAME;
*exstyle |= WS_EX_CLIENTEDGE;
}
break;
case SS_GRAYFRAME:
if (type & CTL3D_STATICFRAMES)
{
*style &= ~SS_GRAYFRAME;
*style |= SS_ETCHEDFRAME;
}
break;
case SS_WHITEFRAME:
if (type & CTL3D_STATICFRAMES)
{
*style &= ~SS_WHITEFRAME;
*exstyle |= WS_EX_DLGMODALFRAME;
}
break;
case SS_BLACKRECT:
if (type & CTL3D_STATICTEXTS)
{
*style &= ~SS_BLACKRECT;
*exstyle |= WS_EX_CLIENTEDGE;
}
break;
case SS_GRAYRECT:
if (type & CTL3D_STATICTEXTS)
{
*style &= ~SS_GRAYRECT;
*style |= SS_ETCHEDFRAME;
}
break;
case SS_WHITERECT:
if (type & CTL3D_STATICTEXTS)
{
*style &= ~SS_WHITERECT;
*exstyle |= WS_EX_DLGMODALFRAME;
}
break;
}
}
static LRESULT CALLBACK subclassproc(INT code, WPARAM wp, LPARAM lp)
{
struct autosubclass *asc = TlsGetValue(autosubclass_index);
if (code == HCBT_CREATEWND)
{
CBT_CREATEWNDA *cbt_cw = (CBT_CREATEWNDA *)lp;
char *cls = cbt_cw->lpcs->lpszClass;
if ((DWORD)cls & 0xffff0000)
{
if ((asc->type & CTL3D_EDITS) && (!strcmpi(cls, "EDIT")) || ((asc->type & CTL3D_LISTBOXES) && !strcmpi(cls, "LISTBOX")))
{
DWORD exstyle = cbt_cw->lpcs->dwExStyle | WS_EX_CLIENTEDGE;
SetWindowLongA(wp, GWL_EXSTYLE, exstyle);
}
if (!strcmpi(cls, "STATIC"))
{
DWORD style = cbt_cw->lpcs->style;
DWORD exstyle = cbt_cw->lpcs->dwExStyle;
ctl3d_static(asc->type, &style, &exstyle);
cbt_cw->lpcs->style = style;
cbt_cw->lpcs->dwExStyle = exstyle;
SetWindowLongA(wp, GWL_STYLE, style);
SetWindowLongA(wp, GWL_EXSTYLE, exstyle);
}
}
}
return CallNextHookEx(asc->hook, code, wp, lp);
}
/***********************************************************************
* Ctl3dAutoSubclassEx (CTL3DV2.27)
*/
BOOL16 WINAPI Ctl3dAutoSubclassEx16(HINSTANCE16 hInst, DWORD type)
{
struct autosubclass *asc = TlsGetValue(autosubclass_index);
if (!asc)
{
asc = (struct autosubclass *)HeapAlloc(GetProcessHeap(), 0, sizeof(struct autosubclass));
asc->hook = SetWindowsHookExA(WH_CBT, subclassproc, NULL, GetCurrentThreadId());
TlsSetValue(autosubclass_index, asc);
}
asc->type = type;
return TRUE;
}
/***********************************************************************
* Ctl3dAutoSubclass (CTL3DV2.16)
*/
BOOL16 WINAPI Ctl3dAutoSubclass16(HINSTANCE16 hInst)
{
Ctl3dAutoSubclassEx16(hInst, CTL3D_ALL);
return TRUE;
}
/***********************************************************************
* Ctl3dColorChange (CTL3DV2.6)
*/
BOOL16 WINAPI Ctl3dColorChange16(void)
{
return TRUE;
}
/***********************************************************************
* Ctl3dCtlColor (CTL3DV2.4)
*/
HBRUSH WINAPI Ctl3dCtlColor16(HDC16 hdc, LONG hwnd)
{
return 0;
}
/***********************************************************************
* Ctl3dCtlColorEx (CTL3DV2.18)
*/
HBRUSH WINAPI Ctl3dCtlColorEx16(UINT16 msg, WPARAM16 wParam, LPARAM lParam)
{
return 0;
}
/***********************************************************************
* Ctl3dDlgFramePaint (CTL3DV2.20)
*/
LRESULT WINAPI Ctl3dDlgFramePaint16(HWND16 hwnd, UINT16 msg, WPARAM16 wParam, LPARAM lParam)
{
return __wine_call_wndproc(hwnd, msg, wParam, lParam, DefWindowProcA);
}
/***********************************************************************
* Ctl3dEnabled (CTL3DV2.5)
*/
BOOL16 WINAPI Ctl3dEnabled16(void)
{
return FALSE;
}
/***********************************************************************
* Ctl3dGetVer (CTL3DV2.1)
*/
WORD WINAPI Ctl3dGetVer16(void)
{
return MAKEWORD(31,2);
}
/***********************************************************************
* Ctl3dIsAutoSubclass (CTL3DV2.23)
*/
BOOL16 WINAPI Ctl3dIsAutoSubclass16(void)
{
return TlsGetValue(autosubclass_index) ? TRUE : FALSE;
}
/***********************************************************************
* Ctl3dRegister (CTL3DV2.12)
*/
BOOL16 WINAPI Ctl3dRegister16(HINSTANCE16 hInst)
{
return TRUE;
}
/***********************************************************************
* Ctl3dSubclassCtlEx (CTL3DV2.25)
*/
BOOL16 WINAPI Ctl3dSubclassCtlEx16(HWND16 hwnd, INT16 type)
{
HWND hwnd32 = HWND_32(hwnd);
char buf[200] = { 0 };
GetClassNameA(hwnd32, buf, sizeof(buf));
if ((type & CTL3D_EDITS) && (!strcmpi(buf, "EDIT")) || ((type & CTL3D_LISTBOXES) && !strcmpi(buf, "LISTBOX")))
{
SetWindowLongA(hwnd32, GWL_EXSTYLE, GetWindowLongA(hwnd32, GWL_EXSTYLE) | WS_EX_CLIENTEDGE);
SetWindowPos(hwnd32, 0, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_DRAWFRAME);
}
else if (!strcmpi(buf, "STATIC"))
{
DWORD style = GetWindowLongA(hwnd32, GWL_STYLE);
DWORD exstyle = GetWindowLongA(hwnd32, GWL_EXSTYLE);
ctl3d_static(type, &style, &exstyle);
SetWindowLongA(hwnd32, GWL_STYLE, style);
SetWindowLongA(hwnd32, GWL_EXSTYLE, exstyle);
}
return TRUE;
}
/***********************************************************************
* Ctl3dSubclassCtl (CTL3DV2.3)
*/
BOOL16 WINAPI Ctl3dSubclassCtl16(HWND16 hwnd)
{
return Ctl3dSubclassCtlEx16(hwnd, CTL3D_ALL);
}
struct ctl3d_enumproc
{
HWND parent;
DWORD types;
};
BOOL CALLBACK ctl3d_enumproc(HWND hwnd, LPARAM lparam)
{
struct ctl3d_enumproc *data = (struct ctl3d_enumproc*)lparam;
if (GetParent(hwnd) != data->parent)
return TRUE;
Ctl3dSubclassCtlEx16(HWND_16(hwnd), data->types);
}
/***********************************************************************
* Ctl3dSubclassDlgEx (CTL3DV2.21)
*/
BOOL16 WINAPI Ctl3dSubclassDlgEx16(HWND16 hwnd, DWORD types)
{
struct ctl3d_enumproc data = { 0 };
data.parent = HWND_32(hwnd);
data.types = types;
EnumChildWindows(data.parent, ctl3d_enumproc, (LPARAM)&data);
return FALSE;
}
/***********************************************************************
* Ctl3dSubclassDlg (CTL3DV2.2)
*/
BOOL16 WINAPI Ctl3dSubclassDlg16(HWND16 hwnd, WORD types)
{
return Ctl3dSubclassDlgEx16(hwnd, types);
}
/***********************************************************************
* Ctl3dUnAutoSubclass (CTL3DV2.24)
*/
BOOL16 WINAPI Ctl3dUnAutoSubclass16(void)
{
struct autosubclass *asc = TlsGetValue(autosubclass_index);
if (asc)
{
UnhookWindowsHookEx(asc->hook);
HeapFree(GetProcessHeap(), 0, asc);
TlsSetValue(autosubclass_index, 0);
}
return FALSE;
}
/***********************************************************************
* Ctl3dUnregister (CTL3DV2.13)
*/
BOOL16 WINAPI Ctl3dUnregister16(HINSTANCE16 hInst)
{
Ctl3dUnAutoSubclass16();
return TRUE;
}
/***********************************************************************
* Ctl3dUnsubclassCtl (CTL3DV2.26)
*/
BOOL16 WINAPI Ctl3dUnsubclassCtl16(HWND16 hwnd)
{
return FALSE;
}
/***********************************************************************
* Ctl3dWinIniChange (CTL3DV2.22)
*/
void WINAPI Ctl3dWinIniChange16(void)
{
}
/***********************************************************************
* ComboWndProc3d (CTL3DV2.10)
*/
LRESULT WINAPI ComboWndProc3d16(HWND16 hwnd, UINT16 msg,WPARAM16 wparam, LPARAM lparam)
{
return __wine_call_wndproc(hwnd, msg, wparam, lparam, combo_proc);
}
/***********************************************************************
* BtnWndProc3d (CTL3DV2.7)
*/
LRESULT WINAPI BtnWndProc3d16(HWND16 hwnd, UINT16 msg, WPARAM16 wparam, LPARAM lparam)
{
return __wine_call_wndproc(hwnd, msg, wparam, lparam, button_proc);
}
/***********************************************************************
* StaticWndProc3d (CTL3DV2.11)
*/
LRESULT WINAPI StaticWndProc3d16(HWND16 hwnd, UINT16 msg, WPARAM16 wparam, LPARAM lparam)
{
return __wine_call_wndproc(hwnd, msg, wparam, lparam, static_proc);
}
/***********************************************************************
* EditWndProc3d (CTL3DV2.8)
*/
LRESULT WINAPI EditWndProc3d16(HWND16 hwnd, UINT16 msg, WPARAM16 wparam, LPARAM lparam)
{
return __wine_call_wndproc(hwnd, msg, wparam, lparam, edit_proc);
}
/***********************************************************************
* ListWndProc3d (CTL3DV2.9)
*/
LRESULT WINAPI ListWndProc3d16(HWND16 hwnd, UINT16 msg, WPARAM16 wparam, LPARAM lparam)
{
return __wine_call_wndproc(hwnd, msg, wparam, lparam, listbox_proc);
}
/***********************************************************************
* Ctl3dDlgProc (CTL3DV2.17)
*/
LRESULT WINAPI Ctl3dDlgProc16(HWND16 hwnd, UINT16 msg, WPARAM16 wparam, LPARAM lparam)
{
return __wine_call_wndproc(hwnd, msg, wparam, lparam, dialog_proc);
}
WORD WINAPI Ctl3dSetStyle16(WORD a1, SEGPTR a2, WORD a3)
{
return 0;
}
================================================
FILE: ctl3dv2/ctl3dv2.def
================================================
; File generated automatically from ..\ctl3dv2\ctl3dv2.dll16.spec; do not edit!
LIBRARY ctl3dv2.dll16
EXPORTS
_wine_spec_dos_header @1 DATA
Ctl3dGetVer16
Ctl3dSubclassDlg16
Ctl3dSubclassCtl16
Ctl3dCtlColor16
Ctl3dEnabled16
Ctl3dColorChange16
BtnWndProc3d16
EditWndProc3d16
ListWndProc3d16
ComboWndProc3d16
StaticWndProc3d16
Ctl3dRegister16
Ctl3dUnregister16
Ctl3dAutoSubclass16
Ctl3dDlgProc16
Ctl3dCtlColorEx16
Ctl3dSetStyle16
Ctl3dDlgFramePaint16
Ctl3dSubclassDlgEx16
Ctl3dWinIniChange16
Ctl3dIsAutoSubclass16
Ctl3dUnAutoSubclass16
Ctl3dSubclassCtlEx16
Ctl3dUnsubclassCtl16
Ctl3dAutoSubclassEx16
================================================
FILE: ctl3dv2/ctl3dv2.dll16.spec
================================================
1 pascal -ret16 Ctl3dGetVer() Ctl3dGetVer16
2 pascal -ret16 Ctl3dSubclassDlg(word word) Ctl3dSubclassDlg16
3 pascal -ret16 Ctl3dSubclassCtl(word) Ctl3dSubclassCtl16
4 pascal -ret16 Ctl3dCtlColor(word long) Ctl3dCtlColor16
5 pascal -ret16 Ctl3dEnabled() Ctl3dEnabled16
6 pascal -ret16 Ctl3dColorChange() Ctl3dColorChange16
7 pascal BtnWndProc3d(word word word long) BtnWndProc3d16
8 pascal EditWndProc3d(word word word long) EditWndProc3d16
9 pascal ListWndProc3d(word word word long) ListWndProc3d16
10 pascal ComboWndProc3d(word word word long) ComboWndProc3d16
11 pascal StaticWndProc3d(word word word long) StaticWndProc3d16
12 pascal -ret16 Ctl3dRegister(word) Ctl3dRegister16
13 pascal -ret16 Ctl3dUnregister(word) Ctl3dUnregister16
16 pascal -ret16 Ctl3dAutoSubclass(word) Ctl3dAutoSubclass16
17 pascal Ctl3dDlgProc(word word word long) Ctl3dDlgProc16
18 pascal -ret16 Ctl3dCtlColorEx(word word long) Ctl3dCtlColorEx16
19 pascal -ret16 Ctl3dSetStyle(word long word) Ctl3dSetStyle16
20 pascal Ctl3dDlgFramePaint(word word word long) Ctl3dDlgFramePaint16
21 pascal -ret16 Ctl3dSubclassDlgEx(word long) Ctl3dSubclassDlgEx16
22 pascal -ret16 Ctl3dWinIniChange() Ctl3dWinIniChange16
23 pascal -ret16 Ctl3dIsAutoSubclass() Ctl3dIsAutoSubclass16
24 pascal -ret16 Ctl3dUnAutoSubclass() Ctl3dUnAutoSubclass16
25 pascal -ret16 Ctl3dSubclassCtlEx(word word) Ctl3dSubclassCtlEx16
26 pascal -ret16 Ctl3dUnsubclassCtl(word) Ctl3dUnsubclassCtl16
27 pascal -ret16 Ctl3dAutoSubclassEx(word long) Ctl3dAutoSubclassEx16
@ stdcall -arch=win32 Ctl3dGetVer16()
@ stdcall -arch=win32 Ctl3dSubclassDlg16(long long)
@ stdcall -arch=win32 Ctl3dSubclassCtl16(long)
@ stdcall -arch=win32 Ctl3dCtlColor16(long long)
@ stdcall -arch=win32 Ctl3dEnabled16()
@ stdcall -arch=win32 Ctl3dColorChange16()
@ stdcall -arch=win32 BtnWndProc3d16(long long long long)
@ stdcall -arch=win32 EditWndProc3d16(long long long long)
@ stdcall -arch=win32 ListWndProc3d16(long long long long)
@ stdcall -arch=win32 ComboWndProc3d16(long long long long)
@ stdcall -arch=win32 StaticWndProc3d16(long long long long)
@ stdcall -arch=win32 Ctl3dRegister16(long)
@ stdcall -arch=win32 Ctl3dUnregister16(long)
@ stdcall -arch=win32 Ctl3dAutoSubclass16(long)
@ stdcall -arch=win32 Ctl3dDlgProc16(long long long long)
@ stdcall -arch=win32 Ctl3dCtlColorEx16(long long long)
@ stdcall -arch=win32 Ctl3dSetStyle16(long long long)
@ stdcall -arch=win32 Ctl3dDlgFramePaint16(long long long long)
@ stdcall -arch=win32 Ctl3dSubclassDlgEx16(long long)
@ stdcall -arch=win32 Ctl3dWinIniChange16()
@ stdcall -arch=win32 Ctl3dIsAutoSubclass16()
@ stdcall -arch=win32 Ctl3dUnAutoSubclass16()
@ stdcall -arch=win32 Ctl3dSubclassCtlEx16(long long)
@ stdcall -arch=win32 Ctl3dUnsubclassCtl16(long)
@ stdcall -arch=win32 Ctl3dAutoSubclassEx16(long long)
================================================
FILE: ctl3dv2/ctl3dv2.vcxproj
================================================
Debug
Win32
Release
Win32
Win32Proj
ctl3dv2
{7F73550E-724D-4F7A-B192-35A764AC24D6}
10.0.17134.0
DynamicLibrary
true
v141
Unicode
DynamicLibrary
false
v141
true
Unicode
true
.dll16
false
Release
.dll16
Level3
Disabled
WIN32;_DEBUG;_WINDOWS;_USRDLL;_X86_;__WINESRC__;__i386__;USE_COMPILER_EXCEPTIONS;HAVE_STRNCASECMP;HAVE__STRNICMP;_WINTERNL_;NtCurrentTeb=NtCurrentTeb__;inline=__inline;%(PreprocessorDefinitions)
../wine
Windows
true
$(OutDir)user.lib;$(OutDir)winecrt0.lib;$(OutDir)libwine.lib;$(OutDir)krnl386.lib;
user32.lib
true
ctl3dv2.def
Level3
MaxSpeed
true
true
WIN32;NDEBUG;_WINDOWS;_USRDLL;_X86_;__WINESRC__;__i386__;USE_COMPILER_EXCEPTIONS;HAVE_STRNCASECMP;HAVE__STRNICMP;_WINTERNL_;NtCurrentTeb=NtCurrentTeb__;inline=__inline;DECLSPEC_HIDDEN=;%(PreprocessorDefinitions)
../wine
Windows
true
true
true
false
ctl3dv2.def
$(OutDir)user.lib;$(OutDir)winecrt0.lib;$(OutDir)libwine.lib;$(OutDir)krnl386.lib;
user32.lib
Document
"$(OutDir)convspec" "%(Filename).spec" CTL3DV2 > "%(Filename).asm" && "$(AsmPath)as" --32 -o "%(Filename).obj" "%(Filename).asm"
%(Filename).obj
"$(OutDir)convspec" "%(Filename).spec" CTL3DV2 > "%(Filename).asm" && "$(AsmPath)as" --32 -o "%(Filename).obj" "%(Filename).asm"
%(Filename).obj
================================================
FILE: ddeml/CMakeLists.txt
================================================
file(GLOB SOURCE *.c *.cpp *.rc)
add_library(ddeml SHARED ${SOURCE} ${CMAKE_CURRENT_BINARY_DIR}/ddeml.def ddeml.dll16.obj)
include_directories(../wine)
add_definitions(-D_X86_ -D__WINESRC__ -D__i386__ -DHAVE_STRNCASECMP -DHAVE__STRNICMP -D_WINTERNL_ -DNtCurrentTeb=NtCurrentTeb__ -DDECLSPEC_HIDDEN= -Dstrncasecmp=_strnicmp)
spec_build(ddeml.dll16 ddeml)
target_link_libraries(ddeml libwine winecrt0 krnl386)
set_target_properties(ddeml PROPERTIES SUFFIX ".dll16")
================================================
FILE: ddeml/Makefile.in
================================================
MODULE = ddeml.dll16
IMPORTS = user32
EXTRADLLFLAGS = -m16
C_SRCS = ddeml.c
================================================
FILE: ddeml/ddeml.c
================================================
/*
* DDEML library
*
* Copyright 1997 Alexandre Julliard
* Copyright 1997 Len White
* Copyright 1999 Keith Matthews
* Copyright 2000 Corel
* Copyright 2001,2002,2009 Eric Pouech
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#include "wine/port.h"
#include
#include
#include "windef.h"
#include "winbase.h"
#include "wine/windef16.h"
#include "wine/winbase16.h"
#include "wownt32.h"
#include "dde.h"
#include "ddeml.h"
#include "winuser.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(ddeml);
typedef HDDEDATA (CALLBACK *PFNCALLBACK16)(UINT16,UINT16,HCONV,HSZ,HSZ,HDDEDATA,
DWORD,DWORD);
typedef struct
{
UINT16 cb;
UINT16 wFlags;
UINT16 wCountryID;
INT16 iCodePage;
DWORD dwLangID;
DWORD dwSecurity;
} CONVCONTEXT16, *LPCONVCONTEXT16;
typedef struct
{
DWORD cb;
DWORD hUser;
HCONV hConvPartner;
HSZ hszSvcPartner;
HSZ hszServiceReq;
HSZ hszTopic;
HSZ hszItem;
UINT16 wFmt;
UINT16 wType;
UINT16 wStatus;
UINT16 wConvst;
UINT16 wLastError;
HCONVLIST hConvList;
CONVCONTEXT16 ConvCtxt;
} CONVINFO16, *LPCONVINFO16;
static void map1632_conv_context(CONVCONTEXT* cc32, const CONVCONTEXT16* cc16)
{
cc32->cb = sizeof(*cc32);
cc32->wFlags = cc16->wFlags;
cc32->wCountryID = cc16->wCountryID;
cc32->iCodePage = cc16->iCodePage;
cc32->dwLangID = cc16->dwLangID;
cc32->dwSecurity = cc16->dwSecurity;
}
static void map3216_conv_context(CONVCONTEXT16* cc16, const CONVCONTEXT* cc32)
{
cc16->cb = sizeof(*cc16);
cc16->wFlags = cc32->wFlags;
cc16->wCountryID = cc32->wCountryID;
cc16->iCodePage = cc32->iCodePage;
cc16->dwLangID = cc32->dwLangID;
cc16->dwSecurity = cc32->dwSecurity;
}
/******************************************************************
* WDML_InvokeCallback16
*
*
*/
static HDDEDATA CALLBACK WDML_InvokeCallback16(DWORD pfn16, UINT uType, UINT uFmt,
HCONV hConv, HSZ hsz1, HSZ hsz2,
HDDEDATA hdata, ULONG_PTR dwData1, ULONG_PTR dwData2)
{
DWORD d1 = 0;
HDDEDATA ret;
CONVCONTEXT16 cc16;
WORD args[14];
switch (uType)
{
case XTYP_CONNECT:
case XTYP_WILDCONNECT:
if (dwData1)
{
map3216_conv_context(&cc16, (const CONVCONTEXT*)dwData1);
d1 = MapLS(&cc16);
}
break;
default:
d1 = dwData1;
break;
}
args[13] = uType;
args[12] = uFmt;
args[11] = HIWORD(hConv);
args[10] = LOWORD(hConv);
args[9] = HIWORD(hsz1);
args[8] = LOWORD(hsz1);
args[7] = HIWORD(hsz2);
args[6] = LOWORD(hsz2);
args[5] = HIWORD(hdata);
args[4] = LOWORD(hdata);
args[3] = HIWORD(d1);
args[2] = LOWORD(d1);
args[1] = HIWORD(dwData2);
args[0] = LOWORD(dwData2);
WOWCallback16Ex(pfn16, WCB16_PASCAL, sizeof(args), args, (DWORD *)&ret);
switch (uType)
{
case XTYP_CONNECT:
case XTYP_WILDCONNECT:
if (d1 != 0) UnMapLS(d1);
break;
}
return ret;
}
#define MAX_THUNKS 32
/* As DDEML doesn't provide a way to get back to an InstanceID when
* a callback is run, we use thunk in order to implement simply the
* 32bit->16bit callback mechanism.
* For each 16bit instance, we create a thunk, which will be passed as
* a 32bit callback. This thunk also stores (in the code!) the 16bit
* address of the 16bit callback, and passes it back to
* WDML_InvokeCallback16.
* The code below is mainly to create the thunks themselves
*/
#include "pshpack1.h"
static struct ddeml_thunk
{
BYTE popl_eax; /* popl %eax (return address) */
BYTE pushl_func; /* pushl $pfn16 (16bit callback function) */
SEGPTR pfn16;
BYTE pushl_eax; /* pushl %eax */
BYTE jmp; /* ljmp WDML_InvokeCallback16 */
DWORD callback;
DWORD instId; /* instance ID */
} *DDEML16_Thunks;
#include "poppack.h"
static CRITICAL_SECTION ddeml_cs;
static CRITICAL_SECTION_DEBUG critsect_debug =
{
0, 0, &ddeml_cs,
{ &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
0, 0, { (DWORD_PTR)(__FILE__ ": ddeml_cs") }
};
static CRITICAL_SECTION ddeml_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
static struct ddeml_thunk* DDEML_AddThunk(DWORD instId, DWORD pfn16)
{
struct ddeml_thunk* thunk;
if (!DDEML16_Thunks)
{
DDEML16_Thunks = VirtualAlloc(NULL, MAX_THUNKS * sizeof(*DDEML16_Thunks), MEM_COMMIT,
PAGE_EXECUTE_READWRITE);
if (!DDEML16_Thunks) return NULL;
for (thunk = DDEML16_Thunks; thunk < &DDEML16_Thunks[MAX_THUNKS]; thunk++)
{
thunk->popl_eax = 0x58; /* popl %eax */
thunk->pushl_func = 0x68; /* pushl $pfn16 */
thunk->pfn16 = 0;
thunk->pushl_eax = 0x50; /* pushl %eax */
thunk->jmp = 0xe9; /* jmp WDML_InvokeCallback16 */
thunk->callback = (char *)WDML_InvokeCallback16 - (char *)(&thunk->callback + 1);
thunk->instId = 0;
}
}
for (thunk = DDEML16_Thunks; thunk < &DDEML16_Thunks[MAX_THUNKS]; thunk++)
{
/* either instId is 0, and we're looking for an empty slot, or
* instId is an already existing instance, and we should find its thunk
*/
if (thunk->instId == instId)
{
thunk->pfn16 = pfn16;
return thunk;
}
}
FIXME("Out of ddeml-thunks. Bump MAX_THUNKS\n");
return NULL;
}
HSZ hsz_progman;
HSZ hsz_progman16;
static void init_hsz()
{
if (!hsz_progman)
{
hsz_progman = (HSZ)(ULONG_PTR)AddAtomA("Progman");
}
if (!hsz_progman16)
{
hsz_progman16 = (HSZ)(ULONG_PTR)AddAtomA("Progman16");
}
}
static HSZ service16_32(HSZ hsz)
{
init_hsz();
if (hsz_progman == hsz)
return hsz_progman16;
return hsz;
}
static HSZ service32_16(HSZ hsz)
{
init_hsz();
if (hsz_progman16 == hsz)
return hsz_progman;
return hsz;
}
static HSZ topic16_32(HSZ hsz)
{
init_hsz();
if (hsz_progman == hsz)
return hsz_progman16;
return hsz;
}
static HSZ topic32_16(HSZ hsz)
{
init_hsz();
if (hsz_progman16 == hsz)
return hsz_progman;
return hsz;
}
/******************************************************************************
* DdeInitialize (DDEML.2)
*/
UINT16 WINAPI DdeInitialize16(LPDWORD pidInst, PFNCALLBACK16 pfnCallback,
DWORD afCmd, DWORD ulRes)
{
UINT16 ret;
DWORD count;
struct ddeml_thunk* thunk;
// Undocumented 0x800 causes DdeClientTransaction to call DdeUninitialize which will likely
// create a deadlock with XTYP_EXECUTE if the client and server are in the same process
afCmd &= ~0x800;
// MF_POSTMSGS causes also deadlocks in DdeDisconnect in the client thread
afCmd &= ~MF_POSTMSGS;
ReleaseThunkLock(&count);
EnterCriticalSection(&ddeml_cs);
if ((thunk = DDEML_AddThunk(*pidInst, (DWORD)pfnCallback)))
{
ret = DdeInitializeA(pidInst, (PFNCALLBACK)thunk, afCmd, ulRes);
if (ret == DMLERR_NO_ERROR) thunk->instId = *pidInst;
}
else ret = DMLERR_SYS_ERROR;
LeaveCriticalSection(&ddeml_cs);
RestoreThunkLock(count);
return ret;
}
/*****************************************************************
* DdeUninitialize (DDEML.3)
*/
BOOL16 WINAPI DdeUninitialize16(DWORD idInst)
{
struct ddeml_thunk* thunk;
BOOL16 ret = FALSE;
if (!DdeUninitialize(idInst)) return FALSE;
EnterCriticalSection(&ddeml_cs);
for (thunk = DDEML16_Thunks; thunk < &DDEML16_Thunks[MAX_THUNKS]; thunk++)
{
if (thunk->instId == idInst)
{
thunk->instId = 0;
ret = TRUE;
break;
}
}
LeaveCriticalSection(&ddeml_cs);
if (!ret) FIXME("Should never happen\n");
return ret;
}
/*****************************************************************
* DdeConnectList [DDEML.4]
*/
HCONVLIST WINAPI DdeConnectList16(DWORD idInst, HSZ hszService, HSZ hszTopic,
HCONVLIST hConvList, LPCONVCONTEXT16 pCC16)
{
CONVCONTEXT cc;
CONVCONTEXT* pCC = NULL;
if (pCC16)
map1632_conv_context(pCC = &cc, pCC16);
return DdeConnectList(idInst, service16_32(hszService), topic16_32(hszTopic), hConvList, pCC);
}
/*****************************************************************
* DdeQueryNextServer [DDEML.5]
*/
HCONV WINAPI DdeQueryNextServer16(HCONVLIST hConvList, HCONV hConvPrev)
{
return DdeQueryNextServer(hConvList, hConvPrev);
}
/*****************************************************************
* DdeDisconnectList (DDEML.6)
*/
BOOL16 WINAPI DdeDisconnectList16(HCONVLIST hConvList)
{
return (BOOL16)DdeDisconnectList(hConvList);
}
/*****************************************************************
* DdeQueryString (DDEML.23)
*/
DWORD WINAPI DdeQueryString16(DWORD idInst, HSZ hsz, LPSTR lpsz, DWORD cchMax,
INT16 codepage)
{
if (codepage != CP_WINANSI)
{
if (!codepage || (codepage == GetKBCodePage()))
WARN("Codepage %x supplied but only CP_WINANSI is supported\n", codepage);
else
{
ERR("Invalid codepage %x\n", codepage);
return DMLERR_INVALIDPARAMETER;
}
}
return DdeQueryStringA(idInst, hsz, lpsz, cchMax, CP_WINANSI);
}
/*****************************************************************
* DdeConnect (DDEML.7)
*/
HCONV WINAPI DdeConnect16(DWORD idInst, HSZ hszService, HSZ hszTopic,
LPCONVCONTEXT16 pCC16)
{
CONVCONTEXT cc;
CONVCONTEXT* pCC = NULL;
if (pCC16)
map1632_conv_context(pCC = &cc, pCC16);
DWORD count;
ReleaseThunkLock(&count);
HCONV result = DdeConnect(idInst, service16_32(hszService), topic16_32(hszTopic), pCC);
RestoreThunkLock(count);
return result;
}
/*****************************************************************
* DdeDisconnect (DDEML.8)
*/
BOOL16 WINAPI DdeDisconnect16(HCONV hConv)
{
return (BOOL16)DdeDisconnect(hConv);
}
/*****************************************************************
* DdeSetUserHandle (DDEML.10)
*/
BOOL16 WINAPI DdeSetUserHandle16(HCONV hConv, DWORD id, DWORD hUser)
{
return DdeSetUserHandle(hConv, id, hUser);
}
/*****************************************************************
* DdeCreateDataHandle (DDEML.14)
*/
HDDEDATA WINAPI DdeCreateDataHandle16(DWORD idInst, LPBYTE pSrc, DWORD cb,
DWORD cbOff, HSZ hszItem, UINT16 wFmt,
UINT16 afCmd)
{
return DdeCreateDataHandle(idInst, pSrc, cb, cbOff, hszItem, wFmt, afCmd);
}
/*****************************************************************
* DdeCreateStringHandle (DDEML.21)
*/
HSZ WINAPI DdeCreateStringHandle16(DWORD idInst, LPCSTR str, INT16 codepage)
{
if (codepage != CP_WINANSI)
{
if (!codepage || (codepage == GetKBCodePage()))
WARN("Codepage %x supplied but only CP_WINANSI is supported\n", codepage);
else
{
ERR("Invalid codepage %x\n", codepage);
return DMLERR_INVALIDPARAMETER;
}
}
if (str && !stricmp(str, "Progman"))
str = "Progman16";
return DdeCreateStringHandleA(idInst, str, CP_WINANSI);
}
/*****************************************************************
* DdeFreeStringHandle (DDEML.22)
*/
BOOL16 WINAPI DdeFreeStringHandle16(DWORD idInst, HSZ hsz)
{
return (BOOL16)DdeFreeStringHandle(idInst, hsz);
}
/*****************************************************************
* DdeFreeDataHandle (DDEML.19)
*/
BOOL16 WINAPI DdeFreeDataHandle16(HDDEDATA hData)
{
return (BOOL16)DdeFreeDataHandle(hData);
}
/*****************************************************************
* DdeKeepStringHandle (DDEML.24)
*/
BOOL16 WINAPI DdeKeepStringHandle16(DWORD idInst, HSZ hsz)
{
return DdeKeepStringHandle(idInst, hsz);
}
/*****************************************************************
* DdeClientTransaction (DDEML.11)
*/
HDDEDATA WINAPI DdeClientTransaction16(LPVOID pData, DWORD cbData, HCONV hConv,
HSZ hszItem, UINT16 wFmt, UINT16 wType,
DWORD dwTimeout, LPDWORD pdwResult)
{
if (cbData != (DWORD)-1)
{
/* pData is not a pointer if cbData is -1, so we linearize the address
* here rather than in the calling code. */
pData = MapSL((SEGPTR)pData);
}
HDDEDATA ret;
DWORD count;
ReleaseThunkLock(&count);
ret = DdeClientTransaction(pData, cbData, hConv, hszItem,
wFmt, wType, dwTimeout, pdwResult);
RestoreThunkLock(count);
return ret;
}
/*****************************************************************
*
* DdeAbandonTransaction (DDEML.12)
*
*/
BOOL16 WINAPI DdeAbandonTransaction16(DWORD idInst, HCONV hConv, DWORD idTransaction)
{
return (BOOL16)DdeAbandonTransaction(idInst, hConv, idTransaction);
}
/*****************************************************************
* DdePostAdvise [DDEML.13]
*/
BOOL16 WINAPI DdePostAdvise16(DWORD idInst, HSZ hszTopic, HSZ hszItem)
{
return (BOOL16)DdePostAdvise(idInst, topic16_32(hszTopic), hszItem);
}
/*****************************************************************
* DdeAddData (DDEML.15)
*/
HDDEDATA WINAPI DdeAddData16(HDDEDATA hData, LPBYTE pSrc, DWORD cb, DWORD cbOff)
{
return DdeAddData(hData, pSrc, cb, cbOff);
}
/*****************************************************************
* DdeGetData [DDEML.16]
*/
DWORD WINAPI DdeGetData16(HDDEDATA hData, LPBYTE pDst, DWORD cbMax, DWORD cbOff)
{
return DdeGetData(hData, pDst, cbMax, cbOff);
}
/*****************************************************************
* DdeAccessData (DDEML.17)
*/
LPBYTE WINAPI DdeAccessData16(HDDEDATA hData, LPDWORD pcbDataSize)
{
FIXME("expect trouble\n");
/* FIXME: there's a memory leak here... */
return (LPBYTE)MapLS(DdeAccessData(hData, pcbDataSize));
}
/*****************************************************************
* DdeUnaccessData (DDEML.18)
*/
BOOL16 WINAPI DdeUnaccessData16(HDDEDATA hData)
{
return DdeUnaccessData(hData);
}
/*****************************************************************
* DdeEnableCallback (DDEML.26)
*/
BOOL16 WINAPI DdeEnableCallback16(DWORD idInst, HCONV hConv, UINT16 wCmd)
{
return DdeEnableCallback(idInst, hConv, wCmd);
}
/*****************************************************************
* DdeNameService (DDEML.27)
*/
HDDEDATA WINAPI DdeNameService16(DWORD idInst, HSZ hsz1, HSZ hsz2, UINT16 afCmd)
{
return DdeNameService(idInst, service16_32(hsz1), hsz2, afCmd);
}
/*****************************************************************
* DdeGetLastError (DDEML.20)
*/
UINT16 WINAPI DdeGetLastError16(DWORD idInst)
{
return (UINT16)DdeGetLastError(idInst);
}
/*****************************************************************
* DdeCmpStringHandles (DDEML.36)
*/
INT16 WINAPI DdeCmpStringHandles16(HSZ hsz1, HSZ hsz2)
{
return DdeCmpStringHandles(hsz1, hsz2);
}
/******************************************************************
* DdeQueryConvInfo (DDEML.9)
*
*/
UINT16 WINAPI DdeQueryConvInfo16(HCONV hConv, DWORD idTransaction,
LPCONVINFO16 lpConvInfo)
{
CONVINFO ci32;
CONVINFO16 ci16;
UINT ret;
ci32.cb = sizeof(ci32);
ci32.ConvCtxt.cb = sizeof(ci32.ConvCtxt);
ret = DdeQueryConvInfo(hConv, idTransaction, &ci32);
if (ret == 0) return 0;
ci16.cb = lpConvInfo->cb;
ci16.hUser = ci32.hUser;
ci16.hConvPartner = service32_16(ci32.hConvPartner);
ci16.hszSvcPartner = service32_16(ci32.hszSvcPartner);
ci16.hszServiceReq = service32_16(ci32.hszServiceReq);
ci16.hszTopic = topic32_16(ci32.hszTopic);
ci16.hszItem = topic32_16(ci32.hszItem);
ci16.wFmt = ci32.wFmt;
ci16.wType = ci32.wType;
ci16.wStatus = ci32.wStatus;
ci16.wConvst = ci32.wConvst;
ci16.wLastError = ci32.wLastError;
ci16.hConvList = ci32.hConvList;
map3216_conv_context(&ci16.ConvCtxt, &ci32.ConvCtxt);
memcpy(lpConvInfo, &ci16, lpConvInfo->cb);
return lpConvInfo->cb;
}
================================================
FILE: ddeml/ddeml.def
================================================
; File generated automatically from ..\ddeml\ddeml.dll16.spec; do not edit!
LIBRARY ddeml.dll16
EXPORTS
_wine_spec_dos_header @1 DATA
================================================
FILE: ddeml/ddeml.dll16.spec
================================================
2 pascal -ret16 DdeInitialize(ptr segptr long long) DdeInitialize16
3 pascal -ret16 DdeUninitialize(long) DdeUninitialize16
4 pascal DdeConnectList(long long long long ptr) DdeConnectList16
5 pascal DdeQueryNextServer(long long) DdeQueryNextServer16
6 pascal -ret16 DdeDisconnectList(long) DdeDisconnectList16
7 pascal DdeConnect(long long long ptr) DdeConnect16
8 pascal -ret16 DdeDisconnect(long) DdeDisconnect16
9 pascal -ret16 DdeQueryConvInfo(long long ptr) DdeQueryConvInfo16
10 pascal -ret16 DdeSetUserHandle(long long long) DdeSetUserHandle16
11 pascal DdeClientTransaction(long long long long word word long ptr) DdeClientTransaction16
12 pascal -ret16 DdeAbandonTransaction(long long long) DdeAbandonTransaction16
13 pascal -ret16 DdePostAdvise(long long long) DdePostAdvise16
14 pascal DdeCreateDataHandle(long ptr long long long word word) DdeCreateDataHandle16
15 pascal DdeAddData(long ptr long long) DdeAddData16
16 pascal DdeGetData(long ptr long long) DdeGetData16
17 pascal DdeAccessData(long ptr) DdeAccessData16
18 pascal -ret16 DdeUnaccessData(long) DdeUnaccessData16
19 pascal -ret16 DdeFreeDataHandle(long) DdeFreeDataHandle16
20 pascal -ret16 DdeGetLastError(long) DdeGetLastError16
21 pascal DdeCreateStringHandle(long str s_word) DdeCreateStringHandle16
22 pascal -ret16 DdeFreeStringHandle(long long) DdeFreeStringHandle16
23 pascal DdeQueryString(long long ptr long s_word) DdeQueryString16
24 pascal -ret16 DdeKeepStringHandle(long long) DdeKeepStringHandle16
26 pascal -ret16 DdeEnableCallback(long long word) DdeEnableCallback16
27 pascal DdeNameService(long long long word) DdeNameService16
36 pascal -ret16 DdeCmpStringHandles(long long) DdeCmpStringHandles16
37 pascal DdeReconnect(long) DdeReconnect
================================================
FILE: ddeml/ddeml.vcxproj
================================================
Debug
Win32
Release
Win32
Win32Proj
ddeml
{D4EED8A5-2B15-4299-9F65-D56383AC7848}
10.0.17134.0
DynamicLibrary
true
v141
Unicode
DynamicLibrary
false
v141
true
Unicode
true
.dll16
false
Release
.dll16
Level3
Disabled
WIN32;_DEBUG;_WINDOWS;_USRDLL;_X86_;__WINESRC__;__i386__;USE_COMPILER_EXCEPTIONS;HAVE_STRNCASECMP;HAVE__STRNICMP;_WINTERNL_;NtCurrentTeb=NtCurrentTeb__;inline=__inline;%(PreprocessorDefinitions)
../wine
Windows
true
$(OutDir)winecrt0.lib;$(OutDir)libwine.lib;$(OutDir)krnl386.lib;
user32.lib;
true
ddeml.def
Level3
MaxSpeed
true
true
WIN32;NDEBUG;_WINDOWS;_USRDLL;_X86_;__WINESRC__;__i386__;USE_COMPILER_EXCEPTIONS;HAVE_STRNCASECMP;HAVE__STRNICMP;_WINTERNL_;NtCurrentTeb=NtCurrentTeb__;inline=__inline;DECLSPEC_HIDDEN=;%(PreprocessorDefinitions)
../wine
Windows
true
true
true
false
ddeml.def
$(OutDir)winecrt0.lib;$(OutDir)libwine.lib;$(OutDir)krnl386.lib;
user32.lib;
Document
"$(OutDir)convspec" "%(Filename).spec" DDEML > "%(Filename).asm" && "$(AsmPath)as" --32 -o "%(Filename).obj" "%(Filename).asm"
%(Filename).obj
"$(OutDir)convspec" "%(Filename).spec" DDEML > "%(Filename).asm" && "$(AsmPath)as" --32 -o "%(Filename).obj" "%(Filename).asm"
%(Filename).obj
================================================
FILE: dispdib/CMakeLists.txt
================================================
file(GLOB SOURCE *.c *.cpp *.rc)
add_library(dispdib SHARED ${SOURCE} ${CMAKE_CURRENT_BINARY_DIR}/dispdib.def dispdib.dll16.obj)
include_directories(../wine)
add_definitions(-D_X86_ -D__WINESRC__ -D__i386__ -DHAVE_STRNCASECMP -DHAVE__STRNICMP -D_WINTERNL_ -DNtCurrentTeb=NtCurrentTeb__ -DDECLSPEC_HIDDEN= -Dstrncasecmp=_strnicmp)
spec_build(dispdib.dll16 dispdib)
target_link_libraries(dispdib libwine winecrt0 krnl386)
set_target_properties(dispdib PROPERTIES SUFFIX ".dll16")
================================================
FILE: dispdib/Makefile.in
================================================
MODULE = dispdib.dll16
EXTRADLLFLAGS = -m16
C_SRCS = dispdib.c
================================================
FILE: dispdib/dispdib.c
================================================
/*
* DISPDIB.dll
*
* Copyright 1998 Ove Kåven (with some help from Marcus Meissner)
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include
#include
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "mmsystem.h"
#include "wine/wingdi16.h"
#include "windows/dispdib.h"
#include "wine/debug.h"
#include "../krnl386/dosexe.h"
WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
#define width 320
static HTASK16 owner = 0;
static HDC dddc;
static int height;
static HWND ddhwnd;
static INTPROC oldproc;
static OUTPROC oldout[0x20];
static INPROC oldin[0x20];
static HANDLE running = 0;
static BOOL vsync = FALSE;
static BOOL hsync = FALSE;
static LPVOID vram;
static void draw()
{
RECT rect;
int new_width, new_height;
const double r = 4.0 / 3.0;
HDC dc = GetDC(ddhwnd);
GetClientRect(ddhwnd, &rect);
/* aspect */
if (rect.right / r > rect.bottom)
{
new_height = rect.bottom;
new_width = rect.bottom * r;
RECT frect = rect;
frect.left = 0;
frect.right = (rect.right - new_width) / 2;
FillRect(dc, &frect, GetStockObject(DKGRAY_BRUSH));
frect.left = rect.right - (rect.right - new_width) / 2;
frect.right = rect.right;
FillRect(dc, &frect, GetStockObject(DKGRAY_BRUSH));
}
else
{
new_width = rect.right;
new_height = rect.right / r;
RECT frect = rect;
frect.top = 0;
frect.bottom = (rect.bottom - new_height) / 2;
FillRect(dc, &frect, GetStockObject(DKGRAY_BRUSH));
frect.top = rect.bottom - (rect.bottom - new_height) / 2;
frect.bottom = rect.bottom;
FillRect(dc, &frect, GetStockObject(DKGRAY_BRUSH));
}
StretchBlt(dc, (rect.right - new_width) / 2, (rect.bottom - new_height) / 2, new_width, new_height, dddc, 0, 0, width, height, SRCCOPY);
ReleaseDC(ddhwnd, dc);
}
static LRESULT CALLBACK ddwndproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static BOOL focus = FALSE, showcur = TRUE;
HWND parhwnd = (HWND)GetWindowLongA(hwnd, GWL_HWNDPARENT);
switch (uMsg)
{
case WM_KILLFOCUS:
if (!showcur)
{
ShowCursor(TRUE);
showcur = TRUE;
}
case WM_SETFOCUS:
focus = uMsg == WM_SETFOCUS;
case WM_KEYDOWN:
case WM_KEYUP:
case WM_CHAR:
case WM_DEADCHAR:
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
case WM_SYSCHAR:
case WM_SYSDEADCHAR:
case WM_UNICHAR:
case WM_TIMER:
case WM_CLOSE:
return CallWindowProcA((WNDPROC)GetWindowLongA(parhwnd, GWL_WNDPROC), parhwnd, uMsg, wParam, lParam);
case WM_SETCURSOR:
if ((LOWORD(lParam) == HTCLIENT) && focus && showcur)
{
ShowCursor(FALSE);
showcur = FALSE;
}
else if (((LOWORD(lParam) != HTCLIENT) || !focus) && !showcur)
{
ShowCursor(TRUE);
showcur = TRUE;
}
break;
}
if ((uMsg >= WM_MOUSEMOVE && uMsg <= WM_MBUTTONDOWN) || uMsg >= MM_JOY1MOVE)
return CallWindowProcA((WNDPROC)GetWindowLongA(parhwnd, GWL_WNDPROC), parhwnd, uMsg, wParam, lParam);
return DefWindowProcA(hwnd, uMsg, wParam, lParam);
}
static void CALLBACK retrace_cb(LPVOID arg, DWORD low, DWORD high)
{
vsync = TRUE;
if (WaitForSingleObject(running, 0))
{
SetEvent(running);
ExitThread(0);
}
SetBitmapBits(GetCurrentObject(dddc, OBJ_BITMAP), width * height, vram);
draw();
}
static DWORD CALLBACK retrace_th(LPVOID arg)
{
LARGE_INTEGER when;
HANDLE timer;
if (!(timer = CreateWaitableTimerA( NULL, FALSE, NULL ))) return 0;
when.u.LowPart = when.u.HighPart = 0;
SetWaitableTimer(timer, &when, 17, retrace_cb, arg, FALSE);
for (;;) SleepEx(INFINITE, TRUE);
}
static void start_retrace_timer()
{
if (running) return;
if (height == 240) FIXME("240 px height doesn't work properly with direct fb access\n");
running = CreateEventA(NULL, TRUE, TRUE, NULL);
vram = MapSL((DWORD)GetProcAddress16(GetModuleHandle16("KERNEL"), (LPCSTR)174) << 16);
CloseHandle(CreateThread(NULL, 0, retrace_th, NULL, 0, NULL));
}
static void WINAPI ddInt10Handler(CONTEXT *context)
{
if (GetCurrentTask() != owner)
{
oldproc(context);
return;
}
switch (AH_reg(context))
{
case 0x00:
start_retrace_timer();
switch (AL_reg(context))
{
case 0x13:
height = 200;
break;
default:
FIXME("Vid mode %#x not supported\n", AL_reg(context));
break;
}
break;
case 0x10:
switch (AL_reg(context))
{
case 0x12:
{
BYTE *ptr = MapSL(MAKESEGPTR(context->SegEs, DX_reg(context)));
for (int i = BX_reg(context); i < CX_reg(context); i++)
{
RGBQUAD color;
color.rgbRed = (ptr[i * 3] << 2) | (ptr[i * 3] >> 4);
color.rgbGreen = (ptr[i * 3 + 1] << 2) | (ptr[i * 3 + 1] >> 4);
color.rgbBlue = (ptr[i * 3 + 2] << 2) | (ptr[i * 3 + 2] >> 4);
color.rgbReserved = 0;
SetDIBColorTable(dddc, i & 0xff, 1, &color);
}
}
}
break;
default:
FIXME("Int 10 func: %#x unimplemented\n", AH_reg(context));
break;
}
}
static DWORD WINAPI ddVGAinHandler(int port, int size)
{
if (GetCurrentTask() != owner)
return oldin[port - 0x3c0] ? oldin[port - 0x3c0](port, size) : 0;
DWORD ret = -1;
switch (port)
{
case 0x3da:
{
start_retrace_timer();
ret = vsync ? 9 : 0;
vsync = FALSE;
hsync = !hsync;
if (!ret) ret = hsync ? 1 : 0;
break;
}
default:
FIXME("vga port %#x unimplemented\n", port);
break;
}
return ret;
}
static void WINAPI ddVGAoutHandler(int port, int size, DWORD value)
{
if (GetCurrentTask() != owner)
{
if (oldout[port - 0x3c0])
oldout[port - 0x3c0](port, size, value);
return;
}
if ((port & ~3) != 0x3c8) start_retrace_timer();
static BYTE dacidx;
static BYTE dacclr = 0;
switch (port)
{
case 0x3c8:
dacidx = value & 0xff;
dacclr = 0;
if (size == 1) break;
value >>= 8;
case 0x3c9:
{
RGBQUAD color;
GetDIBColorTable(dddc, dacidx, 1, &color);
switch (dacclr++)
{
case 0:
color.rgbRed = (BYTE)value << 2;
break;
case 1:
color.rgbGreen = (BYTE)value << 2;
break;
case 2:
color.rgbBlue = (BYTE)value << 2;
dacclr = 0;
break;
}
SetDIBColorTable(dddc, dacidx, 1, &color);
if (!dacclr) dacidx++;
break;
}
default:
FIXME("vga port %#x unimplemented\n", port);
break;
}
}
/*********************************************************************
* DisplayDib (DISPDIB.1)
*
* Disables GDI and takes over the VGA screen to show DIBs in full screen.
*
* FLAGS
*
* DISPLAYDIB_NOPALETTE: don't change palette
* DISPLAYDIB_NOCENTER: don't center bitmap
* DISPLAYDIB_NOWAIT: don't wait (for keypress) before returning
* DISPLAYDIB_BEGIN: start of multiple calls (does not restore the screen)
* DISPLAYDIB_END: end of multiple calls (restores the screen)
* DISPLAYDIB_MODE_DEFAULT: default display mode
* DISPLAYDIB_MODE_320x200x8: Standard VGA 320x200 256 colors
* DISPLAYDIB_MODE_320x240x8: Tweaked VGA 320x240 256 colors
*
* RETURNS
*
* DISPLAYDIB_NOERROR: success
* DISPLAYDIB_NOTSUPPORTED: function not supported
* DISPLAYDIB_INVALIDDIB: null or invalid DIB header
* DISPLAYDIB_INVALIDFORMAT: invalid DIB format
* DISPLAYDIB_INVALIDTASK: not called from current task
*
* BUGS
*
* Waiting for keypresses is not implemented.
*/
WORD WINAPI DisplayDib(
LPBITMAPINFO lpbi, /* [in] DIB header with resolution and palette */
LPSTR lpBits, /* [in] Bitmap bits to show */
WORD wFlags /* [in] */
)
{
HTASK16 task = GetCurrentTask();
if ((wFlags & DISPLAYDIB_BEGIN) && !owner)
{
switch (wFlags & DISPLAYDIB_MODE)
{
default:
return DISPLAYDIB_NOTSUPPORTED;
case DISPLAYDIB_MODE_DEFAULT:
case DISPLAYDIB_MODE_320x200x8:
height = 200;
break;
case DISPLAYDIB_MODE_320x240x8:
height = 240;
break;
}
WNDCLASSA wc;
if (!GetClassInfoA(GetModuleHandleA(NULL), "DispDibClass", &wc))
{
WNDCLASSA ddwc = {0};
ddwc.style = CS_HREDRAW | CS_VREDRAW;
ddwc.lpfnWndProc = ddwndproc;
ddwc.hInstance = GetModuleHandleA(NULL);
ddwc.lpszClassName = "DispDibClass";
if (!RegisterClassA(&ddwc))
return DISPLAYDIB_NOTSUPPORTED;
}
owner = task;
dddc = CreateCompatibleDC(0);
BITMAPINFO *bmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 256*4 + sizeof(BITMAPINFOHEADER));
VOID *section;
bmap->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmap->bmiHeader.biWidth = width;
bmap->bmiHeader.biHeight = height;
bmap->bmiHeader.biPlanes = 1;
bmap->bmiHeader.biBitCount = 8;
HBITMAP ddbmap = CreateDIBSection(dddc, bmap, DIB_RGB_COLORS, §ion, NULL, 0);
HeapFree(GetProcessHeap(), 0, bmap);
SelectObject(dddc, ddbmap);
char title[32] = "\0";
HWND parhwnd = GetActiveWindow();
GetWindowTextA(parhwnd, title, 32);
if (title[0] == '\0') GetModuleName16(GetCurrentTask(), title, 32);
ddhwnd = CreateWindowExA(0, "DispDibClass", title, WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT,
CW_USEDEFAULT, 640, 480, parhwnd, NULL, GetModuleHandleA(NULL), NULL);
if (!ddhwnd)
{
owner = 0;
return DISPLAYDIB_NOTSUPPORTED;
}
oldproc = DOSVM_SetBuiltinVector(0x10, ddInt10Handler);
for (int i = 0; i < 0x20; i++)
DOSVM_setportcb(ddVGAoutHandler, ddVGAinHandler, i + 0x3c0, &oldout[i], &oldin[i]);
return DISPLAYDIB_NOERROR;
}
else if ((owner != task) || !owner)
return DISPLAYDIB_INVALIDTASK;
else if (wFlags & DISPLAYDIB_END)
{
DestroyWindow(ddhwnd);
DeleteDC(dddc);
DOSVM_SetBuiltinVector(0x10, oldproc);
for (int i = 0; i < 0x20; i++)
DOSVM_setportcb(oldout[i], oldin[i], i + 0x3c0, &oldout[i], &oldin[i]);
if (running)
{
ResetEvent(running);
WaitForSingleObject(running, INFINITE);
CloseHandle(running);
running = 0;
}
owner = 0;
return DISPLAYDIB_NOERROR;
}
if (!(wFlags & DISPLAYDIB_NOPALETTE))
{
if (!lpbi)
return DISPLAYDIB_INVALIDDIB;
SetDIBColorTable(dddc, 0, lpbi->bmiHeader.biClrUsed, (RGBQUAD *)&lpbi->bmiColors);
}
if(!(wFlags & /*DISPLAYDIB_NOIMAGE*/ 0x80))
{
if (!lpBits)
return DISPLAYDIB_INVALIDDIB;
SetDIBitsToDevice(dddc, 0, 0, width, height, 0, 0, 0, height, lpBits, lpbi, DIB_RGB_COLORS);
draw();
}
return DISPLAYDIB_NOERROR;
}
================================================
FILE: dispdib/dispdib.def
================================================
; File generated automatically from dispdib\dispdib.dll16.spec; do not edit!
LIBRARY dispdib.dll16
EXPORTS
_wine_spec_dos_header; @1 DATA PRIVATE
================================================
FILE: dispdib/dispdib.dll16.spec
================================================
1 pascal -ret16 DisplayDib(ptr ptr word) DisplayDib
================================================
FILE: dispdib/dispdib.vcxproj
================================================
Debug
Win32
Release
Win32
Win32Proj
dispdib
{3D889B37-09C8-4030-B815-830566CD57A4}
10.0.17134.0
DynamicLibrary
true
v141
Unicode
DynamicLibrary
false
v141
true
Unicode
true
.dll16
false
Release
.dll16
Level3
Disabled
WIN32;_DEBUG;_WINDOWS;_USRDLL;_X86_;__WINESRC__;__i386__;USE_COMPILER_EXCEPTIONS;HAVE_STRNCASECMP;HAVE__STRNICMP;_WINTERNL_;NtCurrentTeb=NtCurrentTeb__;inline=__inline;%(PreprocessorDefinitions)
../wine
Windows
true
$(OutDir)winecrt0.lib;$(OutDir)libwine.lib;$(OutDir)krnl386.lib;
%(AdditionalDependencies)
true
dispdib.def
Level3
MaxSpeed
true
true
WIN32;NDEBUG;_WINDOWS;_USRDLL;_X86_;__WINESRC__;__i386__;USE_COMPILER_EXCEPTIONS;HAVE_STRNCASECMP;HAVE__STRNICMP;_WINTERNL_;NtCurrentTeb=NtCurrentTeb__;inline=__inline;DECLSPEC_HIDDEN=;%(PreprocessorDefinitions)
../wine
Windows
true
true
true
false
dispdib.def
$(OutDir)winecrt0.lib;$(OutDir)libwine.lib;$(OutDir)krnl386.lib;
%(AdditionalDependencies)
Document
"$(OutDir)convspec" "%(Filename).spec" DISPDIB > "%(Filename).asm" && "$(AsmPath)as" --32 -o "%(Filename).obj" "%(Filename).asm"
%(Filename).obj
"$(OutDir)convspec" "%(Filename).spec" DISPDIB > "%(Filename).asm" && "$(AsmPath)as" --32 -o "%(Filename).obj" "%(Filename).asm"
%(Filename).obj
================================================
FILE: display/CMakeLists.txt
================================================
file(GLOB SOURCE *.c *.cpp *.rc)
add_library(display SHARED ${SOURCE} ${CMAKE_CURRENT_BINARY_DIR}/display.def display.drv16.obj)
include_directories(../wine)
add_definitions(-D_X86_ -D__WINESRC__ -D__i386__ -DHAVE_STRNCASECMP -DHAVE__STRNICMP -D_WINTERNL_ -DNtCurrentTeb=NtCurrentTeb__ -DDECLSPEC_HIDDEN= -Dstrncasecmp=_strnicmp)
spec_build(display.drv16 display)
target_link_libraries(display libwine winecrt0 krnl386)
set_target_properties(display PROPERTIES SUFFIX ".drv16")
================================================
FILE: display/Makefile.in
================================================
MODULE = display.drv16
IMPORTS = user32
EXTRADLLFLAGS = -m16
C_SRCS = display.c
RC_SRCS = display.rc
================================================
FILE: display/display.c
================================================
/*
* DISPLAY driver
*
* Copyright 1998 Ulrich Weigand
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include
#include "wine/debug.h"
#include "windef.h"
#include "winbase.h"
#include "wine/winuser16.h"
WINE_DEFAULT_DEBUG_CHANNEL(cursor);
#include "pshpack1.h"
typedef struct tagCURSORINFO16
{
WORD wXMickeys;
WORD wYMickeys;
} CURSORINFO16, *PCURSORINFO16, *LPCURSORINFO16;
#include "poppack.h"
/***********************************************************************
* Inquire (DISPLAY.101)
*/
WORD WINAPI Inquire16(LPCURSORINFO16 lpCursorInfo)
{
lpCursorInfo->wXMickeys = 1;
lpCursorInfo->wYMickeys = 1;
return sizeof(CURSORINFO16);
}
/***********************************************************************
* SetCursor (DISPLAY.102)
*/
VOID WINAPI DISPLAY_SetCursor( struct tagCURSORICONINFO *lpCursor )
{
FIXME("stub\n" );
}
/***********************************************************************
* MoveCursor (DISPLAY.103)
*/
VOID WINAPI MoveCursor16( WORD wAbsX, WORD wAbsY )
{
SetCursorPos( wAbsX, wAbsY );
}
/***********************************************************************
* CheckCursor (DISPLAY.104)
*/
VOID WINAPI CheckCursor16( void )
{
TRACE("stub\n" );
}
/***********************************************************************
* GetDriverResourceID (DISPLAY.450)
*
* Used by USER to check if driver contains better version of a builtin
* resource than USER (yes, our DISPLAY does !).
* wQueriedResID is the ID USER asks about.
* lpsResName does often contain "OEMBIN".
*/
DWORD WINAPI GetDriverResourceID16( WORD wQueriedResID, LPSTR lpsResName )
{
if (wQueriedResID == 3)
return (DWORD)1;
return (DWORD)wQueriedResID;
}
/***********************************************************************
* UserRepaintDisable (DISPLAY.500)
*/
VOID WINAPI UserRepaintDisable16( BOOL16 disable )
{
FIXME("stub\n");
}
WORD WINAPI SetPaletteTranslate16( WORD wNumEntries, LPBYTE lpTranslate)
{
WARN("stub\n");
return 0;
}
================================================
FILE: display/display.def
================================================
; File generated automatically from display\display.drv16.spec; do not edit!
LIBRARY display.drv16
EXPORTS
_wine_spec_dos_header @1 DATA
================================================
FILE: display/display.drv16.spec
================================================
1 stub BitBlt
2 stub ColorInfo
3 stub Control
4 stub Disable
5 stub Enable
6 stub EnumFonts
7 stub EnumObj
8 stub Output
9 stub Pixel
10 stub RealizeObject
11 stub StrBlt
12 stub ScanLR
13 stub DeviceMode
14 stub ExtTextOut
15 stub GetCharWidth
16 stub DeviceBitmap
17 stub FastBorder
18 stub SetAttribute
19 stub DeviceBitmapBits
20 stub CreateBitmap
21 stub DIBScreenBlt
# ATI driver exports
22 stub SetPalette
23 stub GetPalette
24 pascal -ret16 SetPaletteTranslate(word ptr) SetPaletteTranslate16
25 stub GetPaletteTranslate
26 stub UpdateColors
27 stub StretchBlt
28 stub StretchDIBits
29 stub SelectBitmap
30 stub BitmapBits
31 stub ReEnable
# these conflict with ordinals 19-21, thus relocated to 39-41 !
39 stub DIBBlt
40 stub CreateDIBitmap
41 stub DIBToDevice
# ATI driver end
90 stub Do_Polylines
91 stub Do_Scanlines
92 stub SaveScreenBitmap
101 pascal -ret16 Inquire(ptr) Inquire16
102 pascal -ret16 SetCursor(ptr) DISPLAY_SetCursor
103 pascal -ret16 MoveCursor(word word) MoveCursor16
104 pascal -ret16 CheckCursor() CheckCursor16
400 stub PExtTextOut
401 stub PStrBlt
402 stub RExtTextOut
403 stub RStrBlt
450 pascal GetDriverResourceID(word str) GetDriverResourceID16
500 pascal -ret16 UserRepaintDisable(word) UserRepaintDisable16
501 stub ORDINAL_ONLY1
502 stub ORDINAL_ONLY2
600 stub InkReady
601 stub GetLPDevice
================================================
FILE: display/display.rc
================================================
/*
* resource file for DISPLAY driver dll
*
* Copyright 1999 Andreas Mohr
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
1 OEMBIN
{
0x11, /* vertical thumb height (in pixels) */
0x11, /* horizontal thumb width (in pixels) */
0x02, /* icon width (in pixels) */
0x02, /* icon height (in pixels) */
0x01, /* cursor width (in pixels) */
0x01, /* cursor height (in pixels) */
0x00, /* reserved */
0x01, /* vertical-line width */
0x01, /* horizontal-line width */
/* default system color values */
0x00d4d0c8L, /* scrollbar */
0x00d4d0c8L, /* desktop */
0x00800000L, /* active caption */
0x00ffffffL, /* inactive caption */
0x00ffffffL, /* menu */
0x00ffffffL, /* window */
0x00000000L, /* window frame */
0x00000000L, /* menu text */
0x00000000L, /* window text */
0x00ffffffL, /* caption text */
0x00d4d0c8L, /* active border */
0x00d4d0c8L, /* inactive border */
0x00ffffffL, /* app workspace */
0x00800000L, /* hilite bk */
0x00ffffffL, /* hilite text */
0x00d4d0c8L, /* btn face */
0x00808080L, /* btn shadow */
0x00c0c0c0L, /* gray text */
0x00000000L, /* btn text */
0x00000000L /* inactive caption text */
}
/* @makedep: oic_hand.ico */
1 ICON oic_hand.ico
================================================
FILE: display/display.vcxproj
================================================
Debug
Win32
Release
Win32
Win32Proj
10.0.17134.0
display
{E0AF9E72-F364-481A-A6E5-63EA88DF684E}
DynamicLibrary
true
v141
Unicode
DynamicLibrary
false
v141
true
Unicode
true
.drv16
false
Release
.drv16
Level3
Disabled
WIN32;_DEBUG;_WINDOWS;_USRDLL;_X86_;__WINESRC__;__i386__;USE_COMPILER_EXCEPTIONS;HAVE_STRNCASECMP;HAVE__STRNICMP;_WINTERNL_;NtCurrentTeb=NtCurrentTeb__;inline=__inline;%(PreprocessorDefinitions)
../wine
Windows
true
$(OutDir)winecrt0.lib;$(OutDir)libwine.lib;$(OutDir)krnl386.lib;
user32.lib
true
display.def
Level3
MaxSpeed
true
true
WIN32;NDEBUG;_WINDOWS;_USRDLL;_X86_;__WINESRC__;__i386__;USE_COMPILER_EXCEPTIONS;HAVE_STRNCASECMP;HAVE__STRNICMP;_WINTERNL_;NtCurrentTeb=NtCurrentTeb__;inline=__inline;DECLSPEC_HIDDEN=;%(PreprocessorDefinitions)
../wine
Windows
true
true
true
false
display.def
$(OutDir)winecrt0.lib;$(OutDir)libwine.lib;$(OutDir)krnl386.lib;
user32.lib
Document
"$(OutDir)convspec" "%(Filename).spec" DISPLAY > "%(Filename).asm" && "$(AsmPath)as" --32 -o "%(Filename).obj" "%(Filename).asm"
%(Filename).obj
================================================
FILE: dummy.c
================================================
================================================
FILE: gdi/CMakeLists.txt
================================================
file(GLOB SOURCE *.c *.cpp)
add_library(gdi SHARED ${SOURCE} ${CMAKE_CURRENT_BINARY_DIR}/gdi.def gdi.exe16.obj)
include_directories(../wine)
add_definitions(-D_X86_ -D__WINESRC__ -D__i386__ -DHAVE_STRNCASECMP -DHAVE__STRNICMP -D_WINTERNL_ -DNtCurrentTeb=NtCurrentTeb__ -DDECLSPEC_HIDDEN= -Dstrncasecmp=_strnicmp)
spec_build(gdi.exe16 GDI ARG --heap 65520)
target_link_libraries(gdi libwine winecrt0 krnl386 user winspool)
set_target_properties(gdi PROPERTIES SUFFIX ".exe16")
================================================
FILE: gdi/bidi.c
================================================
/*
* Win16 BiDi functions
* Copyright 2000 Erez Volk
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*
* NOTE: Right now, most of these functions do nothing.
*/
#include
#include "windef.h"
#include "winbase.h"
#include "wine/wingdi16.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(gdi);
/***********************************************************************
* RawTextOut (GDI.530)
*/
LONG WINAPI RawTextOut16(HDC16 hdc, INT16 x, INT16 y, LPCSTR str, INT16 count)
{
FIXME("(%04x,%d,%d,%s,%d)\n", hdc, x, y, debugstr_an(str, count), count);
return TextOut16(hdc, x, y, str, count);
}
/***********************************************************************
* RawExtTextOut (GDI.531)
*/
LONG WINAPI RawExtTextOut16( HDC16 hdc, INT16 x, INT16 y, UINT16 flags,
const RECT16 *lprect, LPCSTR str, UINT16 count,
const INT16 *lpDx )
{
FIXME("(%04x,%d,%d,%04x,%p,%s,%d,%p)\n", hdc, x, y, flags, lprect,
debugstr_an(str, count), count, lpDx);
return ExtTextOut16(hdc, x, y, flags, lprect, str, count, lpDx);
}
/***********************************************************************
* RawGetTextExtent (GDI.532)
*/
LONG WINAPI RawGetTextExtent16(HDC16 hdc, LPCSTR lpszString, INT16 cbString )
{
FIXME("(%04hx, %p, %hd): stub\n", hdc, lpszString, cbString);
return GetTextExtent16(hdc, lpszString, cbString);
}
/***********************************************************************
* RawGetTextExtentEx (GDI.533)
*/
LONG WINAPI RawGetTextExtentEx16(void)
{
FIXME("stub (no prototype)\n");
return 0;
}
/***********************************************************************
* BiDiLayout (GDI.536)
*/
LONG WINAPI BiDiLayout16(void) { FIXME("stub (no prototype)\n"); return 0; }
/***********************************************************************
* BiDiCreateTabString (GDI.537)
*/
LONG WINAPI BiDiCreateTabString16(void) { FIXME("stub (no prototype)\n"); return 0; }
/***********************************************************************
* BiDiCreateString (GDI.538)
*/
LONG WINAPI BiDiCreateString16(void) { FIXME("stub (no prototype)\n"); return 0; }
/***********************************************************************
* BiDiStringOut (GDI.539)
*/
LONG WINAPI BiDiStringOut16(void) { FIXME("stub (no prototype)\n"); return 0; }
/***********************************************************************
* BiDiGlyphOut (GDI.540)
*/
LONG WINAPI BiDiGlyphOut16(WORD a1, WORD a2, WORD a3, WORD a4, LPCSTR a5, WORD a6, WORD a7, WORD a8)
{
FIXME("stub(%04x,%04x,%04x,%04x,%s,%04x,%04x,%04x)\n", a1, a2, a3, a4, debugstr_a(a5), a6, a7, a8);
return 0;
}
/***********************************************************************
* BiDiJustifyString (GDI.541)
*/
LONG WINAPI BiDiJustifyString16(void) { FIXME("stub (no prototype)\n"); return 0; }
/***********************************************************************
* BiDiSetStringTabs (GDI.542)
*/
LONG WINAPI BiDiSetStringTabs16(void) { FIXME("stub (no prototype)\n"); return 0; }
/***********************************************************************
* BiDiGetStringExtent (GDI.543)
*/
LONG WINAPI BiDiGetStringExtent16(void) { FIXME("stub (no prototype)\n"); return 0; }
/***********************************************************************
* BiDiGetNextGlyph (GDI.544)
*/
LONG WINAPI BiDiGetNextGlyph16(void) { FIXME("stub (no prototype)\n"); return 0; }
/***********************************************************************
* BiDiGetPrevGlyph (GDI.545)
*/
LONG WINAPI BiDiGetPrevGlyph16(void) { FIXME("stub (no prototype)\n"); return 0; }
/***********************************************************************
* BiDiIsStringRTL (GDI.546)
*/
LONG WINAPI BiDiIsStringRTL16(void) { FIXME("stub (no prototype)\n"); return 0; }
/***********************************************************************
* BiDiGlyphLength (GDI.547)
*/
LONG WINAPI BiDiGlyphLength16(void) { FIXME("stub (no prototype)\n"); return 0; }
/***********************************************************************
* BiDiCaretStringToPel (GDI.548)
*/
LONG WINAPI BiDiCaretStringTopel16(void) { FIXME("stub (no prototype)\n"); return 0; }
/***********************************************************************
* BiDiCaretPelToString (GDI.549)
*/
LONG WINAPI BiDiCaretPelToString16(void) { FIXME("stub (no prototype)\n"); return 0; }
/***********************************************************************
* BiDiStringToGlyph (GDI.550)
*/
LONG WINAPI BiDiStringToGlyph16(void) { FIXME("stub (no prototype)\n"); return 0; }
/***********************************************************************
* BiDiGlyphToString (GDI.551)
*/
LONG WINAPI BiDiGlyphToString16(void) { FIXME("stub (no prototype)\n"); return 0; }
/***********************************************************************
* BiDiPelToGlyph (GDI.552)
*/
LONG WINAPI BiDiPelToGlyph16(void) { FIXME("stub (no prototype)\n"); return 0; }
/***********************************************************************
* BiDiGlyphToPel (GDI.553)
*/
LONG WINAPI BiDiGlyphToPel16(void) { FIXME("stub (no prototype)\n"); return 0; }
/***********************************************************************
* BiDiBounds (GDI.554)
*/
LONG WINAPI BiDiBounds16(void) { FIXME("stub (no prototype)\n"); return 0; }
/***********************************************************************
* BiDiDeleteString (GDI.555)
*/
LONG WINAPI BiDiDeleteString16(WORD a1)
{
FIXME("stub(%04x)\n", a1);
return 0;
}
/***********************************************************************
* BiDiSetDefaults (GDI.556)
*/
LONG WINAPI BiDiSetDefaults16(void) { FIXME("stub (no prototype)\n"); return 0; }
/***********************************************************************
* BiDiGetDefaults (GDI.558)
*/
LONG WINAPI BiDiGetDefaults16(void) { FIXME("stub (no prototype)\n"); return 0; }
/***********************************************************************
* BiDiCalcString16 (GDI.559)
*/
LONG WINAPI BiDiCalcString16(WORD a1, WORD a2, LPCSTR a3, WORD a4, WORD a5, WORD a6, WORD a7, WORD a8)
{
FIXME("stub(%04x,%04x,%p,%04x,%04x,%04x,%04x,%04x)\n", a1, a2, a3, a4, a5, a6, a7, a8);
return 0;
}
/***********************************************************************
* BiDiShape (GDI.560)
*/
LONG WINAPI BiDiShape16(WORD a1, WORD a2, WORD a3, WORD a4, WORD a5, WORD a6, WORD a7, WORD a8, WORD a9, WORD a10,
WORD a11, WORD a12, LPCSTR a13, WORD a14, WORD a15, WORD a16, WORD a17, WORD a18, WORD a19, WORD a20)
{
FIXME("stub(%04x,%04x,%04x,%04x,%04x,%04x,%04x,%04x,%04x,%04x,", a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);
FIXME("%04x,%04x,%04x,%04x,%04x,%04x,%04x,%04x,%04x,%04x)\n", a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
return 0;
}
/***********************************************************************
* BiDiFontComplement (GDI.561)
*/
LONG WINAPI BiDiFontComplement16(void) { FIXME("stub (no prototype)\n"); return 0; }
/***********************************************************************
* BiDiCalcTabString (GDI.563)
*/
LONG WINAPI BiDiCalcTabString16(void) { FIXME("stub (no prototype)\n"); return 0; }
/***********************************************************************
* BiDiSetKashida (GDI.564)
*/
LONG WINAPI BiDiSetKashida16(void) { FIXME("stub (no prototype)\n"); return 0; }
/***********************************************************************
* BiDiKExtTextOut (GDI.565)
*/
LONG WINAPI BiDiKExtTextOut16(void) { FIXME("stub (no prototype)\n"); return 0; }
/***********************************************************************
* BiDiShapeEx (GDI.566)
*/
LONG WINAPI BiDiShapeEx16(void) { FIXME("stub (no prototype)\n"); return 0; }
/***********************************************************************
* BiDiCreateStringEx (GDI.569)
*/
LONG WINAPI BiDiCreateStringEx16(WORD a1, WORD a2, WORD a3, LPVOID a4, WORD a5, WORD a6, WORD a7, WORD a8, WORD a9)
{
FIXME("stub(%04x,%04x,%04x,%p,%04x,%04x,%04x,%04x,%04x)\n", a1, a2, a3, a4, a5, a6, a7, a8, a9);
return 0;
}
/***********************************************************************
* GetUnicodeMap (GDI.570)
*/
LONG WINAPI GetUnicodeMap16(void) { FIXME("stub (no prototype)\n"); return 0; }
/***********************************************************************
* GetTextExtentRtoL (GDI.571)
*/
LONG WINAPI GetTextExtentRtoL16(void) { FIXME("stub (no prototype)\n"); return 0; }
/***********************************************************************
* GetHDCCharSet (GDI.572)
*/
LONG WINAPI GetHDCCharSet16(HDC16 a1)
{
FIXME("stub(%04x)\n", a1);
return 0;
}
/***********************************************************************
* BiDiLayoutEx (GDI.573)
*/
LONG WINAPI BiDiLayoutEx16(LPVOID a1, WORD a2, WORD a3, WORD a4, LPVOID a5, WORD a6, WORD a7, WORD a8, WORD a9, LPVOID a10, LPVOID a11, WORD a12, WORD a13, WORD a14)
{
FIXME("stub(%p,%04x,%04x,%04x,%p,%04x,%04x,%04x,%04x,%p,%p,%04x,%04x,%04x)\n", a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14);
return 0;
}
/***********************************************************************
* BiDiCreateTabStringEx (GDI.574)
*/
LONG WINAPI BiDiCreateTabStringEx16(void) { FIXME("stub (no prototype)\n"); return 0; }
/***********************************************************************
* BiDiCalcTabStringEx (GDI.575)
*/
LONG WINAPI BiDiCalcTabStringEx16(void) { FIXME("stub (no prototype)\n"); return 0; }
/***********************************************************************
* BiDiCalcStringEx (GDI.576)
*/
LONG WINAPI BiDiCalcStringEx16(void) { FIXME("stub (no prototype)\n"); return 0; }
/***********************************************************************
* SetTextCodePage (GDI.588)
*/
LONG WINAPI SetTextCodePage16(WORD a1, WORD a2)
{
FIXME("stub(%04x,%04x)\n", a1, a2);
return 0;
}
/***********************************************************************
* GetTextCodePage (GDI.589)
*/
LONG WINAPI GetTextCodePage16()
{
FIXME("stub(np)\n");
return 0;
}
================================================
FILE: gdi/env.c
================================================
/*
* Driver Environment functions
*
* Note: This has NOTHING to do with the task/process environment!
*
* Copyright 1997 Marcus Meissner
* Copyright 1998 Andreas Mohr
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#include
#include
#include
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "wine/wingdi16.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(gdi);
typedef struct {
ATOM atom;
HGLOBAL16 handle;
} ENVTABLE;
static ENVTABLE EnvTable[20];
static ENVTABLE *SearchEnvTable(ATOM atom)
{
INT16 i;
for (i = 19; i >= 0; i--) {
if (EnvTable[i].atom == atom)
return &EnvTable[i];
}
return NULL;
}
static ATOM GDI_GetNullPortAtom(void)
{
static ATOM NullPortAtom = 0;
if (!NullPortAtom)
{
char NullPort[256];
GetProfileStringA( "windows", "nullport", "none",
NullPort, sizeof(NullPort) );
NullPortAtom = AddAtomA( NullPort );
}
return NullPortAtom;
}
static ATOM PortNameToAtom(LPCSTR lpPortName, BOOL16 add)
{
char buffer[256];
lstrcpynA( buffer, lpPortName, sizeof(buffer) );
if (buffer[0] && buffer[strlen(buffer)-1] == ':') buffer[strlen(buffer)-1] = 0;
if (add)
return AddAtomA(buffer);
else
return FindAtomA(buffer);
}
/***********************************************************************
* GetEnvironment (GDI.133)
*/
INT16 WINAPI GetEnvironment16(LPCSTR lpPortName, LPDEVMODEA lpdev, UINT16 nMaxSize)
{
ATOM atom;
LPCSTR p;
ENVTABLE *env;
WORD size;
TRACE("('%s', %p, %d)\n", lpPortName, lpdev, nMaxSize);
if (!(atom = PortNameToAtom(lpPortName, FALSE)))
return 0;
if (atom == GDI_GetNullPortAtom())
if (!(atom = FindAtomA((LPCSTR)lpdev)))
return 0;
if (!(env = SearchEnvTable(atom)))
return 0;
size = GlobalSize16(env->handle);
if (!lpdev) return 0;
if (size < nMaxSize) nMaxSize = size;
if (!(p = GlobalLock16(env->handle))) return 0;
memcpy(lpdev, p, nMaxSize);
GlobalUnlock16(env->handle);
return nMaxSize;
}
/***********************************************************************
* SetEnvironment (GDI.132)
*/
INT16 WINAPI SetEnvironment16(LPCSTR lpPortName, LPDEVMODEA lpdev, UINT16 nCount)
{
ATOM atom;
BOOL16 nullport = FALSE;
LPCSTR port_name;
LPSTR device_mode;
ENVTABLE *env;
HGLOBAL16 handle;
TRACE("('%s', %p, %d)\n", lpPortName, lpdev, nCount);
if ((atom = PortNameToAtom(lpPortName, FALSE))) {
if (atom == GDI_GetNullPortAtom()) {
nullport = TRUE;
atom = FindAtomA((LPCSTR)lpdev);
}
env = SearchEnvTable(atom);
GlobalFree16(env->handle);
env->atom = 0;
}
if (nCount) { /* store DEVMODE struct */
if (nullport)
port_name = (LPSTR)lpdev;
else
port_name = lpPortName;
if ((atom = PortNameToAtom(port_name, TRUE))
&& (env = SearchEnvTable(0))
&& (handle = GlobalAlloc16(GMEM_SHARE|GMEM_MOVEABLE, nCount))) {
if (!(device_mode = GlobalLock16(handle))) {
GlobalFree16(handle);
return 0;
}
env->atom = atom;
env->handle = handle;
memcpy(device_mode, lpdev, nCount);
GlobalUnlock16(handle);
return handle;
}
else return 0;
}
else return -1;
}
================================================
FILE: gdi/gdi.c
================================================
/*
* GDI 16-bit functions
*
* Copyright 2002 Alexandre Julliard
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include
#include
#include
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "wownt32.h"
#define ExtDeviceMode WINAPI ExtDeviceMode
#include "winspool.h"
#undef ExtDeviceMode
#include "wine/wingdi16.h"
#include "wine/list.h"
#if 0
#include "wine/gdi_driver.h"
#endif
#include "wine/debug.h"
#include "wine/exception.h"
#define STRSAFE_NO_DEPRECATE
#include
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#define DIBINDEX(n) MAKELONG((n),0x10FF)
WINE_DEFAULT_DEBUG_CHANNEL(gdi);
//#define HGDIOBJ_32(handle16) ((HGDIOBJ)(ULONG_PTR)(handle16))
//#define HGDIOBJ_16(handle32) ((HGDIOBJ16)(ULONG_PTR)(handle32))
__declspec(dllimport) HGDIOBJ16 K32HGDIOBJ_16(HGDIOBJ handle);
__declspec(dllimport) HGDIOBJ K32HGDIOBJ_32(HGDIOBJ16 handle);
#define HGDIOBJ_32(handle16) (K32HGDIOBJ_32(handle16))
#define HGDIOBJ_16(handle32) (K32HGDIOBJ_16(handle32))
void WINAPI K32WOWHandle16Destroy(HANDLE handle, WOW_HANDLE_TYPE type);
static BYTE fix_font_charset(BYTE charset);
int WINAPI set_realized_palette(HDC hdc);
HPALETTE WINAPI get_realized_palette();
struct saved_visrgn
{
struct list entry;
HDC hdc;
HRGN hrgn;
};
static struct list saved_regions = LIST_INIT( saved_regions );
static HPALETTE16 hPrimaryPalette;
static UINT16 syspaluse = SYSPAL_STATIC;
static HGDIOBJ16 stock[STOCK_LAST + 2] = {0};
void WINAPI DibMapGlobalMemory(WORD sel, void *base, DWORD size);
void WINAPI DibUnmapGlobalMemory(void *base, DWORD size);
void WINAPI GlobalMapInternal(WORD sel, void *base, DWORD size);
struct dib_driver
{
struct list entry;
HDC hdc;
HANDLE hSection;
LPVOID map;
HBITMAP bitmap;
WORD selector;
DWORD size;
DWORD padding;
};
static struct list dib_drivers = LIST_INIT(dib_drivers);
// on windows 3.1 in 8bit color mode:
// RGB() is matched to the 20 system colors
// PALETTEINDEX() is a direct index to the dc palette, 0 if out of range
// PALETTERGB() is matched to the dc palette
// DIBINDEX() only applies to dib.drv dcs
// color is treated as RGB() unless high byte is exactly 1, 2 or high word 0x10ff for DIBINDEX()
//
// on windows 10 in 24bit color mode:
// RGB() is the direct color
// PALETTEINDEX() is a direct index to the dc palette, 0 if out of range
// PALETTERGB() is the direct color
// DIBINDEX() is 0 for non-dib dcs
// color is treated as PALETTEINDEX() if bit 16 is set else DIBINDEX() if bit 24 is set and byte 3 is 0xff
//
// ntvdm in 8bit color mode behaves like win3.1 with DIBINDEX()
static COLORREF check_colorref(COLORREF color)
{
int type = color >> 16;
if ((type != 0x10ff) && ((type & 0xff00) != 0x100) && ((type & 0xff00) != 0x200))
color &= 0xffffff;
return color;
}
// convert the colorref to a 8bpp dib compatible index value using the rules above
// GDI should just look up PALETTERGB in the dib palette
static COLORREF convert_colorref(COLORREF color)
{
int type = color >> 24;
int index;
switch (type)
{
case 0:
index = GetNearestPaletteIndex(GetStockObject(DEFAULT_PALETTE), color);
if (index >= 10) index += 236;
return DIBINDEX(index);
case 1:
return DIBINDEX(color & 0xff);
}
return color;
}
static void set_dib_colors(HDC hdc)
{
PALETTEENTRY pal[256] = {0};
GetPaletteEntries(GetCurrentObject(hdc, OBJ_PAL), 0, 256, &pal);
for (int i = 0; i < 256; i++)
{
BYTE tmp = pal[i].peRed;
pal[i].peRed = pal[i].peBlue;
pal[i].peBlue = tmp;
}
SetDIBColorTable(hdc, 0, 256, &pal);
}
// some programs such as pirates use a palette with start offset 0
// but the bitmap offsets every pixel by 10. this is used to shortcut the
// foreground palette reindex after realization. it works because windows
// will store the bitmap using foreground indexes but createbitmap and
// setbitmapbits bypasses that. other programs such as darkseed
// check the value of the foreground indexes before calling setbitmapbits.
// to make it work we'd have to reimplement all of gdi so just add a hack here
static void set_dib_colors_for_screen(HDC hdc)
{
char modulename[32];
GetModuleName16(GetCurrentTask(), modulename, 32);
if (strcmp(modulename, "WINPIR")) return set_dib_colors(hdc);
PALETTEENTRY pal[256] = {0};
PALETTEENTRY syspal[10];
PALETTEENTRY tmp;
GetPaletteEntries(GetCurrentObject(hdc, OBJ_PAL), 0, 256, &pal);
GetSystemPaletteEntries(hdc, 0, 10, &syspal);
for (int i = 235; i >= 0; i--)
{
tmp.peBlue = pal[i].peRed;
tmp.peGreen = pal[i].peGreen;
tmp.peRed = pal[i].peBlue;
pal[i + 10].peRed = tmp.peRed;
pal[i + 10].peGreen = tmp.peGreen;
pal[i + 10].peBlue = tmp.peBlue;
}
for (int i = 0; i < 10; i++)
{
pal[i].peBlue = syspal[i].peRed;
pal[i].peGreen = syspal[i].peGreen;
pal[i].peRed = syspal[i].peBlue;
}
SetDIBColorTable(hdc, 0, 256, &pal);
}
// hack so pirates won't read from the screen when the palette is blank
static BOOL is_blank_palette(HPALETTE hpal)
{
PALETTEENTRY pal[236];
int count = GetPaletteEntries(hpal, 0, 236, &pal);
for (int i = 0; i < count; i++)
{
if (((DWORD *)pal)[i] & 0xffffff)
return FALSE;
}
return TRUE;
}
/*
* ############################################################################
*/
#include
#define GDI_MAX_THUNKS 32
static struct gdi_thunk
{
BYTE popl_eax; /* popl %eax (return address) */
BYTE pushl_pfn16; /* pushl pfn16 */
DWORD pfn16; /* pfn16 */
BYTE pushl_eax; /* pushl %eax */
BYTE jmp; /* ljmp GDI_Callback3216 */
DWORD callback;
HDC16 hdc;
} *GDI_Thunks;
#include
/**********************************************************************
* GDI_Callback3216
*/
static BOOL CALLBACK GDI_Callback3216( DWORD pfn16, HDC hdc, INT code )
{
if (pfn16)
{
WORD args[2];
DWORD ret;
args[1] = HDC_16(hdc);
args[0] = code;
WOWCallback16Ex( pfn16, WCB16_PASCAL, sizeof(args), args, &ret );
return LOWORD(ret);
}
return TRUE;
}
/******************************************************************
* GDI_AddThunk
*
*/
static struct gdi_thunk* GDI_AddThunk(HDC16 dc16, ABORTPROC16 pfn16)
{
struct gdi_thunk* thunk;
if (!GDI_Thunks)
{
GDI_Thunks = VirtualAlloc(NULL, GDI_MAX_THUNKS * sizeof(*GDI_Thunks),
MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (!GDI_Thunks)
{
return NULL;
}
for (thunk = GDI_Thunks; thunk < &GDI_Thunks[GDI_MAX_THUNKS]; thunk++)
{
thunk->popl_eax = 0x58; /* popl %eax */
thunk->pushl_pfn16 = 0x68; /* pushl pfn16 */
thunk->pfn16 = 0;
thunk->pushl_eax = 0x50; /* pushl %eax */
thunk->jmp = 0xe9; /* jmp GDI_Callback3216 */
thunk->callback = (char *)GDI_Callback3216 - (char *)(&thunk->callback + 1);
}
}
for (thunk = GDI_Thunks; thunk < &GDI_Thunks[GDI_MAX_THUNKS]; thunk++)
{
if (thunk->pfn16 == 0)
{
thunk->pfn16 = (DWORD)pfn16;
thunk->hdc = dc16;
return thunk;
}
}
FIXME("Out of mmdrv-thunks. Bump GDI_MAX_THUNKS\n");
return NULL;
}
/******************************************************************
* GDI_DeleteThunk
*/
static void GDI_DeleteThunk(struct gdi_thunk* thunk)
{
thunk->pfn16 = 0;
}
/******************************************************************
* GDI_FindThunk
*/
static struct gdi_thunk* GDI_FindThunk(HDC16 hdc)
{
struct gdi_thunk* thunk;
if (!GDI_Thunks) return NULL;
for (thunk = GDI_Thunks; thunk < &GDI_Thunks[GDI_MAX_THUNKS]; thunk++)
{
if (thunk->hdc == hdc) return thunk;
}
return NULL;
}
/**********************************************************************
* QueryAbort (GDI.155)
*
* Calls the app's AbortProc function if avail.
*
* RETURNS
* TRUE if no AbortProc avail or AbortProc wants to continue printing.
* FALSE if AbortProc wants to abort printing.
*/
BOOL16 WINAPI QueryAbort16(HDC16 hdc16, INT16 reserved)
{
struct gdi_thunk* thunk = GDI_FindThunk(hdc16);
if (!thunk) {
ERR("Invalid hdc 0x%x\n", hdc16);
return FALSE;
}
return GDI_Callback3216( thunk->pfn16, HDC_32(hdc16), 0 );
}
/**********************************************************************
* SetAbortProc (GDI.381)
*/
INT16 WINAPI SetAbortProc16(HDC16 hdc16, ABORTPROC16 abrtprc)
{
struct gdi_thunk* thunk;
thunk = GDI_AddThunk(hdc16, abrtprc);
if (!thunk) return FALSE;
if (!SetAbortProc(HDC_32( hdc16 ), (ABORTPROC)thunk))
{
GDI_DeleteThunk(thunk);
return FALSE;
}
return TRUE;
}
/*
* ############################################################################
*/
struct callback16_info
{
FARPROC16 proc;
LPARAM param;
INT result;
};
/* callback for LineDDA16 */
static void CALLBACK linedda_callback( INT x, INT y, LPARAM param )
{
const struct callback16_info *info = (struct callback16_info *)param;
WORD args[4];
args[3] = x;
args[2] = y;
args[1] = HIWORD(info->param);
args[0] = LOWORD(info->param);
WOWCallback16Ex( (DWORD)info->proc, WCB16_PASCAL, sizeof(args), args, NULL );
}
/* callback for EnumObjects16 */
static INT CALLBACK enum_pens_callback( void *ptr, LPARAM param )
{
const struct callback16_info *info = (struct callback16_info *)param;
LOGPEN *pen = ptr;
LOGPEN16 pen16;
SEGPTR segptr;
DWORD ret;
WORD args[4];
pen16.lopnStyle = pen->lopnStyle;
pen16.lopnWidth.x = pen->lopnWidth.x;
pen16.lopnWidth.y = pen->lopnWidth.y;
pen16.lopnColor = pen->lopnColor;
segptr = MapLS( &pen16 );
args[3] = SELECTOROF(segptr);
args[2] = OFFSETOF(segptr);
args[1] = HIWORD(info->param);
args[0] = LOWORD(info->param);
WOWCallback16Ex( (DWORD)info->proc, WCB16_PASCAL, sizeof(args), args, &ret );
UnMapLS( segptr );
return LOWORD(ret);
}
/* callback for EnumObjects16 */
static INT CALLBACK enum_brushes_callback( void *ptr, LPARAM param )
{
const struct callback16_info *info = (struct callback16_info *)param;
LOGBRUSH *brush = ptr;
LOGBRUSH16 brush16;
SEGPTR segptr;
DWORD ret;
WORD args[4];
brush16.lbStyle = brush->lbStyle;
brush16.lbColor = brush->lbColor;
brush16.lbHatch = brush->lbHatch;
segptr = MapLS( &brush16 );
args[3] = SELECTOROF(segptr);
args[2] = OFFSETOF(segptr);
args[1] = HIWORD(info->param);
args[0] = LOWORD(info->param);
WOWCallback16Ex( (DWORD)info->proc, WCB16_PASCAL, sizeof(args), args, &ret );
UnMapLS( segptr );
return ret;
}
static BYTE fix_font_quality(LOGFONT16 *font16)
{
static BOOL init_enable_antialias;
static BOOL enable_antialias;
static BYTE force_font_quality;
if (!init_enable_antialias)
{
init_enable_antialias = TRUE;
enable_antialias = krnl386_get_config_int("otvdm", "EnableFontAntialias", FALSE);
force_font_quality = (BYTE)krnl386_get_config_int("otvdm", "ForceFontQuality", -1);
}
if (font16->lfWidth && font16->lfHeight)
return font16->lfQuality;
if (force_font_quality != (BYTE)-1)
return force_font_quality;
if (enable_antialias)
return font16->lfQuality;
return NONANTIALIASED_QUALITY;
}
/* convert a LOGFONT16 to a LOGFONTA */
static void logfont_16_to_A( const LOGFONT16 *font16, LPLOGFONTA font32 )
{
font32->lfHeight = font16->lfHeight;
font32->lfWidth = font16->lfWidth;
font32->lfEscapement = font16->lfEscapement;
font32->lfOrientation = font16->lfOrientation;
font32->lfWeight = font16->lfWeight;
font32->lfItalic = font16->lfItalic;
font32->lfUnderline = font16->lfUnderline;
font32->lfStrikeOut = font16->lfStrikeOut;
font32->lfCharSet = fix_font_charset(font16->lfCharSet);
font32->lfOutPrecision = font16->lfOutPrecision;
font32->lfClipPrecision = font16->lfClipPrecision;
font32->lfQuality = fix_font_quality(font16);
font32->lfPitchAndFamily = font16->lfPitchAndFamily;
memcpy(font32->lfFaceName, font16->lfFaceName, LF_FACESIZE);
font32->lfFaceName[LF_FACESIZE-1] = 0;
}
/* convert a LOGFONTA to a LOGFONT16 */
static void logfont_A_to_16( const LOGFONTA* font32, LPLOGFONT16 font16 )
{
font16->lfHeight = font32->lfHeight;
font16->lfWidth = font32->lfWidth;
font16->lfEscapement = font32->lfEscapement;
font16->lfOrientation = font32->lfOrientation;
font16->lfWeight = font32->lfWeight;
font16->lfItalic = font32->lfItalic;
font16->lfUnderline = font32->lfUnderline;
font16->lfStrikeOut = font32->lfStrikeOut;
font16->lfCharSet = font32->lfCharSet;
font16->lfOutPrecision = font32->lfOutPrecision;
font16->lfClipPrecision = font32->lfClipPrecision;
font16->lfQuality = font32->lfQuality;
font16->lfPitchAndFamily = font32->lfPitchAndFamily;
memcpy(font16->lfFaceName, font32->lfFaceName, LF_FACESIZE);
font16->lfFaceName[LF_FACESIZE-1] = 0;
}
/* convert a ENUMLOGFONTEXA to a ENUMLOGFONTEX16 */
static void enumlogfontex_A_to_16( const ENUMLOGFONTEXA *fontA,
LPENUMLOGFONTEX16 font16 )
{
logfont_A_to_16( (const LOGFONTA *)fontA, (LPLOGFONT16)font16);
memcpy(font16->elfFullName, fontA->elfFullName, LF_FULLFACESIZE);
font16->elfFullName[LF_FULLFACESIZE-1] = '\0';
memcpy(font16->elfStyle, fontA->elfStyle, LF_FACESIZE);
font16->elfStyle[LF_FACESIZE-1] = '\0';
memcpy(font16->elfScript, fontA->elfScript, LF_FACESIZE);
font16->elfScript[LF_FACESIZE-1] = '\0';
}
/* convert a NEWTEXTMETRICEXA to a NEWTEXTMETRICEX16 */
static void newtextmetricex_A_to_16( const NEWTEXTMETRICEXA *ptmA,
LPNEWTEXTMETRICEX16 ptm16 )
{
ptm16->ntmTm.tmHeight = ptmA->ntmTm.tmHeight;
ptm16->ntmTm.tmAscent = ptmA->ntmTm.tmAscent;
ptm16->ntmTm.tmDescent = ptmA->ntmTm.tmDescent;
ptm16->ntmTm.tmInternalLeading = ptmA->ntmTm.tmInternalLeading;
ptm16->ntmTm.tmExternalLeading = ptmA->ntmTm.tmExternalLeading;
ptm16->ntmTm.tmAveCharWidth = ptmA->ntmTm.tmAveCharWidth;
ptm16->ntmTm.tmMaxCharWidth = ptmA->ntmTm.tmMaxCharWidth;
ptm16->ntmTm.tmWeight = ptmA->ntmTm.tmWeight;
ptm16->ntmTm.tmOverhang = ptmA->ntmTm.tmOverhang;
ptm16->ntmTm.tmDigitizedAspectX = ptmA->ntmTm.tmDigitizedAspectX;
ptm16->ntmTm.tmDigitizedAspectY = ptmA->ntmTm.tmDigitizedAspectY;
ptm16->ntmTm.tmFirstChar = ptmA->ntmTm.tmFirstChar;
ptm16->ntmTm.tmLastChar = ptmA->ntmTm.tmLastChar;
ptm16->ntmTm.tmDefaultChar = ptmA->ntmTm.tmDefaultChar;
ptm16->ntmTm.tmBreakChar = ptmA->ntmTm.tmBreakChar;
ptm16->ntmTm.tmItalic = ptmA->ntmTm.tmItalic;
ptm16->ntmTm.tmUnderlined = ptmA->ntmTm.tmUnderlined;
ptm16->ntmTm.tmStruckOut = ptmA->ntmTm.tmStruckOut;
ptm16->ntmTm.tmPitchAndFamily = ptmA->ntmTm.tmPitchAndFamily;
ptm16->ntmTm.tmCharSet = ptmA->ntmTm.tmCharSet;
ptm16->ntmTm.ntmFlags = ptmA->ntmTm.ntmFlags;
ptm16->ntmTm.ntmSizeEM = ptmA->ntmTm.ntmSizeEM;
ptm16->ntmTm.ntmCellHeight = ptmA->ntmTm.ntmCellHeight;
ptm16->ntmTm.ntmAvgWidth = ptmA->ntmTm.ntmAvgWidth;
ptm16->ntmFontSig = ptmA->ntmFontSig;
}
static const char *font_list[] =
{
"\x82\x6c\x82\x72 \x83\x53\x83\x56\x83\x62\x83\x4e", /* MS Gothic (Japanese font) */
"\x82\x6c\x82\x72 \x96\xbe\x92\xa9", /* MS Mincho (Japanese font) */
"Arial",
"Courier New",
"Times New Roman",
"Wingdings",
"Symbol",
"CenturyOldst",
"Arial Narrow",
"Book Antiqua",
"Bookman Old Style",
"Century Gothic",
"Century Schoolbook",
"Monotype Corsiva",
"Monotype Sorts",
"Fences",
"MT Extra",
"Monotype Sorts",
"System",
"FixedSys",
"Modern",
"Script",
"Terminal",
"Roman",
"Small Fonts",
"MS Serif",
"MS Dialog",
"MS Sans Serif",
"MS LineDraw",
"Century",
"Algerian",
"Arial Rounded MT Bold",
"Braggadocio",
"Britannic Bold",
"Brush Script MT",
"Colonna MT",
"Desdemona",
"Footlight MT Light",
"Impact",
"Kino MT",
"Wide Latin",
"Matura MT Script Capitals",
"Playbill",
"Courier",
"Helvetica",
"Helv",
"Times",
"ITC Avant Garde Gothic",
"ITC Bookman",
"New Century Schoolbook",
"Palatino",
"ITC Zapf Chancery",
"ITC Zapf Dingbats",
"AvantGarde",
"Bookman",
"NewCenturySchlbk",
"Palatino",
"ZapfChancery",
"ZapfDingbats",
"AvantGarde",
"Bookman",
"NewCenturySchlbk",
"Palatino",
"ZapfChancery",
"ZapfDingbats",
NULL
};
static struct list font_allowed_list = LIST_INIT(font_allowed_list);
static struct list font_disallowed_list = LIST_INIT(font_disallowed_list);
struct font_entry
{
struct list entry;
const char *font_name;
};
static void construct_allowed_font_list()
{
int buf_size = 2048;
LPSTR font = HeapAlloc(GetProcessHeap(), 0, buf_size);
while (TRUE)
{
DWORD size = krnl386_get_config_string("EnumFontLimitation", NULL, "", font, buf_size);
if (size < buf_size)
{
break;
}
buf_size *= 2;
font = HeapReAlloc(GetProcessHeap(), 0, font, buf_size);
}
while (TRUE)
{
size_t len = strlen(font);
struct font_entry *elem;
BOOL allowed;
if (len == 0)
break;
elem = (struct font_entry*)HeapAlloc(GetProcessHeap(), 0, sizeof(*elem));
allowed = krnl386_get_config_int("EnumFontLimitation", font, 1);
elem->font_name = font;
if (allowed)
{
list_add_tail(&font_allowed_list, &elem->entry);
}
else
{
list_add_tail(&font_disallowed_list, &elem->entry);
}
font += len + 1;
}
}
/*
* callback for EnumFontFamiliesEx16
* Note: plf is really an ENUMLOGFONTEXA, and ptm is a NEWTEXTMETRICEXA.
* We have to use other types because of the FONTENUMPROCA definition.
*/
static INT CALLBACK enum_font_callback( const LOGFONTA *plf,
const TEXTMETRICA *ptm, DWORD fType,
LPARAM param )
{
struct callback16_info *info = (struct callback16_info *)param;
ENUMLOGFONTEX16 elfe16;
NEWTEXTMETRICEX16 ntm16;
SEGPTR segelfe16;
SEGPTR segntm16;
WORD args[7];
DWORD ret;
static BOOL enum_font_limitation_init;
static BOOL enum_font_limitation;
enumlogfontex_A_to_16((const ENUMLOGFONTEXA *)plf, &elfe16);
newtextmetricex_A_to_16((const NEWTEXTMETRICEXA *)ptm, &ntm16);
/* some old programs can not process many fonts(1000+) */
if (!enum_font_limitation_init)
{
enum_font_limitation_init = TRUE;
enum_font_limitation = krnl386_get_config_int("otvdm", "EnumFontLimitation", FALSE);
if (enum_font_limitation)
{
construct_allowed_font_list();
}
}
if (enum_font_limitation)
{
/* TODO: configurable */
int i;
BOOL found = FALSE;
struct font_entry *font;
BOOL disallow = FALSE;
LIST_FOR_EACH_ENTRY(font, &font_disallowed_list, struct font_entry, entry)
{
if (!stricmp(elfe16.elfLogFont.lfFaceName, font->font_name))
{
disallow = TRUE;
break;
}
}
if (!disallow)
{
for (i = 0; font_list[i]; i++)
{
if (!stricmp(elfe16.elfLogFont.lfFaceName, font_list[i]))
{
found = TRUE;
break;
}
}
}
if (!found && !disallow)
{
LIST_FOR_EACH_ENTRY(font, &font_allowed_list, struct font_entry, entry)
{
if (!stricmp(elfe16.elfLogFont.lfFaceName, font->font_name))
{
found = TRUE;
break;
}
}
}
if (!found)
{
TRACE("font %s skipped.\n", elfe16.elfLogFont.lfFaceName);
return info->result;
}
}
segelfe16 = MapLS( &elfe16 );
segntm16 = MapLS( &ntm16 );
args[6] = SELECTOROF(segelfe16);
args[5] = OFFSETOF(segelfe16);
args[4] = SELECTOROF(segntm16);
args[3] = OFFSETOF(segntm16);
args[2] = fType;
args[1] = HIWORD(info->param);
args[0] = LOWORD(info->param);
WOWCallback16Ex( (DWORD)info->proc, WCB16_PASCAL, sizeof(args), args, &ret );
UnMapLS( segelfe16 );
UnMapLS( segntm16 );
return info->result = LOWORD(ret);
}
struct dib_segptr_bits
{
struct list entry;
HBITMAP16 bmp;
WORD sel;
WORD count;
};
static struct list dib_segptr_list = LIST_INIT( dib_segptr_list );
static SEGPTR alloc_segptr_bits( HBITMAP bmp, void *bits32 )
{
DIBSECTION dib;
unsigned int i, size;
struct dib_segptr_bits *bits;
if (!(bits = HeapAlloc( GetProcessHeap(), 0, sizeof(*bits) ))) return 0;
GetObjectW( bmp, sizeof(dib), &dib );
size = dib.dsBm.bmHeight * dib.dsBm.bmWidthBytes;
/* calculate number of sel's needed for size with 64K steps */
bits->bmp = HBITMAP_16( bmp );
bits->count = (size + 0xffff) / 0x10000;
bits->sel = AllocSelectorArray16( bits->count );
GlobalMapInternal(bits->sel, bits32, size);
for (i = 0; i < bits->count; i++)
{
SetSelectorBase(bits->sel + (i << __AHSHIFT), (DWORD)bits32 + i * 0x10000);
SetSelectorLimit16(bits->sel + (i << __AHSHIFT), size - 1); /* yep, limit is correct */
size -= 0x10000;
}
list_add_head( &dib_segptr_list, &bits->entry );
return MAKESEGPTR( bits->sel, 0 );
}
static void free_segptr_bits( HBITMAP16 bmp )
{
unsigned int i;
struct dib_segptr_bits *bits;
LIST_FOR_EACH_ENTRY( bits, &dib_segptr_list, struct dib_segptr_bits, entry )
{
if (bits->bmp != bmp) continue;
for (i = 0; i < bits->count; i++) FreeSelector16( bits->sel + (i << __AHSHIFT) );
GlobalMapInternal(bits->sel, NULL, 0);
list_remove( &bits->entry );
HeapFree( GetProcessHeap(), 0, bits );
return;
}
}
#if 0
/* window surface used to implement the DIB.DRV driver */
struct dib_window_surface
{
struct window_surface header;
RECT bounds;
void *bits;
UINT info_size;
BITMAPINFO info; /* variable size, must be last */
};
static struct dib_window_surface *get_dib_surface( struct window_surface *surface )
{
return (struct dib_window_surface *)surface;
}
/***********************************************************************
* dib_surface_lock
*/
static void dib_surface_lock( struct window_surface *window_surface )
{
/* nothing to do */
}
/***********************************************************************
* dib_surface_unlock
*/
static void dib_surface_unlock( struct window_surface *window_surface )
{
/* nothing to do */
}
/***********************************************************************
* dib_surface_get_bitmap_info
*/
static void *dib_surface_get_bitmap_info( struct window_surface *window_surface, BITMAPINFO *info )
{
struct dib_window_surface *surface = get_dib_surface( window_surface );
memcpy( info, &surface->info, surface->info_size );
return surface->bits;
}
/***********************************************************************
* dib_surface_get_bounds
*/
static RECT *dib_surface_get_bounds( struct window_surface *window_surface )
{
struct dib_window_surface *surface = get_dib_surface( window_surface );
return &surface->bounds;
}
/***********************************************************************
* dib_surface_set_region
*/
static void dib_surface_set_region( struct window_surface *window_surface, HRGN region )
{
/* nothing to do */
}
/***********************************************************************
* dib_surface_flush
*/
static void dib_surface_flush( struct window_surface *window_surface )
{
/* nothing to do */
}
/***********************************************************************
* dib_surface_destroy
*/
static void dib_surface_destroy( struct window_surface *window_surface )
{
struct dib_window_surface *surface = get_dib_surface( window_surface );
TRACE( "freeing %p\n", surface );
HeapFree( GetProcessHeap(), 0, surface );
}
static const struct window_surface_funcs dib_surface_funcs =
{
dib_surface_lock,
dib_surface_unlock,
dib_surface_get_bitmap_info,
dib_surface_get_bounds,
dib_surface_set_region,
dib_surface_flush,
dib_surface_destroy
};
/***********************************************************************
* create_surface
*/
static struct window_surface *create_surface( const BITMAPINFO *info )
{
struct dib_window_surface *surface;
int color = 0;
if (info->bmiHeader.biBitCount <= 8)
color = info->bmiHeader.biClrUsed ? info->bmiHeader.biClrUsed : (1 << info->bmiHeader.biBitCount);
else if (info->bmiHeader.biCompression == BI_BITFIELDS)
color = 3;
surface = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
offsetof( struct dib_window_surface, info.bmiColors[color] ));
if (!surface) return NULL;
surface->header.funcs = &dib_surface_funcs;
surface->header.rect.left = 0;
surface->header.rect.top = 0;
surface->header.rect.right = info->bmiHeader.biWidth;
surface->header.rect.bottom = abs(info->bmiHeader.biHeight);
surface->header.ref = 1;
surface->info_size = offsetof( BITMAPINFO, bmiColors[color] );
surface->bits = (char *)info + surface->info_size;
memcpy( &surface->info, info, surface->info_size );
TRACE( "created %p %ux%u for info %p bits %p\n",
surface, surface->header.rect.right, surface->header.rect.bottom, info, surface->bits );
return &surface->header;
}
#endif
/***********************************************************************
* SetBkColor (GDI.1)
*/
COLORREF WINAPI SetBkColor16( HDC16 hdc, COLORREF color )
{
return SetBkColor( HDC_32(hdc), check_colorref(color) );
}
/***********************************************************************
* SetBkMode (GDI.2)
*/
INT16 WINAPI SetBkMode16( HDC16 hdc, INT16 mode )
{
return SetBkMode( HDC_32(hdc), mode );
}
/***********************************************************************
* SetMapMode (GDI.3)
*/
INT16 WINAPI SetMapMode16( HDC16 hdc, INT16 mode )
{
return SetMapMode( HDC_32(hdc), mode );
}
/***********************************************************************
* SetROP2 (GDI.4)
*/
INT16 WINAPI SetROP216( HDC16 hdc, INT16 mode )
{
return SetROP2( HDC_32(hdc), mode );
}
INT WINAPI SetRelAbs(HDC hdc,
INT Mode
);
/***********************************************************************
* SetRelAbs (GDI.5)
*/
INT16 WINAPI SetRelAbs16( HDC16 hdc, INT16 mode )
{
return SetRelAbs( HDC_32(hdc), mode );
}
/***********************************************************************
* SetPolyFillMode (GDI.6)
*/
INT16 WINAPI SetPolyFillMode16( HDC16 hdc, INT16 mode )
{
return SetPolyFillMode( HDC_32(hdc), mode );
}
/***********************************************************************
* SetStretchBltMode (GDI.7)
*/
INT16 WINAPI SetStretchBltMode16( HDC16 hdc, INT16 mode )
{
return SetStretchBltMode( HDC_32(hdc), mode );
}
/***********************************************************************
* SetTextCharacterExtra (GDI.8)
*/
INT16 WINAPI SetTextCharacterExtra16( HDC16 hdc, INT16 extra )
{
return SetTextCharacterExtra( HDC_32(hdc), extra );
}
/***********************************************************************
* SetTextColor (GDI.9)
*/
COLORREF WINAPI SetTextColor16( HDC16 hdc, COLORREF color )
{
return SetTextColor( HDC_32(hdc), check_colorref(color) );
}
/***********************************************************************
* SetTextJustification (GDI.10)
*/
INT16 WINAPI SetTextJustification16( HDC16 hdc, INT16 extra, INT16 breaks )
{
return SetTextJustification( HDC_32(hdc), extra, breaks );
}
/***********************************************************************
* SetWindowOrg (GDI.11)
*/
DWORD WINAPI SetWindowOrg16( HDC16 hdc, INT16 x, INT16 y )
{
POINT pt;
if (!SetWindowOrgEx( HDC_32(hdc), x, y, &pt )) return 0;
return MAKELONG( pt.x, pt.y );
}
/***********************************************************************
* SetWindowExt (GDI.12)
*/
DWORD WINAPI SetWindowExt16( HDC16 hdc, INT16 x, INT16 y )
{
SIZE size;
if (!SetWindowExtEx( HDC_32(hdc), x, y, &size )) return 0;
return MAKELONG( size.cx, size.cy );
}
/***********************************************************************
* SetViewportOrg (GDI.13)
*/
DWORD WINAPI SetViewportOrg16( HDC16 hdc, INT16 x, INT16 y )
{
POINT pt;
if (!SetViewportOrgEx( HDC_32(hdc), x, y, &pt )) return 0;
return MAKELONG( pt.x, pt.y );
}
/***********************************************************************
* SetViewportExt (GDI.14)
*/
DWORD WINAPI SetViewportExt16( HDC16 hdc, INT16 x, INT16 y )
{
SIZE size;
if (!SetViewportExtEx( HDC_32(hdc), x, y, &size )) return 0;
return MAKELONG( size.cx, size.cy );
}
/***********************************************************************
* OffsetWindowOrg (GDI.15)
*/
DWORD WINAPI OffsetWindowOrg16( HDC16 hdc, INT16 x, INT16 y )
{
POINT pt;
if (!OffsetWindowOrgEx( HDC_32(hdc), x, y, &pt )) return 0;
return MAKELONG( pt.x, pt.y );
}
/***********************************************************************
* ScaleWindowExt (GDI.16)
*/
DWORD WINAPI ScaleWindowExt16( HDC16 hdc, INT16 xNum, INT16 xDenom,
INT16 yNum, INT16 yDenom )
{
SIZE size;
if (!ScaleWindowExtEx( HDC_32(hdc), xNum, xDenom, yNum, yDenom, &size ))
return FALSE;
return MAKELONG( size.cx, size.cy );
}
/***********************************************************************
* OffsetViewportOrg (GDI.17)
*/
DWORD WINAPI OffsetViewportOrg16( HDC16 hdc, INT16 x, INT16 y )
{
POINT pt;
if (!OffsetViewportOrgEx( HDC_32(hdc), x, y, &pt )) return 0;
return MAKELONG( pt.x, pt.y );
}
/***********************************************************************
* ScaleViewportExt (GDI.18)
*/
DWORD WINAPI ScaleViewportExt16( HDC16 hdc, INT16 xNum, INT16 xDenom,
INT16 yNum, INT16 yDenom )
{
SIZE size;
if (!ScaleViewportExtEx( HDC_32(hdc), xNum, xDenom, yNum, yDenom, &size ))
return FALSE;
return MAKELONG( size.cx, size.cy );
}
/***********************************************************************
* LineTo (GDI.19)
*/
BOOL16 WINAPI LineTo16( HDC16 hdc, INT16 x, INT16 y )
{
return LineTo( HDC_32(hdc), x, y );
}
/***********************************************************************
* MoveTo (GDI.20)
*/
DWORD WINAPI MoveTo16( HDC16 hdc, INT16 x, INT16 y )
{
POINT pt;
if (!MoveToEx( HDC_32(hdc), x, y, &pt )) return 0;
return MAKELONG(pt.x,pt.y);
}
/***********************************************************************
* ExcludeClipRect (GDI.21)
*/
INT16 WINAPI ExcludeClipRect16( HDC16 hdc, INT16 left, INT16 top,
INT16 right, INT16 bottom )
{
return ExcludeClipRect( HDC_32(hdc), left, top, right, bottom );
}
/***********************************************************************
* IntersectClipRect (GDI.22)
*/
INT16 WINAPI IntersectClipRect16( HDC16 hdc, INT16 left, INT16 top,
INT16 right, INT16 bottom )
{
return IntersectClipRect( HDC_32(hdc), left, top, right, bottom );
}
/***********************************************************************
* Arc (GDI.23)
*/
BOOL16 WINAPI Arc16( HDC16 hdc, INT16 left, INT16 top, INT16 right,
INT16 bottom, INT16 xstart, INT16 ystart,
INT16 xend, INT16 yend )
{
return Arc( HDC_32(hdc), left, top, right, bottom, xstart, ystart, xend, yend );
}
/***********************************************************************
* Ellipse (GDI.24)
*/
BOOL16 WINAPI Ellipse16( HDC16 hdc, INT16 left, INT16 top,
INT16 right, INT16 bottom )
{
return Ellipse( HDC_32(hdc), left, top, right, bottom );
}
/**********************************************************************
* FloodFill (GDI.25)
*/
BOOL16 WINAPI FloodFill16( HDC16 hdc, INT16 x, INT16 y, COLORREF color )
{
return ExtFloodFill( HDC_32(hdc), x, y, check_colorref(color), FLOODFILLBORDER );
}
/***********************************************************************
* Pie (GDI.26)
*/
BOOL16 WINAPI Pie16( HDC16 hdc, INT16 left, INT16 top,
INT16 right, INT16 bottom, INT16 xstart, INT16 ystart,
INT16 xend, INT16 yend )
{
return Pie( HDC_32(hdc), left, top, right, bottom, xstart, ystart, xend, yend );
}
/***********************************************************************
* Rectangle (GDI.27)
*/
BOOL16 WINAPI Rectangle16( HDC16 hdc, INT16 left, INT16 top,
INT16 right, INT16 bottom )
{
return Rectangle( HDC_32(hdc), left, top, right, bottom );
}
/***********************************************************************
* RoundRect (GDI.28)
*/
BOOL16 WINAPI RoundRect16( HDC16 hdc, INT16 left, INT16 top, INT16 right,
INT16 bottom, INT16 ell_width, INT16 ell_height )
{
return RoundRect( HDC_32(hdc), left, top, right, bottom, ell_width, ell_height );
}
/***********************************************************************
* PatBlt (GDI.29)
*/
BOOL16 WINAPI PatBlt16( HDC16 hdc, INT16 left, INT16 top,
INT16 width, INT16 height, DWORD rop)
{
return PatBlt( HDC_32(hdc), left, top, width, height, rop );
}
/***********************************************************************
* SaveDC (GDI.30)
*/
INT16 WINAPI SaveDC16( HDC16 hdc )
{
return SaveDC( HDC_32(hdc) );
}
/***********************************************************************
* SetPixel (GDI.31)
*/
COLORREF WINAPI SetPixel16( HDC16 hdc, INT16 x, INT16 y, COLORREF color )
{
return SetPixel( HDC_32(hdc), x, y, check_colorref(color) );
}
/***********************************************************************
* OffsetClipRgn (GDI.32)
*/
INT16 WINAPI OffsetClipRgn16( HDC16 hdc, INT16 x, INT16 y )
{
return OffsetClipRgn( HDC_32(hdc), x, y );
}
/***********************************************************************
* TextOut (GDI.33)
*/
BOOL16 WINAPI TextOut16( HDC16 hdc, INT16 x, INT16 y, LPCSTR str, INT16 count )
{
return TextOutA( HDC_32(hdc), x, y, str, count );
}
/***********************************************************************
* BitBlt (GDI.34)
*/
BOOL16 WINAPI BitBlt16( HDC16 hdcDst, INT16 xDst, INT16 yDst, INT16 width,
INT16 height, HDC16 hdcSrc, INT16 xSrc, INT16 ySrc,
DWORD rop )
{
return StretchBlt16(hdcDst, xDst, yDst, width, height, hdcSrc, xSrc, ySrc, width, height, rop);
}
/***********************************************************************
* StretchBlt (GDI.35)
*/
BOOL16 WINAPI StretchBlt16( HDC16 hdcDst, INT16 xDst, INT16 yDst,
INT16 widthDst, INT16 heightDst,
HDC16 hdcSrc, INT16 xSrc, INT16 ySrc,
INT16 widthSrc, INT16 heightSrc, DWORD rop )
{
HDC hdcsrc32 = HDC_32(hdcSrc);
HDC hdcdst32 = HDC_32(hdcDst);
if (krnl386_get_compat_mode("256color") && krnl386_get_config_int("otvdm", "DIBPalette", FALSE) && (GetDeviceCaps(hdcsrc32, TECHNOLOGY) == DT_RASDISPLAY))
{
DIBSECTION dib, dibdst;
HBITMAP hbmp = GetCurrentObject(hdcsrc32, OBJ_BITMAP);
int count = GetObject(hbmp, sizeof(DIBSECTION), &dib);
HBITMAP hbmpdst = GetCurrentObject(hdcdst32, OBJ_BITMAP);
int countdst = GetObject(hbmpdst, sizeof(DIBSECTION), &dibdst);
BOOL srcdib, dstdib;
if ((count == sizeof(DIBSECTION)) && (dib.dsBmih.biBitCount == 8) && !dib.dshSection && (GetPtr16(HBITMAP_16(hbmp), 1) == 0xd1b00001))
srcdib = TRUE;
if ((countdst == sizeof(DIBSECTION)) && (dibdst.dsBmih.biBitCount == 8) && !dibdst.dshSection && (GetPtr16(HBITMAP_16(hbmpdst), 1) == 0xd1b00001))
dstdib = TRUE;
if (srcdib && (GetObjectType(hdcdst32) == OBJ_DC))
{
HPALETTE realpal = get_realized_palette();
if (realpal != GetStockObject(DEFAULT_PALETTE))
{
HPALETTE oldpal = SelectPalette(hdcsrc32, realpal, FALSE);
set_dib_colors_for_screen(hdcsrc32);
BOOL16 ret = StretchBlt(hdcdst32, xDst, yDst, widthDst, heightDst, hdcsrc32, xSrc, ySrc, widthSrc, heightSrc, rop);
SelectPalette(hdcsrc32, oldpal, FALSE);
set_dib_colors(hdcsrc32);
return ret;
}
}
if (dstdib && (GetObjectType(hdcsrc32) == OBJ_DC))
{
HPALETTE realpal = get_realized_palette();
if (realpal != GetStockObject(DEFAULT_PALETTE))
{
if (is_blank_palette(realpal)) return 0;
HPALETTE oldpal = SelectPalette(hdcdst32, realpal, FALSE);
set_dib_colors_for_screen(hdcdst32);
BOOL16 ret = StretchBlt(hdcdst32, xDst, yDst, widthDst, heightDst, hdcsrc32, xSrc, ySrc, widthSrc, heightSrc, rop);
SelectPalette(hdcdst32, oldpal, FALSE);
set_dib_colors(hdcdst32);
return ret;
}
}
if (dstdib && (dib.dsBm.bmBitsPixel == 1))
{
COLORREF txcolor = GetTextColor(hdcdst32);
COLORREF bkcolor = GetBkColor(hdcdst32);
SetTextColor(hdcdst32, convert_colorref(txcolor));
SetBkColor(hdcdst32, convert_colorref(bkcolor));
BOOL16 ret = StretchBlt(hdcdst32, xDst, yDst, widthDst, heightDst, hdcsrc32, xSrc, ySrc, widthSrc, heightSrc, rop);
SetTextColor(hdcdst32, txcolor);
SetBkColor(hdcdst32, bkcolor);
return ret;
}
if (srcdib && (dibdst.dsBm.bmBitsPixel == 1))
{
COLORREF bkcolor = GetBkColor(hdcsrc32);
SetBkColor(hdcsrc32, convert_colorref(bkcolor));
BOOL16 ret = StretchBlt(hdcdst32, xDst, yDst, widthDst, heightDst, hdcsrc32, xSrc, ySrc, widthSrc, heightSrc, rop);
SetBkColor(hdcsrc32, bkcolor);
return ret;
}
}
return StretchBlt(hdcdst32, xDst, yDst, widthDst, heightDst, hdcsrc32, xSrc, ySrc, widthSrc, heightSrc, rop);
}
/**********************************************************************
* Polygon (GDI.36)
*/
BOOL16 WINAPI Polygon16( HDC16 hdc, const POINT16* pt, INT16 count )
{
int i;
BOOL ret;
LPPOINT pt32 = HeapAlloc( GetProcessHeap(), 0, count*sizeof(POINT) );
if (!pt32) return FALSE;
for (i=count;i--;)
{
pt32[i].x = pt[i].x;
pt32[i].y = pt[i].y;
}
ret = Polygon(HDC_32(hdc),pt32,count);
HeapFree( GetProcessHeap(), 0, pt32 );
return ret;
}
/**********************************************************************
* Polyline (GDI.37)
*/
BOOL16 WINAPI Polyline16( HDC16 hdc, const POINT16* pt, INT16 count )
{
int i;
BOOL16 ret;
LPPOINT pt32 = HeapAlloc( GetProcessHeap(), 0, count*sizeof(POINT) );
if (!pt32) return FALSE;
for (i=count;i--;)
{
pt32[i].x = pt[i].x;
pt32[i].y = pt[i].y;
}
ret = Polyline(HDC_32(hdc),pt32,count);
HeapFree( GetProcessHeap(), 0, pt32 );
return ret;
}
/***********************************************************************
* Escape (GDI.38)
*/
INT16 WINAPI Escape16( HDC16 hdc, INT16 escape, INT16 in_count, SEGPTR in_data, LPVOID out_data )
{
INT ret;
switch(escape)
{
/* Escape(hdc,CLIP_TO_PATH,LPINT16,NULL) */
/* Escape(hdc,DRAFTMODE,LPINT16,NULL) */
/* Escape(hdc,ENUMPAPERBINS,LPINT16,LPSTR); */
/* Escape(hdc,EPSPRINTING,LPINT16,NULL) */
/* Escape(hdc,EXT_DEVICE_CAPS,LPINT16,LPDWORD) */
/* Escape(hdc,GETCOLORTABLE,LPINT16,LPDWORD) */
/* Escape(hdc,MOUSETRAILS,LPINT16,NULL) */
/* Escape(hdc,POSTSCRIPT_IGNORE,LPINT16,NULL) */
/* Escape(hdc,QUERYESCSUPPORT,LPINT16,NULL) */
/* Escape(hdc,SET_ARC_DIRECTION,LPINT16,NULL) */
/* Escape(hdc,SET_POLY_MODE,LPINT16,NULL) */
/* Escape(hdc,SET_SCREEN_ANGLE,LPINT16,NULL) */
/* Escape(hdc,SET_SPREAD,LPINT16,NULL) */
case CLIP_TO_PATH:
case DRAFTMODE:
case ENUMPAPERBINS:
case EPSPRINTING:
case EXT_DEVICE_CAPS:
case GETCOLORTABLE:
case MOUSETRAILS:
case POSTSCRIPT_IGNORE:
case QUERYESCSUPPORT:
case SET_ARC_DIRECTION:
case SET_POLY_MODE:
case SET_SCREEN_ANGLE:
case SET_SPREAD:
{
INT16 *ptr = MapSL(in_data);
INT data = *ptr;
return Escape( HDC_32(hdc), escape, sizeof(data), (LPCSTR)&data, out_data );
}
/* Escape(hdc,ENABLEDUPLEX,LPUINT16,NULL) */
case ENABLEDUPLEX:
{
UINT16 *ptr = MapSL(in_data);
UINT data = *ptr;
return Escape( HDC_32(hdc), escape, sizeof(data), (LPCSTR)&data, NULL );
}
/* Escape(hdc,GETPHYSPAGESIZE,NULL,LPPOINT16) */
/* Escape(hdc,GETPRINTINGOFFSET,NULL,LPPOINT16) */
/* Escape(hdc,GETSCALINGFACTOR,NULL,LPPOINT16) */
case GETPHYSPAGESIZE:
case GETPRINTINGOFFSET:
case GETSCALINGFACTOR:
{
POINT16 *ptr = out_data;
POINT pt32;
ret = Escape( HDC_32(hdc), escape, 0, NULL, &pt32 );
ptr->x = pt32.x;
ptr->y = pt32.y;
return ret;
}
/* Escape(hdc,ENABLEPAIRKERNING,LPINT16,LPINT16); */
/* Escape(hdc,ENABLERELATIVEWIDTHS,LPINT16,LPINT16); */
/* Escape(hdc,SETCOPYCOUNT,LPINT16,LPINT16) */
/* Escape(hdc,SETKERNTRACK,LPINT16,LPINT16) */
/* Escape(hdc,SETLINECAP,LPINT16,LPINT16) */
/* Escape(hdc,SETLINEJOIN,LPINT16,LPINT16) */
/* Escape(hdc,SETMITERLIMIT,LPINT16,LPINT16) */
case ENABLEPAIRKERNING:
case ENABLERELATIVEWIDTHS:
case SETCOPYCOUNT:
case SETKERNTRACK:
case SETLINECAP:
case SETLINEJOIN:
case SETMITERLIMIT:
case SETCHARSET:
{
INT16 *new = MapSL(in_data);
INT16 *old = out_data;
INT out, in = *new;
ret = Escape( HDC_32(hdc), escape, sizeof(in), (LPCSTR)&in, &out );
if (old)
*old = out;
return ret;
}
/* Escape(hdc,SETABORTPROC,ABORTPROC,NULL); */
case SETABORTPROC:
return SetAbortProc16( hdc, (ABORTPROC16)in_data );
/* Escape(hdc,STARTDOC,LPSTR,LPDOCINFO16);
* lpvOutData is actually a pointer to the DocInfo structure and used as
* a second input parameter */
case STARTDOC:
if (out_data)
{
ret = StartDoc16( hdc, out_data );
if (ret > 0) ret = StartPage( HDC_32(hdc) );
return ret;
}
return Escape( HDC_32(hdc), escape, in_count, MapSL(in_data), NULL );
/* Escape(hdc,SET_BOUNDS,LPRECT16,NULL); */
/* Escape(hdc,SET_CLIP_BOX,LPRECT16,NULL); */
case SET_BOUNDS:
case SET_CLIP_BOX:
{
RECT16 *rc16 = MapSL(in_data);
RECT rc;
rc.left = rc16->left;
rc.top = rc16->top;
rc.right = rc16->right;
rc.bottom = rc16->bottom;
return Escape( HDC_32(hdc), escape, sizeof(rc), (LPCSTR)&rc, NULL );
}
/* Escape(hdc,NEXTBAND,NULL,LPRECT16); */
case NEXTBAND:
{
RECT rc;
RECT16 *rc16 = out_data;
ret = Escape( HDC_32(hdc), escape, 0, NULL, &rc );
rc16->left = rc.left;
rc16->top = rc.top;
rc16->right = rc.right;
rc16->bottom = rc.bottom;
return ret;
}
/* Escape(hdc,DRAWPATTERNRECT,PRECT_STRUCT*,NULL); */
case DRAWPATTERNRECT:
{
DRAWPATRECT pr;
DRAWPATRECT16 *pr16 = MapSL(in_data);
pr.ptPosition.x = pr16->ptPosition.x;
pr.ptPosition.y = pr16->ptPosition.y;
pr.ptSize.x = pr16->ptSize.x;
pr.ptSize.y = pr16->ptSize.y;
pr.wStyle = pr16->wStyle;
pr.wPattern = pr16->wPattern;
return Escape( HDC_32(hdc), escape, sizeof(pr), (LPCSTR)&pr, NULL );
}
/* Escape(hdc,ABORTDOC,NULL,NULL); */
/* Escape(hdc,BANDINFO,BANDINFOSTRUCT*,BANDINFOSTRUCT*); */
/* Escape(hdc,BEGIN_PATH,NULL,NULL); */
/* Escape(hdc,ENDDOC,NULL,NULL); */
/* Escape(hdc,END_PATH,PATHINFO,NULL); */
/* Escape(hdc,EXTTEXTOUT,EXTTEXT_STRUCT*,NULL); */
/* Escape(hdc,FLUSHOUTPUT,NULL,NULL); */
/* Escape(hdc,GETFACENAME,NULL,LPSTR); */
/* Escape(hdc,GETPAIRKERNTABLE,NULL,KERNPAIR*); */
/* Escape(hdc,GETSETPAPERBINS,BinInfo*,BinInfo*); */
/* Escape(hdc,GETSETPRINTORIENT,ORIENT*,NULL); */
/* Escape(hdc,GETSETSCREENPARAMS,SCREENPARAMS*,SCREENPARAMS*); */
/* Escape(hdc,GETTECHNOLOGY,NULL,LPSTR); */
/* Escape(hdc,GETTRACKKERNTABLE,NULL,KERNTRACK*); */
/* Escape(hdc,MFCOMMENT,LPSTR,NULL); */
/* Escape(hdc,NEWFRAME,NULL,NULL); */
/* Escape(hdc,PASSTHROUGH,LPSTR,NULL); */
/* Escape(hdc,RESTORE_CTM,NULL,NULL); */
/* Escape(hdc,SAVE_CTM,NULL,NULL); */
/* Escape(hdc,SETALLJUSTVALUES,EXTTEXTDATA*,NULL); */
/* Escape(hdc,SETCOLORTABLE,COLORTABLE_STRUCT*,LPDWORD); */
/* Escape(hdc,SET_BACKGROUND_COLOR,LPDWORD,LPDWORD); */
/* Escape(hdc,TRANSFORM_CTM,LPSTR,NULL); */
case ABORTDOC:
case BANDINFO:
case BEGIN_PATH:
case ENDDOC:
case END_PATH:
case EXTTEXTOUT:
case FLUSHOUTPUT:
case GETFACENAME:
case GETPAIRKERNTABLE:
case GETSETPAPERBINS:
case GETSETPRINTORIENT:
case GETSETSCREENPARAMS:
case GETTECHNOLOGY:
case GETTRACKKERNTABLE:
case MFCOMMENT:
case NEWFRAME:
case PASSTHROUGH:
case RESTORE_CTM:
case SAVE_CTM:
case SETALLJUSTVALUES:
case SETCOLORTABLE:
case SET_BACKGROUND_COLOR:
case TRANSFORM_CTM:
/* pass it unmodified to the 32-bit function */
return Escape( HDC_32(hdc), escape, in_count, MapSL(in_data), out_data );
/* Escape(hdc,ENUMPAPERMETRICS,LPINT16,LPRECT16); */
/* Escape(hdc,GETEXTENDEDTEXTMETRICS,LPUINT16,EXTTEXTMETRIC*); */
/* Escape(hdc,GETEXTENTTABLE,LPSTR,LPINT16); */
/* Escape(hdc,GETSETPAPERMETRICS,LPRECT16,LPRECT16); */
/* Escape(hdc,GETVECTORBRUSHSIZE,LPLOGBRUSH16,LPPOINT16); */
/* Escape(hdc,GETVECTORPENSIZE,LPLOGPEN16,LPPOINT16); */
case ENUMPAPERMETRICS:
case GETEXTENDEDTEXTMETRICS:
case GETEXTENTTABLE:
case GETSETPAPERMETRICS:
case GETVECTORBRUSHSIZE:
case GETVECTORPENSIZE:
default:
FIXME("unknown/unsupported 16-bit escape %x (%d,%p,%p)\n",
escape, in_count, MapSL(in_data), out_data );
return Escape( HDC_32(hdc), escape, in_count, MapSL(in_data), out_data );
case 0xA1D:
{
/* get EUDC font size */
TEXTMETRICW tm;
SIZE16 *size = (SIZE16*)out_data;
if (GetTextMetricsW(HDC_32(hdc), &tm))
{
size->cx = size->cy = tm.tmHeight;
return TRUE;
}
return FALSE;
}
}
}
/***********************************************************************
* RestoreDC (GDI.39)
*/
BOOL16 WINAPI RestoreDC16( HDC16 hdc, INT16 level )
{
return RestoreDC( HDC_32(hdc), level );
}
/***********************************************************************
* FillRgn (GDI.40)
*/
BOOL16 WINAPI FillRgn16( HDC16 hdc, HRGN16 hrgn, HBRUSH16 hbrush )
{
return FillRgn( HDC_32(hdc), HRGN_32(hrgn), HBRUSH_32(hbrush) );
}
/***********************************************************************
* FrameRgn (GDI.41)
*/
BOOL16 WINAPI FrameRgn16( HDC16 hdc, HRGN16 hrgn, HBRUSH16 hbrush,
INT16 nWidth, INT16 nHeight )
{
return FrameRgn( HDC_32(hdc), HRGN_32(hrgn), HBRUSH_32(hbrush), nWidth, nHeight );
}
/***********************************************************************
* InvertRgn (GDI.42)
*/
BOOL16 WINAPI InvertRgn16( HDC16 hdc, HRGN16 hrgn )
{
return InvertRgn( HDC_32(hdc), HRGN_32(hrgn) );
}
/***********************************************************************
* PaintRgn (GDI.43)
*/
BOOL16 WINAPI PaintRgn16( HDC16 hdc, HRGN16 hrgn )
{
return PaintRgn( HDC_32(hdc), HRGN_32(hrgn) );
}
/***********************************************************************
* SelectClipRgn (GDI.44)
*/
INT16 WINAPI SelectClipRgn16( HDC16 hdc, HRGN16 hrgn )
{
return SelectClipRgn( HDC_32(hdc), HRGN_32(hrgn) );
}
/***********************************************************************
* SelectObject (GDI.45)
*/
HGDIOBJ16 WINAPI SelectObject16( HDC16 hdc, HGDIOBJ16 handle )
{
HDC hdc32 = HDC_32(hdc);
HGDIOBJ handle32 = HGDIOBJ_32(handle);
HGDIOBJ result = SelectObject( hdc32, handle32 );
DWORD type = GetObjectType(handle32);
if (krnl386_get_compat_mode("256color") && krnl386_get_config_int("otvdm", "DIBPalette", FALSE) && result && (type == OBJ_BITMAP) && (GetCurrentObject(hdc32, OBJ_PAL) != GetStockObject(DEFAULT_PALETTE)))
{
DIBSECTION dib;
int count = GetObject(handle32, sizeof(DIBSECTION), &dib);
if ((count == sizeof(DIBSECTION)) && (dib.dsBmih.biBitCount == 8) && !dib.dshSection && (GetPtr16(handle, 1) == 0xd1b00001))
set_dib_colors(hdc32);
}
return HGDIOBJ_16( result );
}
/***********************************************************************
* CombineRgn (GDI.47)
*/
INT16 WINAPI CombineRgn16(HRGN16 hDest, HRGN16 hSrc1, HRGN16 hSrc2, INT16 mode)
{
return CombineRgn( HRGN_32(hDest), HRGN_32(hSrc1), HRGN_32(hSrc2), mode );
}
/***********************************************************************
* CreateBitmap (GDI.48)
*/
HBITMAP16 WINAPI CreateBitmap16( INT16 width, INT16 height, UINT16 planes,
UINT16 bpp, LPCVOID bits )
{
if (krnl386_get_compat_mode("256color") && (bpp == 8) && (planes == 1))
{
HBITMAP16 ret;
if (krnl386_get_config_int("otvdm", "DIBPalette", FALSE))
{
HDC16 dc = CreateCompatibleDC16(NULL);
ret = CreateCompatibleBitmap16(dc, width, height);
if (bits)
SetBitmapBits(HBITMAP_32(ret), width * height, bits);
DeleteDC16(dc);
}
else
{
HDC dc = GetDC(NULL);
HBITMAP ret32 = CreateCompatibleBitmap(dc, width, height);
if (bits)
{
BITMAPINFO *bmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 256*2 + sizeof(BITMAPINFOHEADER));
UINT16 *colors = (UINT16 *)bmap->bmiColors;
VOID *section;
bmap->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmap->bmiHeader.biWidth = width;
bmap->bmiHeader.biHeight = -height;
bmap->bmiHeader.biPlanes = 1;
bmap->bmiHeader.biBitCount = 8;
for (int i = 0; i < 256; i++)
colors[i] = i;
SetDIBits(dc, ret, 0, height, bits, bmap, DIB_PAL_COLORS);
HeapFree(GetProcessHeap(), 0, bmap);
}
ret = HBITMAP_16(ret32);
ReleaseDC(NULL, dc);
}
return ret;
}
else if ((planes == 1) && (bpp > 8))
{
HDC dc = GetDC(NULL);
if (bpp == GetDeviceCaps(dc, BITSPIXEL))
{
BITMAPINFO bmpinfo = {0};
VOID *bmp;
HDC16 dc16 = HDC_16(dc);
bmpinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmpinfo.bmiHeader.biWidth = width;
bmpinfo.bmiHeader.biHeight = -height;
bmpinfo.bmiHeader.biPlanes = 1;
bmpinfo.bmiHeader.biBitCount = bpp;
HBITMAP16 ret = CreateDIBSection16(dc16, &bmpinfo, DIB_RGB_COLORS, &bmp, NULL, NULL);
if (bits)
SetDIBits(dc, HBITMAP_32(ret), 0, height, bits, &bmpinfo, DIB_RGB_COLORS);
ReleaseDC(NULL, dc);
return ret;
}
ReleaseDC(NULL, dc);
}
return HBITMAP_16( CreateBitmap( width, height, planes & 0xff, bpp & 0xff, bits ) );
}
/***********************************************************************
* CreateBitmapIndirect (GDI.49)
*/
HBITMAP16 WINAPI CreateBitmapIndirect16( const BITMAP16 * bmp )
{
return CreateBitmap16( bmp->bmWidth, bmp->bmHeight, bmp->bmPlanes,
bmp->bmBitsPixel, MapSL( bmp->bmBits ) );
}
/***********************************************************************
* CreateBrushIndirect (GDI.50)
*/
HBRUSH16 WINAPI CreateBrushIndirect16( const LOGBRUSH16 * brush )
{
LOGBRUSH brush32;
if (brush->lbStyle == BS_DIBPATTERN || brush->lbStyle == BS_DIBPATTERN8X8)
return CreateDIBPatternBrush16( brush->lbHatch, brush->lbColor );
if (brush->lbStyle == BS_NULL)
return GetStockObject16(NULL_BRUSH);
brush32.lbStyle = brush->lbStyle;
brush32.lbColor = brush->lbColor;
if (brush->lbStyle == BS_PATTERN)
{
brush32.lbHatch = HBITMAP_32(brush->lbHatch);
}
else
brush32.lbHatch = brush->lbHatch;
return HBRUSH_16( CreateBrushIndirect(&brush32) );
}
/***********************************************************************
* CreateCompatibleBitmap (GDI.51)
*/
HBITMAP16 WINAPI CreateCompatibleBitmap16( HDC16 hdc, INT16 width, INT16 height )
{
HDC hdc32 = HDC_32(hdc);
if (krnl386_get_compat_mode("256color") && krnl386_get_config_int("otvdm", "DIBPalette", FALSE) && (GetDeviceCaps(hdc32, TECHNOLOGY) == DT_RASDISPLAY))
{
HBITMAP16 ret;
VOID *section;
BITMAPINFO *bmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 256*2 + sizeof(BITMAPINFOHEADER));
UINT16 *colors = (UINT16 *)bmap->bmiColors;
bmap->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmap->bmiHeader.biWidth = width;
bmap->bmiHeader.biHeight = -height;
bmap->bmiHeader.biPlanes = 1;
bmap->bmiHeader.biBitCount = 8;
for (int i = 0; i < 256; i++)
colors[i] = i;
ret = HBITMAP_16(CreateDIBSection(hdc32, bmap, DIB_PAL_COLORS, §ion, NULL, NULL));
SetPtr16(ret, 0xd1b00001, 1);
HeapFree(GetProcessHeap(), 0, bmap);
return ret;
}
return HBITMAP_16( CreateCompatibleBitmap( hdc32, width, height ) );
}
BOOL16 WINAPI IsOldWindowsTask(HINSTANCE16 hInst);
BYTE get_aflags(HMODULE16 hModule);
HPALETTE16 WINAPI SelectPalette16(HDC16 hdc, HPALETTE16 hpal, BOOL16 bForceBackground);
/***********************************************************************
* CreateCompatibleDC (GDI.52)
*/
HDC16 WINAPI CreateCompatibleDC16( HDC16 hdc )
{
HDC hdc32 = CreateCompatibleDC( HDC_32(hdc) );
if (IsOldWindowsTask(GetCurrentTask()) && !(get_aflags(GetExePtr(GetCurrentTask())) & NE_AFLAGS_WIN2_PROTMODE) && (GetCurrentObject(hdc32, OBJ_FONT) == GetStockObject(SYSTEM_FONT)))
SelectObject(hdc32, GetStockObject(SYSTEM_FIXED_FONT));
if (krnl386_get_compat_mode("256color") && krnl386_get_config_int("otvdm", "DIBPalette", FALSE) && (GetDeviceCaps(hdc32, TECHNOLOGY) == DT_RASDISPLAY))
SelectPalette16(HDC_16(hdc32), HPALETTE_16(get_realized_palette()), FALSE);
return HDC_16(hdc32);
}
void add_dib_driver_entry(HBITMAP bitmap, HDC dc, HANDLE hSection, LPVOID bits, WORD selector, DWORD size, DWORD padding)
{
struct dib_driver *drv = (struct dib_driver*)HeapAlloc(GetProcessHeap(), 0, sizeof(struct dib_driver));
drv->bitmap = bitmap;
drv->hdc = dc;
drv->hSection = hSection;
drv->map = bits;
drv->selector = selector;
drv->size = size;
drv->padding = padding;
list_add_head(&dib_drivers, &drv->entry);
}
struct dib_driver *find_dib_driver(WORD selector)
{
struct dib_driver *dib, *next;
LIST_FOR_EACH_ENTRY_SAFE(dib, next, &dib_drivers, struct dib_driver, entry)
{
if (dib->selector == selector)
return dib;
}
return NULL;
}
struct
{
BITMAPINFOHEADER bmi;
RGBQUAD colors[16];
} dib_pal_colors_hack =
{
{0x28, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0},
{{0, 0, 0}, {0, 0, 0x80}, {0, 0x80, 0}, {0, 0x80, 0x80}, {0x80, 0, 0}, {0x80, 0, 0x80},
{0x80, 0x80, 0}, {0xc0, 0xc0, 0xc0}, {0x80, 0x80, 0x80}, {0, 0, 0xff}, {0, 0xff, 0},
{0, 0xff, 0xff}, {0xff, 0, 0}, {0xff, 0, 0xff}, {0xff, 0xff, 0}, {0xff, 0xff, 0xff}}
};
/***********************************************************************
* CreateDC (GDI.53)
*/
HDC16 WINAPI CreateDC16( LPCSTR driver, LPCSTR device, LPCSTR output,
SEGPTR segInitData )
{
const DEVMODEA *initData = (const DEVMODEA*)MapSL(segInitData);
HDC16 dc;
HINSTANCE16 drv;
char tmp[256];
if (device && !strcmp(device, "DefaultPrinter"))
{
int len = 256;
if (GetDefaultPrinterA(tmp, &len))
device = tmp;
}
#if 0
if (!lstrcmpiA( driver, "dib" ) || !lstrcmpiA( driver, "dirdib" ))
{
struct window_surface *surface;
HDC hdc;
if (!(surface = create_surface( (const BITMAPINFO *)initData ))) return 0;
if ((hdc = CreateDCA( "DISPLAY", NULL, NULL, NULL )))
{
__wine_set_visible_region( hdc, CreateRectRgnIndirect( &surface->rect ),
&surface->rect, &surface->rect, surface );
TRACE( "returning hdc %p surface %p\n", hdc, surface );
}
window_surface_release( surface );
return HDC_16( hdc );
}
#else
if (!lstrcmpiA(driver, "dib") || !lstrcmpiA(driver, "dirdib") || !lstrcmpiA(driver, "dib.drv") || !lstrcmpiA(driver, "dirdib.drv"))
{
void *pvBits;
HDC memdc = CreateCompatibleDC(NULL);
HBITMAP bitmap;
WORD selector = SELECTOROF(segInitData);
WORD offset = OFFSETOF(segInitData);
LPVOID base = MapSL(MAKESEGPTR(selector, 0));
DWORD limit = wine_ldt_copy.limit[selector >> __AHSHIFT] + 1;
volatile BITMAPINFO *bmi = (const BITMAPINFO *)initData;
HANDLE hSection = INVALID_HANDLE_VALUE;
LPBYTE bits = NULL;
DWORD avail_size;
DWORD offset_align;
DWORD offset_bits;
if (segInitData == 0)
{
return HDC_16(memdc);
}
if (find_dib_driver(selector))
{
FIXME("Multiple DIB mappings on the same segment are not supported.\n");
return HDC_16(memdc);
}
// check for dib_pal_colors hack
if (bmi->bmiHeader.biBitCount <= 8) // does dib.drv support direct color modes?
{
int maxcolor = bmi->bmiHeader.biClrUsed ? bmi->bmiHeader.biClrUsed : 1 << bmi->bmiHeader.biBitCount;
offset_bits = offset + bmi->bmiHeader.biSize + maxcolor * sizeof(RGBQUAD);
int chkcolor = bmi->bmiHeader.biClrImportant ? bmi->bmiHeader.biClrImportant : maxcolor;
for (int i = 0; i < chkcolor; i++)
{
if (((WORD *)bmi->bmiColors)[i] != i) break;
if (i == (chkcolor - 1))
{
dib_pal_colors_hack.bmi.biWidth = bmi->bmiHeader.biWidth;
dib_pal_colors_hack.bmi.biHeight = bmi->bmiHeader.biHeight;
dib_pal_colors_hack.bmi.biBitCount = bmi->bmiHeader.biBitCount;
dib_pal_colors_hack.bmi.biClrUsed = min(maxcolor, 16);
bmi = (BITMAPINFO *)&dib_pal_colors_hack;
break;
}
}
}
else
offset_bits = offset + bmi->bmiHeader.biSize;
#define DWORD_PADDING(x) (((x) + 3) & -4)
offset_align = DWORD_PADDING(offset_bits) - offset_bits;
avail_size = max(0x10000, limit);
hSection = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, avail_size + offset_align, NULL);
bits = (LPBYTE)MapViewOfFile(hSection, FILE_MAP_WRITE, 0, 0, 0);
memcpy(bits + offset_align, base, limit);
bitmap = CreateDIBSection(NULL, bmi, DIB_RGB_COLORS, &pvBits, hSection, offset_align + offset_bits);
SelectObject(memdc, bitmap);
DibMapGlobalMemory(selector, (LPBYTE)bits + offset_align, avail_size);
if (bmi->bmiHeader.biClrUsed)
SetDIBColorTable(memdc, 0, bmi->bmiHeader.biClrUsed, &bmi->bmiColors);
add_dib_driver_entry(bitmap, memdc, hSection, bits, selector, avail_size, offset_align);
return HDC_16(memdc);
}
#endif
if (!driver || !stricmp(driver, "winspool"))
{
if (!initData || !IsValidDevmodeA(initData, initData->dmSize + initData->dmDriverExtra))
{
LONG size = ExtDeviceMode(NULL, NULL, NULL, device, output, NULL, NULL, 0);
char *dma = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
ExtDeviceMode(NULL, NULL, (LPDEVMODEA)dma, device, output, NULL, NULL, DM_COPY);
HDC16 ret = HDC_16(CreateDCA(driver, device, output, (LPDEVMODEA)dma));
HeapFree(GetProcessHeap(), 0, (LPVOID)dma);
return ret;
}
else
{
DEVMODEA dma = {0};
memcpy(&dma, initData, initData->dmSize);
dma.dmSize = sizeof(DEVMODEA);
dma.dmDriverExtra = 0;
return HDC_16( CreateDCA( driver, device, output, &dma ) );
}
}
dc = HDC_16( CreateDCA( driver, device, output, initData ) );
if (dc)
return dc;
drv = LoadLibrary16(driver);
if (drv == 2)
{
char buf[MAX_PATH];
*buf = 0;
StringCchCatA(buf, ARRAYSIZE(buf), driver);
StringCchCatA(buf, ARRAYSIZE(buf), ".DRV");
drv = LoadLibrary16(buf);
}
if (drv < 32)
{
ERR("DC driver %s not found\n", debugstr_a(driver));
return 0;
}
FIXME("DC driver %s not supported\n", debugstr_a(driver));
return CreateDC16("DIB", NULL, NULL, NULL);
}
/***********************************************************************
* CreateEllipticRgn (GDI.54)
*/
HRGN16 WINAPI CreateEllipticRgn16( INT16 left, INT16 top, INT16 right, INT16 bottom )
{
return HRGN_16( CreateEllipticRgn( left, top, right, bottom ) );
}
/***********************************************************************
* CreateEllipticRgnIndirect (GDI.55)
*/
HRGN16 WINAPI CreateEllipticRgnIndirect16( const RECT16 *rect )
{
return HRGN_16( CreateEllipticRgn( rect->left, rect->top, rect->right, rect->bottom ) );
}
static BYTE fix_font_charset(BYTE charset)
{
//windows 3.1(JP) behaviour
if (GetACP() == 932/*sjis*/)
{
if (charset != ANSI_CHARSET && charset != DEFAULT_CHARSET && charset != SYMBOL_CHARSET && charset != OEM_CHARSET)
{
charset = SHIFTJIS_CHARSET;
}
}
return charset;
}
/***********************************************************************
* CreateFontIndirect (GDI.57)
*/
HFONT16 WINAPI CreateFontIndirect16( const LOGFONT16 *plf16 )
{
HFONT ret;
if (plf16)
{
LOGFONTA lfA;
logfont_16_to_A( plf16, &lfA );
if (lfA.lfCharSet == 0xfe)
lfA.lfCharSet = 0xfd;
ret = CreateFontIndirectA( &lfA );
TRACE("(%d, %d, %04X, %04X, %04X, %02X, %02X, %02X, %02X, %02X, %02X, %02X, %s) = %04X\n", plf16->lfHeight, plf16->lfWidth, plf16->lfEscapement, plf16->lfOrientation, plf16->lfWeight
, plf16->lfItalic, plf16->lfUnderline, plf16->lfStrikeOut, plf16->lfCharSet, plf16->lfOutPrecision, plf16->lfClipPrecision
, plf16->lfPitchAndFamily, debugstr_a(plf16->lfFaceName), (int)HFONT_16(ret));
}
else ret = CreateFontIndirectA( NULL );
return HFONT_16(ret);
}
/***********************************************************************
* CreateFont (GDI.56)
*/
HFONT16 WINAPI CreateFont16(INT16 height, INT16 width, INT16 esc, INT16 orient,
INT16 weight, BYTE italic, BYTE underline,
BYTE strikeout, BYTE charset, BYTE outpres,
BYTE clippres, BYTE quality, BYTE pitch,
LPCSTR name)
{
LOGFONT16 lf16 = { 0 };
lf16.lfHeight = height;
lf16.lfWidth = width;
lf16.lfEscapement = esc;
lf16.lfOrientation = orient;
lf16.lfWeight = weight;
lf16.lfItalic = italic;
lf16.lfUnderline = underline;
lf16.lfStrikeOut = strikeout;
lf16.lfCharSet = charset;
lf16.lfOutPrecision = outpres;
lf16.lfClipPrecision = clippres;
lf16.lfQuality = quality;
lf16.lfPitchAndFamily = pitch;
if (name)
memcpy(lf16.lfFaceName, name, min(LF_FACESIZE - 1, strlen(name) + 1));
return CreateFontIndirect16(&lf16);
}
/***********************************************************************
* CreateHatchBrush (GDI.58)
*/
HBRUSH16 WINAPI CreateHatchBrush16( INT16 style, COLORREF color )
{
return HBRUSH_16( CreateHatchBrush( style, check_colorref(color) ) );
}
/***********************************************************************
* CreatePatternBrush (GDI.60)
*/
HBRUSH16 WINAPI CreatePatternBrush16( HBITMAP16 hbitmap )
{
return HBRUSH_16( CreatePatternBrush( HBITMAP_32(hbitmap) ));
}
/***********************************************************************
* CreatePen (GDI.61)
*/
HPEN16 WINAPI CreatePen16( INT16 style, INT16 width, COLORREF color )
{
LOGPEN logpen;
if (style == PS_NULL)
return GetStockObject16(NULL_PEN);
logpen.lopnStyle = style;
logpen.lopnWidth.x = width;
logpen.lopnWidth.y = 0;
logpen.lopnColor = check_colorref(color);
return HPEN_16( CreatePenIndirect( &logpen ) );
}
/***********************************************************************
* CreatePenIndirect (GDI.62)
*/
HPEN16 WINAPI CreatePenIndirect16( const LOGPEN16 * pen )
{
LOGPEN logpen;
if (pen->lopnStyle == PS_NULL)
return GetStockObject16(NULL_PEN);
if (pen->lopnStyle > PS_INSIDEFRAME) return 0;
logpen.lopnStyle = pen->lopnStyle;
logpen.lopnWidth.x = pen->lopnWidth.x;
logpen.lopnWidth.y = pen->lopnWidth.y;
logpen.lopnColor = pen->lopnColor;
return HPEN_16( CreatePenIndirect( &logpen ) );
}
/***********************************************************************
* CreatePolygonRgn (GDI.63)
*/
HRGN16 WINAPI CreatePolygonRgn16( const POINT16 * points, INT16 count, INT16 mode )
{
return CreatePolyPolygonRgn16( points, &count, 1, mode );
}
/***********************************************************************
* CreateRectRgn (GDI.64)
*
* NOTE: cf. SetRectRgn16
*/
HRGN16 WINAPI CreateRectRgn16( INT16 left, INT16 top, INT16 right, INT16 bottom )
{
HRGN hrgn;
if (left < right) hrgn = CreateRectRgn( left, top, right, bottom );
else hrgn = CreateRectRgn( 0, 0, 0, 0 );
return HRGN_16(hrgn);
}
/***********************************************************************
* CreateRectRgnIndirect (GDI.65)
*/
HRGN16 WINAPI CreateRectRgnIndirect16( const RECT16* rect )
{
return CreateRectRgn16( rect->left, rect->top, rect->right, rect->bottom );
}
/***********************************************************************
* CreateSolidBrush (GDI.66)
*/
HBRUSH16 WINAPI CreateSolidBrush16( COLORREF color )
{
return HBRUSH_16( CreateSolidBrush( check_colorref(color) ) );
}
void delete_dib_driver(HDC hdc)
{
struct dib_driver *dib, *next;
LIST_FOR_EACH_ENTRY_SAFE(dib, next, &dib_drivers, struct dib_driver, entry)
{
if (dib->hdc != hdc) continue;
list_remove(&dib->entry);
DibUnmapGlobalMemory((LPBYTE)dib->map + dib->padding, dib->size);
DeleteObject(dib->bitmap);
UnmapViewOfFile(dib->map);
CloseHandle(dib->hSection);
HeapFree(GetProcessHeap(), 0, dib);
}
}
/***********************************************************************
* DeleteDC (GDI.68)
*/
BOOL16 WINAPI DeleteDC16( HDC16 hdc )
{
HDC hdc32 = HDC_32(hdc);
if (krnl386_get_compat_mode("256color") && krnl386_get_config_int("otvdm", "DIBPalette", FALSE) && (GetDeviceCaps(hdc32, TECHNOLOGY) == DT_RASDISPLAY))
SelectPalette(hdc32, GetStockObject(DEFAULT_PALETTE), FALSE);
if (DeleteDC( hdc32 ))
{
struct saved_visrgn *saved, *next;
struct gdi_thunk* thunk;
if ((thunk = GDI_FindThunk(hdc))) GDI_DeleteThunk(thunk);
LIST_FOR_EACH_ENTRY_SAFE( saved, next, &saved_regions, struct saved_visrgn, entry )
{
if (saved->hdc != hdc32) continue;
list_remove( &saved->entry );
DeleteObject( saved->hrgn );
HeapFree( GetProcessHeap(), 0, saved );
}
delete_dib_driver(hdc32);
K32WOWHandle16Destroy(hdc32, WOW_TYPE_HDC /* GDIOBJ */);
return TRUE;
}
else if (!GetObjectType(hdc32))
return TRUE; // Assume object was already released, dc cache may make this unnecessary
return FALSE;
}
/***********************************************************************
* DeleteObject (GDI.69)
* SysDeleteObject (GDI.605)
*/
BOOL16 WINAPI DeleteObject16( HGDIOBJ16 obj )
{
HANDLE object = HGDIOBJ_32(obj);
BOOL result;
int type = GetObjectType(object);
static BOOL (*haxmvm_DeleteObject)(HGDIOBJ);
static BOOL init;
if (!init)
{
HMODULE haxmvm = GetModuleHandleW(L"haxmvm");
haxmvm_DeleteObject = haxmvm ? (BOOL(*)(HGDIOBJ))GetProcAddress(haxmvm, "haxmvm_DeleteObject") : NULL;
init = TRUE;
}
for (int i = 0; i <= STOCK_LAST + 1; i++)
if (obj == stock[i]) return TRUE;
if (type == OBJ_BITMAP) free_segptr_bits( obj );
else if ((type == OBJ_PAL) && GetPtr16(object, 1))
{
HeapFree(GetProcessHeap(), 0, GetPtr16(object, 1));
SetPtr16(object, NULL, 1);
}
if (haxmvm_DeleteObject)
{
result = haxmvm_DeleteObject(object);
}
else
{
result = DeleteObject( object );
}
if (result)
{
K32WOWHandle16Destroy(object, WOW_TYPE_HDC /* GDIOBJ */);
}
else
{
if (type == OBJ_PAL)
return TRUE;
}
return result;
}
/***********************************************************************
* EnumFonts (GDI.70)
*/
INT16 WINAPI EnumFonts16( HDC16 hDC, LPCSTR lpName, FONTENUMPROC16 efproc,
LPARAM lpData )
{
struct callback16_info info;
info.proc = (FARPROC16)efproc;
info.param = lpData;
info.result = 1;
/* Don't call EnumFontFamilies! */
return EnumFontsA(HDC_32(hDC), lpName, enum_font_callback, (LPARAM)&info);
}
/***********************************************************************
* EnumObjects (GDI.71)
*/
INT16 WINAPI EnumObjects16( HDC16 hdc, INT16 obj, GOBJENUMPROC16 proc, LPARAM lParam )
{
struct callback16_info info;
info.proc = (FARPROC16)proc;
info.param = lParam;
switch(obj)
{
case OBJ_PEN:
return EnumObjects( HDC_32(hdc), OBJ_PEN, enum_pens_callback, (LPARAM)&info );
case OBJ_BRUSH:
return EnumObjects( HDC_32(hdc), OBJ_BRUSH, enum_brushes_callback, (LPARAM)&info );
}
return 0;
}
/***********************************************************************
* EqualRgn (GDI.72)
*/
BOOL16 WINAPI EqualRgn16( HRGN16 rgn1, HRGN16 rgn2 )
{
return EqualRgn( HRGN_32(rgn1), HRGN_32(rgn2) );
}
/***********************************************************************
* GetBitmapBits (GDI.74)
*/
LONG WINAPI GetBitmapBits16( HBITMAP16 hbitmap, LONG count, LPVOID buffer )
{
return GetBitmapBits( HBITMAP_32(hbitmap), count, buffer );
}
/***********************************************************************
* GetBkColor (GDI.75)
*/
COLORREF WINAPI GetBkColor16( HDC16 hdc )
{
return GetBkColor( HDC_32(hdc) );
}
/***********************************************************************
* GetBkMode (GDI.76)
*/
INT16 WINAPI GetBkMode16( HDC16 hdc )
{
return GetBkMode( HDC_32(hdc) );
}
/***********************************************************************
* GetClipBox (GDI.77)
*/
INT16 WINAPI GetClipBox16( HDC16 hdc, LPRECT16 rect )
{
RECT rect32;
INT ret = GetClipBox( HDC_32(hdc), &rect32 );
if (ret != ERROR)
{
rect->left = rect32.left;
rect->top = rect32.top;
rect->right = rect32.right;
rect->bottom = rect32.bottom;
}
return ret;
}
/***********************************************************************
* GetCurrentPosition (GDI.78)
*/
DWORD WINAPI GetCurrentPosition16( HDC16 hdc )
{
POINT pt32;
if (!GetCurrentPositionEx( HDC_32(hdc), &pt32 )) return 0;
return MAKELONG( pt32.x, pt32.y );
}
/***********************************************************************
* GetDCOrg (GDI.79)
*/
DWORD WINAPI GetDCOrg16( HDC16 hdc )
{
POINT pt;
if (GetDCOrgEx( HDC_32(hdc), &pt )) return MAKELONG( pt.x, pt.y );
return 0;
}
/***********************************************************************
* GetDeviceCaps (GDI.80)
*/
INT16 WINAPI GetDeviceCaps16( HDC16 hdc, INT16 cap )
{
HDC hdc32 = HDC_32(hdc);
INT16 ret = GetDeviceCaps( hdc32, cap );
/* some apps don't expect -1 and think it's a B&W screen */
if (krnl386_get_compat_mode("256color") && (GetDeviceCaps(hdc32, TECHNOLOGY) == DT_RASDISPLAY))
{
switch (cap)
{
case BITSPIXEL:
ret = 8;
break;
case SIZEPALETTE:
ret = 256;
break;
case RASTERCAPS:
ret |= RC_PALETTE;
break;
case NUMCOLORS:
ret = 20;
break;
}
}
else if (((cap == NUMCOLORS) || (cap == NUMPENS)) && (ret == -1)) ret = 2048;
else if (cap == VREFRESH) ret = 1;
if (krnl386_get_compat_mode("640X480") && (GetDeviceCaps(hdc32, TECHNOLOGY) == DT_RASDISPLAY))
{
switch (cap)
{
case HORZRES:
ret = 640;
break;
case VERTRES:
ret = 480;
break;
case HORZSIZE:
ret = 169;
break;
case VERTSIZE:
ret = 127;
break;
}
}
int newdpi = krnl386_get_config_int("otvdm", "AdjustDPI", FALSE);
if (newdpi)
{
switch (cap)
{
case LOGPIXELSX:
ret = newdpi;
break;
case LOGPIXELSY:
ret = newdpi;
break;
}
}
return ret;
}
/***********************************************************************
* GetMapMode (GDI.81)
*/
INT16 WINAPI GetMapMode16( HDC16 hdc )
{
return GetMapMode( HDC_32(hdc) );
}
/***********************************************************************
* GetObject (GDI.82)
*/
INT16 WINAPI GetObject16( HGDIOBJ16 handle16, INT16 count, LPVOID buffer )
{
HGDIOBJ handle = HGDIOBJ_32( handle16 );
switch( GetObjectType( handle ))
{
case OBJ_PEN:
if (buffer)
{
LOGPEN16 *pen16 = buffer;
LOGPEN pen;
if (count < sizeof(LOGPEN16)) return 0;
if (!GetObjectW( handle, sizeof(pen), &pen )) return 0;
pen16->lopnStyle = pen.lopnStyle;
pen16->lopnColor = pen.lopnColor;
pen16->lopnWidth.x = pen.lopnWidth.x;
pen16->lopnWidth.y = pen.lopnWidth.y;
}
return sizeof(LOGPEN16);
case OBJ_BRUSH:
if (buffer)
{
LOGBRUSH brush;
LOGBRUSH16 brush16;
if (!GetObjectW( handle, sizeof(brush), &brush )) return 0;
brush16.lbStyle = brush.lbStyle;
brush16.lbColor = brush.lbColor;
brush16.lbHatch = brush.lbHatch;
if (count > sizeof(brush16)) count = sizeof(brush16);
memcpy( buffer, &brush16, count );
return count;
}
return sizeof(LOGBRUSH16);
case OBJ_PAL:
return GetObjectW( handle, count, buffer );
case OBJ_FONT:
if (buffer)
{
LOGFONTA font;
LOGFONT16 font16;
if (!GetObjectA( handle, sizeof(font), &font )) return 0;
logfont_A_to_16( &font, &font16 );
if (count > sizeof(font16)) count = sizeof(font16);
memcpy( buffer, &font16, count );
return count;
}
return sizeof(LOGFONT16);
case OBJ_BITMAP:
{
DIBSECTION dib;
INT size;
BITMAP16 bmp16;
if (!(size = GetObjectW( handle, sizeof(dib), &dib ))) return 0;
if (size == sizeof(DIBSECTION) && count > sizeof(BITMAP16))
{
FIXME("not implemented for DIBs: count %d\n", count);
return 0;
}
else
{
if (!buffer) return sizeof(BITMAP16);
bmp16.bmType = dib.dsBm.bmType;
bmp16.bmWidth = dib.dsBm.bmWidth;
bmp16.bmHeight = dib.dsBm.bmHeight;
bmp16.bmWidthBytes = dib.dsBm.bmWidthBytes;
bmp16.bmPlanes = dib.dsBm.bmPlanes;
bmp16.bmBitsPixel = dib.dsBm.bmBitsPixel;
bmp16.bmBits = 0;
memcpy(buffer, &bmp16, count);
return count;
}
}
default:
return 0;
}
}
/***********************************************************************
* GetPixel (GDI.83)
*/
COLORREF WINAPI GetPixel16( HDC16 hdc, INT16 x, INT16 y )
{
return GetPixel( HDC_32(hdc), x, y );
}
/***********************************************************************
* GetPolyFillMode (GDI.84)
*/
INT16 WINAPI GetPolyFillMode16( HDC16 hdc )
{
return GetPolyFillMode( HDC_32(hdc) );
}
/***********************************************************************
* GetROP2 (GDI.85)
*/
INT16 WINAPI GetROP216( HDC16 hdc )
{
return GetROP2( HDC_32(hdc) );
}
DWORD WINAPI GetRelAbs(_In_ HDC hdc,
_In_ DWORD dwIgnore
);
/***********************************************************************
* GetRelAbs (GDI.86)
*/
INT16 WINAPI GetRelAbs16( HDC16 hdc )
{
return GetRelAbs( HDC_32(hdc), 0 );
}
/***********************************************************************
* GetStockObject (GDI.87)
*/
HGDIOBJ16 WINAPI GetStockObject16( INT16 obj )
{
if (IsOldWindowsTask(GetCurrentTask()) && !(get_aflags(GetExePtr(GetCurrentTask())) & NE_AFLAGS_WIN2_PROTMODE) && (obj == SYSTEM_FONT))
obj = SYSTEM_FIXED_FONT;
HGDIOBJ16 ret = HGDIOBJ_16( GetStockObject( obj ) );
if (ret && (obj <= STOCK_LAST))
stock[obj] = ret;
return ret;
}
/***********************************************************************
* GetStretchBltMode (GDI.88)
*/
INT16 WINAPI GetStretchBltMode16( HDC16 hdc )
{
return GetStretchBltMode( HDC_32(hdc) );
}
/***********************************************************************
* GetTextCharacterExtra (GDI.89)
*/
INT16 WINAPI GetTextCharacterExtra16( HDC16 hdc )
{
return GetTextCharacterExtra( HDC_32(hdc) );
}
/***********************************************************************
* GetTextColor (GDI.90)
*/
COLORREF WINAPI GetTextColor16( HDC16 hdc )
{
return GetTextColor( HDC_32(hdc) );
}
// for old fon vector fonts
// Windows 10 only returns the extent based on the relative angle between the orientation and escapement
// but ignores the absolute angles
// Windows XP is mostly the same but calculates the full extent when the relative angle is 0
// Windows 3.1 returns the full extent but rounds the relative angle down to 0, 90, 180 or 270 degrees
static void check_font_rotation(HDC hdc, SIZE16 *box)
{
if (LOWORD(LOBYTE(GetVersion())) >= 0x6)
{
TEXTMETRICA tm;
GetTextMetricsA(hdc, &tm);
if((tm.tmPitchAndFamily & (TMPF_VECTOR | TMPF_TRUETYPE)) != TMPF_VECTOR)
return;
HFONT hfont = GetCurrentObject(hdc, OBJ_FONT);
LOGFONT lfont;
GetObject(hfont, sizeof(LOGFONT), &lfont);
if (lfont.lfEscapement == lfont.lfOrientation)
{
int angle = lfont.lfEscapement % 1800;
const float d2r = 3.14159265358979323846 / 1800;
if (angle)
{
int x = box->cx, y = box->cy;
box->cx = (y * cosf((900 - angle) * d2r)) + (x * fabsf(cosf(angle * d2r)));
box->cy = (x * cosf((900 - angle) * d2r)) + (y * fabsf(cosf(angle * d2r)));
}
}
}
}
/***********************************************************************
* GetTextExtent (GDI.91)
*/
DWORD WINAPI GetTextExtent16( HDC16 hdc, LPCSTR str, INT16 count )
{
SIZE16 size;
DWORD ret;
__TRY
{
if (!GetTextExtentPoint16( hdc, str, count, &size ))
{
ret = 0;
}
else
{
ret = MAKELONG( size.cx, size.cy );
}
}
__EXCEPT_ALL
{
return 0;
}
__ENDTRY
return ret;
}
/***********************************************************************
* GetTextFace (GDI.92)
*/
INT16 WINAPI GetTextFace16( HDC16 hdc, INT16 count, LPSTR name )
{
return GetTextFaceA( HDC_32(hdc), count, name );
}
/***********************************************************************
* GetTextMetrics (GDI.93)
*/
BOOL16 WINAPI GetTextMetrics16( HDC16 hdc, TEXTMETRIC16 *tm )
{
TEXTMETRICA tm32;
if (!tm) return FALSE;
if (!GetTextMetricsA( HDC_32(hdc), &tm32 )) return FALSE;
tm->tmHeight = tm32.tmHeight;
tm->tmAscent = tm32.tmAscent;
tm->tmDescent = tm32.tmDescent;
tm->tmInternalLeading = tm32.tmInternalLeading;
tm->tmExternalLeading = tm32.tmExternalLeading;
tm->tmAveCharWidth = tm32.tmAveCharWidth;
tm->tmMaxCharWidth = tm32.tmMaxCharWidth;
tm->tmWeight = tm32.tmWeight;
tm->tmOverhang = tm32.tmOverhang;
tm->tmDigitizedAspectX = tm32.tmDigitizedAspectX;
tm->tmDigitizedAspectY = tm32.tmDigitizedAspectY;
tm->tmFirstChar = tm32.tmFirstChar;
tm->tmLastChar = tm32.tmLastChar;
tm->tmDefaultChar = tm32.tmDefaultChar;
tm->tmBreakChar = tm32.tmBreakChar;
tm->tmItalic = tm32.tmItalic;
tm->tmUnderlined = tm32.tmUnderlined;
tm->tmStruckOut = tm32.tmStruckOut;
tm->tmPitchAndFamily = tm32.tmPitchAndFamily;
tm->tmCharSet = tm32.tmCharSet;
return TRUE;
}
/***********************************************************************
* GetViewportExt (GDI.94)
*/
DWORD WINAPI GetViewportExt16( HDC16 hdc )
{
SIZE size;
if (!GetViewportExtEx( HDC_32(hdc), &size )) return 0;
return MAKELONG( size.cx, size.cy );
}
/***********************************************************************
* GetViewportOrg (GDI.95)
*/
DWORD WINAPI GetViewportOrg16( HDC16 hdc )
{
POINT pt;
if (!GetViewportOrgEx( HDC_32(hdc), &pt )) return 0;
return MAKELONG( pt.x, pt.y );
}
/***********************************************************************
* GetWindowExt (GDI.96)
*/
DWORD WINAPI GetWindowExt16( HDC16 hdc )
{
SIZE size;
if (!GetWindowExtEx( HDC_32(hdc), &size )) return 0;
return MAKELONG( size.cx, size.cy );
}
/***********************************************************************
* GetWindowOrg (GDI.97)
*/
DWORD WINAPI GetWindowOrg16( HDC16 hdc )
{
POINT pt;
if (!GetWindowOrgEx( HDC_32(hdc), &pt )) return 0;
return MAKELONG( pt.x, pt.y );
}
/**********************************************************************
* LineDDA (GDI.100)
*/
void WINAPI LineDDA16( INT16 nXStart, INT16 nYStart, INT16 nXEnd,
INT16 nYEnd, LINEDDAPROC16 proc, LPARAM lParam )
{
struct callback16_info info;
info.proc = (FARPROC16)proc;
info.param = lParam;
LineDDA( nXStart, nYStart, nXEnd, nYEnd, linedda_callback, (LPARAM)&info );
}
/***********************************************************************
* OffsetRgn (GDI.101)
*/
INT16 WINAPI OffsetRgn16( HRGN16 hrgn, INT16 x, INT16 y )
{
return OffsetRgn( HRGN_32(hrgn), x, y );
}
/***********************************************************************
* PtVisible (GDI.103)
*/
BOOL16 WINAPI PtVisible16( HDC16 hdc, INT16 x, INT16 y )
{
return PtVisible( HDC_32(hdc), x, y );
}
/***********************************************************************
* SelectVisRgn (GDI.105)
*/
INT16 WINAPI SelectVisRgn16( HDC16 hdc, HRGN16 hrgn )
{
FIXME( "%04x %04x no longer supported\n", hdc, hrgn );
return ERROR;
}
/***********************************************************************
* SetBitmapBits (GDI.106)
*/
LONG WINAPI SetBitmapBits16( HBITMAP16 hbitmap, LONG count, LPCVOID buffer )
{
HBITMAP hbmp32 = HBITMAP_32(hbitmap);
BITMAP bmp;
if (GetObject(hbmp32, sizeof(BITMAP), &bmp) != sizeof(BITMAP))
return 0;
if (krnl386_get_compat_mode("256color") && (bmp.bmBitsPixel > 8))
{
HDC dc = CreateCompatibleDC(NULL);
BITMAPINFO *bmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 256*2 + sizeof(BITMAPINFOHEADER));
UINT16 *colors = (UINT16 *)bmap->bmiColors;
bmap->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmap->bmiHeader.biWidth = bmp.bmWidth;
bmap->bmiHeader.biHeight = -(count / bmp.bmWidth);
bmap->bmiHeader.biPlanes = 1;
bmap->bmiHeader.biBitCount = 8;
for (int i = 0; i < 256; i++)
colors[i] = i;
HPALETTE oldpal = GetCurrentObject(dc, OBJ_PAL);
if (krnl386_get_config_int("otvdm", "DIBPalette", FALSE))
SelectPalette(dc, get_realized_palette(), FALSE);
int ret = SetDIBits(dc, hbmp32, 0, abs(bmap->bmiHeader.biHeight), buffer, bmap, DIB_PAL_COLORS);
HeapFree(GetProcessHeap(), 0, bmap);
SelectPalette(dc, oldpal, FALSE);
DeleteDC(dc);
return ret * bmp.bmWidth;
}
DWORD size = bmp.bmHeight * bmp.bmWidthBytes;
return SetBitmapBits( hbmp32, min(size, count), buffer );
}
#include
typedef struct
{
SHORT dfVersion; /* Version */
LONG dfSize; /* Total File Size */
char dfCopyright[60]; /* Copyright notice */
FONTINFO16 fi; /* FONTINFO structure */
} WINFNT;
#include
LPCSTR krnl386_search_executable_file(LPCSTR lpFile, LPSTR buf, SIZE_T size, BOOL search_builtin);
NE_TYPEINFO *get_resource_table(HMODULE16 hmod, LPCSTR type, LPBYTE *restab);
/***********************************************************************
* AddFontResource (GDI.119)
*/
INT16 WINAPI AddFontResource16( LPCSTR filename )
{
int ret = 0;
LPCSTR filenameold = filename;
char filebuf[MAX_PATH];
char module[MAX_PATH];
if (!HIWORD(filename))
{
if (!GetModuleFileName16(filename, module, MAX_PATH))
return 0;
filename = module;
}
filename = krnl386_search_executable_file(filename, filebuf, MAX_PATH, FALSE);
TRACE("(%s(%s))\n", debugstr_a(filenameold), debugstr_a(filename));
ret = AddFontResourceExA(filename, FR_PRIVATE, 0);
if (ret) return ret;
// try to load 0x100 version bitmap font by converting to a 0x200 font
// which Windows can load
HINSTANCE16 mod = 0;
HANDLE fh, mh;
NE_NAMEINFO *name;
int count = 0;
LPVOID font;
if ((mod = LoadLibrary16(filename)) >= 32)
{
NE_TYPEINFO *type = get_resource_table(mod, RT_FONT, NULL);
if (!type)
{
FreeLibrary16(mod);
return 0;
}
count = type->count;
name = (NE_NAMEINFO*)(type + 1);
}
else
{
fh = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(fh == INVALID_HANDLE_VALUE)
return 0;
mh = CreateFileMappingA(fh, filename, PAGE_READONLY, 0, 0, NULL);
font = MapViewOfFile(mh, FILE_MAP_READ, 0, 0, 0);
count = 1;
mod = 0;
}
char *dst = HeapAlloc(GetProcessHeap(), 0, 65536);
HGLOBAL16 mem = 0;
__TRY
{
for(int num = 0; num < count; num++)
{
WINFNT *fnt;
int size;
if(mod)
{
if (mem)
FreeResource16(mem);
HRSRC16 res = FindResource16(mod, name->id, 8);
mem = LoadResource16(mod, res);
font = LockResource16(mem);
size = SizeofResource16(mod, res);
name++;
}
else
size = GetFileSize(fh, NULL);
fnt = font;
if (fnt->dfVersion != 0x100)
{
int fnum;
if (AddFontMemResourceEx(font, fnt->dfSize, 0, &fnum))
{
TRACE("Added %d fonts\n", fnum);
ret += fnum;
}
continue;
}
if((size < 117) || (fnt->fi.dfType & 1))
continue;
memcpy(dst, font, 118);
int fontsize = (unsigned char)fnt->fi.dfLastChar - (unsigned char)fnt->fi.dfFirstChar + 2;
WORD *charoff = (char *)font + 117;
WORD *ncharoff = dst + 118;
int hdrsize = 118 + (fontsize * 4);
if(size < (117 + (fnt->fi.dfPixWidth ? (fontsize * 2) : 0) + (fnt->fi.dfWidthBytes * fnt->fi.dfPixHeight)))
{
TRACE("Font corrupt\n");
continue;
}
for(int i = 0; i < (fontsize - 1); i++)
{
ncharoff[i * 2] = fnt->fi.dfPixWidth ? fnt->fi.dfPixWidth : charoff[i + 1] - charoff[i];
ncharoff[(i * 2) + 1] = i ? (((ncharoff[(i * 2) - 2] + 7) / 8) * fnt->fi.dfPixHeight) + ncharoff[(i * 2) - 1] : hdrsize;
}
ncharoff[(fontsize - 1) * 2] = ncharoff[((fontsize - 1) * 2) + 1] = 0;
int rowwid = fnt->fi.dfWidthBytes;
int nbitsize = ncharoff[(fontsize * 2) - 3] + (((ncharoff[(fontsize * 2) - 4] + 7) / 8) * fnt->fi.dfPixHeight) - hdrsize;
char *bitdata = (char *)font + fnt->fi.dfBitsOffset;
char *nbitdata = dst + hdrsize;
for(int i = 0; i < (fontsize - 1); i++)
{
int addr = ncharoff[(i * 2) + 1] - hdrsize;
int bytewid = (ncharoff[i * 2] + 7) / 8;
for(int j = 0; j < fnt->fi.dfPixHeight; j++)
{
for(int k = 0; k < bytewid; k++)
{
WORD bits = *(WORD *)(bitdata + (rowwid * j) + ((fnt->fi.dfPixWidth ? fnt->fi.dfPixWidth : charoff[i]) / 8) + k);
bits = (bits >> 8) | (bits << 8);
bits <<= charoff[i] % 8;
nbitdata[addr + j + (k * fnt->fi.dfPixHeight)] = bits >> 8;
}
}
}
strncpy(dst + hdrsize + nbitsize, (char *)font + fnt->fi.dfFace, 256);
int namelen = strlen(dst + hdrsize + nbitsize);
if (namelen > 256)
namelen = 256;
fnt = dst;
fnt->dfVersion = 0x200;
fnt->fi.dfBitsOffset = hdrsize;
fnt->fi.dfFace = hdrsize + nbitsize;
fnt->dfSize = fnt->fi.dfFace + namelen + 1;
if (fnt->fi.dfCharSet == 0xfe) // pagemaker fonts have charset 0xfe which windows 10 treats as utf-8
fnt->fi.dfCharSet = 0xfd;
int fnum;
if (AddFontMemResourceEx(dst, fnt->dfSize, 0, &fnum))
{
TRACE("Added %d fonts\n", fnum);
ret += fnum;
}
}
}
__EXCEPT_ALL
{
ERR("Failed to load old font\n");
}
__ENDTRY
if(mod)
{
if (mem)
FreeResource16(mem);
FreeLibrary16(mod);
}
else
{
UnmapViewOfFile(font);
CloseHandle(mh);
CloseHandle(fh);
}
HeapFree(GetProcessHeap(), 0, dst);
return ret;
}
/***********************************************************************
* Death (GDI.121)
*
* Disables GDI, switches back to text mode.
* We don't have to do anything here,
* just let console support handle everything
*/
void WINAPI Death16(HDC16 hdc)
{
MESSAGE("Death(%04x) called. Application enters text mode...\n", hdc);
}
/***********************************************************************
* Resurrection (GDI.122)
*
* Restores GDI functionality
*/
void WINAPI Resurrection16(HDC16 hdc,
WORD w1, WORD w2, WORD w3, WORD w4, WORD w5, WORD w6)
{
MESSAGE("Resurrection(%04x, %04x, %04x, %04x, %04x, %04x, %04x) called. Application left text mode.\n",
hdc, w1, w2, w3, w4, w5, w6);
}
/***********************************************************************
* MulDiv (GDI.128)
*/
INT16 WINAPI MulDiv16( INT16 nMultiplicand, INT16 nMultiplier, INT16 nDivisor)
{
INT ret;
if (!nDivisor) return -32768;
/* We want to deal with a positive divisor to simplify the logic. */
if (nDivisor < 0)
{
nMultiplicand = - nMultiplicand;
nDivisor = -nDivisor;
}
/* If the result is positive, we "add" to round. else,
* we subtract to round. */
if ( ( (nMultiplicand < 0) && (nMultiplier < 0) ) ||
( (nMultiplicand >= 0) && (nMultiplier >= 0) ) )
ret = (((int)nMultiplicand * nMultiplier) + (nDivisor/2)) / nDivisor;
else
ret = (((int)nMultiplicand * nMultiplier) - (nDivisor/2)) / nDivisor;
if ((ret > 32767) || (ret < -32767)) return -32768;
return (INT16) ret;
}
/***********************************************************************
* GetRgnBox (GDI.134)
*/
INT16 WINAPI GetRgnBox16( HRGN16 hrgn, LPRECT16 rect )
{
RECT r;
INT16 ret = GetRgnBox( HRGN_32(hrgn), &r );
rect->left = r.left;
rect->top = r.top;
rect->right = r.right;
rect->bottom = r.bottom;
return ret;
}
/***********************************************************************
* RemoveFontResource (GDI.136)
*/
BOOL16 WINAPI RemoveFontResource16( LPCSTR filename)
{
char filebuf[MAX_PATH];
char module[MAX_PATH];
if (!HIWORD(filename))
{
if (!GetModuleFileName16(filename, module, MAX_PATH))
return 0;
filename = module;
}
filename = krnl386_search_executable_file(filename, filebuf, MAX_PATH, FALSE);
return RemoveFontResourceExA(filename, FR_PRIVATE, 0);
}
/***********************************************************************
* SetBrushOrg (GDI.148)
*/
DWORD WINAPI SetBrushOrg16( HDC16 hdc, INT16 x, INT16 y )
{
POINT dcpt;
POINT pt;
if (GetDCOrgEx(HDC_32(hdc), &dcpt))
{
x -= dcpt.x;
y -= dcpt.y;
if (!SetBrushOrgEx(HDC_32(hdc), x, y, &pt)) return 0;
pt.x += dcpt.x;
pt.y += dcpt.y;
}
return MAKELONG( pt.x, pt.y );
}
/***********************************************************************
* GetBrushOrg (GDI.149)
*/
DWORD WINAPI GetBrushOrg16( HDC16 hdc )
{
POINT dcpt;
POINT pt;
if (GetDCOrgEx(HDC_32(hdc), &dcpt))
{
if (!GetBrushOrgEx(HDC_32(hdc), &pt)) return 0;
pt.x += dcpt.x;
pt.y += dcpt.y;
}
return MAKELONG( pt.x, pt.y );
}
/***********************************************************************
* UnrealizeObject (GDI.150)
*/
BOOL16 WINAPI UnrealizeObject16( HGDIOBJ16 obj )
{
return UnrealizeObject( HGDIOBJ_32(obj) );
}
/***********************************************************************
* CreateIC (GDI.153)
*/
HDC16 WINAPI CreateIC16( LPCSTR driver, LPCSTR device, LPCSTR output,
const DEVMODEA* initData )
{
char tmp[256];
if (device && !strcmp(device, "DefaultPrinter"))
{
int len = 256;
if (GetDefaultPrinterA(tmp, &len))
device = tmp;
}
if (initData && (!driver || !stricmp(driver, "winspool")))
{
DEVMODEA dma = {0};
if (!IsValidDevmodeA(initData, initData->dmSize + initData->dmDriverExtra))
initData = NULL;
else
{
memcpy(&dma, initData, initData->dmSize);
dma.dmSize = sizeof(DEVMODEA);
dma.dmDriverExtra = 0;
return HDC_16( CreateICA( driver, device, output, &dma ) );
}
}
else if (!stricmp(driver, "dib"))
driver = "DISPLAY";
return HDC_16( CreateICA( driver, device, output, initData ) );
}
/***********************************************************************
* GetNearestColor (GDI.154)
*/
COLORREF WINAPI GetNearestColor16( HDC16 hdc, COLORREF color )
{
return GetNearestColor( HDC_32(hdc), check_colorref(color) );
}
/***********************************************************************
* CreateDiscardableBitmap (GDI.156)
*/
HBITMAP16 WINAPI CreateDiscardableBitmap16( HDC16 hdc, INT16 width, INT16 height )
{
return HBITMAP_16( CreateDiscardableBitmap( HDC_32(hdc), width, height ) );
}
/***********************************************************************
* PtInRegion (GDI.161)
*/
BOOL16 WINAPI PtInRegion16( HRGN16 hrgn, INT16 x, INT16 y )
{
return PtInRegion( HRGN_32(hrgn), x, y );
}
/***********************************************************************
* GetBitmapDimension (GDI.162)
*/
DWORD WINAPI GetBitmapDimension16( HBITMAP16 hbitmap )
{
SIZE16 size;
if (!GetBitmapDimensionEx16( hbitmap, &size )) return 0;
return MAKELONG( size.cx, size.cy );
}
/***********************************************************************
* SetBitmapDimension (GDI.163)
*/
DWORD WINAPI SetBitmapDimension16( HBITMAP16 hbitmap, INT16 x, INT16 y )
{
SIZE16 size;
if (!SetBitmapDimensionEx16( hbitmap, x, y, &size )) return 0;
return MAKELONG( size.cx, size.cy );
}
/***********************************************************************
* SetRectRgn (GDI.172)
*
* NOTE: Win 3.1 sets region to empty if left > right
*/
void WINAPI SetRectRgn16( HRGN16 hrgn, INT16 left, INT16 top, INT16 right, INT16 bottom )
{
if (left < right) SetRectRgn( HRGN_32(hrgn), left, top, right, bottom );
else SetRectRgn( HRGN_32(hrgn), 0, 0, 0, 0 );
}
/******************************************************************
* PlayMetaFileRecord (GDI.176)
*/
void WINAPI PlayMetaFileRecord16( HDC16 hdc, HANDLETABLE16 *ht, METARECORD *mr, UINT16 handles )
{
HANDLETABLE *ht32 = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET(HANDLETABLE, objectHandle[handles] ));
unsigned int i;
for (i = 0; i < handles; i++) ht32->objectHandle[i] = HGDIOBJ_32(ht->objectHandle[i]);
PlayMetaFileRecord( HDC_32(hdc), ht32, mr, handles );
for (i = 0; i < handles; i++) ht->objectHandle[i] = HGDIOBJ_16(ht32->objectHandle[i]);
HeapFree( GetProcessHeap(), 0, ht32 );
}
/***********************************************************************
* SetDCHook (GDI.190)
*/
BOOL16 WINAPI SetDCHook16( HDC16 hdc16, FARPROC16 hookProc, DWORD dwHookData )
{
FIXME( "%04x %p %x: not supported\n", hdc16, hookProc, dwHookData );
return FALSE;
}
/***********************************************************************
* GetDCHook (GDI.191)
*/
DWORD WINAPI GetDCHook16( HDC16 hdc16, FARPROC16 *phookProc )
{
FIXME( "%04x: not supported\n", hdc16 );
return 0;
}
/***********************************************************************
* SetHookFlags (GDI.192)
*/
WORD WINAPI SetHookFlags16( HDC16 hdc, WORD flags )
{
FIXME( "%04x %x: not supported\n", hdc, flags );
return 0;
}
/***********************************************************************
* SetBoundsRect (GDI.193)
*/
UINT16 WINAPI SetBoundsRect16( HDC16 hdc, const RECT16* rect, UINT16 flags )
{
if (rect)
{
RECT rect32;
rect32.left = rect->left;
rect32.top = rect->top;
rect32.right = rect->right;
rect32.bottom = rect->bottom;
return SetBoundsRect( HDC_32( hdc ), &rect32, flags );
}
else return SetBoundsRect( HDC_32( hdc ), NULL, flags );
}
/***********************************************************************
* GetBoundsRect (GDI.194)
*/
UINT16 WINAPI GetBoundsRect16( HDC16 hdc, LPRECT16 rect, UINT16 flags)
{
RECT rect32;
UINT ret = GetBoundsRect( HDC_32( hdc ), &rect32, flags );
if (rect)
{
rect->left = rect32.left;
rect->top = rect32.top;
rect->right = rect32.right;
rect->bottom = rect32.bottom;
}
return ret;
}
/***********************************************************************
* EngineEnumerateFont (GDI.300)
*/
WORD WINAPI EngineEnumerateFont16(LPSTR fontname, FARPROC16 proc, DWORD data )
{
FIXME("(%s,%p,%x),stub\n",fontname,proc,data);
return 0;
}
/***********************************************************************
* EngineDeleteFont (GDI.301)
*/
WORD WINAPI EngineDeleteFont16(LPFONTINFO16 lpFontInfo)
{
WORD handle;
/* untested, don't know if it works.
We seem to access some structure that is located after the
FONTINFO. The FONTINFO documentation says that there may
follow some char-width table or font bitmap or vector info.
I think it is some kind of font bitmap that begins at offset 0x52,
as FONTINFO goes up to 0x51.
If this is correct, everything should be implemented correctly.
*/
if ( ((lpFontInfo->dfType & (RASTER_FONTTYPE|DEVICE_FONTTYPE)) == (RASTER_FONTTYPE|DEVICE_FONTTYPE))
&& (LOWORD(lpFontInfo->dfFace) == LOWORD(lpFontInfo)+0x6e)
&& (handle = *(WORD *)(lpFontInfo+0x54)) )
{
*(WORD *)(lpFontInfo+0x54) = 0;
GlobalFree16(handle);
}
return 1;
}
/***********************************************************************
* EngineRealizeFont (GDI.302)
*/
WORD WINAPI EngineRealizeFont16(LPLOGFONT16 lplogFont, LPTEXTXFORM16 lptextxform, LPFONTINFO16 lpfontInfo)
{
FIXME("(%p,%p,%p),stub\n",lplogFont,lptextxform,lpfontInfo);
return 0;
}
/***********************************************************************
* EngineRealizeFontExt (GDI.315)
*/
WORD WINAPI EngineRealizeFontExt16(LONG l1, LONG l2, LONG l3, LONG l4)
{
FIXME("(%08x,%08x,%08x,%08x),stub\n",l1,l2,l3,l4);
return 0;
}
/***********************************************************************
* EngineGetCharWidth (GDI.303)
*/
WORD WINAPI EngineGetCharWidth16(LPFONTINFO16 lpFontInfo, BYTE firstChar, BYTE lastChar, LPINT16 buffer)
{
int i;
for (i = firstChar; i <= lastChar; i++)
FIXME(" returns font's average width for range %d to %d\n", firstChar, lastChar);
*buffer++ = lpFontInfo->dfAvgWidth; /* insert some charwidth functionality here; use average width for now */
return 1;
}
/***********************************************************************
* EngineSetFontContext (GDI.304)
*/
WORD WINAPI EngineSetFontContext16(LPFONTINFO16 lpFontInfo, WORD data)
{
FIXME("stub?\n");
return 0;
}
/***********************************************************************
* EngineGetGlyphBMP (GDI.305)
*/
WORD WINAPI EngineGetGlyphBMP16(WORD word, LPFONTINFO16 lpFontInfo, WORD w1, WORD w2,
LPSTR string, DWORD dword, /*LPBITMAPMETRICS16*/ LPVOID metrics)
{
FIXME("stub?\n");
return 0;
}
/***********************************************************************
* EngineMakeFontDir (GDI.306)
*/
DWORD WINAPI EngineMakeFontDir16(HDC16 hdc, LPFONTDIR16 fontdir, LPCSTR string)
{
FIXME(" stub! (always fails)\n");
return ~0UL; /* error */
}
/***********************************************************************
* GetCharABCWidths (GDI.307)
*/
BOOL16 WINAPI GetCharABCWidths16( HDC16 hdc, UINT16 firstChar, UINT16 lastChar, LPABC16 abc )
{
BOOL ret;
UINT i;
LPABC abc32 = HeapAlloc( GetProcessHeap(), 0, sizeof(ABC) * (lastChar - firstChar + 1) );
if ((ret = GetCharABCWidthsA( HDC_32(hdc), firstChar, lastChar, abc32 )))
{
for (i = firstChar; i <= lastChar; i++)
{
abc[i-firstChar].abcA = abc32[i-firstChar].abcA;
abc[i-firstChar].abcB = abc32[i-firstChar].abcB;
abc[i-firstChar].abcC = abc32[i-firstChar].abcC;
}
}
HeapFree( GetProcessHeap(), 0, abc32 );
return ret;
}
/***********************************************************************
* GetOutlineTextMetrics (GDI.308)
*
* Gets metrics for TrueType fonts.
*
* PARAMS
* hdc [In] Handle of device context
* cbData [In] Size of metric data array
* lpOTM [Out] Address of metric data array
*
* RETURNS
* Success: Non-zero or size of required buffer
* Failure: 0
*
* NOTES
* lpOTM should be LPOUTLINETEXTMETRIC
*/
UINT16 WINAPI GetOutlineTextMetrics16( HDC16 hdc, UINT16 cbData,
LPOUTLINETEXTMETRIC16 lpOTM )
{
HDC hdc32 = HDC_32(hdc);
int offset = sizeof(OUTLINETEXTMETRICA) - sizeof(*lpOTM);
if (!lpOTM)
{
UINT buf_size = GetOutlineTextMetricsA(hdc32, NULL, NULL);
if (buf_size == 0)
return 0;
return buf_size - offset;
}
if (cbData < sizeof(OUTLINETEXTMETRIC16))
return 0;
/* extra data size for strings */
SIZE_T exsize = cbData - sizeof(*lpOTM);
LPOUTLINETEXTMETRICA otm32 = HeapAlloc(GetProcessHeap(), 0, sizeof(OUTLINETEXTMETRICA) + exsize);
otm32->otmSize = sizeof(*otm32) + exsize;
UINT result = GetOutlineTextMetricsA(hdc32, sizeof(*otm32) + exsize, otm32);
if (result == 0)
{
HeapFree(GetProcessHeap(), 0, otm32);
return 0;
}
lpOTM->otmSize = otm32->otmSize - offset;
lpOTM->otmTextMetrics.tmHeight = otm32->otmTextMetrics.tmHeight;
lpOTM->otmTextMetrics.tmAscent = otm32->otmTextMetrics.tmAscent;
lpOTM->otmTextMetrics.tmDescent = otm32->otmTextMetrics.tmDescent;
lpOTM->otmTextMetrics.tmInternalLeading = otm32->otmTextMetrics.tmInternalLeading;
lpOTM->otmTextMetrics.tmExternalLeading = otm32->otmTextMetrics.tmExternalLeading;
lpOTM->otmTextMetrics.tmAveCharWidth = otm32->otmTextMetrics.tmAveCharWidth;
lpOTM->otmTextMetrics.tmMaxCharWidth = otm32->otmTextMetrics.tmMaxCharWidth;
lpOTM->otmTextMetrics.tmWeight = otm32->otmTextMetrics.tmWeight;
lpOTM->otmTextMetrics.tmOverhang = otm32->otmTextMetrics.tmOverhang;
lpOTM->otmTextMetrics.tmDigitizedAspectX = otm32->otmTextMetrics.tmDigitizedAspectX;
lpOTM->otmTextMetrics.tmDigitizedAspectY = otm32->otmTextMetrics.tmDigitizedAspectY;
lpOTM->otmTextMetrics.tmFirstChar = otm32->otmTextMetrics.tmFirstChar;
lpOTM->otmTextMetrics.tmLastChar = otm32->otmTextMetrics.tmLastChar;
lpOTM->otmTextMetrics.tmDefaultChar = otm32->otmTextMetrics.tmDefaultChar;
lpOTM->otmTextMetrics.tmBreakChar = otm32->otmTextMetrics.tmBreakChar;
lpOTM->otmTextMetrics.tmItalic = otm32->otmTextMetrics.tmItalic;
lpOTM->otmTextMetrics.tmUnderlined = otm32->otmTextMetrics.tmUnderlined;
lpOTM->otmTextMetrics.tmStruckOut = otm32->otmTextMetrics.tmStruckOut;
lpOTM->otmTextMetrics.tmPitchAndFamily = otm32->otmTextMetrics.tmPitchAndFamily;
lpOTM->otmTextMetrics.tmCharSet = otm32->otmTextMetrics.tmCharSet;
lpOTM->otmFiller = otm32->otmFiller;
lpOTM->otmPanoseNumber = otm32->otmPanoseNumber;
lpOTM->otmfsSelection = otm32->otmfsSelection;
lpOTM->otmfsType = otm32->otmfsType;
lpOTM->otmsCharSlopeRise = otm32->otmsCharSlopeRise;
lpOTM->otmsCharSlopeRun = otm32->otmsCharSlopeRun;
lpOTM->otmItalicAngle = otm32->otmItalicAngle;
lpOTM->otmEMSquare = otm32->otmEMSquare;
lpOTM->otmAscent = otm32->otmAscent;
lpOTM->otmDescent = otm32->otmDescent;
lpOTM->otmLineGap = otm32->otmLineGap;
lpOTM->otmsCapEmHeight = otm32->otmsCapEmHeight;
lpOTM->otmsXHeight = otm32->otmsXHeight;
lpOTM->otmrcFontBox.left = otm32->otmrcFontBox.left;
lpOTM->otmrcFontBox.top = otm32->otmrcFontBox.top;
lpOTM->otmrcFontBox.right = otm32->otmrcFontBox.right;
lpOTM->otmrcFontBox.bottom = otm32->otmrcFontBox.bottom;
lpOTM->otmMacAscent = otm32->otmMacAscent;
lpOTM->otmMacDescent = otm32->otmMacDescent;
lpOTM->otmMacLineGap = otm32->otmMacLineGap;
lpOTM->otmusMinimumPPEM = otm32->otmusMinimumPPEM;
lpOTM->otmptSubscriptSize.x = otm32->otmptSubscriptSize.x;
lpOTM->otmptSubscriptSize.y = otm32->otmptSubscriptSize.y;
lpOTM->otmptSubscriptOffset.x = otm32->otmptSubscriptOffset.x;
lpOTM->otmptSubscriptOffset.y = otm32->otmptSubscriptOffset.y;
lpOTM->otmptSuperscriptSize.x = otm32->otmptSuperscriptSize.x;
lpOTM->otmptSuperscriptSize.y = otm32->otmptSuperscriptSize.y;
lpOTM->otmptSuperscriptOffset.x = otm32->otmptSuperscriptOffset.x;
lpOTM->otmptSuperscriptOffset.y = otm32->otmptSuperscriptOffset.y;
lpOTM->otmsStrikeoutSize = otm32->otmsStrikeoutSize;
lpOTM->otmsStrikeoutPosition = otm32->otmsStrikeoutPosition;
lpOTM->otmsUnderscorePosition = otm32->otmsUnderscorePosition;
lpOTM->otmsUnderscoreSize = otm32->otmsUnderscoreSize;
lpOTM->otmpFamilyName = otm32->otmpFamilyName ? (SIZE_T)otm32->otmpFamilyName - offset : 0;
lpOTM->otmpFaceName = otm32->otmpFaceName ? (SIZE_T)otm32->otmpFaceName - offset : 0;
lpOTM->otmpStyleName = otm32->otmpStyleName ? (SIZE_T)otm32->otmpStyleName - offset : 0;
lpOTM->otmpFullName = otm32->otmpFullName ? (SIZE_T)otm32->otmpFullName - offset : 0;
memcpy((LPBYTE)lpOTM + sizeof(*lpOTM), (LPBYTE)otm32 + sizeof(*otm32), result - sizeof(*otm32));
HeapFree(GetProcessHeap(), 0, otm32);
return result - offset;
}
/***********************************************************************
* GetGlyphOutline (GDI.309)
*/
DWORD WINAPI GetGlyphOutline16( HDC16 hdc, UINT16 uChar, UINT16 fuFormat,
LPGLYPHMETRICS16 lpgm, DWORD cbBuffer,
LPVOID lpBuffer, const MAT2 *lpmat2 )
{
DWORD ret;
GLYPHMETRICS gm32;
ret = GetGlyphOutlineA( HDC_32(hdc), uChar, fuFormat, &gm32, cbBuffer, lpBuffer, lpmat2);
if (ret && ret != GDI_ERROR)
{
lpgm->gmBlackBoxX = gm32.gmBlackBoxX;
lpgm->gmBlackBoxY = gm32.gmBlackBoxY;
lpgm->gmptGlyphOrigin.x = gm32.gmptGlyphOrigin.x;
lpgm->gmptGlyphOrigin.y = gm32.gmptGlyphOrigin.y;
lpgm->gmCellIncX = gm32.gmCellIncX;
lpgm->gmCellIncY = gm32.gmCellIncY;
}
return ret;
}
/***********************************************************************
* CreateScalableFontResource (GDI.310)
*/
BOOL16 WINAPI CreateScalableFontResource16( UINT16 fHidden, LPCSTR lpszResourceFile,
LPCSTR fontFile, LPCSTR path )
{
return CreateScalableFontResourceA( fHidden, lpszResourceFile, fontFile, path );
}
/*************************************************************************
* GetFontData (GDI.311)
*
*/
DWORD WINAPI GetFontData16( HDC16 hdc, DWORD table, DWORD offset, LPVOID buffer, DWORD count )
{
return GetFontData( HDC_32(hdc), table, offset, buffer, count );
}
/*************************************************************************
* GetRasterizerCaps (GDI.313)
*/
BOOL16 WINAPI GetRasterizerCaps16( LPRASTERIZER_STATUS lprs, UINT16 cbNumBytes )
{
/* LPRASTERIZER_STATUS must be aligned */
BYTE caps_buf[100] = { 0 };
LPRASTERIZER_STATUS cap = caps_buf + (sizeof(SIZE_T) - (SIZE_T)caps_buf % sizeof(SIZE_T));
if (GetRasterizerCaps(cap, cbNumBytes))
{
memcpy(lprs, cap, min(cbNumBytes, sizeof(RASTERIZER_STATUS)));
return TRUE;
}
else
{
return FALSE;
}
}
/***********************************************************************
* EnumFontFamilies (GDI.330)
*/
INT16 WINAPI EnumFontFamilies16( HDC16 hDC, LPCSTR lpFamily,
FONTENUMPROC16 efproc, LPARAM lpData )
{
struct callback16_info info;
info.proc = (FARPROC16)efproc;
info.param = lpData;
info.result = 1;
return EnumFontFamiliesA(HDC_32(hDC), lpFamily, enum_font_callback, (LPARAM)&info);
}
/*************************************************************************
* GetKerningPairs (GDI.332)
*
*/
INT16 WINAPI GetKerningPairs16( HDC16 hdc, INT16 count, LPKERNINGPAIR16 pairs )
{
KERNINGPAIR *pairs32;
INT i, ret;
if (!count) return 0;
if (!(pairs32 = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*pairs32) ))) return 0;
if ((ret = GetKerningPairsA( HDC_32(hdc), count, pairs32 )))
{
for (i = 0; i < ret; i++)
{
pairs->wFirst = pairs32->wFirst;
pairs->wSecond = pairs32->wSecond;
pairs->iKernAmount = pairs32->iKernAmount;
}
}
HeapFree( GetProcessHeap(), 0, pairs32 );
return ret;
}
/***********************************************************************
* GetTextAlign (GDI.345)
*/
UINT16 WINAPI GetTextAlign16( HDC16 hdc )
{
return GetTextAlign( HDC_32(hdc) );
}
/***********************************************************************
* SetTextAlign (GDI.346)
*/
UINT16 WINAPI SetTextAlign16( HDC16 hdc, UINT16 align )
{
return SetTextAlign( HDC_32(hdc), align );
}
/***********************************************************************
* Chord (GDI.348)
*/
BOOL16 WINAPI Chord16( HDC16 hdc, INT16 left, INT16 top,
INT16 right, INT16 bottom, INT16 xstart, INT16 ystart,
INT16 xend, INT16 yend )
{
return Chord( HDC_32(hdc), left, top, right, bottom, xstart, ystart, xend, yend );
}
/***********************************************************************
* SetMapperFlags (GDI.349)
*/
DWORD WINAPI SetMapperFlags16( HDC16 hdc, DWORD flags )
{
return SetMapperFlags( HDC_32(hdc), flags );
}
/***********************************************************************
* GetCharWidth (GDI.350)
*/
BOOL16 WINAPI GetCharWidth16( HDC16 hdc, UINT16 firstChar, UINT16 lastChar, LPINT16 buffer )
{
BOOL retVal = FALSE;
TEXTMETRIC tm = {0};
HDC hdc32 = HDC_32(hdc);
GetTextMetricsA(hdc32, &tm);
if( firstChar != lastChar )
{
LPINT buf32 = HeapAlloc(GetProcessHeap(), 0, sizeof(INT)*(1 + (lastChar - firstChar)));
if( buf32 )
{
LPINT obuf32 = buf32;
UINT i;
retVal = GetCharWidth32A( hdc32, firstChar, lastChar, buf32);
if (retVal)
{
for (i = firstChar; i <= lastChar; i++) *buffer++ = (*buf32++) + tm.tmOverhang;
}
HeapFree(GetProcessHeap(), 0, obuf32);
}
}
else /* happens quite often to warrant a special treatment */
{
INT chWidth;
retVal = GetCharWidth32A( hdc32, firstChar, lastChar, &chWidth );
*buffer = chWidth + tm.tmOverhang;
}
return retVal;
}
/***********************************************************************
* ExtTextOut (GDI.351)
*/
BOOL16 WINAPI ExtTextOut16( HDC16 hdc, INT16 x, INT16 y, UINT16 flags,
const RECT16 *lprect, LPCSTR str, UINT16 count,
const INT16 *lpDx )
{
BOOL ret;
int i;
RECT rect32;
LPINT lpdx32 = NULL;
if (lpDx) {
lpdx32 = HeapAlloc( GetProcessHeap(),0, sizeof(INT)*count );
if(lpdx32 == NULL) return FALSE;
for (i=count;i--;) lpdx32[i]=lpDx[i];
}
if (lprect)
{
rect32.left = lprect->left;
rect32.top = lprect->top;
rect32.right = lprect->right;
rect32.bottom = lprect->bottom;
}
ret = ExtTextOutA(HDC_32(hdc), x, y, flags, lprect ? &rect32 : NULL, str, count, lpdx32);
HeapFree( GetProcessHeap(), 0, lpdx32 );
return ret;
}
/***********************************************************************
* CreatePalette (GDI.360)
*/
HPALETTE16 WINAPI CreatePalette16( const LOGPALETTE* palette )
{
return HPALETTE_16( CreatePalette( palette ) );
}
/***********************************************************************
* GDISelectPalette (GDI.361)
*/
HPALETTE16 WINAPI GDISelectPalette16( HDC16 hdc, HPALETTE16 hpalette, WORD wBkg )
{
HPALETTE16 ret = HPALETTE_16( SelectPalette( HDC_32(hdc), HPALETTE_32(hpalette), wBkg ));
if (ret && !wBkg) hPrimaryPalette = hpalette;
return ret;
}
/***********************************************************************
* GDIRealizePalette (GDI.362)
*/
UINT16 WINAPI GDIRealizePalette16( HDC16 hdc )
{
HDC hdc32 = HDC_32(hdc);
if (krnl386_get_compat_mode("256color") && krnl386_get_config_int("otvdm", "DIBPalette", FALSE) && (GetDeviceCaps(hdc32, TECHNOLOGY) == DT_RASDISPLAY) &&
(GetObjectType(hdc32) == OBJ_DC))
set_realized_palette(hdc32);
return RealizePalette(hdc32);
}
/***********************************************************************
* GetPaletteEntries (GDI.363)
*/
UINT16 WINAPI GetPaletteEntries16( HPALETTE16 hpalette, UINT16 start,
UINT16 count, LPPALETTEENTRY entries )
{
return GetPaletteEntries( HPALETTE_32(hpalette), start, count, entries );
}
static WINAPI paint_all_windows(HWND hwnd, LPARAM lparam)
{
BOOL found = FALSE;
DWORD *wndlist = (DWORD *)lparam;
for (int j = 1; j <= wndlist[0]; j++)
{
if (wndlist[j] == hwnd)
{
found = TRUE;
break;
}
}
if (!found)
RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
return FALSE;
}
BOOL update_palette(HPALETTE16 hpalette)
{
HPALETTE hpal32 = HPALETTE_32(hpalette);
if (GetObjectType(hpal32) != OBJ_PAL) return;
DWORD *dclist = GetPtr16(hpalette, 1);
DWORD *wndlist = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (dclist[0] + 1) * 4);
for (int i = 1; i < dclist[0]; i++)
{
if (dclist[i])
{
HDC hdc32 = HDC_32(dclist[i] & 0xffff);
if (!GetObjectType(hdc32) || (GetCurrentObject(hdc32, OBJ_PAL) != hpal32))
{
dclist[i] = 0;
continue;
}
HWND hwnd = WindowFromDC(hdc32);
if (hwnd)
{
BOOL found = FALSE;
for (int j = 1; j <= wndlist[0]; j++)
{
if (wndlist[j] == hwnd)
{
found = TRUE;
break;
}
}
if (!found)
{
wndlist[wndlist[0] + 1] = hwnd;
wndlist[0]++;
RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
}
}
else if (krnl386_get_config_int("otvdm", "DIBPalette", FALSE))
{
DIBSECTION dib;
HBITMAP bitmap = GetCurrentObject(hdc32, OBJ_BITMAP);
int ret = GetObject(bitmap, sizeof(DIBSECTION), &dib);
if ((ret == sizeof(DIBSECTION)) && (dib.dsBmih.biBitCount == 8) && !dib.dshSection && (GetPtr16(HBITMAP_16(bitmap), 1) == 0xd1b00001))
set_dib_colors(hdc32);
}
}
}
if (krnl386_get_config_int("otvdm", "DIBPalette", FALSE) && (hpal32 == get_realized_palette()))
EnumThreadWindows(GetCurrentThreadId(), paint_all_windows, wndlist);
HeapFree(GetProcessHeap(), 0, wndlist);
}
/***********************************************************************
* SetPaletteEntries (GDI.364)
*/
UINT16 WINAPI SetPaletteEntries16( HPALETTE16 hpalette, UINT16 start,
UINT16 count, const PALETTEENTRY *entries )
{
UINT16 ret = SetPaletteEntries( HPALETTE_32(hpalette), start, count, entries );
if (GetPtr16(hpalette, 1)) update_palette(hpalette);
return ret;
}
/**********************************************************************
* UpdateColors (GDI.366)
*/
INT16 WINAPI UpdateColors16( HDC16 hdc )
{
UpdateColors( HDC_32(hdc) );
return TRUE;
}
/***********************************************************************
* AnimatePalette (GDI.367)
*/
void WINAPI AnimatePalette16( HPALETTE16 hpalette, UINT16 StartIndex,
UINT16 NumEntries, const PALETTEENTRY* PaletteColors)
{
AnimatePalette(HPALETTE_32(hpalette), StartIndex, NumEntries, PaletteColors);
if (GetPtr16(hpalette, 1)) update_palette(hpalette);
}
/***********************************************************************
* ResizePalette (GDI.368)
*/
BOOL16 WINAPI ResizePalette16( HPALETTE16 hpalette, UINT16 cEntries )
{
return ResizePalette( HPALETTE_32(hpalette), cEntries );
}
/***********************************************************************
* GetNearestPaletteIndex (GDI.370)
*/
UINT16 WINAPI GetNearestPaletteIndex16( HPALETTE16 hpalette, COLORREF color )
{
return GetNearestPaletteIndex( HPALETTE_32(hpalette), check_colorref(color) );
}
/**********************************************************************
* ExtFloodFill (GDI.372)
*/
BOOL16 WINAPI ExtFloodFill16( HDC16 hdc, INT16 x, INT16 y, COLORREF color,
UINT16 fillType )
{
return ExtFloodFill( HDC_32(hdc), x, y, check_colorref(color), fillType );
}
/***********************************************************************
* SetSystemPaletteUse (GDI.373)
*/
UINT16 WINAPI SetSystemPaletteUse16( HDC16 hdc, UINT16 use )
{
syspaluse = use;
return SetSystemPaletteUse( HDC_32(hdc), use );
}
/***********************************************************************
* GetSystemPaletteUse (GDI.374)
*/
UINT16 WINAPI GetSystemPaletteUse16( HDC16 hdc )
{
UINT16 ret = GetSystemPaletteUse( HDC_32(hdc) );
if (!ret && krnl386_get_compat_mode("256color"))
ret = syspaluse;
return ret;
}
/***********************************************************************
* GetSystemPaletteEntries (GDI.375)
*/
UINT16 WINAPI GetSystemPaletteEntries16( HDC16 hdc, UINT16 start, UINT16 count,
LPPALETTEENTRY entries )
{
if (krnl386_get_compat_mode("256color") && krnl386_get_config_int("otvdm", "DIBPalette", FALSE))
{
HPALETTE hpal = get_realized_palette();
if (hpal == GetStockObject(DEFAULT_PALETTE))
{
GetSystemPaletteEntries( HDC_32(hdc), start, count, entries );
return min(count, 256 - start);
}
UINT ret = GetPaletteEntries(hpal, start, count, entries);
return ret;
}
return GetSystemPaletteEntries( HDC_32(hdc), start, count, entries );
}
/***********************************************************************
* ResetDC (GDI.376)
*/
HDC16 WINAPI ResetDC16( HDC16 hdc, const DEVMODEA *devmode )
{
DEVMODEA dma = {0};
if (!IsValidDevmodeA(devmode, devmode->dmSize + devmode->dmDriverExtra))
return NULL;
memcpy(&dma, devmode, devmode->dmSize);
dma.dmSize = sizeof(DEVMODEA);
dma.dmDriverExtra = 0;
if (!dma.dmDeviceName[0]) dma.dmDeviceName[0] = '.';
return HDC_16( ResetDCA( HDC_32(hdc), &dma ) );
}
/******************************************************************
* StartDoc (GDI.377)
*/
INT16 WINAPI StartDoc16( HDC16 hdc, const DOCINFO16 *lpdoc )
{
DOCINFOA docA;
DWORD count;
INT16 ret;
docA.cbSize = sizeof(DOCINFOA);
docA.lpszDocName = MapSL(lpdoc->lpszDocName);
docA.lpszOutput = MapSL(lpdoc->lpszOutput);
if(lpdoc->cbSize > offsetof(DOCINFO16,lpszDatatype))
docA.lpszDatatype = MapSL(lpdoc->lpszDatatype);
else
docA.lpszDatatype = NULL;
if(lpdoc->cbSize > offsetof(DOCINFO16,fwType))
docA.fwType = lpdoc->fwType;
else
docA.fwType = 0;
ReleaseThunkLock(&count);
ret = StartDocA( HDC_32(hdc), &docA );
// if startdoc tries to show a save file dialog but the active window
// disappears then it'll fail, try again and it should find a new window
if ((ret < 0) && (GetLastError() == ERROR_INVALID_WINDOW_HANDLE))
ret = StartDocA( HDC_32(hdc), &docA );
RestoreThunkLock(count);
return ret;
}
/******************************************************************
* EndDoc (GDI.378)
*/
INT16 WINAPI EndDoc16( HDC16 hdc )
{
return EndDoc( HDC_32(hdc) );
}
/******************************************************************
* StartPage (GDI.379)
*/
INT16 WINAPI StartPage16( HDC16 hdc )
{
return StartPage( HDC_32(hdc) );
}
/******************************************************************
* EndPage (GDI.380)
*/
INT16 WINAPI EndPage16( HDC16 hdc )
{
return EndPage( HDC_32(hdc) );
}
/******************************************************************************
* AbortDoc (GDI.382)
*/
INT16 WINAPI AbortDoc16( HDC16 hdc )
{
return AbortDoc( HDC_32(hdc) );
}
/***********************************************************************
* FastWindowFrame (GDI.400)
*/
BOOL16 WINAPI FastWindowFrame16( HDC16 hdc, const RECT16 *rect,
INT16 width, INT16 height, DWORD rop )
{
HDC hdc32 = HDC_32(hdc);
HBRUSH hbrush = SelectObject( hdc32, GetStockObject( GRAY_BRUSH ) );
PatBlt( hdc32, rect->left, rect->top,
rect->right - rect->left - width, height, rop );
PatBlt( hdc32, rect->left, rect->top + height, width,
rect->bottom - rect->top - height, rop );
PatBlt( hdc32, rect->left + width, rect->bottom - 1,
rect->right - rect->left - width, -height, rop );
PatBlt( hdc32, rect->right - 1, rect->top, -width,
rect->bottom - rect->top - height, rop );
SelectObject( hdc32, hbrush );
return TRUE;
}
/***********************************************************************
* GdiInit2 (GDI.403)
*
* See "Undocumented Windows"
*
* PARAMS
* h1 [I] GDI object
* h2 [I] global data
*/
HANDLE16 WINAPI GdiInit216( HANDLE16 h1, HANDLE16 h2 )
{
FIXME("(%04x, %04x), stub.\n", h1, h2);
if (h2 == 0xffff) return 0xffff; /* undefined return value */
return h1; /* FIXME: should be the memory handle of h1 */
}
/***********************************************************************
* FinalGdiInit (GDI.405)
*/
void WINAPI FinalGdiInit16( HBRUSH16 hPattern /* [in] fill pattern of desktop */ )
{
}
/***********************************************************************
* CreateUserBitmap (GDI.407)
*/
HBITMAP16 WINAPI CreateUserBitmap16( INT16 width, INT16 height, UINT16 planes,
UINT16 bpp, LPCVOID bits )
{
return CreateBitmap16( width, height, planes, bpp, bits );
}
/***********************************************************************
* CreateUserDiscardableBitmap (GDI.409)
*/
HBITMAP16 WINAPI CreateUserDiscardableBitmap16( WORD dummy, INT16 width, INT16 height )
{
HDC hdc = CreateDCA( "DISPLAY", NULL, NULL, NULL );
HBITMAP ret = CreateCompatibleBitmap( hdc, width, height );
DeleteDC( hdc );
return HBITMAP_16(ret);
}
/***********************************************************************
* GetCurLogFont (GDI.411)
*/
HFONT16 WINAPI GetCurLogFont16( HDC16 hdc )
{
return HFONT_16( GetCurrentObject( HDC_32(hdc), OBJ_FONT ) );
}
static DWORD rle_size(int type, const VOID *bits)
{
DWORD ret = 0;
__TRY
{
DWORD offset = 0;
BYTE *data = (BYTE *)bits;
BOOL loop = TRUE;
do
{
if (!data[offset++])
{
BYTE byte = data[offset++];
switch (byte)
{
case 0:
break;
case 1:
ret = offset;
loop = FALSE;
break;
default:
offset += byte / type;
offset = (offset + 1) & ~1;
break;
}
}
else
offset++;
}
while (loop);
}
__EXCEPT_ALL
{
ERR("bad bitmap, type %d", type);
}
__ENDTRY
return ret;
}
/***********************************************************************
* StretchDIBits (GDI.439)
*/
INT16 WINAPI StretchDIBits16( HDC16 hdc, INT16 xDst, INT16 yDst, INT16 widthDst,
INT16 heightDst, INT16 xSrc, INT16 ySrc, INT16 widthSrc,
INT16 heightSrc, const VOID *bits,
const BITMAPINFO *info, UINT16 wUsage, DWORD dwRop )
{
BITMAPINFO *bmp = NULL;
INT16 ret;
HDC hdc32 = HDC_32(hdc);
if ((info->bmiHeader.biCompression == BI_RLE4) || (info->bmiHeader.biCompression == BI_RLE8))
{
int hdrsize = info->bmiHeader.biSize + ((info->bmiHeader.biClrUsed ? info->bmiHeader.biClrUsed :
(info->bmiHeader.biBitCount == 4 ? 16 : 256)) * (wUsage == DIB_PAL_COLORS ? 2 : 4));
bmp = HeapAlloc(GetProcessHeap(), 0, hdrsize);
memcpy(bmp, info, hdrsize);
bmp->bmiHeader.biSizeImage = rle_size(info->bmiHeader.biCompression, bits);
}
else if (krnl386_get_compat_mode("256color") && krnl386_get_config_int("otvdm", "DIBPalette", FALSE) && (GetDeviceCaps(hdc32, TECHNOLOGY) == DT_RASDISPLAY) && (info->bmiHeader.biBitCount == 8)) // this doesn't support RLE8 right now
{
DIBSECTION dib;
HBITMAP hbmp = GetCurrentObject(hdc32, OBJ_BITMAP);
int count = GetObject(hbmp, sizeof(DIBSECTION), &dib);
if ((count == sizeof(DIBSECTION)) && (dib.dsBmih.biBitCount == 8) && !dib.dshSection && (GetPtr16(HBITMAP_16(hbmp), 1) == 0xd1b00001))
{
char *section;
HPALETTE hpal = GetCurrentObject(hdc32, OBJ_PAL);
HBITMAP hbmpsrc = CreateDIBSection(hdc32, info, wUsage, §ion, NULL, 0);
HDC hdcsrc = CreateCompatibleDC(hdc32);
HPALETTE oldpal = SelectPalette(hdcsrc, hpal, FALSE);
HBITMAP oldbmp = SelectObject(hdcsrc, hbmpsrc);
memcpy(section, bits, ((info->bmiHeader.biWidth + 3) & ~3) * (ySrc + heightSrc));
INT16 ret = StretchBlt(hdc32, xDst, yDst, widthDst, heightDst, hdcsrc, xSrc, ySrc, widthSrc, heightSrc, dwRop);
SelectPalette(hdcsrc, oldpal, FALSE);
SelectObject(hdcsrc, oldbmp);
DeleteObject(hbmpsrc);
DeleteDC(hdcsrc);
return ret;
}
}
ret = StretchDIBits( hdc32, xDst, yDst, widthDst, heightDst,
xSrc, ySrc, widthSrc, heightSrc, bits,
bmp ? bmp : info, wUsage, dwRop );
if (bmp)
HeapFree(GetProcessHeap(), 0, bmp);
return ret;
}
/***********************************************************************
* SetDIBits (GDI.440)
*/
INT16 WINAPI SetDIBits16( HDC16 hdc, HBITMAP16 hbitmap, UINT16 startscan,
UINT16 lines, LPCVOID bits, const BITMAPINFO *info,
UINT16 coloruse )
{
HBITMAP hbitmap32 = HBITMAP_32(hbitmap);
if (krnl386_get_compat_mode("256color"))
{
// the conversion from 8bpp->1bpp on winxp+ (even in 256 color mode) is different than win31/95 and wine
// the problem shows in The Even More Incredible Machine where the sprites are almost completely masked out
// the cause is that nt scans the dib pallette for the back color and marks the first found match as the
// only index to be 1 and all others are 0, win31 does the match by checking every pixel so if there are
// multiple colors that match the back color nt will ignore all but one while win31 will find them all
// TEMIM hits this problem, by converting to 32bpp the issue is bypassed
// TODO: SetDIBitsFromDevice, 4bpp dibs may also be affected
BITMAP bmap;
int ret = GetObject(hbitmap32, sizeof(BITMAP), &bmap);
if ((bmap.bmPlanes == 1) && (bmap.bmBitsPixel == 1) && (info->bmiHeader.biBitCount == 8))
{
HDC hdcscr = GetDC(NULL);
HDC hdcsrc = CreateCompatibleDC(hdcscr);
HDC hdcdst = HDC_32(hdc);
HBITMAP hbmp = CreateCompatibleBitmap(hdcscr, info->bmiHeader.biWidth, info->bmiHeader.biHeight);
HBITMAP origbmp1 = SelectObject(hdcsrc, hbmp);
int start = info->bmiHeader.biHeight - lines - startscan;
ReleaseDC(hdcscr, NULL);
SaveDC(hdcdst);
SelectObject(hdcdst, hbitmap32);
SetDIBits(hdcsrc, hbmp, startscan, lines, bits, info, coloruse);
BitBlt(hdcdst, 0, start, info->bmiHeader.biWidth, lines, hdcsrc, 0, start, SRCCOPY);
SelectObject(hdcsrc, origbmp1);
DeleteObject(hbmp);
DeleteDC(hdcsrc);
RestoreDC(hdcdst, -1);
return lines;
}
}
BITMAPINFO *bmp = NULL;
INT16 ret;
if (((info->bmiHeader.biCompression == BI_RLE4) || (info->bmiHeader.biCompression == BI_RLE8)) && !info->bmiHeader.biSizeImage)
{
int hdrsize = info->bmiHeader.biSize + ((info->bmiHeader.biClrUsed ? info->bmiHeader.biClrUsed :
(info->bmiHeader.biBitCount == 4 ? 16 : 256)) * (coloruse == DIB_PAL_COLORS ? 2 : 4));
bmp = HeapAlloc(GetProcessHeap(), 0, hdrsize);
memcpy(bmp, info, hdrsize);
bmp->bmiHeader.biSizeImage = rle_size(info->bmiHeader.biCompression, bits);
}
ret = SetDIBits( HDC_32(hdc), hbitmap32, startscan, lines, bits, bmp ? bmp : info, coloruse );
if (bmp)
HeapFree(GetProcessHeap(), 0, bmp);
return ret;
}
/***********************************************************************
* GetDIBits (GDI.441)
*/
INT16 WINAPI GetDIBits16( HDC16 hdc, HBITMAP16 hbitmap, UINT16 startscan,
UINT16 lines, LPVOID bits, BITMAPINFO * info,
UINT16 coloruse )
{
if (lines > info->bmiHeader.biHeight)
{
lines = info->bmiHeader.biHeight;
}
return GetDIBits( HDC_32(hdc), HBITMAP_32(hbitmap), startscan, lines, bits, info, coloruse );
}
/***********************************************************************
* CreateDIBitmap (GDI.442)
*/
HBITMAP16 WINAPI CreateDIBitmap16( HDC16 hdc, const BITMAPINFOHEADER * header,
DWORD init, LPCVOID bits, const BITMAPINFO * data,
UINT16 coloruse )
{
BITMAPINFO *bmp = NULL;
HBITMAP16 ret;
if (data && ((data->bmiHeader.biCompression == BI_RLE4) || (data->bmiHeader.biCompression == BI_RLE8)))
{
int hdrsize = data->bmiHeader.biSize + ((data->bmiHeader.biClrUsed ? data->bmiHeader.biClrUsed :
(data->bmiHeader.biBitCount == 4 ? 16 : 256)) * (coloruse == DIB_PAL_COLORS ? 2 : 4));
bmp = HeapAlloc(GetProcessHeap(), 0, hdrsize);
memcpy(bmp, data, hdrsize);
bmp->bmiHeader.biSizeImage = rle_size(data->bmiHeader.biCompression, bits);
}
if (krnl386_get_compat_mode("256color") && krnl386_get_config_int("otvdm", "DIBPalette", FALSE))
{
HDC16 hdc2 = CreateCompatibleDC16(hdc);
HDC hdc232 = HDC_32(hdc2);
ret = CreateCompatibleBitmap16(hdc2, header->biWidth, header->biHeight);
HBITMAP hbmp = HDC_32(ret);
HBITMAP oldbmp = SelectObject(hdc232, hbmp);
if (GetObjectType(HDC_32(hdc)) == OBJ_DC)
set_dib_colors(hdc232);
SetDIBits(hdc232, hbmp, 0, data->bmiHeader.biHeight, bits, bmp ? bmp : data, coloruse);
SelectObject(hdc232, oldbmp);
DeleteDC16(hdc2);
}
else
ret = HBITMAP_16( CreateDIBitmap( HDC_32(hdc), header, init, bits, bmp ? bmp : data, coloruse ) );
if (bmp)
HeapFree(GetProcessHeap(), 0, bmp);
return ret;
}
/***********************************************************************
* SetDIBitsToDevice (GDI.443)
*/
INT16 WINAPI SetDIBitsToDevice16( HDC16 hdc, INT16 xDest, INT16 yDest, INT16 cx,
INT16 cy, INT16 xSrc, INT16 ySrc, UINT16 startscan,
UINT16 lines, LPCVOID bits, const BITMAPINFO *info,
UINT16 coloruse )
{
return SetDIBitsToDevice( HDC_32(hdc), xDest, yDest, cx, cy, xSrc, ySrc,
startscan, lines, bits, info, coloruse );
}
/***********************************************************************
* CreateRoundRectRgn (GDI.444)
*
* If either ellipse dimension is zero we call CreateRectRgn16 for its
* `special' behaviour. -ve ellipse dimensions can result in GPFs under win3.1
* we just let CreateRoundRectRgn convert them to +ve values.
*/
HRGN16 WINAPI CreateRoundRectRgn16( INT16 left, INT16 top, INT16 right, INT16 bottom,
INT16 ellipse_width, INT16 ellipse_height )
{
if( ellipse_width == 0 || ellipse_height == 0 )
return CreateRectRgn16( left, top, right, bottom );
else
return HRGN_16( CreateRoundRectRgn( left, top, right, bottom,
ellipse_width, ellipse_height ));
}
/***********************************************************************
* CreateDIBPatternBrush (GDI.445)
*/
HBRUSH16 WINAPI CreateDIBPatternBrush16( HGLOBAL16 hbitmap, UINT16 coloruse )
{
BITMAPINFO *bmi;
HBRUSH16 ret;
if (!(bmi = GlobalLock16( hbitmap ))) return 0;
ret = HBRUSH_16( CreateDIBPatternBrushPt( bmi, coloruse ));
GlobalUnlock16( hbitmap );
return ret;
}
/**********************************************************************
* PolyPolygon (GDI.450)
*/
BOOL16 WINAPI PolyPolygon16( HDC16 hdc, const POINT16* pt, const INT16* counts,
UINT16 polygons )
{
int i,nrpts;
LPPOINT pt32;
LPINT counts32;
BOOL16 ret;
nrpts=0;
for (i=polygons;i--;)
nrpts+=counts[i];
pt32 = HeapAlloc( GetProcessHeap(), 0, sizeof(POINT)*nrpts);
if(pt32 == NULL) return FALSE;
for (i=nrpts;i--;)
{
pt32[i].x = pt[i].x;
pt32[i].y = pt[i].y;
}
counts32 = HeapAlloc( GetProcessHeap(), 0, polygons*sizeof(INT) );
if(counts32 == NULL) {
HeapFree( GetProcessHeap(), 0, pt32 );
return FALSE;
}
for (i=polygons;i--;) counts32[i]=counts[i];
ret = PolyPolygon(HDC_32(hdc),pt32,counts32,polygons);
HeapFree( GetProcessHeap(), 0, counts32 );
HeapFree( GetProcessHeap(), 0, pt32 );
return ret;
}
/***********************************************************************
* CreatePolyPolygonRgn (GDI.451)
*/
HRGN16 WINAPI CreatePolyPolygonRgn16( const POINT16 *points,
const INT16 *count, INT16 nbpolygons, INT16 mode )
{
HRGN hrgn;
int i, npts = 0;
INT *count32;
POINT *points32;
for (i = 0; i < nbpolygons; i++) npts += count[i];
points32 = HeapAlloc( GetProcessHeap(), 0, npts * sizeof(POINT) );
for (i = 0; i < npts; i++)
{
points32[i].x = points[i].x;
points32[i].y = points[i].y;
}
count32 = HeapAlloc( GetProcessHeap(), 0, nbpolygons * sizeof(INT) );
for (i = 0; i < nbpolygons; i++) count32[i] = count[i];
hrgn = CreatePolyPolygonRgn( points32, count32, nbpolygons, mode );
HeapFree( GetProcessHeap(), 0, count32 );
HeapFree( GetProcessHeap(), 0, points32 );
return HRGN_16(hrgn);
}
/***********************************************************************
* GdiSeeGdiDo (GDI.452)
*/
DWORD WINAPI GdiSeeGdiDo16( WORD wReqType, WORD wParam1, WORD wParam2,
WORD wParam3 )
{
DWORD ret = ~0U;
switch (wReqType)
{
case 0x0001: /* LocalAlloc */
WARN("LocalAlloc16(%x, %x): ignoring\n", wParam1, wParam3);
ret = 0;
break;
case 0x0002: /* LocalFree */
WARN("LocalFree16(%x): ignoring\n", wParam1);
ret = 0;
break;
case 0x0003: /* LocalCompact */
WARN("LocalCompact16(%x): ignoring\n", wParam3);
ret = 65000; /* lie about the amount of free space */
break;
case 0x0103: /* LocalHeap */
WARN("LocalHeap16(): ignoring\n");
break;
default:
WARN("(wReqType=%04x): Unknown\n", wReqType);
break;
}
return ret;
}
/***********************************************************************
* SetObjectOwner (GDI.461)
*/
void WINAPI SetObjectOwner16( HGDIOBJ16 handle, HANDLE16 owner )
{
/* Nothing to do */
}
/***********************************************************************
* IsGDIObject (GDI.462)
*
* returns type of object if valid (W95 system programming secrets p. 264-5)
*/
BOOL16 WINAPI IsGDIObject16( HGDIOBJ16 handle16 )
{
static const BYTE type_map[] =
{
0, /* bad */
1, /* OBJ_PEN */
2, /* OBJ_BRUSH */
7, /* OBJ_DC */
9, /* OBJ_METADC */
4, /* OBJ_PAL */
3, /* OBJ_FONT */
5, /* OBJ_BITMAP */
6, /* OBJ_REGION */
10, /* OBJ_METAFILE */
7, /* OBJ_MEMDC */
0, /* OBJ_EXTPEN */
9, /* OBJ_ENHMETADC */
12, /* OBJ_ENHMETAFILE */
0 /* OBJ_COLORSPACE */
};
UINT type = GetObjectType( HGDIOBJ_32( handle16 ));
if (type >= ARRAY_SIZE(type_map)) return FALSE;
return type_map[type];
}
/***********************************************************************
* RectVisible (GDI.465)
* RectVisibleOld (GDI.104)
*/
BOOL16 WINAPI RectVisible16( HDC16 hdc, const RECT16* rect16 )
{
RECT rect;
rect.left = rect16->left;
rect.top = rect16->top;
rect.right = rect16->right;
rect.bottom = rect16->bottom;
return RectVisible( HDC_32(hdc), &rect );
}
/***********************************************************************
* RectInRegion (GDI.466)
* RectInRegionOld (GDI.181)
*/
BOOL16 WINAPI RectInRegion16( HRGN16 hrgn, const RECT16 *rect )
{
RECT r32;
r32.left = rect->left;
r32.top = rect->top;
r32.right = rect->right;
r32.bottom = rect->bottom;
return RectInRegion( HRGN_32(hrgn), &r32 );
}
/***********************************************************************
* GetBitmapDimensionEx (GDI.468)
*/
BOOL16 WINAPI GetBitmapDimensionEx16( HBITMAP16 hbitmap, LPSIZE16 size )
{
SIZE size32;
BOOL ret = GetBitmapDimensionEx( HBITMAP_32(hbitmap), &size32 );
if (ret)
{
size->cx = size32.cx;
size->cy = size32.cy;
}
return ret;
}
/***********************************************************************
* GetBrushOrgEx (GDI.469)
*/
BOOL16 WINAPI GetBrushOrgEx16( HDC16 hdc, LPPOINT16 pt )
{
POINT pt32;
if (!GetBrushOrgEx( HDC_32(hdc), &pt32 )) return FALSE;
pt->x = pt32.x;
pt->y = pt32.y;
return TRUE;
}
/***********************************************************************
* GetCurrentPositionEx (GDI.470)
*/
BOOL16 WINAPI GetCurrentPositionEx16( HDC16 hdc, LPPOINT16 pt )
{
POINT pt32;
if (!GetCurrentPositionEx( HDC_32(hdc), &pt32 )) return FALSE;
pt->x = pt32.x;
pt->y = pt32.y;
return TRUE;
}
/***********************************************************************
* GetTextExtentPoint (GDI.471)
*
* FIXME: Should this have a bug for compatibility?
* Original Windows versions of GetTextExtentPoint{A,W} have documented
* bugs (-> MSDN KB q147647.txt).
*/
BOOL16 WINAPI GetTextExtentPoint16( HDC16 hdc, LPCSTR str, INT16 count, LPSIZE16 size )
{
SIZE size32;
HDC hdc32 = HDC_32(hdc);
TEXTMETRICA tm;
GetTextMetricsA(hdc32, &tm);
BOOL ret = GetTextExtentPoint32A( hdc32, str, count, &size32 );
if (ret)
{
size->cx = size32.cx + tm.tmOverhang;
size->cy = size32.cy;
check_font_rotation( hdc32, size );
}
return ret;
}
/***********************************************************************
* GetViewportExtEx (GDI.472)
*/
BOOL16 WINAPI GetViewportExtEx16( HDC16 hdc, LPSIZE16 size )
{
SIZE size32;
if (!GetViewportExtEx( HDC_32(hdc), &size32 )) return FALSE;
size->cx = size32.cx;
size->cy = size32.cy;
return TRUE;
}
/***********************************************************************
* GetViewportOrgEx (GDI.473)
*/
BOOL16 WINAPI GetViewportOrgEx16( HDC16 hdc, LPPOINT16 pt )
{
POINT pt32;
if (!GetViewportOrgEx( HDC_32(hdc), &pt32 )) return FALSE;
pt->x = pt32.x;
pt->y = pt32.y;
return TRUE;
}
/***********************************************************************
* GetWindowExtEx (GDI.474)
*/
BOOL16 WINAPI GetWindowExtEx16( HDC16 hdc, LPSIZE16 size )
{
SIZE size32;
if (!GetWindowExtEx( HDC_32(hdc), &size32 )) return FALSE;
size->cx = size32.cx;
size->cy = size32.cy;
return TRUE;
}
/***********************************************************************
* GetWindowOrgEx (GDI.475)
*/
BOOL16 WINAPI GetWindowOrgEx16( HDC16 hdc, LPPOINT16 pt )
{
POINT pt32;
if (!GetWindowOrgEx( HDC_32(hdc), &pt32 )) return FALSE;
pt->x = pt32.x;
pt->y = pt32.y;
return TRUE;
}
/***********************************************************************
* OffsetViewportOrgEx (GDI.476)
*/
BOOL16 WINAPI OffsetViewportOrgEx16( HDC16 hdc, INT16 x, INT16 y, LPPOINT16 pt)
{
POINT pt32;
BOOL16 ret = OffsetViewportOrgEx( HDC_32(hdc), x, y, &pt32 );
if (pt)
{
pt->x = pt32.x;
pt->y = pt32.y;
}
return ret;
}
/***********************************************************************
* OffsetWindowOrgEx (GDI.477)
*/
BOOL16 WINAPI OffsetWindowOrgEx16( HDC16 hdc, INT16 x, INT16 y, LPPOINT16 pt )
{
POINT pt32;
BOOL16 ret = OffsetWindowOrgEx( HDC_32(hdc), x, y, &pt32 );
if (pt)
{
pt->x = pt32.x;
pt->y = pt32.y;
}
return ret;
}
/***********************************************************************
* SetBitmapDimensionEx (GDI.478)
*/
BOOL16 WINAPI SetBitmapDimensionEx16( HBITMAP16 hbitmap, INT16 x, INT16 y, LPSIZE16 prevSize )
{
SIZE size32;
BOOL ret = SetBitmapDimensionEx( HBITMAP_32(hbitmap), x, y, &size32 );
if (ret && prevSize)
{
prevSize->cx = size32.cx;
prevSize->cy = size32.cy;
}
return ret;
}
/***********************************************************************
* SetViewportExtEx (GDI.479)
*/
BOOL16 WINAPI SetViewportExtEx16( HDC16 hdc, INT16 x, INT16 y, LPSIZE16 size )
{
SIZE size32;
BOOL16 ret = SetViewportExtEx( HDC_32(hdc), x, y, &size32 );
if (size) { size->cx = size32.cx; size->cy = size32.cy; }
return ret;
}
/***********************************************************************
* SetViewportOrgEx (GDI.480)
*/
BOOL16 WINAPI SetViewportOrgEx16( HDC16 hdc, INT16 x, INT16 y, LPPOINT16 pt )
{
POINT pt32;
BOOL16 ret = SetViewportOrgEx( HDC_32(hdc), x, y, &pt32 );
if (pt)
{
pt->x = pt32.x;
pt->y = pt32.y;
}
return ret;
}
/***********************************************************************
* SetWindowExtEx (GDI.481)
*/
BOOL16 WINAPI SetWindowExtEx16( HDC16 hdc, INT16 x, INT16 y, LPSIZE16 size )
{
SIZE size32;
BOOL16 ret = SetWindowExtEx( HDC_32(hdc), x, y, &size32 );
if (size) { size->cx = size32.cx; size->cy = size32.cy; }
return ret;
}
/***********************************************************************
* SetWindowOrgEx (GDI.482)
*/
BOOL16 WINAPI SetWindowOrgEx16( HDC16 hdc, INT16 x, INT16 y, LPPOINT16 pt )
{
POINT pt32;
BOOL16 ret = SetWindowOrgEx( HDC_32(hdc), x, y, &pt32 );
if (pt)
{
pt->x = pt32.x;
pt->y = pt32.y;
}
return ret;
}
/***********************************************************************
* MoveToEx (GDI.483)
*/
BOOL16 WINAPI MoveToEx16( HDC16 hdc, INT16 x, INT16 y, LPPOINT16 pt )
{
POINT pt32;
if (!MoveToEx( HDC_32(hdc), x, y, &pt32 )) return FALSE;
if (pt)
{
pt->x = pt32.x;
pt->y = pt32.y;
}
return TRUE;
}
/***********************************************************************
* ScaleViewportExtEx (GDI.484)
*/
BOOL16 WINAPI ScaleViewportExtEx16( HDC16 hdc, INT16 xNum, INT16 xDenom,
INT16 yNum, INT16 yDenom, LPSIZE16 size )
{
SIZE size32;
BOOL16 ret = ScaleViewportExtEx( HDC_32(hdc), xNum, xDenom, yNum, yDenom,
&size32 );
if (size) { size->cx = size32.cx; size->cy = size32.cy; }
return ret;
}
/***********************************************************************
* ScaleWindowExtEx (GDI.485)
*/
BOOL16 WINAPI ScaleWindowExtEx16( HDC16 hdc, INT16 xNum, INT16 xDenom,
INT16 yNum, INT16 yDenom, LPSIZE16 size )
{
SIZE size32;
BOOL16 ret = ScaleWindowExtEx( HDC_32(hdc), xNum, xDenom, yNum, yDenom,
&size32 );
if (size) { size->cx = size32.cx; size->cy = size32.cy; }
return ret;
}
/***********************************************************************
* GetAspectRatioFilterEx (GDI.486)
*/
BOOL16 WINAPI GetAspectRatioFilterEx16( HDC16 hdc, LPSIZE16 pAspectRatio )
{
FIXME("(%04x, %p): -- Empty Stub !\n", hdc, pAspectRatio);
return FALSE;
}
/******************************************************************************
* PolyBezier (GDI.502)
*/
BOOL16 WINAPI PolyBezier16( HDC16 hdc, const POINT16* lppt, INT16 cPoints )
{
int i;
BOOL16 ret;
LPPOINT pt32 = HeapAlloc( GetProcessHeap(), 0, cPoints*sizeof(POINT) );
if(!pt32) return FALSE;
for (i=cPoints;i--;)
{
pt32[i].x = lppt[i].x;
pt32[i].y = lppt[i].y;
}
ret= PolyBezier(HDC_32(hdc), pt32, cPoints);
HeapFree( GetProcessHeap(), 0, pt32 );
return ret;
}
/******************************************************************************
* PolyBezierTo (GDI.503)
*/
BOOL16 WINAPI PolyBezierTo16( HDC16 hdc, const POINT16* lppt, INT16 cPoints )
{
int i;
BOOL16 ret;
LPPOINT pt32 = HeapAlloc( GetProcessHeap(), 0,
cPoints*sizeof(POINT) );
if(!pt32) return FALSE;
for (i=cPoints;i--;)
{
pt32[i].x = lppt[i].x;
pt32[i].y = lppt[i].y;
}
ret= PolyBezierTo(HDC_32(hdc), pt32, cPoints);
HeapFree( GetProcessHeap(), 0, pt32 );
return ret;
}
/******************************************************************************
* ExtSelectClipRgn (GDI.508)
*/
INT16 WINAPI ExtSelectClipRgn16( HDC16 hdc, HRGN16 hrgn, INT16 fnMode )
{
return ExtSelectClipRgn( HDC_32(hdc), HRGN_32(hrgn), fnMode);
}
/***********************************************************************
* AbortPath (GDI.511)
*/
BOOL16 WINAPI AbortPath16(HDC16 hdc)
{
return AbortPath( HDC_32(hdc) );
}
/***********************************************************************
* BeginPath (GDI.512)
*/
BOOL16 WINAPI BeginPath16(HDC16 hdc)
{
return BeginPath( HDC_32(hdc) );
}
/***********************************************************************
* CloseFigure (GDI.513)
*/
BOOL16 WINAPI CloseFigure16(HDC16 hdc)
{
return CloseFigure( HDC_32(hdc) );
}
/***********************************************************************
* EndPath (GDI.514)
*/
BOOL16 WINAPI EndPath16(HDC16 hdc)
{
return EndPath( HDC_32(hdc) );
}
/***********************************************************************
* FillPath (GDI.515)
*/
BOOL16 WINAPI FillPath16(HDC16 hdc)
{
return FillPath( HDC_32(hdc) );
}
/*******************************************************************
* FlattenPath (GDI.516)
*/
BOOL16 WINAPI FlattenPath16(HDC16 hdc)
{
return FlattenPath( HDC_32(hdc) );
}
/***********************************************************************
* GetPath (GDI.517)
*/
INT16 WINAPI GetPath16(HDC16 hdc, LPPOINT16 pPoints, LPBYTE pTypes, INT16 nSize)
{
FIXME("(%d,%p,%p): stub\n",hdc,pPoints,pTypes);
return 0;
}
/***********************************************************************
* PathToRegion (GDI.518)
*/
HRGN16 WINAPI PathToRegion16(HDC16 hdc)
{
return HRGN_16( PathToRegion( HDC_32(hdc) ));
}
/***********************************************************************
* SelectClipPath (GDI.519)
*/
BOOL16 WINAPI SelectClipPath16(HDC16 hdc, INT16 iMode)
{
return SelectClipPath( HDC_32(hdc), iMode );
}
/*******************************************************************
* StrokeAndFillPath (GDI.520)
*/
BOOL16 WINAPI StrokeAndFillPath16(HDC16 hdc)
{
return StrokeAndFillPath( HDC_32(hdc) );
}
/*******************************************************************
* StrokePath (GDI.521)
*/
BOOL16 WINAPI StrokePath16(HDC16 hdc)
{
return StrokePath( HDC_32(hdc) );
}
/*******************************************************************
* WidenPath (GDI.522)
*/
BOOL16 WINAPI WidenPath16(HDC16 hdc)
{
return WidenPath( HDC_32(hdc) );
}
/***********************************************************************
* GetArcDirection (GDI.524)
*/
INT16 WINAPI GetArcDirection16( HDC16 hdc )
{
return GetArcDirection( HDC_32(hdc) );
}
/***********************************************************************
* SetArcDirection (GDI.525)
*/
INT16 WINAPI SetArcDirection16( HDC16 hdc, INT16 nDirection )
{
return SetArcDirection( HDC_32(hdc), (INT)nDirection );
}
/***********************************************************************
* CreateHalftonePalette (GDI.529)
*/
HPALETTE16 WINAPI CreateHalftonePalette16( HDC16 hdc )
{
return HPALETTE_16( CreateHalftonePalette( HDC_32(hdc) ));
}
/***********************************************************************
* SetDIBColorTable (GDI.602)
*/
UINT16 WINAPI SetDIBColorTable16( HDC16 hdc, UINT16 startpos, UINT16 entries, RGBQUAD *colors )
{
return SetDIBColorTable( HDC_32(hdc), startpos, entries, colors );
}
/***********************************************************************
* GetDIBColorTable (GDI.603)
*/
UINT16 WINAPI GetDIBColorTable16( HDC16 hdc, UINT16 startpos, UINT16 entries, RGBQUAD *colors )
{
return GetDIBColorTable( HDC_32(hdc), startpos, entries, colors );
}
/***********************************************************************
* GetRegionData (GDI.607)
*
* FIXME: is LPRGNDATA the same in Win16 and Win32 ?
*/
DWORD WINAPI GetRegionData16( HRGN16 hrgn, DWORD count, LPRGNDATA rgndata )
{
return GetRegionData( HRGN_32(hrgn), count, rgndata );
}
/***********************************************************************
* GdiFreeResources (GDI.609)
*/
WORD WINAPI GdiFreeResources16( DWORD reserve )
{
return 90; /* lie about it, it shouldn't matter */
}
/***********************************************************************
* GdiSignalProc32 (GDI.610)
*/
WORD WINAPI GdiSignalProc( UINT uCode, DWORD dwThreadOrProcessID,
DWORD dwFlags, HMODULE16 hModule )
{
return 0;
}
/***********************************************************************
* GetTextCharset (GDI.612)
*/
UINT16 WINAPI GetTextCharset16( HDC16 hdc )
{
return GetTextCharset( HDC_32(hdc) );
}
/***********************************************************************
* EnumFontFamiliesEx (GDI.613)
*/
INT16 WINAPI EnumFontFamiliesEx16( HDC16 hdc, LPLOGFONT16 plf,
FONTENUMPROC16 proc, LPARAM lParam,
DWORD dwFlags)
{
struct callback16_info info;
LOGFONTA lfA, *plfA;
info.proc = (FARPROC16)proc;
info.param = lParam;
info.result = 1;
if (plf)
{
logfont_16_to_A(plf, &lfA);
plfA = &lfA;
}
else plfA = NULL;
return EnumFontFamiliesExA( HDC_32(hdc), plfA, enum_font_callback,
(LPARAM)&info, dwFlags );
}
/*************************************************************************
* GetFontLanguageInfo (GDI.616)
*/
DWORD WINAPI GetFontLanguageInfo16( HDC16 hdc )
{
return GetFontLanguageInfo( HDC_32(hdc) );
}
/***********************************************************************
* SetLayout (GDI.1000)
*
* Sets left->right or right->left text layout flags of a dc.
*/
BOOL16 WINAPI SetLayout16( HDC16 hdc, DWORD layout )
{
return SetLayout( HDC_32(hdc), layout );
}
/***********************************************************************
* SetSolidBrush (GDI.604)
*
* Change the color of a solid brush.
*
* PARAMS
* hBrush [I] Brush to change the color of
* newColor [I] New color for hBrush
*
* RETURNS
* Success: TRUE. The color of hBrush is set to newColor.
* Failure: FALSE.
*
* FIXME
* This function is undocumented and untested. The implementation may
* not be correct.
*/
BOOL16 WINAPI SetSolidBrush16(HBRUSH16 hBrush, COLORREF newColor )
{
FIXME( "%04x %08x no longer supported\n", hBrush, newColor );
return FALSE;
}
/***********************************************************************
* Copy (GDI.250)
*/
void WINAPI Copy16( LPVOID src, LPVOID dst, WORD size )
{
memcpy( dst, src, size );
}
/***********************************************************************
* RealizeDefaultPalette (GDI.365)
*/
UINT16 WINAPI RealizeDefaultPalette16( HDC16 hdc )
{
FIXME( "%04x semi-stub\n", hdc );
return GDIRealizePalette16( hdc );
}
/***********************************************************************
* IsDCCurrentPalette (GDI.412)
*/
BOOL16 WINAPI IsDCCurrentPalette16(HDC16 hDC)
{
return HPALETTE_16( GetCurrentObject( HDC_32(hDC), OBJ_PAL )) == hPrimaryPalette;
}
/*********************************************************************
* SetMagicColors (GDI.606)
*/
VOID WINAPI SetMagicColors16(HDC16 hDC, COLORREF color, UINT16 index)
{
FIXME("(hDC %04x, color %04x, index %04x): stub\n", hDC, (int)color, index);
}
/***********************************************************************
* DPtoLP (GDI.67)
*/
BOOL16 WINAPI DPtoLP16( HDC16 hdc, LPPOINT16 points, INT16 count )
{
POINT points32[8], *pt32 = points32;
int i;
BOOL ret;
if (count > 8)
{
if (!(pt32 = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*pt32) ))) return FALSE;
}
for (i = 0; i < count; i++)
{
pt32[i].x = points[i].x;
pt32[i].y = points[i].y;
}
if ((ret = DPtoLP( HDC_32(hdc), pt32, count )))
{
for (i = 0; i < count; i++)
{
if (pt32[i].x >= 0x8000) points[i].x = 0x7fff;
else if (pt32[i].x < (LONG)0xffff8000) points[i].x = 0x8000;
else points[i].x = pt32[i].x;
if (pt32[i].y >= 0x8000) points[i].y = 0x7fff;
else if (pt32[i].y < (LONG)0xffff8000) points[i].y = 0x8000;
else points[i].y = pt32[i].y;
}
}
if (pt32 != points32) HeapFree( GetProcessHeap(), 0, pt32 );
return ret;
}
/***********************************************************************
* LPtoDP (GDI.99)
*/
BOOL16 WINAPI LPtoDP16( HDC16 hdc, LPPOINT16 points, INT16 count )
{
POINT points32[8], *pt32 = points32;
int i;
BOOL ret;
if (count > 8)
{
if (!(pt32 = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*pt32) ))) return FALSE;
}
for (i = 0; i < count; i++)
{
pt32[i].x = points[i].x;
pt32[i].y = points[i].y;
}
if ((ret = LPtoDP( HDC_32(hdc), pt32, count )))
{
for (i = 0; i < count; i++)
{
if (pt32[i].x >= 0x8000) points[i].x = 0x7fff;
else if (pt32[i].x < (LONG)0xffff8000) points[i].x = 0x8000;
else points[i].x = pt32[i].x;
if (pt32[i].y >= 0x8000) points[i].y = 0x7fff;
else if (pt32[i].y < (LONG)0xffff8000) points[i].y = 0x8000;
else points[i].y = pt32[i].y;
}
}
if (pt32 != points32) HeapFree( GetProcessHeap(), 0, pt32 );
return ret;
}
/***********************************************************************
* GetDCState (GDI.179)
*/
HDC16 WINAPI GetDCState16( HDC16 hdc )
{
ERR( "no longer supported\n" );
return 0;
}
/***********************************************************************
* SetDCState (GDI.180)
*/
void WINAPI SetDCState16( HDC16 hdc, HDC16 hdcs )
{
ERR( "no longer supported\n" );
}
/***********************************************************************
* SetDCOrg (GDI.117)
*/
DWORD WINAPI SetDCOrg16( HDC16 hdc16, INT16 x, INT16 y )
{
FIXME( "%04x %d,%d no longer supported\n", hdc16, x, y );
return 0;
}
/***********************************************************************
* InquireVisRgn (GDI.131)
*/
HRGN16 WINAPI InquireVisRgn16( HDC16 hdc )
{
static HRGN hrgn;
if (!hrgn) hrgn = CreateRectRgn( 0, 0, 0, 0 );
GetRandomRgn( HDC_32(hdc), hrgn, SYSRGN );
return HRGN_16(hrgn);
}
/***********************************************************************
* OffsetVisRgn (GDI.102)
*/
INT16 WINAPI OffsetVisRgn16( HDC16 hdc16, INT16 x, INT16 y )
{
FIXME( "%04x %d,%d no longer supported\n", hdc16, x, y );
return ERROR;
}
/***********************************************************************
* ExcludeVisRect (GDI.73)
*/
INT16 WINAPI ExcludeVisRect16( HDC16 hdc16, INT16 left, INT16 top, INT16 right, INT16 bottom )
{
FIXME( "%04x %d,%d-%d,%d no longer supported\n", hdc16, left, top, right, bottom );
return ERROR;
}
/***********************************************************************
* IntersectVisRect (GDI.98)
*/
INT16 WINAPI IntersectVisRect16( HDC16 hdc16, INT16 left, INT16 top, INT16 right, INT16 bottom )
{
FIXME( "%04x %d,%d-%d,%d no longer supported\n", hdc16, left, top, right, bottom );
return ERROR;
}
/***********************************************************************
* SaveVisRgn (GDI.129)
*/
HRGN16 WINAPI SaveVisRgn16( HDC16 hdc16 )
{
FIXME( "%04x no longer supported\n", hdc16 );
return 0;
}
/***********************************************************************
* RestoreVisRgn (GDI.130)
*/
INT16 WINAPI RestoreVisRgn16( HDC16 hdc16 )
{
FIXME( "%04x no longer supported\n", hdc16 );
return ERROR;
}
/***********************************************************************
* GetClipRgn (GDI.173)
*/
HRGN16 WINAPI GetClipRgn16( HDC16 hdc )
{
static HRGN hrgn;
if (!hrgn) hrgn = CreateRectRgn( 0, 0, 0, 0 );
GetClipRgn( HDC_32(hdc), hrgn );
return HRGN_16(hrgn);
}
/***********************************************************************
* MakeObjectPrivate (GDI.463)
*
* What does that mean ?
* Some little docu can be found in "Undocumented Windows",
* but this is basically useless.
*/
void WINAPI MakeObjectPrivate16( HGDIOBJ16 handle16, BOOL16 private )
{
FIXME( "stub: %x %u\n", handle16, private );
}
/***********************************************************************
* CreateDIBSection (GDI.489)
*/
HBITMAP16 WINAPI CreateDIBSection16 (HDC16 hdc, const BITMAPINFO *bmi, UINT16 usage,
SEGPTR *bits16, HANDLE section, DWORD offset)
{
LPVOID bits32;
HBITMAP hbitmap;
hbitmap = CreateDIBSection( HDC_32(hdc), bmi, usage, &bits32, section, offset );
if (hbitmap && bits32 && bits16) *bits16 = alloc_segptr_bits( hbitmap, bits32 );
return HBITMAP_16(hbitmap);
}
void WINAPI GdiTaskTermination16(WORD arg1)
{
FIXME("(%04x)\n", arg1);
}
WORD WINAPI GetPhysicalFontHandle16(WORD arg1/* dc? */)
{
FIXME("(%04x)\n", arg1);
return 0;
}
WORD WINAPI GdiMoveBitmap16(WORD arg1)
{
FIXME("(%04x)\n", arg1);
return 0;
}
BOOL16 WINAPI IsDCDirty16(WORD arg1, SEGPTR arg2)
{
FIXME("(%04x,%08x)\n", arg1, arg2);
return 0;
}
void WINAPI UnicodeToAnsi16(SEGPTR arg1, SEGPTR arg2)
{
FIXME("(%08x,%08x)\n", arg1, arg2);
return 0;
}
void WINAPI ShrinkGdiHeap16()
{
FIXME("()\n");
}
DWORD WINAPI GetAspectRatioFilter16(WORD arg1)
{
FIXME("(%04x)\n", arg1);
return 0;
}
WORD WINAPI SelectBitmap16(WORD arg1, WORD arg2)
{
FIXME("(%04x)\n", arg1);
return SelectObject16(arg1, arg2);
}
WORD WINAPI GetFontAssocStatus16(HDC16 hdc)
{
static BOOL load;
static FARPROC GetFontAssocStatus;
if (!load)
{
load = TRUE;
GetFontAssocStatus = GetProcAddress(GetModuleHandleW(L"GDI32"), "GetFontAssocStatus");
}
if (!GetFontAssocStatus)
{
ERR("(%04x)\n", hdc);
return 0;
}
return ((ULONG(WINAPI*)(HDC))GetFontAssocStatus)(HDC_32(hdc));
}
// style
// bit 1: scan direction 0 = left to right 1 = right to left
// bit 7: match type 0 = color 1 = not color
WORD WINAPI ScanLR16(HDC16 hdc, WORD x, WORD y, DWORD color, WORD style)
{
HDC hdc32 = HDC_32(hdc);
if (!hdc32 || (GetDeviceCaps(hdc32, TECHNOLOGY) != DT_RASDISPLAY))
{
ERR("Invalid DC (%04x)\n", hdc);
return -1;
}
COLORREF pixel = GetPixel(hdc32, x, y);
if (pixel == CLR_INVALID)
return 0x8000; // out of range
for (int i = x; (i <= 0xffff) && (i >= 0); (style & 2) ? i-- : i++)
{
pixel = GetPixel(hdc32, i, y);
if (pixel == CLR_INVALID)
return -1;
if ((style & 0x80) ? (pixel != color) : (pixel == color))
return i;
}
return -1;
}
LPCSTR RedirectSystemDir(LPCSTR path, LPSTR to, size_t max_len);
BOOL WINAPI DllEntryPoint(DWORD fdwReason, HINSTANCE hinstDLL, WORD ds,
WORD wHeapSize, DWORD dwReserved1, WORD wReserved2)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
{
static BOOL init = FALSE;
if (init == TRUE)
break;
init = TRUE;
WIN32_FIND_DATAA fileinfo = {0};
char syspath[MAX_PATH];
char fonfile[MAX_PATH];
char origsyspath[MAX_PATH];
GetWindowsDirectoryA(origsyspath, MAX_PATH);
StringCchCatA(origsyspath, MAX_PATH, "\\system\\");
RedirectSystemDir(origsyspath, syspath, MAX_PATH);
strcpy(fonfile, syspath);
StringCchCatA(fonfile, MAX_PATH, "*.*");
HANDLE file = FindFirstFileA(fonfile, &fileinfo);
if (file == INVALID_HANDLE_VALUE)
break;
BOOL ret;
do
{
LPCSTR *ext = fileinfo.cFileName + strlen(fileinfo.cFileName) - 4;
if (!stricmp(ext, ".ttf") || !stricmp(ext, ".fon"))
{
strcpy(fonfile, syspath);
strcat(fonfile, fileinfo.cFileName);
AddFontResource16(fonfile);
}
ret = FindNextFileA(file, &fileinfo);
} while (ret);
for (int i = 0; i <= STOCK_LAST; i++) GetStockObject16(i);
HDC dc = CreateCompatibleDC(NULL);
stock[STOCK_LAST + 1] = HGDIOBJ_16(GetCurrentObject(dc, OBJ_BITMAP));
DeleteDC(dc);
FindClose(file);
break;
}
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
HFONT16 WINAPI GetSystemIconFont16()
{
// only known to be used by Simplified Chinese progman
// uses SPI_GETICONTITLELOGFONT if this returns 0
return 0;
}
================================================
FILE: gdi/gdi.def
================================================
; File generated automatically from gdi.exe16.spec; do not edit!
LIBRARY gdi.exe16
EXPORTS
_wine_spec_dos_header;=.L__wine_spec_dos_header @1 DATA PRIVATE
================================================
FILE: gdi/gdi.exe16.spec
================================================
1 pascal SetBkColor(word long) SetBkColor16
2 pascal -ret16 SetBkMode(word word) SetBkMode16
3 pascal -ret16 SetMapMode(word word) SetMapMode16
4 pascal -ret16 SetROP2(word word) SetROP216
5 pascal -ret16 SetRelAbs(word word) SetRelAbs16
6 pascal -ret16 SetPolyFillMode(word word) SetPolyFillMode16
7 pascal -ret16 SetStretchBltMode(word word) SetStretchBltMode16
8 pascal -ret16 SetTextCharacterExtra(word s_word) SetTextCharacterExtra16
9 pascal SetTextColor(word long) SetTextColor16
10 pascal -ret16 SetTextJustification(word s_word s_word) SetTextJustification16
11 pascal SetWindowOrg(word s_word s_word) SetWindowOrg16
12 pascal SetWindowExt(word s_word s_word) SetWindowExt16
13 pascal SetViewportOrg(word s_word s_word) SetViewportOrg16
14 pascal SetViewportExt(word s_word s_word) SetViewportExt16
15 pascal OffsetWindowOrg(word s_word s_word) OffsetWindowOrg16
16 pascal ScaleWindowExt(word s_word s_word s_word s_word) ScaleWindowExt16
17 pascal OffsetViewportOrg(word s_word s_word) OffsetViewportOrg16
18 pascal ScaleViewportExt(word s_word s_word s_word s_word) ScaleViewportExt16
19 pascal -ret16 LineTo(word s_word s_word) LineTo16
20 pascal MoveTo(word s_word s_word) MoveTo16
21 pascal -ret16 ExcludeClipRect(word s_word s_word s_word s_word) ExcludeClipRect16
22 pascal -ret16 IntersectClipRect(word s_word s_word s_word s_word) IntersectClipRect16
23 pascal -ret16 Arc(word s_word s_word s_word s_word s_word s_word s_word s_word) Arc16
24 pascal -ret16 Ellipse(word s_word s_word s_word s_word) Ellipse16
25 pascal -ret16 FloodFill(word s_word s_word long) FloodFill16
26 pascal -ret16 Pie(word s_word s_word s_word s_word s_word s_word s_word s_word) Pie16
27 pascal -ret16 Rectangle(word s_word s_word s_word s_word) Rectangle16
28 pascal -ret16 RoundRect(word s_word s_word s_word s_word s_word s_word) RoundRect16
29 pascal -ret16 PatBlt(word s_word s_word s_word s_word long) PatBlt16
30 pascal -ret16 SaveDC(word) SaveDC16
31 pascal SetPixel(word s_word s_word long) SetPixel16
32 pascal -ret16 OffsetClipRgn(word s_word s_word) OffsetClipRgn16
33 pascal -ret16 TextOut(word s_word s_word str word) TextOut16
34 pascal -ret16 BitBlt( word s_word s_word s_word s_word word s_word s_word long) BitBlt16
35 pascal -ret16 StretchBlt(word s_word s_word s_word s_word word s_word s_word s_word s_word long) StretchBlt16
36 pascal -ret16 Polygon (word ptr word) Polygon16
37 pascal -ret16 Polyline (word ptr word) Polyline16
38 pascal Escape(word word word segptr ptr) Escape16
39 pascal -ret16 RestoreDC(word s_word) RestoreDC16
40 pascal -ret16 FillRgn(word word word) FillRgn16
41 pascal -ret16 FrameRgn(word word word word word) FrameRgn16
42 pascal -ret16 InvertRgn(word word) InvertRgn16
43 pascal -ret16 PaintRgn(word word) PaintRgn16
44 pascal -ret16 SelectClipRgn(word word) SelectClipRgn16
45 pascal -ret16 SelectObject(word word) SelectObject16
46 stub BITMAPBITS # W1.1, W2.0
47 pascal -ret16 CombineRgn(word word word s_word) CombineRgn16
48 pascal -ret16 CreateBitmap(word word word word ptr) CreateBitmap16
49 pascal -ret16 CreateBitmapIndirect(ptr) CreateBitmapIndirect16
50 pascal -ret16 CreateBrushIndirect(ptr) CreateBrushIndirect16
51 pascal -ret16 CreateCompatibleBitmap(word word word) CreateCompatibleBitmap16
52 pascal -ret16 CreateCompatibleDC(word) CreateCompatibleDC16
53 pascal -ret16 CreateDC(str str str segptr) CreateDC16
54 pascal -ret16 CreateEllipticRgn(s_word s_word s_word s_word) CreateEllipticRgn16
55 pascal -ret16 CreateEllipticRgnIndirect(ptr) CreateEllipticRgnIndirect16
56 pascal -ret16 CreateFont(s_word s_word s_word s_word s_word word word word word word word word word str) CreateFont16
57 pascal -ret16 CreateFontIndirect(ptr) CreateFontIndirect16
58 pascal -ret16 CreateHatchBrush(word long) CreateHatchBrush16
#59 ??? (not even in W1.1, W2.0)
60 pascal -ret16 CreatePatternBrush(word) CreatePatternBrush16
61 pascal -ret16 CreatePen(s_word s_word long) CreatePen16
62 pascal -ret16 CreatePenIndirect(ptr) CreatePenIndirect16
63 pascal -ret16 CreatePolygonRgn(ptr word word) CreatePolygonRgn16
64 pascal -ret16 CreateRectRgn(s_word s_word s_word s_word) CreateRectRgn16
65 pascal -ret16 CreateRectRgnIndirect(ptr) CreateRectRgnIndirect16
66 pascal -ret16 CreateSolidBrush(long) CreateSolidBrush16
67 pascal -ret16 DPtoLP(word ptr s_word) DPtoLP16
68 pascal -ret16 DeleteDC(word) DeleteDC16
69 pascal -ret16 DeleteObject(word) DeleteObject16
70 pascal -ret16 EnumFonts(word str segptr long) EnumFonts16
71 pascal -ret16 EnumObjects(word word segptr long) EnumObjects16
72 pascal -ret16 EqualRgn(word word) EqualRgn16
73 pascal -ret16 ExcludeVisRect(word s_word s_word s_word s_word) ExcludeVisRect16
74 pascal GetBitmapBits(word long ptr) GetBitmapBits16
75 pascal GetBkColor(word) GetBkColor16
76 pascal -ret16 GetBkMode(word) GetBkMode16
77 pascal -ret16 GetClipBox(word ptr) GetClipBox16
78 pascal GetCurrentPosition(word) GetCurrentPosition16
79 pascal GetDCOrg(word) GetDCOrg16
80 pascal -ret16 GetDeviceCaps(word s_word) GetDeviceCaps16
81 pascal -ret16 GetMapMode(word) GetMapMode16
82 pascal -ret16 GetObject(word s_word ptr) GetObject16
83 pascal GetPixel(word s_word s_word) GetPixel16
84 pascal -ret16 GetPolyFillMode(word) GetPolyFillMode16
85 pascal -ret16 GetROP2(word) GetROP216
86 pascal -ret16 GetRelAbs(word) GetRelAbs16
87 pascal -ret16 GetStockObject(word) GetStockObject16
88 pascal -ret16 GetStretchBltMode(word) GetStretchBltMode16
89 pascal -ret16 GetTextCharacterExtra(word) GetTextCharacterExtra16
90 pascal GetTextColor(word) GetTextColor16
91 pascal GetTextExtent(word ptr s_word) GetTextExtent16
92 pascal -ret16 GetTextFace(word s_word ptr) GetTextFace16
93 pascal -ret16 GetTextMetrics(word ptr) GetTextMetrics16
94 pascal GetViewportExt(word) GetViewportExt16
95 pascal GetViewportOrg(word) GetViewportOrg16
96 pascal GetWindowExt(word) GetWindowExt16
97 pascal GetWindowOrg(word) GetWindowOrg16
98 pascal -ret16 IntersectVisRect(word s_word s_word s_word s_word) IntersectVisRect16
99 pascal -ret16 LPtoDP(word ptr s_word) LPtoDP16
100 pascal -ret16 LineDDA(s_word s_word s_word s_word segptr long) LineDDA16
101 pascal -ret16 OffsetRgn(word s_word s_word) OffsetRgn16
102 pascal -ret16 OffsetVisRgn(word s_word s_word) OffsetVisRgn16
103 pascal -ret16 PtVisible(word s_word s_word) PtVisible16
104 pascal -ret16 RectVisibleOld(word ptr) RectVisible16 # also named RECTVISIBLE
105 pascal -ret16 SelectVisRgn(word word) SelectVisRgn16
106 pascal SetBitmapBits(word long ptr) SetBitmapBits16
# ??? (not even in W1.1)
117 pascal SetDCOrg(word s_word s_word) SetDCOrg16
# 118 stub InternalCreateDC # W1.1, W2.0
118 pascal -ret16 GetSystemIconFont() GetSystemIconFont16
119 pascal -ret16 AddFontResource(str) AddFontResource16
120 stub GetContinuingTextExtent # W1.1, W2.0
121 pascal -ret16 Death(word) Death16
122 pascal -ret16 Resurrection(word word word word word word word) Resurrection16
123 pascal -ret16 PlayMetaFile(word word) PlayMetaFile16
124 pascal -ret16 GetMetaFile(str) GetMetaFile16
125 pascal -ret16 CreateMetaFile(str) CreateMetaFile16
126 pascal -ret16 CloseMetaFile(word) CloseMetaFile16
127 pascal -ret16 DeleteMetaFile(word) DeleteMetaFile16
128 pascal -ret16 MulDiv(s_word s_word s_word) MulDiv16
129 pascal -ret16 SaveVisRgn(word) SaveVisRgn16
130 pascal -ret16 RestoreVisRgn(word) RestoreVisRgn16
131 pascal -ret16 InquireVisRgn(word) InquireVisRgn16
132 pascal -ret16 SetEnvironment(str str word) SetEnvironment16
133 pascal -ret16 GetEnvironment(str str word) GetEnvironment16
134 pascal -ret16 GetRgnBox(word ptr) GetRgnBox16
135 pascal -ret16 ScanLR(word word word long word) ScanLR16
136 pascal -ret16 RemoveFontResource(str) RemoveFontResource16
#137 - 147 removed sometime after W2.0
137 stub GSV
138 stub DPXlate
139 stub SetWinViewExt
140 stub ScaleExt
141 stub WordSet
142 stub RectStuff
143 stub OffsetOrg
144 stub LockDC # < W2.0
145 stub UnlockDC # < W2.0
146 stub LockUnlock # < W2.0
147 stub GDI_FarFrame
148 pascal SetBrushOrg(word s_word s_word) SetBrushOrg16
149 pascal GetBrushOrg(word) GetBrushOrg16
150 pascal -ret16 UnrealizeObject(word) UnrealizeObject16
151 pascal -ret16 CopyMetaFile(word str) CopyMetaFile16
152 stub GDIInitApp # W1.1, W2.0
153 pascal -ret16 CreateIC(str str str ptr) CreateIC16
154 pascal GetNearestColor(word long) GetNearestColor16
155 pascal -ret16 QueryAbort(word word) QueryAbort16
156 pascal -ret16 CreateDiscardableBitmap(word word word) CreateDiscardableBitmap16
157 stub CompatibleBitmap # W1.1, W2.0
158 stub EnumCallback
159 pascal -ret16 GetMetaFileBits(word) GetMetaFileBits16
160 pascal -ret16 SetMetaFileBits(word) SetMetaFileBits16
161 pascal -ret16 PtInRegion(word s_word s_word) PtInRegion16
162 pascal GetBitmapDimension(word) GetBitmapDimension16
163 pascal SetBitmapDimension(word s_word s_word) SetBitmapDimension16
164 stub PixToLine # W1.1, W2.0
#165 - 200 not in W1.1
169 pascal -ret16 IsDCDirty(word segptr) IsDCDirty16
170 stub SetDCStatus
171 stub LVBUNION # W2.0 (only ?)
172 pascal -ret16 SetRectRgn(word s_word s_word s_word s_word) SetRectRgn16
173 pascal -ret16 GetClipRgn(word) GetClipRgn16
174 stub BLOAT # W2.0 (only ?) ROTFL ! ;-))
175 pascal -ret16 EnumMetaFile(word word segptr long) EnumMetaFile16
176 pascal -ret16 PlayMetaFileRecord(word ptr ptr word) PlayMetaFileRecord16
177 stub RCOS # W2.0 (only ?)
178 stub RSIN # W2.0 (only ?)
179 pascal -ret16 GetDCState(word) GetDCState16
180 pascal -ret16 SetDCState(word word) SetDCState16
181 pascal -ret16 RectInRegionOld(word ptr) RectInRegion16 # also named RECTINREGION
182 stub REQUESTSEM # W2.0 (only ?)
183 stub CLEARSEM # W2.0 (only ?)
184 stub STUFFVISIBLE # W2.0 (only ?)
185 stub STUFFINREGION # W2.0 (only ?)
186 stub DELETEABOVELINEFONTS # W2.0 (only ?)
188 stub GetTextExtentEx
190 pascal -ret16 SetDCHook(word segptr long) SetDCHook16
191 pascal GetDCHook(word ptr) GetDCHook16
192 pascal -ret16 SetHookFlags(word word) SetHookFlags16
193 pascal -ret16 SetBoundsRect(word ptr word) SetBoundsRect16
194 pascal -ret16 GetBoundsRect(word ptr word) GetBoundsRect16
195 pascal -ret16 SelectBitmap(word word) SelectBitmap16
196 pascal -ret16 SetMetaFileBitsBetter(word) SetMetaFileBitsBetter16
201 stub DMBITBLT
202 stub DMCOLORINFO
206 stub dmEnumDFonts
207 stub DMENUMOBJ
208 stub DMOUTPUT
209 stub DMPIXEL
210 stub dmRealizeObject
211 stub DMSTRBLT
212 stub DMSCANLR
213 stub BRUTE
214 stub DMEXTTEXTOUT
215 stub DMGETCHARWIDTH
216 stub DMSTRETCHBLT
217 stub DMDIBBITS
218 stub DMSTRETCHDIBITS
219 stub DMSETDIBTODEV
220 stub DMTRANSPOSE
230 pascal -ret16 CreatePQ(word) CreatePQ16
231 pascal -ret16 MinPQ(word) MinPQ16
232 pascal -ret16 ExtractPQ(word) ExtractPQ16
233 pascal -ret16 InsertPQ(word word word) InsertPQ16
234 pascal -ret16 SizePQ(word word) SizePQ16
235 pascal -ret16 DeletePQ(word) DeletePQ16
240 pascal -ret16 OpenJob(str str word) OpenJob16
241 pascal -ret16 WriteSpool(word ptr word) WriteSpool16
242 pascal -ret16 WriteDialog(word str word) WriteDialog16
243 pascal -ret16 CloseJob(word) CloseJob16
244 pascal -ret16 DeleteJob(word word) DeleteJob16
245 pascal GetSpoolJob(word ptr) GetSpoolJob16
246 pascal -ret16 StartSpoolPage(word) StartSpoolPage16
247 pascal -ret16 EndSpoolPage(word) EndSpoolPage16
248 stub QueryJob
250 pascal -ret16 Copy(ptr ptr word) Copy16
253 stub DeleteSpoolPage
254 pascal -ret16 SpoolFile(ptr ptr ptr ptr) SpoolFile16
267 stub StartDocPrintEra
268 stub StartPagePrinter
269 stub WritePrinter
270 stub EndPagePrinter
271 stub AbortPrinter
272 stub EndDocPrinter
274 stub ClosePrinter
280 stub GetRealDriverInfo
281 pascal DrvSetPrinterData(str str long ptr long) DrvSetPrinterData16
282 pascal DrvGetPrinterData(str str ptr ptr long ptr) DrvGetPrinterData16
299 stub ENGINEGETCHARWIDTHEX
300 pascal EngineEnumerateFont(str segptr long) EngineEnumerateFont16
301 pascal -ret16 EngineDeleteFont(ptr) EngineDeleteFont16
302 pascal EngineRealizeFont(ptr ptr ptr) EngineRealizeFont16
303 pascal -ret16 EngineGetCharWidth(ptr word word ptr) EngineGetCharWidth16
304 pascal -ret16 EngineSetFontContext(ptr word) EngineSetFontContext16
305 pascal -ret16 EngineGetGlyphBMP(word ptr word word ptr long ptr) EngineGetGlyphBMP16
306 pascal EngineMakeFontDir(word ptr ptr) EngineMakeFontDir16
307 pascal -ret16 GetCharABCWidths(word word word ptr) GetCharABCWidths16
308 pascal -ret16 GetOutlineTextMetrics(word word ptr) GetOutlineTextMetrics16
309 pascal GetGlyphOutline(word word word ptr long ptr ptr) GetGlyphOutline16
310 pascal -ret16 CreateScalableFontResource(word str str str) CreateScalableFontResource16
311 pascal GetFontData(word long long ptr long) GetFontData16
312 stub ConvertOutLineFontFile
313 pascal -ret16 GetRasterizerCaps(ptr word) GetRasterizerCaps16
314 stub EngineExtTextOut
315 pascal EngineRealizeFontExt(long long long long) EngineRealizeFontExt16
316 stub EngineGetCharWidthStr
317 stub EngineGetGlyphBmpExt
330 pascal -ret16 EnumFontFamilies(word str segptr long) EnumFontFamilies16
332 pascal -ret16 GetKerningPairs(word word ptr) GetKerningPairs16
345 pascal -ret16 GetTextAlign(word) GetTextAlign16
346 pascal -ret16 SetTextAlign(word word) SetTextAlign16
347 stub MFDRAWTEXT # W2.0 (only ?)
348 pascal -ret16 Chord(word s_word s_word s_word s_word s_word s_word s_word s_word) Chord16
349 pascal SetMapperFlags(word long) SetMapperFlags16
350 pascal -ret16 GetCharWidth(word word word ptr) GetCharWidth16
351 pascal -ret16 ExtTextOut(word s_word s_word word ptr str word ptr) ExtTextOut16
352 pascal -ret16 GetPhysicalFontHandle(word) GetPhysicalFontHandle16
353 pascal GetAspectRatioFilter(word) GetAspectRatioFilter16
354 pascal -ret16 ShrinkGDIHeap() ShrinkGdiHeap16
355 stub FTrapping0
360 pascal -ret16 CreatePalette(ptr) CreatePalette16
361 pascal -ret16 GDISelectPalette(word word word) GDISelectPalette16
362 pascal -ret16 GDIRealizePalette(word) GDIRealizePalette16
363 pascal -ret16 GetPaletteEntries(word word word ptr) GetPaletteEntries16
364 pascal -ret16 SetPaletteEntries(word word word ptr) SetPaletteEntries16
365 pascal -ret16 RealizeDefaultPalette(word) RealizeDefaultPalette16
366 pascal -ret16 UpdateColors(word) UpdateColors16
367 pascal -ret16 AnimatePalette(word word word ptr) AnimatePalette16
368 pascal -ret16 ResizePalette(word word) ResizePalette16
370 pascal -ret16 GetNearestPaletteIndex(word long) GetNearestPaletteIndex16
372 pascal -ret16 ExtFloodFill(word s_word s_word long word) ExtFloodFill16
373 pascal -ret16 SetSystemPaletteUse(word word) SetSystemPaletteUse16
374 pascal -ret16 GetSystemPaletteUse(word) GetSystemPaletteUse16
375 pascal -ret16 GetSystemPaletteEntries(word word word ptr) GetSystemPaletteEntries16
376 pascal -ret16 ResetDC(word ptr) ResetDC16
377 pascal -ret16 StartDoc(word ptr) StartDoc16
378 pascal -ret16 EndDoc(word) EndDoc16
379 pascal -ret16 StartPage(word) StartPage16
380 pascal -ret16 EndPage(word) EndPage16
381 pascal -ret16 SetAbortProc(word segptr) SetAbortProc16
382 pascal -ret16 AbortDoc(word) AbortDoc16
400 pascal -ret16 FastWindowFrame(word ptr s_word s_word long) FastWindowFrame16
401 pascal -ret16 GdiMoveBitmap(word) GdiMoveBitmap16
402 stub GDIGETBITSGLOBAL # W2.0 (only ?)
403 pascal -ret16 GdiInit2(word word) GdiInit216
404 stub GetTTGlyphIndexMap
405 pascal -ret16 FinalGdiInit(word) FinalGdiInit16
406 stub CREATEREALBITMAPINDIRECT # W2.0 (only ?)
407 pascal -ret16 CreateUserBitmap(word word word word ptr) CreateUserBitmap16
408 stub CREATEREALBITMAP # W2.0 (only ?)
409 pascal -ret16 CreateUserDiscardableBitmap(word word word) CreateUserDiscardableBitmap16
410 pascal -ret16 IsValidMetaFile (word) IsValidMetaFile16
411 pascal -ret16 GetCurLogFont(word) GetCurLogFont16
412 pascal -ret16 IsDCCurrentPalette(word) IsDCCurrentPalette16
439 pascal -ret16 StretchDIBits (word s_word s_word s_word s_word s_word s_word s_word s_word ptr ptr word long) StretchDIBits16
440 pascal -ret16 SetDIBits(word word word word ptr ptr word) SetDIBits16
441 pascal -ret16 GetDIBits(word word word word ptr ptr word) GetDIBits16
442 pascal -ret16 CreateDIBitmap(word ptr long ptr ptr word) CreateDIBitmap16
443 pascal -ret16 SetDIBitsToDevice(word s_word s_word s_word s_word s_word s_word word word ptr ptr word) SetDIBitsToDevice16
444 pascal -ret16 CreateRoundRectRgn(s_word s_word s_word s_word s_word s_word) CreateRoundRectRgn16
445 pascal -ret16 CreateDIBPatternBrush(word word) CreateDIBPatternBrush16
449 stub DEVICECOLORMATCH
450 pascal -ret16 PolyPolygon(word ptr ptr word) PolyPolygon16
451 pascal -ret16 CreatePolyPolygonRgn(ptr ptr word word) CreatePolyPolygonRgn16
452 pascal GdiSeeGdiDo(word word word word) GdiSeeGdiDo16
460 pascal -ret16 GdiTaskTermination(word) GdiTaskTermination16
461 pascal -ret16 SetObjectOwner(word word) SetObjectOwner16
462 pascal -ret16 IsGDIObject(word) IsGDIObject16
463 pascal -ret16 MakeObjectPrivate(word word) MakeObjectPrivate16
464 stub FIXUPBOGUSPUBLISHERMETAFILE
465 pascal -ret16 RectVisible(word ptr) RectVisible16 # RECTVISIBLE_EHH ??
466 pascal -ret16 RectInRegion(word ptr) RectInRegion16 # RECTINREGION_EHH ??
467 pascal -ret16 UnicodeToAnsi(segptr segptr) UnicodeToAnsi16
468 pascal -ret16 GetBitmapDimensionEx(word ptr) GetBitmapDimensionEx16
469 pascal -ret16 GetBrushOrgEx(word ptr) GetBrushOrgEx16
470 pascal -ret16 GetCurrentPositionEx(word ptr) GetCurrentPositionEx16
471 pascal -ret16 GetTextExtentPoint(word ptr s_word ptr) GetTextExtentPoint16
472 pascal -ret16 GetViewportExtEx(word ptr) GetViewportExtEx16
473 pascal -ret16 GetViewportOrgEx(word ptr) GetViewportOrgEx16
474 pascal -ret16 GetWindowExtEx(word ptr) GetWindowExtEx16
475 pascal -ret16 GetWindowOrgEx(word ptr) GetWindowOrgEx16
476 pascal -ret16 OffsetViewportOrgEx(word s_word s_word ptr) OffsetViewportOrgEx16
477 pascal -ret16 OffsetWindowOrgEx(word s_word s_word ptr) OffsetWindowOrgEx16
478 pascal -ret16 SetBitmapDimensionEx(word s_word s_word ptr) SetBitmapDimensionEx16
479 pascal -ret16 SetViewportExtEx(word s_word s_word ptr) SetViewportExtEx16
480 pascal -ret16 SetViewportOrgEx(word s_word s_word ptr) SetViewportOrgEx16
481 pascal -ret16 SetWindowExtEx(word s_word s_word ptr) SetWindowExtEx16
482 pascal -ret16 SetWindowOrgEx(word s_word s_word ptr) SetWindowOrgEx16
483 pascal -ret16 MoveToEx(word s_word s_word ptr) MoveToEx16
484 pascal -ret16 ScaleViewportExtEx(word s_word s_word s_word s_word ptr) ScaleViewportExtEx16
485 pascal -ret16 ScaleWindowExtEx(word s_word s_word s_word s_word ptr) ScaleWindowExtEx16
486 pascal -ret16 GetAspectRatioFilterEx(word ptr) GetAspectRatioFilterEx16
488 pascal -ret16 GetFontAssocStatus(word) GetFontAssocStatus16
489 pascal -ret16 CreateDIBSection(word ptr word ptr long long) CreateDIBSection16
490 stub CloseEnhMetafile
#490 stub POLYLINEWOW # conflicts with CloseEnhMetaFile !!
491 stub CopyEnhMetafile
492 stub CreateEnhMetafile
493 stub DeleteEnhMetafile
495 stub GDIComment
496 stub GetEnhMetafile
497 stub GetEnhMetafileBits
498 stub GetEnhMetafileDescription
499 stub GetEnhMetafileHeader
501 stub GetEnhMetafilePaletteEntries
502 pascal -ret16 PolyBezier(word ptr word) PolyBezier16
503 pascal -ret16 PolyBezierTo(word ptr word) PolyBezierTo16
504 stub PlayEnhMetafileRecord
505 stub SetEnhMetafileBits
506 stub SetMetaRgn
508 pascal -ret16 ExtSelectClipRgn(word word word) ExtSelectClipRgn16
511 pascal -ret16 AbortPath(word) AbortPath16
512 pascal -ret16 BeginPath(word) BeginPath16
513 pascal -ret16 CloseFigure(word) CloseFigure16
514 pascal -ret16 EndPath(word) EndPath16
515 pascal -ret16 FillPath(word) FillPath16
516 pascal -ret16 FlattenPath(word) FlattenPath16
517 pascal -ret16 GetPath(word ptr ptr word) GetPath16
518 pascal -ret16 PathToRegion(word) PathToRegion16
519 pascal -ret16 SelectClipPath(word word) SelectClipPath16
520 pascal -ret16 StrokeAndFillPath(word) StrokeAndFillPath16
521 pascal -ret16 StrokePath(word) StrokePath16
522 pascal -ret16 WidenPath(word) WidenPath16
523 stub ExtCreatePen
524 pascal -ret16 GetArcDirection(word) GetArcDirection16
525 pascal -ret16 SetArcDirection(word word) SetArcDirection16
526 stub GetMiterLimit
527 stub SetMiterLimit
528 stub GDIParametersInfo
529 pascal -ret16 CreateHalftonePalette(word) CreateHalftonePalette16
# Hebrew version API's
530 pascal -ret16 RawTextOut(word s_word s_word str word) RawTextOut16
531 pascal -ret16 RawExtTextOut(word s_word s_word word ptr str word ptr) RawExtTextOut16
532 pascal -ret16 RawGetTextExtent(word str word) RawGetTextExtent16
533 pascal -ret16 RawGetTextExtentEx() RawGetTextExtentEx16
536 pascal -ret16 BiDiLayout() BiDiLayout16
537 pascal -ret16 BiDiCreateTabString() BiDiCreateTabString16
538 pascal -ret16 BiDiCreateString() BiDiCreateString16
539 pascal -ret16 BiDiStringOut() BiDiStringOut16
540 pascal -ret16 BiDiGlyphOut(word word word word str word word word) BiDiGlyphOut16
541 pascal -ret16 BiDiJustifyString() BiDiJustifyString16
542 pascal -ret16 BiDiSetStringTabs() BiDiSetStringTabs16
543 pascal -ret16 BiDiGetStringExtent() BiDiGetStringExtent16
544 pascal -ret16 BiDiGetNextGlyph() BiDiGetNextGlyph16
545 pascal -ret16 BiDiGetPrevGlyph() BiDiGetPrevGlyph16
546 pascal -ret16 BiDiIsStringRTL() BiDiIsStringRTL16
547 pascal -ret16 BiDiGlyphLength() BiDiGlyphLength16
548 pascal -ret16 BiDiCaretStringToPel() BiDiCaretStringTopel16
549 pascal -ret16 BiDiCaretPelToString() BiDiCaretPelToString16
550 pascal -ret16 BiDiStringToGlyph() BiDiStringToGlyph16
551 pascal -ret16 BiDiGlyphToString() BiDiGlyphToString16
552 pascal -ret16 BiDiPelToGlyph() BiDiPelToGlyph16
553 pascal -ret16 BiDiGlyphToPel() BiDiGlyphToPel16
554 pascal -ret16 BiDiBounds() BiDiBounds16
555 pascal -ret16 BiDiDeleteString(word) BiDiDeleteString16
556 pascal -ret16 BiDiSetDefaults() BiDiSetDefaults16
558 pascal -ret16 BiDiGetDefaults() BiDiGetDefaults16
559 pascal -ret16 BiDiCalcString(word word ptr word word word word word) BiDiCalcString16
560 pascal -ret16 BiDiShape(word word word word word word word word word word word word word word word word word word word word) BiDiShape16
561 pascal -ret16 BiDiFontComplement() BiDiFontComplement16
563 pascal -ret16 BiDiCalcTabString() BiDiCalcTabString16
564 pascal -ret16 BiDiSetKashida() BiDiSetKashida16
565 pascal -ret16 BiDiKExtTextOut() BiDiKExtTextOut16
566 pascal -ret16 BiDiShapeEx() BiDiShapeEx16
569 pascal -ret16 BiDiCreateStringEx(word word word ptr word word word word word) BiDiCreateStringEx16
570 pascal -ret16 GetUnicodeMap() GetUnicodeMap16
571 pascal -ret16 GetTextExtentRtoL() GetTextExtentRtoL16
572 pascal -ret16 GetHDCCharSet(word) GetHDCCharSet16
573 pascal -ret16 BiDiLayoutEx(ptr word word word ptr word word word word ptr ptr word word word) BiDiLayoutEx16
574 pascal -ret16 BiDiCreateTabStringEx() BiDiCreateTabStringEx16
575 pascal -ret16 BiDiCalcTabStringEx() BiDiCalcTabStringEx16
576 pascal -ret16 BiDiCalcStringEx() BiDiCalcStringEx16
588 pascal -ret16 SetTextCodePage(word word) SetTextCodePage16
589 pascal -ret16 GetTextCodePage() GetTextCodePage16
602 pascal -ret16 SetDIBColorTable(word word word ptr) SetDIBColorTable16
603 pascal -ret16 GetDIBColorTable(word word word ptr) GetDIBColorTable16
604 pascal -ret16 SetSolidBrush(word long) SetSolidBrush16
605 pascal -ret16 SysDeleteObject(word) DeleteObject16 # ???
606 pascal -ret16 SetMagicColors(word long word) SetMagicColors16
607 pascal GetRegionData(word long ptr) GetRegionData16
608 stub ExtCreateRegion
609 pascal -ret16 GdiFreeResources(long) GdiFreeResources16
610 pascal -ret16 GdiSignalProc32(long long long word) GdiSignalProc
611 stub GetRandomRgn
612 pascal -ret16 GetTextCharset(word) GetTextCharset16
613 pascal -ret16 EnumFontFamiliesEx(word ptr segptr long long) EnumFontFamiliesEx16
614 stub AddLpkToGDI
615 stub GetCharacterPlacement
616 pascal GetFontLanguageInfo(word) GetFontLanguageInfo16
650 stub BuildInverseTableDIB
701 stub GDITHKCONNECTIONDATALS
702 stub FT_GDIFTHKTHKCONNECTIONDATA
703 stub FDTHKCONNECTIONDATASL
704 stub ICMTHKCONNECTIONDATASL
820 stub ICMCreateTransform
821 stub ICMDeleteTransform
822 stub ICMTranslateRGB
823 stub ICMTranslateRGBs
824 stub ICMCheckColorsInGamut
1000 pascal -ret16 SetLayout(word long) SetLayout16
1001 stub GetLayout
5000 pascal DllEntryPoint(long word word word long word) DllEntryPoint
================================================
FILE: gdi/gdi.vcxproj
================================================
Debug
Win32
Release
Win32
{0EBCFB5B-3092-4E06-A007-CA50B1DA3298}
Win32Proj
gdi
10.0.17134.0
DynamicLibrary
true
v141
Unicode
DynamicLibrary
false
v141
true
Unicode
true
.exe16
false
.exe16
Level3
Disabled
WIN32;_DEBUG;_WINDOWS;_USRDLL;GDI_EXPORTS;_X86_;__WINESRC__;__i386__;USE_COMPILER_EXCEPTIONS;HAVE_STRNCASECMP;HAVE__STRNICMP;_WINTERNL_;NtCurrentTeb=NtCurrentTeb__;inline=__inline;%(PreprocessorDefinitions)
../wine
Windows
true
$(OutDir)winecrt0.lib;$(OutDir)krnl386.lib;$(OutDir)user.lib;$(OutDir)libwine.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;advapi32.lib;winspool.lib
gdi.def
Level3
MaxSpeed
true
true
WIN32;NDEBUG;_WINDOWS;_USRDLL;GDI_EXPORTS;_X86_;__WINESRC__;__i386__;USE_COMPILER_EXCEPTIONS;HAVE_STRNCASECMP;HAVE__STRNICMP;_WINTERNL_;NtCurrentTeb=NtCurrentTeb__;inline=__inline;DECLSPEC_HIDDEN=;%(PreprocessorDefinitions)
../wine
Windows
true
true
true
gdi.def
false
$(OutDir)winecrt0.lib;$(OutDir)krnl386.lib;$(OutDir)user.lib;$(OutDir)libwine.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;advapi32.lib;winspool.lib
Document
"$(OutDir)convspec" "%(Filename).spec" --heap 65520 GDI > "%(Filename).asm" && "$(AsmPath)as" --32 -o "%(Filename).obj" "%(Filename).asm"
%(Filename).obj
"$(OutDir)convspec" "%(Filename).spec" --heap 65520 GDI > "%(Filename).asm" && "$(AsmPath)as" --32 -o "%(Filename).obj" "%(Filename).asm"
%(Filename).obj
================================================
FILE: gdi/gdi.vcxproj.filters
================================================
{4FC737F1-C7A5-4376-A066-2A32D752A2FF}
cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
{93995380-89BD-4b04-88EB-625FBE52EBFB}
h;hh;hpp;hxx;hm;inl;inc;xsd
{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
ソース ファイル
ソース ファイル
ソース ファイル
ソース ファイル
ソース ファイル
ソース ファイル
================================================
FILE: gdi/metafile.c
================================================
/*
* Metafile functions
*
* Copyright David W. Metcalfe, 1994
* Copyright Niels de Carpentier, 1996
* Copyright Albrecht Kleine, 1996
* Copyright Huw Davies, 1996
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#include
#include
#include "wine/winbase16.h"
#include "wine/wingdi16.h"
#include "wownt32.h"
#include "winreg.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(metafile);
#define METAFILE_MEMORY 1
#define METAFILE_DISK 2
#define MFHEADERSIZE (sizeof(METAHEADER))
#define MFVERSION 0x300
/******************************************************************
* MF_GetMetaHeader16
*
* Returns ptr to METAHEADER associated with HMETAFILE16
* Should be followed by call to MF_ReleaseMetaHeader16
*/
static METAHEADER *MF_GetMetaHeader16( HMETAFILE16 hmf )
{
return GlobalLock16(hmf);
}
/******************************************************************
* MF_ReleaseMetaHeader16
*
* Releases METAHEADER associated with HMETAFILE16
*/
static BOOL16 MF_ReleaseMetaHeader16( HMETAFILE16 hmf )
{
return GlobalUnlock16( hmf );
}
/******************************************************************
* create_metafile16
*
* Create a 16-bit metafile from a 32-bit one. The 32-bit one is deleted.
*/
static HMETAFILE16 create_metafile16( HMETAFILE hmf )
{
UINT size;
HMETAFILE16 hmf16;
if (!hmf) return 0;
size = GetMetaFileBitsEx( hmf, 0, NULL );
hmf16 = GlobalAlloc16( GMEM_MOVEABLE, size );
if (hmf16)
{
void *buffer = GlobalLock16( hmf16 );
GetMetaFileBitsEx( hmf, size, buffer );
GlobalUnlock16( hmf16 );
}
DeleteMetaFile( hmf );
return hmf16;
}
/******************************************************************
* create_metafile32
*
* Create a 32-bit metafile from a 16-bit one.
*/
static HMETAFILE create_metafile32( HMETAFILE16 hmf16 )
{
METAHEADER *mh = MF_GetMetaHeader16( hmf16 );
if (!mh) return 0;
return SetMetaFileBitsEx( /*mh->mtSize * 2*/GlobalSize16(hmf16), (BYTE *)mh );
}
/**********************************************************************
* CreateMetaFile (GDI.125)
*/
HDC16 WINAPI CreateMetaFile16( LPCSTR filename )
{
return HDC_16( CreateMetaFileA( filename ) );
}
/******************************************************************
* CloseMetaFile (GDI.126)
*/
HMETAFILE16 WINAPI CloseMetaFile16(HDC16 hdc)
{
return create_metafile16( CloseMetaFile( HDC_32(hdc) ));
}
/******************************************************************
* DeleteMetaFile (GDI.127)
*/
BOOL16 WINAPI DeleteMetaFile16( HMETAFILE16 hmf )
{
return !GlobalFree16( hmf );
}
/******************************************************************
* GetMetaFile (GDI.124)
*/
HMETAFILE16 WINAPI GetMetaFile16( LPCSTR lpFilename )
{
return create_metafile16( GetMetaFileA( lpFilename ));
}
/******************************************************************
* CopyMetaFile (GDI.151)
*/
HMETAFILE16 WINAPI CopyMetaFile16( HMETAFILE16 hSrcMetaFile, LPCSTR lpFilename)
{
HMETAFILE hmf = create_metafile32( hSrcMetaFile );
HMETAFILE hmf2 = CopyMetaFileA( hmf, lpFilename );
DeleteMetaFile( hmf );
return create_metafile16( hmf2 );
}
/******************************************************************
* IsValidMetaFile (GDI.410)
*
* Attempts to check if a given metafile is correctly formatted.
* Currently, the only things verified are several properties of the
* header.
*
* RETURNS
* TRUE if hmf passes some tests for being a valid metafile, FALSE otherwise.
*
* BUGS
* This is not exactly what windows does, see _Undocumented_Windows_
* for details.
*/
BOOL16 WINAPI IsValidMetaFile16(HMETAFILE16 hmf)
{
BOOL16 res=FALSE;
METAHEADER *mh = MF_GetMetaHeader16(hmf);
if (mh) {
if (mh->mtType == METAFILE_MEMORY || mh->mtType == METAFILE_DISK)
if (mh->mtHeaderSize == MFHEADERSIZE/sizeof(INT16))
if (mh->mtVersion == MFVERSION)
res=TRUE;
MF_ReleaseMetaHeader16(hmf);
}
TRACE("IsValidMetaFile %x => %d\n",hmf,res);
return res;
}
/******************************************************************
* PlayMetaFile (GDI.123)
*
*/
BOOL16 WINAPI PlayMetaFile16( HDC16 hdc, HMETAFILE16 hmf16 )
{
HMETAFILE hmf = create_metafile32( hmf16 );
BOOL ret = PlayMetaFile( HDC_32(hdc), hmf );
DeleteMetaFile( hmf );
return ret;
}
#define META_EOF 0x0000
typedef struct
{
LPARAM lpData;
SEGPTR spht;
WORD seg;
WORD offset;
SEGPTR record;
HMETAFILE hmf32;
SEGPTR lpEnumFunc;
WORD max;
} enum_metafile_data;
int CALLBACK EnumMetaFileCallback(HDC hdc, HANDLETABLE *lpht, METARECORD *lpMR, int nObj, LPARAM param)
{
enum_metafile_data *d = (enum_metafile_data*)param;
HANDLETABLE16 *lpht16;
int i;
WORD args[8];
DWORD ret;
lpht16 = MapSL(d->spht);
for (i = 0; i < nObj; i++)
{
lpht16->objectHandle[i] = HDC_16(lpht->objectHandle[i]);
}
if (lpMR->rdSize > d->max)
{
ERR("\n");
}
DWORD siz = lpMR->rdSize * 2;
memcpy(MapSL(d->record), lpMR, siz);
args[7] = HDC_16(hdc);
args[6] = SELECTOROF(d->spht);
args[5] = OFFSETOF(d->spht);
args[4] = SELECTOROF(d->record);
args[3] = OFFSETOF(d->record);
args[2] = nObj;
args[1] = HIWORD(d->lpData);
args[0] = LOWORD(d->lpData);
WOWCallback16Ex((DWORD)d->lpEnumFunc, WCB16_PASCAL, sizeof(args), args, &ret);
memcpy(lpMR, MapSL(d->record), siz);
lpht16 = MapSL(d->spht);
for (i = 0; i < nObj; i++)
{
lpht->objectHandle[i] = HDC_32(lpht16->objectHandle[i]);
}
return LOWORD(ret);
}
/******************************************************************
* EnumMetaFile (GDI.175)
*
*/
BOOL16 WINAPI EnumMetaFile16( HDC16 hdc16, HMETAFILE16 hmf,
MFENUMPROC16 lpEnumFunc, LPARAM lpData )
{
#if 1
METAHEADER *mh = MF_GetMetaHeader16(hmf);
HMETAFILE hmf32 = create_metafile32(hmf);
enum_metafile_data param;
BOOL r;
HGLOBAL16 hHT;
param.lpData = lpData;
hHT = GlobalAlloc16(GMEM_MOVEABLE | GMEM_ZEROINIT,
FIELD_OFFSET(HANDLETABLE16, objectHandle[mh->mtNoObjects]));
HGLOBAL16 record = GlobalAlloc16(GMEM_MOVEABLE | GMEM_ZEROINIT, mh->mtMaxRecord * 2);
param.max = mh->mtMaxRecord;
param.spht = WOWGlobalLock16(hHT);
param.lpEnumFunc = lpEnumFunc;
param.seg = hmf | 7;
param.hmf32 = hmf32;
param.record = WOWGlobalLock16(record);
r = EnumMetaFile(HDC_32(hdc16), hmf32, EnumMetaFileCallback, ¶m);
DeleteMetaFile(hmf32);
GlobalFree16(hHT);
GlobalFree16(record);
/* twice */
MF_ReleaseMetaHeader16(hmf);
MF_ReleaseMetaHeader16(hmf);
return r;
#else
METAHEADER *mh = MF_GetMetaHeader16(hmf);
METARECORD *mr;
HANDLETABLE16 *ht;
HDC hdc = HDC_32(hdc16);
HGLOBAL16 hHT;
SEGPTR spht;
unsigned int offset = 0;
WORD i, seg;
HPEN hPen;
HBRUSH hBrush;
HFONT hFont;
WORD args[8];
BOOL16 result = TRUE;
TRACE("(%p, %04x, %p, %08lx)\n", hdc, hmf, lpEnumFunc, lpData);
if(!mh) return FALSE;
/* save the current pen, brush and font */
hPen = GetCurrentObject(hdc, OBJ_PEN);
hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
hFont = GetCurrentObject(hdc, OBJ_FONT);
/* create the handle table */
hHT = GlobalAlloc16(GMEM_MOVEABLE | GMEM_ZEROINIT,
FIELD_OFFSET(HANDLETABLE16, objectHandle[mh->mtNoObjects]));
spht = WOWGlobalLock16(hHT);
seg = hmf | 7;
offset = mh->mtHeaderSize * 2;
/* loop through metafile records */
args[7] = hdc16;
args[6] = SELECTOROF(spht);
args[5] = OFFSETOF(spht);
args[4] = seg + (HIWORD(offset) << __AHSHIFT);
args[3] = LOWORD(offset);
args[2] = mh->mtNoObjects;
args[1] = HIWORD(lpData);
args[0] = LOWORD(lpData);
while (offset < (mh->mtSize * 2))
{
DWORD ret;
mr = (METARECORD *)((char *)mh + offset);
if (mr->rdFunction == META_EOF) {
TRACE("Got META_EOF so stopping\n");
break;
}
WOWCallback16Ex( (DWORD)lpEnumFunc, WCB16_PASCAL, sizeof(args), args, &ret );
if (!LOWORD(ret))
{
result = FALSE;
break;
}
offset += (mr->rdSize * 2);
args[4] = seg + (HIWORD(offset) << __AHSHIFT);
args[3] = LOWORD(offset);
}
SelectObject(hdc, hBrush);
SelectObject(hdc, hPen);
SelectObject(hdc, hFont);
ht = GlobalLock16(hHT);
/* free objects in handle table */
for(i = 0; i < mh->mtNoObjects; i++)
if(*(ht->objectHandle + i) != 0)
DeleteObject( (HGDIOBJ)(ULONG_PTR)(*(ht->objectHandle + i) ));
/* free handle table */
GlobalFree16(hHT);
MF_ReleaseMetaHeader16(hmf);
return result;
#endif
}
/******************************************************************
* GetMetaFileBits (GDI.159)
*
* Trade in a metafile object handle for a handle to the metafile memory.
*
* PARAMS
* hmf [I] metafile handle
*/
HGLOBAL16 WINAPI GetMetaFileBits16( HMETAFILE16 hmf )
{
TRACE("hMem out: %04x\n", hmf);
return hmf;
}
/******************************************************************
* SetMetaFileBits (GDI.160)
*
* Trade in a metafile memory handle for a handle to a metafile object.
* The memory region should hold a proper metafile, otherwise
* problems will occur when it is used. Validity of the memory is not
* checked. The function is essentially just the identity function.
*
* PARAMS
* hMem [I] handle to a memory region holding a metafile
*
* RETURNS
* Handle to a metafile on success, NULL on failure..
*/
HMETAFILE16 WINAPI SetMetaFileBits16( HGLOBAL16 hMem )
{
TRACE("hmf out: %04x\n", hMem);
return hMem;
}
/******************************************************************
* SetMetaFileBitsBetter (GDI.196)
*
* Trade in a metafile memory handle for a handle to a metafile object,
* making a cursory check (using IsValidMetaFile()) that the memory
* handle points to a valid metafile.
*
* RETURNS
* Handle to a metafile on success, NULL on failure..
*/
HMETAFILE16 WINAPI SetMetaFileBitsBetter16( HMETAFILE16 hMeta )
{
if( IsValidMetaFile16( hMeta ) )
return GlobalReAlloc16( hMeta, 0, GMEM_SHARE | GMEM_NODISCARD | GMEM_MODIFY);
return 0;
}
================================================
FILE: gdi/printdrv.c
================================================
/*
* Implementation of some printer driver bits
*
* Copyright 1996 John Harvey
* Copyright 1998 Huw Davies
* Copyright 1998 Andreas Mohr
* Copyright 1999 Klaas van Gend
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#include "wine/port.h"
#include
#include
#include
#include
#include
#include
#include
#ifdef HAVE_IO_H
# include
#endif
#ifdef HAVE_SYS_WAIT_H
# include
#endif
#ifdef HAVE_UNISTD_H
# include
#endif
#include
#include "windef.h"
#include "winbase.h"
#include "winuser.h"
#include "wine/winbase16.h"
#include "wine/wingdi16.h"
#include "winspool.h"
#include "winerror.h"
#include "winreg.h"
#include "wownt32.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(print);
static const char PrinterModel[] = "Printer Model";
static const char DefaultDevMode[] = "Default DevMode";
static const char PrinterDriverData[] = "PrinterDriverData";
static const char Printers[] = "System\\CurrentControlSet\\Control\\Print\\Printers\\";
/****************** misc. printer related functions */
/*
* The following function should implement a queuing system
*/
struct hpq
{
struct hpq *next;
int tag;
int key;
};
static struct hpq *hpqueue;
/**********************************************************************
* CreatePQ (GDI.230)
*
*/
HPQ16 WINAPI CreatePQ16(INT16 size)
{
#if 0
HGLOBAL16 hpq = 0;
WORD tmp_size;
LPWORD pPQ;
tmp_size = size << 2;
if (!(hpq = GlobalAlloc16(GMEM_SHARE|GMEM_MOVEABLE, tmp_size + 8)))
return 0xffff;
pPQ = GlobalLock16(hpq);
*pPQ++ = 0;
*pPQ++ = tmp_size;
*pPQ++ = 0;
*pPQ++ = 0;
GlobalUnlock16(hpq);
return (HPQ16)hpq;
#else
FIXME("(%d): stub\n",size);
return 1;
#endif
}
/**********************************************************************
* DeletePQ (GDI.235)
*
*/
INT16 WINAPI DeletePQ16(HPQ16 hPQ)
{
return GlobalFree16(hPQ);
}
/**********************************************************************
* ExtractPQ (GDI.232)
*
*/
INT16 WINAPI ExtractPQ16(HPQ16 hPQ)
{
struct hpq *queue, *prev, *current, *currentPrev;
int key = 0, tag = -1;
prev = NULL;
queue = current = hpqueue;
if (current)
key = current->key;
while (current)
{
currentPrev = current;
current = current->next;
if (current)
{
if (current->key < key)
{
queue = current;
prev = currentPrev;
}
}
}
if (queue)
{
tag = queue->tag;
if (prev)
prev->next = queue->next;
else
hpqueue = queue->next;
HeapFree(GetProcessHeap(), 0, queue);
}
TRACE("%x got tag %d key %d\n", hPQ, tag, key);
return tag;
}
/**********************************************************************
* InsertPQ (GDI.233)
*
*/
INT16 WINAPI InsertPQ16(HPQ16 hPQ, INT16 tag, INT16 key)
{
struct hpq *queueItem = HeapAlloc(GetProcessHeap(), 0, sizeof(struct hpq));
if(queueItem == NULL) {
ERR("Memory exhausted!\n");
return FALSE;
}
queueItem->next = hpqueue;
hpqueue = queueItem;
queueItem->key = key;
queueItem->tag = tag;
FIXME("(%x %d %d): stub???\n", hPQ, tag, key);
return TRUE;
}
/**********************************************************************
* MinPQ (GDI.231)
*
*/
INT16 WINAPI MinPQ16(HPQ16 hPQ)
{
FIXME("(%x): stub\n", hPQ);
return 0;
}
/**********************************************************************
* SizePQ (GDI.234)
*
*/
INT16 WINAPI SizePQ16(HPQ16 hPQ, INT16 sizechange)
{
FIXME("(%x %d): stub\n", hPQ, sizechange);
return -1;
}
/*
* The following functions implement part of the spooling process to
* print manager. I would like to see wine have a version of print managers
* that used LPR/LPD. For simplicity print jobs will be sent to a file for
* now.
*/
#ifdef HAVE_UNISTD_H
typedef struct PRINTJOB
{
char *pszOutput;
char *pszTitle;
HDC16 hDC;
HANDLE16 hHandle;
int nIndex;
int fd;
pid_t pid;
} PRINTJOB, *PPRINTJOB;
#define MAX_PRINT_JOBS 1
#define SP_OK 1
static PPRINTJOB gPrintJobsTable[MAX_PRINT_JOBS];
static PPRINTJOB FindPrintJobFromHandle(HANDLE16 hHandle)
{
return gPrintJobsTable[0];
}
#endif
#ifdef HAVE_UNISTD_H
static int CreateSpoolFile(LPCSTR pszOutput, pid_t *out_pid)
{
int fd=-1;
char psCmd[1024];
const char *psCmdP = psCmd;
HKEY hkey;
/* TTD convert the 'output device' into a spool file name */
if (pszOutput == NULL || *pszOutput == '\0' || out_pid == NULL)
return -1;
*out_pid = -1;
psCmd[0] = 0;
/* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
if(!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Printing\\Spooler", &hkey))
{
DWORD type, count = sizeof(psCmd);
RegQueryValueExA(hkey, pszOutput, 0, &type, (LPBYTE)psCmd, &count);
RegCloseKey(hkey);
}
if (!psCmd[0] && !strncmp("LPR:",pszOutput,4))
sprintf(psCmd,"|lpr -P'%s'",pszOutput+4);
TRACE("Got printerSpoolCommand '%s' for output device '%s'\n",
psCmd, pszOutput);
if (!*psCmd)
psCmdP = pszOutput;
else
{
while (*psCmdP && isspace(*psCmdP))
{
psCmdP++;
}
if (!*psCmdP)
return -1;
}
TRACE("command: '%s'\n", psCmdP);
#ifdef HAVE_FORK
if (*psCmdP == '|')
{
int fds[2];
if (pipe(fds)) {
ERR("pipe() failed!\n");
return -1;
}
if ((*out_pid = fork()) == 0)
{
psCmdP++;
TRACE("In child need to exec %s\n",psCmdP);
close(0);
dup2(fds[0],0);
close (fds[1]);
/* reset signals that we previously set to SIG_IGN */
signal( SIGPIPE, SIG_DFL );
execl("/bin/sh", "/bin/sh", "-c", psCmdP, NULL);
_exit(1);
}
close (fds[0]);
fd = fds[1];
TRACE("Need to execute a cmnd and pipe the output to it\n");
}
else
#endif
{
char *buffer;
WCHAR psCmdPW[MAX_PATH];
TRACE("Just assume it's a file\n");
/**
* The file name can be dos based, we have to find its
* corresponding Unix file name.
*/
MultiByteToWideChar(CP_ACP, 0, psCmdP, -1, psCmdPW, MAX_PATH);
if ((buffer = wine_get_unix_file_name(psCmdPW)))
{
if ((fd = open(buffer, O_CREAT | O_TRUNC | O_WRONLY, 0666)) < 0)
{
ERR("Failed to create spool file '%s' ('%s'). (error %s)\n",
buffer, psCmdP, strerror(errno));
}
HeapFree(GetProcessHeap(), 0, buffer);
}
}
return fd;
}
static int FreePrintJob(HANDLE16 hJob)
{
int nRet = SP_ERROR;
PPRINTJOB pPrintJob;
pPrintJob = FindPrintJobFromHandle(hJob);
if (pPrintJob != NULL)
{
nRet = SP_OK;
gPrintJobsTable[pPrintJob->nIndex] = NULL;
HeapFree(GetProcessHeap(), 0, pPrintJob->pszOutput);
HeapFree(GetProcessHeap(), 0, pPrintJob->pszTitle);
if (pPrintJob->fd >= 0) close(pPrintJob->fd);
if (pPrintJob->pid > 0)
{
pid_t wret;
int status;
do {
wret = waitpid(pPrintJob->pid, &status, 0);
} while (wret < 0 && errno == EINTR);
if (wret < 0 || !WIFEXITED(status) || WEXITSTATUS(status))
nRet = SP_ERROR;
}
HeapFree(GetProcessHeap(), 0, pPrintJob);
}
return nRet;
}
#endif
/**********************************************************************
* OpenJob (GDI.240)
*
*/
HPJOB16 WINAPI OpenJob16(LPCSTR lpOutput, LPCSTR lpTitle, HDC16 hDC)
{
#ifdef HAVE_UNISTD_H
HPJOB16 hHandle = (HPJOB16)SP_ERROR;
PPRINTJOB pPrintJob;
TRACE("'%s' '%s' %04x\n", lpOutput, lpTitle, hDC);
pPrintJob = gPrintJobsTable[0];
if (pPrintJob == NULL)
{
int fd;
pid_t pid;
/* Try and create a spool file */
fd = CreateSpoolFile(lpOutput, &pid);
if (fd >= 0)
{
pPrintJob = HeapAlloc(GetProcessHeap(), 0, sizeof(PRINTJOB));
if(pPrintJob == NULL) {
WARN("Memory exhausted!\n");
return hHandle;
}
hHandle = 1;
pPrintJob->pszOutput = HeapAlloc(GetProcessHeap(), 0, strlen(lpOutput)+1);
strcpy( pPrintJob->pszOutput, lpOutput );
if(lpTitle)
{
pPrintJob->pszTitle = HeapAlloc(GetProcessHeap(), 0, strlen(lpTitle)+1);
strcpy( pPrintJob->pszTitle, lpTitle );
}
pPrintJob->hDC = hDC;
pPrintJob->fd = fd;
pPrintJob->pid = pid;
pPrintJob->nIndex = 0;
pPrintJob->hHandle = hHandle;
gPrintJobsTable[pPrintJob->nIndex] = pPrintJob;
}
}
TRACE("return %04x\n", hHandle);
return hHandle;
#endif
FIXME("stub");
}
/**********************************************************************
* CloseJob (GDI.243)
*
*/
INT16 WINAPI CloseJob16(HPJOB16 hJob)
{
#ifdef HAVE_UNISTD_H
int nRet = SP_ERROR;
PPRINTJOB pPrintJob;
TRACE("%04x\n", hJob);
pPrintJob = FindPrintJobFromHandle(hJob);
if (pPrintJob != NULL)
{
FreePrintJob(hJob);
nRet = 1;
}
return nRet;
#endif
}
/**********************************************************************
* WriteSpool (GDI.241)
*
*/
INT16 WINAPI WriteSpool16(HPJOB16 hJob, LPSTR lpData, INT16 cch)
{
#ifdef HAVE_UNISTD_H
int nRet = SP_ERROR;
PPRINTJOB pPrintJob;
TRACE("%04x %p %04x\n", hJob, lpData, cch);
pPrintJob = FindPrintJobFromHandle(hJob);
if (pPrintJob != NULL && pPrintJob->fd >= 0 && cch)
{
if (write(pPrintJob->fd, lpData, cch) != cch)
nRet = SP_OUTOFDISK;
else
nRet = cch;
#if 0
/* FIXME: We just cannot call 16 bit functions from here, since we
* have acquired several locks (DC). And we do not really need to.
*/
if (pPrintJob->hDC == 0) {
TRACE("hDC == 0 so no QueryAbort\n");
}
else if (!(QueryAbort16(pPrintJob->hDC, (nRet == SP_OUTOFDISK) ? nRet : 0 )))
{
CloseJob16(hJob); /* printing aborted */
nRet = SP_APPABORT;
}
#endif
}
return nRet;
#endif
}
typedef INT (WINAPI *MSGBOX_PROC)( HWND, LPCSTR, LPCSTR, UINT );
/**********************************************************************
* WriteDialog (GDI.242)
*
*/
INT16 WINAPI WriteDialog16(HPJOB16 hJob, LPSTR lpMsg, INT16 cchMsg)
{
HMODULE mod;
MSGBOX_PROC pMessageBoxA;
INT16 ret = 0;
TRACE("%04x %04x '%s'\n", hJob, cchMsg, lpMsg);
if ((mod = GetModuleHandleA("user32.dll")))
{
if ((pMessageBoxA = (MSGBOX_PROC)GetProcAddress( mod, "MessageBoxA" )))
ret = pMessageBoxA(0, lpMsg, "Printing Error", MB_OKCANCEL);
}
return ret;
}
/**********************************************************************
* DeleteJob (GDI.244)
*
*/
INT16 WINAPI DeleteJob16(HPJOB16 hJob, INT16 nNotUsed)
{
int nRet;
TRACE("%04x\n", hJob);
//nRet = FreePrintJob(hJob);
return nRet;
}
/*
* The following two function would allow a page to be sent to the printer
* when it has been processed. For simplicity they haven't been implemented.
* This means a whole job has to be processed before it is sent to the printer.
*/
/**********************************************************************
* StartSpoolPage (GDI.246)
*
*/
INT16 WINAPI StartSpoolPage16(HPJOB16 hJob)
{
FIXME("StartSpoolPage GDI.246 unimplemented\n");
return 1;
}
/**********************************************************************
* EndSpoolPage (GDI.247)
*
*/
INT16 WINAPI EndSpoolPage16(HPJOB16 hJob)
{
FIXME("EndSpoolPage GDI.247 unimplemented\n");
return 1;
}
/**********************************************************************
* GetSpoolJob (GDI.245)
*
*/
DWORD WINAPI GetSpoolJob16(int nOption, LONG param)
{
DWORD retval = 0;
TRACE("In GetSpoolJob param 0x%x noption %d\n",param, nOption);
return retval;
}
/******************************************************************
* DrvGetPrinterDataInternal
*
* Helper for DrvGetPrinterData
*/
static DWORD DrvGetPrinterDataInternal(LPCSTR RegStr_Printer,
LPBYTE lpPrinterData, int cbData, int what)
{
DWORD res = -1;
HKEY hkey;
DWORD dwType, cbQueryData;
if (!(RegOpenKeyA(HKEY_LOCAL_MACHINE, RegStr_Printer, &hkey))) {
if (what == INT_PD_DEFAULT_DEVMODE) { /* "Default DevMode" */
if (!(RegQueryValueExA(hkey, DefaultDevMode, 0, &dwType, 0, &cbQueryData))) {
if (!lpPrinterData)
res = cbQueryData;
else if ((cbQueryData) && (cbQueryData <= cbData)) {
cbQueryData = cbData;
if (RegQueryValueExA(hkey, DefaultDevMode, 0,
&dwType, lpPrinterData, &cbQueryData))
res = cbQueryData;
}
}
} else { /* "Printer Driver" */
cbQueryData = 32;
RegQueryValueExA(hkey, "Printer Driver", 0,
&dwType, lpPrinterData, &cbQueryData);
res = cbQueryData;
}
}
if (hkey) RegCloseKey(hkey);
return res;
}
/******************************************************************
* DrvGetPrinterData (GDI.282)
*
*/
DWORD WINAPI DrvGetPrinterData16(LPSTR lpPrinter, LPSTR lpProfile,
LPDWORD lpType, LPBYTE lpPrinterData,
int cbData, LPDWORD lpNeeded)
{
LPSTR RegStr_Printer;
HKEY hkey = 0, hkey2 = 0;
DWORD res = 0;
DWORD dwType, PrinterAttr, cbPrinterAttr, SetData, size;
if (HIWORD(lpPrinter))
TRACE("printer %s\n",lpPrinter);
else
TRACE("printer %p\n",lpPrinter);
if (HIWORD(lpProfile))
TRACE("profile %s\n",lpProfile);
else
TRACE("profile %p\n",lpProfile);
TRACE("lpType %p\n",lpType);
if ((!lpPrinter) || (!lpProfile) || (!lpNeeded))
return ERROR_INVALID_PARAMETER;
RegStr_Printer = HeapAlloc(GetProcessHeap(), 0,
strlen(Printers) + strlen(lpPrinter) + 2);
strcpy(RegStr_Printer, Printers);
strcat(RegStr_Printer, lpPrinter);
if ((PtrToUlong(lpProfile) == INT_PD_DEFAULT_DEVMODE) || (HIWORD(lpProfile) &&
(!strcmp(lpProfile, DefaultDevMode)))) {
size = DrvGetPrinterDataInternal(RegStr_Printer, lpPrinterData, cbData,
INT_PD_DEFAULT_DEVMODE);
if (size+1) {
*lpNeeded = size;
if ((lpPrinterData) && (*lpNeeded > cbData))
res = ERROR_MORE_DATA;
}
else res = ERROR_INVALID_PRINTER_NAME;
}
else
if ((PtrToUlong(lpProfile) == INT_PD_DEFAULT_MODEL) || (HIWORD(lpProfile) &&
(!strcmp(lpProfile, PrinterModel)))) {
*lpNeeded = 32;
if (!lpPrinterData) goto failed;
if (cbData < 32) {
res = ERROR_MORE_DATA;
goto failed;
}
size = DrvGetPrinterDataInternal(RegStr_Printer, lpPrinterData, cbData,
INT_PD_DEFAULT_MODEL);
if ((size+1) && (lpType))
*lpType = REG_SZ;
else
res = ERROR_INVALID_PRINTER_NAME;
}
else
{
if ((res = RegOpenKeyA(HKEY_LOCAL_MACHINE, RegStr_Printer, &hkey)))
goto failed;
cbPrinterAttr = 4;
if ((res = RegQueryValueExA(hkey, "Attributes", 0,
&dwType, (LPBYTE)&PrinterAttr, &cbPrinterAttr)))
goto failed;
if ((res = RegOpenKeyA(hkey, PrinterDriverData, &hkey2)))
goto failed;
*lpNeeded = cbData;
res = RegQueryValueExA(hkey2, lpProfile, 0,
lpType, lpPrinterData, lpNeeded);
if ((res != ERROR_CANTREAD) &&
((PrinterAttr &
(PRINTER_ATTRIBUTE_ENABLE_BIDI|PRINTER_ATTRIBUTE_NETWORK))
== PRINTER_ATTRIBUTE_NETWORK))
{
if (!(res) && (*lpType == REG_DWORD) && (*(LPDWORD)lpPrinterData == -1))
res = ERROR_INVALID_DATA;
}
else
{
SetData = -1;
RegSetValueExA(hkey2, lpProfile, 0, REG_DWORD, (LPBYTE)&SetData, 4); /* no result returned */
}
}
failed:
if (hkey2) RegCloseKey(hkey2);
if (hkey) RegCloseKey(hkey);
HeapFree(GetProcessHeap(), 0, RegStr_Printer);
return res;
}
/******************************************************************
* DrvSetPrinterData (GDI.281)
*
*/
DWORD WINAPI DrvSetPrinterData16(LPSTR lpPrinter, LPSTR lpProfile,
DWORD lpType, LPBYTE lpPrinterData,
DWORD dwSize)
{
LPSTR RegStr_Printer;
HKEY hkey = 0;
DWORD res = 0;
if (HIWORD(lpPrinter))
TRACE("printer %s\n",lpPrinter);
else
TRACE("printer %p\n",lpPrinter);
if (HIWORD(lpProfile))
TRACE("profile %s\n",lpProfile);
else
TRACE("profile %p\n",lpProfile);
TRACE("lpType %08x\n",lpType);
if ((!lpPrinter) || (!lpProfile) ||
(PtrToUlong(lpProfile) == INT_PD_DEFAULT_MODEL) || (HIWORD(lpProfile) &&
(!strcmp(lpProfile, PrinterModel))))
return ERROR_INVALID_PARAMETER;
RegStr_Printer = HeapAlloc(GetProcessHeap(), 0,
strlen(Printers) + strlen(lpPrinter) + 2);
strcpy(RegStr_Printer, Printers);
strcat(RegStr_Printer, lpPrinter);
if ((PtrToUlong(lpProfile) == INT_PD_DEFAULT_DEVMODE) || (HIWORD(lpProfile) &&
(!strcmp(lpProfile, DefaultDevMode)))) {
if ( RegOpenKeyA(HKEY_LOCAL_MACHINE, RegStr_Printer, &hkey)
!= ERROR_SUCCESS ||
RegSetValueExA(hkey, DefaultDevMode, 0, REG_BINARY,
lpPrinterData, dwSize) != ERROR_SUCCESS )
res = ERROR_INVALID_PRINTER_NAME;
}
else
{
strcat(RegStr_Printer, "\\");
if( (res = RegOpenKeyA(HKEY_LOCAL_MACHINE, RegStr_Printer, &hkey)) ==
ERROR_SUCCESS ) {
if (!lpPrinterData)
res = RegDeleteValueA(hkey, lpProfile);
else
res = RegSetValueExA(hkey, lpProfile, 0, lpType,
lpPrinterData, dwSize);
}
}
if (hkey) RegCloseKey(hkey);
HeapFree(GetProcessHeap(), 0, RegStr_Printer);
return res;
}
HANDLE16 WINAPI SpoolFile16(LPCSTR printer, LPCSTR port, LPCSTR job, LPCSTR file)
{
HANDLE hprinter;
HANDLE16 ret = SP_ERROR;
if (!OpenPrinterA(printer, &hprinter, NULL))
return SP_ERROR;
DOC_INFO_1 dinfo;
dinfo.pDocName = job;
dinfo.pOutputFile = NULL;
dinfo.pDatatype = "RAW";
if (!StartDocPrinterA(hprinter, 1, &dinfo))
goto outprn;
HFILE fd = CreateFileA(file, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (fd == INVALID_HANDLE_VALUE)
goto outfile;
while (1)
{
char buf[1024];
int read, write;
if (!ReadFile(fd, &buf, 1024, &read, NULL) || !read)
break;
if (!WritePrinter(hprinter, &buf, read, &write))
goto outfile;
}
ret = 1;
outfile:
CloseHandle(fd);
EndDocPrinter(hprinter);
outprn:
ClosePrinter(hprinter);
return ret;
}
================================================
FILE: gvm/CMakeLists.txt
================================================
add_library(gvm SHARED gvm.c)
include_directories(../wine)
add_definitions(-D__i386__ -DNtCurrentTeb=NtCurrentTeb__ -DDECLSPEC_HIDDEN=)
target_link_libraries(gvm libwine)
set_target_properties(gvm PROPERTIES PREFIX "")
================================================
FILE: gvm/gvm-interface.h
================================================
/*
* QEMU GVM support
*
* Copyright IBM, Corp. 2008
*
* Authors:
* Anthony Liguori
*
* Copyright (c) 2017 Intel Corporation
* Written by:
* Haitao Shan
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*
*/
#ifndef GVM_INTERFACE_H
#define GVM_INTERFACE_H
#ifdef _WIN32
#include
#include
#include
#endif
#include
#include
#include
#include
#define __u8 uint8_t
#define __u16 uint16_t
#define __u32 uint32_t
#define __u64 uint64_t
#define __s8 int8_t
#define __s16 int16_t
#define __s32 int32_t
#define __s64 int64_t
/*
* GVM x86 specific structures and definitions
*
*/
#define DE_VECTOR 0
#define DB_VECTOR 1
#define BP_VECTOR 3
#define OF_VECTOR 4
#define BR_VECTOR 5
#define UD_VECTOR 6
#define NM_VECTOR 7
#define DF_VECTOR 8
#define TS_VECTOR 10
#define NP_VECTOR 11
#define SS_VECTOR 12
#define GP_VECTOR 13
#define PF_VECTOR 14
#define MF_VECTOR 16
#define AC_VECTOR 17
#define MC_VECTOR 18
#define XM_VECTOR 19
#define VE_VECTOR 20
/* Architectural interrupt line count. */
#define GVM_NR_INTERRUPTS 256
struct gvm_memory_alias {
__u32 slot; /* this has a different namespace than memory slots */
__u32 flags;
__u64 guest_phys_addr;
__u64 memory_size;
__u64 target_phys_addr;
};
/* for GVM_GET_IRQCHIP and GVM_SET_IRQCHIP */
struct gvm_pic_state {
__u8 last_irr; /* edge detection */
__u8 irr; /* interrupt request register */
__u8 imr; /* interrupt mask register */
__u8 isr; /* interrupt service register */
__u8 priority_add; /* highest irq priority */
__u8 irq_base;
__u8 read_reg_select;
__u8 poll;
__u8 special_mask;
__u8 init_state;
__u8 auto_eoi;
__u8 rotate_on_auto_eoi;
__u8 special_fully_nested_mode;
__u8 init4; /* true if 4 byte init */
__u8 elcr; /* PIIX edge/trigger selection */
__u8 elcr_mask;
};
#define GVM_IOAPIC_NUM_PINS 24
struct gvm_ioapic_state {
__u64 base_address;
__u32 ioregsel;
__u32 id;
__u32 irr;
__u32 pad;
union {
__u64 bits;
struct {
__u8 vector;
__u8 delivery_mode:3;
__u8 dest_mode:1;
__u8 delivery_status:1;
__u8 polarity:1;
__u8 remote_irr:1;
__u8 trig_mode:1;
__u8 mask:1;
__u8 reserve:7;
__u8 reserved[4];
__u8 dest_id;
} fields;
} redirtbl[GVM_IOAPIC_NUM_PINS];
};
#define GVM_IRQCHIP_PIC_MASTER 0
#define GVM_IRQCHIP_PIC_SLAVE 1
#define GVM_IRQCHIP_IOAPIC 2
#define GVM_NR_IRQCHIPS 3
#define GVM_RUN_X86_SMM (1 << 0)
/* for GVM_GET_REGS and GVM_SET_REGS */
struct gvm_regs {
/* out (GVM_GET_REGS) / in (GVM_SET_REGS) */
__u64 rax, rbx, rcx, rdx;
__u64 rsi, rdi, rsp, rbp;
__u64 r8, r9, r10, r11;
__u64 r12, r13, r14, r15;
__u64 rip, rflags;
};
/* for GVM_GET_LAPIC and GVM_SET_LAPIC */
#define GVM_APIC_REG_SIZE 0x400
struct gvm_lapic_state {
char regs[GVM_APIC_REG_SIZE];
};
struct gvm_segment {
__u64 base;
__u32 limit;
__u16 selector;
__u8 type;
__u8 present, dpl, db, s, l, g, avl;
__u8 unusable;
__u8 padding;
};
struct gvm_dtable {
__u64 base;
__u16 limit;
__u16 padding[3];
};
/* for GVM_GET_SREGS and GVM_SET_SREGS */
struct gvm_sregs {
/* out (GVM_GET_SREGS) / in (GVM_SET_SREGS) */
struct gvm_segment cs, ds, es, fs, gs, ss;
struct gvm_segment tr, ldt;
struct gvm_dtable gdt, idt;
__u64 cr0, cr2, cr3, cr4, cr8;
__u64 efer;
__u64 apic_base;
__u64 interrupt_bitmap[(GVM_NR_INTERRUPTS + 63) / 64];
};
/* for GVM_GET_FPU and GVM_SET_FPU */
struct gvm_fpu {
__u8 fpr[8][16];
__u16 fcw;
__u16 fsw;
__u8 ftwx; /* in fxsave format */
__u8 pad1;
__u16 last_opcode;
__u64 last_ip;
__u64 last_dp;
__u8 xmm[16][16];
__u32 mxcsr;
__u32 pad2;
};
struct gvm_msr_entry {
__u32 index;
__u32 reserved;
__u64 data;
};
/* for GVM_GET_MSRS and GVM_SET_MSRS */
struct gvm_msrs {
__u32 nmsrs; /* number of msrs in entries */
__u32 pad;
struct gvm_msr_entry entries[0];
};
/* for GVM_GET_MSR_INDEX_LIST */
struct gvm_msr_list {
__u32 nmsrs; /* number of msrs in entries */
__u32 indices[0];
};
struct gvm_cpuid_entry {
__u32 function;
__u32 index;
__u32 flags;
__u32 eax;
__u32 ebx;
__u32 ecx;
__u32 edx;
__u32 padding[3];
};
#define GVM_CPUID_FLAG_SIGNIFCANT_INDEX (1 << 0)
#define GVM_CPUID_FLAG_STATEFUL_FUNC (1 << 1)
#define GVM_CPUID_FLAG_STATE_READ_NEXT (1 << 2)
/* for GVM_SET_CPUID */
struct gvm_cpuid {
__u32 nent;
__u32 padding;
struct gvm_cpuid_entry entries[0];
};
struct gvm_debug_exit_arch {
__u32 exception;
__u32 pad;
__u64 pc;
__u64 dr6;
__u64 dr7;
};
#define GVM_GUESTDBG_USE_SW_BP 0x00010000
#define GVM_GUESTDBG_USE_HW_BP 0x00020000
#define GVM_GUESTDBG_INJECT_DB 0x00040000
#define GVM_GUESTDBG_INJECT_BP 0x00080000
/* for GVM_SET_GUEST_DEBUG */
struct gvm_guest_debug_arch {
__u64 debugreg[8];
};
/* When set in flags, include corresponding fields on GVM_SET_VCPU_EVENTS */
#define GVM_VCPUEVENT_VALID_NMI_PENDING 0x00000001
#define GVM_VCPUEVENT_VALID_SIPI_VECTOR 0x00000002
#define GVM_VCPUEVENT_VALID_SHADOW 0x00000004
#define GVM_VCPUEVENT_VALID_SMM 0x00000008
/* Interrupt shadow states */
#define GVM_X86_SHADOW_INT_MOV_SS 0x01
#define GVM_X86_SHADOW_INT_STI 0x02
/* for GVM_GET/SET_VCPU_EVENTS */
struct gvm_vcpu_events {
struct {
__u8 injected;
__u8 nr;
__u8 has_error_code;
__u8 pad;
__u32 error_code;
} exception;
struct {
__u8 injected;
__u8 nr;
__u8 soft;
__u8 shadow;
} interrupt;
struct {
__u8 injected;
__u8 pending;
__u8 masked;
__u8 pad;
} nmi;
__u32 sipi_vector;
__u32 flags;
struct {
__u8 smm;
__u8 pending;
__u8 smm_inside_nmi;
__u8 latched_init;
} smi;
__u32 reserved[9];
};
/* for GVM_GET/SET_DEBUGREGS */
struct gvm_debugregs {
__u64 db[4];
__u64 dr6;
__u64 dr7;
__u64 flags;
__u64 reserved[9];
};
/* for GVM_CAP_XSAVE */
struct gvm_xsave {
__u32 region[1024];
};
#define GVM_MAX_XCRS 16
struct gvm_xcr {
__u32 xcr;
__u32 reserved;
__u64 value;
};
struct gvm_xcrs {
__u32 nr_xcrs;
__u32 flags;
struct gvm_xcr xcrs[GVM_MAX_XCRS];
__u64 padding[16];
};
/* definition of registers in gvm_run */
struct gvm_sync_regs {
__u32 dummy[0];
};
#define GVM_X86_QUIRK_LINT0_REENABLED (1 << 0)
#define GVM_X86_QUIRK_CD_NW_CLEARED (1 << 1)
#define FILE_DEVICE_GVM 0xE3E3
/* Macros to convert Linux style ioctl to Windows */
#define __IO(a,b) CTL_CODE(FILE_DEVICE_GVM, b, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define __IOR(a,b,c) __IO(a,b)
#define __IOW(a,b,c) __IO(a,b)
#define __IOWR(a,b,c) __IO(a,b)
#define GVM_API_VERSION 1
/* for GVM_CREATE_MEMORY_REGION */
struct gvm_memory_region {
__u32 slot;
__u32 flags;
__u64 guest_phys_addr;
__u64 memory_size; /* bytes */
};
/* for GVM_SET_USER_MEMORY_REGION */
struct gvm_userspace_memory_region {
__u32 slot;
__u32 flags;
__u64 guest_phys_addr;
__u64 memory_size; /* bytes */
__u64 userspace_addr; /* start of the userspace allocated memory */
};
/*
* The bit 0 ~ bit 15 of gvm_memory_region::flags are visible for userspace,
* other bits are reserved for gvm internal use which are defined in
* include/linux/gvm_host.h.
*/
#define GVM_MEM_LOG_DIRTY_PAGES (1UL << 0)
#define GVM_MEM_READONLY (1UL << 1)
/* for GVM_IRQ_LINE */
struct gvm_irq_level {
/*
* ACPI gsi notion of irq.
* For IA-64 (APIC model) IOAPIC0: irq 0-23; IOAPIC1: irq 24-47..
* For X86 (standard AT mode) PIC0/1: irq 0-15. IOAPIC0: 0-23..
* For ARM: See Documentation/virtual/gvm/api.txt
*/
union {
__u32 irq;
__s32 status;
};
__u32 level;
};
struct gvm_irqchip {
__u32 chip_id;
__u32 pad;
union {
char dummy[512]; /* reserving space */
struct gvm_pic_state pic;
struct gvm_ioapic_state ioapic;
} chip;
};
#define GVM_EXIT_UNKNOWN 0
#define GVM_EXIT_EXCEPTION 1
#define GVM_EXIT_IO 2
#define GVM_EXIT_HYPERCALL 3
#define GVM_EXIT_DEBUG 4
#define GVM_EXIT_HLT 5
#define GVM_EXIT_MMIO 6
#define GVM_EXIT_IRQ_WINDOW_OPEN 7
#define GVM_EXIT_SHUTDOWN 8
#define GVM_EXIT_FAIL_ENTRY 9
#define GVM_EXIT_INTR 10
#define GVM_EXIT_SET_TPR 11
#define GVM_EXIT_TPR_ACCESS 12
#define GVM_EXIT_NMI 16
#define GVM_EXIT_INTERNAL_ERROR 17
#define GVM_EXIT_OSI 18
#define GVM_EXIT_PAPR_HCALL 19
#define GVM_EXIT_WATCHDOG 21
#define GVM_EXIT_EPR 23
#define GVM_EXIT_SYSTEM_EVENT 24
#define GVM_EXIT_IOAPIC_EOI 26
/* For GVM_EXIT_INTERNAL_ERROR */
/* Emulate instruction failed. */
#define GVM_INTERNAL_ERROR_EMULATION 1
/* Encounter unexpected simultaneous exceptions. */
#define GVM_INTERNAL_ERROR_SIMUL_EX 2
/* Encounter unexpected vm-exit due to delivery event. */
#define GVM_INTERNAL_ERROR_DELIVERY_EV 3
/* for GVM_RUN, returned by mmap(vcpu_fd, offset=0) */
struct gvm_run {
/* in */
__u8 request_interrupt_window;
__u8 user_event_pending;
__u8 padding1[6];
/* out */
__u32 exit_reason;
__u8 ready_for_interrupt_injection;
__u8 if_flag;
__u16 flags;
/* in (pre_gvm_run), out (post_gvm_run) */
__u64 cr8;
__u64 apic_base;
union {
/* GVM_EXIT_UNKNOWN */
struct {
__u64 hardware_exit_reason;
} hw;
/* GVM_EXIT_FAIL_ENTRY */
struct {
__u64 hardware_entry_failure_reason;
} fail_entry;
/* GVM_EXIT_EXCEPTION */
struct {
__u32 exception;
__u32 error_code;
} ex;
/* GVM_EXIT_IO */
struct {
#define GVM_EXIT_IO_IN 0
#define GVM_EXIT_IO_OUT 1
__u8 direction;
__u8 size; /* bytes */
__u16 port;
__u32 count;
__u64 data_offset; /* relative to gvm_run start */
} io;
/* GVM_EXIT_DEBUG */
struct {
struct gvm_debug_exit_arch arch;
} debug;
/* GVM_EXIT_MMIO */
struct {
__u64 phys_addr;
__u8 data[8];
__u32 len;
__u8 is_write;
} mmio;
/* GVM_EXIT_HYPERCALL */
struct {
__u64 nr;
__u64 args[6];
__u64 ret;
__u32 longmode;
__u32 pad;
} hypercall;
/* GVM_EXIT_TPR_ACCESS */
struct {
__u64 rip;
__u32 is_write;
__u32 pad;
} tpr_access;
/* GVM_EXIT_INTERNAL_ERROR */
struct {
__u32 suberror;
/* Available with GVM_CAP_INTERNAL_ERROR_DATA: */
__u32 ndata;
__u64 data[16];
} internal;
/* GVM_EXIT_OSI */
struct {
__u64 gprs[32];
} osi;
/* GVM_EXIT_PAPR_HCALL */
struct {
__u64 nr;
__u64 ret;
__u64 args[9];
} papr_hcall;
/* GVM_EXIT_EPR */
struct {
__u32 epr;
} epr;
/* GVM_EXIT_SYSTEM_EVENT */
struct {
#define GVM_SYSTEM_EVENT_SHUTDOWN 1
#define GVM_SYSTEM_EVENT_RESET 2
#define GVM_SYSTEM_EVENT_CRASH 3
__u32 type;
__u64 flags;
} system_event;
/* GVM_EXIT_IOAPIC_EOI */
struct {
__u8 vector;
} eoi;
/* Fix the size of the union. */
char padding[256];
};
/*
* shared registers between gvm and userspace.
* gvm_valid_regs specifies the register classes set by the host
* gvm_dirty_regs specified the register classes dirtied by userspace
* struct gvm_sync_regs is architecture specific, as well as the
* bits for gvm_valid_regs and gvm_dirty_regs
*/
__u64 gvm_valid_regs;
__u64 gvm_dirty_regs;
union {
struct gvm_sync_regs regs;
char padding[2048];
} s;
};
/* for GVM_TRANSLATE */
struct gvm_translation {
/* in */
__u64 linear_address;
/* out */
__u64 physical_address;
__u8 valid;
__u8 writeable;
__u8 usermode;
__u8 pad[5];
};
/* for GVM_INTERRUPT */
struct gvm_interrupt {
/* in */
__u32 irq;
};
/* for GVM_GET_DIRTY_LOG */
struct gvm_dirty_log {
__u32 slot;
__u32 padding1;
union {
void *dirty_bitmap; /* one bit per page */
__u64 padding2;
};
};
/* for GVM_TPR_ACCESS_REPORTING */
struct gvm_tpr_access_ctl {
__u32 enabled;
__u32 flags;
__u32 reserved[8];
};
/* for GVM_SET_VAPIC_ADDR */
struct gvm_vapic_addr {
__u64 vapic_addr;
};
/* for GVM_SET_MP_STATE */
/* not all states are valid on all architectures */
#define GVM_MP_STATE_RUNNABLE 0
#define GVM_MP_STATE_UNINITIALIZED 1
#define GVM_MP_STATE_INIT_RECEIVED 2
#define GVM_MP_STATE_HALTED 3
#define GVM_MP_STATE_SIPI_RECEIVED 4
#define GVM_MP_STATE_STOPPED 5
#define GVM_MP_STATE_CHECK_STOP 6
#define GVM_MP_STATE_OPERATING 7
#define GVM_MP_STATE_LOAD 8
struct gvm_mp_state {
__u32 mp_state;
};
/* for GVM_SET_GUEST_DEBUG */
#define GVM_GUESTDBG_ENABLE 0x00000001
#define GVM_GUESTDBG_SINGLESTEP 0x00000002
struct gvm_guest_debug {
__u32 control;
__u32 pad;
struct gvm_guest_debug_arch arch;
};
/* for GVM_ENABLE_CAP */
struct gvm_enable_cap {
/* in */
__u32 cap;
__u32 flags;
__u64 args[4];
__u8 pad[64];
};
/*
* ioctls for /dev/gvm fds:
*/
#define GVM_GET_API_VERSION __IO(GVMIO, 0x00)
#define GVM_CREATE_VM __IO(GVMIO, 0x01) /* returns a VM fd */
#define GVM_GET_MSR_INDEX_LIST __IOWR(GVMIO, 0x02, struct gvm_msr_list)
/*
* Check if a gvm extension is available. Argument is extension number,
* return is 1 (yes) or 0 (no, sorry).
*/
#define GVM_CHECK_EXTENSION __IO(GVMIO, 0x03)
/*
* Get size for mmap(vcpu_fd)
*/
#define GVM_GET_VCPU_MMAP_SIZE __IO(GVMIO, 0x04) /* in bytes */
#define GVM_GET_SUPPORTED_CPUID __IOWR(GVMIO, 0x05, struct gvm_cpuid)
#define GVM_GET_EMULATED_CPUID __IOWR(GVMIO, 0x09, struct gvm_cpuid)
/*
* Extension capability list.
*/
#define GVM_CAP_IRQCHIP 0
#define GVM_CAP_HLT 1
#define GVM_CAP_MMU_SHADOW_CACHE_CONTROL 2
#define GVM_CAP_VAPIC 6
#define GVM_CAP_NR_VCPUS 9 /* returns recommended max vcpus per vm */
#define GVM_CAP_NR_MEMSLOTS 10 /* returns max memory slots per vm */
#define GVM_CAP_SYNC_MMU 16 /* Changes to host mmap are reflected in guest */
#define GVM_CAP_IOMMU 18
#define GVM_CAP_USER_NMI 22
#define GVM_CAP_IRQ_ROUTING 25
#define GVM_CAP_SET_BOOT_CPU_ID 34
#define GVM_CAP_SET_IDENTITY_MAP_ADDR 37
#define GVM_CAP_PCI_SEGMENT 47
#define GVM_CAP_INTR_SHADOW 49
#define GVM_CAP_ENABLE_CAP 54
#define GVM_CAP_XSAVE 55
#define GVM_CAP_XCRS 56
#define GVM_CAP_MAX_VCPUS 66 /* returns max vcpus per vm */
#define GVM_CAP_SW_TLB 69
#define GVM_CAP_SYNC_REGS 74
#define GVM_CAP_READONLY_MEM 81
#define GVM_CAP_EXT_EMUL_CPUID 95
#define GVM_CAP_IOAPIC_POLARITY_IGNORED 97
#define GVM_CAP_ENABLE_CAP_VM 98
#define GVM_CAP_VM_ATTRIBUTES 101
#define GVM_CAP_CHECK_EXTENSION_VM 105
#define GVM_CAP_DISABLE_QUIRKS 116
#define GVM_CAP_X86_SMM 117
#define GVM_CAP_MULTI_ADDRESS_SPACE 118
#define GVM_CAP_GUEST_DEBUG_HW_BPS 119
#define GVM_CAP_GUEST_DEBUG_HW_WPS 120
#define GVM_CAP_VCPU_ATTRIBUTES 127
#define GVM_CAP_MAX_VCPU_ID 128
#define GVM_CAP_X2APIC_API 129
#define GVM_CAP_MSI_DEVID 131
struct gvm_irq_routing_irqchip {
__u32 irqchip;
__u32 pin;
};
struct gvm_irq_routing_msi {
__u32 address_lo;
__u32 address_hi;
__u32 data;
union {
__u32 pad;
__u32 devid;
};
};
struct gvm_irq_routing_hv_sint {
__u32 vcpu;
__u32 sint;
};
/* gsi routing entry types */
#define GVM_IRQ_ROUTING_IRQCHIP 1
#define GVM_IRQ_ROUTING_MSI 2
#define GVM_IRQ_ROUTING_HV_SINT 4
struct gvm_irq_routing_entry {
__u32 gsi;
__u32 type;
__u32 flags;
__u32 pad;
union {
struct gvm_irq_routing_irqchip irqchip;
struct gvm_irq_routing_msi msi;
struct gvm_irq_routing_hv_sint hv_sint;
__u32 pad[8];
} u;
};
struct gvm_irq_routing {
__u32 nr;
__u32 flags;
struct gvm_irq_routing_entry entries[0];
};
/* For GVM_CAP_SW_TLB */
#define GVM_MMU_FSL_BOOKE_NOHV 0
#define GVM_MMU_FSL_BOOKE_HV 1
struct gvm_config_tlb {
__u64 params;
__u64 array;
__u32 mmu_type;
__u32 array_len;
};
struct gvm_dirty_tlb {
__u64 bitmap;
__u32 num_dirty;
};
/* Available with GVM_CAP_ONE_REG */
#define GVM_REG_ARCH_MASK 0xff00000000000000ULL
#define GVM_REG_GENERIC 0x0000000000000000ULL
/*
* Architecture specific registers are to be defined in arch headers and
* ORed with the arch identifier.
*/
#define GVM_REG_PPC 0x1000000000000000ULL
#define GVM_REG_X86 0x2000000000000000ULL
#define GVM_REG_IA64 0x3000000000000000ULL
#define GVM_REG_ARM 0x4000000000000000ULL
#define GVM_REG_S390 0x5000000000000000ULL
#define GVM_REG_ARM64 0x6000000000000000ULL
#define GVM_REG_MIPS 0x7000000000000000ULL
#define GVM_REG_SIZE_SHIFT 52
#define GVM_REG_SIZE_MASK 0x00f0000000000000ULL
#define GVM_REG_SIZE_U8 0x0000000000000000ULL
#define GVM_REG_SIZE_U16 0x0010000000000000ULL
#define GVM_REG_SIZE_U32 0x0020000000000000ULL
#define GVM_REG_SIZE_U64 0x0030000000000000ULL
#define GVM_REG_SIZE_U128 0x0040000000000000ULL
#define GVM_REG_SIZE_U256 0x0050000000000000ULL
#define GVM_REG_SIZE_U512 0x0060000000000000ULL
#define GVM_REG_SIZE_U1024 0x0070000000000000ULL
struct gvm_reg_list {
__u64 n; /* number of regs */
__u64 reg[0];
};
struct gvm_one_reg {
__u64 id;
__u64 addr;
};
#define GVM_MSI_VALID_DEVID (1U << 0)
struct gvm_msi {
__u32 address_lo;
__u32 address_hi;
__u32 data;
__u32 flags;
__u32 devid;
__u8 pad[12];
};
/*
* ioctls for VM fds
*/
#define GVM_SET_MEMORY_REGION __IOW(GVMIO, 0x40, struct gvm_memory_region)
/*
* GVM_CREATE_VCPU receives as a parameter the vcpu slot, and returns
* a vcpu fd.
*/
#define GVM_CREATE_VCPU __IO(GVMIO, 0x41)
#define GVM_GET_DIRTY_LOG __IOW(GVMIO, 0x42, struct gvm_dirty_log)
/* GVM_SET_MEMORY_ALIAS is obsolete: */
#define GVM_SET_MEMORY_ALIAS __IOW(GVMIO, 0x43, struct gvm_memory_alias)
#define GVM_SET_NR_MMU_PAGES __IO(GVMIO, 0x44)
#define GVM_GET_NR_MMU_PAGES __IO(GVMIO, 0x45)
#define GVM_SET_USER_MEMORY_REGION __IOW(GVMIO, 0x46, \
struct gvm_userspace_memory_region)
#define GVM_SET_TSS_ADDR __IO(GVMIO, 0x47)
#define GVM_SET_IDENTITY_MAP_ADDR __IOW(GVMIO, 0x48, __u64)
#define GVM_KICK_VCPU __IO(GVMIO, 0x49)
/* Device model IOC */
#define GVM_CREATE_IRQCHIP __IO(GVMIO, 0x60)
#define GVM_GET_IRQCHIP __IOWR(GVMIO, 0x62, struct gvm_irqchip)
#define GVM_SET_IRQCHIP __IOR(GVMIO, 0x63, struct gvm_irqchip)
#define GVM_IRQ_LINE_STATUS __IOWR(GVMIO, 0x67, struct gvm_irq_level)
#define GVM_SET_GSI_ROUTING __IOW(GVMIO, 0x6a, struct gvm_irq_routing)
/* deprecated, replaced by GVM_ASSIGN_DEV_IRQ */
#define GVM_ASSIGN_IRQ __GVM_DEPRECATED_VM_R_0x70
#define GVM_ASSIGN_DEV_IRQ __IOW(GVMIO, 0x70, struct gvm_assigned_irq)
#define GVM_REINJECT_CONTROL __IO(GVMIO, 0x71)
#define GVM_SET_BOOT_CPU_ID __IO(GVMIO, 0x78)
/*
* ioctls for vcpu fds
*/
#define GVM_RUN __IO(GVMIO, 0x80)
#define GVM_VCPU_MMAP __IO(GVMIO, 0x87)
#define GVM_GET_REGS __IOR(GVMIO, 0x81, struct gvm_regs)
#define GVM_SET_REGS __IOW(GVMIO, 0x82, struct gvm_regs)
#define GVM_GET_SREGS __IOR(GVMIO, 0x83, struct gvm_sregs)
#define GVM_SET_SREGS __IOW(GVMIO, 0x84, struct gvm_sregs)
#define GVM_TRANSLATE __IOWR(GVMIO, 0x85, struct gvm_translation)
#define GVM_INTERRUPT __IOW(GVMIO, 0x86, struct gvm_interrupt)
#define GVM_GET_MSRS __IOWR(GVMIO, 0x88, struct gvm_msrs)
#define GVM_SET_MSRS __IOW(GVMIO, 0x89, struct gvm_msrs)
#define GVM_GET_FPU __IOR(GVMIO, 0x8c, struct gvm_fpu)
#define GVM_SET_FPU __IOW(GVMIO, 0x8d, struct gvm_fpu)
#define GVM_GET_LAPIC __IOR(GVMIO, 0x8e, struct gvm_lapic_state)
#define GVM_SET_LAPIC __IOW(GVMIO, 0x8f, struct gvm_lapic_state)
#define GVM_SET_CPUID __IOW(GVMIO, 0x90, struct gvm_cpuid)
#define GVM_GET_CPUID __IOWR(GVMIO, 0x91, struct gvm_cpuid)
/* Available with GVM_CAP_VAPIC */
#define GVM_TPR_ACCESS_REPORTING __IOWR(GVMIO, 0x92, struct gvm_tpr_access_ctl)
/* Available with GVM_CAP_VAPIC */
#define GVM_SET_VAPIC_ADDR __IOW(GVMIO, 0x93, struct gvm_vapic_addr)
#define GVM_GET_MP_STATE __IOR(GVMIO, 0x98, struct gvm_mp_state)
#define GVM_SET_MP_STATE __IOW(GVMIO, 0x99, struct gvm_mp_state)
/* Available with GVM_CAP_USER_NMI */
#define GVM_NMI __IO(GVMIO, 0x9a)
/* Available with GVM_CAP_SET_GUEST_DEBUG */
#define GVM_SET_GUEST_DEBUG __IOW(GVMIO, 0x9b, struct gvm_guest_debug)
/* Available with GVM_CAP_VCPU_EVENTS */
#define GVM_GET_VCPU_EVENTS __IOR(GVMIO, 0x9f, struct gvm_vcpu_events)
#define GVM_SET_VCPU_EVENTS __IOW(GVMIO, 0xa0, struct gvm_vcpu_events)
/* Available with GVM_CAP_DEBUGREGS */
#define GVM_GET_DEBUGREGS __IOR(GVMIO, 0xa1, struct gvm_debugregs)
#define GVM_SET_DEBUGREGS __IOW(GVMIO, 0xa2, struct gvm_debugregs)
/*
* vcpu version available with GVM_ENABLE_CAP
* vm version available with GVM_CAP_ENABLE_CAP_VM
*/
#define GVM_ENABLE_CAP __IOW(GVMIO, 0xa3, struct gvm_enable_cap)
/* Available with GVM_CAP_XSAVE */
#define GVM_GET_XSAVE __IOR(GVMIO, 0xa4, struct gvm_xsave)
#define GVM_SET_XSAVE __IOW(GVMIO, 0xa5, struct gvm_xsave)
/* Available with GVM_CAP_XCRS */
#define GVM_GET_XCRS __IOR(GVMIO, 0xa6, struct gvm_xcrs)
#define GVM_SET_XCRS __IOW(GVMIO, 0xa7, struct gvm_xcrs)
/* Available with GVM_CAP_SW_TLB */
#define GVM_DIRTY_TLB __IOW(GVMIO, 0xaa, struct gvm_dirty_tlb)
/* Available with GVM_CAP_X86_SMM */
#define GVM_SMI __IO(GVMIO, 0xb7)
#define GVM_X2APIC_API_USE_32BIT_IDS (1ULL << 0)
#define GVM_X2APIC_API_DISABLE_BROADCAST_QUIRK (1ULL << 1)
#endif /*GVM_INTERFACE_H */
================================================
FILE: gvm/gvm.c
================================================
#include "gvm.h"
#include "../krnl386/kernel16_private.h"
#include "wownt32.h"
BOOL initflag;
UINT8 *mem;
#define KRNL386 "krnl386.exe16"
BOOL is_single_step = FALSE;
DWORD WINAPI panic_msgbox(LPVOID data)
{
MessageBoxA(NULL, (LPCSTR)data, "GVM Hypervisor error", MB_OK | MB_ICONERROR);
HeapFree(GetProcessHeap(), 0, data);
return 0;
}
#define PANIC_HRESULT(msg, hresult) panic_hresult(msg, hresult, __FUNCTION__, __LINE__)
#ifdef _MSC_VER
#define PANIC(msg, ...) panic("%s:%d\n" msg, __FUNCTION__, __LINE__, __VA_ARGS__)
#else
#define PANIC(msg, ...) panic("%s:%d\n" msg, __FUNCTION__, __LINE__ __VA_OPT__(,) __VA_ARGS__)
#endif
/* _Noreturn */
void panic(const char *msg, ...)
{
LPSTR buffer = HeapAlloc(GetProcessHeap(), 0, 512);
DWORD threadId;
va_list arg;
va_start(arg, msg);
vsnprintf(buffer, 512, msg, arg);
va_end(arg);
HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)panic_msgbox, buffer, 0, &threadId);
WaitForSingleObject(hThread, INFINITE);
ExitThread(1);
return;
}
/* _Noreturn */
void panic_hresult(const char *msg, HRESULT result, const char *func, int line)
{
LPSTR buffer = HeapAlloc(GetProcessHeap(), 0, 512);
DWORD threadId;
LPSTR err_str = NULL;
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, result, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&err_str, 0, NULL);
snprintf(buffer, 512, "%s:%d\n%s HRESULT=%s(%08x)", func, line, msg, err_str, result);
LocalFree(err_str);
HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)panic_msgbox, buffer, 0, &threadId);
WaitForSingleObject(hThread, INFINITE);
ExitThread(1);
return;
}
static HMODULE krnl386 = 0;
PVOID dynamic_setWOW32Reserved(PVOID w)
{
static PVOID(*setWOW32Reserved)(PVOID);
if (!setWOW32Reserved)
{
if (!krnl386)
krnl386 = LoadLibraryA(KRNL386);
setWOW32Reserved = (PVOID(*)(PVOID))GetProcAddress(krnl386, "setWOW32Reserved");
}
return setWOW32Reserved(w);
}
PVOID dynamic_getWOW32Reserved()
{
static PVOID(*getWOW32Reserved)();
if (!getWOW32Reserved)
{
if (!krnl386)
krnl386 = LoadLibraryA(KRNL386);
getWOW32Reserved = (PVOID(*)())GetProcAddress(krnl386, "getWOW32Reserved");
}
return getWOW32Reserved();
}
WINE_VM86_TEB_INFO *dynamic_getGdiTebBatch()
{
static WINE_VM86_TEB_INFO*(*getGdiTebBatch)();
if (!getGdiTebBatch)
{
if (!krnl386)
krnl386 = LoadLibraryA(KRNL386);
getGdiTebBatch = (WINE_VM86_TEB_INFO*(*)())GetProcAddress(krnl386, "getGdiTebBatch");
}
return getGdiTebBatch();
}
void dynamic__wine_call_int_handler(CONTEXT *context, BYTE intnum)
{
static void(*__wine_call_int_handler)(CONTEXT *context, BYTE intnum);
if (!__wine_call_int_handler)
{
if (!krnl386)
krnl386 = LoadLibraryA(KRNL386);
__wine_call_int_handler = (void(*)(CONTEXT *context, BYTE intnum))GetProcAddress(krnl386, "__wine_call_int_handler");
}
__wine_call_int_handler(context, intnum);
}
/***********************************************************************
* SELECTOR_SetEntries
*
* Set the LDT entries for an array of selectors.
*/
static BOOL SELECTOR_SetEntries(WORD sel, const void *base, DWORD size, unsigned char flags)
{
LDT_ENTRY entry;
WORD i, count;
wine_ldt_set_base(&entry, base);
wine_ldt_set_limit(&entry, size - 1);
wine_ldt_set_flags(&entry, flags);
count = (size + 0xffff) / 0x10000;
for (i = 0; i < count; i++)
{
if (wine_ldt_set_entry(sel + (i << 3), &entry) < 0) return FALSE;
wine_ldt_set_base(&entry, (char*)wine_ldt_get_base(&entry) + 0x10000);
/* yep, Windows sets limit like that, not 64K sel units */
wine_ldt_set_limit(&entry, wine_ldt_get_limit(&entry) - 0x10000);
}
return TRUE;
}
void wine_ldt_free_entries(unsigned short sel, int count);
/***********************************************************************
* SELECTOR_AllocBlock
*
* Allocate selectors for a block of linear memory.
*/
WORD SELECTOR_AllocBlock(const void *base, DWORD size, unsigned char flags)
{
WORD sel, count;
if (!size) return 0;
count = (size + 0xffff) / 0x10000;
if ((sel = wine_ldt_alloc_entries(count)))
{
if (SELECTOR_SetEntries(sel, base, size, flags)) return sel;
wine_ldt_free_entries(sel, count);
sel = 0;
}
return sel;
}
__declspec(dllimport) LDT_ENTRY wine_ldt[8192];
LDT_ENTRY gdt[];
void load_seg(struct gvm_segment *segment, WORD sel)
{
const LDT_ENTRY *entry = (sel & 0x4 || (sel >> 3) >= 512) ? wine_ldt : gdt;
segment->selector = sel;
segment->base = (UINT64)wine_ldt_get_base(entry + (sel >> 3));
segment->limit = (UINT64)wine_ldt_get_limit(entry + (sel >> 3));
segment->type = entry[sel >> 3].HighWord.Bits.Type & 15;
segment->s = entry[sel >> 3].HighWord.Bits.Type >> 4;
segment->dpl = entry[sel >> 3].HighWord.Bits.Dpl;
segment->present = entry[sel >> 3].HighWord.Bits.Pres;
segment->avl = entry[sel >> 3].HighWord.Bits.Sys;
segment->l = entry[sel >> 3].HighWord.Bits.Reserved_0;
segment->db = entry[sel >> 3].HighWord.Bits.Default_Big;
segment->g = entry[sel >> 3].HighWord.Bits.Granularity;
}
void set_eflags(struct gvm_vcpu_state *state, DWORD eflags)
{
*(uint32*)&state->regs.rflags = eflags | 2 | 0x3000 | (is_single_step ? 0x100 : 0) | 0x200;
}
void load_context_to_state(CONTEXT *context, vcpu_state *state)
{
load_seg(get_gs(state), (WORD)context->SegGs);
load_seg(get_fs(state), (WORD)context->SegFs);
load_seg(get_es(state), (WORD)context->SegEs);
load_seg(get_ds(state), (WORD)context->SegDs);
load_seg(get_cs(state), (WORD)context->SegCs);
load_seg(get_ss(state), (WORD)context->SegSs);
set_edi(state, context->Edi);
set_esi(state, context->Esi);
set_ebx(state, context->Ebx);
set_edx(state, context->Edx);
set_ecx(state, context->Ecx);
set_eax(state, context->Eax);
set_ebp(state, context->Ebp);
set_eip(state, context->Eip);
set_eflags(state, context->EFlags);
set_esp(state, context->Esp);
}
void save_context_from_state(CONTEXT *context, vcpu_state *state)
{
context->SegGs = get_seg_selector(get_gs(state));
context->SegFs = get_seg_selector(get_fs(state));
context->SegEs = get_seg_selector(get_es(state));
context->SegDs = get_seg_selector(get_ds(state));
context->SegCs = get_seg_selector(get_cs(state));
context->SegSs = get_seg_selector(get_ss(state));
context->Edi = get_edi(state);
context->Esi = get_esi(state);
context->Ebx = get_ebx(state);
context->Edx = get_edx(state);
context->Ecx = get_ecx(state);
context->Eax = get_eax(state);
context->Ebp = get_ebp(state);
context->Eip = get_eip(state);
context->EFlags = get_eflags(state) & ~2;
context->Esp = get_esp(state);
dynamic_setWOW32Reserved((PVOID)(get_seg_selector(get_ss(state)) << 16 | get_sp(state)));
}
#include
typedef enum
{
INT_GATE_TASK = 5,
INT_GATE_INT16 = 6,
INT_GATE_TRAP16 = 7,
INT_GATE_INT32 = 0xE,
INT_GATE_TRAP32 = 0xF,
} interrupt_gate_type;
typedef struct
{
WORD offset_low;
WORD selector;
BYTE reserved;
union
{
struct
{
BYTE type : 4 /* INT_GATE_TASK */, S : 1, DPL : 2, P : 1;
};
BYTE data;
};
WORD offset_high;
} interrupt_gate;
_STATIC_ASSERT(sizeof(interrupt_gate) == 8);
#include
LPVOID trap_int;
#ifdef _MSC_VER
__declspec(align(4096))
#endif
interrupt_gate idt[256];
#ifdef __GNUC__
__attribute__ ((aligned(4096)))
#endif
;
#ifdef _MSC_VER
__declspec(align(4096))
#endif
LDT_ENTRY gdt[512] = { 0 };
#ifdef __GNUC__
__attribute__ ((aligned(4096)))
#endif
;
WORD seg_cs;
WORD seg_ds;
typedef DWORD (*DOSVM_inport_t)(int port, int size);
typedef void (*DOSVM_outport_t)(int port, int size, DWORD value);
DOSVM_inport_t DOSVM_inport;
DOSVM_outport_t DOSVM_outport;
HANDLE inject_event;
CRITICAL_SECTION inject_crit_section;
typedef VOID (WINAPI *GetpWin16Lock_t)(SYSLEVEL **lock);
GetpWin16Lock_t pGetpWin16Lock;
SYSLEVEL *win16_syslevel;
typedef BOOL(WINAPI *WOWCallback16Ex_t)(DWORD vpfn16, DWORD dwFlags,
DWORD cbArgs, LPVOID pArgs, LPDWORD pdwRetCode);
WOWCallback16Ex_t pWOWCallback16Ex;
typedef BOOL (WINAPI *vm_inject_t)(DWORD vpfn16, DWORD dwFlags,
DWORD cbArgs, LPVOID pArgs, LPDWORD pdwRetCode);
BOOL WINAPI vm_inject(DWORD vpfn16, DWORD dwFlags,
DWORD cbArgs, LPVOID pArgs, LPDWORD pdwRetCode);
__declspec(dllexport) DWORD wine_call_to_16_vm86(DWORD target, DWORD cbArgs, PEXCEPTION_HANDLER handler,
void(*from16_reg)(void),
LONG(*__wine_call_from_16)(void),
int(*relay_call_from_16)(void *entry_point, unsigned char *args16, CONTEXT *context),
void(*__wine_call_to_16_ret)(void),
int dasm,
BOOL vm86,
void *memory_base,
pm_interrupt_handler pih);
static CRITICAL_SECTION running_critical_section;
static HANDLE hDevice;
static HANDLE hVM;
#ifdef _MSC_VER
__declspec(thread)
#elif defined(__GUNC__)
__thread
#else
_Thread_local
#endif
HANDLE hVCPU;
static void init_vcpu();
static HANDLE get_vcpu_handle()
{
if (!hVCPU)
{
init_vcpu();
}
return hVCPU;
}
#ifdef _MSC_VER
__declspec(thread)
#elif defined(__GUNC__)
__thread
#else
_Thread_local
#endif
struct gvm_run *gvm_run;
static void get_vcpu_regs(vcpu_state *state)
{
if (!DeviceIoControl(get_vcpu_handle(), GVM_GET_REGS, NULL, 0, &state->regs, sizeof(state->regs), NULL, NULL))
{
PANIC("GVM_GET_REGS");
return;
}
if (!DeviceIoControl(get_vcpu_handle(), GVM_GET_SREGS, NULL, 0, &state->sregs, sizeof(state->sregs), NULL, NULL))
{
PANIC("GVM_GET_SREGS");
return;
}
}
static void set_vcpu_regs(vcpu_state *state)
{
if (!DeviceIoControl(get_vcpu_handle(), GVM_SET_REGS, &state->regs, sizeof(state->regs), NULL, 0, NULL, NULL))
{
PANIC("GVM_SET_REGS");
return;
}
if (!DeviceIoControl(get_vcpu_handle(), GVM_SET_SREGS, &state->sregs, sizeof(state->sregs), NULL, 0, NULL, NULL))
{
PANIC("GVM_SET_SREGS");
return;
}
}
unsigned long vcpu_id = 0;
static void init_vcpu()
{
struct gvm_vcpu_state state;
LONGLONG handle64;
if (!DeviceIoControl(hVM, GVM_CREATE_VCPU, &vcpu_id, sizeof(vcpu_id), &handle64, sizeof(handle64), NULL, NULL))
{
PANIC("failed to create vcpu");
return;
}
InterlockedAdd(&vcpu_id, 1);
hVCPU = (HANDLE)handle64;
if (!DeviceIoControl(get_vcpu_handle(), GVM_VCPU_MMAP, NULL, 0, &handle64, sizeof(handle64), NULL, NULL))
{
PANIC("GVM_VCPU_MMAP");
return;
}
gvm_run = (struct gvm_run*)handle64;
get_vcpu_regs(&state);
/* setup initial states */
state.sregs.gdt.base = (UINT64)gdt;
state.sregs.gdt.limit = 0x7ff;
state.sregs.ldt.selector = 0x18;
state.sregs.ldt.base = (UINT64)&wine_ldt[0];
state.sregs.ldt.limit = 65535;
UINT32 *tss = (UINT32 *)gdt + 0x200;
state.sregs.tr.selector = 0x18;
state.sregs.tr.base = (UINT64)tss;
state.sregs.tr.limit = 0x64;
state.sregs.tr.type = 11;
state.sregs.tr.present = 1;
state.sregs.idt.limit = 0x8 * 256 - 1;
state.sregs.idt.base = (SIZE_T)&idt[0];
state.sregs.cr0 |= 1;
state.regs.rflags |= 0x200;
set_vcpu_regs(&state);
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
{
if (fdwReason != DLL_THREAD_DETACH)
{
return TRUE;
}
if (hVCPU)
{
CloseHandle(hVCPU);
hVCPU = NULL;
gvm_run = NULL;
}
return TRUE;
}
BOOL init_vm86(BOOL vm86)
{
int type = 0;
LONGLONG handle64;
InitializeCriticalSection(&running_critical_section);
#ifdef _MSC_VER
__asm
{
mov seg_cs, cs
mov seg_ds, ds
}
#else
seg_cs = wine_get_cs();
seg_ds = wine_get_ds();
#endif
hDevice = CreateFileA("\\\\.\\gvm", GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (!hDevice)
{
PANIC("failed to open gvm");
return FALSE;
}
if (!DeviceIoControl(hDevice, GVM_CREATE_VM, &type, sizeof(type), &handle64, sizeof(handle64), NULL, NULL))
{
PANIC("failed to create vm");
return FALSE;
}
hVM = (HANDLE)handle64;
trap_int = VirtualAlloc(NULL, 0x10000, MEM_COMMIT, PAGE_READWRITE);
DWORD trap_addr = (DWORD)trap_int;
gdt[1].BaseLow = trap_addr & 0xffff;
gdt[1].HighWord.Bytes.BaseMid = (trap_addr >> 16) & 0xff;
gdt[1].HighWord.Bytes.BaseHi = (trap_addr >> 24) & 0xff;
gdt[1].LimitLow = 0xffff;
gdt[1].HighWord.Bytes.Flags1 = 0x9b;
gdt[1].HighWord.Bytes.Flags2 = 0x40;
gdt[2].BaseLow = trap_addr & 0xffff;
gdt[2].HighWord.Bytes.BaseMid = (trap_addr >> 16) & 0xff;
gdt[2].HighWord.Bytes.BaseHi = (trap_addr >> 24) & 0xff;
gdt[2].LimitLow = 0xffff;
gdt[2].HighWord.Bytes.Flags1 = 0x93;
gdt[2].HighWord.Bytes.Flags2 = 0x40;
GetThreadSelectorEntry(GetCurrentThread(), seg_cs, gdt + (seg_cs >> 3));
GetThreadSelectorEntry(GetCurrentThread(), seg_ds, gdt + (seg_ds >> 3));
UINT32 *tss = (UINT32 *)gdt + 0x200;
tss[1] = 0x10000; // SP0
tss[2] = 0x10; // SS0
for (int i = 0; i < 256; i++)
{
idt[i].DPL = 3;
idt[i].type = INT_GATE_INT32;
idt[i].selector = 0x0b;
idt[i].P = 1;
idt[i].offset_low = i;
idt[i].offset_high = 0;
}
memset(trap_int, 0xF4, 256); /* hlt */
((char *)trap_int)[256] = 0xcf; /* iret */
if (!krnl386)
krnl386 = LoadLibraryA(KRNL386);
pWOWCallback16Ex = (WOWCallback16Ex_t)GetProcAddress(krnl386, "K32WOWCallback16Ex");
void(WINAPI *set_vm_inject_cb)(vm_inject_t) = (void(WINAPI *)(vm_inject_t))GetProcAddress(krnl386, "set_vm_inject_cb");
set_vm_inject_cb(vm_inject);
inject_event = CreateEventW(NULL, TRUE, FALSE, NULL);
InitializeCriticalSection(&inject_crit_section);
pGetpWin16Lock = (GetpWin16Lock_t)GetProcAddress(krnl386, "GetpWin16Lock");
pGetpWin16Lock(&win16_syslevel);
DOSVM_inport = (DOSVM_inport_t)GetProcAddress(krnl386, "DOSVM_inport");
DOSVM_outport = (DOSVM_outport_t)GetProcAddress(krnl386, "DOSVM_outport");
return TRUE;
}
void PUSH16(struct gvm_vcpu_state *state, WORD val)
{
if (state->sregs.ss.db)
{
*(uint32*)&state->regs.rsp -= 2;
LPWORD stack = (LPWORD)(state->sregs.ss.base + (uint32)state->regs.rsp);
*stack = val;
}
else
{
*(uint16*)&state->regs.rsp -= 2;
LPWORD stack = (LPWORD)(state->sregs.ss.base + (uint16)state->regs.rsp);
*stack = val;
}
}
void PUSH32(struct gvm_vcpu_state *state, DWORD val)
{
if (state->sregs.ss.db)
{
*(uint32*)&state->regs.rsp -= 4;
LPDWORD stack = (LPDWORD)(state->sregs.ss.base + (uint32)state->regs.rsp);
*stack = val;
}
else
{
*(uint16*)&state->regs.rsp -= 4;
LPDWORD stack = (LPDWORD)(state->sregs.ss.base + (uint16)state->regs.rsp);
*stack = val;
}
}
WORD POP16(struct gvm_vcpu_state *state)
{
if (state->sregs.ss.db)
{
LPWORD stack = (LPWORD)(state->sregs.ss.base + (uint32)state->regs.rsp);
*(uint32*)&state->regs.rsp += 2;
return *stack;
}
else
{
LPWORD stack = (LPWORD)(state->sregs.ss.base + (uint16)state->regs.rsp);
*(uint16*)&state->regs.rsp += 2;
return *stack;
}
}
DWORD POP32(struct gvm_vcpu_state *state)
{
if (state->sregs.ss.db)
{
LPDWORD stack = (LPDWORD)(state->sregs.ss.base + (uint32)state->regs.rsp);
*(uint32*)&state->regs.rsp += 4;
return *stack;
}
else
{
LPDWORD stack = (LPDWORD)(state->sregs.ss.base + (uint16)state->regs.rsp);
*(uint16*)&state->regs.rsp += 4;
return *stack;
}
}
WORD PEEK16(struct gvm_vcpu_state *state, int i)
{
if (state->sregs.ss.db)
{
LPWORD stack = (LPWORD)(state->sregs.ss.base + (uint32)state->regs.rsp);
return stack[i];
}
else
{
LPWORD stack = (LPWORD)(state->sregs.ss.base + (uint16)state->regs.rsp);
return stack[i];
}
}
DWORD PEEK32(struct gvm_vcpu_state *state, int i)
{
if (state->sregs.ss.db)
{
LPDWORD stack = (LPDWORD)(state->sregs.ss.base + (uint32)state->regs.rsp);
return stack[i];
}
else
{
LPDWORD stack = (LPDWORD)(state->sregs.ss.base + (uint16)state->regs.rsp);
return stack[i];
}
}
void relay(LPVOID relay_func, BOOL reg, vcpu_state *state, DWORD ret_addr, DWORD cbArgs, PEXCEPTION_HANDLER handler, DWORD old_frame16)
{
unsigned char *stack1 = (unsigned char*)(get_seg_base(get_ss(state))+ get_sp(state));
unsigned char *stack = stack1;
/*
* (sp+24) word first 16-bit arg
* (sp+22) word cs
* (sp+20) word ip
* (sp+18) word bp
* (sp+14) long 32-bit entry point (reused for Win16 mutex recursion count)
* (sp+12) word ip of actual entry point (necessary for relay debugging)
* (sp+8) long relay (argument conversion) function entry point
* (sp+4) long cs of 16-bit entry point
* (sp) long ip of 16-bit entry point
*/
DWORD ip = *(DWORD*)stack;
stack += sizeof(DWORD);
DWORD cs = *(DWORD*)stack;
stack += sizeof(DWORD);
DWORD relay = *(DWORD*)stack;
stack += sizeof(DWORD);
WORD ip2 = *(WORD*)stack;
stack += sizeof(WORD);
DWORD entry = *(DWORD*)stack;
//for debug
void *entryf = (void*)entry;
stack += sizeof(DWORD);
WORD bp = *(WORD*)stack;
stack += sizeof(WORD);
WORD ip19 = *(WORD*)stack;
stack += sizeof(WORD);
WORD cs16 = *(WORD*)stack;
stack += sizeof(WORD);
WORD *args = (WORD*)stack;
set_eip(state, ip);
load_seg(get_cs(state), (WORD)cs);
#include
/* 16-bit stack layout after __wine_call_from_16() */
typedef struct _STACK16FRAME
{
struct STACK32FRAME *frame32; /* 00 32-bit frame from last CallTo16() */
DWORD edx; /* 04 saved registers */
DWORD ecx; /* 08 */
DWORD ebp; /* 0c */
WORD ds; /* 10 */
WORD es; /* 12 */
WORD fs; /* 14 */
WORD gs; /* 16 */
DWORD callfrom_ip; /* 18 callfrom tail IP */
DWORD module_cs; /* 1c module code segment */
DWORD relay; /* 20 relay function address */
WORD entry_ip; /* 22 entry point IP */
DWORD entry_point; /* 26 API entry point to call, reused as mutex count */
WORD bp; /* 2a 16-bit stack frame chain */
WORD ip; /* 2c return address */
WORD cs; /* 2e */
} STACK16FRAME;
#include
CONTEXT context;
STACK32FRAME dummy_stack32 = { 0 };
dummy_stack32.retaddr = ret_addr;
dummy_stack32.nb_args = cbArgs;
dummy_stack32.frame.Handler = handler;
DWORD osp = get_esp(state);
PUSH16(state, get_seg_selector(get_gs(state)));
PUSH16(state, get_seg_selector(get_fs(state)));
PUSH16(state, get_seg_selector(get_es(state)));
PUSH16(state, get_seg_selector(get_ds(state)));
PUSH32(state, get_ebp(state));
PUSH32(state, get_ecx(state));
PUSH32(state, get_edx(state));
PUSH32(state, osp);
save_context_from_state(&context, state);
STACK16FRAME *oa = (STACK16FRAME*)wine_ldt_get_ptr((WORD)context.SegSs, context.Esp);
DWORD ooo = (WORD)context.Esp;
int off = 0;
if (reg)
{
context.Esp = osp + (SIZE_T)stack - (SIZE_T)stack1 - 4;
off = ooo - context.Esp;
context.Ebp = (context.Ebp & ~0xffff) | bp;
context.Eip = ip19;
context.SegCs = cs16;
}
int fret;
LPVOID old;
PCONTEXT pctx = NULL;
#if _MSC_VER
__asm
{
mov old, esp
push cbArgs
push old /* target(esp) */
push retaddr /* retaddr */
push ebp
push ebx
push esi
push edi
push old_frame16 /* frame16 */
/* set up exception handler */
push handler
mov eax, fs:[0]
push eax
mov dummy_stack32.frame.Next, eax
mov fs : [0], esp
push cs
push 0
mov eax, [oa]
mov[eax], esp
lea eax, [context]
push eax
push args
push entry
call relay_func
add esp, 12 + 8
mov fret, eax
pop dword ptr fs : [0]
pop eax
jmp skip
retaddr :
mov pctx, ecx
skip:
mov esp, old
}
#else
fret = ((int(*)(void *entry_point, unsigned char *args16, CONTEXT *context))relay_func)((void*)entry, (unsigned char*)args, &context);
#endif
if (!reg)
{
set_eax(state, fret);
}
if (pctx)
{
/* Throw16 */
context = *pctx;
reg = TRUE;
}
if (!reg)
{
set_eax(state, fret);
context.SegSs = ((size_t)dynamic_getWOW32Reserved() >> 16) & 0xFFFF;
context.Esp = ((size_t)dynamic_getWOW32Reserved()) & 0xFFFF;
oa = (STACK16FRAME*)wine_ldt_get_ptr(context.SegSs, context.Esp);
}
else
{
oa = (STACK16FRAME*)wine_ldt_get_ptr(context.SegSs, context.Esp + off);
}
if (reg)
set_eax(state, (DWORD)context.Eax);
set_ecx(state, reg ? (DWORD)context.Ecx : (DWORD)oa->ecx);
if (reg)
set_edx(state, (DWORD)context.Edx);
else
set_edx(state, (DWORD)oa->edx);
set_ebx(state, (DWORD)context.Ebx);
set_esp(state, (DWORD)context.Esp);
set_ebp(state, (DWORD)context.Ebp);
set_esi(state, (DWORD)context.Esi);
set_edi(state, (DWORD)context.Edi);
load_seg(get_es(state), reg ? (WORD)context.SegEs : (WORD)oa->es);
load_seg(get_ss(state), (WORD)context.SegSs);
load_seg(get_ds(state), reg ? (WORD)context.SegDs : (WORD)oa->ds);
//ES, CS, SS, DS, FS, GS
/* Some programs expect that gs is not a valid selector! */
/* Some programs expect that fs is not a valid selector! */
/* win16 sets 0? */
load_seg(get_fs(state), 0);
load_seg(get_gs(state), 0);
if (reg)
{
if (!(ip19 != context.Eip || cs16 != context.SegCs))
{
context.Eip = oa->callfrom_ip;
context.SegCs = oa->module_cs;
}
else
{
/* CS:IP changed! */
context.Eip = context.Eip;
}
set_esp(state, context.Esp);
set_ebp(state, context.Ebp);
}
else
{
set_sp(state, context.Esp + 0x2c);
set_bp(state, bp);
}
set_eflags(state, context.EFlags);
set_eip(state, context.Eip);
load_seg(get_cs(state), (WORD)context.SegCs);
}
LPBYTE get_base_addr(WORD sel)
{
return wine_ldt_get_base(wine_ldt + (sel >> 3));
}
typedef int disassemble_debug_t(char *buffer, UINT8 *oprom, BOOL op_size, UINT64 eip);
static disassemble_debug_t *disassemble_debug;
static void trace(vcpu_state *state, uint16 cs, uint32 eip, uint16 ss, uint32 esp, uint32 eflags)
{
char buf[512];
UINT8 *d = get_base_addr(cs) + eip;
if (!disassemble_debug)
{
disassemble_debug = (disassemble_debug_t*)GetProcAddress(LoadLibraryA("vm86.dll"), "disassemble_debug");
}
int len = disassemble_debug(buf, d, (wine_ldt_get_flags(wine_ldt + (cs >> 3)) & WINE_LDT_FLAGS_32BIT) == WINE_LDT_FLAGS_32BIT, eip);
int i;
fprintf(stderr, "%04x:%04x\t", cs, eip);
for (i = 0; i < len; i++)
{
fprintf(stderr, "%02x", d[i]);
}
fprintf(stderr, "\t%s\n", buf);
eflags &= ~2;
eflags &= ~0x100;
if (get_seg_selector(get_fs(state)) || get_seg_selector(get_gs(state)))
{
fprintf(stderr,
"EAX:%04X,ECX:%04X,EDX:%04X,EBX:%04X,"
"ESP:%04X,EBP:%04X,ESI:%04X,EDI:%04X,"
"ES:%04X,CS:%04X,SS:%04X,DS:%04X,FS:%04x,GS:%04x,"
"IP:%04X,stack:%08X,"
"EFLAGS:%08X"
"\n",
get_eax(state), get_ecx(state), get_edx(state), get_ebx(state),
esp, get_ebp(state), get_esi(state), get_edi(state),
get_seg_selector(get_es(state)), cs, ss, get_seg_selector(get_ds(state)), get_seg_selector(get_fs(state)), get_seg_selector(get_gs(state)),
eip, *(LPDWORD)(get_base_addr(ss) + esp),
eflags
);
}
else
{
fprintf(stderr,
"EAX:%04X,ECX:%04X,EDX:%04X,EBX:%04X,"
"ESP:%04X,EBP:%04X,ESI:%04X,EDI:%04X,"
"ES:%04X,CS:%04X,SS:%04X,DS:%04X,"
"IP:%04X,stack:%08X,"
"EFLAGS:%08X"
"\n",
get_eax(state), get_ecx(state), get_edx(state), get_ebx(state),
esp, get_ebp(state), get_esi(state), get_edi(state),
get_seg_selector(get_es(state)), cs, ss, get_seg_selector(get_ds(state)),
eip, *(LPDWORD)(get_base_addr(ss) + esp),
eflags
);
}
}
BOOL has_x86_exception_err(WORD num)
{
switch (num)
{
case 0:case 1:case 2:case 3:case 4:case 5:case 6:case 7:
return FALSE;
case 8:
return TRUE;
case 9:
return FALSE;
case 10:case 11:case 12:case 13:case 14:
return TRUE;
case 15:case 16:
return FALSE;
case 17:
return TRUE;
case 18:case 19:case 20:case 21:case 22:case 23:case 24:case 25:case 26:case 27:case 28:case 29:
return FALSE;
case 30:
return TRUE;
case 31:
return FALSE;
}
return FALSE;
}
volatile struct
{
BOOL inject;
DWORD vpfn16;
DWORD dwFlags;
DWORD cbArgs;
LPVOID pArgs;
LPDWORD pdwRetCode;
} vm_inject_state;
BOOL WINAPI vm_inject(DWORD vpfn16, DWORD dwFlags,
DWORD cbArgs, LPVOID pArgs, LPDWORD pdwRetCode)
{
/* FIXME */
return TRUE;
}
void vm_inject_call(SEGPTR ret_addr, PEXCEPTION_HANDLER handler,
void(*from16_reg)(void),
LONG(*__wine_call_from_16)(void),
int(*relay_call_from_16)(void *entry_point, unsigned char *args16, CONTEXT *context),
void(*__wine_call_to_16_ret)(void),
int dasm,
pm_interrupt_handler pih, CONTEXT *context)
{
DWORD ret;
EnterCriticalSection(&inject_crit_section);
static char intstack[4096];
static WORD intstksel = 0;
if (!intstksel)
intstksel = SELECTOR_AllocBlock(intstack, 4096, WINE_LDT_FLAGS_DATA);
WORD sp = context->Esp;
DWORD ss_base = get_base_addr(context->SegSs);
if (wine_ldt_get_flags(wine_ldt + (context->SegSs >> 3)) & WINE_LDT_FLAGS_32BIT) // don't call int handler on a large stack
{
ss_base = (DWORD)intstack;
sp = 4096;
dynamic_setWOW32Reserved((PVOID)MAKESEGPTR(intstksel, 4096));
}
{
char *stack = ss_base + sp - vm_inject_state.cbArgs;
vm_inject_state.inject = FALSE;
memcpy(stack, vm_inject_state.pArgs, vm_inject_state.cbArgs);
/* push return address */
stack -= sizeof(SEGPTR);
*((SEGPTR *)stack) = ret_addr;
vm_inject_state.cbArgs += sizeof(SEGPTR);
}
LeaveCriticalSection(&inject_crit_section);
ret = wine_call_to_16_vm86(vm_inject_state.vpfn16, vm_inject_state.cbArgs, handler, from16_reg, __wine_call_from_16, relay_call_from_16, __wine_call_to_16_ret, dasm, FALSE, NULL, pih);
if (vm_inject_state.pdwRetCode)
*vm_inject_state.pdwRetCode = ret;
SetEvent(inject_event);
}
BOOL syscall_init = FALSE;
static int compare(const void *a1, const void *a2)
{
SIZE_T lhs = *(const SIZE_T*)a1;
SIZE_T rhs = *(const SIZE_T*)a2;
if (lhs == rhs)
return 0;
if (lhs < rhs)
return -1;
return 1;
}
void vm86main(CONTEXT *context, DWORD csip, DWORD sssp, DWORD cbArgs, PEXCEPTION_HANDLER handler,
void(*from16_reg)(void),
LONG(*__wine_call_from_16)(void),
int(*relay_call_from_16)(void *entry_point, unsigned char *args16, CONTEXT *context),
void(*__wine_call_to_16_ret)(void),
int dasm,
pm_interrupt_handler pih
)
{
DWORD old_frame16 = PtrToUlong(dynamic_getWOW32Reserved());
EnterCriticalSection(&running_critical_section);
if (!syscall_init)
{
SIZE_T pages[4] = { (SIZE_T)from16_reg & ~0xfff, (SIZE_T)__wine_call_from_16 & ~0xfff, (SIZE_T)__wine_call_to_16_ret & ~0xfff, 0x80000000 };
int i;
SIZE_T map_addr = 0x000;
qsort((void*)pages, sizeof(pages) / sizeof(pages[0]), sizeof(pages[0]), compare);
for (i = 0; i < sizeof(pages) / sizeof(pages[0]); i++)
{
SIZE_T len = pages[i] - map_addr;
struct gvm_userspace_memory_region mem;
if (pages[i] > map_addr)
{
mem.slot = i;
mem.guest_phys_addr = map_addr;
mem.userspace_addr = map_addr;
mem.memory_size = len;
mem.flags = 0;
if (!DeviceIoControl(hVM, GVM_SET_USER_MEMORY_REGION, &mem, sizeof(mem), NULL, 0, NULL, NULL))
{
PANIC("GVM_SET_USER_MEMORY_REGION");
return;
}
}
map_addr = pages[i] + 4096;
}
syscall_init = TRUE;
}
is_single_step = dasm;
DWORD ret_addr;
vcpu_state state;
{
get_vcpu_regs(&state);
load_seg(get_gs(&state), (WORD)0);
load_seg(get_fs(&state), (WORD)0);
if (!csip)
{
load_seg(get_es(&state), (WORD)context->SegEs);
load_seg(get_ds(&state), (WORD)context->SegDs);
load_seg(get_cs(&state), (WORD)context->SegCs);
load_seg(get_ss(&state), (WORD)context->SegSs);
set_edi(&state, context->Edi);
set_esi(&state, context->Esi);
set_ebx(&state, context->Ebx);
set_edx(&state, context->Edx);
set_ecx(&state, context->Ecx);
set_eax(&state, context->Eax);
set_ebp(&state, context->Ebp);
set_eip(&state, context->Eip);
set_eflags(&state, context->EFlags);
set_esp(&state, context->Esp - cbArgs);
}
else
{
load_seg(get_cs(&state), (WORD)SELECTOROF(csip));
load_seg(get_ss(&state), (WORD)SELECTOROF(sssp));
set_eip(&state, OFFSETOF(csip));
set_esp(&state, OFFSETOF(sssp) - cbArgs);
}
set_vcpu_regs(&state);
unsigned char *stack = (unsigned char*)get_seg_base(get_ss(&state))+ get_esp(&state);
ret_addr = (*(LPDWORD)stack);
}
vcpu_state state2 = state;
if (is_single_step)
{
trace(&state2, get_seg_selector(get_cs(&state2)), get_eip(&state2), get_seg_selector(get_ss(&state2)), get_esp(&state2), get_eflags(&state2));
}
while (TRUE)
{
if (get_seg_selector(get_cs(&state2)) == (ret_addr >> 16) && get_ip(&state2) == (ret_addr & 0xFFFF))
{
set_vcpu_regs(&state2);
break;
}
if (!DeviceIoControl(get_vcpu_handle(), GVM_RUN, NULL, 0, NULL, 0, NULL, NULL))
{
LeaveCriticalSection(&running_critical_section);
PANIC("GVM_RUN");
return;
}
get_vcpu_regs(&state2);
UINT32 ptr = get_seg_base(get_cs(&state2)) + get_eip(&state2);
/* TODO: PIO */
switch (gvm_run->exit_reason)
{
case GVM_EXIT_INTERNAL_ERROR:
case GVM_EXIT_HLT:
if (((DWORD)ptr >= (DWORD)trap_int) && ((DWORD)ptr <= ((DWORD)trap_int + 256)))
{
int intvec = ((DWORD)ptr & 0xff) - 1;
BOOL has_err = has_x86_exception_err(intvec);
DWORD err = has_err ? PEEK32(&state2, 0) : 0;
DWORD eip = PEEK32(&state2, (has_err ? 1 : 0) + 0);
DWORD cs = PEEK32(&state2, (has_err ? 1 : 0) + 1);
DWORD flags = PEEK32(&state2, (has_err ? 1 : 0) + 2);
DWORD old_esp = PEEK32(&state2, (has_err ? 1 : 0) + 3);
DWORD old_ss = PEEK32(&state2, (has_err ? 1 : 0) + 4);
if (intvec == 6 /* #UD??????? */ && cs == (ret_addr >> 16) && eip == (ret_addr & 0xFFFF) || eip == from16_reg || eip == __wine_call_from_16)
{
if (has_err)
{
err = POP32(&state2);
}
DWORD eip = POP32(&state2);
DWORD cs = POP32(&state2);
DWORD eflags = POP32(&state2);
DWORD esp = POP32(&state2);
DWORD ss = POP32(&state2);
load_seg(get_cs(&state2), (WORD)cs);
set_eip(&state2, eip);
load_seg(get_ss(&state2), (WORD)ss);
set_esp(&state2, esp);
set_eflags(&state2, flags);
ptr = get_seg_base(get_cs(&state2)) + get_eip(&state2);
if (get_seg_selector(get_cs(&state2)) == (ret_addr >> 16) && get_ip(&state2) == (ret_addr & 0xFFFF))
{
set_vcpu_regs(&state2);
break;
}
if (ptr == from16_reg || ptr == __wine_call_from_16)
{
LeaveCriticalSection(&running_critical_section);
relay(relay_call_from_16, ptr == from16_reg, &state2, ret_addr, cbArgs, handler, old_frame16);
EnterCriticalSection(&running_critical_section);
}
else
{
PANIC("");
}
set_vcpu_regs(&state2);
break;
}
const char *name = NULL;
switch (intvec)
{
case 0: name = "#DE"; break;
case 2: name = "int 2h"; break;
case 4: name = "#OF"; break;
case 6: name = "#UD"; break;
case 7: name = "#NM"; break;
case 8: name = "#DF"; break;
case 10: name = "#TS"; break;
case 11: name = "#NP"; break;
case 12: name = "#SS"; break;
case 13: name = "#GP"; break;
case 14: name = "#PF"; break;
}
set_eip(&state2, 256);
if (name)
{
DWORD cpusig[4];
#ifdef _MSC_VER
__cpuid(cpusig, 0);
#else
__cpuid(0, cpusig[0], cpusig[1], cpusig[2], cpusig[3]);
#endif
fprintf(stderr, "cpu type %x %x %x %x\n", cpusig[0], cpusig[1], cpusig[2], cpusig[3]);
trace(&state2, cs, eip, (WORD)old_ss, old_esp, flags);
PANIC("exception %s", name);
}
else
{
DWORD eip = POP32(&state2);
DWORD cs = POP32(&state2);
DWORD eflags = POP32(&state2);
DWORD esp = POP32(&state2);
DWORD ss = POP32(&state2);
load_seg(get_cs(&state2), (WORD)cs);
set_eip(&state2, eip);
load_seg(get_ss(&state2), (WORD)ss);
set_esp(&state2, esp);
CONTEXT ctx;
save_context_from_state(&ctx, &state2);
set_vcpu_regs(&state2);
LeaveCriticalSection(&running_critical_section);
dynamic__wine_call_int_handler(&ctx, intvec);
EnterCriticalSection(&running_critical_section);
load_context_to_state(&ctx, &state2);
set_vcpu_regs(&state2);
}
}
break;
default:
PANIC("%d", gvm_run->exit_reason);
break;
}
}
save_context_from_state(context, &state2);
LeaveCriticalSection(&running_critical_section);
}
__declspec(dllexport) DWORD wine_call_to_16_vm86(DWORD target, DWORD cbArgs, PEXCEPTION_HANDLER handler,
void(*from16_reg)(void),
LONG(*__wine_call_from_16)(void),
int(*relay_call_from_16)(void *entry_point, unsigned char *args16, CONTEXT *context),
void(*__wine_call_to_16_ret)(void),
int dasm,
BOOL vm86,
void *memory_base,
pm_interrupt_handler pih)
{
mem = vm86 ? (UINT8*)memory_base : NULL;
if (!initflag)
initflag = init_vm86(vm86);
CONTEXT context = { 0 };
vm86main(&context, target, (DWORD)dynamic_getWOW32Reserved(), cbArgs, handler, from16_reg, __wine_call_from_16, relay_call_from_16, __wine_call_to_16_ret, dasm, pih);
return (context.Eax & 0xffff) | context.Edx << 16;
}
__declspec(dllexport) void wine_call_to_16_regs_vm86(CONTEXT *context, DWORD cbArgs, PEXCEPTION_HANDLER handler,
void(*from16_reg)(void),
LONG(*__wine_call_from_16)(void),
int(*relay_call_from_16)(void *entry_point, unsigned char *args16, CONTEXT *context),
void(*__wine_call_to_16_ret)(void),
int dasm,
BOOL vm86,
void *memory_base,
pm_interrupt_handler pih
)
{
mem = vm86 ? (UINT8*)memory_base : NULL;
if (!initflag)
initflag = init_vm86(vm86);
vm86main(context, 0, 0, cbArgs, handler, from16_reg, __wine_call_from_16, relay_call_from_16, __wine_call_to_16_ret, dasm, pih);
}
================================================
FILE: gvm/gvm.def
================================================
================================================
FILE: gvm/gvm.h
================================================
#pragma once
#include
#include "gvm-interface.h"
#include
#include
struct gvm_vcpu_state
{
struct gvm_regs regs;
struct gvm_sregs sregs;
};
typedef UINT16 uint16;
typedef UINT32 uint32;
typedef UINT64 uint64;
/* register utils */
typedef struct gvm_vcpu_state vcpu_state;
typedef struct gvm_segment segment;
/* 16-bit regs */
static inline uint16 get_ax(vcpu_state *state)
{
return (uint16)state->regs.rax;
}
static inline uint16 get_cx(vcpu_state *state)
{
return (uint16)state->regs.rcx;
}
static inline uint16 get_dx(vcpu_state *state)
{
return (uint16)state->regs.rdx;
}
static inline uint16 get_bx(vcpu_state *state)
{
return (uint16)state->regs.rbx;
}
static inline uint16 get_sp(vcpu_state *state)
{
return (uint16)state->regs.rsp;
}
static inline uint16 get_bp(vcpu_state *state)
{
return (uint16)state->regs.rbp;
}
static inline uint16 get_si(vcpu_state *state)
{
return (uint16)state->regs.rsi;
}
static inline uint16 get_di(vcpu_state *state)
{
return (uint16)state->regs.rdi;
}
static inline uint16 get_ip(vcpu_state *state)
{
return (uint16)state->regs.rip;
}
static inline uint16 get_flags(vcpu_state *state)
{
return (uint16)state->regs.rflags;
}
static inline uint16 set_ax(vcpu_state *state, uint16 val)
{
return *(uint16*)&state->regs.rax = val;
}
static inline uint16 set_cx(vcpu_state *state, uint16 val)
{
return *(uint16*)&state->regs.rcx = val;
}
static inline uint16 set_dx(vcpu_state *state, uint16 val)
{
return *(uint16*)&state->regs.rdx = val;
}
static inline uint16 set_bx(vcpu_state *state, uint16 val)
{
return *(uint16*)&state->regs.rbx = val;
}
static inline uint16 set_sp(vcpu_state *state, uint16 val)
{
return *(uint16*)&state->regs.rsp = val;
}
static inline uint16 set_bp(vcpu_state *state, uint16 val)
{
return *(uint16*)&state->regs.rbp = val;
}
static inline uint16 set_si(vcpu_state *state, uint16 val)
{
return *(uint16*)&state->regs.rsi = val;
}
static inline uint16 set_di(vcpu_state *state, uint16 val)
{
return *(uint16*)&state->regs.rdi = val;
}
static inline uint16 set_ip(vcpu_state *state, uint16 val)
{
return *(uint16*)&state->regs.rip = val;
}
static inline segment *get_es(vcpu_state *state)
{
return &state->sregs.es;
}
static inline segment *get_cs(vcpu_state *state)
{
return &state->sregs.cs;
}
static inline segment *get_ss(vcpu_state *state)
{
return &state->sregs.ss;
}
static inline segment *get_ds(vcpu_state *state)
{
return &state->sregs.ds;
}
static inline segment *get_fs(vcpu_state *state)
{
return &state->sregs.fs;
}
static inline segment *get_gs(vcpu_state *state)
{
return &state->sregs.gs;
}
static inline uint16 get_seg_selector(segment *seg)
{
return seg->selector;
}
static inline uint32 get_seg_base(segment *seg)
{
return (uint32)seg->base;
}
static inline uint32 get_seg_limit(segment *seg)
{
return seg->limit;
}
/* 32-bit regs */
static inline uint32 get_eax(vcpu_state *state)
{
return (uint32)state->regs.rax;
}
static inline uint32 get_ecx(vcpu_state *state)
{
return (uint32)state->regs.rcx;
}
static inline uint32 get_edx(vcpu_state *state)
{
return (uint32)state->regs.rdx;
}
static inline uint32 get_ebx(vcpu_state *state)
{
return (uint32)state->regs.rbx;
}
static inline uint32 get_esp(vcpu_state *state)
{
return (uint32)state->regs.rsp;
}
static inline uint32 get_ebp(vcpu_state *state)
{
return (uint32)state->regs.rbp;
}
static inline uint32 get_esi(vcpu_state *state)
{
return (uint32)state->regs.rsi;
}
static inline uint32 get_edi(vcpu_state *state)
{
return (uint32)state->regs.rdi;
}
static inline uint32 get_eip(vcpu_state *state)
{
return (uint32)state->regs.rip;
}
static inline uint32 get_eflags(vcpu_state *state)
{
return (uint32)state->regs.rflags;
}
static inline uint32 set_eax(vcpu_state *state, uint32 val)
{
return *(uint32*)&state->regs.rax = val;
}
static inline uint32 set_ecx(vcpu_state *state, uint32 val)
{
return *(uint32*)&state->regs.rcx = val;
}
static inline uint32 set_edx(vcpu_state *state, uint32 val)
{
return *(uint32*)&state->regs.rdx = val;
}
static inline uint32 set_ebx(vcpu_state *state, uint32 val)
{
return *(uint32*)&state->regs.rbx = val;
}
static inline uint32 set_esp(vcpu_state *state, uint32 val)
{
return *(uint32*)&state->regs.rsp = val;
}
static inline uint32 set_ebp(vcpu_state *state, uint32 val)
{
return *(uint32*)&state->regs.rbp = val;
}
static inline uint32 set_esi(vcpu_state *state, uint32 val)
{
return *(uint32*)&state->regs.rsi = val;
}
static inline uint32 set_edi(vcpu_state *state, uint32 val)
{
return *(uint32*)&state->regs.rdi = val;
}
static inline uint32 set_eip(vcpu_state *state, uint32 val)
{
return *(uint32*)&state->regs.rip = val;
}
================================================
FILE: gvm/gvm.vcxproj
================================================
Debug
Win32
Release
Win32
15.0
Win32Proj
gvm
10.0.17134.0
{258FD007-046D-4625-BB5A-B7934B71934F}
DynamicLibrary
true
v141
Unicode
DynamicLibrary
false
v141
true
Unicode
DynamicLibrary
true
v141
Unicode
DynamicLibrary
false
v141
true
Unicode
false
true
NotUsing
Level3
MaxSpeed
true
true
true
__i386__;_WINDOWS;HAS_I386;NtCurrentTeb=NtCurrentTeb__;WIN32;__i386__;_WINDOWS;HAS_I386;NtCurrentTeb=NtCurrentTeb__;NDEBUG;_CONSOLE;DECLSPEC_HIDDEN=;%(PreprocessorDefinitions)
true
../wine
Console
true
true
true
$(OutDir)libwine.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
gvm.def
NotUsing
Level3
Disabled
true
__i386__;_WINDOWS;HAS_I386;NtCurrentTeb=NtCurrentTeb__;WIN32;__i386__;_WINDOWS;HAS_I386;NtCurrentTeb=NtCurrentTeb__;_DEBUG;_CONSOLE;DECLSPEC_HIDDEN=;%(PreprocessorDefinitions)
true
../wine
Console
true
$(OutDir)libwine.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
gvm.def
================================================
FILE: gvm/gvm.vcxproj.filters
================================================
{4FC737F1-C7A5-4376-A066-2A32D752A2FF}
cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
{93995380-89BD-4b04-88EB-625FBE52EBFB}
h;hh;hpp;hxx;hm;inl;inc;ipp;xsd
{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
ヘッダー ファイル
ヘッダー ファイル
ソース ファイル
ソース ファイル
================================================
FILE: haxmvm/CMakeLists.txt
================================================
add_library(haxmvm SHARED haxmvm.c)
include_directories(../wine)
add_definitions(-D__i386__ -DNtCurrentTeb=NtCurrentTeb__ -DDECLSPEC_HIDDEN=)
target_link_libraries(haxmvm libwine)
set_target_properties(haxmvm PROPERTIES PREFIX "")
================================================
FILE: haxmvm/haxmvm.c
================================================
#include "haxmvm.h"
#include "../krnl386/kernel16_private.h"
BOOL initflag;
UINT8 *mem;
#define KRNL386 "krnl386.exe16"
BOOL is_single_step = FALSE;
DWORD WINAPI panic_msgbox(LPVOID data)
{
MessageBoxA(NULL, (LPCSTR)data, "Hypervisor error", MB_OK | MB_ICONERROR);
HeapFree(GetProcessHeap(), 0, data);
return 0;
}
void haxmvm_panic(const char *fmt, ...)
{
LPSTR buffer = HeapAlloc(GetProcessHeap(), 0, 512);
DWORD threadId;
va_list arg;
va_start(arg, fmt);
vsnprintf(buffer, 512, fmt, arg);
va_end(arg);
buffer[512 - 1] = '\0';
HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)panic_msgbox, buffer, 0, &threadId);
WaitForSingleObject(hThread, INFINITE);
ExitThread(1);
}
PVOID dynamic_setWOW32Reserved(PVOID w)
{
static PVOID(*setWOW32Reserved)(PVOID);
if (!setWOW32Reserved)
{
HMODULE krnl386 = LoadLibraryA(KRNL386);
setWOW32Reserved = (PVOID(*)(PVOID))GetProcAddress(krnl386, "setWOW32Reserved");
}
return setWOW32Reserved(w);
}
PVOID dynamic_getWOW32Reserved()
{
static PVOID(*getWOW32Reserved)();
if (!getWOW32Reserved)
{
HMODULE krnl386 = LoadLibraryA(KRNL386);
getWOW32Reserved = (PVOID(*)())GetProcAddress(krnl386, "getWOW32Reserved");
}
return getWOW32Reserved();
}
WINE_VM86_TEB_INFO *dynamic_getGdiTebBatch()
{
static WINE_VM86_TEB_INFO*(*getGdiTebBatch)();
if (!getGdiTebBatch)
{
HMODULE krnl386 = LoadLibraryA(KRNL386);
getGdiTebBatch = (WINE_VM86_TEB_INFO*(*)())GetProcAddress(krnl386, "getGdiTebBatch");
}
return getGdiTebBatch();
}
void dynamic__wine_call_int_handler(CONTEXT *context, BYTE intnum)
{
static void(*__wine_call_int_handler)(CONTEXT *context, BYTE intnum);
if (!__wine_call_int_handler)
{
HMODULE krnl386 = LoadLibraryA(KRNL386);
__wine_call_int_handler = (void(*)(CONTEXT *context, BYTE intnum))GetProcAddress(krnl386, "__wine_call_int_handler");
}
__wine_call_int_handler(context, intnum);
}
/***********************************************************************
* SELECTOR_SetEntries
*
* Set the LDT entries for an array of selectors.
*/
static BOOL SELECTOR_SetEntries(WORD sel, const void *base, DWORD size, unsigned char flags)
{
LDT_ENTRY entry;
WORD i, count;
wine_ldt_set_base(&entry, base);
wine_ldt_set_limit(&entry, size - 1);
wine_ldt_set_flags(&entry, flags);
count = (size + 0xffff) / 0x10000;
for (i = 0; i < count; i++)
{
if (wine_ldt_set_entry(sel + (i << 3), &entry) < 0) return FALSE;
wine_ldt_set_base(&entry, (char*)wine_ldt_get_base(&entry) + 0x10000);
/* yep, Windows sets limit like that, not 64K sel units */
wine_ldt_set_limit(&entry, wine_ldt_get_limit(&entry) - 0x10000);
}
return TRUE;
}
void wine_ldt_free_entries(unsigned short sel, int count);
/***********************************************************************
* SELECTOR_AllocBlock
*
* Allocate selectors for a block of linear memory.
*/
WORD SELECTOR_AllocBlock(const void *base, DWORD size, unsigned char flags)
{
WORD sel, count;
if (!size) return 0;
count = (size + 0xffff) / 0x10000;
if ((sel = wine_ldt_alloc_entries(count)))
{
if (SELECTOR_SetEntries(sel, base, size, flags)) return sel;
wine_ldt_free_entries(sel, count);
sel = 0;
}
return sel;
}
__declspec(dllimport) LDT_ENTRY wine_ldt[8192];
HANDLE hSystem;
HANDLE hVM;
HANDLE hVCPU;
struct hax_tunnel *tunnel;
// 2MB is enough for 0x00000000-0x7fffffff plus 1 page for the pagedir
#ifdef _MSC_VER
__declspec(align(4096))
#endif
DWORD
#ifdef __GNUC__
__attribute__ ((aligned(4096)))
#endif
guestpt[0x80400] = {0}
;
LDT_ENTRY gdt[];
void load_seg(segment_desc_t *segment, WORD sel)
{
const LDT_ENTRY *entry = (sel & 0x4 || (sel >> 3) >= 512) ? wine_ldt : gdt;
segment->selector = sel;
segment->base = (uint64)wine_ldt_get_base(entry + (sel >> 3));
segment->limit = (uint64)wine_ldt_get_limit(entry + (sel >> 3));
segment->type = entry[sel >> 3].HighWord.Bits.Type;
segment->present = entry[sel >> 3].HighWord.Bits.Pres;
segment->operand_size = entry[sel >> 3].HighWord.Bits.Default_Big;
segment->dpl = entry[sel >> 3].HighWord.Bits.Dpl;
segment->granularity = entry[sel >> 3].HighWord.Bits.Granularity;
segment->null = 0;
segment->desc = entry[sel >> 3].HighWord.Bits.Type >> 4;
if (!sel || !segment->type || !segment->present)
segment->ar = 0;
}
void set_eflags(struct vcpu_state_t *state, DWORD eflags)
{
state->_eflags = eflags | 2 | 0x3000 | (is_single_step ? 0x100 : 0);
}
void load_context_to_state(CONTEXT *context, struct vcpu_state_t *state)
{
DWORD bytes;
load_seg(&state->_gs, (WORD)context->SegGs);
load_seg(&state->_fs, (WORD)context->SegFs);
load_seg(&state->_es, (WORD)context->SegEs);
load_seg(&state->_ds, (WORD)context->SegDs);
load_seg(&state->_cs, (WORD)context->SegCs);
load_seg(&state->_ss, (WORD)context->SegSs);
state->_edi = context->Edi;
state->_esi = context->Esi;
state->_ebx = context->Ebx;
state->_edx = context->Edx;
state->_ecx = context->Ecx;
state->_eax = context->Eax;
state->_ebp = context->Ebp;
state->_eip = context->Eip;
set_eflags(state, context->EFlags);
state->_esp = context->Esp;
}
void load_context(CONTEXT *context)
{
DWORD bytes;
struct vcpu_state_t state;
if (!DeviceIoControl(hVCPU, HAX_VCPU_GET_REGS, NULL, 0, &state, sizeof(state), &bytes, NULL))
return;
load_seg(&state._gs, (WORD)context->SegGs);
load_seg(&state._fs, (WORD)context->SegFs);
load_seg(&state._es, (WORD)context->SegEs);
load_seg(&state._ds, (WORD)context->SegDs);
load_seg(&state._cs, (WORD)context->SegCs);
load_seg(&state._ss, (WORD)context->SegSs);
state._edi = context->Edi;
state._esi = context->Esi;
state._ebx = context->Ebx;
state._edx = context->Edx;
state._ecx = context->Ecx;
state._eax = context->Eax;
state._ebp = context->Ebp;
state._eip = context->Eip;
set_eflags(&state, context->EFlags);
state._esp = context->Esp;
if (!DeviceIoControl(hVCPU, HAX_VCPU_SET_REGS, &state, sizeof(state), NULL, 0, &bytes, NULL))
return;
}
void save_context_from_state(CONTEXT *context, struct vcpu_state_t *state)
{
context->SegGs = state->_gs.selector;
context->SegFs = state->_fs.selector;
context->SegEs = state->_es.selector;
context->SegDs = state->_ds.selector;
context->SegCs = state->_cs.selector;
context->SegSs = state->_ss.selector;
context->Edi = state->_edi;
context->Esi = state->_esi;
context->Ebx = state->_ebx;
context->Edx = state->_edx;
context->Ecx = state->_ecx;
context->Eax = state->_eax;
context->Ebp = state->_ebp;
context->Eip = state->_eip;
context->EFlags = state->_eflags & ~2;
context->Esp = state->_esp;
dynamic_setWOW32Reserved((PVOID)(state->_ss.selector << 16 | state->_sp));
}
void save_context(CONTEXT *context)
{
DWORD bytes;
struct vcpu_state_t state;
if (!DeviceIoControl(hVCPU, HAX_VCPU_GET_REGS, NULL, 0, &state, sizeof(state), &bytes, NULL))
return;
save_context_from_state(context, &state);
context->EFlags &= ~0x200;
}
#include
typedef enum
{
INT_GATE_TASK = 5,
INT_GATE_INT16 = 6,
INT_GATE_TRAP16 = 7,
INT_GATE_INT32 = 0xE,
INT_GATE_TRAP32 = 0xF,
} interrupt_gate_type;
typedef struct
{
WORD offset_low;
WORD selector;
BYTE reserved;
union
{
struct
{
BYTE type : 4 /* INT_GATE_TASK */, S : 1, DPL : 2, P : 1;
};
BYTE data;
};
WORD offset_high;
} interrupt_gate;
_STATIC_ASSERT(sizeof(interrupt_gate) == 8);
#include
#define HAXMVM_STR2(s) #s
#define HAXMVM_STR(s) HAXMVM_STR2(s)
#ifdef _MSC_VER
#define HAXMVM_ERR fprintf(stderr, __FUNCTION__ "(" HAXMVM_STR(__LINE__) ") HAXM err.\n");
#define HAXMVM_ERRF(fmt, ...) fprintf(stderr, __FUNCTION__ "(" HAXMVM_STR(__LINE__) ") " fmt "\n", __VA_ARGS__);
#else
#define HAXMVM_ERR fprintf(stderr, "%s(" HAXMVM_STR(__LINE__) ") HAXM err.\n", __FUNCTION__);
#define HAXMVM_ERRF(fmt, ...) fprintf(stderr, "%s(" HAXMVM_STR(__LINE__) ") " fmt "\n", __FUNCTION__, ##__VA_ARGS__);
#endif
LPVOID trap_int;
#ifdef _MSC_VER
__declspec(align(4096))
#endif
interrupt_gate idt[256];
#ifdef __GNUC__
__attribute__ ((aligned(4096)))
#endif
;
#ifdef _MSC_VER
__declspec(align(4096))
#endif
LDT_ENTRY gdt[512] = { 0 };
#ifdef __GNUC__
__attribute__ ((aligned(4096)))
#endif
;
WORD seg_cs;
WORD seg_ds;
static BOOL set_ram(struct hax_set_ram_info *pram)
{
DWORD bytes;
struct hax_set_ram_info ram = *pram;
ram.flags = HAX_RAM_INFO_STANDALONE;
if (!DeviceIoControl(hVM, HAX_VM_IOCTL_SET_RAM, &ram, sizeof(struct hax_set_ram_info), NULL, 0, &bytes, NULL))
return FALSE;
DWORD physaddr = ram.pa_start / 4096;
for (DWORD i = 0; i < (ram.size / 4096); i++)
{
DWORD pte = physaddr + i;
guestpt[pte] = (pte << 12) | 7;
}
return TRUE;
}
#define dprintf(...) //fprintf(stderr, __VA_ARGS__)
static CRITICAL_SECTION crst;
static CRITICAL_SECTION_DEBUG critsect_debug =
{
0, 0, &crst,
{ &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
0, 0, { (DWORD_PTR)(__FILE__ ": crst") }
};
static CRITICAL_SECTION crst = { &critsect_debug, -1, 0, 0, 0, 0 };
void alloc_ram(uint32_t addr, uint32_t size)
{
MEMORY_BASIC_INFORMATION mbi;
struct hax_set_ram_info ram = { 0 };
BOOL protect = 0;
DWORD old = 0;
ram.pa_start = addr;
ram.size = size;
ram.va = addr;
if (VirtualQuery(ram.va, &mbi, sizeof(MEMORY_BASIC_INFORMATION)))
{
if (!(mbi.Protect & PAGE_EXECUTE_READWRITE) && !(mbi.Protect & PAGE_READWRITE))
{
protect = VirtualProtect(ram.va, 4096, PAGE_EXECUTE_READWRITE, &old);
}
}
dprintf("alloc = %08x\n", ram.va);
if (!set_ram(&ram))
{
HAXMVM_ERRF("SET_RAM");
}
if (protect && 0)
{
VirtualProtect(ram.va, 4096, old, &old);
}
}
static void intel_vt_x_workaround_update_entry(int sel, const LDT_ENTRY *entry)
{
DWORD bytes;
uint32 start = ((uint32)wine_ldt_get_base(entry) & ~0xfff);
uint32 size = 0;
EnterCriticalSection(&crst);
for (uint32 i = start; i <= ((uint32)wine_ldt_get_base(entry) + wine_ldt_get_limit(entry)); i += 4096)
{
if (!i || guestpt[i / 4096])
{
continue;
}
alloc_ram(i, 4096);
}
LeaveCriticalSection(&crst);
}
/*
* WOW64 syscall entry:
* B8 XX XX XX XX mov eax,XXXXX
* BA XX XX XX XX mov edx,_Wow64SystemServiceCall@0
* FF D2 call edx
* C2 XX XX ret xx
* 90 nop
*/
#include
struct wow64_syscall
{
BYTE mov_eax;
DWORD num;
BYTE mov_edx;
DWORD Wow64SystemServiceCall;
WORD call_edx;
BYTE ret;
WORD ret_n;
BYTE nop;
};
struct hooked_syscall
{
BYTE jmp_rel;
DWORD address;
};
#include
BOOL hook_nt_syscall(struct wow64_syscall **old_syscall, LPVOID hook_func, LPCSTR hook_dll, LPCSTR hook_func_name)
{
HMODULE dll = GetModuleHandleA(hook_dll);
LPVOID func = (LPVOID)GetProcAddress(dll, hook_func_name);
struct wow64_syscall *syscall = (struct wow64_syscall*)func;
MEMORY_BASIC_INFORMATION mbi;
DWORD old;
if (!func)
{
return FALSE;
}
if (syscall->mov_eax != 0xb8 || syscall->mov_edx != 0xba || syscall->call_edx != 0xd2ff || syscall->ret != 0xc2 || syscall->nop != 0x90)
{
return FALSE;
}
if (!VirtualQuery(syscall, &mbi, sizeof(mbi)))
{
return FALSE;
}
VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, &old);
*old_syscall = VirtualAlloc(NULL, 4096, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
**old_syscall = *syscall;
((struct hooked_syscall*)syscall)->jmp_rel = 0xe9;
((struct hooked_syscall*)syscall)->address = (char*)hook_func - (char*)(&((struct hooked_syscall*)syscall)->address + 1);
VirtualProtect(mbi.BaseAddress, mbi.RegionSize, old, &old);
return TRUE;
}
static void discard_memory(PVOID BaseAddress, ULONG RegionSize)
{
DWORD physaddr = (DWORD)BaseAddress / 4096;
for (DWORD i = 0; i < (RegionSize / 4096); i++)
{
DWORD pte = physaddr + i;
if (sizeof(guestpt) / sizeof(guestpt[0]) <= pte)
*(int*)0 = 0;
if (guestpt[pte])
{
struct hax_set_ram_info ram = { pte * 4096, 4096, HAX_RAM_INFO_INVALID };
if (!DeviceIoControl(hVM, HAX_VM_IOCTL_SET_RAM, &ram, sizeof(ram), NULL, 0, NULL, NULL))
{
HAXMVM_ERRF("Failed to discard memory %p", pte);
}
guestpt[pte] = 0;
}
}
}
struct wow64_syscall *old_NtFreeVirtualMemory;
NTSTATUS NTAPI hook_NtFreeVirtualMemory(HANDLE ProcessHandle, PVOID *BaseAddress, PULONG RegionSize, ULONG FreeType)
{
NTSTATUS result = ((NTSTATUS(NTAPI*)(HANDLE, PVOID*, PULONG, ULONG))old_NtFreeVirtualMemory)(ProcessHandle, BaseAddress, RegionSize, FreeType);
if (NT_SUCCESS(result))
{
discard_memory(*BaseAddress, *RegionSize);
}
return result;
}
__declspec(dllexport) BOOL haxmvm_DeleteObject(HANDLE hobj)
{
DIBSECTION dib;
BOOL discard = FALSE;
MEMORY_BASIC_INFORMATION mbi;
BOOL result;
if (GetObjectType(hobj) == OBJ_BITMAP && GetObjectW(hobj, sizeof(dib), &dib) == sizeof(dib))
{
if (VirtualQuery(dib.dsBm.bmBits, &mbi, sizeof(mbi)))
{
discard = mbi.State == MEM_COMMIT;
}
}
result = DeleteObject(hobj);
if (result && discard)
{
discard_memory(mbi.BaseAddress, mbi.RegionSize);
}
return result;
}
BOOL init_vm86(BOOL vm86)
{
if (!hook_nt_syscall(&old_NtFreeVirtualMemory, hook_NtFreeVirtualMemory, "ntdll", "NtFreeVirtualMemory"))
{
HAXMVM_ERRF("Failed to hook NtFreeVirtualMemory.");
}
#ifdef _MSC_VER
__asm
{
mov seg_cs, cs
mov seg_ds, ds
}
#else
seg_cs = wine_get_cs();
seg_ds = wine_get_ds();
#endif
hSystem = CreateFileW(L"\\\\.\\HAX", 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hSystem == INVALID_HANDLE_VALUE)
{
HAXMVM_ERRF("HAXM is not installed.\n");
return FALSE;
}
struct hax_module_version ver;
DWORD bytes;
if (!DeviceIoControl(hSystem, HAX_IOCTL_VERSION, NULL, NULL, &ver, sizeof(ver), &bytes, NULL))
{
HAXMVM_ERRF("VERSION");
return FALSE;
}
uint32_t vm_id;
if (!DeviceIoControl(hSystem, HAX_IOCTL_CREATE_VM, NULL, NULL, &vm_id, sizeof(vm_id), &bytes, NULL))
{
HAXMVM_ERRF("CREATE_VM");
return FALSE;
}
WCHAR buf[1000];
swprintf_s(buf, RTL_NUMBER_OF(buf), L"\\\\.\\hax_vm%02d", vm_id);
hVM = CreateFileW(buf, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hVM == INVALID_HANDLE_VALUE)
{
HAXMVM_ERRF("Could not create vm.");
return FALSE;
}
uint32_t vcpu_id;
struct hax_qemu_version verq;
/* 3~ enable fast mmio */
verq.cur_version = 1;
verq.least_version = 0;
if (!DeviceIoControl(hVM, HAX_VM_IOCTL_NOTIFY_QEMU_VERSION, &verq, sizeof(verq), NULL, 0, &bytes, NULL))
{
}
vcpu_id = 1;
if (!DeviceIoControl(hVM, HAX_VM_IOCTL_VCPU_CREATE, &vcpu_id, sizeof(vcpu_id), NULL, 0, &bytes, NULL))
{
HAXMVM_ERRF("could not create vcpu.");
return FALSE;
}
swprintf_s(buf, RTL_NUMBER_OF(buf), L"\\\\.\\hax_vm%02d_vcpu%02d", vm_id, vcpu_id);
hVCPU = CreateFileW(buf, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
struct hax_tunnel_info tunnel_info;
if (!DeviceIoControl(hVCPU, HAX_VCPU_IOCTL_SETUP_TUNNEL, NULL, 0, &tunnel_info, sizeof(tunnel_info), &bytes, NULL))
{
HAXMVM_ERRF("SETUP_TUNNEL");
return FALSE;
}
/* memory mapping */
struct hax_alloc_ram_info alloc_ram = { 0 };
struct hax_set_ram_info ram = { 0 };
MEMORY_BASIC_INFORMATION mbi = { 0 };
trap_int = VirtualAlloc(NULL, 0x10000, MEM_COMMIT, PAGE_READWRITE);
alloc_ram.size = 0x201000;
alloc_ram.va = (uint64_t)guestpt;
if (!DeviceIoControl(hVM, HAX_VM_IOCTL_ALLOC_RAM, &alloc_ram, sizeof(alloc_ram), NULL, 0, &bytes, NULL))
{
HAXMVM_ERRF("ALLOC_RAM");
return FALSE;
}
ram.pa_start = (uint64_t)guestpt;
ram.size = 0x201000;
ram.va = (uint64_t)guestpt;
if (!DeviceIoControl(hVM, HAX_VM_IOCTL_SET_RAM, &ram, sizeof(ram), NULL, 0, &bytes, NULL))
{
HAXMVM_ERRF("SET_RAM");
return FALSE;
}
// fill in the pagedir
for (int i = 0; i < 512; i++)
guestpt[0x80000 + i] = ((DWORD)guestpt + 4096 * i) | 7;
tunnel = (struct hax_tunnel*)tunnel_info.va;
struct vcpu_state_t state;
if (!DeviceIoControl(hVCPU, HAX_VCPU_GET_REGS, NULL, 0, &state, sizeof(state), &bytes, NULL))
{
HAXMVM_ERRF("GET_REGS");
return FALSE;
}
/* setup initial states */
state._gdt.base = (uint64)gdt;
state._gdt.limit = 0x7ff;
DWORD trap_addr = (DWORD)trap_int;
gdt[1].BaseLow = trap_addr & 0xffff;
gdt[1].HighWord.Bytes.BaseMid = (trap_addr >> 16) & 0xff;
gdt[1].HighWord.Bytes.BaseHi = (trap_addr >> 24) & 0xff;
gdt[1].LimitLow = 0xffff;
gdt[1].HighWord.Bytes.Flags1 = 0x9b;
gdt[1].HighWord.Bytes.Flags2 = 0x40;
gdt[2].BaseLow = trap_addr & 0xffff;
gdt[2].HighWord.Bytes.BaseMid = (trap_addr >> 16) & 0xff;
gdt[2].HighWord.Bytes.BaseHi = (trap_addr >> 24) & 0xff;
gdt[2].LimitLow = 0xffff;
gdt[2].HighWord.Bytes.Flags1 = 0x93;
gdt[2].HighWord.Bytes.Flags2 = 0x40;
GetThreadSelectorEntry(GetCurrentThread(), seg_cs, gdt + (seg_cs >> 3));
GetThreadSelectorEntry(GetCurrentThread(), seg_ds, gdt + (seg_ds >> 3));
state._ldt.selector = 0x18;
state._ldt.base = (uint64)&wine_ldt[0];
state._ldt.limit = 65535;
UINT32 *tss = (UINT32 *)gdt + 0x200;
state._tr.selector = 0x18;
state._tr.base = (uint64)tss;
state._tr.limit = 0x64;
state._tr.ar = 0x8b;
tss[1] = 0x10000; // SP0
tss[2] = 0x10; // SS0
state._idt.limit = 0x8 * 256 - 1;
state._idt.base = (SIZE_T)&idt[0];
state._cr3 = guestpt + 0x80000;
state._cr0 |= 0x80000001;
state._eflags |= 0x200;
for (int i = 0; i < 256; i++)
{
idt[i].DPL = 3;
idt[i].type = INT_GATE_INT32;
idt[i].selector = 0x0b;
idt[i].P = 1;
idt[i].offset_low = i;
idt[i].offset_high = 0;
}
memset(trap_int, 0xF4, 256); /* hlt */
((char *)trap_int)[256] = 0xcf; /* iret */
ram.pa_start = (uint64_t)&idt;
ram.size = 4096;
ram.va = (uint64_t)&idt;
if (!set_ram(&ram))
{
HAXMVM_ERRF("SET_RAM\n");
return FALSE;
}
ram.pa_start = (uint64_t)&wine_ldt & ~0xfff;
ram.size = 65536 + 4096;
ram.va = (uint64_t)&wine_ldt & ~0xfff;
if (!set_ram(&ram))
{
HAXMVM_ERRF("SET_RAM\n");
return FALSE;
}
ram.pa_start = (uint64_t)trap_int;
ram.size = 0x10000;
ram.va = (uint64_t)trap_int;
if (!set_ram(&ram))
{
HAXMVM_ERRF("SET_RAM");
return FALSE;
}
ram.pa_start = (uint64_t)&gdt;
ram.size = 0x1000;
ram.va = (uint64_t)&gdt;
if (!set_ram(&ram))
{
HAXMVM_ERRF("SET_RAM");
return FALSE;
}
if (!DeviceIoControl(hVCPU, HAX_VCPU_SET_REGS, &state, sizeof(state), NULL, 0, &bytes, NULL))
{
HAXMVM_ERRF("SET_REGS");
return FALSE;
}
((void(*)(void(*intel_vt_x_workaround_update_entry)(const LDT_ENTRY *entry)))GetProcAddress(GetModuleHandleA("libwine"), "set_intel_vt_x_workaround"))(intel_vt_x_workaround_update_entry);
return TRUE;
}
BOOL vm_exit()
{
CloseHandle(hVCPU);
CloseHandle(hVM);
CloseHandle(hSystem);
return TRUE;
}
void PUSH16(struct vcpu_state_t *state, WORD val)
{
if (state->_ss.operand_size)
{
state->_esp -= 2;
unsigned char *stack = (unsigned char*)(state->_ss.base + state->_esp);
*(LPWORD)stack = val;
}
else
{
state->_sp -= 2;
unsigned char *stack = (unsigned char*)(state->_ss.base + state->_sp);
*(LPWORD)stack = val;
}
}
void PUSH32(struct vcpu_state_t *state, DWORD val)
{
if (state->_ss.operand_size)
{
state->_esp -= 4;
unsigned char *stack = (unsigned char*)(state->_ss.base + state->_esp);
*(LPDWORD)stack = val;
}
else
{
state->_sp -= 4;
unsigned char *stack = (unsigned char*)(state->_ss.base + state->_sp);
*(LPDWORD)stack = val;
}
}
WORD POP16(struct vcpu_state_t *state)
{
if (state->_ss.operand_size)
{
LPWORD stack = (LPWORD)(state->_ss.base + state->_esp);
state->_esp += 2;
return *stack;
}
else
{
LPWORD stack = (LPWORD)(state->_ss.base + state->_sp);
state->_sp += 2;
return *stack;
}
}
DWORD POP32(struct vcpu_state_t *state)
{
if (state->_ss.operand_size)
{
LPDWORD stack = (LPDWORD)(state->_ss.base + state->_esp);
state->_esp += 4;
return *stack;
}
else
{
LPDWORD stack = (LPDWORD)(state->_ss.base + state->_sp);
state->_sp += 4;
return *stack;
}
}
WORD PEEK16(struct vcpu_state_t *state, int i)
{
if (state->_ss.operand_size)
{
LPWORD stack = (LPWORD)(state->_ss.base + state->_esp);
return stack[i];
}
else
{
LPWORD stack = (LPWORD)(state->_ss.base + state->_sp);
return stack[i];
}
}
DWORD PEEK32(struct vcpu_state_t *state, int i)
{
if (state->_ss.operand_size)
{
LPDWORD stack = (LPDWORD)(state->_ss.base + state->_esp);
return stack[i];
}
else
{
LPDWORD stack = (LPDWORD)(state->_ss.base + state->_sp);
return stack[i];
}
}
void relay(LPVOID relay_func, BOOL reg, struct vcpu_state_t *state, DWORD ret_addr, DWORD cbArgs, PEXCEPTION_HANDLER handler, DWORD old_frame16)
{
unsigned char *stack1 = (unsigned char*)(state->_ss.base + state->_sp);
unsigned char *stack = stack1;
/*
* (sp+24) word first 16-bit arg
* (sp+22) word cs
* (sp+20) word ip
* (sp+18) word bp
* (sp+14) long 32-bit entry point (reused for Win16 mutex recursion count)
* (sp+12) word ip of actual entry point (necessary for relay debugging)
* (sp+8) long relay (argument conversion) function entry point
* (sp+4) long cs of 16-bit entry point
* (sp) long ip of 16-bit entry point
*/
DWORD ip = *(DWORD*)stack;
stack += sizeof(DWORD);
DWORD cs = *(DWORD*)stack;
stack += sizeof(DWORD);
DWORD relay = *(DWORD*)stack;
stack += sizeof(DWORD);
WORD ip2 = *(WORD*)stack;
stack += sizeof(WORD);
DWORD entry = *(DWORD*)stack;
//for debug
void *entryf = (void*)entry;
stack += sizeof(DWORD);
WORD bp = *(WORD*)stack;
stack += sizeof(WORD);
WORD ip19 = *(WORD*)stack;
stack += sizeof(WORD);
WORD cs16 = *(WORD*)stack;
stack += sizeof(WORD);
WORD *args = (WORD*)stack;
state->_eip = ip;
load_seg(&state->_cs, (WORD)cs);
#include
/* 16-bit stack layout after __wine_call_from_16() */
typedef struct _STACK16FRAME
{
struct STACK32FRAME *frame32; /* 00 32-bit frame from last CallTo16() */
DWORD edx; /* 04 saved registers */
DWORD ecx; /* 08 */
DWORD ebp; /* 0c */
WORD ds; /* 10 */
WORD es; /* 12 */
WORD fs; /* 14 */
WORD gs; /* 16 */
DWORD callfrom_ip; /* 18 callfrom tail IP */
DWORD module_cs; /* 1c module code segment */
DWORD relay; /* 20 relay function address */
WORD entry_ip; /* 22 entry point IP */
DWORD entry_point; /* 26 API entry point to call, reused as mutex count */
WORD bp; /* 2a 16-bit stack frame chain */
WORD ip; /* 2c return address */
WORD cs; /* 2e */
} STACK16FRAME;
#include
CONTEXT context;
STACK32FRAME dummy_stack32 = { 0 };
dummy_stack32.retaddr = ret_addr;
dummy_stack32.nb_args = cbArgs;
dummy_stack32.frame.Handler = handler;
DWORD osp = state->_esp;
PUSH16(state, state->_gs.selector);
PUSH16(state, state->_fs.selector);
PUSH16(state, state->_es.selector);
PUSH16(state, state->_ds.selector);
PUSH32(state, state->_ebp);
PUSH32(state, state->_ecx);
PUSH32(state, state->_edx);
PUSH32(state, osp);
save_context_from_state(&context, state);
STACK16FRAME *oa = (STACK16FRAME*)wine_ldt_get_ptr((WORD)context.SegSs, context.Esp);
DWORD ooo = (WORD)context.Esp;
int off = 0;
if (reg)
{
context.Esp = osp + (SIZE_T)stack - (SIZE_T)stack1 - 4;
off = ooo - context.Esp;
context.Ebp = (context.Ebp & ~0xffff) | bp;
context.Eip = ip19;
context.SegCs = cs16;
}
int fret;
LPVOID old;
PCONTEXT pctx = NULL;
#if _MSC_VER
__asm
{
mov old, esp
push cbArgs
push old /* target(esp) */
push retaddr /* retaddr */
push ebp
push ebx
push esi
push edi
push old_frame16 /* frame16 */
/* set up exception handler */
push handler
mov eax, fs:[0]
push eax
mov dummy_stack32.frame.Next, eax
mov fs : [0], esp
push cs
push 0
mov eax, [oa]
mov[eax], esp
lea eax, [context]
push eax
push args
push entry
call relay_func
add esp, 12 + 8
mov fret, eax
pop dword ptr fs : [0]
pop eax
jmp skip
retaddr :
mov pctx, ecx
skip:
mov esp, old
}
#else
fret = ((int(*)(void *entry_point, unsigned char *args16, CONTEXT *context))relay_func)((void*)entry, (unsigned char*)args, &context);
#endif
if (!reg)
{
state->_eax = fret;
}
if (pctx)
{
/* Throw16 */
context = *pctx;
reg = TRUE;
}
if (!reg)
{
state->_eax = fret;
context.SegSs = ((size_t)dynamic_getWOW32Reserved() >> 16) & 0xFFFF;
context.Esp = ((size_t)dynamic_getWOW32Reserved()) & 0xFFFF;
oa = (STACK16FRAME*)wine_ldt_get_ptr(context.SegSs, context.Esp);
}
else
{
oa = (STACK16FRAME*)wine_ldt_get_ptr(context.SegSs, context.Esp + off);
}
if (reg) state->_eax = (DWORD)context.Eax;
state->_ecx = reg ? (DWORD)context.Ecx : (DWORD)oa->ecx;
if (reg) state->_edx = (DWORD)context.Edx;
else
state->_edx = (DWORD)oa->edx;
state->_ebx = (DWORD)context.Ebx;
state->_esp = (DWORD)context.Esp;
state->_ebp = (DWORD)context.Ebp;
state->_esi = (DWORD)context.Esi;
state->_edi = (DWORD)context.Edi;
load_seg(&state->_es, reg ? (WORD)context.SegEs : (WORD)oa->es);
load_seg(&state->_ss, (WORD)context.SegSs);
load_seg(&state->_ds, reg ? (WORD)context.SegDs : (WORD)oa->ds);
//ES, CS, SS, DS, FS, GS
/* Some programs expect that gs is not a valid selector! */
/* Some programs expect that fs is not a valid selector! */
/* win16 sets 0? */
load_seg(&state->_fs, 0);//(WORD)context.SegFs == reg_fs ? 0 : context.SegFs;
load_seg(&state->_gs, 0);//(WORD)context.SegGs == reg_gs ? 0 : context.SegGs;
if (reg)
{
if (!(ip19 != context.Eip || cs16 != context.SegCs))
{
context.Eip = oa->callfrom_ip;
context.SegCs = oa->module_cs;
}
else
{
/* CS:IP changed! */
context.Eip = context.Eip;
}
state->_esp = context.Esp;
state->_ebp = context.Ebp;
}
else
{
state->_esp = osp + 18 + 2;
state->_esp -= (ooo - context.Esp);
WORD bpp = state->_esp;
state->_esp = context.Esp + 0x2c;
state->_bp = bp;
}
set_eflags(state, context.EFlags);
state->_eip = context.Eip;
load_seg(&state->_cs, (WORD)context.SegCs);
}
LPBYTE get_base_addr(WORD sel)
{
return wine_ldt_get_base(wine_ldt + (sel >> 3));
}
static uint64 dr7;
void set_break_point(struct vcpu_state_t *state, WORD sel, DWORD addr, int breakpoint)
{
LPBYTE base = get_base_addr(sel);
if (!base)
return;
if (wine_ldt_get_limit(wine_ldt + (sel >> 3)) < addr)
return;
uint64 linear = (uint64)base + addr;
switch (breakpoint)
{
case 0:
state->_dr0 = linear;
break;
case 1:
state->_dr1 = linear;
break;
case 2:
state->_dr2 = linear;
break;
case 3:
state->_dr3 = linear;
break;
default:
return;
}
state->_dr7 |= (1 << (2 * breakpoint + 1)) | (0 << (18 + 4 * breakpoint));
state->_dr6 = 0;
}
typedef int disassemble_debug_t(char *buffer, UINT8 *oprom, BOOL op_size, UINT64 eip);
static disassemble_debug_t *disassemble_debug;
static void trace(struct vcpu_state_t *state, uint16 cs, uint32 eip, uint16 ss, uint32 esp, uint32 eflags)
{
char buf[512];
UINT8 *d = get_base_addr(cs) + eip;
if (!disassemble_debug)
{
disassemble_debug = (disassemble_debug_t*)GetProcAddress(LoadLibraryA("vm86.dll"), "disassemble_debug");
}
int len = disassemble_debug(buf, d, (wine_ldt_get_flags(wine_ldt + (cs >> 3)) & WINE_LDT_FLAGS_32BIT) == WINE_LDT_FLAGS_32BIT, eip);
int i;
fprintf(stderr, "%04x:%04x\t", cs, eip);
for (i = 0; i < len; i++)
{
fprintf(stderr, "%02x", d[i]);
}
fprintf(stderr, "\t%s\n", buf);
eflags &= ~2;
eflags &= ~0x100;
eflags |= 0x200;
if (state->_fs.selector || state->_gs.selector)
{
fprintf(stderr,
"EAX:%04X,ECX:%04X,EDX:%04X,EBX:%04X,"
"ESP:%04X,EBP:%04X,ESI:%04X,EDI:%04X,"
"ES:%04X,CS:%04X,SS:%04X,DS:%04X,FS:%04x,GS:%04x,"
"IP:%04X,stack:%08X,"
"EFLAGS:%08X"
"\n",
state->_eax, state->_ecx, state->_edx, state->_ebx,
esp, state->_ebp, state->_esi, state->_edi,
state->_es.selector, cs, ss, state->_ds.selector, state->_fs.selector, state->_gs.selector,
eip, *(LPDWORD)(get_base_addr(ss) + esp),
eflags
);
}
else
{
fprintf(stderr,
"EAX:%04X,ECX:%04X,EDX:%04X,EBX:%04X,"
"ESP:%04X,EBP:%04X,ESI:%04X,EDI:%04X,"
"ES:%04X,CS:%04X,SS:%04X,DS:%04X,"
"IP:%04X,stack:%08X,"
"EFLAGS:%08X"
"\n",
state->_eax, state->_ecx, state->_edx, state->_ebx,
esp, state->_ebp, state->_esi, state->_edi,
state->_es.selector, cs, ss, state->_ds.selector,
eip, *(LPDWORD)(get_base_addr(ss) + esp),
eflags
);
}
}
BOOL has_x86_exception_err(WORD num)
{
switch (num)
{
case 0:case 1:case 2:case 3:case 4:case 5:case 6:case 7:
return FALSE;
case 8:
return TRUE;
case 9:
return FALSE;
case 10:case 11:case 12:case 13:case 14:
return TRUE;
case 15:case 16:
return FALSE;
case 17:
return TRUE;
case 18:case 19:case 20:case 21:case 22:case 23:case 24:case 25:case 26:case 27:case 28:case 29:
return FALSE;
case 30:
return TRUE;
case 31:
return FALSE;
}
return FALSE;
}
BOOL workaround_watcom(struct vcpu_state_t *state, uint16 cs, uint32 eip)
{
/* workaround for Watcom C 8.5 win386 startup */
const unsigned char startup[] = {
0xbf, 0x02, 0x00,
0x26, 0x8a, 0x2f,
0x26, 0x8a, 0x0f,
0x3a, 0xe9,
0x74, 0xf9,
0x26, 0x8a, 0x0f,
0x26, 0x3a, 0x0f,
0x75, 0x10,
0x2d, 0x01, 0x00,
0x83, 0xda, 0x00,
0x8a, 0xec,
0x0a, 0xe8,
0x0a, 0xee,
0x0a, 0xea,
0x75, 0xeb,
0x4f,
0x75, 0xe5,
0xf7, 0xda,
0xf7, 0xd8,
0x83, 0xda, 0x00,
0xb9, 0x6e, 0x00,
};
const unsigned char *code = get_base_addr(cs) + eip;
if (!memcmp(code - sizeof(startup), startup, sizeof(startup)) && code[0] == 0xf7 && code[1] == 0xf1) /* div ax, cx */
{
state->_dx = 0;
return TRUE;
}
return FALSE;
}
BOOL syscall_init = FALSE;
LPBYTE syscall_trap = FALSE;
void fstsw(WORD* a);
void vm86main(CONTEXT *context, DWORD cbArgs, PEXCEPTION_HANDLER handler,
void(*from16_reg)(void),
LONG(*__wine_call_from_16)(void),
int(*relay_call_from_16)(void *entry_point, unsigned char *args16, CONTEXT *context),
void(*__wine_call_to_16_ret)(void),
int dasm,
pm_interrupt_handler pih
)
{
DWORD old_frame16 = PtrToUlong(dynamic_getWOW32Reserved());
if (!initflag)
{
haxmvm_panic("Could not initialize the hypervisor.\nHAXM may not be installed.\n");
}
if (tunnel->_exit_status == HAX_EXIT_STATECHANGE)
{
haxmvm_panic("hypervisor is panicked!!!");
}
if (!syscall_init)
{
SIZE_T page1 = (SIZE_T)from16_reg / 4096 * 4096;
SIZE_T page2 = (SIZE_T)__wine_call_from_16 / 4096 * 4096;
SIZE_T page3 = (SIZE_T)__wine_call_to_16_ret / 4096 * 4096;
LPBYTE trap = syscall_trap = (LPBYTE)VirtualAlloc(NULL, 4096, MEM_COMMIT, PAGE_READWRITE);
memset(trap, 0xEE, 4096); /* out forces a vmexit from user mode without modifing any registers */
struct hax_alloc_ram_info alloc_ram = { 0 };
struct hax_set_ram_info ram = { 0 };
alloc_ram.size = 4096;
alloc_ram.va = trap;
DWORD bytes;
if (!DeviceIoControl(hVM, HAX_VM_IOCTL_ALLOC_RAM, &alloc_ram, sizeof(alloc_ram), NULL, 0, &bytes, NULL))
{
HAXMVM_ERRF("ALLOC_RAM");
}
ram.pa_start = (SIZE_T)trap;
ram.size = (SIZE_T)4096;
ram.va = (SIZE_T)trap;
if (!DeviceIoControl(hVM, HAX_VM_IOCTL_SET_RAM, &ram, sizeof(ram), NULL, 0, &bytes, NULL))
{
HAXMVM_ERRF("SET_RAM\n");
}
guestpt[page1 >> 12] = (DWORD)trap | 7;
guestpt[page2 >> 12] = (DWORD)trap | 7;
guestpt[page3 >> 12] = (DWORD)trap | 7;
syscall_init = TRUE;
}
is_single_step = dasm;
MEMORY_BASIC_INFORMATION mbi;
DWORD bytes;
DWORD ret_addr;
struct vcpu_state_t state_ini;
{
DWORD bytes;
struct vcpu_state_t state;
if (!DeviceIoControl(hVCPU, HAX_VCPU_GET_REGS, NULL, 0, &state, sizeof(state), &bytes, NULL))
HAXMVM_ERRF("GET_REGS");
load_seg(&state._gs, (WORD)0);
load_seg(&state._fs, (WORD)0);
load_seg(&state._es, (WORD)context->SegEs);
load_seg(&state._ds, (WORD)context->SegDs);
load_seg(&state._cs, (WORD)context->SegCs);
load_seg(&state._ss, (WORD)context->SegSs);
state._edi = context->Edi;
state._esi = context->Esi;
state._ebx = context->Ebx;
state._edx = context->Edx;
state._ecx = context->Ecx;
state._eax = context->Eax;
state._ebp = context->Ebp;
state._eip = context->Eip;
set_eflags(&state, context->EFlags);
state._esp = context->Esp - cbArgs;
if (!DeviceIoControl(hVCPU, HAX_VCPU_SET_REGS, &state, sizeof(state), NULL, 0, &bytes, NULL))
HAXMVM_ERRF("SET_REGS");
unsigned char *stack = (unsigned char*)state._ss.base + state._esp;
ret_addr = (*(LPDWORD)stack) + 1;
}
struct vcpu_state_t state2;
DeviceIoControl(hVCPU, HAX_VCPU_GET_REGS, NULL, 0, &state2, sizeof(state2), &bytes, NULL);
if (is_single_step)
{
trace(&state2, state2._cs.selector, state2._eip, state2._ss.selector, state2._esp, state2._eflags);
}
while (TRUE)
{
dprintf("run %04X:%04X(base:%04llX) ESP:%08X F:%08X CS:%08X\n", state2._cs.selector, state2._eip, state2._cs.base, state2._esp, state2._eflags, state2._cs.ar);
if (state2._cs.selector == (ret_addr >> 16) && state2._eip == (ret_addr & 0xFFFF))
{
if (!DeviceIoControl(hVCPU, HAX_VCPU_SET_REGS, &state2, sizeof(state2), NULL, 0, &bytes, NULL))
{
HAXMVM_ERRF("SET_REGS");
}
break;
}
if (is_single_step)
{
/* Debug exception */
fprintf(stderr, "%04x:%04x EAX:%04x EDX:%04x EF:%04x %p\n", state2._cs.selector, state2._eip,
state2._eax, state2._edx, state2._eflags, (LPBYTE)state2._cs.base + state2._eip);
}
if (!DeviceIoControl(hVCPU, HAX_VCPU_IOCTL_RUN, NULL, 0, NULL, 0, &bytes, NULL))
return;
DeviceIoControl(hVCPU, HAX_VCPU_GET_REGS, NULL, 0, &state2, sizeof(state2), &bytes, NULL);
dprintf("end %04X:%04X(base:%04llX) ESP:%08X F:%08X\n", state2._cs.selector, state2._eip, state2._cs.base, state2._esp, state2._eflags);
if (state2._cs.selector == (ret_addr >> 16) && state2._eip == (ret_addr & 0xFFFF))
{
if (!DeviceIoControl(hVCPU, HAX_VCPU_SET_REGS, &state2, sizeof(state2), NULL, 0, &bytes, NULL))
{
HAXMVM_ERRF("SET_REGS");
}
break;
}
LPVOID ptr = (LPBYTE)state2._cs.base + state2._eip;
switch(tunnel->_exit_status)
{
case HAX_EXIT_IO:
if (tunnel->io._direction == HAX_IO_OUT)
{
LPBYTE ptr2 = (LPBYTE)ptr - 1;
BOOL is_reg = ptr2 == from16_reg;
if (is_reg || ptr2 == __wine_call_from_16)
{
relay(relay_call_from_16, is_reg, &state2, ret_addr, cbArgs, handler, old_frame16);
if (!DeviceIoControl(hVCPU, HAX_VCPU_SET_REGS, &state2, sizeof(state2), NULL, 0, &bytes, NULL))
{
HAXMVM_ERRF("SET_REGS");
}
break;
}
}
else if (tunnel->io._direction == HAX_IO_IN)
{
printf("");
}
break;
case HAX_EXIT_HLT:
if (((DWORD)ptr >= (DWORD)trap_int) && ((DWORD)ptr <= ((DWORD)trap_int + 256)))
{
int intvec = ((DWORD)ptr & 0xff) - 1;
BOOL has_err = has_x86_exception_err(intvec);
DWORD err = has_err ? PEEK32(&state2, 0) : 0;
DWORD eip = PEEK32(&state2, (has_err ? 1 : 0) + 0);
DWORD cs = PEEK32(&state2, (has_err ? 1 : 0) + 1);
DWORD flags = PEEK32(&state2, (has_err ? 1 : 0) + 2);
DWORD old_esp = PEEK32(&state2, (has_err ? 1 : 0) + 3);
DWORD old_ss = PEEK32(&state2, (has_err ? 1 : 0) + 4);
const char *name = NULL;
switch (intvec)
{
case 0: name = "#DE"; break;
case 2: name = "int 2h"; break;
case 4: name = "#OF"; break;
case 6: name = "#UD"; break;
case 7: name = "#NM"; break;
case 8: name = "#DF"; break;
case 10: name = "#TS"; break;
case 11: name = "#NP"; break;
case 12: name = "#SS"; break;
case 13: name = "#GP"; break;
case 14: name = "#PF"; break;
}
state2._eip = 256;
if (intvec == 1 && (state2._dr6 & 15 || is_single_step))
{
if (state2._dr6 & 15)
{
if (state2._dr6 & 1)
{
fprintf(stderr, "breakpoint 0\n");
}
if (state2._dr6 & 2)
{
fprintf(stderr, "breakpoint 1\n");
}
if (state2._dr6 & 4)
{
fprintf(stderr, "breakpoint 2\n");
}
if (state2._dr6 & 8)
{
fprintf(stderr, "breakpoint 3\n");
}
state2._dr6 = 0;
flags |= 0x100;
dr7 = state2._dr7;
state2._dr7 = 0;
/* breakpoint -> disable -> step -> enable */
}
else if (!is_single_step)
{
flags &= ~0x100;
state2._dr7 = dr7;
}
trace(&state2, cs, eip, old_ss, old_esp, flags);
state2._eip = 256;
break;
}
dprintf("err:%X flg:%08X %04X:%04X\n", err, flags, cs, eip);
if (intvec == 0x0e)
{
alloc_ram(state2._cr2 & ~0xfff, 4096);
state2._esp += 4;
}
else if (name)
{
if (intvec == 0)
{
if (workaround_watcom(&state2, cs, eip))
{
break;
}
}
if (intvec == 0x0d)
{
if (err == 0x40)
{
/* many startups access the BDA directly */
static WORD dosmem_0040H = 0;
if (!dosmem_0040H)
{
DWORD(WINAPI *GetProcAddress16)(HMODULE16, LPCSTR);
HMODULE16(WINAPI *GetModuleHandle16)(LPCSTR);
static HMODULE krnl386;
if (!krnl386)
krnl386 = LoadLibraryA(KRNL386);
GetProcAddress16 = (DWORD(WINAPI *)(HMODULE16, LPCSTR))GetProcAddress(krnl386, "GetProcAddress16");
GetModuleHandle16 = (HMODULE16(WINAPI *)(LPCSTR))GetProcAddress(krnl386, "GetModuleHandle16");
dosmem_0040H = (WORD)GetProcAddress16(GetModuleHandle16("KERNEL"), (LPCSTR)193);
(void(*)(void))GetProcAddress(krnl386, "DOSVM_start_bios_timer")();
}
err = POP32(&state2);
eip = POP32(&state2);
cs = POP32(&state2);
flags = POP32(&state2);
old_esp = POP32(&state2);
old_ss = POP32(&state2);
/* allocate segment 40h */
LPLDT_ENTRY entry = wine_ldt + (dosmem_0040H >> __AHSHIFT);
gdt[0x40 >> __AHSHIFT] = *entry;
load_seg(&state2._cs, cs);
state2._eip = eip;
set_eflags(&state2, flags & ~0x10000);
load_seg(&state2._ss, old_ss);
state2._esp = old_esp;
break;
}
}
DWORD handler = pih(intvec, MAKESEGPTR(cs, eip));
if (!handler)
{
trace(&state2, cs, eip, old_ss, old_esp, flags);
HAXMVM_ERRF("%s %02x %04x %04x:%04x %04x:%04x", name, intvec, err, cs, eip, old_ss, old_esp);
HAXMVM_ERRF("%04X:%04X(base:%04llX) ESP:%08X", state2._cs.selector, state2._eip, state2._cs.base, state2._esp);
HAXMVM_ERRF("exception");
haxmvm_panic("exception %s", name);
}
if (has_err)
{
err = POP32(&state2);
}
eip = POP32(&state2);
cs = POP32(&state2);
flags = POP32(&state2);
old_esp = POP32(&state2);
old_ss = POP32(&state2);
state2._eip = OFFSETOF(handler);
set_eflags(&state2, flags);
load_seg(&state2._cs, SELECTOROF(handler));
load_seg(&state2._ss, old_ss);
state2._esp = old_esp;
}
else
{
DWORD eip = POP32(&state2);
DWORD cs = POP32(&state2);
DWORD eflags = POP32(&state2);
DWORD esp = POP32(&state2);
DWORD ss = POP32(&state2);
load_seg(&state2._cs, (WORD)cs);
state2._eip = eip;
load_seg(&state2._ss, (WORD)ss);
state2._esp = esp;
CONTEXT ctx;
save_context_from_state(&ctx, &state2);
if (!DeviceIoControl(hVCPU, HAX_VCPU_SET_REGS, &state2, sizeof(state2), NULL, 0, &bytes, NULL))
{
HAXMVM_ERRF("SET_REGS");
}
if (intvec == 0x10) // redirect fpu errors to int 13h
{
WORD sw;
fstsw(&sw);
if (sw & 0x80)
intvec = 2;
}
dynamic__wine_call_int_handler(&ctx, intvec);
load_context_to_state(&ctx, &state2);
}
}
break;
case HAX_EXIT_INTERRUPT: //TODO: vm_inject
break;
case HAX_EXIT_STATECHANGE:
default:
HAXMVM_ERRF("%04X:%04X(base:%04llX) ESP:%08X", state2._cs.selector, state2._eip, state2._cs.base, state2._esp);
HAXMVM_ERRF("hypervisor is panicked!!!");
haxmvm_panic("hypervisor is panicked!!!");
}
if (!DeviceIoControl(hVCPU, HAX_VCPU_SET_REGS, &state2, sizeof(state2), NULL, 0, &bytes, NULL))
{
HAXMVM_ERRF("SET_REGS");
}
}
save_context(context);
}
__declspec(dllexport) DWORD wine_call_to_16_vm86(DWORD target, DWORD cbArgs, PEXCEPTION_HANDLER handler,
void(*from16_reg)(void),
LONG(*__wine_call_from_16)(void),
int(*relay_call_from_16)(void *entry_point, unsigned char *args16, CONTEXT *context),
void(*__wine_call_to_16_ret)(void),
int dasm,
BOOL vm86,
void *memory_base,
pm_interrupt_handler pih)
{
mem = vm86 ? (UINT8*)memory_base : NULL;
if (!initflag)
initflag = init_vm86(vm86);
CONTEXT context;
PVOID oldstack = dynamic_getWOW32Reserved();
save_context(&context);
//why??
dynamic_setWOW32Reserved(oldstack);
context.SegSs = ((size_t)dynamic_getWOW32Reserved() >> 16) & 0xFFFF;
context.Esp = ((size_t)dynamic_getWOW32Reserved()) & 0xFFFF;
context.SegCs = target >> 16;
context.Eip = target & 0xFFFF;//i386_jmp_far(target >> 16, target & 0xFFFF);
vm86main(&context, cbArgs, handler, from16_reg, __wine_call_from_16, relay_call_from_16, __wine_call_to_16_ret, dasm, pih);
return (context.Eax & 0xffff) | context.Edx << 16;
}
__declspec(dllexport) void wine_call_to_16_regs_vm86(CONTEXT *context, DWORD cbArgs, PEXCEPTION_HANDLER handler,
void(*from16_reg)(void),
LONG(*__wine_call_from_16)(void),
int(*relay_call_from_16)(void *entry_point, unsigned char *args16, CONTEXT *context),
void(*__wine_call_to_16_ret)(void),
int dasm,
BOOL vm86,
void *memory_base,
pm_interrupt_handler pih
)
{
mem = vm86 ? (UINT8*)memory_base : NULL;
if (!initflag)
initflag = init_vm86(vm86);
vm86main(context, cbArgs, handler, from16_reg, __wine_call_from_16, relay_call_from_16, __wine_call_to_16_ret, dasm, pih);
}
SIZE_T base = 0;
SIZE_T x87func = 0x200 - 0x10;
void callx87(const char *addr, LPCVOID eax)
{
DWORD bytes;
struct vcpu_state_t state;
DeviceIoControl(hVCPU, HAX_VCPU_GET_REGS, NULL, 0, &state, sizeof(state), &bytes, NULL);
state._rip = addr;
state._eax = eax;
load_seg(&state._cs, seg_cs);
load_seg(&state._ds, seg_ds);
while (TRUE)
{
DeviceIoControl(hVCPU, HAX_VCPU_SET_REGS, &state, sizeof(state), NULL, 0, &bytes, NULL);
if (!DeviceIoControl(hVCPU, HAX_VCPU_IOCTL_RUN, NULL, 0, NULL, 0, &bytes, NULL))
return;
DeviceIoControl(hVCPU, HAX_VCPU_GET_REGS, NULL, 0, &state, sizeof(state), &bytes, NULL);
if (tunnel->_exit_status == HAX_EXIT_HLT)
{
struct vcpu_state_t state2 = state;
LPVOID ptr = (LPBYTE)state2._cs.base + state2._eip;
if (((DWORD)ptr >= (DWORD)trap_int) && ((DWORD)ptr <= ((DWORD)trap_int + 256)))
{
int intvec = ((DWORD)ptr & 0xff) - 1;
state2._eip = 256;
if (intvec == 0x0e)
{
alloc_ram(state2._cr2 & ~0xfff, 4096);
state2._esp += 4;
}
else
break;
}
else
break;
state = state2;
}
else
break;
}
if (tunnel->_exit_status == HAX_EXIT_STATECHANGE)
{
HAXMVM_ERRF("hypervisor is panicked!!!");
haxmvm_panic("win87em: hypervisor is panicked!!!");
}
}
/* x87 service functions */
static BOOL get_fpu_regs(struct fx_layout *fx)
{
if (!DeviceIoControl(hVCPU, HAX_VCPU_IOCTL_GET_FPU, NULL, 0, fx, sizeof(*fx), NULL, NULL))
{
HAXMVM_ERRF("HAX_VCPU_IOCTL_GET_FPU");
return FALSE;
}
return TRUE;
}
static BOOL set_fpu_regs(struct fx_layout *fx)
{
if (!DeviceIoControl(hVCPU, HAX_VCPU_IOCTL_SET_FPU, fx, sizeof(*fx), NULL, 0, NULL, NULL))
{
HAXMVM_ERRF("HAX_VCPU_IOCTL_SET_FPU");
return FALSE;
}
return TRUE;
}
void fldcw(WORD a)
{
struct fx_layout fx;
if (!get_fpu_regs(&fx))
{
return;
}
fx.fcw = a;
if (!set_fpu_regs(&fx))
{
return;
}
}
void wait()
{
char instr[] = { 0x9b, 0xee }; /* wait */
callx87(instr, NULL);
}
void fninit()
{
char instr[] = { 0xdb, 0xe3, 0xee }; /* fninit */
callx87(instr, NULL);
}
void fstcw(WORD* a)
{
struct fx_layout fx;
if (!get_fpu_regs(&fx))
{
return;
}
*a = fx.fcw;
}
void fstsw(WORD* a)
{
struct fx_layout fx;
if (!get_fpu_regs(&fx))
{
return;
}
*a = fx.fsw;
}
void frndint()
{
char instr[] = { 0xd9, 0xfc, 0xee }; /* frndint */
callx87(instr, NULL);
}
void fclex()
{
char instr[] = { 0xdb, 0xe2, 0xee }; /* fnclex */
callx87(instr, NULL);
}
void fsave(char* a)
{
char instr[] = { 0xdd, 0x30, 0xee }; /* fnsave [eax] */
callx87(instr, a);
}
void frstor(const char* a)
{
char instr[] = { 0xdd, 0x20, 0xee }; /* frstor [eax] */
callx87(instr, a);
}
void fstenv32(char* a)
{
const char instr[] = { 0xd9, 0x30, 0xee }; /* fnstenv dword ptr [eax] */
callx87(instr, a);
}
typedef void(*fldcw_t)(WORD);
typedef void(*wait_t)();
typedef void(*fninit_t)();
typedef void(*fstcw_t)(WORD*);
typedef void(*fstsw_t)(WORD*);
typedef void(*frndint_t)();
typedef void(*fclex_t)();
typedef void(*fsave_t)(char*);
typedef void(*fstenv32_t)(char*);
typedef void(*frstor_t)(const char*);
typedef DWORD(*fistp_t)(WORD);
typedef struct
{
fldcw_t fldcw;
wait_t wait;
fninit_t fninit;
fstcw_t fstcw;
fstsw_t fstsw;
frndint_t frndint;
fclex_t fclex;
fsave_t fsave;
frstor_t frstor;
fstenv32_t fstenv32;
fistp_t fistp;
} x87function;
__declspec(dllexport) void load_x87function(x87function *func)
{
func->fclex = fclex;
func->fldcw = fldcw;
func->fninit = fninit;
func->frndint = frndint;
func->frstor = frstor;
func->fsave = fsave;
func->fstcw = fstcw;
func->fstsw = fstsw;
func->wait = wait;
func->fstenv32 = fstenv32;
}
================================================
FILE: haxmvm/haxmvm.h
================================================
#pragma once
#include
#include
#include
// Signed Types
typedef signed char int8;
typedef signed short int16;
typedef signed int int32;
typedef signed long long int64;
// Unsigned Types
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint32;
typedef unsigned int uint;
typedef unsigned long long uint64;
typedef unsigned long ulong;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;
typedef unsigned long ulong_t;
/* Common typedef for all platform */
typedef uint64 hax_pa_t;
typedef uint64 hax_pfn_t;
typedef uint64 paddr_t;
typedef uint64 vaddr_t;
#include
struct hax_module_version {
uint32_t compat_version;
uint32_t cur_version;
};
struct vmx_msr {
uint64_t entry;
uint64_t value;
};
#define HAX_MAX_MSR_ARRAY 0x20
struct hax_msr_data {
uint16_t nr_msr;
uint16_t done;
uint16_t pad[2];
struct vmx_msr entries[HAX_MAX_MSR_ARRAY];
};
struct hax_set_ram_info {
uint64_t pa_start;
uint32_t size;
uint8_t flags;
uint8_t pad[3];
uint64_t va;
};
struct hax_alloc_ram_info {
uint32_t size;
uint32_t pad;
uint64_t va;
};
union interruptibility_state_t {
uint32 raw;
struct {
uint32 sti_blocking : 1;
uint32 movss_blocking : 1;
uint32 smi_blocking : 1;
uint32 nmi_blocking : 1;
uint32 reserved : 28;
};
uint64_t pad;
};
typedef union interruptibility_state_t interruptibility_state_t;
struct segment_desc_t {
uint16 selector;
uint16 _dummy;
uint32 limit;
uint64 base;
union {
struct {
uint32 type : 4;
uint32 desc : 1;
uint32 dpl : 2;
uint32 present : 1;
uint32 : 4;
uint32 available : 1;
uint32 long_mode : 1;
uint32 operand_size : 1;
uint32 granularity : 1;
uint32 null : 1;
uint32 : 15;
};
uint32 ar;
};
uint32 ipad;
};
typedef struct segment_desc_t segment_desc_t;
struct vcpu_state_t {
union {
uint64 _regs[16];
struct {
union {
struct {
uint8 _al,
_ah;
};
uint16 _ax;
uint32 _eax;
uint64 _rax;
};
union {
struct {
uint8 _cl,
_ch;
};
uint16 _cx;
uint32 _ecx;
uint64 _rcx;
};
union {
struct {
uint8 _dl,
_dh;
};
uint16 _dx;
uint32 _edx;
uint64 _rdx;
};
union {
struct {
uint8 _bl,
_bh;
};
uint16 _bx;
uint32 _ebx;
uint64 _rbx;
};
union {
uint16 _sp;
uint32 _esp;
uint64 _rsp;
};
union {
uint16 _bp;
uint32 _ebp;
uint64 _rbp;
};
union {
uint16 _si;
uint32 _esi;
uint64 _rsi;
};
union {
uint16 _di;
uint32 _edi;
uint64 _rdi;
};
uint64 _r8;
uint64 _r9;
uint64 _r10;
uint64 _r11;
uint64 _r12;
uint64 _r13;
uint64 _r14;
uint64 _r15;
};
};
union {
uint32 _eip;
uint64 _rip;
};
union {
uint32 _eflags;
uint64 _rflags;
};
segment_desc_t _cs;
segment_desc_t _ss;
segment_desc_t _ds;
segment_desc_t _es;
segment_desc_t _fs;
segment_desc_t _gs;
segment_desc_t _ldt;
segment_desc_t _tr;
segment_desc_t _gdt;
segment_desc_t _idt;
uint64 _cr0;
uint64 _cr2;
uint64 _cr3;
uint64 _cr4;
uint64 _dr0;
uint64 _dr1;
uint64 _dr2;
uint64 _dr3;
uint64 _dr6;
uint64 _dr7;
uint64 _pde;
uint32 _efer;
uint32 _sysenter_cs;
uint64 _sysenter_eip;
uint64 _sysenter_esp;
uint32 _activity_state;
uint32 pad;
interruptibility_state_t _interruptibility_state;
};
/* This interface is support only after API version 2 */
struct hax_qemu_version {
/* Current API version in QEMU*/
uint32_t cur_version;
/* The least API version supported by QEMU */
uint32_t least_version;
};
#define HAX_IO_OUT 0
#define HAX_IO_IN 1
struct hax_tunnel_info {
uint64_t va;
uint64_t io_va;
uint16_t size;
uint16_t pad[3];
};
typedef enum exit_status {
HAX_EXIT_IO = 1,
HAX_EXIT_MMIO,
HAX_EXIT_REALMODE,
HAX_EXIT_INTERRUPT,
HAX_EXIT_UNKNOWN,
HAX_EXIT_HLT,
HAX_EXIT_STATECHANGE,
HAX_EXIT_PAUSED,
HAX_EXIT_FAST_MMIO,
HAX_EXIT_PAGEFAULT
} exit_status;
typedef enum exit_reason {
EXIT_INTERRUPT_WIN = 0x07,
EXIT_HLT = 0x0c,
EXIT_INTERRUPT = 0x30
} exit_reason;
struct hax_tunnel {
exit_reason _exit_reason;
uint32_t pad0;
exit_status _exit_status;/* exit_status */
uint32_t user_event_pending;
int ready_for_interrupt_injection;
int request_interrupt_window;
union {
struct {
uint8_t _direction;
uint8_t _df;
uint16_t _size;
uint16_t _port;
uint16_t _count;
/* Followed owned by HAXM, QEMU should not touch them */
/* bit 1 is 1 means string io */
uint8_t _flags;
uint8_t _pad0;
uint16_t _pad1;
uint32_t _pad2;
vaddr_t _vaddr;
} io;
struct {
paddr_t gla;
} mmio;
struct {
paddr_t gpa;
#define HAX_PAGEFAULT_ACC_R (1 << 0)
#define HAX_PAGEFAULT_ACC_W (1 << 1)
#define HAX_PAGEFAULT_ACC_X (1 << 2)
#define HAX_PAGEFAULT_PERM_R (1 << 4)
#define HAX_PAGEFAULT_PERM_W (1 << 5)
#define HAX_PAGEFAULT_PERM_X (1 << 6)
uint32_t flags;
uint32_t reserved1;
uint64_t reserved2;
} pagefault;
struct {
paddr_t dummy;
} state;
};
uint64_t apic_base;
};
enum run_flag {
HAX_EXIT = 0,
HAX_RESUME = 1
};
#define HAX_RAM_INFO_ROM (1 << 0)
#define HAX_RAM_INFO_STANDALONE (1 << 6)
#define HAX_RAM_INFO_INVALID (1 << 7)
#include
struct hax_vcpu_mem {
uint32_t size;
uint64_t uva;
void *kva;
void *hinfo;
};
#include
struct fx_layout {
uint16 fcw;
uint16 fsw;
uint8 ftw;
uint8 res1;
uint16 fop;
union {
struct {
uint32 fip;
uint16 fcs;
uint16 res2;
};
uint64 fpu_ip;
};
union {
struct {
uint32 fdp;
uint16 fds;
uint16 res3;
};
uint64 fpu_dp;
};
uint32 mxcsr;
uint32 mxcsr_mask;
uint8 st_mm[8][16];
uint8 mmx_1[8][16];
uint8 mmx_2[8][16];
uint8 pad[96];
};
#include
#define HAX_CAP_STATUS_WORKING (1 << 0)
#define HAX_CAP_MEMQUOTA (1 << 1)
#define HAX_CAP_WORKSTATUS_MASK 0x01
#define HAX_CAP_FAILREASON_VT (1 << 0)
#define HAX_CAP_FAILREASON_NX (1 << 1)
#define HAX_CAP_EPT (1 << 0)
#define HAX_CAP_FASTMMIO (1 << 1)
#define HAX_CAP_UG (1 << 2)
#define HAX_CAP_64BIT_RAMBLOCK (1 << 3)
#define HAX_CAP_64BIT_SETRAM (1 << 4)
#define HAX_CAP_TUNNEL_PAGE (1 << 5)
#define HAX_CAP_RAM_PROTECTION (1 << 6)
#define HAX_CAP_DEBUG (1 << 7)
#define HAX_CAP_IMPLICIT_RAMBLOCK (1 << 8)
#include
struct hax_capabilityinfo {
/*
* bit 0: 1 - working, 0 - not working, possibly because NT/NX disabled
* bit 1: 1 - memory limitation working, 0 - no memory limitation
*/
uint16_t wstatus;
/*
* valid when not working
* bit0: VT not enabeld
* bit1: NX not enabled
*/
/*
* valid when working
* bit0: EPT enabled
* bit1: fastMMIO
*/
uint16_t winfo;
uint32_t win_refcount;
uint64_t mem_quota;
};
#include
#define HAX_DEVICE_TYPE 0x4000
#define HAX_IOCTL_VERSION \
CTL_CODE(HAX_DEVICE_TYPE, 0x900, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define HAX_IOCTL_CREATE_VM \
CTL_CODE(HAX_DEVICE_TYPE, 0x901, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define HAX_IOCTL_CAPABILITY \
CTL_CODE(HAX_DEVICE_TYPE, 0x910, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define HAX_IOCTL_SET_MEMLIMIT \
CTL_CODE(HAX_DEVICE_TYPE, 0x911, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define HAX_VM_IOCTL_VCPU_CREATE \
CTL_CODE(HAX_DEVICE_TYPE, 0x902, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define HAX_VM_IOCTL_ALLOC_RAM \
CTL_CODE(HAX_DEVICE_TYPE, 0x903, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define HAX_VM_IOCTL_SET_RAM \
CTL_CODE(HAX_DEVICE_TYPE, 0x904, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define HAX_VM_IOCTL_VCPU_DESTROY \
CTL_CODE(HAX_DEVICE_TYPE, 0x905, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define HAX_VM_IOCTL_ADD_RAMBLOCK \
CTL_CODE(HAX_DEVICE_TYPE, 0x913, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define HAX_VM_IOCTL_SET_RAM2 \
CTL_CODE(HAX_DEVICE_TYPE, 0x914, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define HAX_VM_IOCTL_PROTECT_RAM \
CTL_CODE(HAX_DEVICE_TYPE, 0x915, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define HAX_VCPU_IOCTL_RUN \
CTL_CODE(HAX_DEVICE_TYPE, 0x906, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define HAX_VCPU_IOCTL_SET_MSRS \
CTL_CODE(HAX_DEVICE_TYPE, 0x907, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define HAX_VCPU_IOCTL_GET_MSRS \
CTL_CODE(HAX_DEVICE_TYPE, 0x908, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define HAX_VCPU_IOCTL_SET_FPU \
CTL_CODE(HAX_DEVICE_TYPE, 0x909, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define HAX_VCPU_IOCTL_GET_FPU \
CTL_CODE(HAX_DEVICE_TYPE, 0x90a, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define HAX_VCPU_IOCTL_SETUP_TUNNEL \
CTL_CODE(HAX_DEVICE_TYPE, 0x90b, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define HAX_VCPU_IOCTL_INTERRUPT \
CTL_CODE(HAX_DEVICE_TYPE, 0x90c, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define HAX_VCPU_SET_REGS \
CTL_CODE(HAX_DEVICE_TYPE, 0x90d, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define HAX_VCPU_GET_REGS \
CTL_CODE(HAX_DEVICE_TYPE, 0x90e, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define HAX_VCPU_IOCTL_KICKOFF \
CTL_CODE(HAX_DEVICE_TYPE, 0x90f, METHOD_BUFFERED, FILE_ANY_ACCESS)
/* API version 2.0 */
#define HAX_VM_IOCTL_NOTIFY_QEMU_VERSION \
CTL_CODE(HAX_DEVICE_TYPE, 0x910, METHOD_BUFFERED, FILE_ANY_ACCESS)
================================================
FILE: haxmvm/haxmvm.vcxproj
================================================
Debug
Win32
Release
Win32
Debug
x64
Release
x64
15.0
{55AC3B70-9AFB-498C-BEC6-F56AF538FEDF}
Win32Proj
haxmvm
10.0.17134.0
DynamicLibrary
true
v141
Unicode
DynamicLibrary
false
v141
true
Unicode
DynamicLibrary
true
v141
Unicode
DynamicLibrary
false
v141
true
Unicode
false
true
true
false
NotUsing
Level3
MaxSpeed
true
true
true
__i386__;_WINDOWS;HAS_I386;NtCurrentTeb=NtCurrentTeb__;WIN32;__i386__;_WINDOWS;HAS_I386;NtCurrentTeb=NtCurrentTeb__;NDEBUG;_CONSOLE;DECLSPEC_HIDDEN=;%(PreprocessorDefinitions)
true
../wine
Console
true
true
true
$(OutDir)libwine.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
NotUsing
Level3
Disabled
true
__i386__;_WINDOWS;HAS_I386;NtCurrentTeb=NtCurrentTeb__;WIN32;__i386__;_WINDOWS;HAS_I386;NtCurrentTeb=NtCurrentTeb__;_DEBUG;_CONSOLE;DECLSPEC_HIDDEN=;%(PreprocessorDefinitions)
true
../wine
Console
true
$(OutDir)libwine.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
NotUsing
Level3
Disabled
true
__i386__;_WINDOWS;HAS_I386;NtCurrentTeb=NtCurrentTeb__;_DEBUG;_CONSOLE;DECLSPEC_HIDDEN=;%(PreprocessorDefinitions)
true
../wine
Console
true
$(OutDir)libwine.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
NotUsing
Level3
MaxSpeed
true
true
true
__i386__;_WINDOWS;HAS_I386;NtCurrentTeb=NtCurrentTeb__;NDEBUG;_CONSOLE;DECLSPEC_HIDDEN=;%(PreprocessorDefinitions)
true
../wine
Console
true
true
true
$(OutDir)libwine.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
================================================
FILE: haxmvm/haxmvm.vcxproj.filters
================================================
{4FC737F1-C7A5-4376-A066-2A32D752A2FF}
cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
{93995380-89BD-4b04-88EB-625FBE52EBFB}
h;hh;hpp;hxx;hm;inl;inc;ipp;xsd
{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
ヘッダー ファイル
ソース ファイル
================================================
FILE: install.inf
================================================
[Version]
Signature="$Windows NT$"
[DefaultInstall.ntamd64]
DelReg=DefaultInstall.ntamd64.DelReg
AddReg=DefaultInstall.ntamd64.AddReg
[DefaultInstall.ntamd64.DelReg]
HKLM,%NtVdm64%\OTVDM
HKLM,%NtVdm64%\OTVDM,,0x4000
[DefaultInstall.ntamd64.AddReg]
HKLM,%NtVdm64%\0OTVDM,CommandLine,,%CommandLine%
HKLM,%NtVdm64%\0OTVDM,InternalName,,*
HKLM,%NtVdm64%\0OTVDM,ProductName,,*
HKLM,%NtVdm64%\0OTVDM,ProductVersion,,*
HKLM,%NtVdm64%\0OTVDM,MappedExeName,,%01%\%MappedExeName%
HKLM,%NtVdm64%\0OTVDM,CommandLine,0x4000,%CommandLine%
HKLM,%NtVdm64%\0OTVDM,InternalName,0x4000,*
HKLM,%NtVdm64%\0OTVDM,ProductName,0x4000,*
HKLM,%NtVdm64%\0OTVDM,ProductVersion,0x4000,*
HKLM,%NtVdm64%\0OTVDM,MappedExeName,0x4000,%01%\%MappedExeName%
[Strings]
NtVdm64=SOFTWARE\Microsoft\Windows NT\CurrentVersion\NtVdm64
CommandLine=" --ntvdm64: ""%m"" --ntvdm64-args: %c"
;If you want to hide the console window, change otvdm.exe to otvdmw.exe
MappedExeName=otvdm.exe
================================================
FILE: installw.inf
================================================
[Version]
Signature="$Windows NT$"
[DefaultInstall.ntamd64]
DelReg=DefaultInstall.ntamd64.DelReg
AddReg=DefaultInstall.ntamd64.AddReg
[DefaultInstall.ntamd64.DelReg]
HKLM,%NtVdm64%\OTVDM
HKLM,%NtVdm64%\OTVDM,,0x4000
[DefaultInstall.ntamd64.AddReg]
HKLM,%NtVdm64%\0OTVDM,CommandLine,,%CommandLine%
HKLM,%NtVdm64%\0OTVDM,InternalName,,*
HKLM,%NtVdm64%\0OTVDM,ProductName,,*
HKLM,%NtVdm64%\0OTVDM,ProductVersion,,*
HKLM,%NtVdm64%\0OTVDM,MappedExeName,,%01%\%MappedExeName%
HKLM,%NtVdm64%\0OTVDM,CommandLine,0x4000,%CommandLine%
HKLM,%NtVdm64%\0OTVDM,InternalName,0x4000,*
HKLM,%NtVdm64%\0OTVDM,ProductName,0x4000,*
HKLM,%NtVdm64%\0OTVDM,ProductVersion,0x4000,*
HKLM,%NtVdm64%\0OTVDM,MappedExeName,0x4000,%01%\%MappedExeName%
[Strings]
NtVdm64=SOFTWARE\Microsoft\Windows NT\CurrentVersion\NtVdm64
CommandLine=" --ntvdm64: ""%m"" --ntvdm64-args: %c"
;If you want to hide the console window, change otvdm.exe to otvdmw.exe
MappedExeName=otvdmw.exe
================================================
FILE: keyboard/CMakeLists.txt
================================================
file(GLOB SOURCE *.c *.cpp *.rc)
add_library(keyboard SHARED ${SOURCE} ${CMAKE_CURRENT_BINARY_DIR}/keyboard.def keyboard.drv16.obj)
include_directories(../wine)
add_definitions(-D_X86_ -D__WINESRC__ -D__i386__ -DHAVE_STRNCASECMP -DHAVE__STRNICMP -D_WINTERNL_ -DNtCurrentTeb=NtCurrentTeb__ -DDECLSPEC_HIDDEN= -Dstrncasecmp=_strnicmp)
spec_build(keyboard.drv16 keyboard)
target_link_libraries(keyboard libwine winecrt0 krnl386)
set_target_properties(keyboard PROPERTIES SUFFIX ".drv16")
================================================
FILE: keyboard/keyboard.c
================================================
/*
* KEYBOARD driver
*
* Copyright 1993 Bob Amstadt
* Copyright 1996 Albrecht Kleine
* Copyright 1997 David Faure
* Copyright 1998 Morten Welinder
* Copyright 1998 Ulrich Weigand
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include
#include
#include
#include
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "winerror.h"
#include "wine/winuser16.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(keyboard);
#include "pshpack1.h"
typedef struct _KBINFO
{
BYTE Begin_First_Range;
BYTE End_First_Range;
BYTE Begin_Second_Range;
BYTE End_Second_Range;
WORD StateSize;
} KBINFO, *LPKBINFO;
#include "poppack.h"
static FARPROC16 DefKeybEventProc;
static LPBYTE pKeyStateTable;
/***********************************************************************
* Inquire (KEYBOARD.1)
*/
WORD WINAPI Inquire16(LPKBINFO kbInfo)
{
kbInfo->Begin_First_Range = 0;
kbInfo->End_First_Range = 0;
kbInfo->Begin_Second_Range = 0;
kbInfo->End_Second_Range = 0;
kbInfo->StateSize = 16;
return sizeof(KBINFO);
}
/***********************************************************************
* Enable (KEYBOARD.2)
*/
VOID WINAPI Enable16( FARPROC16 proc, LPBYTE lpKeyState )
{
DefKeybEventProc = proc;
pKeyStateTable = lpKeyState;
memset( lpKeyState, 0, 256 ); /* all states to false */
}
/***********************************************************************
* Disable (KEYBOARD.3)
*/
VOID WINAPI Disable16(VOID)
{
DefKeybEventProc = NULL;
pKeyStateTable = NULL;
}
/****************************************************************************
* ToAscii (KEYBOARD.4)
*/
INT16 WINAPI ToAscii16(UINT16 virtKey,UINT16 scanCode, LPBYTE lpKeyState,
LPVOID lpChar, UINT16 flags)
{
return ToAscii( virtKey, scanCode, lpKeyState, lpChar, flags );
}
/***********************************************************************
* AnsiToOem (KEYBOARD.5)
*/
INT16 WINAPI AnsiToOem16( LPCSTR s, LPSTR d )
{
CharToOemA( s, d );
return -1;
}
/***********************************************************************
* OemToAnsi (KEYBOARD.6)
*/
INT16 WINAPI OemToAnsi16( LPCSTR s, LPSTR d )
{
OemToCharA( s, d );
return -1;
}
/**********************************************************************
* SetSpeed (KEYBOARD.7)
*/
WORD WINAPI SetSpeed16(WORD unused)
{
FIXME("(%04x): stub\n", unused);
return 0xffff;
}
/**********************************************************************
* ScreenSwitchEnable (KEYBOARD.100)
*/
VOID WINAPI ScreenSwitchEnable16(WORD unused)
{
FIXME("(%04x): stub\n", unused);
}
/**********************************************************************
* OemKeyScan (KEYBOARD.128)
*/
DWORD WINAPI OemKeyScan16(WORD wOemChar)
{
return OemKeyScan( wOemChar );
}
/**********************************************************************
* VkKeyScan (KEYBOARD.129)
*/
WORD WINAPI VkKeyScan16(CHAR cChar)
{
return VkKeyScanA( cChar );
}
/******************************************************************************
* GetKeyboardType (KEYBOARD.130)
*/
INT16 WINAPI GetKeyboardType16(INT16 nTypeFlag)
{
return GetKeyboardType( nTypeFlag );
}
/******************************************************************************
* MapVirtualKey (KEYBOARD.131)
*
* MapVirtualKey translates keycodes from one format to another
*/
UINT16 WINAPI MapVirtualKey16(UINT16 wCode, UINT16 wMapType)
{
return MapVirtualKeyA(wCode,wMapType);
}
/****************************************************************************
* GetKBCodePage (KEYBOARD.132)
*/
INT16 WINAPI GetKBCodePage16(void)
{
return GetKBCodePage();
}
/****************************************************************************
* GetKeyNameText (KEYBOARD.133)
*/
INT16 WINAPI GetKeyNameText16(LONG lParam, LPSTR lpBuffer, INT16 nSize)
{
return GetKeyNameTextA( lParam, lpBuffer, nSize );
}
/***********************************************************************
* AnsiToOemBuff (KEYBOARD.134)
*/
void WINAPI AnsiToOemBuff16( LPCSTR s, LPSTR d, UINT16 len )
{
if (len != 0) CharToOemBuffA( s, d, len );
}
/***********************************************************************
* OemToAnsiBuff (KEYBOARD.135)
*/
void WINAPI OemToAnsiBuff16( LPCSTR s, LPSTR d, UINT16 len )
{
if (len != 0) OemToCharBuffA( s, d, len );
}
================================================
FILE: keyboard/keyboard.def
================================================
; File generated automatically from keyboard.drv16.spec; do not edit!
LIBRARY keyboard.drv16
EXPORTS
_wine_spec_dos_header @1 DATA
================================================
FILE: keyboard/keyboard.drv16.spec
================================================
1 pascal -ret16 Inquire(ptr) Inquire16
2 pascal -ret16 Enable(segptr ptr) Enable16
3 pascal -ret16 Disable() Disable16
4 pascal -ret16 ToAscii(word word ptr ptr word) ToAscii16
5 pascal -ret16 AnsiToOem(str ptr) AnsiToOem16
6 pascal -ret16 OemToAnsi(str ptr) OemToAnsi16
7 pascal -ret16 SetSpeed(word) SetSpeed16
#8 stub WEP
9 stub INQUIREEX
10 stub TOASCIIEX
11 stub VKKEYSCANEX
12 stub MAPVIRTUALKEYEX
13 stub NEWTABLEEX
14 stub __EXPORTEDSTUB
100 pascal ScreenSwitchEnable(word) ScreenSwitchEnable16
#126 pascal GetTableSeg
#127 pascal NewTable
128 pascal OemKeyScan(word) OemKeyScan16
129 pascal -ret16 VkKeyScan(word) VkKeyScan16
130 pascal -ret16 GetKeyboardType(word) GetKeyboardType16
131 pascal -ret16 MapVirtualKey(word word) MapVirtualKey16
132 pascal -ret16 GetKBCodePage() GetKBCodePage16
133 pascal -ret16 GetKeyNameText(long ptr word) GetKeyNameText16
134 pascal -ret16 AnsiToOemBuff(ptr ptr word) AnsiToOemBuff16
135 pascal -ret16 OemToAnsiBuff(ptr ptr word) OemToAnsiBuff16
#136 pascal EnableKbSysReq
#137 pascal GetBiosKeyProc
================================================
FILE: keyboard/keyboard.vcxproj
================================================
Debug
Win32
Release
Win32
{B83EEE1C-F8DE-4F82-8928-67F1B142E5F2}
Win32Proj
keyboard
10.0.17134.0
DynamicLibrary
true
v141
Unicode
DynamicLibrary
false
v141
true
Unicode
true
.drv16
false
.drv16
Level3
Disabled
WIN32;_DEBUG;_WINDOWS;_USRDLL;KEYBOARD_EXPORTS;_X86_;__WINESRC__;__i386__;USE_COMPILER_EXCEPTIONS;HAVE_STRNCASECMP;HAVE__STRNICMP;_WINTERNL_;NtCurrentTeb=NtCurrentTeb__;inline=__inline;%(PreprocessorDefinitions)
../wine
Windows
true
$(OutDir)winecrt0.lib;$(OutDir)libwine.lib;kernel32.lib;user32.lib
keyboard.def
Level3
MaxSpeed
true
true
WIN32;NDEBUG;_WINDOWS;_USRDLL;KEYBOARD_EXPORTS;_X86_;__WINESRC__;__i386__;USE_COMPILER_EXCEPTIONS;HAVE_STRNCASECMP;HAVE__STRNICMP;_WINTERNL_;NtCurrentTeb=NtCurrentTeb__;inline=__inline;DECLSPEC_HIDDEN=;%(PreprocessorDefinitions)
../wine
Windows
true
true
true
false
keyboard.def
$(OutDir)winecrt0.lib;$(OutDir)libwine.lib;kernel32.lib;user32.lib
Document
"$(OutDir)convspec" "%(Filename).spec" KEYBOARD > "%(Filename).asm" && "$(AsmPath)as" --32 -o "%(Filename).obj" "%(Filename).asm"
%(Filename).obj
"$(OutDir)convspec" "%(Filename).spec" KEYBOARD > "%(Filename).asm" && "$(AsmPath)as" --32 -o "%(Filename).obj" "%(Filename).asm"
%(Filename).obj
================================================
FILE: keyboard/keyboard.vcxproj.filters
================================================
{4FC737F1-C7A5-4376-A066-2A32D752A2FF}
cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
{93995380-89BD-4b04-88EB-625FBE52EBFB}
h;hh;hpp;hxx;hm;inl;inc;xsd
{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
ソース ファイル
ソース ファイル
ソース ファイル
================================================
FILE: krnl386/CMakeLists.txt
================================================
file(GLOB SOURCE *.c *.cpp)
add_library(krnl386 SHARED ${SOURCE} krnl386.exe16.obj ${CMAKE_CURRENT_BINARY_DIR}/krnl386.def)
include_directories(../wine)
add_definitions(-DMZ_SUPPORTED -DENABLEREDIRECTSYSTEMDIR -D_X86_ -D__WINESRC__ -D__i386__ -DHAVE_STRNCASECMP -DHAVE__STRNICMP -D_WINTERNL_ -DNtCurrentTeb=NtCurrentTeb__ -DDECLSPEC_HIDDEN= -Dstrncasecmp=_strnicmp)
spec_build(krnl386.exe16 KERNEL ARG --heap 65520)
target_link_libraries(krnl386 libwine winecrt0 lz32.lib ntdll.lib ddraw.lib dsound.lib)
set_target_properties(krnl386 PROPERTIES SUFFIX ".exe16")
================================================
FILE: krnl386/Makefile.in
================================================
MODULE = krnl386.exe16
IMPORTLIB = kernel
IMPORTS = winecrt0 kernel32 ntdll
DELAYIMPORTS = ddraw dsound user32
EXTRADLLFLAGS = -m16 -nodefaultlibs -Wb,--dll-name,kernel
C_SRCS = \
atom.c \
dma.c \
dosaspi.c \
dosdev.c \
dosexe.c \
dosmem.c \
dosvm.c \
error.c \
file.c \
fpu.c \
global.c \
instr.c \
int09.c \
int10.c \
int13.c \
int15.c \
int16.c \
int21.c \
int25.c \
int26.c \
int2f.c \
int31.c \
int33.c \
int67.c \
interrupts.c \
ioports.c \
kernel.c \
local.c \
ne_module.c \
ne_segment.c \
registry.c \
relay.c \
resource.c \
selector.c \
snoop.c \
soundblaster.c \
syslevel.c \
task.c \
thunk.c \
timer.c \
utthunk.c \
vga.c \
vxd.c \
wowthunk.c
RC_SRCS = version.rc
================================================
FILE: krnl386/atom.c
================================================
/*
* Atom table functions - 16 bit variant
*
* Copyright 1993, 1994, 1995 Alexandre Julliard
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
/*
* Warning: The code assumes that LocalAlloc() returns a block aligned
* on a 4-bytes boundary (because of the shifting done in
* HANDLETOATOM). If this is not the case, the allocation code will
* have to be changed.
*/
#include "config.h"
#include "wine/port.h"
#include
#include
#include
#include
#include
#include "windef.h"
#include "winbase.h"
#include "winerror.h"
#include "winternl.h"
#include "wine/unicode.h"
#include "wine/winbase16.h"
#include "kernel16_private.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(atom);
#define DEFAULT_ATOMTABLE_SIZE 37
#define MAX_ATOM_LEN 255
#define ATOMTOHANDLE(atom) ((HANDLE16)(atom) << 2)
#define HANDLETOATOM(handle) ((ATOM)(0xc000 | ((handle) >> 2)))
typedef struct
{
HANDLE16 next;
WORD refCount;
BYTE length;
CHAR str[1];
} ATOMENTRY;
typedef struct
{
WORD size;
HANDLE16 entries[1];
} ATOMTABLE;
/***********************************************************************
* ATOM_GetTable
*
* Return a pointer to the atom table of a given segment, creating
* it if necessary.
*
* RETURNS
* Pointer to table: Success
* NULL: Failure
*/
static ATOMTABLE *ATOM_GetTable( BOOL create /* [in] Create */ )
{
INSTANCEDATA *ptr = MapSL( MAKESEGPTR( CURRENT_DS, 0 ) );
if (ptr->atomtable)
{
ATOMTABLE *table = (ATOMTABLE *)((char *)ptr + ptr->atomtable);
if (table->size) return table;
}
if (!create) return NULL;
if (!InitAtomTable16( 0 )) return NULL;
/* Reload ptr in case it moved in linear memory */
ptr = MapSL( MAKESEGPTR( CURRENT_DS, 0 ) );
return (ATOMTABLE *)((char *)ptr + ptr->atomtable);
}
/***********************************************************************
* ATOM_Hash
* RETURNS
* The hash value for the input string
*/
static WORD ATOM_Hash(
WORD entries, /* [in] Total number of entries */
LPCSTR str, /* [in] Pointer to string to hash */
WORD len /* [in] Length of string */
) {
WORD i, hash = 0;
TRACE("%x, %s, %x\n", entries, str, len);
for (i = 0; i < len; i++) hash ^= toupper(str[i]) + i;
return hash % entries;
}
/***********************************************************************
* ATOM_IsIntAtomA
*/
static BOOL ATOM_IsIntAtomA(LPCSTR atomstr,WORD *atomid)
{
UINT atom = 0;
if (!HIWORD(atomstr)) atom = LOWORD(atomstr);
else
{
if (*atomstr++ != '#') return FALSE;
while (*atomstr >= '0' && *atomstr <= '9')
{
atom = atom * 10 + *atomstr - '0';
atomstr++;
}
if (*atomstr) return FALSE;
}
if (atom >= MAXINTATOM)
{
SetLastError( ERROR_INVALID_PARAMETER );
atom = 0;
}
*atomid = atom;
return TRUE;
}
/***********************************************************************
* ATOM_MakePtr
*
* Make an ATOMENTRY pointer from a handle (obtained from GetAtomHandle()).
*/
static inline ATOMENTRY *ATOM_MakePtr( HANDLE16 handle /* [in] Handle */ )
{
return MapSL( MAKESEGPTR( CURRENT_DS, handle ) );
}
/***********************************************************************
* InitAtomTable (KERNEL.68)
*/
WORD WINAPI InitAtomTable16( WORD entries )
{
int i;
HANDLE16 handle;
ATOMTABLE *table;
/* Allocate the table */
if (!entries) entries = DEFAULT_ATOMTABLE_SIZE; /* sanity check */
handle = LocalAlloc16( LMEM_FIXED, FIELD_OFFSET( ATOMTABLE, entries[entries] ));
if (!handle) return 0;
table = MapSL( MAKESEGPTR( CURRENT_DS, handle ) );
table->size = entries;
for (i = 0; i < entries; i++) table->entries[i] = 0;
/* Store a pointer to the table in the instance data */
((INSTANCEDATA *)MapSL( MAKESEGPTR( CURRENT_DS, 0 )))->atomtable = handle;
return handle;
}
/***********************************************************************
* GetAtomHandle (KERNEL.73)
*/
HANDLE16 WINAPI GetAtomHandle16( ATOM atom )
{
if (atom < MAXINTATOM) return 0;
return ATOMTOHANDLE( atom );
}
/***********************************************************************
* AddAtom (KERNEL.70)
*
* Windows DWORD aligns the atom entry size.
* The remaining unused string space created by the alignment
* gets padded with '\0's in a certain way to ensure
* that at least one trailing '\0' remains.
*
* RETURNS
* Atom: Success
* 0: Failure
*/
ATOM WINAPI AddAtom16( LPCSTR str )
{
char buffer[MAX_ATOM_LEN+1];
WORD hash;
HANDLE16 entry;
ATOMENTRY * entryPtr;
ATOMTABLE * table;
int len, ae_len;
WORD iatom;
if (ATOM_IsIntAtomA( str, &iatom )) return iatom;
TRACE("%s\n",debugstr_a(str));
if (strlen(str) >= 256)
return INVALID_ATOM;
if (!(table = ATOM_GetTable( TRUE ))) return 0;
/* Make a copy of the string to be sure it doesn't move in linear memory. */
lstrcpynA( buffer, str, sizeof(buffer) );
len = strlen( buffer );
hash = ATOM_Hash( table->size, buffer, len );
entry = table->entries[hash];
while (entry)
{
entryPtr = ATOM_MakePtr( entry );
if ((entryPtr->length == len) &&
(!strncasecmp( entryPtr->str, buffer, len )))
{
entryPtr->refCount++;
TRACE("-- existing 0x%x\n", entry);
return HANDLETOATOM( entry );
}
entry = entryPtr->next;
}
ae_len = (sizeof(ATOMENTRY)+len+3) & ~3;
entry = LocalAlloc16( LMEM_FIXED, ae_len );
if (!entry) return 0;
/* Reload the table ptr in case it moved in linear memory */
table = ATOM_GetTable( FALSE );
entryPtr = ATOM_MakePtr( entry );
entryPtr->next = table->entries[hash];
entryPtr->refCount = 1;
entryPtr->length = len;
memcpy( entryPtr->str, buffer, len);
/* Some applications _need_ the '\0' padding provided by memset */
/* Note that 1 byte of the str is accounted for in the ATOMENTRY struct */
memset( entryPtr->str+len, 0, ae_len - sizeof(ATOMENTRY) - (len - 1));
table->entries[hash] = entry;
TRACE("-- new 0x%x\n", entry);
return HANDLETOATOM( entry );
}
/***********************************************************************
* DeleteAtom (KERNEL.71)
*/
ATOM WINAPI DeleteAtom16( ATOM atom )
{
ATOMENTRY * entryPtr;
ATOMTABLE * table;
HANDLE16 entry, *prevEntry;
WORD hash;
if (atom < MAXINTATOM) return 0; /* Integer atom */
TRACE("0x%x\n",atom);
if (!(table = ATOM_GetTable( FALSE ))) return 0;
entry = ATOMTOHANDLE( atom );
entryPtr = ATOM_MakePtr( entry );
/* Find previous atom */
hash = ATOM_Hash( table->size, entryPtr->str, entryPtr->length );
prevEntry = &table->entries[hash];
while (*prevEntry && *prevEntry != entry)
{
ATOMENTRY * prevEntryPtr = ATOM_MakePtr( *prevEntry );
prevEntry = &prevEntryPtr->next;
}
if (!*prevEntry) return atom;
/* Delete atom */
if (--entryPtr->refCount == 0)
{
*prevEntry = entryPtr->next;
LocalFree16( entry );
}
return 0;
}
/***********************************************************************
* FindAtom (KERNEL.69)
*/
ATOM WINAPI FindAtom16( LPCSTR str )
{
ATOMTABLE * table;
WORD hash,iatom;
HANDLE16 entry;
int len;
TRACE("%s\n",debugstr_a(str));
if (ATOM_IsIntAtomA( str, &iatom )) return iatom;
if ((len = strlen( str )) > 255) len = 255;
if (!(table = ATOM_GetTable( FALSE ))) return 0;
hash = ATOM_Hash( table->size, str, len );
entry = table->entries[hash];
while (entry)
{
ATOMENTRY * entryPtr = ATOM_MakePtr( entry );
if ((entryPtr->length == len) &&
(!strncasecmp( entryPtr->str, str, len )))
{
TRACE("-- found %x\n", entry);
return HANDLETOATOM( entry );
}
entry = entryPtr->next;
}
TRACE("-- not found\n");
return 0;
}
/***********************************************************************
* GetAtomName (KERNEL.72)
*/
UINT16 WINAPI GetAtomName16( ATOM atom, LPSTR buffer, INT16 count )
{
ATOMENTRY * entryPtr;
HANDLE16 entry;
char * strPtr;
INT len;
char text[8];
TRACE("%x\n",atom);
if (!count) return 0;
if (atom == INVALID_ATOM)
return 0;
if (atom < MAXINTATOM)
{
sprintf( text, "#%d", atom );
len = strlen(text);
strPtr = text;
}
else
{
if (!ATOM_GetTable( FALSE )) return 0;
entry = ATOMTOHANDLE( atom );
entryPtr = ATOM_MakePtr( entry );
len = entryPtr->length;
strPtr = entryPtr->str;
}
if (len >= count) len = count-1;
memcpy( buffer, strPtr, len );
buffer[len] = '\0';
return len;
}
================================================
FILE: krnl386/compat.c
================================================
#include
#include "kernel16_private.h"
// this only currently will get the flags for the first task
// it might be work on a per-task basis
static char modes[256];
BOOL WINAPI krnl386_get_compat_mode(const LPCSTR mode)
{
int size = strlen(mode);
if (size >= 256)
return FALSE;
char lowermode[256];
for (int i = 0; i < size; i++)
lowermode[i] = tolower(mode[i]);
lowermode[size] = '\0';
return strstr(modes, lowermode) ? TRUE : FALSE;
}
void WINAPI krnl386_set_compat_path(const LPCSTR path)
{
HKEY hkey;
LSTATUS stat = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers", &hkey);
modes[0] = '\0';
if (stat)
return;
int size = 256;
int type;
char drive[MAX_PATH];
char smvalue[256];
char *value = path;
strncpy(drive, path, 3);
drive[3] = '\0';
type = GetDriveTypeA(drive);
if ((type == DRIVE_CDROM) || (type == DRIVE_REMOVABLE) || (type == DRIVE_REMOTE))
{
// Based on reactos layer.c
HANDLE FindHandle;
WIN32_FIND_DATAA FindData;
DWORD SignMedia = 0;
char *filepath = strrchr(path, '\\');
if (!filepath)
return;
int len = filepath - path + 1;
strncpy(drive, path, len);
int count = 9;
drive[len] = '*';
drive[len + 1] = '\0';
FindHandle = FindFirstFileA(drive, &FindData);
if (FindHandle != INVALID_HANDLE_VALUE)
{
do
{
if (!(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && FindData.nFileSizeLow)
{
SignMedia = ((SignMedia << 1) | (SignMedia >> 31)) ^ FindData.nFileSizeLow;
count--;
}
} while (FindNextFileA(FindHandle, &FindData) && count);
FindClose(FindHandle);
}
drive[len - 1] = '\0';
filepath = strrchr(drive, '\\');
if (!filepath)
filepath = path + 3;
else
filepath = path + (filepath - drive) + 1;
snprintf(smvalue, 256, "SIGN.MEDIA=%X %s", SignMedia, filepath);
value = smvalue;
}
stat = RegQueryValueExA(hkey, value, 0, &type, &modes, &size);
RegCloseKey(hkey);
if (stat || (type != REG_SZ))
{
modes[0] = '\0';
return;
}
for (int i = 0; i < size; i++)
modes[i] = tolower(modes[i]);
return;
}
ULONG WINAPI get_windows_build()
{
static ULONG build = 0;
if (build) return build;
RTL_OSVERSIONINFOEXW winver;
if (RtlGetVersion(&winver))
return 0;
build = winver.dwBuildNumber;
return build;
}
================================================
FILE: krnl386/conf.c
================================================
#include
static BOOL init;
static CHAR filename[MAX_PATH];
static CRITICAL_SECTION critical_section;
DWORD WINAPI krnl386_get_config_string(LPCSTR appname, LPCSTR keyname, LPCSTR def, LPSTR ret, DWORD size);
DWORD WINAPI krnl386_get_config_int(LPCSTR appname, LPCSTR keyname, INT def);
void init_config()
{
init = TRUE;
InitializeCriticalSection(&critical_section);
EnterCriticalSection(&critical_section);
DWORD filename_len;
filename_len = GetModuleFileNameA(GetModuleHandleA(NULL), filename, MAX_PATH);
if (!filename_len)
return 0;
CHAR ininame[] = "otvdm.ini";
if (_countof(ininame) + filename_len >= MAX_PATH)
return 0;
LPSTR last = strrchr(filename, '\\');
memcpy(last + 1, ininame, sizeof(ininame));
LeaveCriticalSection(&critical_section);
}
DWORD WINAPI krnl386_get_config_string(LPCSTR appname, LPCSTR keyname, LPCSTR def, LPSTR ret, DWORD size)
{
if (!init)
init_config();
EnterCriticalSection(&critical_section);
DWORD result = GetPrivateProfileStringA(appname, keyname, def, ret, size, filename);
LeaveCriticalSection(&critical_section);
return result;
}
DWORD WINAPI krnl386_get_config_int(LPCSTR appname, LPCSTR keyname, INT def)
{
if (!init)
init_config();
EnterCriticalSection(&critical_section);
DWORD result = GetPrivateProfileIntA(appname, keyname, def, filename);
LeaveCriticalSection(&critical_section);
return result;
}
================================================
FILE: krnl386/dma.c
================================================
/*
* DMA Emulation
*
* Copyright 2002 Christian Costa
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#include
#include "windef.h"
#include "winbase.h"
#include "dosexe.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(dma);
/* Internal registers of the 2 DMA chips which control 8 DMA channels */
static DWORD DMA_BaseAddress[8];
static WORD DMA_ByteCount[8];
static DWORD DMA_CurrentBaseAddress[8];
static WORD DMA_CurrentByteCount[8];
static BYTE DMA_Command[8];
static BYTE DMA_Mask[2]={0x0F,0x0F};
static BYTE DMA_Status[2]={0x00,0x00};
static BOOL DMA_Toggle[2]={FALSE,FALSE};
/*
* DMA_Transfer : Try to perform a transfer of reqlen elements (8 or 16 bits)
* on the specified channel and return the elements transferred
*/
int DMA_Transfer(int channel,int reqlen,void* buffer)
{
int i,size,ret=0;
int opmode,increment,autoinit,trmode,dmachip;
int regmode = DMA_Command[channel];
char *p,*dmabuf;
dmabuf = buffer;
dmachip = (channel<4) ? 0 : 1;
TRACE("DMA_Command = %x reqlen=%d\n",regmode,reqlen);
/* Exit if channel is masked */
if (DMA_Mask[dmachip]&(1<<(channel&3)))
return 0;
opmode = (regmode & 0xC0) >> 6;
increment = !(regmode & 0x20);
autoinit = regmode & 0x10;
trmode = (regmode & 0x0C) >> 2;
/* Transfer size : 8 bits for channels 0..3, 16 bits for channels 4..7 */
size = (channel<4) ? 1 : 2;
/* Process operating mode */
switch(opmode)
{
case 0:
/* Request mode */
FIXME("Request Mode - Not Implemented\n");
return 0;
case 1:
/* Single Mode */
break;
case 2:
/* Request mode */
FIXME("Block Mode - Not Implemented\n");
return 0;
case 3:
/* Cascade Mode */
ERR("Cascade Mode should not be used by regular apps\n");
return 0;
}
/* Perform one the 4 transfer modes */
if (trmode == 4) {
/* Illegal */
ERR("DMA Transfer Type Illegal\n");
return 0;
}
ret = min(DMA_CurrentByteCount[channel],reqlen);
/* Update DMA registers */
DMA_CurrentByteCount[channel]-=ret;
if (increment)
DMA_CurrentBaseAddress[channel] += ret * size;
else
DMA_CurrentBaseAddress[channel] -= ret * size;
switch(trmode)
{
case 0:
/* Verification (no real transfer)*/
TRACE("Verification DMA operation\n");
break;
case 1:
/* Write */
TRACE("Perform Write transfer of %d bytes at %x with count %x\n",ret,
DMA_CurrentBaseAddress[channel],DMA_CurrentByteCount[channel]);
if (increment)
memcpy((void*)DMA_CurrentBaseAddress[channel],dmabuf,ret*size);
else
for(i=0,p=(char*)DMA_CurrentBaseAddress[channel];i>2):(port>>1);
dmachip = (channel<4) ? 0 : 1;
if (!DMA_Toggle[dmachip])
DMA_BaseAddress[channel]=(DMA_BaseAddress[channel] & ~0xFF)|(val & 0xFF);
else {
DMA_BaseAddress[channel]=(DMA_BaseAddress[channel] & (~(0xFF << 8)))|((val & 0xFF) << 8);
DMA_CurrentBaseAddress[channel] = DMA_BaseAddress[channel];
TRACE("Write Base Address = %x\n",DMA_BaseAddress[channel]);
}
DMA_Toggle[dmachip] = !DMA_Toggle[dmachip];
break;
case 0x01:
case 0x03:
case 0x05:
case 0x07:
case 0xC2:
case 0xC6:
case 0xCA:
case 0xCE:
/* Count*/
channel = ((port-1)&0xC0)?(((port-1)-0xC0)>>2):(port>>1);
dmachip = (channel<4) ? 0 : 1;
if (!DMA_Toggle[dmachip])
DMA_ByteCount[channel]=(DMA_ByteCount[channel] & ~0xFF)|((val+1) & 0xFF);
else {
DMA_ByteCount[channel]=(DMA_ByteCount[channel] & (~(0xFF << 8)))|(((val+1) & 0xFF) << 8);
DMA_CurrentByteCount[channel] = DMA_ByteCount[channel];
TRACE("Write Count = %x.\n",DMA_ByteCount[channel]);
}
DMA_Toggle[dmachip] = !DMA_Toggle[dmachip];
break;
/* Low Page Base Address */
case 0x87: DMA_BaseAddress[0]=(DMA_BaseAddress[0] & 0xFF00FFFF)|((val & 0xFF) << 16); break;
case 0x83: DMA_BaseAddress[1]=(DMA_BaseAddress[1] & 0xFF00FFFF)|((val & 0xFF) << 16); break;
case 0x81: DMA_BaseAddress[2]=(DMA_BaseAddress[2] & 0xFF00FFFF)|((val & 0xFF) << 16); break;
case 0x82: DMA_BaseAddress[3]=(DMA_BaseAddress[3] & 0xFF00FFFF)|((val & 0xFF) << 16); break;
case 0x8B: DMA_BaseAddress[5]=(DMA_BaseAddress[5] & 0xFF00FFFF)|((val & 0xFF) << 16); break;
case 0x89: DMA_BaseAddress[6]=(DMA_BaseAddress[6] & 0xFF00FFFF)|((val & 0xFF) << 16); break;
case 0x8A: DMA_BaseAddress[7]=(DMA_BaseAddress[7] & 0xFF00FFFF)|((val & 0xFF) << 16); break;
/* Low Page Base Address (only 4 lower bits are significant) */
case 0x487: DMA_BaseAddress[0]=(DMA_BaseAddress[0] & 0x00FFFFFF)|((val & 0x0F) << 24); break;
case 0x483: DMA_BaseAddress[1]=(DMA_BaseAddress[1] & 0x00FFFFFF)|((val & 0x0F) << 24); break;
case 0x481: DMA_BaseAddress[2]=(DMA_BaseAddress[2] & 0x00FFFFFF)|((val & 0x0F) << 24); break;
case 0x482: DMA_BaseAddress[3]=(DMA_BaseAddress[3] & 0x00FFFFFF)|((val & 0x0F) << 24); break;
case 0x48B: DMA_BaseAddress[5]=(DMA_BaseAddress[5] & 0x00FFFFFF)|((val & 0x0F) << 24); break;
case 0x489: DMA_BaseAddress[6]=(DMA_BaseAddress[6] & 0x00FFFFFF)|((val & 0x0F) << 24); break;
case 0x48A: DMA_BaseAddress[7]=(DMA_BaseAddress[7] & 0x00FFFFFF)|((val & 0x0F) << 24); break;
case 0x08:
case 0xD0:
/* Command */
FIXME("Write Command (%x) - Not Implemented\n",val);
break;
case 0x0B:
case 0xD6:
/* Mode */
TRACE("Write Mode (%x)\n",val);
DMA_Command[((port==0xD6)?4:0)+(val&0x3)]=val;
switch(val>>6)
{
case 0:
/* Request mode */
FIXME("Request Mode - Not Implemented\n");
break;
case 1:
/* Single Mode */
break;
case 2:
/* Block mode */
FIXME("Block Mode - Not Implemented\n");
break;
case 3:
/* Cascade Mode */
ERR("Cascade Mode should not be used by regular apps\n");
break;
}
break;
case 0x0A:
case 0xD4:
/* Write Single Mask Bit */
TRACE("Write Single Mask Bit (%x)\n",val);
dmachip = (port==0x0A) ? 0 : 1;
if (val&4)
DMA_Mask[dmachip] |= 1<<(val&3);
else
DMA_Mask[dmachip] &= ~(1<<(val&3));
break;
case 0x0F:
case 0xDE:
/* Write All Mask Bits (only 4 lower bits are significant */
FIXME("Write All Mask Bits (%x)\n",val);
dmachip = (port==0x0F) ? 0 : 1;
DMA_Mask[dmachip] = val & 0x0F;
break;
case 0x09:
case 0xD2:
/* Software DRQx Request */
FIXME("Software DRQx Request (%x) - Not Implemented\n",val);
break;
case 0x0C:
case 0xD8:
/* Reset DMA Pointer Flip-Flop */
TRACE("Reset Flip-Flop\n");
DMA_Toggle[port==0xD8]=FALSE;
break;
case 0x0D:
case 0xDA:
/* Master Reset */
TRACE("Master Reset\n");
dmachip = (port==0x0D) ? 0 : 1;
/* Reset DMA Pointer Flip-Flop */
DMA_Toggle[dmachip]=FALSE;
/* Mask all channels */
DMA_Mask[dmachip] = 0x0F;
break;
case 0x0E:
case 0xDC:
/* Reset Mask Register */
FIXME("Reset Mask Register\n");
dmachip = (port==0x0E) ? 0 : 1;
/* Unmask all channels */
DMA_Mask[dmachip] = 0x00;
break;
}
}
BYTE DMA_ioport_in( WORD port )
{
int channel,dmachip;
BYTE res = 0;
switch(port)
{
case 0x00:
case 0x02:
case 0x04:
case 0x06:
case 0xC0:
case 0xC4:
case 0xC8:
case 0xCC:
/* Base Address*/
channel = (port&0xC0)?((port-0xC0)>>2):(port>>1);
dmachip = (channel<4) ? 0 : 1;
if (!DMA_Toggle[dmachip])
res = DMA_CurrentBaseAddress[channel] & 0xFF;
else {
res = (DMA_CurrentBaseAddress[channel] & (0xFF << 8))>>8;
TRACE("Read Current Base Address = %x\n",DMA_CurrentBaseAddress[channel]);
}
DMA_Toggle[dmachip] = !DMA_Toggle[dmachip];
break;
case 0x01:
case 0x03:
case 0x05:
case 0x07:
case 0xC2:
case 0xC6:
case 0xCA:
case 0xCE:
/* Count*/
channel = ((port-1)&0xC0)?(((port-1)-0xC0)>>2):(port>>1);
dmachip = (channel<4) ? 0 : 1;
if (!DMA_Toggle[dmachip])
res = DMA_CurrentByteCount[channel];
else {
res = DMA_CurrentByteCount[channel] >> 8;
TRACE("Read Current Count = %x.\n",DMA_CurrentByteCount[channel]);
}
DMA_Toggle[dmachip] = !DMA_Toggle[dmachip];
break;
/* Low Page Base Address */
case 0x87: res = DMA_BaseAddress[0] >> 16; break;
case 0x83: res = DMA_BaseAddress[1] >> 16; break;
case 0x81: res = DMA_BaseAddress[2] >> 16; break;
case 0x82: res = DMA_BaseAddress[3] >> 16; break;
case 0x8B: res = DMA_BaseAddress[5] >> 16; break;
case 0x89: res = DMA_BaseAddress[6] >> 16; break;
case 0x8A: res = DMA_BaseAddress[7] >> 16; break;
/* High Page Base Address */
case 0x487: res = DMA_BaseAddress[0] >> 24; break;
case 0x483: res = DMA_BaseAddress[1] >> 24; break;
case 0x481: res = DMA_BaseAddress[2] >> 24; break;
case 0x482: res = DMA_BaseAddress[3] >> 24; break;
case 0x48B: res = DMA_BaseAddress[5] >> 24; break;
case 0x489: res = DMA_BaseAddress[6] >> 24; break;
case 0x48A: res = DMA_BaseAddress[7] >> 24; break;
case 0x08:
case 0xD0:
/* Status */
TRACE("Status Register Read\n");
res = DMA_Status[(port==0x08)?0:1];
break;
case 0x0D:
case 0xDA:
/* Temporary */
FIXME("Temporary Register Read- Not Implemented\n");
break;
}
return res;
}
================================================
FILE: krnl386/dosaspi.c
================================================
/*
* Copyright 2000 David Elliott
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#include
#include
#include "windef.h"
#include "winbase.h"
#include "wine/windef16.h"
#include "wine/winaspi.h"
#include "wine/debug.h"
#include "dosexe.h"
#include "winerror.h"
WINE_DEFAULT_DEBUG_CHANNEL(aspi);
static HINSTANCE hWNASPI32 = INVALID_HANDLE_VALUE;
static DWORD (__cdecl *pSendASPI32Command) (LPSRB) = NULL;
static void
DOSASPI_PostProc( SRB_ExecSCSICmd *lpPRB )
{
DWORD ptrSRB;
LPSRB16 lpSRB16;
memcpy(&ptrSRB,lpPRB->SenseArea + lpPRB->SRB_SenseLen,sizeof(DWORD));
TRACE("Copying data back to DOS client at 0x%8x\n",ptrSRB);
lpSRB16 = PTR_REAL_TO_LIN(SELECTOROF(ptrSRB),OFFSETOF(ptrSRB));
lpSRB16->cmd.SRB_TargStat = lpPRB->SRB_TargStat;
lpSRB16->cmd.SRB_HaStat = lpPRB->SRB_HaStat;
memcpy(lpSRB16->cmd.CDBByte + lpSRB16->cmd.SRB_CDBLen,lpPRB->SenseArea,lpSRB16->cmd.SRB_SenseLen);
/* Now do posting */
if( lpPRB->SRB_Status == SS_SECURITY_VIOLATION )
{
/* SS_SECURITY_VIOLATION isn't defined in DOS ASPI */
TRACE("Returning SS_NO_DEVICE for SS_SECURITY_VIOLATION\n");
lpPRB->SRB_Status = SS_NO_DEVICE;
}
lpSRB16->cmd.SRB_Status = lpPRB->SRB_Status;
TRACE("SRB_Status = 0x%x\n", lpPRB->SRB_Status);
HeapFree(GetProcessHeap(),0,lpPRB);
if( (lpSRB16->cmd.SRB_Flags & SRB_POSTING) && lpSRB16->cmd.SRB_PostProc )
{
CONTEXT ctx;
/* The stack should look like this on entry to proc
* NOTE: the SDK draws the following diagram bass awkwardly, use this one
* to avoid being confused. Remember, the act of pushing something on
* an intel stack involves decreasing the stack pointer by the size of
* the data, and then copying the data at the new SP.
*/
/***************************
* ... Other crap that is already on the stack ...
* Segment of SRB Pointer <- SP+6
* Offset of SRB Pointer <- SP+4
* Segment of return address <- SP+2
* Offset of return address <- SP+0
*/
/* FIXME: I am about 99% sure what is here is correct,
* but this code has never been tested (and probably
* won't be either until someone finds a DOS program
* that actually uses a Post Routine) */
/* Zero everything */
memset(&ctx, 0, sizeof(ctx));
ctx.EFlags |= V86_FLAG;
/* CS:IP is routine to call */
ctx.SegCs = SELECTOROF(lpSRB16->cmd.SRB_PostProc);
ctx.Eip = OFFSETOF(lpSRB16->cmd.SRB_PostProc);
/* DPMI_CallRMProc will push the pointer to the stack
* it is given (in this case &ptrSRB) with length
* 2*sizeof(WORD), that is, it copies the contents
* of ptrSRB onto the stack, and decs sp by 2*sizeof(WORD).
* After doing that, it pushes the return address
* onto the stack (so we don't need to worry about that)
* So the stack should be okay for the PostProc
*/
if(DPMI_CallRMProc(&ctx, (LPWORD)&ptrSRB, 2, FALSE))
{
TRACE("DPMI_CallRMProc returned nonzero (error) status\n");
}
} /* if ((SRB_Flags&SRB_POSTING) && SRB_PostProc) */
}
static
DWORD ASPI_SendASPIDOSCommand(DWORD ptrSRB)
{
PSRB_ExecSCSICmd lpPRB;
DWORD retval;
union tagSRB16 * lpSRB16;
lpSRB16 = PTR_REAL_TO_LIN(SELECTOROF(ptrSRB),OFFSETOF(ptrSRB));
retval = SS_ERR;
switch( lpSRB16->common.SRB_Cmd )
{
case SC_HA_INQUIRY:
TRACE("SC_HA_INQUIRY\n");
/* Format is identical in this case */
retval = (*pSendASPI32Command)((LPSRB)lpSRB16);
break;
case SC_GET_DEV_TYPE:
TRACE("SC_GET_DEV_TYPE\n");
/* Format is identical in this case */
retval = (*pSendASPI32Command)((LPSRB)lpSRB16);
break;
case SC_EXEC_SCSI_CMD:
TRACE("SC_EXEC_SCSI_CMD\n");
TRACE("Copying data from DOS client at 0x%8x\n",ptrSRB);
lpPRB = HeapAlloc(GetProcessHeap(),0,sizeof(SRB)+lpSRB16->cmd.SRB_SenseLen+sizeof(DWORD));
#define srb_dos_to_w32(name) \
lpPRB->SRB_##name = lpSRB16->cmd.SRB_##name
srb_dos_to_w32(Cmd);
srb_dos_to_w32(Status);
srb_dos_to_w32(HaId);
srb_dos_to_w32(BufLen);
srb_dos_to_w32(SenseLen);
srb_dos_to_w32(CDBLen);
srb_dos_to_w32(Target);
srb_dos_to_w32(Lun);
#undef srb_dos_to_w32
/* Allow certain flags to go on to WNASPI32, we also need
* to make sure SRB_POSTING is enabled */
lpPRB->SRB_Flags = SRB_POSTING | (lpSRB16->cmd.SRB_Flags&(SRB_DIR_IN|SRB_DIR_OUT|SRB_ENABLE_RESIDUAL_COUNT));
/* Pointer to data buffer */
lpPRB->SRB_BufPointer = PTR_REAL_TO_LIN(SELECTOROF(lpSRB16->cmd.SRB_BufPointer),
OFFSETOF(lpSRB16->cmd.SRB_BufPointer));
/* Copy CDB in */
memcpy(&lpPRB->CDBByte[0],&lpSRB16->cmd.CDBByte[0],lpSRB16->cmd.SRB_CDBLen);
/* Set post proc to our post proc */
lpPRB->SRB_PostProc = DOSASPI_PostProc;
/* Stick the DWORD after all the sense info */
memcpy(lpPRB->SenseArea + lpPRB->SRB_SenseLen,&ptrSRB,sizeof(DWORD));
retval = (*pSendASPI32Command)((LPSRB)lpPRB);
break;
case SC_ABORT_SRB:
TRACE("SC_ABORT_SRB\n");
/* Would need some sort of table of active shit */
break;
case SC_RESET_DEV:
TRACE("SC_RESET_DEV\n");
break;
default:
TRACE("Unknown command code\n");
break;
}
TRACE("Returning %x\n", retval );
return retval;
}
static void WINAPI ASPI_DOS_func(CONTEXT *context)
{
WORD *stack = CTX_SEG_OFF_TO_LIN(context, context->SegSs, context->Esp);
DWORD ptrSRB = *(DWORD *)&stack[2];
ASPI_SendASPIDOSCommand(ptrSRB);
/* simulate a normal RETF sequence as required by DPMI CallRMProcFar */
context->Eip = *(stack++);
context->SegCs = *(stack++);
context->Esp += 2*sizeof(WORD);
}
/**********************************************************************
* ASPIHandler
*
* returns the address of a real mode callback to ASPI_DOS_func()
*/
void DOSVM_ASPIHandler( CONTEXT *context )
{
FARPROC16 *p = CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx);
TRACE("DOS ASPI opening\n");
if ((CX_reg(context) == 4) || (CX_reg(context) == 5))
{
if( hWNASPI32 == INVALID_HANDLE_VALUE )
{
TRACE("Loading WNASPI32\n");
hWNASPI32 = LoadLibraryExA("WNASPI32", 0, 0);
}
if( hWNASPI32 == INVALID_HANDLE_VALUE )
{
ERR("Error loading WNASPI32\n");
goto error_exit;
}
/* Get SendASPI32Command by Ordinal 2 */
/* Cast to correct argument/return types */
pSendASPI32Command = (DWORD (*)(LPSRB))GetProcAddress(hWNASPI32, (LPCSTR)2);
if( !pSendASPI32Command )
{
ERR("Error getting ordinal 2 from WNASPI32\n");
goto error_exit;
}
*p = DPMI_AllocInternalRMCB(ASPI_DOS_func);
TRACE("allocated real mode proc %p\n", *p);
SET_AX( context, CX_reg(context) );
return;
}
error_exit:
/* Return some error... General Failure sounds okay */
SET_AX( context, ERROR_GEN_FAILURE );
SET_CFLAG(context);
}
================================================
FILE: krnl386/dosdev.c
================================================
/*
* DOS devices
*
* Copyright 1999 Ove Kåven
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include
#include
#include "wine/winbase16.h"
#include "dosexe.h"
#include "wine/debug.h"
#include "pshpack1.h"
/* Warning: need to return LOL ptr w/ offset 0 (&ptr_first_DPB) to programs ! */
typedef struct _DOS_LISTOFLISTS
{
WORD CX_Int21_5e01; /* -24d contents of CX from INT 21/AX=5E01h */
WORD LRU_count_FCB_cache; /* -22d */
WORD LRU_count_FCB_open; /* -20d */
DWORD OEM_func_handler; /* -18d OEM function of INT 21/AH=F8h */
WORD INT21_offset; /* -14d offset in DOS CS of code to return from INT 21 call */
WORD sharing_retry_count; /* -12d */
WORD sharing_retry_delay; /* -10d */
DWORD ptr_disk_buf; /* -8d ptr to current disk buf */
WORD offs_unread_CON; /* -4d pointer in DOS data segment of unread CON input */
WORD seg_first_MCB; /* -2d */
DWORD ptr_first_DPB; /* 00 */
DWORD ptr_first_SysFileTable; /* 04 */
DWORD ptr_clock_dev_hdr; /* 08 */
DWORD ptr_CON_dev_hdr; /* 0C */
WORD max_byte_per_sec; /* 10 maximum bytes per sector of any block device */
DWORD ptr_disk_buf_info; /* 12 */
DWORD ptr_array_CDS; /* 16 current directory structure */
DWORD ptr_sys_FCB; /* 1A */
WORD nr_protect_FCB; /* 1E */
BYTE nr_block_dev; /* 20 */
BYTE nr_avail_drive_letters; /* 21 */
DOS_DEVICE_HEADER NUL_dev; /* 22 */
BYTE nr_drives_JOINed; /* 34 */
WORD ptr_spec_prg_names; /* 35 */
DWORD ptr_SETVER_prg_list; /* 37 */
WORD DOS_HIGH_A20_func_offs;/* 3B */
WORD PSP_last_exec; /* 3D if DOS in HMA: PSP of program executed last; if DOS low: 0000h */
WORD BUFFERS_val; /* 3F */
WORD BUFFERS_nr_lookahead; /* 41 */
BYTE boot_drive; /* 43 */
BYTE flag_DWORD_moves; /* 44 01h for 386+, 00h otherwise */
WORD size_extended_mem; /* 45 size of extended mem in KB */
SEGPTR wine_rm_lol; /* -- wine: Real mode pointer to LOL */
SEGPTR wine_pm_lol; /* -- wine: Protected mode pointer to LOL */
} DOS_LISTOFLISTS;
#include "poppack.h"
#define CON_BUFFER 128
enum strategy { SYSTEM_STRATEGY_NUL, SYSTEM_STRATEGY_CON, NB_SYSTEM_STRATEGIES };
static void *strategy_data[NB_SYSTEM_STRATEGIES];
#define LJMP 0xea
/* prototypes */
static void WINAPI nul_strategy(CONTEXT*ctx);
static void WINAPI nul_interrupt(CONTEXT*ctx);
static void WINAPI con_strategy(CONTEXT*ctx);
static void WINAPI con_interrupt(CONTEXT*ctx);
/* devices */
static const WINEDEV devs[] =
{
{ "NUL ",
ATTR_CHAR|ATTR_NUL|ATTR_DEVICE,
nul_strategy, nul_interrupt },
{ "CON ",
ATTR_CHAR|ATTR_STDIN|ATTR_STDOUT|ATTR_FASTCON|ATTR_NOTEOF|ATTR_DEVICE,
con_strategy, con_interrupt }
};
#define NR_DEVS (sizeof(devs)/sizeof(WINEDEV))
/* DOS data segment */
typedef struct
{
DOS_LISTOFLISTS lol;
DOS_DEVICE_HEADER dev[NR_DEVS-1];
DOS_DEVICE_HEADER *last_dev; /* ptr to last registered device driver */
WINEDEV_THUNK thunk[NR_DEVS];
REQ_IO req;
BYTE buffer[CON_BUFFER];
} DOS_DATASEG;
#define DOS_DATASEG_OFF(xxx) FIELD_OFFSET(DOS_DATASEG, xxx)
static DWORD DOS_LOLSeg;
static struct _DOS_LISTOFLISTS * DOSMEM_LOL(void)
{
return PTR_REAL_TO_LIN(HIWORD(DOS_LOLSeg),0);
}
/* the device implementations */
static void do_lret(CONTEXT*ctx)
{
WORD *stack = CTX_SEG_OFF_TO_LIN(ctx, ctx->SegSs, ctx->Esp);
ctx->Eip = *(stack++);
ctx->SegCs = *(stack++);
ctx->Esp += 2*sizeof(WORD);
}
static void do_strategy(CONTEXT*ctx, int id, int extra)
{
REQUEST_HEADER *hdr = CTX_SEG_OFF_TO_LIN(ctx, ctx->SegEs, ctx->Ebx);
void **hdr_ptr = strategy_data[id];
if (!hdr_ptr) {
hdr_ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(void *)+extra);
strategy_data[id] = hdr_ptr;
}
*hdr_ptr = hdr;
do_lret(ctx);
}
static REQUEST_HEADER * get_hdr(int id, void**extra)
{
void **hdr_ptr = strategy_data[id];
if (extra)
*extra = hdr_ptr ? (void*)(hdr_ptr+1) : NULL;
return hdr_ptr ? *hdr_ptr : NULL;
}
static void WINAPI nul_strategy(CONTEXT*ctx)
{
do_strategy(ctx, SYSTEM_STRATEGY_NUL, 0);
}
static void WINAPI nul_interrupt(CONTEXT*ctx)
{
REQUEST_HEADER *hdr = get_hdr(SYSTEM_STRATEGY_NUL, NULL);
/* eat everything and recycle nothing */
switch (hdr->command) {
case CMD_INPUT:
((REQ_IO*)hdr)->count = 0;
hdr->status = STAT_DONE;
break;
case CMD_SAFEINPUT:
hdr->status = STAT_DONE|STAT_BUSY;
break;
default:
hdr->status = STAT_DONE;
}
do_lret(ctx);
}
static void WINAPI con_strategy(CONTEXT*ctx)
{
do_strategy(ctx, SYSTEM_STRATEGY_CON, sizeof(int));
}
static void WINAPI con_interrupt(CONTEXT*ctx)
{
int *scan;
REQUEST_HEADER *hdr = get_hdr(SYSTEM_STRATEGY_CON,(void **)&scan);
BIOSDATA *bios = DOSVM_BiosData();
WORD CurOfs = bios->NextKbdCharPtr;
DOS_LISTOFLISTS *lol = DOSMEM_LOL();
DOS_DATASEG *dataseg = (DOS_DATASEG *)lol;
BYTE *linebuffer = dataseg->buffer;
BYTE *curbuffer = (lol->offs_unread_CON) ?
(((BYTE*)dataseg) + lol->offs_unread_CON) : NULL;
DOS_DEVICE_HEADER *con = dataseg->dev;
DWORD w;
switch (hdr->command) {
case CMD_INPUT:
{
REQ_IO *io = (REQ_IO *)hdr;
WORD count = io->count, len = 0;
BYTE *buffer = CTX_SEG_OFF_TO_LIN(ctx,
SELECTOROF(io->buffer),
(DWORD)OFFSETOF(io->buffer));
hdr->status = STAT_BUSY;
/* first, check whether we already have data in line buffer */
if (curbuffer) {
/* yep, copy as much as we can */
BYTE data = 0;
while ((lenoffs_unread_CON = 0;
curbuffer = NULL;
/* if we're not in raw mode, call it a day */
if (!(con->attr & ATTR_RAW)) {
hdr->status = STAT_DONE;
io->count = len;
break;
}
} else {
/* still some data left */
lol->offs_unread_CON = curbuffer - (BYTE*)lol;
/* but buffer was filled, we're done */
hdr->status = STAT_DONE;
io->count = len;
break;
}
}
/* if we're in raw mode, we just need to fill the buffer */
if (con->attr & ATTR_RAW) {
while (lenFirstKbdCharPtr) {
/* no input available yet, so wait... */
DOSVM_Wait( ctx );
}
/* read from keyboard queue (call int16?) */
data = ((WORD*)bios)[CurOfs];
CurOfs += 2;
if (CurOfs >= bios->KbdBufferEnd) CurOfs = bios->KbdBufferStart;
bios->NextKbdCharPtr = CurOfs;
/* if it's an extended key, save scancode */
if (LOBYTE(data) == 0) *scan = HIBYTE(data);
/* store ASCII char in buffer */
buffer[len++] = LOBYTE(data);
}
} else {
/* we're not in raw mode, so we need to do line input... */
while (TRUE) {
WORD data;
/* check for new keyboard input */
while (CurOfs == bios->FirstKbdCharPtr) {
/* no input available yet, so wait... */
DOSVM_Wait( ctx );
}
/* read from keyboard queue (call int16?) */
data = ((WORD*)bios)[CurOfs];
CurOfs += 2;
if (CurOfs >= bios->KbdBufferEnd) CurOfs = bios->KbdBufferStart;
bios->NextKbdCharPtr = CurOfs;
if (LOBYTE(data) == '\r') {
/* it's the return key, we're done */
linebuffer[len++] = LOBYTE(data);
break;
}
else if (LOBYTE(data) >= ' ') {
/* a character */
if ((len+1)0) {
len--;
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), "\b \b", 3, &w, NULL);
}
break;
}
}
if (len > count) {
/* save rest of line for later */
lol->offs_unread_CON = linebuffer - (BYTE*)lol + count;
len = count;
}
memcpy(buffer, linebuffer, len);
}
hdr->status = STAT_DONE;
io->count = len;
}
break;
case CMD_SAFEINPUT:
if (curbuffer) {
/* some line input waiting */
hdr->status = STAT_DONE;
((REQ_SAFEINPUT*)hdr)->data = *curbuffer;
}
else if (con->attr & ATTR_RAW) {
if (CurOfs == bios->FirstKbdCharPtr) {
/* no input */
hdr->status = STAT_DONE|STAT_BUSY;
} else {
/* some keyboard input waiting */
hdr->status = STAT_DONE;
((REQ_SAFEINPUT*)hdr)->data = ((BYTE*)bios)[CurOfs];
}
} else {
/* no line input */
hdr->status = STAT_DONE|STAT_BUSY;
}
break;
case CMD_INSTATUS:
if (curbuffer) {
/* we have data */
hdr->status = STAT_DONE;
}
else if (con->attr & ATTR_RAW) {
if (CurOfs == bios->FirstKbdCharPtr) {
/* no input */
hdr->status = STAT_DONE|STAT_BUSY;
} else {
/* some keyboard input waiting */
hdr->status = STAT_DONE;
}
} else {
/* no line input */
hdr->status = STAT_DONE|STAT_BUSY;
}
break;
case CMD_INFLUSH:
/* flush line and keyboard queue */
lol->offs_unread_CON = 0;
bios->NextKbdCharPtr = bios->FirstKbdCharPtr;
break;
case CMD_OUTPUT:
case CMD_SAFEOUTPUT:
{
REQ_IO *io = (REQ_IO *)hdr;
BYTE *buffer = CTX_SEG_OFF_TO_LIN(ctx,
SELECTOROF(io->buffer),
(DWORD)OFFSETOF(io->buffer));
DWORD result = 0;
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), buffer, io->count, &result, NULL);
io->count = result;
hdr->status = STAT_DONE;
}
break;
default:
hdr->status = STAT_DONE;
}
do_lret(ctx);
}
static void InitListOfLists(DOS_LISTOFLISTS *DOS_LOL)
{
/*
Output of DOS 6.22:
0133:0020 6A 13-33 01 CC 00 33 01 59 00 j.3...3.Y.
0133:0030 70 00 00 00 72 02 00 02-6D 00 33 01 00 00 2E 05 p...r...m.3.....
0133:0040 00 00 FC 04 00 00 03 08-92 21 11 E0 04 80 C6 0D .........!......
0133:0050 CC 0D 4E 55 4C 20 20 20-20 20 00 00 00 00 00 00 ..NUL ......
0133:0060 00 4B BA C1 06 14 00 00-00 03 01 00 04 70 CE FF .K...........p..
0133:0070 FF 00 00 00 00 00 00 00-00 01 00 00 0D 05 00 00 ................
0133:0080 00 FF FF 00 00 00 00 FE-00 00 F8 03 FF 9F 70 02 ..............p.
0133:0090 D0 44 C8 FD D4 44 C8 FD-D4 44 C8 FD D0 44 C8 FD .D...D...D...D..
0133:00A0 D0 44 C8 FD D0 44 .D...D
*/
DOS_LOL->CX_Int21_5e01 = 0x0;
DOS_LOL->LRU_count_FCB_cache = 0x0;
DOS_LOL->LRU_count_FCB_open = 0x0;
DOS_LOL->OEM_func_handler = -1; /* not available */
DOS_LOL->INT21_offset = 0x0;
DOS_LOL->sharing_retry_count = 3;
DOS_LOL->sharing_retry_delay = 1;
DOS_LOL->ptr_disk_buf = 0x0;
DOS_LOL->offs_unread_CON = 0x0;
DOS_LOL->seg_first_MCB = 0x0;
DOS_LOL->ptr_first_DPB = 0x0;
DOS_LOL->ptr_first_SysFileTable = 0x0;
DOS_LOL->ptr_clock_dev_hdr = 0x0;
DOS_LOL->ptr_CON_dev_hdr = 0x0;
DOS_LOL->max_byte_per_sec = 512;
DOS_LOL->ptr_disk_buf_info = 0x0;
DOS_LOL->ptr_array_CDS = 0x0;
DOS_LOL->ptr_sys_FCB = 0x0;
DOS_LOL->nr_protect_FCB = 0x0;
DOS_LOL->nr_block_dev = 0x0;
DOS_LOL->nr_avail_drive_letters = 26; /* A - Z */
DOS_LOL->nr_drives_JOINed = 0x0;
DOS_LOL->ptr_spec_prg_names = 0x0;
DOS_LOL->ptr_SETVER_prg_list = 0x0; /* no SETVER list */
DOS_LOL->DOS_HIGH_A20_func_offs = 0x0;
DOS_LOL->PSP_last_exec = 0x0;
DOS_LOL->BUFFERS_val = 99; /* maximum: 99 */
DOS_LOL->BUFFERS_nr_lookahead = 8; /* maximum: 8 */
DOS_LOL->boot_drive = 3; /* C: */
DOS_LOL->flag_DWORD_moves = 0x01; /* i386+ */
DOS_LOL->size_extended_mem = 0xf000; /* very high value */
}
void DOSDEV_SetupDevice(const WINEDEV * devinfo,
WORD seg, WORD off_dev, WORD off_thunk)
{
DOS_DEVICE_HEADER *dev = PTR_REAL_TO_LIN(seg, off_dev);
WINEDEV_THUNK *thunk = PTR_REAL_TO_LIN(seg, off_thunk);
DOS_DATASEG *dataseg = (DOS_DATASEG*)DOSMEM_LOL();
dev->attr = devinfo->attr;
dev->strategy = off_thunk + FIELD_OFFSET(WINEDEV_THUNK, ljmp1);
dev->interrupt = off_thunk + FIELD_OFFSET(WINEDEV_THUNK, ljmp2);
memcpy(dev->name, devinfo->name, 8);
thunk->ljmp1 = LJMP;
thunk->strategy = DPMI_AllocInternalRMCB(devinfo->strategy);
thunk->ljmp2 = LJMP;
thunk->interrupt = DPMI_AllocInternalRMCB(devinfo->interrupt);
dev->next_dev = NONEXT;
if (dataseg->last_dev)
dataseg->last_dev->next_dev = MAKESEGPTR(seg, off_dev);
dataseg->last_dev = dev;
}
void DOSDEV_InstallDOSDevices(void)
{
DOS_DATASEG *dataseg;
WORD seg;
WORD selector;
unsigned int n;
/* allocate DOS data segment or something */
dataseg = DOSVM_AllocDataUMB( sizeof(DOS_DATASEG), &seg, &selector );
DOS_LOLSeg = MAKESEGPTR( seg, 0 );
DOSMEM_LOL()->wine_rm_lol =
MAKESEGPTR( seg, FIELD_OFFSET(DOS_LISTOFLISTS, ptr_first_DPB) );
DOSMEM_LOL()->wine_pm_lol =
MAKESEGPTR( selector, FIELD_OFFSET(DOS_LISTOFLISTS, ptr_first_DPB) );
/* initialize the magnificent List Of Lists */
InitListOfLists(&dataseg->lol);
/* Set up first device (NUL) */
dataseg->last_dev = NULL;
DOSDEV_SetupDevice( &devs[0],
seg,
DOS_DATASEG_OFF(lol.NUL_dev),
DOS_DATASEG_OFF(thunk[0]) );
/* Set up the remaining devices */
for (n = 1; n < NR_DEVS; n++)
DOSDEV_SetupDevice( &devs[n],
seg,
DOS_DATASEG_OFF(dev[n-1]),
DOS_DATASEG_OFF(thunk[n]) );
/* CON is device 1 */
dataseg->lol.ptr_CON_dev_hdr = MAKESEGPTR(seg, DOS_DATASEG_OFF(dev[0]));
}
void DOSDEV_SetSharingRetry(WORD delay, WORD count)
{
DOSMEM_LOL()->sharing_retry_delay = delay;
if (count) DOSMEM_LOL()->sharing_retry_count = count;
}
SEGPTR DOSDEV_GetLOL(BOOL v86)
{
if (v86) return DOSMEM_LOL()->wine_rm_lol;
else return DOSMEM_LOL()->wine_pm_lol;
}
================================================
FILE: krnl386/dosexe.c
================================================
/*
* DOS (MZ) loader
*
* Copyright 1998 Ove Kåven
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*
* Note: This code hasn't been completely cleaned up yet.
*/
#include "config.h"
#include "wine/port.h"
#include
#include
#include
#include
#include
#include
#ifdef HAVE_UNISTD_H
# include
#endif
#include
#ifdef HAVE_SYS_STAT_H
# include
#endif
#ifdef HAVE_SYS_TIME_H
# include
#endif
#include "windef.h"
#include "winbase.h"
#include "wine/winbase16.h"
#include "wingdi.h"
#include "winuser.h"
#include "winerror.h"
#include "wine/debug.h"
#include "kernel16_private.h"
#include "dosexe.h"
#include "vga.h"
#include "../toolhelp/toolhelp.h"
WINE_DEFAULT_DEBUG_CHANNEL(module);
static BOOL DOSVM_isdosexe;
/**********************************************************************
* DOSVM_IsWin16
*
* Return TRUE if we are in Windows process.
*/
BOOL DOSVM_IsWin16(void)
{
return !DOSVM_isdosexe;
}
/**********************************************************************
* DOSVM_Exit
*/
void DOSVM_Exit( WORD retval )
{
DWORD count;
TOOLHELP_CallNotify(NFY_EXITTASK, retval);
ReleaseThunkLock( &count );
ExitThread( retval );
}
#ifdef MZ_SUPPORTED
#define BIOS_DATA_SEGMENT 0x40
#define PSP_SIZE 0x10
#define SEG16(ptr,seg) ((LPVOID)((BYTE*)ptr+((DWORD)(seg)<<4)))
#define SEGPTR16(ptr,segptr) ((LPVOID)((BYTE*)ptr+((DWORD)SELECTOROF(segptr)<<4)+OFFSETOF(segptr)))
/* structures for EXEC */
#include "pshpack1.h"
typedef struct {
WORD env_seg;
DWORD cmdline;
DWORD fcb1;
DWORD fcb2;
WORD init_sp;
WORD init_ss;
WORD init_ip;
WORD init_cs;
} ExecBlock;
typedef struct {
WORD load_seg;
WORD rel_seg;
} OverlayBlock;
#include "poppack.h"
/* global variables */
pid_t dosvm_pid;
static WORD init_cs,init_ip,init_ss,init_sp;
static HANDLE dosvm_thread, loop_thread;
static DWORD dosvm_tid, loop_tid;
static DWORD MZ_Launch( LPCSTR cmdtail, int length );
static BOOL MZ_InitTask(void);
static void MZ_CreatePSP( LPVOID lpPSP, WORD env, WORD par )
{
PDB16*psp=lpPSP;
psp->int20=0x20CD; /* int 20 */
/* some programs use this to calculate how much memory they need */
psp->nextParagraph=0x9FFF; /* FIXME: use a real value */
/* FIXME: dispatcher */
psp->savedint22 = DOSVM_GetRMHandler(0x22);
psp->savedint23 = DOSVM_GetRMHandler(0x23);
psp->savedint24 = DOSVM_GetRMHandler(0x24);
psp->parentPSP=par;
psp->environment=env;
/* FIXME: more PSP stuff */
}
extern char *DOSMEM_dosmem;
static void MZ_FillPSP( LPVOID lpPSP, LPCSTR cmdtail, int length )
{
PDB16 *psp = (PDB16*)lpPSP;
if(length > 127)
{
WARN( "Command tail truncated! (length %d)\n", length );
length = 126;
}
psp->cmdLine[0] = length;
/*
* Length of exactly 127 bytes means that full command line is
* stored in environment variable CMDLINE and PSP contains
* command tail truncated to 126 bytes.
*/
if(length == 127)
length = 126;
if(length > 0)
memmove(psp->cmdLine+1, cmdtail, length);
psp->cmdLine[length+1] = '\r';
/* FIXME: more PSP stuff */
}
static WORD MZ_InitEnvironment( LPCSTR env, LPCSTR name )
{
unsigned sz=0;
unsigned i=0;
WORD seg;
LPSTR envblk;
if (env) {
/* get size of environment block */
while (env[sz++]) sz+=strlen(env+sz)+1;
} else sz++;
/* allocate it */
envblk=DOSMEM_AllocBlock(sz+sizeof(WORD)+strlen(name)+1,&seg);
/* fill it */
if (env) {
memcpy(envblk,env,sz);
} else envblk[0]=0;
/* DOS environment variables are uppercase */
while (envblk[i]){
while (envblk[i] != '='){
if (envblk[i]>='a' && envblk[i] <= 'z'){
envblk[i] -= 32;
}
i++;
}
i += strlen(envblk+i) + 1;
}
/* DOS 3.x: the block contains 1 additional string */
*(WORD*)(envblk+sz)=1;
/* being the program name itself */
strcpy(envblk+sz+sizeof(WORD),name);
return seg;
}
static BOOL MZ_InitMemory(void)
{
/* initialize the memory */
TRACE("Initializing DOS memory structures\n");
DOSMEM_MapDosLayout();
DOSDEV_InstallDOSDevices();
MSCDEX_InstallCDROM();
return TRUE;
}
static BOOL MZ_DoLoadImage( HANDLE hFile, LPCSTR filename, OverlayBlock *oblk, WORD par_env_seg )
{
IMAGE_DOS_HEADER mz_header;
DWORD image_start,image_size,min_size,max_size,avail;
BYTE*psp_start,*load_start;
LPSTR oldenv = 0;
int x, old_com=0, alloc;
SEGPTR reloc;
WORD env_seg, load_seg, rel_seg, oldpsp_seg;
DWORD len;
if (DOSVM_psp) {
/* DOS process already running, inherit from it */
PDB16* par_psp;
alloc=0;
oldpsp_seg = DOSVM_psp;
if( !par_env_seg) {
par_psp = (PDB16*)PTR_REAL_TO_LIN(DOSVM_psp, 0);
oldenv = (LPSTR)((DWORD)PTR_REAL_TO_LIN(par_psp->environment, 0));
}
} else {
/* allocate new DOS process, inheriting from Wine environment */
alloc=1;
oldpsp_seg = 0;
if( !par_env_seg)
oldenv = GetEnvironmentStringsA();
}
SetFilePointer(hFile,0,NULL,FILE_BEGIN);
if ( !ReadFile(hFile,&mz_header,sizeof(mz_header),&len,NULL)
|| len != sizeof(mz_header)
|| mz_header.e_magic != IMAGE_DOS_SIGNATURE) {
const char *p = strrchr( filename, '.' );
if (!p || strcasecmp( p, ".com" )) /* check for .COM extension */
{
SetLastError(ERROR_BAD_FORMAT);
goto load_error;
}
old_com=1; /* assume .COM file */
image_start=0;
image_size=GetFileSize(hFile,NULL);
min_size=0x10000; max_size=0x100000;
mz_header.e_crlc=0;
mz_header.e_ss=0; mz_header.e_sp=0xFFFE;
mz_header.e_cs=0; mz_header.e_ip=0x100;
} else {
/* calculate load size */
image_start=mz_header.e_cparhdr<<4;
image_size=mz_header.e_cp<<9; /* pages are 512 bytes */
/* From Ralf Brown Interrupt List: If the word at offset 02h is 4, it should
* be treated as 00h, since pre-1.10 versions of the MS linker set it that
* way. */
if ((mz_header.e_cblp!=0)&&(mz_header.e_cblp!=4)) image_size-=512-mz_header.e_cblp;
image_size-=image_start;
min_size=image_size+((DWORD)mz_header.e_minalloc<<4)+(PSP_SIZE<<4);
max_size=image_size+((DWORD)mz_header.e_maxalloc<<4)+(PSP_SIZE<<4);
}
if (alloc) MZ_InitMemory();
if (oblk) {
/* load overlay into preallocated memory */
load_seg=oblk->load_seg;
rel_seg=oblk->rel_seg;
load_start=(LPBYTE)((DWORD)load_seg<<4);
} else {
/* allocate environment block */
if( par_env_seg)
env_seg = par_env_seg;
else
env_seg=MZ_InitEnvironment(oldenv, filename);
if (alloc)
FreeEnvironmentStringsA( oldenv);
/* allocate memory for the executable */
TRACE("Allocating DOS memory (min=%d, max=%d)\n",min_size,max_size);
avail=DOSMEM_Available();
if (availmax_size) avail=max_size;
psp_start=DOSMEM_AllocBlock(avail,&DOSVM_psp);
if (!psp_start) {
ERR("error allocating DOS memory\n");
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto load_error;
}
load_seg=DOSVM_psp+(old_com?0:PSP_SIZE);
rel_seg=load_seg;
load_start=psp_start+(PSP_SIZE<<4);
MZ_CreatePSP(psp_start, env_seg, oldpsp_seg);
}
/* load executable image */
TRACE("loading DOS %s image, %08x bytes\n",old_com?"COM":"EXE",image_size);
SetFilePointer(hFile,image_start,NULL,FILE_BEGIN);
if (!ReadFile(hFile,load_start,image_size,&len,NULL) || len != image_size) {
/* check if this is due to the workaround for the pre-1.10 MS linker and we
really had only 4 bytes on the last page */
if (mz_header.e_cblp != 4 || image_size - len != 512 - 4) {
SetLastError(ERROR_BAD_FORMAT);
goto load_error;
}
}
if (mz_header.e_crlc) {
/* load relocation table */
TRACE("loading DOS EXE relocation table, %d entries\n",mz_header.e_crlc);
/* FIXME: is this too slow without read buffering? */
SetFilePointer(hFile,mz_header.e_lfarlc,NULL,FILE_BEGIN);
for (x=0; x 126)
{
char *cmd = HeapAlloc( GetProcessHeap(), 0,
dos_length + strlen(filename) + 4 );
char *ptr = cmd;
if (!cmd)
return;
/*
* Append filename. If path includes spaces, quote the path.
*/
if (strchr(filename, ' '))
{
*ptr++ = '\"';
strcpy( ptr, filename );
ptr += strlen(filename);
*ptr++ = '\"';
}
else
{
strcpy( ptr, filename );
ptr += strlen(filename);
}
/*
* Append command tail.
*/
if (cmdline[0] != ' ')
*ptr++ = ' ';
strcpy( ptr, cmdline );
/*
* Set environment variable. This will be passed to
* new DOS process.
*/
if (!SetEnvironmentVariableA( "CMDLINE", cmd ))
{
HeapFree(GetProcessHeap(), 0, cmd );
return;
}
HeapFree(GetProcessHeap(), 0, cmd );
dos_length = 127;
}
}
AllocConsole();
SetConsoleTitleA(filename);
if (MZ_DoLoadImage( hFile, filename, NULL, 0 ))
{
DWORD err = MZ_Launch( dos_cmdtail, dos_length );
/* if we get back here it failed */
SetLastError( err );
}
}
/***********************************************************************
* MZ_Exec
*
* this may only be called from existing DOS processes
*/
BOOL MZ_Exec( CONTEXT *context, LPCSTR filename, BYTE func, LPVOID paramblk )
{
DWORD binType;
STARTUPINFOA st;
PROCESS_INFORMATION pe;
HANDLE hFile;
BOOL ret = FALSE;
if(!GetBinaryTypeA(filename, &binType)) /* determine what kind of binary this is */
{
return FALSE; /* binary is not an executable */
}
/* handle non-dos executables */
if(binType != SCS_DOS_BINARY)
{
if(func == 0) /* load and execute */
{
LPSTR fullCmdLine;
WORD fullCmdLength;
LPBYTE psp_start = (LPBYTE)PTR_REAL_TO_LIN(DOSVM_psp, 0);
PDB16 *psp = (PDB16 *)psp_start;
ExecBlock *blk = paramblk;
LPBYTE cmdline = PTR_REAL_TO_LIN(SELECTOROF(blk->cmdline),OFFSETOF(blk->cmdline));
LPBYTE envblock = PTR_REAL_TO_LIN(psp->environment, 0);
int cmdLength = cmdline[0];
/*
* If cmdLength is 127, command tail is truncated and environment
* variable CMDLINE should contain full command line
* (this includes filename).
*/
if (cmdLength == 127)
{
FIXME( "CMDLINE argument passing is unimplemented.\n" );
cmdLength = 126; /* FIXME */
}
fullCmdLength = (strlen(filename) + 1) + cmdLength + 1; /* filename + space + cmdline + terminating null character */
fullCmdLine = HeapAlloc(GetProcessHeap(), 0, fullCmdLength);
if(!fullCmdLine) return FALSE; /* return false on memory alloc failure */
/* build the full command line from the executable file and the command line being passed in */
snprintf(fullCmdLine, fullCmdLength, "%s ", filename); /* start off with the executable filename and a space */
memcpy(fullCmdLine + strlen(fullCmdLine), cmdline + 1, cmdLength); /* append cmdline onto the end */
fullCmdLine[fullCmdLength - 1] = 0; /* null terminate string */
ZeroMemory (&st, sizeof(STARTUPINFOA));
st.cb = sizeof(STARTUPINFOA);
ret = CreateProcessA (NULL, fullCmdLine, NULL, NULL, TRUE, 0, envblock, NULL, &st, &pe);
/* wait for the app to finish and clean up PROCESS_INFORMATION handles */
if(ret)
{
WaitForSingleObject(pe.hProcess, INFINITE); /* wait here until the child process is complete */
CloseHandle(pe.hProcess);
CloseHandle(pe.hThread);
}
HeapFree(GetProcessHeap(), 0, fullCmdLine); /* free the memory we allocated */
}
else
{
FIXME("EXEC type of %d not implemented for non-dos executables\n", func);
ret = FALSE;
}
return ret;
} /* if(binType != SCS_DOS_BINARY) */
/* handle dos executables */
hFile = CreateFileA( filename, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, 0, 0);
if (hFile == INVALID_HANDLE_VALUE) return FALSE;
switch (func) {
case 0: /* load and execute */
case 1: /* load but don't execute */
{
/* save current process's return SS:SP now */
LPBYTE psp_start = (LPBYTE)PTR_REAL_TO_LIN(DOSVM_psp, 0);
PDB16 *psp = (PDB16 *)psp_start;
psp->saveStack = (DWORD)MAKESEGPTR(context->SegSs, LOWORD(context->Esp));
}
ret = MZ_DoLoadImage( hFile, filename, NULL, ((ExecBlock *)paramblk)->env_seg );
if (ret) {
/* MZ_LoadImage created a new PSP and loaded new values into it,
* let's work on the new values now */
LPBYTE psp_start = (LPBYTE)PTR_REAL_TO_LIN(DOSVM_psp, 0);
ExecBlock *blk = paramblk;
LPBYTE cmdline = PTR_REAL_TO_LIN(SELECTOROF(blk->cmdline),OFFSETOF(blk->cmdline));
/* First character contains the length of the command line. */
MZ_FillPSP(psp_start, (LPSTR)cmdline + 1, cmdline[0]);
/* the lame MS-DOS engineers decided that the return address should be in int22 */
DOSVM_SetRMHandler(0x22, (FARPROC16)MAKESEGPTR(context->SegCs, LOWORD(context->Eip)));
if (func) {
/* don't execute, just return startup state */
/*
* From Ralph Brown:
* For function 01h, the AX value to be passed to the child program
* is put on top of the child's stack
*/
LPBYTE stack;
init_sp -= 2;
stack = CTX_SEG_OFF_TO_LIN(context, init_ss, init_sp);
/* FIXME: push AX correctly */
stack[0] = 0x00; /* push AL */
stack[1] = 0x00; /* push AH */
blk->init_cs = init_cs;
blk->init_ip = init_ip;
blk->init_ss = init_ss;
blk->init_sp = init_sp;
} else {
/* execute by making us return to new process */
context->SegCs = init_cs;
context->Eip = init_ip;
context->SegSs = init_ss;
context->Esp = init_sp;
context->SegDs = DOSVM_psp;
context->SegEs = DOSVM_psp;
context->Eax = 0;
}
}
break;
case 3: /* load overlay */
{
OverlayBlock *blk = paramblk;
ret = MZ_DoLoadImage( hFile, filename, blk, 0);
}
break;
default:
FIXME("EXEC load type %d not implemented\n", func);
SetLastError(ERROR_INVALID_FUNCTION);
break;
}
CloseHandle(hFile);
return ret;
}
/***********************************************************************
* MZ_AllocDPMITask
*/
void MZ_AllocDPMITask( void )
{
MZ_InitMemory();
MZ_InitTask();
}
/***********************************************************************
* MZ_RunInThread
*/
void MZ_RunInThread( PAPCFUNC proc, ULONG_PTR arg )
{
if (loop_thread) {
DOS_SPC spc;
HANDLE event;
spc.proc = proc;
spc.arg = arg;
event = CreateEventW(NULL, TRUE, FALSE, NULL);
PostThreadMessageA(loop_tid, WM_USER + 1, (WPARAM)event, (LPARAM)&spc);
WaitForSingleObject(event, INFINITE);
CloseHandle(event);
} else
proc(arg);
}
void *dosvm_vm86_teb_info;
static DWORD WINAPI MZ_DOSVM( LPVOID lpExtra )
{
CONTEXT context;
INT ret;
dosvm_pid = getpid();
memset( &context, 0, sizeof(context) );
context.SegCs = init_cs;
context.Eip = init_ip;
context.SegSs = init_ss;
context.Esp = init_sp;
context.SegDs = DOSVM_psp;
context.SegEs = DOSVM_psp;
context.EFlags = V86_FLAG | VIF_MASK;
DOSVM_SetTimer(0x10000);
dosvm_vm86_teb_info = get_vm86_teb_info();
ret = DOSVM_Enter( &context );
if (ret == -1) ret = GetLastError();
dosvm_pid = 0;
return ret;
}
static BOOL MZ_InitTask(void)
{
if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
GetCurrentProcess(), &loop_thread,
0, FALSE, DUPLICATE_SAME_ACCESS))
return FALSE;
dosvm_thread = CreateThread(NULL, 0, MZ_DOSVM, NULL, CREATE_SUSPENDED, &dosvm_tid);
if (!dosvm_thread) {
CloseHandle(loop_thread);
loop_thread = 0;
return FALSE;
}
loop_tid = GetCurrentThreadId();
return TRUE;
}
static DWORD MZ_Launch( LPCSTR cmdtail, int length )
{
TDB *pTask = GlobalLock16( GetCurrentTask() );
BYTE *psp_start = PTR_REAL_TO_LIN( DOSVM_psp, 0 );
DWORD rv;
SYSLEVEL *lock;
MSG msg;
MZ_FillPSP(psp_start, cmdtail, length);
pTask->flags |= TDBF_WINOLDAP;
/* DTA is set to PSP:0080h when a program is started. */
pTask->dta = MAKESEGPTR( DOSVM_psp, 0x80 );
GetpWin16Lock( &lock );
_LeaveSysLevel( lock );
/* force the message queue to be created */
PeekMessageW(&msg, NULL, WM_USER + 1, WM_USER + 1, PM_NOREMOVE);
ResumeThread(dosvm_thread);
rv = DOSVM_Loop(dosvm_thread);
CloseHandle(dosvm_thread);
dosvm_thread = 0; dosvm_tid = 0;
CloseHandle(loop_thread);
loop_thread = 0; loop_tid = 0;
if (rv) return rv;
VGA_Clean();
ExitProcess(0);
}
/***********************************************************************
* MZ_Exit
*/
void MZ_Exit( CONTEXT *context, BOOL cs_psp, WORD retval )
{
if (DOSVM_psp) {
WORD psp_seg = cs_psp ? context->SegCs : DOSVM_psp;
LPBYTE psp_start = (LPBYTE)PTR_REAL_TO_LIN(psp_seg, 0);
PDB16 *psp = (PDB16 *)psp_start;
WORD parpsp = psp->parentPSP; /* check for parent DOS process */
if (parpsp) {
/* retrieve parent's return address */
FARPROC16 retaddr = DOSVM_GetRMHandler(0x22);
/* restore interrupts */
DOSVM_SetRMHandler(0x22, psp->savedint22);
DOSVM_SetRMHandler(0x23, psp->savedint23);
DOSVM_SetRMHandler(0x24, psp->savedint24);
/* FIXME: deallocate file handles etc */
/* free process's associated memory
* FIXME: walk memory and deallocate all blocks owned by process */
DOSMEM_FreeBlock( PTR_REAL_TO_LIN(psp->environment,0) );
DOSMEM_FreeBlock( PTR_REAL_TO_LIN(DOSVM_psp,0) );
/* switch to parent's PSP */
DOSVM_psp = parpsp;
psp_start = (LPBYTE)((DWORD)PTR_REAL_TO_LIN(parpsp, 0));
psp = (PDB16 *)psp_start;
/* now return to parent */
DOSVM_retval = retval;
context->SegCs = SELECTOROF(retaddr);
context->Eip = OFFSETOF(retaddr);
context->SegSs = SELECTOROF(psp->saveStack);
context->Esp = OFFSETOF(psp->saveStack);
return;
} else
TRACE("killing DOS task\n");
}
DOSVM_Exit( retval );
}
/***********************************************************************
* MZ_Current
*/
BOOL MZ_Current( void )
{
return (dosvm_pid != 0); /* FIXME: do a better check */
}
#else /* !MZ_SUPPORTED */
/***********************************************************************
* __wine_load_dos_exe (KERNEL.@)
*/
void __wine_load_dos_exe( LPCSTR filename, LPCSTR cmdline )
{
SetLastError( ERROR_NOT_SUPPORTED );
}
/***********************************************************************
* MZ_Exec
*/
BOOL MZ_Exec( CONTEXT *context, LPCSTR filename, BYTE func, LPVOID paramblk )
{
/* can't happen */
SetLastError(ERROR_BAD_FORMAT);
return FALSE;
}
/***********************************************************************
* MZ_AllocDPMITask
*/
void MZ_AllocDPMITask( void )
{
FIXME("Actual real-mode calls not supported on this platform!\n");
}
/***********************************************************************
* MZ_RunInThread
*/
void MZ_RunInThread( PAPCFUNC proc, ULONG_PTR arg )
{
proc(arg);
}
/***********************************************************************
* MZ_Exit
*/
void MZ_Exit( CONTEXT *context, BOOL cs_psp, WORD retval )
{
DOSVM_Exit( retval );
}
/***********************************************************************
* MZ_Current
*/
BOOL MZ_Current( void )
{
return FALSE;
}
#endif /* !MZ_SUPPORTED */
================================================
FILE: krnl386/dosexe.h
================================================
/*
* DOS EXE loader
*
* Copyright 1998 Ove Kåven
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef __WINE_DOSEXE_H
#define __WINE_DOSEXE_H
#include
#include
#include "windef.h"
#include "wine/library.h"
#include "wine/windef16.h"
#include "winbase.h"
#include "winnt.h" /* for PCONTEXT */
#include "wincon.h" /* for MOUSE_EVENT_RECORD */
#ifndef DECLSPEC_HIDDEN
#define DECLSPEC_HIDDEN
#endif
#define MAX_DOS_DRIVES 26
struct _DOSEVENT;
typedef struct {
PAPCFUNC proc;
ULONG_PTR arg;
} DOS_SPC;
typedef int pid_t;
extern pid_t dosvm_pid DECLSPEC_HIDDEN;
/* amount of space reserved for relay stack */
#define DOSVM_RELAY_DATA_SIZE 4096
/* various real-mode code stubs */
struct DPMI_segments
{
WORD wrap_seg;
WORD xms_seg;
WORD dpmi_seg;
WORD dpmi_sel;
WORD int48_sel;
WORD int16_sel;
WORD relay_code_sel;
WORD relay_data_sel;
};
/* 48-bit segmented pointers for DOS DPMI32 */
typedef struct {
WORD selector;
DWORD offset;
} SEGPTR48, FARPROC48;
typedef void (*DOSRELAY)(CONTEXT*,void*);
typedef void (WINAPI *RMCBPROC)(CONTEXT*);
typedef void (WINAPI *INTPROC)(CONTEXT*);
typedef void (WINAPI *OUTPROC)(int port, int size, DWORD value);
typedef DWORD (WINAPI *INPROC)(int port, int size);
#define DOS_PRIORITY_REALTIME 0 /* IRQ0 */
#define DOS_PRIORITY_KEYBOARD 1 /* IRQ1 */
#define DOS_PRIORITY_VGA 2 /* IRQ9 */
#define DOS_PRIORITY_MOUSE 5 /* IRQ12 */
#define DOS_PRIORITY_SERIAL 10 /* IRQ4 */
extern WORD DOSVM_psp DECLSPEC_HIDDEN; /* psp of current DOS task */
extern WORD DOSVM_retval DECLSPEC_HIDDEN; /* return value of previous DOS task */
extern struct DPMI_segments *DOSVM_dpmi_segments DECLSPEC_HIDDEN;
#if defined(linux) && defined(__i386__) && defined(HAVE_SYS_VM86_H)
# define MZ_SUPPORTED
#endif /* linux-i386 */
/*
* Declare some CONTEXT.EFlags bits.
* IF_MASK is only pushed into real mode stack.
*/
#define V86_FLAG 0x00020000
#define TF_MASK 0x00000100
#define IF_MASK 0x00000200
#define VIF_MASK 0x00080000
#define VIP_MASK 0x00100000
#define ADD_LOWORD(dw,val) ((dw) = ((dw) & 0xffff0000) | LOWORD((DWORD)(dw)+(val)))
#define PTR_REAL_TO_LIN(seg,off) ((void*)(((unsigned int)(seg) << 4) + LOWORD(off) + (size_t)DOSMEM_dosmem))
/* NOTE: Interrupts might get called from four modes: real mode, 16-bit,
* 32-bit segmented (DPMI32) and 32-bit linear (via DeviceIoControl).
* For automatic conversion of pointer
* parameters, interrupt handlers should use CTX_SEG_OFF_TO_LIN with
* the contents of a segment register as second and the contents of
* a *32-bit* general register as third parameter, e.g.
* CTX_SEG_OFF_TO_LIN( context, DS_reg(context), EDX_reg(context) )
* This will generate a linear pointer in all three cases:
* Real-Mode: Seg*16 + LOWORD(Offset)
* 16-bit: convert (Seg, LOWORD(Offset)) to linear
* 32-bit segmented: convert (Seg, Offset) to linear
* 32-bit linear: use Offset as linear address (DeviceIoControl!)
*
* Real-mode is recognized by checking the V86 bit in the flags register,
* 32-bit linear mode is recognized by checking whether 'seg' is
* a system selector (0 counts also as 32-bit segment) and 32-bit
* segmented mode is recognized by checking whether 'seg' is 32-bit
* selector which is neither system selector nor zero.
*/
#define CTX_SEG_OFF_TO_LIN(context,seg,off) \
(ISV86(context) ? PTR_REAL_TO_LIN((seg),(off)) : wine_ldt_get_ptr((seg),(off)))
#define INT_BARF(context,num) \
ERR( "int%x: unknown/not implemented parameters:\n" \
"int%x: AX %04x, BX %04x, CX %04x, DX %04x, " \
"SI %04x, DI %04x, DS %04x, ES %04x\n", \
(num), (num), LOWORD((context)->Eax), LOWORD((context)->Ebx), \
LOWORD((context)->Ecx), LOWORD((context)->Edx), LOWORD((context)->Esi), \
LOWORD((context)->Edi), (WORD)(context)->SegDs, (WORD)(context)->SegEs )
/* pushing on stack in 16 bit needs segment wrap around */
#define PUSH_WORD16(context,val) \
*((WORD*)CTX_SEG_OFF_TO_LIN((context), \
(context)->SegSs, ADD_LOWORD( context->Esp, -2 ) )) = (val)
/* Macros for easier access to i386 context registers */
#define AX_reg(context) ((WORD)(context)->Eax)
#define BX_reg(context) ((WORD)(context)->Ebx)
#define CX_reg(context) ((WORD)(context)->Ecx)
#define DX_reg(context) ((WORD)(context)->Edx)
#define SI_reg(context) ((WORD)(context)->Esi)
#define DI_reg(context) ((WORD)(context)->Edi)
#define AL_reg(context) ((BYTE)(context)->Eax)
#define AH_reg(context) ((BYTE)((context)->Eax >> 8))
#define BL_reg(context) ((BYTE)(context)->Ebx)
#define BH_reg(context) ((BYTE)((context)->Ebx >> 8))
#define CL_reg(context) ((BYTE)(context)->Ecx)
#define CH_reg(context) ((BYTE)((context)->Ecx >> 8))
#define DL_reg(context) ((BYTE)(context)->Edx)
#define DH_reg(context) ((BYTE)((context)->Edx >> 8))
#define SET_CFLAG(context) ((context)->EFlags |= 0x0001)
#define RESET_CFLAG(context) ((context)->EFlags &= ~0x0001)
#define SET_ZFLAG(context) ((context)->EFlags |= 0x0040)
#define RESET_ZFLAG(context) ((context)->EFlags &= ~0x0040)
#define ISV86(context) ((context)->EFlags & 0x00020000)
#define SET_AX(context,val) ((void)((context)->Eax = ((context)->Eax & ~0xffff) | (WORD)(val)))
#define SET_BX(context,val) ((void)((context)->Ebx = ((context)->Ebx & ~0xffff) | (WORD)(val)))
#define SET_CX(context,val) ((void)((context)->Ecx = ((context)->Ecx & ~0xffff) | (WORD)(val)))
#define SET_DX(context,val) ((void)((context)->Edx = ((context)->Edx & ~0xffff) | (WORD)(val)))
#define SET_SI(context,val) ((void)((context)->Esi = ((context)->Esi & ~0xffff) | (WORD)(val)))
#define SET_DI(context,val) ((void)((context)->Edi = ((context)->Edi & ~0xffff) | (WORD)(val)))
#define SET_AL(context,val) ((void)((context)->Eax = ((context)->Eax & ~0xff) | (BYTE)(val)))
#define SET_BL(context,val) ((void)((context)->Ebx = ((context)->Ebx & ~0xff) | (BYTE)(val)))
#define SET_CL(context,val) ((void)((context)->Ecx = ((context)->Ecx & ~0xff) | (BYTE)(val)))
#define SET_DL(context,val) ((void)((context)->Edx = ((context)->Edx & ~0xff) | (BYTE)(val)))
#define SET_AH(context,val) ((void)((context)->Eax = ((context)->Eax & ~0xff00) | (((BYTE)(val)) << 8)))
#define SET_BH(context,val) ((void)((context)->Ebx = ((context)->Ebx & ~0xff00) | (((BYTE)(val)) << 8)))
#define SET_CH(context,val) ((void)((context)->Ecx = ((context)->Ecx & ~0xff00) | (((BYTE)(val)) << 8)))
#define SET_DH(context,val) ((void)((context)->Edx = ((context)->Edx & ~0xff00) | (((BYTE)(val)) << 8)))
#include
typedef struct
{
WORD Com1Addr; /* 00: COM1 I/O address */
WORD Com2Addr; /* 02: COM2 I/O address */
WORD Com3Addr; /* 04: COM3 I/O address */
WORD Com4Addr; /* 06: COM4 I/O address */
WORD Lpt1Addr; /* 08: LPT1 I/O address */
WORD Lpt2Addr; /* 0a: LPT2 I/O address */
WORD Lpt3Addr; /* 0c: LPT3 I/O address */
WORD Lpt4Addr; /* 0e: LPT4 I/O address */
WORD InstalledHardware; /* 10: Installed hardware flags */
BYTE POSTstatus; /* 12: Power-On Self Test status */
WORD MemSize; /* 13: Base memory size in Kb */
WORD unused1; /* 15: Manufacturing test scratch pad */
BYTE KbdFlags1; /* 17: Keyboard flags 1 */
BYTE KbdFlags2; /* 18: Keyboard flags 2 */
BYTE unused2; /* 19: Keyboard driver workspace */
WORD NextKbdCharPtr; /* 1a: Next character in kbd buffer */
WORD FirstKbdCharPtr; /* 1c: First character in kbd buffer */
WORD KbdBuffer[16]; /* 1e: Keyboard buffer */
BYTE DisketteStatus1; /* 3e: Diskette recalibrate status */
BYTE DisketteStatus2; /* 3f: Diskette motor status */
BYTE DisketteStatus3; /* 40: Diskette motor timeout */
BYTE DisketteStatus4; /* 41: Diskette last operation status */
BYTE DiskStatus[7]; /* 42: Disk status/command bytes */
BYTE VideoMode; /* 49: Video mode */
WORD VideoColumns; /* 4a: Number of columns */
WORD VideoPageSize; /* 4c: Video page size in bytes */
WORD VideoPageStartAddr; /* 4e: Video page start address */
BYTE VideoCursorPos[16]; /* 50: Cursor position for 8 pages, column/row order */
WORD VideoCursorType; /* 60: Video cursor type */
BYTE VideoCurPage; /* 62: Video current page */
WORD VideoCtrlAddr; /* 63: Video controller address */
BYTE VideoReg1; /* 65: Video mode select register */
BYTE VideoReg2; /* 66: Video CGA palette register */
DWORD ResetEntry; /* 67: Warm reset entry point */
BYTE LastIRQ; /* 6b: Last unexpected interrupt */
DWORD Ticks; /* 6c: Ticks since midnight */
BYTE TicksOverflow; /* 70: Timer overflow if past midnight */
BYTE CtrlBreakFlag; /* 71: Ctrl-Break flag */
WORD ResetFlag; /* 72: POST Reset flag */
BYTE DiskOpStatus; /* 74: Last hard-disk operation status */
BYTE NbHardDisks; /* 75: Number of hard disks */
BYTE DiskCtrlByte; /* 76: Disk control byte */
BYTE DiskIOPort; /* 77: Disk I/O port offset */
BYTE LptTimeout[4]; /* 78: Timeouts for parallel ports */
BYTE ComTimeout[4]; /* 7c: Timeouts for serial ports */
WORD KbdBufferStart; /* 80: Keyboard buffer start */
WORD KbdBufferEnd; /* 82: Keyboard buffer end */
BYTE RowsOnScreenMinus1; /* 84: EGA only */
WORD BytesPerChar; /* 85: EGA only */
BYTE ModeOptions; /* 87: EGA only */
BYTE FeatureBitsSwitches; /* 88: EGA only */
BYTE VGASettings; /* 89: VGA misc settings */
BYTE DisplayCombination; /* 8A: VGA display combinations */
BYTE DiskDataRate; /* 8B: Last disk data rate selected */
} BIOSDATA;
#include
/* Device driver header */
#define NONEXT ((DWORD)-1)
#define ATTR_STDIN 0x0001
#define ATTR_STDOUT 0x0002
#define ATTR_NUL 0x0004
#define ATTR_CLOCK 0x0008
#define ATTR_FASTCON 0x0010
#define ATTR_RAW 0x0020
#define ATTR_NOTEOF 0x0040
#define ATTR_DEVICE 0x0080
#define ATTR_REMOVABLE 0x0800
#define ATTR_NONIBM 0x2000 /* block devices */
#define ATTR_UNTILBUSY 0x2000 /* char devices */
#define ATTR_IOCTL 0x4000
#define ATTR_CHAR 0x8000
#include
typedef struct
{
DWORD next_dev;
WORD attr;
WORD strategy;
WORD interrupt;
char name[8];
} DOS_DEVICE_HEADER;
#include
/* DOS Device requests */
#define CMD_INIT 0
#define CMD_MEDIACHECK 1 /* block devices */
#define CMD_BUILDBPB 2 /* block devices */
#define CMD_INIOCTL 3
#define CMD_INPUT 4 /* read data */
#define CMD_SAFEINPUT 5 /* "non-destructive input no wait", char devices */
#define CMD_INSTATUS 6 /* char devices */
#define CMD_INFLUSH 7 /* char devices */
#define CMD_OUTPUT 8 /* write data */
#define CMD_SAFEOUTPUT 9 /* write data with verify */
#define CMD_OUTSTATUS 10 /* char devices */
#define CMD_OUTFLUSH 11 /* char devices */
#define CMD_OUTIOCTL 12
#define CMD_DEVOPEN 13
#define CMD_DEVCLOSE 14
#define CMD_REMOVABLE 15 /* block devices */
#define CMD_UNTILBUSY 16 /* output until busy */
#define STAT_MASK 0x00FF
#define STAT_DONE 0x0100
#define STAT_BUSY 0x0200
#define STAT_ERROR 0x8000
#include
typedef struct {
BYTE size; /* length of header + data */
BYTE unit; /* unit (block devices only) */
BYTE command;
WORD status;
BYTE reserved[8];
} REQUEST_HEADER;
typedef struct {
REQUEST_HEADER hdr;
BYTE media; /* media descriptor from BPB */
SEGPTR buffer;
WORD count; /* byte/sector count */
WORD sector; /* starting sector (block devices) */
DWORD volume; /* volume ID (block devices) */
} REQ_IO;
typedef struct {
REQUEST_HEADER hdr;
BYTE data;
} REQ_SAFEINPUT;
/* WINE device driver thunk from RM */
typedef struct {
BYTE ljmp1;
FARPROC16 strategy;
BYTE ljmp2;
FARPROC16 interrupt;
} WINEDEV_THUNK;
#include
/* Device driver info (used for initialization) */
typedef struct
{
char name[8];
WORD attr;
RMCBPROC strategy;
RMCBPROC interrupt;
} WINEDEV;
/* dosexe.c */
extern BOOL MZ_Exec( CONTEXT *context, LPCSTR filename, BYTE func, LPVOID paramblk ) DECLSPEC_HIDDEN;
extern void MZ_Exit( CONTEXT *context, BOOL cs_psp, WORD retval ) DECLSPEC_HIDDEN;
extern BOOL MZ_Current( void ) DECLSPEC_HIDDEN;
extern void MZ_AllocDPMITask( void ) DECLSPEC_HIDDEN;
extern void MZ_RunInThread( PAPCFUNC proc, ULONG_PTR arg ) DECLSPEC_HIDDEN;
extern BOOL DOSVM_IsWin16(void) DECLSPEC_HIDDEN;
extern void DOSVM_Exit( WORD retval ) DECLSPEC_HIDDEN;
/* dosvm.c */
extern void DOSVM_SendQueuedEvents( CONTEXT * ) DECLSPEC_HIDDEN;
extern void WINAPI DOSVM_AcknowledgeIRQ( CONTEXT * ) DECLSPEC_HIDDEN;
extern INT DOSVM_Enter( CONTEXT *context ) DECLSPEC_HIDDEN;
extern void DOSVM_Wait( CONTEXT * ) DECLSPEC_HIDDEN;
extern DWORD DOSVM_Loop( HANDLE hThread ) DECLSPEC_HIDDEN;
extern void DOSVM_QueueEvent( INT irq, INT priority, DOSRELAY relay, LPVOID data ) DECLSPEC_HIDDEN;
extern void DOSVM_PIC_ioport_out( WORD port, BYTE val ) DECLSPEC_HIDDEN;
extern void DOSVM_SetTimer( UINT ticks ) DECLSPEC_HIDDEN;
extern LPVOID DOSVM_AllocDataUMB(DWORD, WORD *, WORD *) DECLSPEC_HIDDEN;
extern void DOSVM_InitSegments(void) DECLSPEC_HIDDEN;
/* devices.c */
extern void DOSDEV_InstallDOSDevices(void) DECLSPEC_HIDDEN;
extern void DOSDEV_SetupDevice(const WINEDEV * devinfo,
WORD seg, WORD off_dev, WORD off_thunk) DECLSPEC_HIDDEN;
extern void DOSDEV_SetSharingRetry(WORD delay, WORD count) DECLSPEC_HIDDEN;
extern SEGPTR DOSDEV_GetLOL(BOOL v86) DECLSPEC_HIDDEN;
/* dma.c */
extern int DMA_Transfer(int channel,int reqlength,void* buffer) DECLSPEC_HIDDEN;
extern void DMA_ioport_out( WORD port, BYTE val ) DECLSPEC_HIDDEN;
extern BYTE DMA_ioport_in( WORD port ) DECLSPEC_HIDDEN;
/* dosaspi.c */
extern void DOSVM_ASPIHandler(CONTEXT*) DECLSPEC_HIDDEN;
/* dosmem.c */
extern BIOSDATA *DOSVM_BiosData( void ) DECLSPEC_HIDDEN;
__declspec(dllexport) extern void DOSVM_start_bios_timer(void) DECLSPEC_HIDDEN;
/* fpu.c */
extern void WINAPI DOSVM_Int34Handler(CONTEXT*) DECLSPEC_HIDDEN;
extern void WINAPI DOSVM_Int35Handler(CONTEXT*) DECLSPEC_HIDDEN;
extern void WINAPI DOSVM_Int36Handler(CONTEXT*) DECLSPEC_HIDDEN;
extern void WINAPI DOSVM_Int37Handler(CONTEXT*) DECLSPEC_HIDDEN;
extern void WINAPI DOSVM_Int38Handler(CONTEXT*) DECLSPEC_HIDDEN;
extern void WINAPI DOSVM_Int39Handler(CONTEXT*) DECLSPEC_HIDDEN;
extern void WINAPI DOSVM_Int3aHandler(CONTEXT*) DECLSPEC_HIDDEN;
extern void WINAPI DOSVM_Int3bHandler(CONTEXT*) DECLSPEC_HIDDEN;
extern void WINAPI DOSVM_Int3cHandler(CONTEXT*) DECLSPEC_HIDDEN;
extern void WINAPI DOSVM_Int3dHandler(CONTEXT*) DECLSPEC_HIDDEN;
extern void WINAPI DOSVM_Int3eHandler(CONTEXT*) DECLSPEC_HIDDEN;
/* int09.c */
extern void WINAPI DOSVM_Int09Handler(CONTEXT*) DECLSPEC_HIDDEN;
extern void DOSVM_Int09SendScan(BYTE scan,BYTE ascii) DECLSPEC_HIDDEN;
extern BYTE DOSVM_Int09ReadScan(BYTE*ascii) DECLSPEC_HIDDEN;
/* int10.c */
extern void WINAPI DOSVM_Int10Handler(CONTEXT*) DECLSPEC_HIDDEN;
extern void DOSVM_PutChar(BYTE ascii) DECLSPEC_HIDDEN;
/* int13.c */
extern void WINAPI DOSVM_Int13Handler(CONTEXT*) DECLSPEC_HIDDEN;
/* int15.c */
extern void WINAPI DOSVM_Int15Handler(CONTEXT*) DECLSPEC_HIDDEN;
/* int16.c */
extern void WINAPI DOSVM_Int16Handler(CONTEXT*) DECLSPEC_HIDDEN;
extern BOOL DOSVM_Int16ReadChar( BYTE *, BYTE *, CONTEXT * ) DECLSPEC_HIDDEN;
extern BOOL DOSVM_Int16AddChar(BYTE ascii, BYTE scan) DECLSPEC_HIDDEN;
/* int21.c */
extern void WINAPI DOSVM_Int21Handler(CONTEXT*) DECLSPEC_HIDDEN;
/* int25.c */
BOOL DOSVM_RawRead( BYTE, DWORD, DWORD, BYTE *, BOOL ) DECLSPEC_HIDDEN;
void WINAPI DOSVM_Int25Handler( CONTEXT * ) DECLSPEC_HIDDEN;
/* int26.c */
BOOL DOSVM_RawWrite( BYTE, DWORD, DWORD, BYTE *, BOOL ) DECLSPEC_HIDDEN;
void WINAPI DOSVM_Int26Handler( CONTEXT * ) DECLSPEC_HIDDEN;
/* int2f.c */
extern void WINAPI DOSVM_Int2fHandler(CONTEXT*) DECLSPEC_HIDDEN;
extern void MSCDEX_InstallCDROM(void) DECLSPEC_HIDDEN;
/* int31.c */
extern void WINAPI DOSVM_Int31Handler(CONTEXT*) DECLSPEC_HIDDEN;
extern void WINAPI DOSVM_RawModeSwitchHandler(CONTEXT*) DECLSPEC_HIDDEN;
extern BOOL DOSVM_IsDos32(void) DECLSPEC_HIDDEN;
extern FARPROC16 DPMI_AllocInternalRMCB(RMCBPROC) DECLSPEC_HIDDEN;
extern int DPMI_CallRMProc(CONTEXT*,LPWORD,int,int) DECLSPEC_HIDDEN;
extern BOOL DOSVM_CheckWrappers(CONTEXT*) DECLSPEC_HIDDEN;
/* int33.c */
extern void WINAPI DOSVM_Int33Handler(CONTEXT*) DECLSPEC_HIDDEN;
extern void DOSVM_Int33Message(UINT,WPARAM,LPARAM) DECLSPEC_HIDDEN;
extern void DOSVM_Int33Console(MOUSE_EVENT_RECORD*) DECLSPEC_HIDDEN;
/* int67.c */
extern void WINAPI DOSVM_Int67Handler(CONTEXT*) DECLSPEC_HIDDEN;
extern void EMS_Ioctl_Handler(CONTEXT*) DECLSPEC_HIDDEN;
/* interrupts.c */
extern void __wine_call_int_handler( CONTEXT *, BYTE ) DECLSPEC_HIDDEN;
extern void DOSVM_CallBuiltinHandler( CONTEXT *, BYTE ) DECLSPEC_HIDDEN;
extern BOOL DOSVM_EmulateInterruptPM( CONTEXT *, BYTE ) DECLSPEC_HIDDEN;
extern BOOL DOSVM_EmulateInterruptRM( CONTEXT *, BYTE ) DECLSPEC_HIDDEN;
extern FARPROC16 DOSVM_GetPMHandler16( BYTE ) DECLSPEC_HIDDEN;
extern FARPROC48 DOSVM_GetPMHandler48( BYTE ) DECLSPEC_HIDDEN;
extern FARPROC16 DOSVM_GetRMHandler( BYTE ) DECLSPEC_HIDDEN;
extern void DOSVM_HardwareInterruptPM( CONTEXT *, BYTE ) DECLSPEC_HIDDEN;
extern void DOSVM_HardwareInterruptRM( CONTEXT *, BYTE ) DECLSPEC_HIDDEN;
extern void DOSVM_SetPMHandler16( BYTE, FARPROC16 ) DECLSPEC_HIDDEN;
extern void DOSVM_SetPMHandler48( BYTE, FARPROC48 ) DECLSPEC_HIDDEN;
extern void DOSVM_SetRMHandler( BYTE, FARPROC16 ) DECLSPEC_HIDDEN;
/* ioports.c */
extern DWORD DOSVM_inport( int port, int size, CONTEXT *ctx ) DECLSPEC_HIDDEN;
extern void DOSVM_outport( int port, int size, DWORD value, CONTEXT *ctx ) DECLSPEC_HIDDEN;
extern void DOSVM_setportcb(OUTPROC outproc, INPROC inproc, int port, OUTPROC *oldout, INPROC* oldin) DECLSPEC_HIDDEN;
/* relay.c */
void DOSVM_RelayHandler( CONTEXT * ) DECLSPEC_HIDDEN;
void DOSVM_BuildCallFrame( CONTEXT *, DOSRELAY, LPVOID ) DECLSPEC_HIDDEN;
/* soundblaster.c */
extern void SB_ioport_out( WORD port, BYTE val ) DECLSPEC_HIDDEN;
extern BYTE SB_ioport_in( WORD port ) DECLSPEC_HIDDEN;
/* timer.c */
extern void WINAPI DOSVM_Int08Handler(CONTEXT*) DECLSPEC_HIDDEN;
extern char *DOSMEM_dosmem;
extern void *dosvm_vm86_teb_info;
#endif /* __WINE_DOSEXE_H */
================================================
FILE: krnl386/dosmem.c
================================================
/*
* DOS memory emulation
*
* Copyright 1995 Alexandre Julliard
* Copyright 1996 Marcus Meissner
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#include "wine/port.h"
#include
#include
#include
#include
#include
#ifdef HAVE_SYS_MMAN_H
# include
#endif
#include "windef.h"
#include "winbase.h"
#include "excpt.h"
#include "winternl.h"
#include "wine/winbase16.h"
#include "kernel16_private.h"
#include "dosexe.h"
#include "wine/debug.h"
#include "windows/wownt32.h"
WINE_DEFAULT_DEBUG_CHANNEL(dosmem);
WINE_DECLARE_DEBUG_CHANNEL(selector);
WORD DOSMEM_0000H; /* segment at 0:0 */
WORD DOSMEM_BiosDataSeg; /* BIOS data segment at 0x40:0 */
WORD DOSMEM_BiosSysSeg; /* BIOS ROM segment at 0xf000:0 */
/* DOS memory highest address (including HMA) */
#define DOSMEM_SIZE 0x110000
#define DOSMEM_64KB 0x10000
/*
* Memory Control Block (MCB) definition
* FIXME: implement Allocation Strategy
*/
#define MCB_DUMP(mc) \
TRACE ("MCB_DUMP base=%p type=%02xh psp=%04xh size=%04xh\n", mc, mc->type, mc->psp , mc->size )
#define MCB_NEXT(mc) \
(MCB*) ((mc->type==MCB_TYPE_LAST) ? NULL : (char*)(mc) + ((mc->size + 1) << 4) )
/* FIXME: should we check more? */
#define MCB_VALID(mc) \
((mc->type==MCB_TYPE_NORMAL) || (mc->type==MCB_TYPE_LAST))
#define MCB_TYPE_NORMAL 0x4d
#define MCB_TYPE_LAST 0x5a
#define MCB_PSP_DOS 0x0060
#define MCB_PSP_FREE 0
#include "pshpack1.h"
typedef struct {
BYTE type;
WORD psp; /* segment of owner psp */
WORD size; /* in paragraphs */
BYTE pad[3];
BYTE name[8];
} MCB;
#include "poppack.h"
/*
#define __DOSMEM_DEBUG__
*/
#define VM_STUB(x) (0x90CF00CD|(x<<8)) /* INT x; IRET; NOP */
#define VM_STUB_SEGMENT 0xf000 /* BIOS segment */
/* FIXME: this should be moved to the LOL */
static MCB* DOSMEM_root_block;
/* when looking at DOS and real mode memory, we activate in three different
* modes, depending the situation.
* 1/ By default (protected mode), the first MB of memory (actually 0x110000,
* when you also look at the HMA part) is always reserved, whatever you do.
* We allocated some PM selectors to this memory, even if this area is not
* committed at startup
* 2/ if a program tries to use the memory through the selectors, we actually
* commit this memory, made of: BIOS segment, but also some system
* information, usually low in memory that we map for the circumstance also
* in the BIOS segment, so that we keep the low memory protected (for NULL
* pointer deref catching for example). In this case, we're still in PM
* mode, accessing part of the "physical" real mode memory. In fact, we don't
* map all the first meg, we keep 64k uncommitted to still catch NULL
* pointers dereference
* 3/ if the process enters the real mode, then we (also) commit the full first
* MB of memory (and also initialize the DOS structures in it).
*/
/* DOS memory base (linear in process address space) */
/*static*/ char *DOSMEM_dosmem;
static char *DOSMEM_sysmem;
/* number of bytes protected from _dosmem. 0 when DOS memory is initialized,
* 64k otherwise to trap NULL pointers deref */
static DWORD DOSMEM_protect;
static LONG WINAPI dosmem_handler(EXCEPTION_POINTERS* except);
static void *vectored_handler;
/***********************************************************************
* DOSMEM_FillIsrTable
*
* Fill the interrupt table with fake BIOS calls to BIOSSEG (0xf000).
*
* NOTES:
* Linux normally only traps INTs performed from or destined to BIOSSEG
* for us to handle, if the int_revectored table is empty. Filling the
* interrupt table with calls to INT stubs in BIOSSEG allows DOS programs
* to hook interrupts, as well as use their familiar retf tricks to call
* them, AND let Wine handle any unhooked interrupts transparently.
*/
static void DOSMEM_FillIsrTable(void)
{
SEGPTR *isr = (SEGPTR*)DOSMEM_sysmem;
int x;
for (x=0; x<256; x++) isr[x]=MAKESEGPTR(VM_STUB_SEGMENT,x*4);
}
static void DOSMEM_MakeIsrStubs(void)
{
DWORD *stub = (DWORD*)(DOSMEM_dosmem + (VM_STUB_SEGMENT << 4));
int x;
for (x=0; x<256; x++) stub[x]=VM_STUB(x);
}
BIOSDATA* DOSVM_BiosData(void)
{
return (BIOSDATA *)(DOSMEM_sysmem + 0x400);
}
/**********************************************************************
* DOSMEM_GetTicksSinceMidnight
*
* Return number of clock ticks since midnight.
*/
static DWORD DOSMEM_GetTicksSinceMidnight(void)
{
SYSTEMTIME time;
/* This should give us the (approximately) correct
* 18.206 clock ticks per second since midnight.
*/
GetLocalTime( &time );
return (((time.wHour * 3600 + time.wMinute * 60 +
time.wSecond) * 18206) / 1000) +
(time.wMilliseconds * 1000 / 54927);
}
/***********************************************************************
* DOSMEM_FillBiosSegments
*
* Fill the BIOS data segment with dummy values.
*/
static void DOSMEM_FillBiosSegments(void)
{
BYTE *pBiosSys = (BYTE*)DOSMEM_dosmem + 0xf0000;
BYTE *pBiosROMTable = pBiosSys+0xe6f5;
BIOSDATA *pBiosData = DOSVM_BiosData();
static const char bios_date[] = "13/01/99";
/* Clear all unused values */
memset( pBiosData, 0, sizeof(*pBiosData) );
/* FIXME: should check the number of configured drives and ports */
pBiosData->Com1Addr = 0x3f8;
pBiosData->Com2Addr = 0x2f8;
pBiosData->Lpt1Addr = 0x378;
pBiosData->Lpt2Addr = 0x278;
pBiosData->InstalledHardware = 0x5463;
pBiosData->MemSize = 640;
pBiosData->NextKbdCharPtr = 0x1e;
pBiosData->FirstKbdCharPtr = 0x1e;
pBiosData->VideoMode = 3;
pBiosData->VideoColumns = 80;
pBiosData->VideoPageSize = 80 * 25 * 2;
pBiosData->VideoPageStartAddr = 0xb800;
pBiosData->VideoCtrlAddr = 0x3d4;
pBiosData->Ticks = DOSMEM_GetTicksSinceMidnight();
pBiosData->NbHardDisks = 2;
pBiosData->KbdBufferStart = 0x1e;
pBiosData->KbdBufferEnd = 0x3e;
pBiosData->RowsOnScreenMinus1 = 24;
pBiosData->BytesPerChar = 0x10;
pBiosData->ModeOptions = 0x64;
pBiosData->FeatureBitsSwitches = 0xf9;
pBiosData->VGASettings = 0x51;
pBiosData->DisplayCombination = 0x08;
pBiosData->DiskDataRate = 0;
/* fill ROM configuration table (values from Award) */
*(pBiosROMTable+0x0) = 0x08; /* number of bytes following LO */
*(pBiosROMTable+0x1) = 0x00; /* number of bytes following HI */
*(pBiosROMTable+0x2) = 0xfc; /* model */
*(pBiosROMTable+0x3) = 0x01; /* submodel */
*(pBiosROMTable+0x4) = 0x00; /* BIOS revision */
*(pBiosROMTable+0x5) = 0x74; /* feature byte 1 */
*(pBiosROMTable+0x6) = 0x00; /* feature byte 2 */
*(pBiosROMTable+0x7) = 0x00; /* feature byte 3 */
*(pBiosROMTable+0x8) = 0x00; /* feature byte 4 */
*(pBiosROMTable+0x9) = 0x00; /* feature byte 5 */
/* BIOS date string */
memcpy(pBiosSys+0xfff5, bios_date, sizeof bios_date);
/* BIOS ID */
*(pBiosSys+0xfffe) = 0xfc;
/* Reboot vector (f000:fff0 or ffff:0000) */
*(DWORD*)(pBiosSys + 0xfff0) = VM_STUB(0x19);
}
BOOL WINAPI vm_inject(DWORD vpfn16, DWORD dwFlags,
DWORD cbArgs, LPVOID pArgs, LPDWORD pdwRetCode);
/***********************************************************************
* BiosTick
*
* Increment the BIOS tick counter. Called by timer signal handler.
*/
static void CALLBACK BiosTick( LPVOID arg, DWORD low, DWORD high )
{
FARPROC16 tickhndlr = DOSVM_GetPMHandler16(8);
BIOSDATA *pBiosData = arg;
pBiosData->Ticks++;
// TODO: fix PIT
if (tickhndlr && (tickhndlr != (FARPROC16)MAKESEGPTR(DOSVM_dpmi_segments->int16_sel, 5 * 8)))
{
DWORD ret;
WORD dummyflags;
vm_inject(tickhndlr, WCB16_PASCAL, 2, &dummyflags, &ret);
}
}
/***********************************************************************
* timer_thread
*/
static DWORD CALLBACK timer_thread( void *arg )
{
LARGE_INTEGER when;
HANDLE timer;
if (!(timer = CreateWaitableTimerA( NULL, FALSE, NULL ))) return 0;
when.u.LowPart = when.u.HighPart = 0;
SetWaitableTimer( timer, &when, 55 /* actually 54.925 */, BiosTick, arg, FALSE );
for (;;) SleepEx( INFINITE, TRUE );
}
/***********************************************************************
* DOSVM_start_bios_timer
*
* Start the BIOS ticks timer when the app accesses selector 0x40.
*/
__declspec(dllexport) void DOSVM_start_bios_timer(void)
{
static LONG running;
if (!InterlockedExchange( &running, 1 ))
CloseHandle( CreateThread( NULL, 0, timer_thread, DOSVM_BiosData(), 0, NULL ));
}
/***********************************************************************
* DOSMEM_Collapse
*
* Helper function for internal use only.
* Attach all following free blocks to this one, even if this one is not free.
*/
static void DOSMEM_Collapse( MCB* mcb )
{
MCB* next = MCB_NEXT( mcb );
while (next && next->psp == MCB_PSP_FREE)
{
mcb->size = mcb->size + next->size + 1;
mcb->type = next->type; /* make sure keeping MCB_TYPE_LAST */
next = MCB_NEXT( next );
}
}
/******************************************************************
* DOSMEM_InitDosMemory
*/
BOOL DOSMEM_InitDosMemory(void)
{
//FIXME
//emulatorgasubeki
//ERR("NOTIMPL");
//return TRUE;
static BOOL done;
static HANDLE hRunOnce;
DWORD old_prot;
if (done) return TRUE;
/* FIXME: this isn't 100% thread safe, as we won't catch accesses while initializing */
if (hRunOnce == 0)
{
HANDLE hEvent = CreateEventW( NULL, TRUE, FALSE, NULL );
if (InterlockedCompareExchangePointer( &hRunOnce, hEvent, 0 ) == 0)
{
BOOL ret;
DWORD reserve;
/* ok, we're the winning thread */
if (!(ret = VirtualProtect( DOSMEM_dosmem + DOSMEM_protect,
DOSMEM_SIZE - DOSMEM_protect,
PAGE_READWRITE, &old_prot )))
ERR("Cannot load access low 1Mb, DOS subsystem unavailable\n");
RemoveVectoredExceptionHandler( vectored_handler );
/*
* Reserve either:
* - lowest 64k for NULL pointer catching (Win16)
* - lowest 1k for interrupt handlers and
* another 0.5k for BIOS, DOS and intra-application
* areas (DOS)
*/
if (DOSMEM_dosmem != DOSMEM_sysmem)
reserve = 0x10000; /* 64k */
else
reserve = 0x600; /* 1.5k */
/*
* Set DOS memory base and initialize conventional memory.
*/
DOSMEM_FillBiosSegments();
DOSMEM_FillIsrTable();
/* align root block to paragraph */
DOSMEM_root_block = (MCB*)(DOSMEM_dosmem + reserve);
DOSMEM_root_block->type = MCB_TYPE_LAST;
DOSMEM_root_block->psp = MCB_PSP_FREE;
DOSMEM_root_block->size = (DOSMEM_dosmem + 0x9fffc - ((char*)DOSMEM_root_block)) >> 4;
TRACE("DOS conventional memory initialized, %d bytes free.\n",
DOSMEM_Available());
DOSVM_InitSegments();
SetEvent( hRunOnce );
done = TRUE;
return ret;
}
/* someone beat us here... */
CloseHandle( hEvent );
}
/* and wait for the winner to have finished */
WaitForSingleObject( hRunOnce, INFINITE );
return TRUE;
}
/******************************************************************
* dosmem_handler
*
* Handler to catch access to our 1MB address space reserved for real memory
*/
static LONG WINAPI dosmem_handler(EXCEPTION_POINTERS* except)
{
if (except->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
{
char *addr = (char *)except->ExceptionRecord->ExceptionInformation[1];
if (addr >= DOSMEM_dosmem + DOSMEM_protect && addr < DOSMEM_dosmem + DOSMEM_SIZE)
{
if (DOSMEM_InitDosMemory()) return EXCEPTION_CONTINUE_EXECUTION;
}
}
return EXCEPTION_CONTINUE_SEARCH;
}
/***********************************************************************
* DOSMEM_Init
*
* Create the dos memory segments, and store them into the KERNEL
* exported values.
*/
BOOL DOSMEM_Init(void)
{
void *addr = (void *)1;
SIZE_T size = DOSMEM_SIZE - 1;
if (NtAllocateVirtualMemory( GetCurrentProcess(), &addr, 0, &size,
MEM_RESERVE | MEM_COMMIT, PAGE_NOACCESS ))
{
addr = 0;
if (NtAllocateVirtualMemory(GetCurrentProcess(), &addr, 0, &size,
MEM_RESERVE | MEM_COMMIT, PAGE_NOACCESS))
{
ERR("Cannot allocate DOS memory\n");
//ExitProcess(1);
}
}
if (addr <= (void *)DOSMEM_64KB)
{
DOSMEM_dosmem = 0;
DOSMEM_protect = DOSMEM_64KB;
DOSMEM_sysmem = (char *)0xf0000; /* store sysmem in high addresses for now */
}
else
{
WARN( "First megabyte not available for DOS address space.\n" );
DOSMEM_dosmem = addr;
DOSMEM_protect = 0;
DOSMEM_sysmem = DOSMEM_dosmem;
}
vectored_handler = AddVectoredExceptionHandler(FALSE, dosmem_handler);
DOSMEM_0000H = GLOBAL_CreateBlock( GMEM_FIXED, DOSMEM_sysmem,
DOSMEM_64KB, 0, WINE_LDT_FLAGS_DATA, 0 );
DOSMEM_BiosDataSeg = GLOBAL_CreateBlock( GMEM_FIXED, DOSMEM_sysmem + 0x400,
0x100, 0, WINE_LDT_FLAGS_DATA, 0 );
DOSMEM_BiosSysSeg = GLOBAL_CreateBlock( GMEM_FIXED, DOSMEM_dosmem + 0xf0000,
DOSMEM_64KB, 0, WINE_LDT_FLAGS_DATA, 0 );
return TRUE;
}
/***********************************************************************
* DOSMEM_MapLinearToDos
*
* Linear address to the DOS address space.
*/
UINT DOSMEM_MapLinearToDos(LPVOID ptr)
{
if (((char*)ptr >= DOSMEM_dosmem) &&
((char*)ptr < DOSMEM_dosmem + DOSMEM_SIZE))
return (char *)ptr - DOSMEM_dosmem;
return (UINT)ptr;
}
/***********************************************************************
* DOSMEM_MapDosToLinear
*
* DOS linear address to the linear address space.
*/
LPVOID DOSMEM_MapDosToLinear(UINT ptr)
{
if (ptr < DOSMEM_SIZE) return DOSMEM_dosmem + ptr;
return (LPVOID)ptr;
}
/***********************************************************************
* DOSMEM_MapRealToLinear
*
* Real mode DOS address into a linear pointer
*/
LPVOID DOSMEM_MapRealToLinear(DWORD x)
{
LPVOID lin;
lin = DOSMEM_dosmem + HIWORD(x) * 16 + LOWORD(x);
TRACE_(selector)("(0x%08x) returns %p.\n", x, lin );
return lin;
}
/***********************************************************************
* DOSMEM_AllocBlock
*
* Carve a chunk of the DOS memory block (without selector).
*/
LPVOID DOSMEM_AllocBlock(UINT size, UINT16* pseg)
{
MCB *curr;
MCB *next = NULL;
WORD psp;
DOSMEM_InitDosMemory();
curr = DOSMEM_root_block;
if (!(psp = DOSVM_psp)) psp = MCB_PSP_DOS;
if (pseg) *pseg = 0;
TRACE( "(%04xh)\n", size );
/* round up to paragraph */
size = (size + 15) >> 4;
#ifdef __DOSMEM_DEBUG__
DOSMEM_Available(); /* checks the whole MCB list */
#endif
/* loop over all MCB and search the next large enough MCB */
while (curr)
{
if (!MCB_VALID (curr))
{
ERR( "MCB List Corrupt\n" );
MCB_DUMP( curr );
return NULL;
}
if (curr->psp == MCB_PSP_FREE)
{
DOSMEM_Collapse( curr );
/* is it large enough (one paragraph for the MCB)? */
if (curr->size >= size)
{
if (curr->size > size)
{
/* split curr */
next = (MCB *) ((char*) curr + ((size+1) << 4));
next->psp = MCB_PSP_FREE;
next->size = curr->size - (size+1);
next->type = curr->type;
curr->type = MCB_TYPE_NORMAL;
curr->size = size;
}
/* curr is the found block */
curr->psp = psp;
if( pseg ) *pseg = (((char*)curr) + 16 - DOSMEM_dosmem) >> 4;
return (LPVOID) ((char*)curr + 16);
}
}
curr = MCB_NEXT(curr);
}
return NULL;
}
/***********************************************************************
* DOSMEM_FreeBlock
*/
BOOL DOSMEM_FreeBlock(void* ptr)
{
MCB* mcb = (MCB*) ((char*)ptr - 16);
TRACE( "(%p)\n", ptr );
#ifdef __DOSMEM_DEBUG__
DOSMEM_Available();
#endif
if (!MCB_VALID (mcb))
{
ERR( "MCB invalid\n" );
MCB_DUMP( mcb );
return FALSE;
}
mcb->psp = MCB_PSP_FREE;
DOSMEM_Collapse( mcb );
return TRUE;
}
/***********************************************************************
* DOSMEM_ResizeBlock
*
* Resize DOS memory block in place. Returns block size or -1 on error.
*
* If exact is TRUE, returned value is either old or requested block
* size. If exact is FALSE, block is expanded even if there is not
* enough space for full requested block size.
*
* TODO: return also biggest block size
*/
UINT DOSMEM_ResizeBlock(void *ptr, UINT size, BOOL exact)
{
MCB* mcb = (MCB*) ((char*)ptr - 16);
MCB* next;
TRACE( "(%p,%04xh,%s)\n", ptr, size, exact ? "TRUE" : "FALSE" );
/* round up to paragraph */
size = (size + 15) >> 4;
#ifdef __DOSMEM_DEBUG__
DOSMEM_Available();
#endif
if (!MCB_VALID (mcb))
{
ERR( "MCB invalid\n" );
MCB_DUMP( mcb );
return -1;
}
/* resize needed? */
if (mcb->size == size)
return size << 4;
/* collapse free blocks */
DOSMEM_Collapse( mcb );
/* shrink mcb ? */
if (mcb->size > size)
{
next = (MCB *) ((char*)mcb + ((size+1) << 4));
next->type = mcb->type;
next->psp = MCB_PSP_FREE;
next->size = mcb->size - (size+1);
mcb->type = MCB_TYPE_NORMAL;
mcb->size = size;
return size << 4;
}
if (!exact)
{
return mcb->size << 4;
}
return -1;
}
/***********************************************************************
* DOSMEM_Available
*/
UINT DOSMEM_Available(void)
{
UINT available = 0;
UINT total = 0;
MCB *curr = DOSMEM_root_block;
/* loop over all MCB and search the largest free MCB */
while (curr)
{
#ifdef __DOSMEM_DEBUG__
MCB_DUMP( curr );
#endif
if (!MCB_VALID (curr))
{
ERR( "MCB List Corrupt\n" );
MCB_DUMP( curr );
return 0;
}
if (curr->psp == MCB_PSP_FREE &&
curr->size > available )
available = curr->size;
total += curr->size + 1;
curr = MCB_NEXT( curr );
}
TRACE( " %04xh of %04xh paragraphs available\n", available, total );
return available << 4;
}
/******************************************************************
* DOSMEM_MapDosLayout
*
* Initialize the first MB of memory to look like a real DOS setup
*/
BOOL DOSMEM_MapDosLayout(void)
{
static BOOL already_mapped;
DWORD old_prot;
if (!already_mapped)
{
if (DOSMEM_dosmem || !VirtualProtect( NULL, DOSMEM_SIZE, PAGE_EXECUTE_READWRITE, &old_prot ))
{
//ERR( "Need full access to the first megabyte for DOS mode\n" );
//ExitProcess(1);
WARN( "Need full access to the first megabyte for DOS mode\n" );
}
/* copy the BIOS and ISR area down */
memcpy( DOSMEM_dosmem, DOSMEM_sysmem, 0x400 + 0x100 );
DOSMEM_sysmem = DOSMEM_dosmem;
SetSelectorBase( DOSMEM_0000H, 0 );
SetSelectorBase( DOSMEM_BiosDataSeg, 0x400 );
/* we may now need the actual interrupt stubs, and since we've just moved the
* interrupt vector table away, we can fill the area with stubs instead... */
DOSMEM_MakeIsrStubs();
already_mapped = TRUE;
}
return TRUE;
}
================================================
FILE: krnl386/dosvm.c
================================================
/*
* DOS Virtual Machine
*
* Copyright 1998 Ove Kåven
* Copyright 2002 Jukka Heinonen
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*
* Note: This code hasn't been completely cleaned up yet.
*/
#include "config.h"
#include "wine/port.h"
#include
#include
#include
#include
#include
#include
#include
#ifdef HAVE_UNISTD_H
# include
#endif
#ifdef HAVE_SYS_TIME_H
# include
#endif
#include
#include "wine/winbase16.h"
#include "wine/exception.h"
#include "windef.h"
#include "winbase.h"
#include "winternl.h"
#include "wingdi.h"
#include "winuser.h"
#include "windows/wownt32.h"
#include "winnt.h"
#include "wincon.h"
#include "dosexe.h"
#include "wine/debug.h"
#include "excpt.h"
#include "kernel16_private.h"
WINE_DEFAULT_DEBUG_CHANNEL(int);
#ifdef MZ_SUPPORTED
WINE_DECLARE_DEBUG_CHANNEL(module);
WINE_DECLARE_DEBUG_CHANNEL(relay);
#endif
WORD DOSVM_psp = 0;
WORD DOSVM_retval = 0;
/*
* Wine DOS memory layout above 640k:
*
* a0000 - affff : VGA graphics (vga.c)
* b0000 - bffff : Monochrome text (unused)
* b8000 - bffff : VGA text (vga.c)
* c0000 - cffff : EMS frame (int67.c)
* d0000 - effff : Free memory for UMBs (himem.c)
* f0000 - fffff : BIOS stuff (msdos/dosmem.c)
* 100000 -10ffff : High memory area (unused)
*/
/*
* Table of real mode segments and protected mode selectors
* for code stubs and other miscellaneous storage.
*/
struct DPMI_segments *DOSVM_dpmi_segments = NULL;
/*
* First and last address available for upper memory blocks.
*/
#define DOSVM_UMB_BOTTOM 0xd0000
#define DOSVM_UMB_TOP 0xeffff
/*
* First free address for upper memory blocks.
*/
static DWORD DOSVM_umb_free = DOSVM_UMB_BOTTOM;
typedef struct _DOSEVENT {
int irq,priority;
DOSRELAY relay;
void *data;
struct _DOSEVENT *next;
} DOSEVENT, *LPDOSEVENT;
static struct _DOSEVENT *pending_event, *current_event;
static HANDLE event_notifier;
static CRITICAL_SECTION qcrit;
static CRITICAL_SECTION_DEBUG critsect_debug =
{
0, 0, &qcrit,
{ &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
0, 0, { (DWORD_PTR)(__FILE__ ": qcrit") }
};
static CRITICAL_SECTION qcrit = { &critsect_debug, -1, 0, 0, 0, 0 };
/***********************************************************************
* DOSVM_HasPendingEvents
*
* Return true if there are pending events that are not
* blocked by currently active event.
*/
static BOOL DOSVM_HasPendingEvents( void )
{
if (!pending_event)
return FALSE;
if (!current_event)
return TRUE;
if (pending_event->priority < current_event->priority)
return TRUE;
return FALSE;
}
/***********************************************************************
* DOSVM_SendOneEvent
*
* Process single pending event.
*
* This function should be called with queue critical section locked.
* The function temporarily releases the critical section if it is
* possible that internal interrupt handler or user procedure will
* be called. This is because we may otherwise get a deadlock if
* another thread is waiting for the same critical section.
*/
static void DOSVM_SendOneEvent( CONTEXT *context )
{
LPDOSEVENT event = pending_event;
/* Remove from pending events list. */
pending_event = event->next;
/* Process active event. */
if (event->irq >= 0)
{
BYTE intnum = (event->irq < 8) ?
(event->irq + 8) : (event->irq - 8 + 0x70);
/* Event is an IRQ, move it to current events list. */
event->next = current_event;
current_event = event;
TRACE( "Dispatching IRQ %d.\n", event->irq );
if (ISV86(context))
{
/*
* Note that if DOSVM_HardwareInterruptRM calls an internal
* interrupt directly, current_event might be cleared
* (and event freed) in this call.
*/
LeaveCriticalSection(&qcrit);
DOSVM_HardwareInterruptRM( context, intnum );
EnterCriticalSection(&qcrit);
}
else
{
/*
* This routine only modifies current context so it is
* not necessary to release critical section.
*/
DOSVM_HardwareInterruptPM( context, intnum );
}
}
else
{
/* Callback event. */
TRACE( "Dispatching callback event.\n" );
if (ISV86(context))
{
/*
* Call relay immediately in real mode.
*/
LeaveCriticalSection(&qcrit);
(*event->relay)( context, event->data );
EnterCriticalSection(&qcrit);
}
else
{
/*
* Force return to relay code. We do not want to
* call relay directly because we may be inside a signal handler.
*/
DOSVM_BuildCallFrame( context, event->relay, event->data );
}
HeapFree(GetProcessHeap(), 0, event);
}
}
/***********************************************************************
* DOSVM_SendQueuedEvents
*
* As long as context instruction pointer stays unmodified,
* process all pending events that are not blocked by currently
* active event.
*
* This routine assumes that caller has already cleared TEB.vm86_pending
* and checked that interrupts are enabled.
*/
void DOSVM_SendQueuedEvents( CONTEXT *context )
{
DWORD old_cs = context->SegCs;
DWORD old_ip = context->Eip;
EnterCriticalSection(&qcrit);
TRACE( "Called in %s mode %s events pending (time=%d)\n",
ISV86(context) ? "real" : "protected",
DOSVM_HasPendingEvents() ? "with" : "without",
GetTickCount() );
TRACE( "cs:ip=%04x:%08x, ss:sp=%04x:%08x\n",
context->SegCs, context->Eip, context->SegSs, context->Esp);
while (context->SegCs == old_cs &&
context->Eip == old_ip &&
DOSVM_HasPendingEvents())
{
DOSVM_SendOneEvent(context);
/*
* Event handling may have turned pending events flag on.
* We disable it here because this prevents some
* unnecessary calls to this function.
*/
get_vm86_teb_info()->vm86_pending = 0;
}
#ifdef MZ_SUPPORTED
if (DOSVM_HasPendingEvents())
{
/*
* Interrupts disabled, but there are still
* pending events, make sure that pending flag is turned on.
*/
TRACE( "Another event is pending, setting VIP flag.\n" );
get_vm86_teb_info()->vm86_pending |= VIP_MASK;
}
#else
FIXME("No DOS .exe file support on this platform (yet)\n");
#endif /* MZ_SUPPORTED */
LeaveCriticalSection(&qcrit);
}
#ifdef MZ_SUPPORTED
/***********************************************************************
* DOSVM_QueueEvent
*/
void DOSVM_QueueEvent( INT irq, INT priority, DOSRELAY relay, LPVOID data)
{
LPDOSEVENT event, cur, prev;
BOOL old_pending;
if (MZ_Current()) {
event = HeapAlloc(GetProcessHeap(), 0, sizeof(DOSEVENT));
if (!event) {
ERR("out of memory allocating event entry\n");
return;
}
event->irq = irq; event->priority = priority;
event->relay = relay; event->data = data;
EnterCriticalSection(&qcrit);
old_pending = DOSVM_HasPendingEvents();
/* insert event into linked list, in order *after*
* all earlier events of higher or equal priority */
cur = pending_event; prev = NULL;
while (cur && cur->priority<=priority) {
prev = cur;
cur = cur->next;
}
event->next = cur;
if (prev) prev->next = event;
else pending_event = event;
if (!old_pending && DOSVM_HasPendingEvents()) {
TRACE("new event queued, signalling (time=%d)\n", GetTickCount());
/* Alert VM86 thread about the new event. */
//ERR("kill(%d, %d)\n", dosvm_pid, 12);
//see dlls/ntdll/signal_i386.c
//get vm's thread teb
((WINE_VM86_TEB_INFO*)dosvm_vm86_teb_info)->vm86_pending |= VIP_MASK;
//=> VM thread
//kill(dosvm_pid,SIGUSR2);
/* Wake up DOSVM_Wait so that it can serve pending events. */
SetEvent(event_notifier);
} else {
TRACE("new event queued (time=%d)\n", GetTickCount());
}
LeaveCriticalSection(&qcrit);
} else {
/* DOS subsystem not running */
/* (this probably means that we're running a win16 app
* which uses DPMI to thunk down to DOS services) */
if (irq<0) {
/* callback event, perform it with dummy context */
CONTEXT context;
memset(&context,0,sizeof(context));
(*relay)(&context,data);
} else {
ERR("IRQ without DOS task: should not happen\n");
}
}
}
static void DOSVM_ProcessConsole(void)
{
INPUT_RECORD msg;
DWORD res;
BYTE scan, ascii;
if (ReadConsoleInputA(GetStdHandle(STD_INPUT_HANDLE),&msg,1,&res)) {
switch (msg.EventType) {
case KEY_EVENT:
scan = msg.Event.KeyEvent.wVirtualScanCode;
ascii = msg.Event.KeyEvent.uChar.AsciiChar;
TRACE("scan %02x, ascii %02x\n", scan, ascii);
/* set the "break" (release) flag if key released */
if (!msg.Event.KeyEvent.bKeyDown) scan |= 0x80;
/* check whether extended bit is set,
* and if so, queue the extension prefix */
if (msg.Event.KeyEvent.dwControlKeyState & ENHANCED_KEY) {
DOSVM_Int09SendScan(0xE0,0);
}
DOSVM_Int09SendScan(scan, ascii);
break;
case MOUSE_EVENT:
DOSVM_Int33Console(&msg.Event.MouseEvent);
break;
case WINDOW_BUFFER_SIZE_EVENT:
FIXME("unhandled WINDOW_BUFFER_SIZE_EVENT.\n");
break;
case MENU_EVENT:
FIXME("unhandled MENU_EVENT.\n");
break;
case FOCUS_EVENT:
FIXME("unhandled FOCUS_EVENT.\n");
break;
default:
FIXME("unknown console event: %d\n", msg.EventType);
}
}
}
static void DOSVM_ProcessMessage(MSG *msg)
{
BYTE scan = 0;
TRACE("got message %04x, wparam=%08lx, lparam=%08lx\n",msg->message,msg->wParam,msg->lParam);
if ((msg->message>=WM_MOUSEFIRST)&&
(msg->message<=WM_MOUSELAST)) {
DOSVM_Int33Message(msg->message,msg->wParam,msg->lParam);
} else {
switch (msg->message) {
case WM_KEYUP:
scan = 0x80;
case WM_KEYDOWN:
scan |= (msg->lParam >> 16) & 0x7f;
/* check whether extended bit is set,
* and if so, queue the extension prefix */
if (msg->lParam & 0x1000000) {
/* FIXME: some keys (function keys) have
* extended bit set even when they shouldn't,
* should check for them */
DOSVM_Int09SendScan(0xE0,0);
}
DOSVM_Int09SendScan(scan,0);
break;
}
}
}
/***********************************************************************
* DOSVM_Wait
*
* Wait for asynchronous events. This routine temporarily enables
* interrupts and waits until some asynchronous event has been
* processed.
*/
void DOSVM_Wait( CONTEXT *waitctx )
{
if (DOSVM_HasPendingEvents())
{
CONTEXT context = *waitctx;
/*
* If DOSVM_Wait is called from protected mode we emulate
* interrupt reflection and convert context into real mode context.
* This is actually the correct thing to do as long as DOSVM_Wait
* is only called from those interrupt functions that DPMI reflects
* to real mode.
*
* FIXME: Need to think about where to place real mode stack.
* FIXME: If DOSVM_Wait calls are nested stack gets corrupted.
* Can this really happen?
*/
if (!ISV86(&context))
{
context.EFlags |= V86_FLAG;
context.SegSs = 0xffff;
context.Esp = 0;
}
context.EFlags |= VIF_MASK;
context.SegCs = 0;
context.Eip = 0;
DOSVM_SendQueuedEvents(&context);
if(context.SegCs || context.Eip)
DPMI_CallRMProc( &context, NULL, 0, TRUE );
}
else
{
HANDLE objs[2];
int objc = DOSVM_IsWin16() ? 2 : 1;
DWORD waitret;
objs[0] = event_notifier;
objs[1] = GetStdHandle(STD_INPUT_HANDLE);
waitret = MsgWaitForMultipleObjects( objc, objs, FALSE,
INFINITE, QS_ALLINPUT );
if (waitret == WAIT_OBJECT_0)
{
/*
* New pending event has been queued, we ignore it
* here because it will be processed on next call to
* DOSVM_Wait.
*/
}
else if (objc == 2 && waitret == WAIT_OBJECT_0 + 1)
{
DOSVM_ProcessConsole();
}
else if (waitret == WAIT_OBJECT_0 + objc)
{
MSG msg;
while (PeekMessageA(&msg,0,0,0,PM_REMOVE|PM_NOYIELD))
{
/* got a message */
DOSVM_ProcessMessage(&msg);
/* we don't need a TranslateMessage here */
DispatchMessageA(&msg);
}
}
else
{
ERR_(module)( "dosvm wait error=%d\n", GetLastError() );
}
}
}
DWORD DOSVM_Loop( HANDLE hThread )
{
HANDLE objs[2];
int count = 0;
MSG msg;
DWORD waitret;
objs[count++] = hThread;
DWORD ununsed;
if (GetConsoleMode( GetStdHandle(STD_INPUT_HANDLE), &ununsed))
objs[count++] = GetStdHandle(STD_INPUT_HANDLE);
for(;;) {
TRACE_(int)("waiting for action\n");
waitret = MsgWaitForMultipleObjects(count, objs, FALSE, INFINITE, QS_ALLINPUT);
if (waitret == WAIT_OBJECT_0) {
DWORD rv;
if(!GetExitCodeThread(hThread, &rv)) {
ERR("Failed to get thread exit code!\n");
rv = 0;
}
return rv;
}
else if (waitret == WAIT_OBJECT_0 + count) {
while (PeekMessageA(&msg,0,0,0,PM_REMOVE)) {
if (msg.hwnd) {
/* it's a window message */
DOSVM_ProcessMessage(&msg);
DispatchMessageA(&msg);
} else {
/* it's a thread message */
switch (msg.message) {
case WM_QUIT:
/* stop this madness!! */
return 0;
case WM_USER + 1:
/* run passed procedure in this thread */
/* (sort of like APC, but we signal the completion) */
{
DOS_SPC *spc = (DOS_SPC *)msg.lParam;
TRACE_(int)("calling %p with arg %08lx\n", spc->proc, spc->arg);
(spc->proc)(spc->arg);
TRACE_(int)("done, signalling event %lx\n", msg.wParam);
SetEvent( (HANDLE)msg.wParam );
}
break;
default:
DispatchMessageA(&msg);
}
}
}
}
else if (waitret == WAIT_OBJECT_0 + 1)
{
DOSVM_ProcessConsole();
}
else
{
ERR_(int)("MsgWaitForMultipleObjects returned unexpected value.\n");
return 0;
}
}
}
static LONG WINAPI exception_handler(EXCEPTION_POINTERS *eptr)
{
EXCEPTION_RECORD *rec = eptr->ExceptionRecord;
CONTEXT *context = eptr->ContextRecord;
int arg = rec->ExceptionInformation[0];
BOOL ret;
context = *(CONTEXT**)(&rec->ExceptionInformation[1]);
switch(rec->ExceptionCode) {
case EXCEPTION_VM86_INTx:
TRACE_(relay)("Call DOS int 0x%02x ret=%04x:%04x\n"
" eax=%08x ebx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x\n"
" ebp=%08x esp=%08x ds=%04x es=%04x fs=%04x gs=%04x flags=%08x\n",
arg, context->SegCs, context->Eip,
context->Eax, context->Ebx, context->Ecx, context->Edx, context->Esi, context->Edi,
context->Ebp, context->Esp, context->SegDs, context->SegEs, context->SegFs, context->SegGs,
context->EFlags );
ret = DOSVM_EmulateInterruptRM( context, arg );
TRACE_(relay)("Ret DOS int 0x%02x ret=%04x:%04x\n"
" eax=%08x ebx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x\n"
" ebp=%08x esp=%08x ds=%04x es=%04x fs=%04x gs=%04x flags=%08x\n",
arg, context->SegCs, context->Eip,
context->Eax, context->Ebx, context->Ecx, context->Edx, context->Esi, context->Edi,
context->Ebp, context->Esp, context->SegDs, context->SegEs,
context->SegFs, context->SegGs, context->EFlags );
return ret ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_EXECUTE_HANDLER;
case EXCEPTION_VM86_STI:
/* case EXCEPTION_VM86_PICRETURN: */
if (!ISV86(context))
ERR( "Protected mode STI caught by real mode handler!\n" );
DOSVM_SendQueuedEvents(context);
return EXCEPTION_CONTINUE_EXECUTION;
case EXCEPTION_SINGLE_STEP:
ret = DOSVM_EmulateInterruptRM( context, 1 );
return ret ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_EXECUTE_HANDLER;
case EXCEPTION_BREAKPOINT:
ret = DOSVM_EmulateInterruptRM( context, 3 );
return ret ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_EXECUTE_HANDLER;
}
return EXCEPTION_CONTINUE_SEARCH;
}
INT DOSVM_Enter( CONTEXT *context )
{
INT ret = 0;
if (!ISV86(context))
ERR( "Called with protected mode context!\n" );
__TRY
{
if (!WOWCallback16Ex( 0, WCB16_REGS, 0, NULL, (DWORD *)context )) ret = -1;
TRACE_(module)( "ret %d err %u\n", ret, GetLastError() );
}
__EXCEPT(exception_handler)
{
TRACE_(module)( "leaving vm86 mode\n" );
}
__ENDTRY
return ret;
}
/***********************************************************************
* DOSVM_PIC_ioport_out
*/
void DOSVM_PIC_ioport_out( WORD port, BYTE val)
{
if (port != 0x20)
{
FIXME( "Unsupported PIC port %04x\n", port );
}
else if (val == 0x20 || (val >= 0x60 && val <= 0x67))
{
EnterCriticalSection(&qcrit);
if (!current_event)
{
WARN( "%s without active IRQ\n",
val == 0x20 ? "EOI" : "Specific EOI" );
}
else if (val != 0x20 && val - 0x60 != current_event->irq)
{
WARN( "Specific EOI but current IRQ %d is not %d\n",
current_event->irq, val - 0x60 );
}
else
{
LPDOSEVENT event = current_event;
TRACE( "Received %s for current IRQ %d, clearing event\n",
val == 0x20 ? "EOI" : "Specific EOI", event->irq );
current_event = event->next;
if (event->relay)
(*event->relay)(NULL,event->data);
HeapFree(GetProcessHeap(), 0, event);
if (DOSVM_HasPendingEvents())
{
TRACE( "Another event pending, setting pending flag\n" );
get_vm86_teb_info()->vm86_pending |= VIP_MASK;
}
}
LeaveCriticalSection(&qcrit);
}
else
{
FIXME( "Unrecognized PIC command %02x\n", val );
}
}
#else /* !MZ_SUPPORTED */
/***********************************************************************
* DOSVM_Enter
*/
INT DOSVM_Enter( CONTEXT *context )
{
SetLastError( ERROR_NOT_SUPPORTED );
return -1;
}
/***********************************************************************
* DOSVM_Wait
*/
void DOSVM_Wait( CONTEXT *waitctx ) { }
/***********************************************************************
* DOSVM_PIC_ioport_out
*/
void DOSVM_PIC_ioport_out( WORD port, BYTE val) {}
/***********************************************************************
* DOSVM_QueueEvent
*/
void DOSVM_QueueEvent( INT irq, INT priority, DOSRELAY relay, LPVOID data)
{
if (irq<0) {
/* callback event, perform it with dummy context */
CONTEXT context;
memset(&context,0,sizeof(context));
(*relay)(&context,data);
} else {
ERR("IRQ without DOS task: should not happen\n");
}
}
#endif /* MZ_SUPPORTED */
/**********************************************************************
* DOSVM_AcknowledgeIRQ
*
* This routine should be called by all internal IRQ handlers.
*/
void WINAPI DOSVM_AcknowledgeIRQ( CONTEXT *context )
{
/*
* Send EOI to PIC.
*/
DOSVM_PIC_ioport_out( 0x20, 0x20 );
/*
* Protected mode IRQ handlers are supposed
* to turn VIF flag on before they return.
*/
if (!ISV86(context))
get_vm86_teb_info()->dpmi_vif = 1;
}
/***********************************************************************
* DOSVM_AllocUMB
*
* Allocate upper memory block (UMB) from upper memory.
* Returned pointer is aligned to 16-byte (paragraph) boundary.
*
* This routine is only for allocating static storage for
* Wine internal uses. Allocated memory can be accessed from
* real mode, memory is taken from area already mapped and reserved
* by Wine and the allocation has very little memory and speed
* overhead. Use of this routine also preserves precious DOS
* conventional memory.
*/
LPVOID DOSVM_umb_bottom = DOSVM_UMB_BOTTOM;
LPVOID DOSVM_umb_top = DOSVM_UMB_TOP;
static LPVOID DOSVM_AllocUMB( DWORD size )
{
//not wine
if (DOSVM_UMB_BOTTOM == DOSVM_umb_free)
{
DOSVM_umb_free = (size_t)DOSMEM_dosmem + DOSVM_umb_free;
//DOSVM_umb_free = malloc(DOSVM_UMB_TOP - DOSVM_UMB_BOTTOM);
DOSVM_umb_bottom = DOSVM_umb_free;
DOSVM_umb_top = (BYTE*)DOSVM_umb_bottom + DOSVM_UMB_TOP - DOSVM_UMB_BOTTOM;
//LPVOID ret = VirtualAlloc(DOSVM_UMB_BOTTOM, DOSVM_UMB_TOP - DOSVM_UMB_BOTTOM, MEM_COMMIT, PAGE_READWRITE);//DOSVM_UMB_TOP 0xeffff
}
if (DOSVM_umb_bottom != DOSVM_UMB_BOTTOM) {
LPVOID ptr = (LPVOID)DOSVM_umb_free;
size = ((size + 15) >> 4) << 4;
if (DOSVM_umb_free + size - 1 > DOSVM_umb_top) {
ERR("Out of upper memory area.\n");
return 0;
}
DOSVM_umb_free += size;
return ptr;
}
//
LPVOID ptr = (LPVOID)DOSVM_umb_free;
size = ((size + 15) >> 4) << 4;
if(DOSVM_umb_free + size - 1 > DOSVM_UMB_TOP) {
ERR("Out of upper memory area.\n");
return 0;
}
DOSVM_umb_free += size;
return ptr;
}
/**********************************************************************
* alloc_selector
*
* Allocate a selector corresponding to a real mode address.
* size must be < 64k.
*/
static WORD alloc_selector( void *base, DWORD size, unsigned char flags )
{
WORD sel = wine_ldt_alloc_entries( 1 );
if (sel)
{
LDT_ENTRY entry;
wine_ldt_set_base( &entry, base );
wine_ldt_set_limit( &entry, size - 1 );
wine_ldt_set_flags( &entry, flags );
wine_ldt_set_entry( sel, &entry );
}
return sel;
}
/***********************************************************************
* DOSVM_AllocCodeUMB
*
* Allocate upper memory block for storing code stubs.
* Initializes real mode segment and 16-bit protected mode selector
* for the allocated code block.
*
* FIXME: should allocate a single PM selector for the whole UMB range.
*/
static LPVOID DOSVM_AllocCodeUMB( DWORD size, WORD *segment, WORD *selector )
{
LPVOID ptr = DOSVM_AllocUMB( size );
if (segment)
*segment = ((DWORD)ptr - (DWORD)DOSMEM_dosmem) >> 4;
if (selector)
*selector = alloc_selector( ptr, size, WINE_LDT_FLAGS_CODE );
return ptr;
}
/***********************************************************************
* DOSVM_AllocDataUMB
*
* Allocate upper memory block for storing data.
* Initializes real mode segment and 16-bit protected mode selector
* for the allocated data block.
*/
LPVOID DOSVM_AllocDataUMB( DWORD size, WORD *segment, WORD *selector )
{
LPVOID ptr = DOSVM_AllocUMB( size );
if (segment)
*segment = ((DWORD)ptr - (DWORD)DOSMEM_dosmem) >> 4;
if (selector)
*selector = alloc_selector( ptr, size, WINE_LDT_FLAGS_DATA );
return ptr;
}
/***********************************************************************
* DOSVM_InitSegments
*
* Initializes DOSVM_dpmi_segments. Allocates required memory and
* sets up segments and selectors for accessing the memory.
*/
void DOSVM_InitSegments(void)
{
DWORD old_prot;
LPSTR ptr;
int i;
static const char wrap_code[]={
0xCD,0x31, /* int $0x31 */
0xCB /* lret */
};
static const char enter_xms[]=
{
/* XMS hookable entry point */
0xEB,0x03, /* jmp entry */
0x90,0x90,0x90, /* nop;nop;nop */
/* entry: */
/* real entry point */
/* for simplicity, we'll just use the same hook as DPMI below */
0xCD,0x31, /* int $0x31 */
0xCB /* lret */
};
static const char enter_pm[]=
{
0x50, /* pushw %ax */
0x52, /* pushw %dx */
0x55, /* pushw %bp */
0x89,0xE5, /* movw %sp,%bp */
/* get return CS */
0x8B,0x56,0x08, /* movw 8(%bp),%dx */
/* just call int 31 here to get into protected mode... */
/* it'll check whether it was called from dpmi_seg... */
0xCD,0x31, /* int $0x31 */
/* we are now in the context of a 16-bit relay call */
/* need to fixup our stack;
* 16-bit relay return address will be lost,
* but we won't worry quite yet
*/
0x8E,0xD0, /* movw %ax,%ss */
0x66,0x0F,0xB7,0xE5, /* movzwl %bp,%esp */
/* set return CS */
0x89,0x56,0x08, /* movw %dx,8(%bp) */
0x5D, /* popw %bp */
0x5A, /* popw %dx */
0x58, /* popw %ax */
0xfb, /* sti, enable and check virtual interrupts */
0xCB /* lret */
};
static const char relay[]=
{
0xca, 0x04, 0x00, /* 16-bit far return and pop 4 bytes (relay void* arg) */
0xcd, 0x31, /* int 31 */
0xfb, 0x66, 0xcb /* sti and 32-bit far return */
};
/*
* Allocate pointer array.
*/
DOSVM_dpmi_segments = DOSVM_AllocUMB( sizeof(struct DPMI_segments) );
/*
* RM / offset 0: Exit from real mode.
* RM / offset 2: Points to lret opcode.
*/
ptr = DOSVM_AllocCodeUMB( sizeof(wrap_code),
&DOSVM_dpmi_segments->wrap_seg, 0 );
memcpy( ptr, wrap_code, sizeof(wrap_code) );
/*
* RM / offset 0: XMS driver entry.
*/
ptr = DOSVM_AllocCodeUMB( sizeof(enter_xms),
&DOSVM_dpmi_segments->xms_seg, 0 );
memcpy( ptr, enter_xms, sizeof(enter_xms) );
/*
* RM / offset 0: Switch to DPMI.
* PM / offset 8: DPMI raw mode switch.
*/
ptr = DOSVM_AllocCodeUMB( sizeof(enter_pm),
&DOSVM_dpmi_segments->dpmi_seg,
&DOSVM_dpmi_segments->dpmi_sel );
memcpy( ptr, enter_pm, sizeof(enter_pm) );
/*
* PM / offset N*6: Interrupt N in DPMI32.
*/
ptr = DOSVM_AllocCodeUMB( 6 * 256,
0, &DOSVM_dpmi_segments->int48_sel );
for(i=0; i<256; i++) {
/*
* Each 32-bit interrupt handler is 6 bytes:
* 0xCD, = int (nested 16-bit interrupt)
* 0x66,0xCA,0x04,0x00 = ret 4 (32-bit far return and pop 4 bytes / eflags)
*/
ptr[i * 6 + 0] = 0xCD;
ptr[i * 6 + 1] = i;
ptr[i * 6 + 2] = 0x66;
ptr[i * 6 + 3] = 0xCA;
ptr[i * 6 + 4] = 0x04;
ptr[i * 6 + 5] = 0x00;
}
/*
* PM / offset N*5: Interrupt N in 16-bit protected mode.
*/
ptr = DOSVM_AllocCodeUMB( 5 * 256,
0, &DOSVM_dpmi_segments->int16_sel );
for(i=0; i<256; i++) {
/*
* Each 16-bit interrupt handler is 5 bytes:
* 0xCD, = int (interrupt)
* 0xCA,0x02,0x00 = ret 2 (16-bit far return and pop 2 bytes / eflags)
*/
ptr[i * 5 + 0] = 0xCD;
ptr[i * 5 + 1] = i;
ptr[i * 5 + 2] = 0xCA;
ptr[i * 5 + 3] = 0x02;
ptr[i * 5 + 4] = 0x00;
}
// replace int 8 with a far ret so it doesn't cause a DF trap
ptr[8 * 5 + 0] = 0xCA;
ptr[8 * 5 + 1] = 0x02;
ptr[8 * 5 + 2] = 0x00;
/*
* PM / offset 0: Stub where __wine_call_from_16_regs returns.
* PM / offset 3: Stub which swaps back to 32-bit application code/stack.
* PM / offset 5: Stub which enables interrupts
*/
ptr = DOSVM_AllocCodeUMB( sizeof(relay),
0, &DOSVM_dpmi_segments->relay_code_sel);
memcpy( ptr, relay, sizeof(relay) );
/*
* Space for 16-bit stack used by relay code.
*/
ptr = DOSVM_AllocDataUMB( DOSVM_RELAY_DATA_SIZE,
0, &DOSVM_dpmi_segments->relay_data_sel);
memset( ptr, 0, DOSVM_RELAY_DATA_SIZE );
/*
* As we store code in UMB we should make sure it is executable
*/
VirtualProtect((void *)DOSVM_UMB_BOTTOM, DOSVM_UMB_TOP - DOSVM_UMB_BOTTOM, PAGE_EXECUTE_READWRITE, &old_prot);
event_notifier = CreateEventW(NULL, FALSE, FALSE, NULL);
}
================================================
FILE: krnl386/error.c
================================================
/*
* Log internal errors
*
* Copyright 1997 Andrew Taylor
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include
#include
#include
#include
#include "windef.h"
#include "wine/winbase16.h"
#include "wine/debug.h"
#include "kernel16_private.h"
/* LogParamError and LogError values */
/* Error modifier bits */
#define ERR_WARNING 0x8000
#define ERR_PARAM 0x4000
#define ERR_SIZE_MASK 0x3000
#define ERR_BYTE 0x1000
#define ERR_WORD 0x2000
#define ERR_DWORD 0x3000
/* LogParamError() values */
/* Generic parameter values */
#define ERR_BAD_VALUE 0x6001
#define ERR_BAD_FLAGS 0x6002
#define ERR_BAD_INDEX 0x6003
#define ERR_BAD_DVALUE 0x7004
#define ERR_BAD_DFLAGS 0x7005
#define ERR_BAD_DINDEX 0x7006
#define ERR_BAD_PTR 0x7007
#define ERR_BAD_FUNC_PTR 0x7008
#define ERR_BAD_SELECTOR 0x6009
#define ERR_BAD_STRING_PTR 0x700a
#define ERR_BAD_HANDLE 0x600b
/* KERNEL parameter errors */
#define ERR_BAD_HINSTANCE 0x6020
#define ERR_BAD_HMODULE 0x6021
#define ERR_BAD_GLOBAL_HANDLE 0x6022
#define ERR_BAD_LOCAL_HANDLE 0x6023
#define ERR_BAD_ATOM 0x6024
#define ERR_BAD_HFILE 0x6025
/* USER parameter errors */
#define ERR_BAD_HWND 0x6040
#define ERR_BAD_HMENU 0x6041
#define ERR_BAD_HCURSOR 0x6042
#define ERR_BAD_HICON 0x6043
#define ERR_BAD_HDWP 0x6044
#define ERR_BAD_CID 0x6045
#define ERR_BAD_HDRVR 0x6046
/* GDI parameter errors */
#define ERR_BAD_COORDS 0x7060
#define ERR_BAD_GDI_OBJECT 0x6061
#define ERR_BAD_HDC 0x6062
#define ERR_BAD_HPEN 0x6063
#define ERR_BAD_HFONT 0x6064
#define ERR_BAD_HBRUSH 0x6065
#define ERR_BAD_HBITMAP 0x6066
#define ERR_BAD_HRGN 0x6067
#define ERR_BAD_HPALETTE 0x6068
#define ERR_BAD_HMETAFILE 0x6069
/* LogError() values */
/* KERNEL errors */
#define ERR_GALLOC 0x0001
#define ERR_GREALLOC 0x0002
#define ERR_GLOCK 0x0003
#define ERR_LALLOC 0x0004
#define ERR_LREALLOC 0x0005
#define ERR_LLOCK 0x0006
#define ERR_ALLOCRES 0x0007
#define ERR_LOCKRES 0x0008
#define ERR_LOADMODULE 0x0009
/* USER errors */
#define ERR_CREATEDLG 0x0040
#define ERR_CREATEDLG2 0x0041
#define ERR_REGISTERCLASS 0x0042
#define ERR_DCBUSY 0x0043
#define ERR_CREATEWND 0x0044
#define ERR_STRUCEXTRA 0x0045
#define ERR_LOADSTR 0x0046
#define ERR_LOADMENU 0x0047
#define ERR_NESTEDBEGINPAINT 0x0048
#define ERR_BADINDEX 0x0049
#define ERR_CREATEMENU 0x004a
/* GDI errors */
#define ERR_CREATEDC 0x0080
#define ERR_CREATEMETA 0x0081
#define ERR_DELOBJSELECTED 0x0082
#define ERR_SELBITMAP 0x0083
#define ErrorString(manifest) { manifest, # manifest }
static const struct {
int constant;
const char *name;
} ErrorStrings[] = {
ErrorString(ERR_GALLOC),
ErrorString(ERR_GREALLOC),
ErrorString(ERR_GLOCK),
ErrorString(ERR_LALLOC),
ErrorString(ERR_LREALLOC),
ErrorString(ERR_LLOCK),
ErrorString(ERR_ALLOCRES),
ErrorString(ERR_LOCKRES),
ErrorString(ERR_LOADMODULE),
ErrorString(ERR_CREATEDLG),
ErrorString(ERR_CREATEDLG2),
ErrorString(ERR_REGISTERCLASS),
ErrorString(ERR_DCBUSY),
ErrorString(ERR_CREATEWND),
ErrorString(ERR_STRUCEXTRA),
ErrorString(ERR_LOADSTR),
ErrorString(ERR_LOADMENU),
ErrorString(ERR_NESTEDBEGINPAINT),
ErrorString(ERR_BADINDEX),
ErrorString(ERR_CREATEMENU),
ErrorString(ERR_CREATEDC),
ErrorString(ERR_CREATEMETA),
ErrorString(ERR_DELOBJSELECTED),
ErrorString(ERR_SELBITMAP)
};
static const struct {
int constant;
const char *name;
} ParamErrorStrings[] = {
ErrorString(ERR_BAD_VALUE),
ErrorString(ERR_BAD_FLAGS),
ErrorString(ERR_BAD_INDEX),
ErrorString(ERR_BAD_DVALUE),
ErrorString(ERR_BAD_DFLAGS),
ErrorString(ERR_BAD_DINDEX),
ErrorString(ERR_BAD_PTR),
ErrorString(ERR_BAD_FUNC_PTR),
ErrorString(ERR_BAD_SELECTOR),
ErrorString(ERR_BAD_STRING_PTR),
ErrorString(ERR_BAD_HANDLE),
ErrorString(ERR_BAD_HINSTANCE),
ErrorString(ERR_BAD_HMODULE),
ErrorString(ERR_BAD_GLOBAL_HANDLE),
ErrorString(ERR_BAD_LOCAL_HANDLE),
ErrorString(ERR_BAD_ATOM),
ErrorString(ERR_BAD_HFILE),
ErrorString(ERR_BAD_HWND),
ErrorString(ERR_BAD_HMENU),
ErrorString(ERR_BAD_HCURSOR),
ErrorString(ERR_BAD_HICON),
ErrorString(ERR_BAD_HDWP),
ErrorString(ERR_BAD_CID),
ErrorString(ERR_BAD_HDRVR),
ErrorString(ERR_BAD_COORDS),
ErrorString(ERR_BAD_GDI_OBJECT),
ErrorString(ERR_BAD_HDC),
ErrorString(ERR_BAD_HPEN),
ErrorString(ERR_BAD_HFONT),
ErrorString(ERR_BAD_HBRUSH),
ErrorString(ERR_BAD_HBITMAP),
ErrorString(ERR_BAD_HRGN),
ErrorString(ERR_BAD_HPALETTE),
ErrorString(ERR_BAD_HMETAFILE)
};
#undef ErrorString
/***********************************************************************
* GetErrorString (internal)
*/
static const char *GetErrorString(UINT16 uErr)
{
static char buffer[80];
unsigned int n;
for (n = 0; n < ARRAY_SIZE(ErrorStrings); n++) {
if (uErr == ErrorStrings[n].constant)
return ErrorStrings[n].name;
}
sprintf(buffer, "%x", uErr);
return buffer;
}
/***********************************************************************
* GetParamErrorString (internal)
*/
static const char *GetParamErrorString(UINT16 uErr) {
static char buffer[80];
if (uErr & ERR_WARNING) {
strcpy(buffer, "ERR_WARNING | ");
uErr &= ~ERR_WARNING;
} else
buffer[0] = '\0';
{
unsigned int n;
for (n = 0; n < ARRAY_SIZE(ParamErrorStrings); n++) {
if (uErr == ParamErrorStrings[n].constant) {
strcat(buffer, ParamErrorStrings[n].name);
return buffer;
}
}
}
sprintf(buffer + strlen(buffer), "%x", uErr);
return buffer;
}
/***********************************************************************
* SetLastError (KERNEL.147)
*/
void WINAPI SetLastError16( DWORD error )
{
SetLastError( error );
}
/***********************************************************************
* GetLastError (KERNEL.148)
*/
DWORD WINAPI GetLastError16(void)
{
return GetLastError();
}
/***********************************************************************
* LogError (KERNEL.324)
*/
VOID WINAPI LogError16(UINT16 uErr, LPVOID lpvInfo)
{
MESSAGE("(%s, %p)\n", GetErrorString(uErr), lpvInfo);
}
/***********************************************************************
* LogParamError (KERNEL.325)
*/
void WINAPI LogParamError16(UINT16 uErr, FARPROC16 lpfn, LPVOID lpvParam)
{
/* FIXME: is it possible to get the module name/function
* from the lpfn param?
*/
MESSAGE("(%s, %p, %p)\n", GetParamErrorString(uErr), lpfn, lpvParam);
}
/***********************************************************************
* K327 (KERNEL.327)
*/
void WINAPI HandleParamError( CONTEXT *context )
{
UINT16 uErr = LOWORD(context->Ebx);
FARPROC16 lpfn = (FARPROC16)MAKESEGPTR( context->SegCs, context->Eip );
LPVOID lpvParam = (LPVOID)MAKELONG( LOWORD(context->Eax), LOWORD(context->Ecx) );
LogParamError16( uErr, lpfn, lpvParam );
if (!(uErr & ERR_WARNING))
{
/* Abort current procedure: Unwind stack frame and jump
to error handler (location at [bp-2]) */
WORD *stack = MapSL( MAKESEGPTR( context->SegSs, LOWORD(context->Ebp) ));
context->Esp = LOWORD(context->Ebp) - 2;
context->Ebp = stack[0] & 0xfffe;
context->Eip = stack[-1];
context->Eax = context->Ecx = context->Edx = 0;
context->SegEs = 0;
}
}
================================================
FILE: krnl386/file.c
================================================
/*
* File handling functions
*
* Copyright 1993 John Burton
* Copyright 1996 Alexandre Julliard
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*
* TODO:
* Fix the CopyFileEx methods to implement the "extended" functionality.
* Right now, they simply call the CopyFile method.
*/
#include "config.h"
#include "wine/port.h"
#include
#include
#include
#include "winerror.h"
#include "windef.h"
#include "winbase.h"
#include "winternl.h"
#include "wine/winbase16.h"
#include "kernel16_private.h"
#include "wine/unicode.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(file);
#include
#include
#include
#pragma comment(lib, "imagehlp.lib")
#pragma comment(lib, "shlwapi.lib")
#ifdef ENABLEREDIRECTSYSTEMDIR
BOOL EnableRedirectSystemDir = TRUE;
#else
BOOL EnableRedirectSystemDir = FALSE;
#endif
const char *GetRedirectWindowsDir();
static void RedirectPrivateProfileStringWindowsDir(LPCSTR filename, LPCSTR output);
NTSYSAPI
NTSTATUS
NTAPI
NtAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
IN HANDLE TokenHandle,
IN ACCESS_MASK DesiredAccess,
IN PGENERIC_MAPPING GenericMapping,
OUT PPRIVILEGE_SET PrivilegeSet OPTIONAL,
IN OUT PULONG PrivilegeSetLength,
OUT PACCESS_MASK GrantedAccess,
OUT PNTSTATUS AccessStatus);
BOOL can_write_directory(LPCSTR path)
{
HANDLE hToken = INVALID_HANDLE_VALUE, hTokenImpersonation = INVALID_HANDLE_VALUE;
PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL;
GENERIC_MAPPING genericMapping = { 0 };
PRIVILEGE_SET privilegeSet = { 0 };
NTSTATUS accessStatus = 0;
DWORD dwDesiredAccess = FILE_GENERIC_WRITE;
DWORD dwSize = sizeof(PRIVILEGE_SET);
DWORD dwGrantedAccess = 0;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_DUPLICATE, &hToken))
goto fail;
if (!DuplicateTokenEx(hToken, GENERIC_ALL, NULL, SecurityImpersonation, TokenImpersonation, &hTokenImpersonation))
goto fail;
if (GetNamedSecurityInfoA(path, SE_FILE_OBJECT, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, NULL, NULL, NULL, NULL, &pSecurityDescriptor) != ERROR_SUCCESS)
goto fail;
genericMapping.GenericRead = FILE_GENERIC_READ;
genericMapping.GenericWrite = FILE_GENERIC_WRITE;
genericMapping.GenericExecute = FILE_GENERIC_EXECUTE;
genericMapping.GenericAll = FILE_ALL_ACCESS;
MapGenericMask(&dwDesiredAccess, &genericMapping);
/* Because app compatibility layer hooks AccessCheck and returns incorrect result, call NtAccessCheck. (NS_WRPMitigation::APIHook_AccessCheck) */
if (!NT_SUCCESS(NtAccessCheck(pSecurityDescriptor, hTokenImpersonation, dwDesiredAccess, &genericMapping, &privilegeSet, &dwSize, &dwGrantedAccess, &accessStatus)))
goto fail;
fail:
CloseHandle(hToken);
CloseHandle(hTokenImpersonation);
LocalFree(pSecurityDescriptor);
return NT_SUCCESS(accessStatus);
}
BOOL is_readonly_directory(LPCSTR path)
{
DWORD attr = GetFileAttributesA(path);
if (attr == -1)
return FALSE;
if (GetDriveTypeA(path) == DRIVE_CDROM)
return TRUE;
return (attr & FILE_ATTRIBUTE_READONLY) == FILE_ATTRIBUTE_READONLY;
}
__declspec(dllexport) LPCSTR RedirectDriveRoot(LPCSTR path, LPSTR to, size_t max_len, BOOL silence)
{
LPCSTR path_old = path;
enum WRITABLE_CACHE
{
NOTCACHED,
ALLOWED,
DENIED,
READONLY,
};
static enum WRITABLE_CACHE writable_cache[26];
char drive = path ? path[0] : 0;
char root[4] = { drive, ':', '\\', 0 };
char drive_buf[5] = { '.', '.', '\\', drive, 0 };
if (!path)
return NULL;
if (!(path[0] && path[1] == ':' && (path[2] == 0 || path[2] == '\\' || path[2] == '/')))
return path;
if (!((path[0] >= 'A' && path[0] <= 'Z') || (path[0] >= 'a' && path[0] <= 'z')))
return path;
if (drive >= 'a' && drive <= 'z')
{
drive -= 'a' - 'A';
}
path += 2;
if (path[0])
path += 1;
if (strchr(path, '\\'))
return path_old;
if (strchr(path, '/'))
return path_old;
if (writable_cache[drive - 'A'] == NOTCACHED)
{
if (is_readonly_directory(root))
{
writable_cache[drive - 'A'] = READONLY;
return path_old;
}
if (can_write_directory(root))
{
writable_cache[drive - 'A'] = ALLOWED;
return path_old;
}
else
{
writable_cache[drive - 'A'] = DENIED;
}
}
else
{
if (writable_cache[drive - 'A'] == ALLOWED || writable_cache[drive - 'A'] == READONLY)
{
return path_old;
}
}
PathCombineA(to, GetRedirectWindowsDir(), drive_buf);
CreateDirectoryA(to, NULL);
PathCombineA(to, to, path);
if (!silence)
{
ERR("%s => %s\n", path_old, to);
}
return to;
}
/* buf: X:\XXX\YYY\C\ZZZ => C:\ZZZ */
void UnredirectDriveRoot(LPSTR buf, SIZE_T buf_len)
{
char drive_root[MAX_PATH];
PathCombineA(drive_root, GetRedirectWindowsDir(), "..\\");
if (memcmp(drive_root, buf, min(strlen(buf), strlen(drive_root))) == 0)
{
LPCSTR drive_dir = buf + strlen(drive_root);
if (drive_dir[0] >= 'A' && drive_dir[0] <= 'Z' && drive_dir[1] == '\\')
{
buf[0] = drive_dir[0];
buf[1] = ':';
buf[2] = '\\';
memmove(buf + 3, drive_dir + 2, strlen(drive_dir + 2) + 1);
}
return;
}
return;
}
/*
* C:\WINDOWS-> redirected windows dir
* C:\WINDOWS\SYSTEM32 -> redirected windows dir\SYSTEM
*/
__declspec(dllexport) LPCSTR RedirectSystemDir(LPCSTR path, LPSTR to, size_t max_len)
{
char dirbuf[240];
if (!EnableRedirectSystemDir) return path;
char buf[MAX_PATH];
if (!PathCanonicalizeA(buf, path))
{
return path;
}
char bufwdir[MAX_PATH];
GetWindowsDirectoryA(bufwdir, MAX_PATH);
size_t windir_len = strlen(bufwdir);
if (PathCommonPrefixA(buf, bufwdir, NULL) < windir_len)
{
return path;
}
if (!PathAppendA(bufwdir, "system32"))
{
return path;
}
//system32->system
if (PathCommonPrefixA(buf, bufwdir, NULL) >= strlen(bufwdir))
{
memcpy(buf + strlen(bufwdir) - 2, buf + strlen(bufwdir), strlen(buf) - strlen(bufwdir) + 1);
}
//.\windir\
dirbuf[0] = '\0';
char *dir = &dirbuf[0];
GetModuleFileNameA(GetModuleHandleA("otvdm.exe"), dir, MAX_PATH);
char *file = PathFindFileNameA(dir);
if (file != dir) *file = '\0';
if (!PathAppendA(dir, GetRedirectWindowsDir()))
return path;
if (!PathAppendA(dir, buf + windir_len))
return path;
if (strlen(dir) >= max_len)
return path;
file = PathFindFileNameA(dir);
char f = *file;
*file = '\0';
GetShortPathNameA(dir, to, max_len);
*file = f;
PathCombineA(to, to, file);
return to;
}
NTSYSAPI NTSTATUS NTAPI RtlUpcaseUnicodeStringToOemString(
POEM_STRING DestinationString,
PCUNICODE_STRING SourceString,
BOOLEAN AllocateDestinationString
);
static LPWSTR strdupAtoW(LPCSTR str)
{
LPWSTR ret;
INT len;
if (!str) return NULL;
len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
if (ret) MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
return ret;
}
static LPWSTR strdupOEMtoW(LPCSTR str)
{
LPWSTR ret;
INT len;
if (!str) return NULL;
len = MultiByteToWideChar(CP_OEMCP, 0, str, -1, NULL, 0);
ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
if (ret) MultiByteToWideChar(CP_OEMCP, 0, str, -1, ret, len);
return ret;
}
static LPCSTR strdupWtoOEM(LPCWSTR str)
{
LPSTR ret;
INT len;
if (!str) return NULL;
len = WideCharToMultiByte(CP_OEMCP, 0, str, -1, NULL, 0, NULL, NULL);
ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(CHAR));
if (ret) WideCharToMultiByte(CP_OEMCP, 0, str, -1, ret, len, NULL, NULL);
return ret;
}
#define DOS_TABLE_SIZE 256
static HANDLE *FILE_GetTable()
{
static DWORD dos_handles_index = NULL;
if (!dos_handles_index) dos_handles_index = TlsAlloc();
HANDLE *dos_handles = TlsGetValue(dos_handles_index);
if (!dos_handles)
{
dos_handles = (HANDLE *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HANDLE)*256);
TlsSetValue(dos_handles_index, dos_handles);
}
return dos_handles;
}
// only call at task exit
void FILE_CloseAll()
{
HANDLE *dos_handles = FILE_GetTable();
for (int i = 0; i < 256; i++)
{
if (dos_handles[i])
CloseHandle(dos_handles[i]);
}
HeapFree(GetProcessHeap(), 0, dos_handles);
}
/***********************************************************************
* FILE_InitProcessDosHandles
*
* Allocates the default DOS handles for a process. Called either by
* Win32HandleToDosFileHandle below or by the DOSVM stuff.
*/
static void FILE_InitProcessDosHandles( void )
{
HANDLE hStdInput, hStdOutput, hStdError, hNull;
static BOOL init_done /* = FALSE */;
HANDLE cp = GetCurrentProcess();
if (init_done) return;
HANDLE *dos_handles = FILE_GetTable();
init_done = TRUE;
hStdInput = GetStdHandle(STD_INPUT_HANDLE);
hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
hStdError = GetStdHandle(STD_ERROR_HANDLE);
hNull = CreateFileA("NUL", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
/* Invalid console handles need to translate to real DOS handles in a new process */
if (!hStdInput) hStdInput = hNull;
if (!hStdOutput) hStdOutput = hNull;
if (!hStdError) hStdError = hNull;
DuplicateHandle(cp, hStdInput, cp, &dos_handles[0], 0, TRUE, DUPLICATE_SAME_ACCESS);
DuplicateHandle(cp, hStdOutput, cp, &dos_handles[1], 0, TRUE, DUPLICATE_SAME_ACCESS);
DuplicateHandle(cp, hStdError, cp, &dos_handles[2], 0, TRUE, DUPLICATE_SAME_ACCESS);
DuplicateHandle(cp, hStdError, cp, &dos_handles[3], 0, TRUE, DUPLICATE_SAME_ACCESS);
DuplicateHandle(cp, hStdError, cp, &dos_handles[4], 0, TRUE, DUPLICATE_SAME_ACCESS);
CloseHandle(hNull);
}
/***********************************************************************
* DosFileHandleToWin32Handle (KERNEL32.20)
*
* Return the Win32 handle for a DOS handle.
*
* Note: this is not exactly right, since on Win95 the Win32 handles
* are on top of DOS handles and we do it the other way
* around. Should be good enough though.
*/
HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle )
{
HFILE16 hfile = (HFILE16)handle;
if (hfile < 5) FILE_InitProcessDosHandles();
HANDLE *dos_handles = FILE_GetTable();
if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
{
SetLastError( ERROR_INVALID_HANDLE );
return INVALID_HANDLE_VALUE;
}
return dos_handles[hfile];
}
/***********************************************************************
* Win32HandleToDosFileHandle (KERNEL32.21)
*
* Allocate a DOS handle for a Win32 handle. The Win32 handle is no
* longer valid after this function (even on failure).
*
* Note: this is not exactly right, since on Win95 the Win32 handles
* are on top of DOS handles and we do it the other way
* around. Should be good enough though.
*/
HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle )
{
int i;
if (!handle || (handle == INVALID_HANDLE_VALUE))
return HFILE_ERROR;
HANDLE *dos_handles = FILE_GetTable();
for (i = 5; i < DOS_TABLE_SIZE; i++)
if (dos_handles[i] == handle) return (HFILE)i;
for (i = 5; i < DOS_TABLE_SIZE; i++)
if (!dos_handles[i])
{
dos_handles[i] = handle;
TRACE("Got %d for h32 %p\n", i, handle );
return (HFILE)i;
}
CloseHandle( handle );
SetLastError( ERROR_TOO_MANY_OPEN_FILES );
return HFILE_ERROR;
}
/***********************************************************************
* DisposeLZ32Handle (KERNEL32.22)
*
* Note: this is not entirely correct, we should only close the
* 32-bit handle and not the 16-bit one, but we cannot do
* this because of the way our DOS handles are implemented.
* It shouldn't break anything though.
*/
BOOL16 WINAPI DeleteDosFileHandle( HANDLE handle )
{
int i;
if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
HANDLE *dos_handles = FILE_GetTable();
for (i = 5; i < DOS_TABLE_SIZE; i++)
if (dos_handles[i] == handle)
{
dos_handles[i] = 0;
return TRUE;
}
return FALSE;
}
/***********************************************************************
* GetProfileInt (KERNEL.57)
*/
UINT16 WINAPI GetProfileInt16( LPCSTR section, LPCSTR entry, INT16 def_val )
{
return GetPrivateProfileInt16( section, entry, def_val, "win.ini" );
}
int CALLBACK enum_ini_font(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
{
char *name = (char *)lParam;
return strncmp(name, lf->lfFaceName, strlen(lf->lfFaceName));
}
/***********************************************************************
* GetProfileString (KERNEL.58)
*/
INT16 WINAPI GetProfileString16( LPCSTR section, LPCSTR entry, LPCSTR def_val,
LPSTR buffer, UINT16 len )
{
char tmp[256];
int tmplen = 256;
if (section && entry && !stricmp(section, "devices") && !stricmp(entry, "DefaultPrinter"))
{
if (GetDefaultPrinterA(tmp, &tmplen))
entry = tmp;
}
INT16 ret = GetPrivateProfileString16( section, entry, def_val,
buffer, len, "win.ini" );
if (ret && section && entry && !stricmp(section, "windows") && !stricmp(entry, "device"))
{
char *comma = strchr(buffer, ',');
if (!comma && ((len - 1) == ret))
{
ret = GetPrivateProfileString16( section, entry, def_val,
tmp, tmplen, "win.ini" );
comma = strchr(tmp, ',');
if (comma && (len > (strlen(comma) + 14)))
{
strcpy(buffer, "DefaultPrinter");
strcpy(buffer + 14, comma);
}
}
else if (comma && ((comma - buffer) > 32))
{
strcpy(buffer, "DefaultPrinter");
strcpy(buffer + 14, comma);
}
ret = strlen(buffer);
}
else if (!ret && section && !stricmp(section, "fonts"))
{
LOGFONTA lf;
HDC hdc = GetDC(0);
lf.lfCharSet = DEFAULT_CHARSET;
lf.lfPitchAndFamily = 0;
lf.lfFaceName[0] = 0;
ret = EnumFontFamiliesExA(hdc, &lf, enum_ini_font, entry, 0);
ReleaseDC(0, hdc);
if (!ret)
strncpy(buffer, "vgaoem.fon", len); // actual filename is unavailable
return !ret ? strnlen(buffer, len) : 0;
}
else if (ret && !PathIsRelativeA(buffer) && PathFileExistsA(buffer))
{
int cnt = GetShortPathNameA(buffer, tmp, len <= 256 ? len : 256);
if (cnt)
strcpy(buffer, tmp);
}
return ret;
}
/***********************************************************************
* WriteProfileString (KERNEL.59)
*/
BOOL16 WINAPI WriteProfileString16( LPCSTR section, LPCSTR entry,
LPCSTR string )
{
return WritePrivateProfileString16( section, entry, string, "win.ini" );
}
/* get the search path for the current module; helper for OpenFile16 */
/*static */char *get_search_path(void)
{
UINT len, i;
char *ret, *p, module[OFS_MAXPATHNAME];
module[0] = 0;
if (GetCurrentTask() && GetModuleFileName16( GetCurrentTask(), module, sizeof(module) ))
{
if (!(p = strrchr( module, '\\' ))) p = module;
*p = 0;
}
char windir[MAX_PATH];
char windir2[MAX_PATH];
char realwinsys[MAX_PATH];
char *windir3;
GetWindowsDirectoryA(windir, MAX_PATH);
windir3 = RedirectSystemDir(windir, windir2, MAX_PATH);
char vdmpath[MAX_PATH];
GetModuleFileNameA(GetModuleHandleA(NULL), vdmpath, MAX_PATH);
PathRemoveFileSpecA(vdmpath);
GetShortPathNameA(vdmpath, vdmpath, MAX_PATH);
strcpy(realwinsys, windir);
strcat(realwinsys, "\\SYSTEM");
len = (strlen(vdmpath) + 1 + 2 + /* search order: first current dir */
GetSystemDirectory16( NULL, 0 ) + 1 + /* then system dir */
strlen(windir3) + 1 + /* then windows dir */
strlen( module ) + 1 + /* then module path */
GetEnvironmentVariableA( "PATH16", NULL, 0 ) + 1 + /* then look in PATH */
strlen(realwinsys) + 1); /* then the real windows system dir */
if (!(ret = HeapAlloc( GetProcessHeap(), 0, len ))) return NULL;
strcpy(ret, ".;");
p = ret + 2;
strcpy(p, vdmpath);
p += strlen(vdmpath);
*p++ = ';';
GetSystemDirectory16( p, ret + len - p );
p += strlen( p );
*p++ = ';';
strcpy(p, windir3);//GetWindowsDirectoryA( p, ret + len - p );
p += strlen( p );
*p++ = ';';
if (module[0])
{
strcpy( p, module );
p += strlen( p );
*p++ = ';';
}
i = GetEnvironmentVariableA("PATH16", p, ret + len - p);
if (i)
{
p += i;
*p++ = ';';
}
strcpy(p, realwinsys);
return ret;
}
char *krnl386_get_search_path(void)
{
return get_search_path();
}
#define STRSAFE_NO_DEPRECATE
#include
LPCSTR krnl386_search_executable_file(LPCSTR lpFile, LPSTR buf, SIZE_T size, BOOL search_builtin)
{
char *path = krnl386_get_search_path();
LPCSTR result = lpFile;
if (SearchPathA(path, lpFile, NULL, size, buf, NULL))
{
result = buf;
}
else
{
char dlldir[MAX_PATH];
GetDllDirectoryA(MAX_PATH, dlldir);
if (SearchPathA(dlldir, lpFile, NULL, size, buf, NULL))
{
result = buf;
}
}
if (result == lpFile && search_builtin)
{
char filewin32[MAX_PATH];
LPSTR ext = PathFindExtensionA(lpFile);
if (ext && !stricmp(ext, ".dll") || !stricmp(ext, ".exe") || !stricmp(ext, ".drv"))
{
filewin32[0] = '\0';
if (StringCbCatA(filewin32, ARRAYSIZE(filewin32), lpFile) == S_OK &&
StringCbCatA(filewin32, ARRAYSIZE(filewin32), "16") == S_OK)
{
if (SearchPathA(path, filewin32, NULL, size, buf, NULL))
{
result = buf;
}
else
{
char dlldir[MAX_PATH];
GetDllDirectoryA(MAX_PATH, dlldir);
if (SearchPathA(dlldir, filewin32, NULL, size, buf, NULL))
{
result = buf;
}
}
}
}
}
HeapFree(GetProcessHeap(), 0, path);
return result;
}
/***********************************************************************
* create_file_OF
*
* Wrapper for CreateFile that takes OF_* mode flags.
*/
static HANDLE create_file_OF( LPCWSTR path, INT mode )
{
DWORD access, sharing, creation;
if (mode & OF_CREATE)
{
creation = CREATE_ALWAYS;
access = GENERIC_READ | GENERIC_WRITE;
}
else
{
creation = OPEN_EXISTING;
switch(mode & 0x03)
{
case OF_READ: access = GENERIC_READ; break;
case OF_WRITE: access = GENERIC_WRITE; break;
case OF_READWRITE: access = GENERIC_READ | GENERIC_WRITE; break;
default: access = 0; break;
}
}
switch(mode & 0x70)
{
case OF_SHARE_EXCLUSIVE: sharing = 0; break;
case OF_SHARE_DENY_WRITE: sharing = FILE_SHARE_READ; break;
case OF_SHARE_DENY_READ: sharing = FILE_SHARE_WRITE; break;
case OF_SHARE_DENY_NONE:
case OF_SHARE_COMPAT:
default: sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
}
return CreateFileW( path, access, sharing | FILE_SHARE_DELETE, NULL, creation, FILE_ATTRIBUTE_NORMAL, 0 );
}
/***********************************************************************
* OpenFile (KERNEL.74)
* OpenFileEx (KERNEL.360)
*/
HFILE16 WINAPI WIN16_OpenFile16( LPCSTR name, SEGPTR ofs, UINT16 mode )
{
CURRENT_STACK16->es = SELECTOROF(ofs);
return OpenFile16(name, MapSL(ofs), mode);
}
HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
{
HFILE hFileRet = 0;
HANDLE handle = INVALID_HANDLE_VALUE;
FILETIME filetime;
WORD filedatetime[2];
OEM_STRING oem;
UNICODE_STRING uni;
FILETIME lfiletime;
WCHAR pathname[sizeof(ofs->szPathName)];
LPWSTR namew;
const WCHAR *p, *filename;
CHAR buf[OFS_MAXPATHNAME];
CHAR redir[MAX_PATH];
BOOL result;
oem.Buffer = ofs->szPathName;
oem.Length = 0;
oem.MaximumLength = sizeof(ofs->szPathName);
if (!ofs) return HFILE_ERROR;
TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",debugstr_a(name),
((mode & 0x3 )==OF_READ)?"OF_READ":
((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
);
name = RedirectSystemDir(name, redir, MAX_PATH);
if ((mode & (OF_CREATE | OF_SHARE_EXCLUSIVE)) == (OF_CREATE | OF_SHARE_EXCLUSIVE))
{
mode &= ~OF_SHARE_EXCLUSIVE;
}
{
ofs->cBytes = sizeof(OFSTRUCT);
ofs->nErrCode = 0;
if (mode & OF_REOPEN) name = ofs->szPathName;
if (!name)
{
return HFILE_ERROR;
}
name = RedirectDriveRoot(name, buf, ARRAY_SIZE(buf), FALSE);
if (mode & OF_REOPEN)
namew = strdupOEMtoW(name);
else
namew = strdupAtoW(name);
/* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
Are there any cases where getting the path here is wrong?
Uwe Bonnes 1997 Apr 2 */
if (!*namew)
{
/* empty path => cwd */
result = GetCurrentDirectoryW(sizeof(ofs->szPathName), pathname);
if (result)
{
size_t len = wcslen(pathname);
if (len < sizeof(ofs->szPathName) - 1 && pathname[len - 1] != '\\' && pathname[len - 1] != '/')
{
pathname[len] = '\\';
pathname[len + 1] = 0;
}
}
if (result && !(mode & OF_PARSE))
{
SetLastError(ERROR_FILE_NOT_FOUND);
RtlInitUnicodeString(&uni, pathname);
if (!NT_SUCCESS(RtlUpcaseUnicodeStringToOemString(&oem, &uni, FALSE)))
{
ERR("RtlUpcaseUnicodeStringToOemString failed\n");
ofs->szPathName[0] = '\0';
}
goto error;
}
}
else
{
result = GetFullPathNameW(namew, sizeof(ofs->szPathName), pathname, NULL);
}
if (!result)
{
RtlInitUnicodeString(&uni, namew);
if (!NT_SUCCESS(RtlUpcaseUnicodeStringToOemString(&oem, &uni, FALSE)))
{
ERR("RtlUpcaseUnicodeStringToOemString failed\n");
ofs->szPathName[0] = '\0';
}
goto error;
}
/* If OF_SEARCH is set, ignore the given path */
filename = namew;
if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
{
/* First try the file name as is */
if (GetFileAttributesW( filename ) != INVALID_FILE_ATTRIBUTES) filename = NULL;
else
{
/* Now remove the path */
if (filename[0] && (filename[1] == ':')) filename += 2;
if ((p = wcsrchr( filename, '\\' ))) filename = p + 1;
if ((p = wcsrchr( filename, '/' ))) filename = p + 1;
if (!filename[0])
{
RtlInitUnicodeString(&uni, filename);
if (!NT_SUCCESS(RtlUpcaseUnicodeStringToOemString(&oem, &uni, FALSE)))
{
ERR("RtlUpcaseUnicodeStringToOemString failed\n");
ofs->szPathName[0] = '\0';
}
SetLastError( ERROR_FILE_NOT_FOUND );
goto error;
}
}
}
/* Now look for the file */
if (!(mode & OF_PARSE) && !(mode & OF_CREATE) && filename)
{
BOOL found;
char *path = get_search_path();
WCHAR *pathw;
if (!path)
{
RtlInitUnicodeString(&uni, filename);
if (!NT_SUCCESS(RtlUpcaseUnicodeStringToOemString(&oem, &uni, FALSE)))
{
ERR("RtlUpcaseUnicodeStringToOemString failed\n");
ofs->szPathName[0] = '\0';
}
goto error;
}
if (!wcsicmp(pathname, L"\\\\.\\nul"))
found = TRUE;
else
{
pathw = strdupAtoW(path);
found = SearchPathW( pathw, filename, NULL, sizeof(ofs->szPathName),
pathname, NULL );
HeapFree( GetProcessHeap(), 0, path );
HeapFree( GetProcessHeap(), 0, pathw );
}
if (!found)
{
RtlInitUnicodeString(&uni, pathname);
if (!NT_SUCCESS(RtlUpcaseUnicodeStringToOemString(&oem, &uni, FALSE)))
{
ERR("RtlUpcaseUnicodeStringToOemString failed\n");
ofs->szPathName[0] = '\0';
}
goto error;
}
}
TRACE("found %s\n", debugstr_w(pathname) );
if (mode & OF_DELETE)
{
RtlInitUnicodeString(&uni, pathname);
if (!NT_SUCCESS(RtlUpcaseUnicodeStringToOemString(&oem, &uni, FALSE)))
{
ERR("RtlUpcaseUnicodeStringToOemString failed\n");
ofs->szPathName[0] = '\0';
}
if (!DeleteFileW(pathname)) goto error;
TRACE("(%s): OF_DELETE return = OK\n", name);
HeapFree(GetProcessHeap(), 0, namew);
return 1;
}
GetShortPathNameW(pathname, pathname, ARRAY_SIZE(pathname));
if (pathname[0] && pathname[wcslen(pathname) - 1] == '\\')
{
SetLastError(ERROR_FILE_NOT_FOUND);
handle = INVALID_HANDLE_VALUE;
hFileRet = HFILE_ERROR16;
}
else if (!(mode & OF_PARSE))
{
handle = create_file_OF(pathname, mode);
}
RtlInitUnicodeString(&uni, pathname);
if (!NT_SUCCESS(RtlUpcaseUnicodeStringToOemString(&oem, &uni, FALSE)))
{
ERR("RtlUpcaseUnicodeStringToOemString failed\n");
ofs->szPathName[0] = '\0';
}
UnredirectDriveRoot(ofs->szPathName, ARRAY_SIZE(ofs->szPathName));
if (!(mode & OF_PARSE))
{
if (handle == INVALID_HANDLE_VALUE) goto error;
}
if (mode & OF_PARSE)
{
SYSTEMTIME systime;
GetSystemTime(&systime);
SystemTimeToFileTime(&systime, &filetime);
}
else
{
GetFileTime( handle, NULL, NULL, &filetime );
}
FileTimeToLocalFileTime(&filetime, &lfiletime);
FileTimeToDosDateTime( &lfiletime, &filedatetime[0], &filedatetime[1] );
if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
{
if (ofs->Reserved1 != filedatetime[0] || ofs->Reserved2 != filedatetime[1] )
{
CloseHandle( handle );
WARN("(%s): OF_VERIFY failed\n", name );
/* FIXME: what error here? */
SetLastError( ERROR_FILE_NOT_FOUND );
goto error;
}
}
ofs->Reserved1 = filedatetime[0];
ofs->Reserved2 = filedatetime[1];
}
if (!(mode & OF_PARSE))
{
hFileRet = Win32HandleToDosFileHandle(handle);
TRACE("(%s): OK, return = %p\n", name, handle);
}
if (hFileRet == HFILE_ERROR16) goto error;
HeapFree(GetProcessHeap(), 0, namew);
if (!(mode & OF_PARSE) && mode & OF_EXIST) _lclose16( hFileRet ); /* Return the handle, but close it first */
return hFileRet;
error: /* We get here if there was an error opening the file */
ofs->nErrCode = GetLastError();
WARN("(%s): return = HFILE_ERROR error= %d\n", name,ofs->nErrCode );
HeapFree(GetProcessHeap(), 0, namew);
return HFILE_ERROR16;
}
/***********************************************************************
* _lclose (KERNEL.81)
*/
HFILE16 WINAPI _lclose16( HFILE16 hFile )
{
HANDLE *dos_handles = FILE_GetTable();
if ((hFile >= DOS_TABLE_SIZE) || !dos_handles[hFile])
{
SetLastError( ERROR_INVALID_HANDLE );
return HFILE_ERROR16;
}
TRACE("%d (handle32=%p)\n", hFile, dos_handles[hFile] );
CloseHandle( dos_handles[hFile] );
dos_handles[hFile] = 0;
return 0;
}
/***********************************************************************
* _lcreat (KERNEL.83)
*/
HFILE16 WINAPI _lcreat16( LPCSTR path, INT16 attr )
{
CHAR buf[MAX_PATH];
path = RedirectSystemDir(path, buf, MAX_PATH);
path = RedirectDriveRoot(path, buf, MAX_PATH, FALSE);
return Win32HandleToDosFileHandle( (HANDLE)_lcreat( path, attr ) );
}
/***********************************************************************
* _llseek (KERNEL.84)
*/
LONG WINAPI _llseek16( HFILE16 hFile, LONG lOffset, INT16 nOrigin )
{
HANDLE fd = DosFileHandleToWin32Handle(hFile);
LONG high = 0;
DWORD offset = (DWORD)lOffset;
switch (nOrigin)
{
case FILE_BEGIN:
break;
case FILE_END:
offset += GetFileSize(fd, NULL);
break;
case FILE_CURRENT:
offset += SetFilePointer(fd, 0, NULL, FILE_CURRENT);
break;
default:
SetLastError(ERROR_INVALID_PARAMETER);
return -1;
}
return SetFilePointer(fd, offset, &high, FILE_BEGIN);
}
/***********************************************************************
* _lopen (KERNEL.85)
*/
HFILE16 WINAPI _lopen16( LPCSTR path, INT16 mode )
{
CHAR buf[MAX_PATH];
path = RedirectSystemDir(path, buf, MAX_PATH);
path = RedirectDriveRoot(path, buf, MAX_PATH, FALSE);
return Win32HandleToDosFileHandle( (HANDLE)_lopen( path, mode ) );
}
/***********************************************************************
* _lread16 (internal)
*/
UINT16 WINAPI _lread16( HFILE16 hFile, LPVOID buffer, UINT16 count )
{
return (UINT16)_lread((HFILE)DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
}
/***********************************************************************
* _lwrite (KERNEL.86)
*/
UINT16 WINAPI _lwrite16( HFILE16 hFile, LPCSTR buffer, UINT16 count )
{
return (UINT16)_hwrite( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
}
/***********************************************************************
* _hread (KERNEL.349)
*/
LONG WINAPI WIN16_hread( HFILE16 hFile, SEGPTR buffer, LONG count )
{
LONG maxlen;
TRACE("%d %08x %d\n", hFile, (DWORD)buffer, count );
/* Some programs pass a count larger than the allocated buffer */
maxlen = GetSelectorLimit16( SELECTOROF(buffer) ) - OFFSETOF(buffer) + 1;
if (count > maxlen)
{
LPVOID temp_buffer = HeapAlloc(GetProcessHeap(), 0, count);
HFILE result = _lread((HFILE)DosFileHandleToWin32Handle(hFile), temp_buffer, count );
if (result != HFILE_ERROR)
{
memcpy(MapSL(buffer), temp_buffer, (size_t)result);
}
HeapFree(GetProcessHeap(), 0, temp_buffer);
return result;
}
return _lread((HFILE)DosFileHandleToWin32Handle(hFile), MapSL(buffer), count );
}
/***********************************************************************
* _lread (KERNEL.82)
*/
UINT16 WINAPI WIN16_lread( HFILE16 hFile, SEGPTR buffer, UINT16 count )
{
return (UINT16)WIN16_hread( hFile, buffer, (LONG)count );
}
/***********************************************************************
* _hwrite (KERNEL.350)
*/
LONG WINAPI _hwrite16( HFILE16 hFile, LPCSTR buffer, LONG count )
{
return _hwrite( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, count );
}
/***********************************************************************
* GetTempDrive (KERNEL.92)
* A closer look at krnl386.exe shows what the SDK doesn't mention:
*
* returns:
* AL: driveletter
* AH: ':' - yes, some kernel code even does stosw with
* the returned AX.
* DX: 1 for success
*/
UINT WINAPI GetTempDrive( BYTE ignored )
{
WCHAR buffer[MAX_PATH];
BYTE ret;
if (GetTempPathW( MAX_PATH, buffer )) ret = (BYTE)toupperW(buffer[0]);
else ret = 'C';
return MAKELONG( ret | (':' << 8), 1 );
}
#define MAX_TEMP_PATH 144
/***********************************************************************
* GetTempFileName (KERNEL.97)
*/
UINT16 WINAPI GetTempFileName16( BYTE drive, LPCSTR prefix, UINT16 unique,
LPSTR buffer )
{
char temppath[MAX_TEMP_PATH];
char *unique_buf;
if (!(drive & ~TF_FORCEDRIVE)) /* drive 0 means current default drive */
{
WCHAR curdir[MAX_PATH];
DWORD r = GetCurrentDirectoryW(MAX_PATH, curdir);
if (r >= MAX_PATH || r == 0 || curdir[1] != ':')
{
ERR("could not get current drive\n");
return 0;
}
drive |= curdir[0];
}
if (drive & TF_FORCEDRIVE)
{
/* C:~preuuuu.TMP */
sprintf(temppath, "%c:", drive & ~TF_FORCEDRIVE);
}
else
{
DWORD r = GetTempPathA(MAX_TEMP_PATH, temppath);
if (r >= MAX_TEMP_PATH)
{
ERR("temp path is too long\n");
return 0;
}
if (r < 3)
{
return 0;
}
}
GetShortPathNameA(temppath, temppath, MAX_TEMP_PATH);
if (strlen(temppath) + 12 /* ~preuuuu.TMP */ >= MAX_TEMP_PATH - 1)
{
ERR("temp path is too long\n");
return 0;
}
unique_buf = temppath + strlen(temppath);
*unique_buf++ = '~';
if (prefix[0])
{
*unique_buf++ = prefix[0];
if (prefix[1])
{
*unique_buf++ = prefix[1];
if (prefix[2])
{
*unique_buf++ = prefix[2];
}
}
}
if (!unique)
{
int num = GetTickCount() & 0xffff;
if (num == 0)
{
num = 1;
}
unique = num;
do
{
HANDLE handle;
sprintf(unique_buf, "%04X.TMP", unique);
handle = CreateFileA(temppath, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
if (handle != INVALID_HANDLE_VALUE)
{
CloseHandle(handle);
break;
}
if (GetLastError() == ERROR_ACCESS_DENIED)
{
ERR("%s ERROR_ACCESS_DENIED\n", temppath);
}
if (GetLastError() != ERROR_FILE_EXISTS &&
GetLastError() != ERROR_SHARING_VIOLATION)
break;
if (!(++unique & 0xffff)) unique = 1;
} while (unique != num);
}
else
{
sprintf(unique_buf, "%04X.TMP", unique);
}
if (strlen(temppath) + 1 > MAX_TEMP_PATH)
{
ERR("temp path is too long\n");
return 0;
}
else
{
strcpy(buffer, temppath);
}
return unique;
}
typedef const char* (*ini_redirect_str_func)();
typedef int(*ini_redirect_int_func)();
struct ini_redirect_data
{
const char *file;
const char *section;
const char *entry;
const char *value;
ini_redirect_str_func get_str;
ini_redirect_int_func get_int;
BOOL overwrite_section;
};
int system_ini_keyboard_type()
{
return GetKeyboardType(0);
}
int system_ini_keyboard_subtype()
{
return GetKeyboardType(1);
}
static const char *system_ini_boot_language_dll()
{
switch (GetUserDefaultUILanguage())
{
case 1030:
case 1035:
case 1039:
case 1044:
case 1053:
return "langsca.dll";
case 1043:
return "langdut.dll";
case 2057:
case 3084:
case 1040:
case 2070:
case 3082:
return "langeng.dll";
case 1036:
return "langfrn.dll";
case 1031:
return "langger.dll";
case 1034:
return "langspa.dll";
case 1033:
default:
return "";
}
}
const char *system_init_boot_description_language_dll()
{
LANGID lang = GetUserDefaultUILanguage();
static char buf[256];
if (GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SNATIVELANGNAME, buf, ARRAY_SIZE(buf)))
{
return buf;
}
return "English (American)";
}
const char *system_init_boot_description_keyboard_typ()
{
char buf[KL_NAMELENGTH];
if (GetKeyboardLayoutNameA(buf))
{
HKEY hkey;
HKEY hkey2;
static char buf2[256];
DWORD cb = ARRAY_SIZE(buf2);
if (RegOpenKeyA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts\\", &hkey) == ERROR_SUCCESS)
{
if (RegOpenKeyA(hkey, buf, &hkey2) == ERROR_SUCCESS)
{
LRESULT result = RegQueryValueExA(hkey2, "Layout Text", NULL, NULL, buf2, &cb);
RegCloseKey(hkey2);
RegCloseKey(hkey);
if (result == ERROR_SUCCESS)
{
return buf2;
}
}
else
{
RegCloseKey(hkey);
}
}
}
return "Enhanced 101 or 102 key US and Non US keyboards";
}
int system_init_boot_description_codepage()
{
return GetACP();
}
/* HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\WOW */
/* HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows NT\CurrentVersion\IniFileMapping */
/* HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\IniFileMapping */
struct ini_redirect_data ini_redirect_list[] =
{
{"system.ini", "boot", "sound.drv", "sound.drv"},
{"system.ini", "boot", "comm.drv", "comm.drv"},
{"system.ini", "boot", "keyboard.drv", "keyboard.drv"},
{"system.ini", "boot", "system.drv", "system.drv"},
{"system.ini", "boot", "display.drv", "display.drv"},
{"system.ini", "boot", "shell", "progman.exe"},
{"system.ini", "boot", "mouse.drv", "mouse.drv"},
{"system.ini", "boot", "network.drv", "network.drv"},
{"system.ini", "boot", "language.dll", NULL, system_ini_boot_language_dll},
{"system.ini", "boot", "drivers", "mmsystem.dll"},
/* {"system.ini", "boot", "oemfonts.fon", "", NULL}, */
/* {"system.ini", "boot", "fixedfon.fon", "", NULL}, */
/* {"system.ini", "boot", "fonts.fon", "", NULL}, */
{"system.ini", "keyboard", "type", NULL, NULL, system_ini_keyboard_type},
{"system.ini", "keyboard", "subtype", NULL, NULL, system_ini_keyboard_subtype},
{"system.ini", "keyboard", "keyboard.dll", ""},
{"system.ini", "boot.description", "system.drv", "MS-DOS or PC-DOS System"},
/* {"system.ini", "boot.description", "aspect", "100,96,96"}, */
{"system.ini", "boot.description", "display.drv", "VGA"},
{"system.ini", "boot.description", "keyboard.typ", NULL, system_init_boot_description_keyboard_typ},
{"system.ini", "boot.description", "mouse.drv", "Microsoft, or IBM PS/2"},
{"system.ini", "boot.description", "network.drv", "LAN Support"},
{"system.ini", "boot.description", "language.dll", NULL, system_init_boot_description_language_dll},
{"system.ini", "boot.description", "codepage", NULL, NULL, system_init_boot_description_codepage},
/* {"system.ini", "boot.description", "woafont.fon", ""}, */
/* HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\MCI (Only available in 32-bit windows) */
{"system.ini", "mci", "AVIVideo", "mciavi.drv"},
{"system.ini", "mci", "Sequencer", "mciseq.drv"},
{"system.ini", "mci", "CDAudio", "mcicda.drv"},
{"system.ini", "mci", "WaveAudio", "mciwave.drv"},
/* MPEGVideo! */
{"system.ini", "mci", "MPEGVideo", "mciqtz.drv"},
/*
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\MCI Extensions
HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows NT\CurrentVersion\MCI Extensions
*/
#if 0
{"win.ini", "mci extensions", "aiff", "MPEGVideo"},
{"win.ini", "mci extensions", "dat", "MPEGVideo"},
{"win.ini", "mci extensions", "m2t", "MPEGVideo"},
{"win.ini", "mci extensions", "mpa", "MPEGVideo"},
{"win.ini", "mci extensions", "wmx", "MPEGVideo"},
{"win.ini", "mci extensions", "Mid", "MPEGVideo"},
{"win.ini", "mci extensions", "wmv", "MPEGVideo"},
{"win.ini", "mci extensions", "m3u", "MPEGVideo"},
{"win.ini", "mci extensions", "avi", "MPEGVideo"},
{"win.ini", "mci extensions", "ivf", "MPEGVideo"},
{"win.ini", "mci extensions", "wvx", "MPEGVideo"},
{"win.ini", "mci extensions", "m4v", "MPEGVideo"},
{"win.ini", "mci extensions", "mts", "MPEGVideo"},
{"win.ini", "mci extensions", "mp4v", "MPEGVideo"},
{"win.ini", "mci extensions", "mp2v", "MPEGVideo"},
{"win.ini", "mci extensions", "adts", "MPEGVideo"},
{"win.ini", "mci extensions", "wma", "MPEGVideo"},
{"win.ini", "mci extensions", "mpeg", "MPEGVideo"},
{"win.ini", "mci extensions", "tts", "MPEGVideo"},
{"win.ini", "mci extensions", "mpv2", "MPEGVideo"},
{"win.ini", "mci extensions", "au", "MPEGVideo"},
{"win.ini", "mci extensions", "3gpp", "MPEGVideo"},
{"win.ini", "mci extensions", "m4a", "MPEGVideo"},
{"win.ini", "mci extensions", "wax", "MPEGVideo"},
{"win.ini", "mci extensions", "aif", "MPEGVideo"},
{"win.ini", "mci extensions", "asx", "MPEGVideo"},
{"win.ini", "mci extensions", "Wav", "MPEGVideo"},
{"win.ini", "mci extensions", "m2ts", "MPEGVideo"},
{"win.ini", "mci extensions", "mov", "MPEGVideo"},
{"win.ini", "mci extensions", "wpl", "MPEGVideo"},
{"win.ini", "mci extensions", "aac", "MPEGVideo"},
{"win.ini", "mci extensions", "3gp2", "MPEGVideo"},
{"win.ini", "mci extensions", "mp4", "MPEGVideo"},
{"win.ini", "mci extensions", "mp3", "MPEGVideo"},
{"win.ini", "mci extensions", "mp2", "MPEGVideo"},
{"win.ini", "mci extensions", "wm", "MPEGVideo"},
{"win.ini", "mci extensions", "adt", "MPEGVideo"},
{"win.ini", "mci extensions", "cda", "MPEGVideo"},
{"win.ini", "mci extensions", "3g2", "MPEGVideo"},
{"win.ini", "mci extensions", "asf", "MPEGVideo"},
{"win.ini", "mci extensions", "mod", "MPEGVideo"},
{"win.ini", "mci extensions", "m1v", "MPEGVideo"},
{"win.ini", "mci extensions", "ts", "MPEGVideo"},
{"win.ini", "mci extensions", "rmi", "MPEGVideo"},
{"win.ini", "mci extensions", "mpg", "MPEGVideo"},
{"win.ini", "mci extensions", "3gp", "MPEGVideo"},
{"win.ini", "mci extensions", "aifc", "MPEGVideo"},
{"win.ini", "mci extensions", "mpe", "MPEGVideo"},
{"win.ini", "mci extensions", "m2v", "MPEGVideo"},
{"win.ini", "mci extensions", "snd", "MPEGVideo"},
#else
{"win.ini", "mci extensions", "Mid", "Sequencer"},
{"win.ini", "mci extensions", "Wav", "WaveAudio"},
{"win.ini", "mci extensions", "avi", "avivideo"},
{"win.ini", "mci extensions", "cda", "CDAudio"},
{"win.ini", "mci extensions", "rmi", "Sequencer"},
{"win.ini", "mci extensions", "wma", "MPEGVideo"},
{"win.ini", "mci extensions", "m4v", "MPEGVideo"},
{"win.ini", "mci extensions", "m4a", "MPEGVideo"},
{"win.ini", "mci extensions", "aac", "MPEGVideo"},
{"win.ini", "mci extensions", "mp4", "MPEGVideo"},
{"win.ini", "mci extensions", "mov", "MPEGVideo"},
{"win.ini", "mci extensions", "mp3", "MPEGVideo"},
{"win.ini", "mci extensions", "mpg", "MPEGVideo"},
{"win.ini", "mci extensions", "mp2", "MPEGVideo"},
{"win.ini", "mci extensions", "dat", "MPEGVideo"},
{"win.ini", "mci extensions", "m2t", "MPEGVideo"},
{"win.ini", "mci extensions", "mpa", "MPEGVideo"},
{"win.ini", "mci extensions", "wmx", "MPEGVideo"},
{"win.ini", "mci extensions", "wmv", "MPEGVideo"},
{"win.ini", "mci extensions", "m3u", "MPEGVideo"},
{"win.ini", "mci extensions", "ivf", "MPEGVideo"},
{"win.ini", "mci extensions", "mts", "MPEGVideo"},
{"win.ini", "mci extensions", "au", "MPEGVideo"},
{"win.ini", "mci extensions", "mpe", "MPEGVideo"},
{"win.ini", "mci extensions", "mod", "MPEGVideo"},
{"win.ini", "mci extensions", "aif", "MPEGVideo"},
/* When there are many extensions, MPLAYER causes buffer overflow. */
/*
{"win.ini", "mci extensions", "wax", "MPEGVideo"},
{"win.ini", "mci extensions", "asx", "MPEGVideo"},
{"win.ini", "mci extensions", "wpl", "MPEGVideo"},
{"win.ini", "mci extensions", "wm", "MPEGVideo"},
{"win.ini", "mci extensions", "adt", "MPEGVideo"},
{"win.ini", "mci extensions", "3g2", "MPEGVideo"},
{"win.ini", "mci extensions", "asf", "MPEGVideo"},
{"win.ini", "mci extensions", "m1v", "MPEGVideo"},
{"win.ini", "mci extensions", "tts", "MPEGVideo"},
{"win.ini", "mci extensions", "ts", "MPEGVideo"},
{"win.ini", "mci extensions", "wvx", "MPEGVideo"},
{"win.ini", "mci extensions", "3gp", "MPEGVideo"},
{"win.ini", "mci extensions", "m2v", "MPEGVideo"},
{"win.ini", "mci extensions", "snd", "MPEGVideo"},
{"win.ini", "mci extensions", "mpeg", "MPEGVideo"},
{"win.ini", "mci extensions", "mp4v", "MPEGVideo"},
{"win.ini", "mci extensions", "mp2v", "MPEGVideo"},
{"win.ini", "mci extensions", "adts", "MPEGVideo"},
{"win.ini", "mci extensions", "aifc", "MPEGVideo"},
{"win.ini", "mci extensions", "3gp2", "MPEGVideo"},
{"win.ini", "mci extensions", "m2ts", "MPEGVideo"},
{"win.ini", "mci extensions", "aiff", "MPEGVideo"},
{"win.ini", "mci extensions", "mpv2", "MPEGVideo"},
{"win.ini", "mci extensions", "3gpp", "MPEGVideo"},
*/
#endif
/* overwrite section */
{"win.ini", "mci extensions", NULL, NULL, NULL, NULL, TRUE},
};
/***********************************************************************
* GetPrivateProfileInt (KERNEL.127)
*/
UINT16 WINAPI GetPrivateProfileInt16( LPCSTR section, LPCSTR entry,
INT16 def_val, LPCSTR filename )
{
/* we used to have some elaborate return value limitation (<= -32768 etc.)
* here, but Win98SE doesn't care about this at all, so I deleted it.
* AFAIR versions prior to Win9x had these limits, though. */
char ini[MAX_PATH];
LPCSTR filename_file = PathFindFileNameA(filename);
for (int i = 0; i < ARRAY_SIZE(ini_redirect_list); i++)
{
if (!ini_redirect_list[i].entry)
{
continue;
}
if (!stricmp(ini_redirect_list[i].file, filename_file) && !stricmp(section, ini_redirect_list[i].section) && !stricmp(entry, ini_redirect_list[i].entry))
{
if (ini_redirect_list[i].get_int)
return ini_redirect_list[i].get_int();
}
}
RedirectPrivateProfileStringWindowsDir(filename,ini);
return (INT16)GetPrivateProfileIntA(section,entry,def_val,ini);
}
char windowsPath[MAX_PATH];
const char *GetRedirectWindowsDir()
{
if (*windowsPath != '\0')
return windowsPath;
#ifdef ENABLEREDIRECTSYSTEMDIR
GetModuleFileNameA(GetModuleHandleA(NULL), windowsPath, MAX_PATH);
PathRemoveFileSpecA(windowsPath);
char ini[MAX_PATH];
krnl386_get_config_string("otvdm", "WINDIR", "WINDOWS", ini, sizeof(ini));
PathCombineA(windowsPath, windowsPath, ini);
GetShortPathNameA(windowsPath, windowsPath, sizeof(windowsPath));
PathRemoveBackslashA(windowsPath);
if (strstr(windowsPath, "\\\\") || strstr(windowsPath, "/"))
{
ERR("WINDIR %s is not a correct path.\n", windowsPath);
}
return windowsPath;
#else
GetWindowsDirectoryA(windowsPath, sizeof(windowsPath));
GetShortPathNameA(windowsPath, windowsPath, sizeof(windowsPath));
return windowsPath;
#endif
}
static void RedirectPrivateProfileStringWindowsDir(LPCSTR filename, LPCSTR output)
{
if (!filename)
filename = "win.ini";
if (PathIsFileSpecA(filename) && !strchr(filename, '/'))
{
PathCombineA(output, GetRedirectWindowsDir(), filename);
}
else
{
strcpy(output, filename);
}
}
static BOOL append_ini_section(LPSTR data, SIZE_T *buf_pos, SIZE_T len, LPCSTR entry)
{
SIZE_T ent_len = strlen(entry) + 1;
memcpy(data + *buf_pos, entry, min(ent_len, len - *buf_pos - 2));
*buf_pos += min(ent_len, len - *buf_pos - 2);
data[*buf_pos] = '\0';
data[*buf_pos + 1] = '\0';
return TRUE;
}
static int construct_redirected_ini_section(LPCSTR section, LPSTR data, UINT16 size, LPCSTR filename)
{
LPCSTR filename_file = PathFindFileNameA(filename);
SIZE_T buf_pos = 0;
if (size == 0)
{
return 0;
}
if (size == 1)
{
data[0] = '\0';
return 0;
}
data[0] = '\0';
data[1] = '\0';
if (size == 2)
{
return 0;
}
for (int i = 0; i < ARRAY_SIZE(ini_redirect_list); i++)
{
if (!ini_redirect_list[i].entry)
{
continue;
}
if (!stricmp(ini_redirect_list[i].file, filename_file) && !stricmp(section, ini_redirect_list[i].section))
{
if (!append_ini_section(data, &buf_pos, size, ini_redirect_list[i].entry))
{
break;
}
}
}
return buf_pos;
}
/***********************************************************************
* GetPrivateProfileString (KERNEL.128)
*/
INT16 WINAPI GetPrivateProfileString16( LPCSTR section, LPCSTR entry,
LPCSTR def_val, LPSTR buffer,
UINT16 len, LPCSTR filename )
{
char filenamebuf[MAX_PATH];
BOOL overwrite_section = FALSE;
TRACE("%s %s %s\n", filename, section, entry);
if (!section || !filename)
{
if (buffer && len) buffer[0] = 0;
return 0;
}
LPCSTR filename_file = PathFindFileNameA(filename);
if (entry)
{
for (int i = 0; i < ARRAY_SIZE(ini_redirect_list); i++)
{
if (!ini_redirect_list[i].entry)
{
continue;
}
if (!stricmp(ini_redirect_list[i].file, filename_file) && !stricmp(section, ini_redirect_list[i].section) && !stricmp(entry, ini_redirect_list[i].entry))
{
LPCSTR val = ini_redirect_list[i].value;
SIZE_T size;
if (!val && ini_redirect_list[i].get_str)
{
val = ini_redirect_list[i].get_str();
}
if (!val)
{
break;
}
if (len == 0)
{
return 0;
}
else if (len == 1)
{
buffer[0] = '\0';
return 0;
}
size = min(strlen(val), len - 1);
memcpy(buffer, val, size);
buffer[size] = '\0';
return strlen(buffer);
}
}
}
else
{
for (int i = 0; i < ARRAY_SIZE(ini_redirect_list); i++)
{
if (ini_redirect_list[i].entry)
{
continue;
}
if (ini_redirect_list[i].overwrite_section && !stricmp(ini_redirect_list[i].file, filename_file) && !stricmp(section, ini_redirect_list[i].section))
{
overwrite_section = TRUE;
}
}
}
RedirectPrivateProfileStringWindowsDir(filename, filenamebuf);
filename = filenamebuf;
TRACE("(%s, %s, %s, %p, %u, %s)\n", debugstr_a(section), debugstr_a(entry),
debugstr_a(def_val), buffer, len, debugstr_a(filename));
/* len = 0 means unlimited buffer length (windows bug?) */
if (!entry && len == 0)
{
len = 0xffff;
}
if (!entry)
{
/* We have to return the list of keys in the section but without the values
* so we need to massage the results of GetPrivateProfileSectionA.
*/
UINT ret, oldlen = len, size = min( len, 1024 );
LPSTR data, src;
if (overwrite_section)
return construct_redirected_ini_section(section, buffer, oldlen, filename);
for (;;)
{
if (!(data = HeapAlloc(GetProcessHeap(), 0, size ))) return 0;
ret = GetPrivateProfileSectionA( section, data, size, filename );
if (!ret)
{
HeapFree( GetProcessHeap(), 0, data );
ret = construct_redirected_ini_section(section, buffer, oldlen, filename);
if (!ret)
ret = GetPrivateProfileStringA(section, entry, def_val, buffer, len, filename);
return ret;
}
if (ret != size - 2) break;
/* overflow, try again */
size *= 2;
HeapFree( GetProcessHeap(), 0, data );
}
src = data;
while (len && *src)
{
char *p = strchr( src, '=' );
/* A valid entry is formed by name = value */
if (!p)
{
src += strlen(src) + 1;
continue;
}
if (p - src < len)
{
memcpy( buffer, src, p - src );
buffer += p - src;
*buffer++ = 0;
len -= (p - src) + 1;
src += strlen(src) + 1;
}
else /* overflow */
{
memcpy( buffer, src, len );
buffer += len;
len = 0;
}
}
HeapFree( GetProcessHeap(), 0, data );
if (len)
{
*buffer = 0;
return oldlen - len;
}
if (oldlen > 2)
{
buffer[-2] = 0;
buffer[-1] = 0;
return oldlen - 2;
}
return 0;
}
return GetPrivateProfileStringA( section, entry, def_val, buffer, len, filename );
}
static BOOL16 check_write_profile_error(LPCSTR filename, DWORD error)
{
if (error == ERROR_ACCESS_DENIED)
{
OFSTRUCT ofstr;
HFILE ret = OpenFile(filename, &ofstr, OF_EXIST);
if (ret != HFILE_ERROR)
{
WARN("Failed to write profile data because it was redirected to the registry");
return TRUE; // fake success, any written data can't be read anyway
}
}
return FALSE;
}
/***********************************************************************
* WritePrivateProfileString (KERNEL.129)
*/
BOOL16 WINAPI WritePrivateProfileString16( LPCSTR section, LPCSTR entry,
LPCSTR string, LPCSTR filename )
{
char filenamebuf[MAX_PATH];
RedirectPrivateProfileStringWindowsDir(filename, &filenamebuf);
filename = filenamebuf;
BOOL ret = WritePrivateProfileStringA(section,entry,string,filename);
if (!ret)
return check_write_profile_error(filename, GetLastError());
return ret;
}
/***********************************************************************
* GetWindowsDirectory (KERNEL.134)
*/
UINT16 WINAPI GetWindowsDirectory16( LPSTR path, UINT16 count )
{
const char *w = GetRedirectWindowsDir();
UINT16 len = strlen(w);
if (len + 1 > count)
return strlen(w) + 1;
strcpy(path, w);
return len;
//return GetWindowsDirectoryA( path, count );
}
/***********************************************************************
* GetSystemDirectory (KERNEL.135)
*/
UINT16 WINAPI GetSystemDirectory16( LPSTR path, UINT16 count )
{
static const char system16[] = "\\SYSTEM";
char windir[MAX_PATH];
UINT16 len;
len = GetWindowsDirectory16(windir, sizeof(windir) - sizeof(system16) + 1) + sizeof(system16);
if (count >= len)
{
lstrcpyA(path, windir);
lstrcatA(path, system16);
len--; /* space for the terminating zero is not included on success */
}
return len;
}
/***********************************************************************
* GetDriveType (KERNEL.136)
* Get the type of a drive in Win16.
*
* RETURNS
* The type of the Drive. For a list see GetDriveTypeW from kernel32.
*
* NOTES
* Note that it returns DRIVE_REMOTE for CD-ROMs, since MSCDEX uses the
* remote drive API. The return value DRIVE_REMOTE for CD-ROMs has been
* verified on Win 3.11 and Windows 95. Some programs rely on it, so don't
* do any pseudo-clever changes.
*/
UINT16 WINAPI GetDriveType16( UINT16 drive ) /* [in] number (NOT letter) of drive */
{
UINT type;
WCHAR root[3];
root[0] = 'A' + drive;
root[1] = ':';
root[2] = 0;
type = GetDriveTypeW( root );
if (type == DRIVE_CDROM) type = DRIVE_REMOTE;
else if (type == DRIVE_NO_ROOT_DIR) type = DRIVE_UNKNOWN;
return type;
}
/***********************************************************************
* GetProfileSectionNames (KERNEL.142)
*/
WORD WINAPI GetProfileSectionNames16(LPSTR buffer, WORD size)
{
return GetPrivateProfileSectionNamesA(buffer,size,"win.ini");
}
/***********************************************************************
* GetPrivateProfileSectionNames (KERNEL.143)
*/
WORD WINAPI GetPrivateProfileSectionNames16( LPSTR buffer, WORD size,
LPCSTR filename )
{
return GetPrivateProfileSectionNamesA(buffer,size,filename);
}
/***********************************************************************
* CreateDirectory (KERNEL.144)
*/
BOOL16 WINAPI CreateDirectory16( LPCSTR path, LPVOID dummy )
{
return CreateDirectoryA( path, NULL );
}
/***********************************************************************
* RemoveDirectory (KERNEL.145)
*/
BOOL16 WINAPI RemoveDirectory16( LPCSTR path )
{
return RemoveDirectoryA( path );
}
/***********************************************************************
* DeleteFile (KERNEL.146)
*/
BOOL16 WINAPI DeleteFile16( LPCSTR path )
{
return DeleteFileA( path );
}
/***********************************************************************
* SetHandleCount (KERNEL.199)
*/
UINT16 WINAPI SetHandleCount16( UINT16 count )
{
return SetHandleCount( count );
}
/***********************************************************************
* GetShortPathName (KERNEL.274)
*/
WORD WINAPI GetShortPathName16( LPCSTR longpath, LPSTR shortpath, WORD len )
{
return GetShortPathNameA( longpath, shortpath, len );
}
/***********************************************************************
* WriteOutProfiles (KERNEL.315)
*/
void WINAPI WriteOutProfiles16(void)
{
WritePrivateProfileSectionW( NULL, NULL, NULL );
}
/***********************************************************************
* WritePrivateProfileStruct (KERNEL.406)
*/
BOOL16 WINAPI WritePrivateProfileStruct16 (LPCSTR section, LPCSTR key,
LPVOID buf, UINT16 bufsize, LPCSTR filename)
{
char filenamebuf[MAX_PATH];
RedirectPrivateProfileStringWindowsDir(filename, &filenamebuf);
filename = filenamebuf;
return WritePrivateProfileStructA( section, key, buf, bufsize, filename );
}
/***********************************************************************
* GetPrivateProfileStruct (KERNEL.407)
*/
BOOL16 WINAPI GetPrivateProfileStruct16(LPCSTR section, LPCSTR key,
LPVOID buf, UINT16 len, LPCSTR filename)
{
char filenamebuf[MAX_PATH];
RedirectPrivateProfileStringWindowsDir(filename, &filenamebuf);
filename = filenamebuf;
return GetPrivateProfileStructA( section, key, buf, len, filename );
}
/***********************************************************************
* GetCurrentDirectory (KERNEL.411)
*/
UINT16 WINAPI GetCurrentDirectory16( UINT16 buflen, LPSTR buf )
{
return GetCurrentDirectoryA( buflen, buf );
}
/***********************************************************************
* SetCurrentDirectory (KERNEL.412)
*/
BOOL16 WINAPI SetCurrentDirectory16( LPCSTR dir )
{
char fulldir[MAX_PATH];
if (!GetFullPathNameA( dir, MAX_PATH, fulldir, NULL )) return FALSE;
if (!SetCurrentDirectoryA( dir )) return FALSE;
if (fulldir[0] && fulldir[1] == ':')
{
TDB *pTask = GlobalLock16( GetCurrentTask() );
char env_var[4] = "=A:";
env_var[1] = fulldir[0];
SetEnvironmentVariableA( env_var, fulldir );
/* update the directory in the TDB */
if (pTask)
{
pTask->curdrive = 0x80 | (fulldir[0] - 'A');
GetShortPathNameA( fulldir + 2, pTask->curdir, sizeof(pTask->curdir) );
}
}
return TRUE;
}
/*************************************************************************
* FindFirstFile (KERNEL.413)
*/
HANDLE16 WINAPI FindFirstFile16( LPCSTR path, WIN32_FIND_DATAA *data )
{
HGLOBAL16 h16;
HANDLE handle, *ptr;
if (!(h16 = GlobalAlloc16( GMEM_MOVEABLE, sizeof(handle) ))) return INVALID_HANDLE_VALUE16;
ptr = GlobalLock16( h16 );
*ptr = handle = FindFirstFileA( path, data );
GlobalUnlock16( h16 );
if (handle == INVALID_HANDLE_VALUE)
{
GlobalFree16( h16 );
h16 = INVALID_HANDLE_VALUE16;
}
return h16;
}
/*************************************************************************
* FindNextFile (KERNEL.414)
*/
BOOL16 WINAPI FindNextFile16( HANDLE16 handle, WIN32_FIND_DATAA *data )
{
HANDLE *ptr;
BOOL ret = FALSE;
if ((handle == INVALID_HANDLE_VALUE16) || !(ptr = GlobalLock16( handle )))
{
SetLastError( ERROR_INVALID_HANDLE );
return ret;
}
ret = FindNextFileA( *ptr, data );
GlobalUnlock16( handle );
return ret;
}
/*************************************************************************
* FindClose (KERNEL.415)
*/
BOOL16 WINAPI FindClose16( HANDLE16 handle )
{
HANDLE *ptr;
if ((handle == INVALID_HANDLE_VALUE16) || !(ptr = GlobalLock16( handle )))
{
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
FindClose( *ptr );
GlobalUnlock16( handle );
GlobalFree16( handle );
return TRUE;
}
/***********************************************************************
* WritePrivateProfileSection (KERNEL.416)
*/
BOOL16 WINAPI WritePrivateProfileSection16( LPCSTR section,
LPCSTR string, LPCSTR filename )
{
return WritePrivateProfileSectionA( section, string, filename );
}
/***********************************************************************
* WriteProfileSection (KERNEL.417)
*/
BOOL16 WINAPI WriteProfileSection16( LPCSTR section, LPCSTR keys_n_values)
{
return WritePrivateProfileSection16( section, keys_n_values, "win.ini");
}
/***********************************************************************
* GetPrivateProfileSection (KERNEL.418)
*/
INT16 WINAPI GetPrivateProfileSection16( LPCSTR section, LPSTR buffer,
UINT16 len, LPCSTR filename )
{
return GetPrivateProfileSectionA( section, buffer, len, filename );
}
/***********************************************************************
* GetProfileSection (KERNEL.419)
*/
INT16 WINAPI GetProfileSection16( LPCSTR section, LPSTR buffer, UINT16 len )
{
return GetPrivateProfileSection16( section, buffer, len, "win.ini" );
}
/**************************************************************************
* GetFileAttributes (KERNEL.420)
*/
DWORD WINAPI GetFileAttributes16( LPCSTR name )
{
return GetFileAttributesA( name );
}
/**************************************************************************
* SetFileAttributes (KERNEL.421)
*/
BOOL16 WINAPI SetFileAttributes16( LPCSTR lpFileName, DWORD attributes )
{
return SetFileAttributesA( lpFileName, attributes );
}
/***********************************************************************
* GetDiskFreeSpace (KERNEL.422)
*/
BOOL16 WINAPI GetDiskFreeSpace16( LPCSTR root, LPDWORD cluster_sectors,
LPDWORD sector_bytes, LPDWORD free_clusters,
LPDWORD total_clusters )
{
return GetDiskFreeSpaceA( root, cluster_sectors, sector_bytes,
free_clusters, total_clusters );
}
/***********************************************************************
* FileCDR (KERNEL.130)
*/
FARPROC16 WINAPI FileCDR16(FARPROC16 x)
{
FIXME("(%p): stub\n", x);
return (FARPROC16)TRUE;
}
================================================
FILE: krnl386/fpu.c
================================================
/*
* DOS interrupt 34->3e handlers. All FPU interrupt code should be
* moved into this file.
*
* Copyright 2002 Robert 'Admiral' Coeyman
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include
#include "dosexe.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(int);
/*
* The actual work is done by a single routine.
*/
static void FPU_ModifyCode(CONTEXT *context, BYTE Opcode);
/**********************************************************************
* DOSVM_Int34Handler
*
* Handler for int 34 (FLOATING POINT EMULATION - Opcode 0xd8).
*
* The interrupt list isn't specific about what this interrupt
* actually does. [ interrup.m ]
*/
void WINAPI DOSVM_Int34Handler(CONTEXT *context)
{
TRACE("Int 0x34 called-- FP opcode 0xd8\n");
FPU_ModifyCode(context, 0xd8);
}
/**********************************************************************
* DOSVM_Int35Handler
*
* Handler for int 35 (FLOATING POINT EMULATION - Opcode 0xd9).
*
* The interrupt list isn't specific about what this interrupt
* actually does. [ interrup.m ]
*/
void WINAPI DOSVM_Int35Handler(CONTEXT *context)
{
TRACE("Int 0x35 called-- FP opcode 0xd9\n");
FPU_ModifyCode(context, 0xd9);
}
/**********************************************************************
* DOSVM_Int36Handler
*
* Handler for int 36 (FLOATING POINT EMULATION - Opcode 0xda).
*
* The interrupt list isn't specific about what this interrupt
* actually does. [ interrup.m ]
*/
void WINAPI DOSVM_Int36Handler(CONTEXT *context)
{
TRACE("Int 0x36 called-- FP opcode 0xda\n");
FPU_ModifyCode(context, 0xda);
}
/**********************************************************************
* DOSVM_Int37Handler
*
* Handler for int 37 (FLOATING POINT EMULATION - Opcode 0xdb).
*
* The interrupt list isn't specific about what this interrupt
* actually does. [ interrup.m ]
*/
void WINAPI DOSVM_Int37Handler(CONTEXT *context)
{
TRACE("Int 0x37 called-- FP opcode 0xdb\n");
FPU_ModifyCode(context, 0xdb);
}
/**********************************************************************
* DOSVM_Int38Handler
*
* Handler for int 38 (FLOATING POINT EMULATION - Opcode 0xdc).
*
* Between versions 3.0 and 5.01, the original PC-MOS API call that
* was here was moved to int 0xd4.
*
* The interrupt list isn't specific about what this interrupt
* actually does. [ interrup.m ]
*/
void WINAPI DOSVM_Int38Handler(CONTEXT *context)
{
TRACE("Int 0x38 called-- FP opcode 0xdc\n");
FPU_ModifyCode(context, 0xdc);
}
/**********************************************************************
* DOSVM_Int39Handler
*
* Handler for int 39 (FLOATING POINT EMULATION - Opcode 0xdd).
*
* The interrupt list isn't specific about what this interrupt
* actually does. [ interrup.m ]
*/
void WINAPI DOSVM_Int39Handler(CONTEXT *context)
{
TRACE("Int 0x39 called-- FP opcode 0xdd\n");
FPU_ModifyCode(context, 0xdd);
}
/**********************************************************************
* DOSVM_Int3aHandler
*
* Handler for int 3a (FLOATING POINT EMULATION - Opcode 0xde).
*
* The interrupt list isn't specific about what this interrupt
* actually does. [ interrup.m ]
*/
void WINAPI DOSVM_Int3aHandler(CONTEXT *context)
{
TRACE("Int 0x3a called-- FP opcode 0xde\n");
FPU_ModifyCode(context, 0xde);
}
/**********************************************************************
* DOSVM_Int3bHandler
*
* Handler for int 3B (FLOATING POINT EMULATION - Opcode 0xdf).
*
* The interrupt list isn't specific about what this interrupt
* actually does. [ interrup.m ]
*/
void WINAPI DOSVM_Int3bHandler(CONTEXT *context)
{
TRACE("Int 0x3b called-- FP opcode 0xdf\n");
FPU_ModifyCode(context, 0xdf);
}
/**********************************************************************
* DOSVM_Int3cHandler
*
* Handler for int 3C (FLOATING POINT EMULATION - INSTRUCTIONS WITH SEGMENT OVERRIDE).
*
* Generated code is CD 3C xy mm ... (CD = int | 3C = this interrupt)
* xy is a modified ESC code and mm is the modR/M byte.
* xy byte seems to be encoded as ss011xxx or ss000xxx
* ss= segment override.
* 00 -> DS
* 01 -> SS
* 10 -> CS
* 11 -> ES
*
* 11011xxx should be the opcode instruction.
*/
void WINAPI DOSVM_Int3cHandler(CONTEXT *context)
{
FIXME("Int 3C NOT Implemented\n");
INT_BARF(context, 0x3c);
}
/**********************************************************************
* DOSVM_Int3dHandler
*
* Handler for int 3D (FLOATING POINT EMULATION - Standalone FWAIT).
*
* Opcode 0x90 is a NOP. It just fills space where the 3D was.
*/
void WINAPI DOSVM_Int3dHandler(CONTEXT *context)
{
TRACE("Int 0x3d called-- Standalone FWAIT\n");
FPU_ModifyCode(context, 0x90);
}
/**********************************************************************
* DOSVM_Int3eHandler
*
* FLOATING POINT EMULATION -- Borland "Shortcut" call.
* The two bytes following the int 3E instruction are
* the subcode and a NOP ( 0x90 ), except for subcodes DC and DE
* where the second byte is the register count.
*
* Direct access 4.0 modifies and does not restore this vector.
*
*/
void WINAPI DOSVM_Int3eHandler(CONTEXT *context)
{
FIXME("Int 3E NOT Implemented\n");
INT_BARF(context, 0x3e);
}
/**********************************************************************
* FPU_ModifyCode
*
* This is the function that inserts the 0x9b fwait instruction
* and the actual FPU opcode into the program.
* -A.C.
*
* Code thanks to Ove Kaaven
*/
static void FPU_ModifyCode(CONTEXT *context, BYTE Opcode)
{
BYTE *code = CTX_SEG_OFF_TO_LIN(context, context->SegCs, context->Eip);
/*
* All *NIX systems should have a real or kernel emulated FPU.
*/
code[-2] = 0x9b; /* The fwait instruction */
code[-1] = Opcode; /* Insert the opcode */
if ( ISV86(context) && LOWORD(context->Eip) < 2 )
FIXME("Backed up over a real mode segment boundary in FPU code.\n");
context->Eip -= 2; /* back up the return address 2 bytes */
TRACE("Modified code in FPU int call to 0x9b 0x%x\n",Opcode);
}
================================================
FILE: krnl386/global.c
================================================
/*
* Global heap functions
*
* Copyright 1995 Alexandre Julliard
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
/* 0xffff sometimes seems to mean: CURRENT_DS */
#include "config.h"
#include "wine/port.h"
#include
#include
#include
#include
#ifdef HAVE_UNISTD_H
# include
#endif
#include
#ifdef HAVE_SYS_PARAM_H
#include
#endif
#ifdef HAVE_SYS_SYSCTL_H
#include
#endif
#include "wine/winbase16.h"
#include "winternl.h"
#include "kernel16_private.h"
#include "wine/debug.h"
#include "winuser.h"
#include "wingdi.h"
WINE_DEFAULT_DEBUG_CHANNEL(global);
/* Global arena block */
typedef struct
{
void *base; /* Base address (0 if discarded) */
DWORD size; /* Size in bytes (0 indicates a free block) */
HGLOBAL16 handle; /* Handle for this block */
HGLOBAL16 hOwner; /* Owner of this block */
BYTE lockCount; /* Count of GlobalFix() calls */
BYTE pageLockCount; /* Count of GlobalPageLock() calls */
BYTE flags; /* Allocation flags */
BYTE selCount; /* Number of selectors allocated for this block */
DWORD dib_avail_size;
WORD wSeg;
WORD wType;
HGLOBAL link_hndl;
BYTE pad[0x10 - 4 - 2 - 2 - 4]; /* win31 GLOBALARENA size = 0x20 */
} GLOBALARENA;
/* Flags definitions */
#define GA_MOVEABLE 0x02 /* same as GMEM_MOVEABLE */
#define GA_DGROUP 0x04
#define GA_DISCARDABLE 0x08
#define GA_IPCSHARE 0x10 /* same as GMEM_DDESHARE */
#define GA_DOSMEM 0x20
/* Arena array (FIXME) */
static GLOBALARENA *pGlobalArena;
static int globalArenaSize;
static DWORD *selTable;
#define GLOBAL_MAX_ALLOC_SIZE 0x00ff0000 /* Largest allocation is 16M - 64K */
#define GLOBAL_MAX_COUNT 8192 /* Max number of allocated blocks */
#define VALID_HANDLE(handle) (((handle)&4)&&(((handle)>>__AHSHIFT)> __AHSHIFT))
static HANDLE get_win16_heap(void)
{
static HANDLE win16_heap;
/* we create global memory block with execute permission. The access can be limited
* for 16-bit code on selector level */
if (!win16_heap) win16_heap = HeapCreate(HEAP_CREATE_ENABLE_EXECUTE, 0, 0);
return win16_heap;
}
static void clear_sel_table(WORD sel, WORD selcount)
{
for (int i = 0; i < selcount; i++)
{
selTable[(sel + i) >> __AHSHIFT] = 0;
}
}
static void set_sel_table(WORD sel, WORD selcount)
{
for (int i = 0; i < selcount; i++)
{
selTable[(sel + i) >> __AHSHIFT] = (sel >> __AHSHIFT) * sizeof(GLOBALARENA);
}
}
/***********************************************************************
* GLOBAL_GetArena
*
* Return the arena for a given selector, growing the arena array if needed.
*/
static GLOBALARENA *GLOBAL_GetArena( WORD sel, WORD selcount )
{
if (((sel >> __AHSHIFT) + selcount) > globalArenaSize)
{
int newsize = ((sel >> __AHSHIFT) + selcount + 0xff) & ~0xff;
if (!pGlobalArena)
{
SIZE_T size;
pThhook->SelTableLen = GLOBAL_MAX_COUNT * sizeof(DWORD);
size = GLOBAL_MAX_COUNT * sizeof(GLOBALARENA) + 0x80 /* unknown */ + pThhook->SelTableLen;
pGlobalArena = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size);
if (!pGlobalArena) return 0;
WORD sel = SELECTOR_AllocBlock(pGlobalArena, 0x10000, WINE_LDT_FLAGS_DATA);
SetSelectorLimit16(sel, size - 1);
pThhook->hGlobalHeap = sel;
pThhook->pGlobalHeap = sel;
pThhook->SelTableStart = GLOBAL_MAX_COUNT * sizeof(GLOBALARENA) + 0x80; /* 0x00040080; */
selTable = (DWORD*)((BYTE*)(pGlobalArena) + pThhook->SelTableStart);
set_sel_table(sel, 1);
}
if (newsize > GLOBAL_MAX_COUNT) return 0;
globalArenaSize = newsize;
}
return pGlobalArena + (sel >> __AHSHIFT);
}
void debug_handles(void)
{
int printed=0;
int i;
for (i = globalArenaSize-1 ; i>=0 ; i--) {
if (pGlobalArena[i].size!=0 && (pGlobalArena[i].handle & 0x8000)){
printed=1;
DPRINTF("0x%08x, ",pGlobalArena[i].handle);
}
}
if (printed)
DPRINTF("\n");
}
/***********************************************************************
* GLOBAL_CreateBlock
*
* Create a global heap block for a fixed range of linear memory.
*/
HGLOBAL16 GLOBAL_CreateBlock( WORD flags, void *ptr, DWORD size,
HGLOBAL16 hOwner, unsigned char selflags, WORD sel )
{
WORD selcount;
GLOBALARENA *pArena;
/* Allocate the selector(s) */
if (sel)
{
if (size > 65536)
{
ERR("prealloced sel must not be larger than 65536");
return 0;
}
WORD descflags = selflags & 0x40 ? (selflags & ~0x40) | 0x4000 : selflags;
SELECTOR_ReallocBlock(sel, ptr, size);
SelectorAccessRights16(sel, 1, descflags);
}
else
sel = SELECTOR_AllocBlock( ptr, size, selflags );
if (!sel) return 0;
selcount = (size + 0xffff) / 0x10000;
if (!(pArena = GLOBAL_GetArena( sel, selcount )))
{
SELECTOR_FreeBlock( sel );
return 0;
}
/* Fill the arena block */
pArena->base = ptr;
pArena->size = size == 1 && ptr == NULL ? 0 : GetSelectorLimit16(sel) + 1;
pArena->handle = (flags & GMEM_MOVEABLE) ? sel - 1 : sel;
pArena->hOwner = hOwner;
pArena->lockCount = 0;
pArena->pageLockCount = 0;
pArena->wSeg = 0;
pArena->wType = GT_UNKNOWN;
pArena->flags = flags & GA_MOVEABLE;
pArena->link_hndl = NULL;
if (flags & GMEM_DISCARDABLE) pArena->flags |= GA_DISCARDABLE;
if (flags & GMEM_DDESHARE) pArena->flags |= GA_IPCSHARE;
if (!(selflags & (WINE_LDT_FLAGS_CODE^WINE_LDT_FLAGS_DATA))) pArena->flags |= GA_DGROUP;
pArena->selCount = selcount;
if (selcount > 1) /* clear the next arena blocks */
memset( pArena + 1, 0, (selcount - 1) * sizeof(GLOBALARENA) );
set_sel_table(sel, selcount);
return pArena->handle;
}
/***********************************************************************
* GLOBAL_FreeBlock
*
* Free a block allocated by GLOBAL_CreateBlock, without touching
* the associated linear memory range.
*/
BOOL16 GLOBAL_FreeBlock( HGLOBAL16 handle )
{
WORD sel;
GLOBALARENA *pArena;
if (!handle) return TRUE;
sel = GlobalHandleToSel16( handle );
if (!VALID_HANDLE(sel)) return FALSE;
pArena = GET_ARENA_PTR(sel);
SELECTOR_FreeBlock( sel );
clear_sel_table(sel, pArena->selCount);
memset( pArena, 0, sizeof(GLOBALARENA) );
return TRUE;
}
/***********************************************************************
* GLOBAL_MoveBlock
*/
BOOL16 GLOBAL_MoveBlock( HGLOBAL16 handle, void *ptr, DWORD size )
{
WORD sel;
GLOBALARENA *pArena;
if (!handle) return TRUE;
sel = GlobalHandleToSel16( handle );
if (!VALID_HANDLE(sel)) return FALSE;
pArena = GET_ARENA_PTR(sel);
if (pArena->selCount != 1)
return FALSE;
pArena->base = ptr;
pArena->size = size;
SELECTOR_ReallocBlock( sel, ptr, size );
return TRUE;
}
/***********************************************************************
* GLOBAL_Alloc
*
* Implementation of GlobalAlloc16()
*/
HGLOBAL16 GLOBAL_Alloc( UINT16 flags, DWORD size, HGLOBAL16 hOwner, unsigned char selflags, WORD sel )
{
void *ptr;
HGLOBAL16 handle;
TRACE("%d flags=%04x\n", size, flags );
/* If size is 0, create a discarded block */
if (size == 0) return GLOBAL_CreateBlock( flags, NULL, 1, hOwner, selflags, sel );
/* Fixup the size */
DWORD fixup_size = (size < 0x10000) ? 0x1f : 0xfff; // selectors larger than 64k need page granularity
if (size > GLOBAL_MAX_ALLOC_SIZE) return 0;
size = (size + fixup_size) & ~fixup_size;
/* Allocate the linear memory */
ptr = HeapAlloc( get_win16_heap(), 0, size);
/* FIXME: free discardable blocks and try again? */
if (!ptr) return 0;
/* Allocate the selector(s) */
handle = GLOBAL_CreateBlock( flags, ptr, size, hOwner, selflags, sel );
if (!handle)
{
HeapFree( get_win16_heap(), 0, ptr );
return 0;
}
if (flags & GMEM_ZEROINIT) memset( ptr, 0, size );
else if (size > 100) // some programs depend on the block not being cleared also work around bug in procyan2
{
for (int i = 1; i < 22; i++)
((char *)ptr)[size - i] = 0xff;
}
else ((char *)ptr)[size - 1] = 0xff;
return handle;
}
WORD GLOBAL_GetSegNum(HGLOBAL16 hg)
{
return GET_ARENA_PTR(hg)->wSeg;
}
void GLOBAL_SetSeg(HGLOBAL16 hg, WORD wSeg, WORD type)
{
GET_ARENA_PTR(hg)->wSeg = wSeg;
GET_ARENA_PTR(hg)->wType = type;
}
HGLOBAL GLOBAL_GetLink(HGLOBAL16 hg)
{
return GET_ARENA_PTR(hg)->link_hndl;
}
void GLOBAL_SetLink(HGLOBAL16 hg16, HGLOBAL hg)
{
GET_ARENA_PTR(hg16)->link_hndl = hg;
}
HGLOBAL16 GLOBAL_FindLink(HGLOBAL hg)
{
int i;
GLOBALARENA *pArena = pGlobalArena;
for (i = 0; i < globalArenaSize; i++, pArena++)
{
if ((pArena->size != 0) && (pArena->link_hndl == hg))
return pArena->handle;
}
return 0;
}
/***********************************************************************
* GlobalAlloc (KERNEL.15)
* GlobalAlloc16 (KERNEL32.24)
*
* Allocate a global memory object.
*
* RETURNS
* Handle: Success
* NULL: Failure
*/
HGLOBAL16 WINAPI GlobalAlloc16(
UINT16 flags, /* [in] Object allocation attributes */
DWORD size /* [in] Number of bytes to allocate */
) {
HANDLE16 owner = GetCurrentPDB16();
if (flags & GMEM_DDESHARE)
{
/* make it owned by the calling module */
STACK16FRAME *frame = CURRENT_STACK16;
owner = GetExePtr( frame->cs );
}
HGLOBAL16 handle = GLOBAL_Alloc( flags, size, owner, WINE_LDT_FLAGS_DATA, 0 );
if (!handle)
{
ERR("Could not allocate %04X,%08X\n", flags, size);
}
return handle;
}
/***********************************************************************
* GlobalReAlloc (KERNEL.16)
*
* Change the size or attributes of a global memory object.
*
* RETURNS
* Handle: Success
* NULL: Failure
*/
HGLOBAL16 WINAPI GlobalReAlloc16(
HGLOBAL16 handle, /* [in] Handle of global memory object */
DWORD size, /* [in] New size of block */
UINT16 flags /* [in] How to reallocate object */
) {
WORD selcount;
DWORD oldsize;
void *ptr, *newptr;
GLOBALARENA *pArena, *pNewArena;
WORD sel = GlobalHandleToSel16( handle );
HANDLE heap = get_win16_heap();
TRACE("%04x %d flags=%04x\n",
handle, size, flags );
if (!handle) return 0;
if (!VALID_HANDLE(handle))
{
WARN("Invalid handle 0x%04x!\n", handle);
return 0;
}
pArena = GET_ARENA_PTR( handle );
if (pArena->wType == GT_INTERNAL)
return 0;
/* Discard the block if requested */
if ((size == 0) && (flags & GMEM_MOVEABLE) && !(flags & GMEM_MODIFY))
{
if (!(pArena->flags & GA_MOVEABLE) ||
!(pArena->flags & GA_DISCARDABLE) ||
(pArena->lockCount > 0) || (pArena->pageLockCount > 0)) return 0;
if (pArena->dib_avail_size)
{
FIXME("DIB.DRV\n");
}
else if (pArena->flags & GA_DOSMEM)
DOSMEM_FreeBlock( pArena->base );
else
HeapFree( heap, 0, pArena->base );
pArena->base = 0;
/* Note: we rely on the fact that SELECTOR_ReallocBlock won't
* change the selector if we are shrinking the block.
* FIXME: shouldn't we keep selectors until the block is deleted?
*/
SELECTOR_ReallocBlock( sel, 0, 1 );
return handle;
}
/* Change the flags */
if (flags & GMEM_MODIFY)
{
/* Change the flags, leaving GA_DGROUP alone */
pArena->flags = (pArena->flags & GA_DGROUP) | (flags & GA_MOVEABLE);
if (flags & GMEM_DISCARDABLE) pArena->flags |= GA_DISCARDABLE;
return handle;
}
/* Fixup the size */
DWORD fixup_size = 0x1f;
BOOL old = IsOldWindowsTask(GetCurrentTask());
DWORD add_size = old ? 0x100 : 0;
if (size + add_size > 0x10000)
add_size = 0;
if (size > GLOBAL_MAX_ALLOC_SIZE - (fixup_size + 1)) return 0;
if (size == 0) size = fixup_size + 1;
else size = (size + fixup_size) & ~fixup_size;
/* Reallocate the linear memory */
ptr = pArena->base;
oldsize = pArena->size;
TRACE("oldbase %p oldsize %08x newsize %08x\n", ptr,oldsize,size);
if (ptr && (size == oldsize)) return handle; /* Nothing to do */
if (pArena->dib_avail_size)
{
if (size > pArena->dib_avail_size)
{
ERR("could not realloc dib memory\n");
return 0;
}
pArena->size = size;
SetSelectorLimit16(sel, size - 1);
return handle;
}
if (pArena->flags & GA_DOSMEM)
{
if (DOSMEM_ResizeBlock(ptr, size, TRUE) == size)
newptr = ptr;
else if(pArena->pageLockCount > 0)
newptr = 0;
else
{
newptr = DOSMEM_AllocBlock( size, NULL );
if (newptr)
{
memcpy( newptr, ptr, oldsize );
DOSMEM_FreeBlock( ptr );
}
}
}
else
{
/*
* if more than one reader (e.g. some pointer has been
* given out by GetVDMPointer32W16),
* only try to realloc in place
*/
if (ptr)
newptr = HeapReAlloc( heap,
(pArena->pageLockCount > 0) ? HEAP_REALLOC_IN_PLACE_ONLY : 0,
ptr, size + add_size );
else
newptr = HeapAlloc( heap, 0, size + add_size );
}
if (!newptr)
{
FIXME("Realloc failed lock %d\n",pArena->pageLockCount);
if (pArena->pageLockCount <1)
{
if (pArena->flags & GA_DOSMEM)
DOSMEM_FreeBlock( pArena->base );
else
HeapFree( heap, 0, ptr );
SELECTOR_FreeBlock( sel );
memset( pArena, 0, sizeof(GLOBALARENA) );
}
return 0;
}
ptr = newptr;
/* Reallocate the selector(s) */
sel = SELECTOR_ReallocBlock( sel, ptr, size + add_size);
if (!sel)
{
if (pArena->flags & GA_DOSMEM)
DOSMEM_FreeBlock( pArena->base );
else
HeapFree( heap, 0, ptr );
memset( pArena, 0, sizeof(GLOBALARENA) );
return 0;
}
selcount = (size + 0xffff) / 0x10000;
if (!(pNewArena = GLOBAL_GetArena( sel, selcount )))
{
if (pArena->flags & GA_DOSMEM)
DOSMEM_FreeBlock( pArena->base );
else
HeapFree( heap, 0, ptr );
SELECTOR_FreeBlock( sel );
return 0;
}
/* Fill the new arena block
As we may have used HEAP_REALLOC_IN_PLACE_ONLY, areas may overlap*/
if (pNewArena != pArena)
{
clear_sel_table( handle, pArena->selCount );
memmove( pNewArena, pArena, sizeof(GLOBALARENA) );
memset( pArena, 0, sizeof(GLOBALARENA) );
set_sel_table( pNewArena->handle, selcount );
}
pNewArena->base = ptr;
pNewArena->size = GetSelectorLimit16(sel) + 1 - add_size;
pNewArena->selCount = selcount;
pNewArena->handle = (pNewArena->flags & GA_MOVEABLE) ? sel - 1 : sel;
if (selcount > 1) /* clear the next arena blocks */
memset( pNewArena + 1, 0, (selcount - 1) * sizeof(GLOBALARENA) );
if ((oldsize < size) && (flags & GMEM_ZEROINIT))
memset( (char *)ptr + oldsize, 0, size - oldsize );
return !(pNewArena->handle ^ handle & ~1) ? handle : pNewArena->handle;
}
static void check_gptr(HANDLE src)
{
BOOL valid = FALSE;
if ((DWORD)src & 4)
{
if (GlobalFlags(src) != GMEM_INVALID_HANDLE)
valid = TRUE;
}
else
{
if (HeapValidate(GetProcessHeap(), 0, src))
valid = TRUE;
}
if (valid)
GlobalFree(src);
}
/***********************************************************************
* GlobalFree (KERNEL.17)
* GlobalFree16 (KERNEL32.31)
* RETURNS
* NULL: Success
* Handle: Failure
*/
HGLOBAL16 WINAPI GlobalFree16(
HGLOBAL16 handle /* [in] Handle of global memory object */
) {
void *ptr;
if (!VALID_HANDLE(handle))
{
WARN("Invalid handle 0x%04x passed to GlobalFree16!\n",handle);
return 0;
}
GLOBALARENA *pArena = GET_ARENA_PTR(handle);
ptr = pArena->base;
if (pArena->wType == GT_INTERNAL)
return 0;
TRACE("%04x\n", handle );
if (pArena->dib_avail_size)
{
FIXME("DIB.DRV\n");
return 0;
}
HGLOBAL ddehndl = GLOBAL_GetLink(handle);
if (!GLOBAL_FreeBlock( handle )) return handle; /* failed */
HeapFree( get_win16_heap(), 0, ptr );
if (ddehndl) check_gptr(ddehndl);
return 0;
}
/**********************************************************************
* K32WOWGlobalLock16 (KERNEL32.60)
*/
SEGPTR WINAPI K32WOWGlobalLock16( HGLOBAL16 handle )
{
WORD sel = GlobalHandleToSel16( handle );
TRACE("(%04x) -> %08x\n", handle, MAKELONG( 0, sel ) );
if (handle)
{
if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
if (!VALID_HANDLE(handle)) {
WARN("Invalid handle 0x%04x passed to WIN16_GlobalLock16!\n",handle);
sel = 0;
}
else if (!GET_ARENA_PTR(handle)->base)
sel = 0;
else if ((GET_ARENA_PTR(handle)->flags & GA_DISCARDABLE) || IsOldWindowsTask(GetCurrentTask()))
GET_ARENA_PTR(handle)->lockCount++;
}
return MAKESEGPTR( sel, 0 );
}
/*
WOW32
GLOBALALLOC
gs=0000,fs=0000,es=16e7,ds=16e7,edi=00000000,esi=00000000,ebx=00000000,edx=00000000,ecx=00000000,eax=00000000
gs=0000,fs=0000,es=0000,ds=16e7,edi=00000000,esi=00000000,ebx=000016ce,edx=00040002,ecx=000016ce,eax=000016ce
GLOBALLOCK
gs=0000,fs=0000,es=16e7,ds=16e7,edi=00000000,esi=00000000,ebx=00000000,edx=00000000,ecx=00000000,eax=00000000
gs=0000,fs=0000,es=0000,ds=16e7,edi=00000000,esi=00000000,ebx=00000000,edx=000016cf,ecx=000016cf,eax=00000000
GLOBALUNLOCK
gs=0000,fs=0000,es=16e7,ds=16e7,edi=00000000,esi=00000000,ebx=00000000,edx=00000000,ecx=00000000,eax=00000000
gs=0000,fs=0000,es=0000,ds=16e7,edi=00000000,esi=00000000,ebx=00000000,edx=000016ce,ecx=00000000,eax=00000000
GLOBALREALLOC
gs=0000,fs=0000,es=16e7,ds=16e7,edi=00000000,esi=00000000,ebx=00000000,edx=00000000,ecx=00000000,eax=00000000
gs=0000,fs=0000,es=0000,ds=16e7,edi=00000000,esi=00000000,ebx=000002a0,edx=00000000,ecx=000016ce,eax=000016ce
GLOBALSIZE
gs=0000,fs=0000,es=16e7,ds=16e7,edi=00000000,esi=00000000,ebx=00000000,edx=00000000,ecx=00000000,eax=00000000
gs=0000,fs=0000,es=0000,ds=16e7,edi=00000000,esi=00000000,ebx=0000267e,edx=00000000,ecx=00000200,eax=00002000
GLOBALHANDLE
gs=0000,fs=0000,es=16e7,ds=16e7,edi=00000000,esi=00000000,ebx=00000000,edx=00000000,ecx=00000000,eax=00000000
gs=0000,fs=0000,es=16e7,ds=16e7,edi=00000000,esi=00000000,ebx=00002676,edx=000016cf,ecx=00000000,eax=000016ce
GLOBALFLAGS
gs=0000,fs=0000,es=16e7,ds=16e7,edi=00000000,esi=00000000,ebx=00000000,edx=00000000,ecx=00000000,eax=00000000
gs=0000,fs=0000,es=0000,ds=16e7,edi=00000000,esi=00000000,ebx=0000267e,edx=000016cf,ecx=00000000,eax=00000000
GLOBALFREE
gs=0000,fs=0000,es=16e7,ds=16e7,edi=00000000,esi=00000000,ebx=00000000,edx=00000000,ecx=00000000,eax=00000000
gs=0000,fs=0000,es=0000,ds=16e7,edi=00000000,esi=00000000,ebx=00000fc0,edx=00000000,ecx=00000000,eax=00000000
GLOBALALLOC
gs=0000,fs=0000,es=16e7,ds=16e7,edi=cdcdcdcd,esi=cdcdcdcd,ebx=cdcdcdcd,edx=cdcdcdcd,ecx=cdcdcdcd,eax=cdcdcdcd
gs=0000,fs=0000,es=0000,ds=16e7,edi=cdcdcdcd,esi=cdcdcdcd,ebx=000016ce,edx=00040002,ecx=000016ce,eax=000016ce
GLOBALLOCK
gs=0000,fs=0000,es=16e7,ds=16e7,edi=cdcdcdcd,esi=cdcdcdcd,ebx=cdcdcdcd,edx=cdcdcdcd,ecx=cdcdcdcd,eax=cdcdcdcd
gs=0000,fs=0000,es=0000,ds=16e7,edi=cdcdcdcd,esi=cdcdcdcd,ebx=cdcdcdcd,edx=cdcd16cf,ecx=cdcd16cf,eax=00000000
GLOBALUNLOCK
gs=0000,fs=0000,es=16e7,ds=16e7,edi=cdcdcdcd,esi=cdcdcdcd,ebx=cdcdcdcd,edx=cdcdcdcd,ecx=cdcdcdcd,eax=cdcdcdcd
gs=0000,fs=0000,es=0000,ds=16e7,edi=cdcdcdcd,esi=cdcdcdcd,ebx=cdcdcdcd,edx=cdcd16ce,ecx=cdcd0000,eax=00000000
GLOBALREALLOC
gs=0000,fs=0000,es=16e7,ds=16e7,edi=cdcdcdcd,esi=cdcdcdcd,ebx=cdcdcdcd,edx=cdcdcdcd,ecx=cdcdcdcd,eax=cdcdcdcd
gs=0000,fs=0000,es=0000,ds=16e7,edi=cdcdcdcd,esi=cdcdcdcd,ebx=000002a0,edx=00000000,ecx=000016ce,eax=000016ce
GLOBALSIZE
gs=0000,fs=0000,es=16e7,ds=16e7,edi=cdcdcdcd,esi=cdcdcdcd,ebx=cdcdcdcd,edx=cdcdcdcd,ecx=cdcdcdcd,eax=cdcdcdcd
gs=0000,fs=0000,es=0000,ds=16e7,edi=cdcdcdcd,esi=cdcdcdcd,ebx=cdcd267e,edx=cdcd0000,ecx=cdcd0200,eax=00002000
GLOBALHANDLE
gs=0000,fs=0000,es=16e7,ds=16e7,edi=cdcdcdcd,esi=cdcdcdcd,ebx=cdcdcdcd,edx=cdcdcdcd,ecx=cdcdcdcd,eax=cdcdcdcd
gs=0000,fs=0000,es=16e7,ds=16e7,edi=cdcdcdcd,esi=cdcdcdcd,ebx=cdcd2676,edx=cdcd16cf,ecx=cdcdcdcd,eax=000016ce
GLOBALFLAGS
gs=0000,fs=0000,es=16e7,ds=16e7,edi=cdcdcdcd,esi=cdcdcdcd,ebx=cdcdcdcd,edx=cdcdcdcd,ecx=cdcdcdcd,eax=cdcdcdcd
gs=0000,fs=0000,es=0000,ds=16e7,edi=cdcdcdcd,esi=cdcdcdcd,ebx=cdcd267e,edx=cdcd16cf,ecx=cdcd0000,eax=00000000
GLOBALFREE
gs=0000,fs=0000,es=16e7,ds=16e7,edi=cdcdcdcd,esi=cdcdcdcd,ebx=cdcdcdcd,edx=cdcdcdcd,ecx=cdcdcdcd,eax=cdcdcdcd
gs=0000,fs=0000,es=0000,ds=16e7,edi=cdcdcdcd,esi=cdcdcdcd,ebx=00000fc0,edx=00000000,ecx=cdcd0000,eax=00000000
WIN31
GLOBALALLOC
gs=0000,fs=0000,es=1de7,ds=1de7,edi=00000000,esi=00000000,ebx=00000000,edx=00000000,ecx=00000000,eax=00000000
gs=0000,fs=0000,es=0000,ds=1de7,edi=00000000,esi=00000000,ebx=00001dce,edx=810b0002,ecx=00001dce,eax=00001dce
GLOBALLOCK
gs=0000,fs=0000,es=1de7,ds=1de7,edi=00000000,esi=00000000,ebx=00000000,edx=00000000,ecx=00000000,eax=00000000
gs=0000,fs=0000,es=0000,ds=1de7,edi=00000000,esi=00000000,ebx=00000000,edx=00001dcf,ecx=00001dcf,eax=00000000
GLOBALUNLOCK
gs=0000,fs=0000,es=1de7,ds=1de7,edi=00000000,esi=00000000,ebx=00000000,edx=00000000,ecx=00000000,eax=00000000
gs=0000,fs=0000,es=0000,ds=1de7,edi=00000000,esi=00000000,ebx=00000000,edx=00001dce,ecx=00000000,eax=00000000
GLOBALREALLOC
gs=0000,fs=0000,es=1de7,ds=1de7,edi=00000000,esi=00000000,ebx=00000000,edx=00000000,ecx=00000000,eax=00000000
gs=0000,fs=0000,es=0000,ds=1de7,edi=00000000,esi=00000000,ebx=00000000,edx=00000000,ecx=00001dce,eax=00001dce
GLOBALSIZE
gs=0000,fs=0000,es=1de7,ds=1de7,edi=00000000,esi=00000000,ebx=00000000,edx=00000000,ecx=00000000,eax=00000000
gs=0000,fs=0000,es=0000,ds=1de7,edi=00000000,esi=00000000,ebx=0000267e,edx=00000000,ecx=00000200,eax=00002000
GLOBALHANDLE
gs=0000,fs=0000,es=1de7,ds=1de7,edi=00000000,esi=00000000,ebx=00000000,edx=00000000,ecx=00000000,eax=00000000
gs=0000,fs=0000,es=1de7,ds=1de7,edi=00000000,esi=00000000,ebx=00002676,edx=00001dcf,ecx=00000000,eax=00001dce
GLOBALFLAGS
gs=0000,fs=0000,es=1de7,ds=1de7,edi=00000000,esi=00000000,ebx=00000000,edx=00000000,ecx=00000000,eax=00000000
gs=0000,fs=0000,es=0000,ds=1de7,edi=00000000,esi=00000000,ebx=0000267e,edx=00001dcf,ecx=00000000,eax=00000000
GLOBALFREE
gs=0000,fs=0000,es=1de7,ds=1de7,edi=00000000,esi=00000000,ebx=00000000,edx=00000000,ecx=00000000,eax=00000000
gs=0000,fs=0000,es=0000,ds=1de7,edi=00000000,esi=00000000,ebx=00004c20,edx=00000000,ecx=00000000,eax=00000000
GLOBALALLOC
gs=0000,fs=0000,es=1de7,ds=1de7,edi=cdcdcdcd,esi=cdcdcdcd,ebx=cdcdcdcd,edx=cdcdcdcd,ecx=cdcdcdcd,eax=cdcdcdcd
gs=0000,fs=0000,es=0000,ds=1de7,edi=cdcdcdcd,esi=cdcdcdcd,ebx=00001dce,edx=810b0002,ecx=00001dce,eax=00001dce
GLOBALLOCK
gs=0000,fs=0000,es=1de7,ds=1de7,edi=cdcdcdcd,esi=cdcdcdcd,ebx=cdcdcdcd,edx=cdcdcdcd,ecx=cdcdcdcd,eax=cdcdcdcd
gs=0000,fs=0000,es=0000,ds=1de7,edi=cdcdcdcd,esi=cdcdcdcd,ebx=cdcdcdcd,edx=cdcd1dcf,ecx=cdcd1dcf,eax=00000000
GLOBALUNLOCK
gs=0000,fs=0000,es=1de7,ds=1de7,edi=cdcdcdcd,esi=cdcdcdcd,ebx=cdcdcdcd,edx=cdcdcdcd,ecx=cdcdcdcd,eax=cdcdcdcd
gs=0000,fs=0000,es=0000,ds=1de7,edi=cdcdcdcd,esi=cdcdcdcd,ebx=cdcdcdcd,edx=cdcd1dce,ecx=cdcd0000,eax=00000000
GLOBALREALLOC
gs=0000,fs=0000,es=1de7,ds=1de7,edi=cdcdcdcd,esi=cdcdcdcd,ebx=cdcdcdcd,edx=cdcdcdcd,ecx=cdcdcdcd,eax=cdcdcdcd
gs=0000,fs=0000,es=0000,ds=1de7,edi=cdcdcdcd,esi=cdcdcdcd,ebx=00000000,edx=00000000,ecx=00001dce,eax=00001dce
GLOBALSIZE
gs=0000,fs=0000,es=1de7,ds=1de7,edi=cdcdcdcd,esi=cdcdcdcd,ebx=cdcdcdcd,edx=cdcdcdcd,ecx=cdcdcdcd,eax=cdcdcdcd
gs=0000,fs=0000,es=0000,ds=1de7,edi=cdcdcdcd,esi=cdcdcdcd,ebx=cdcd267e,edx=cdcd0000,ecx=cdcd0200,eax=00002000
GLOBALHANDLE
gs=0000,fs=0000,es=1de7,ds=1de7,edi=cdcdcdcd,esi=cdcdcdcd,ebx=cdcdcdcd,edx=cdcdcdcd,ecx=cdcdcdcd,eax=cdcdcdcd
gs=0000,fs=0000,es=1de7,ds=1de7,edi=cdcdcdcd,esi=cdcdcdcd,ebx=cdcd2676,edx=cdcd1dcf,ecx=cdcdcdcd,eax=00001dce
GLOBALFLAGS
gs=0000,fs=0000,es=1de7,ds=1de7,edi=cdcdcdcd,esi=cdcdcdcd,ebx=cdcdcdcd,edx=cdcdcdcd,ecx=cdcdcdcd,eax=cdcdcdcd
gs=0000,fs=0000,es=0000,ds=1de7,edi=cdcdcdcd,esi=cdcdcdcd,ebx=cdcd267e,edx=cdcd1dcf,ecx=cdcd0000,eax=00000000
GLOBALFREE
gs=0000,fs=0000,es=1de7,ds=1de7,edi=cdcdcdcd,esi=cdcdcdcd,ebx=cdcdcdcd,edx=cdcdcdcd,ecx=cdcdcdcd,eax=cdcdcdcd
gs=0000,fs=0000,es=0000,ds=1de7,edi=cdcdcdcd,esi=cdcdcdcd,ebx=00004bc0,edx=00000000,ecx=cdcd0000,eax=00000000
GLOBALALLOC
es=0 ecx=ebx=eax=handle
edx=???
GLOBALLOCK
es=0 cx=dx=segment
eax=offset
GLOBALUNLOCK
es=0 dx=handle
eax=result
cx=0?result?
GLOBALREALLOC
es=0 ecx=eax=handle
edx=0?
ebx=???
GLOBALSIZE
es=0 eax=size(low)
cx=size>>4?
dx=size(high)
bx=???
GLOBALHANDLE
es=es
eax=handle dx=segment
bx=???
GLOBALFLAGS
es=0 eax=result
cx=0?result?
dx=segment
bx=???
GLOBALFREE
es=0 eax=result
cx=0?result?
edx=0?result?
ebx=???
*/
/* yes, win16 sets es to 0 */
void WINAPI WIN16_GlobalAlloc16(UINT16 flags, DWORD size, CONTEXT *context)
{
context->SegEs= 0;
context->Ecx = context->Ebx = context->Eax = GlobalAlloc16(flags, size);
}
/***********************************************************************
* GlobalLock (KERNEL.18)
*
* This is the GlobalLock16() function used by 16-bit code.
*/
SEGPTR WINAPI WIN16_GlobalLock16(HGLOBAL16 handle)
{
SEGPTR ret = K32WOWGlobalLock16(handle);
CURRENT_STACK16->ecx &= ~0xffff;
CURRENT_STACK16->ecx |= SELECTOROF(ret); /* selector must be returned in CX as well */
CURRENT_STACK16->es = 0;
return ret;
}
HGLOBAL16 WINAPI WIN16_GlobalReAlloc16(HGLOBAL16 handle, DWORD size, UINT16 flags)
{
CURRENT_STACK16->es = 0;
return CURRENT_STACK16->ecx = GlobalReAlloc16(handle, size, flags);
}
DWORD WINAPI WIN16_GlobalSize16(HGLOBAL16 handle)
{
DWORD size = GlobalSize16(handle);
CURRENT_STACK16->es = 0;
CURRENT_STACK16->ecx &= ~0xffff;
CURRENT_STACK16->ecx |= (WORD)((size >> 4) & 0xffff);
return size;
}
DWORD WINAPI WIN16_GlobalFlags16(HGLOBAL16 handle)
{
CURRENT_STACK16->es = 0;
return MAKELONG(GlobalFlags16(handle), GlobalHandleToSel16(handle));
}
DWORD WINAPI WIN16_GlobalFree16(HGLOBAL16 handle)
{
CURRENT_STACK16->es = 0;
CURRENT_STACK16->fs = 0;
CURRENT_STACK16->gs = 0;
return GlobalFree16(handle);
}
void regen_icon(HICON16 icon);
DWORD WINAPI WIN16_GlobalUnlock16(HGLOBAL16 handle)
{
DWORD ret = MAKELONG(GlobalUnlock16(handle), handle);
CURRENT_STACK16->es = 0;
if (!ret) return 0;
GLOBALARENA *pArena = GET_ARENA_PTR(handle);
if (pArena->wType == (GT_RESOURCE | (12 << 4))) // GD_CURSOR
{
static void (*regen_icon)(HICON16) = 0;
if (!regen_icon)
regen_icon = (void (*)(HICON16))GetProcAddress(GetModuleHandle("user.exe16"), "regen_icon");
regen_icon((HICON16)handle);
}
return ret;
}
/***********************************************************************
* GlobalLock16 (KERNEL32.25)
*
* This is the GlobalLock16() function used by 32-bit code.
*
* RETURNS
* Pointer to first byte of memory block
* NULL: Failure
*/
LPVOID WINAPI GlobalLock16(
HGLOBAL16 handle /* [in] Handle of global memory object */
) {
if (!handle) return 0;
if (!VALID_HANDLE(handle))
return 0;
// don't use IsOldWindowsTask here as it'll cause an infinite loop
if (GET_ARENA_PTR(handle)->flags & GA_DISCARDABLE)
GET_ARENA_PTR(handle)->lockCount++;
return GET_ARENA_PTR(handle)->base;
}
/***********************************************************************
* GlobalUnlock (KERNEL.19)
* GlobalUnlock16 (KERNEL32.26)
* NOTES
* Should the return values be cast to booleans?
*
* RETURNS
* TRUE: Object is still locked
* FALSE: Object is unlocked
*/
BOOL16 WINAPI GlobalUnlock16(
HGLOBAL16 handle /* [in] Handle of global memory object */
) {
GLOBALARENA *pArena = GET_ARENA_PTR(handle);
if (!VALID_HANDLE(handle)) {
WARN("Invalid handle 0x%04x passed to GlobalUnlock16!\n",handle);
return FALSE;
}
TRACE("%04x\n", handle );
if (pArena->lockCount) pArena->lockCount--;
if (CURRENT_STACK16)
CURRENT_STACK16->es = 0;
return pArena->lockCount;
}
BOOL16 WINAPI WIN32_GlobalUnlock16(
HGLOBAL16 handle /* [in] Handle of global memory object */
) {
GLOBALARENA *pArena = GET_ARENA_PTR(handle);
if (!VALID_HANDLE(handle)) {
WARN("Invalid handle 0x%04x passed to GlobalUnlock16!\n",handle);
return FALSE;
}
TRACE("%04x\n", handle );
if (pArena->lockCount) pArena->lockCount--;
return pArena->lockCount;
}
/***********************************************************************
* GlobalChangeLockCount (KERNEL.365)
*
* This is declared as a register function as it has to preserve
* *all* registers, even AX/DX !
*
*/
void WINAPI GlobalChangeLockCount16( HGLOBAL16 handle, INT16 delta, CONTEXT *context )
{
if ( delta == 1 )
GlobalLock16( handle );
else if ( delta == -1 )
GlobalUnlock16( handle );
else
ERR("(%04X, %d): strange delta value\n", handle, delta );
}
/***********************************************************************
* GlobalSize (KERNEL.20)
* GlobalSize16 (KERNEL32.32)
*
* Get the current size of a global memory object.
*
* RETURNS
* Size in bytes of object
* 0: Failure
*/
DWORD WINAPI GlobalSize16(
HGLOBAL16 handle /* [in] Handle of global memory object */
) {
TRACE("%04x\n", handle );
if (!handle) return 0;
if (!VALID_HANDLE(handle))
return 0;
return GET_ARENA_PTR(handle)->size;
}
/***********************************************************************
* GlobalHandle (KERNEL.21)
*
* Get the handle associated with a pointer to the global memory block.
*
* NOTES
* Why is GlobalHandleToSel used here with the sel as input?
*
* RETURNS
* Handle: Success
* NULL: Failure
*/
DWORD WINAPI GlobalHandle16(
WORD sel /* [in] Address of global memory block */
) {
TRACE("%04x\n", sel );
if (!VALID_HANDLE(sel)) {
WARN("Invalid handle 0x%04x passed to GlobalHandle16!\n",sel);
return 0;
}
WORD handle = GET_ARENA_PTR(sel)->handle;
if (!handle)
return 0;
return MAKELONG( handle, GlobalHandleToSel16(sel) );
}
/***********************************************************************
* GlobalHandleNoRIP (KERNEL.159)
*/
DWORD WINAPI GlobalHandleNoRIP16( WORD sel )
{
int i;
for (i = globalArenaSize-1 ; i>=0 ; i--) {
if (pGlobalArena[i].size!=0 && pGlobalArena[i].handle == sel)
return MAKELONG( GET_ARENA_PTR(sel)->handle, GlobalHandleToSel16(sel) );
}
return 0;
}
/***********************************************************************
* GlobalFlags (KERNEL.22)
*
* Get information about a global memory object.
*
* NOTES
* Should this return GMEM_INVALID_HANDLE instead of 0 on invalid
* handle?
*
* RETURNS
* Value specifying flags and lock count
* GMEM_INVALID_HANDLE: Invalid handle
*/
UINT16 WINAPI GlobalFlags16(
HGLOBAL16 handle /* [in] Handle of global memory object */
) {
GLOBALARENA *pArena;
TRACE("%04x\n", handle );
if (!VALID_HANDLE(handle)) {
WARN("Invalid handle 0x%04x passed to GlobalFlags16!\n",handle);
return 0;
}
pArena = GET_ARENA_PTR(handle);
return pArena->lockCount |
((pArena->flags & GA_DISCARDABLE) ? GMEM_DISCARDABLE : 0) |
((pArena->base == 0) ? GMEM_DISCARDED : 0);
}
/***********************************************************************
* LockSegment (KERNEL.23)
*/
HGLOBAL16 WINAPI LockSegment16( HGLOBAL16 handle )
{
TRACE("%04x\n", handle );
if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
if (!VALID_HANDLE(handle)) {
WARN("Invalid handle 0x%04x passed to LockSegment16!\n",handle);
return 0;
}
if ((GET_ARENA_PTR(handle)->flags & GA_DISCARDABLE) || IsOldWindowsTask(GetCurrentTask()))
GET_ARENA_PTR(handle)->lockCount++;
return handle;
}
/***********************************************************************
* UnlockSegment (KERNEL.24)
*/
void WINAPI UnlockSegment16( HGLOBAL16 handle )
{
TRACE("%04x\n", handle );
if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
if (!VALID_HANDLE(handle)) {
WARN("Invalid handle 0x%04x passed to UnlockSegment16!\n",handle);
return;
}
if(GET_ARENA_PTR(handle)->lockCount) GET_ARENA_PTR(handle)->lockCount--;
/* FIXME: this ought to return the lock count in CX (go figure...) */
}
/***********************************************************************
* GlobalCompact (KERNEL.25)
*/
DWORD WINAPI GlobalCompact16( DWORD desired )
{
return GLOBAL_MAX_ALLOC_SIZE;
}
/***********************************************************************
* GlobalFreeAll (KERNEL.26)
*/
void WINAPI GlobalFreeAll16( HGLOBAL16 owner )
{
int i;
GLOBALARENA *pArena;
pArena = pGlobalArena;
for (i = 0; i < globalArenaSize; i++, pArena++)
{
if ((pArena->size != 0) && (pArena->hOwner == owner))
GlobalFree16( pArena->handle );
}
}
/***********************************************************************
* GlobalWire (KERNEL.111)
* GlobalWire16 (KERNEL32.29)
*/
SEGPTR WINAPI GlobalWire16( HGLOBAL16 handle )
{
return WIN16_GlobalLock16( handle );
}
/***********************************************************************
* GlobalUnWire (KERNEL.112)
* GlobalUnWire16 (KERNEL32.30)
*/
BOOL16 WINAPI GlobalUnWire16( HGLOBAL16 handle )
{
return !GlobalUnlock16( handle );
}
/***********************************************************************
* SetSwapAreaSize (KERNEL.106)
*/
LONG WINAPI SetSwapAreaSize16( WORD size )
{
FIXME("(%d) - stub!\n", size );
return MAKELONG( size, 0xffff );
}
/***********************************************************************
* GlobalLRUOldest (KERNEL.163)
*/
HGLOBAL16 WINAPI GlobalLRUOldest16( HGLOBAL16 handle )
{
TRACE("%04x\n", handle );
if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
return handle;
}
/***********************************************************************
* GlobalLRUNewest (KERNEL.164)
*/
HGLOBAL16 WINAPI GlobalLRUNewest16( HGLOBAL16 handle )
{
TRACE("%04x\n", handle );
if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
return handle;
}
/***********************************************************************
* GetFreeSpace (KERNEL.169)
*/
DWORD WINAPI GetFreeSpace16( UINT16 wFlags )
{
MEMORYSTATUS ms;
GlobalMemoryStatus( &ms );
return min(ms.dwAvailVirtual, 102400000);
}
/***********************************************************************
* GlobalDOSAlloc (KERNEL.184)
*
* Allocate memory in the first MB.
*
* RETURNS
* Address (HW=Paragraph segment; LW=Selector)
*/
DWORD WINAPI GlobalDOSAlloc16(
DWORD size /* [in] Number of bytes to be allocated */
) {
UINT16 uParagraph;
LPVOID lpBlock;
DWORD fixup_size = 0x1f;
size = (size + fixup_size) & ~fixup_size;
lpBlock = DOSMEM_AllocBlock(size, &uParagraph);
if( lpBlock )
{
HMODULE16 hModule = GetModuleHandle16("KERNEL");
WORD wSelector;
GLOBALARENA *pArena;
wSelector = GLOBAL_CreateBlock(GMEM_FIXED, lpBlock, size, hModule, WINE_LDT_FLAGS_DATA, 0 );
pArena = GET_ARENA_PTR(wSelector);
pArena->flags |= GA_DOSMEM;
return MAKELONG(wSelector,uParagraph);
}
return 0;
}
/***********************************************************************
* GlobalDOSFree (KERNEL.185)
*
* Free memory allocated with GlobalDOSAlloc
*
* RETURNS
* NULL: Success
* sel: Failure
*/
WORD WINAPI GlobalDOSFree16(
WORD sel /* [in] Selector */
) {
DWORD block = GetSelectorBase(sel);
if( block && block < 0x100000 )
{
LPVOID lpBlock = DOSMEM_MapDosToLinear( block );
if( DOSMEM_FreeBlock( lpBlock ) )
GLOBAL_FreeBlock( sel );
sel = 0;
}
return sel;
}
/***********************************************************************
* GlobalPageLock (KERNEL.191)
* GlobalSmartPageLock(KERNEL.230)
*/
WORD WINAPI GlobalPageLock16( HGLOBAL16 handle )
{
TRACE("%04x\n", handle );
if (!VALID_HANDLE(handle)) {
WARN("Invalid handle 0x%04x passed to GlobalPageLock!\n",handle);
return 0;
}
return ++(GET_ARENA_PTR(handle)->pageLockCount);
}
/***********************************************************************
* GlobalPageUnlock (KERNEL.192)
* GlobalSmartPageUnlock(KERNEL.231)
*/
WORD WINAPI GlobalPageUnlock16( HGLOBAL16 handle )
{
TRACE("%04x\n", handle );
if (!VALID_HANDLE(handle)) {
WARN("Invalid handle 0x%04x passed to GlobalPageUnlock!\n",handle);
return 0;
}
return --(GET_ARENA_PTR(handle)->pageLockCount);
}
/***********************************************************************
* GlobalFix (KERNEL.197)
* GlobalFix16 (KERNEL32.27)
*/
WORD WINAPI GlobalFix16( HGLOBAL16 handle )
{
TRACE("%04x\n", handle );
if (!VALID_HANDLE(handle)) {
WARN("Invalid handle 0x%04x passed to GlobalFix16!\n",handle);
return 0;
}
if ((GET_ARENA_PTR(handle)->flags & GA_DISCARDABLE) || IsOldWindowsTask(GetCurrentTask()))
GET_ARENA_PTR(handle)->lockCount++;
return GlobalHandleToSel16(handle);
}
/***********************************************************************
* GlobalUnfix (KERNEL.198)
* GlobalUnfix16 (KERNEL32.28)
*/
void WINAPI GlobalUnfix16( HGLOBAL16 handle )
{
TRACE("%04x\n", handle );
if (!VALID_HANDLE(handle)) {
WARN("Invalid handle 0x%04x passed to GlobalUnfix16!\n",handle);
return;
}
if (GET_ARENA_PTR(handle)->lockCount)
GET_ARENA_PTR(handle)->lockCount--;
}
/***********************************************************************
* FarSetOwner (KERNEL.403)
*/
void WINAPI FarSetOwner16( HGLOBAL16 handle, HANDLE16 hOwner )
{
if (!VALID_HANDLE(handle)) {
WARN("Invalid handle 0x%04x passed to FarSetOwner!\n",handle);
return;
}
GET_ARENA_PTR(handle)->hOwner = hOwner;
}
/***********************************************************************
* FarGetOwner (KERNEL.404)
*/
HANDLE16 WINAPI FarGetOwner16( HGLOBAL16 handle )
{
if (!VALID_HANDLE(handle)) {
WARN("Invalid handle 0x%04x passed to FarGetOwner!\n",handle);
return 0;
}
return GET_ARENA_PTR(handle)->hOwner;
}
/************************************************************************
* GlobalMasterHandle (KERNEL.28)
*
*
* Should return selector and handle of the information structure for
* the global heap. selector and handle are stored in the THHOOK as
* pGlobalHeap and hGlobalHeap.
* As Wine doesn't have this structure, we return both values as zero
* Applications should interpret this as "No Global Heap"
*/
DWORD WINAPI GlobalMasterHandle16(void)
{
DWORD ret = 0;
FIXME(": stub\n");
// some real mode programs don't check for null, provide enough to prevent crashes
if (IsOldWindowsTask(GetCurrentTask()))
{
// this is an early form of LOCALHEAPINFO
static WORD dummyheap[0x18];
static WORD sel = 0;
if (!sel)
{
sel = AllocSelector16(0);
SetSelectorBase(sel, (DWORD)dummyheap);
SetSelectorLimit16(sel, 0x30);
SelectorAccessRights16(sel, 1, 0); // data, readonly
dummyheap[0] = 'Z'; // check value don't care so pretend MCB end of chain
dummyheap[2] = 0; // count is 0
dummyheap[3] = sel; // start of chain
dummyheap[4] = sel; // pretend MCB pointer
dummyheap[18] = -1; // unknown
}
ret = sel << 16;
}
return ret;
}
/***********************************************************************
* GlobalHandleToSel (TOOLHELP.50)
*
* FIXME: This is in TOOLHELP but we keep a copy here for now.
*/
WORD WINAPI GlobalHandleToSel16( HGLOBAL16 handle )
{
if (!handle) return 0;
if (!VALID_HANDLE(handle)) {
WARN("Invalid handle 0x%04x passed to GlobalHandleToSel!\n",handle);
return 0;
}
if (!(handle & 7))
{
WARN("Program attempted invalid selector conversion\n" );
return handle - 1;
}
return handle | 7;
}
/***********************************************************************
* GetFreeMemInfo (KERNEL.316)
*/
DWORD WINAPI GetFreeMemInfo16(void)
{
SYSTEM_BASIC_INFORMATION info;
MEMORYSTATUS status;
NtQuerySystemInformation( SystemBasicInformation, &info, sizeof(info), NULL );
GlobalMemoryStatus( &status );
return MAKELONG( status.dwTotalVirtual / info.PageSize, status.dwAvailVirtual / info.PageSize );
}
/***********************************************************************
* A20Proc (KERNEL.165)
*/
void WINAPI A20Proc16( WORD unused )
{
/* this is also a NOP in Windows */
}
/***********************************************************************
* LimitEMSPages (KERNEL.156)
*/
DWORD WINAPI LimitEMSPages16( DWORD unused )
{
return 0;
}
void WINAPI DibMapGlobalMemory(WORD sel, void *base, DWORD size)
{
GLOBALARENA *pArena = GET_ARENA_PTR(sel);
int i;
if (!sel) /* not hglobal */
{
SetSelectorBase(sel, base);
return;
}
pArena->dib_avail_size = size;
pArena->base = base;
for (i = 0; i < pArena->selCount; i++)
{
SetSelectorBase(sel + i * 8, (LPBYTE)base + i * 0x10000);
}
}
void WINAPI DibUnmapGlobalMemory(void *base, DWORD size)
{
int i;
LPVOID heap = HeapAlloc(get_win16_heap(), 0, size);
memcpy(heap, base, size);
for (i = 0; i < globalArenaSize; i++)
{
GLOBALARENA *pArena = pGlobalArena + i;
if (!pArena->dib_avail_size)
continue;
if (pArena->base >= base && (LPBYTE)pArena->base < (LPBYTE)base + size)
{
pArena->dib_avail_size = 0;
pArena->base = (LPBYTE)heap + ((SIZE_T)pArena->base - (SIZE_T)base);
for (i = 0; i < pArena->selCount; i++)
SetSelectorBase(pArena->handle + i * 8, (LPBYTE)pArena->base + i * 0x10000);
}
}
}
void WINAPI GlobalMapInternal(WORD sel, void *base, DWORD size)
{
GLOBALARENA *pArena = GET_ARENA_PTR(sel);
if (!sel)
return;
if (!base || !size)
{
memset(pArena, 0, sizeof(GLOBALARENA));
return;
}
pArena->base = base;
pArena->size = size;
pArena->wType = GT_INTERNAL;
}
================================================
FILE: krnl386/instr.c
================================================
/*
* Emulation of privileged instructions
*
* Copyright 1995 Alexandre Julliard
* Copyright 2005 Ivan Leo Puoti
* Copyright 2005 Laurent Pinchart
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#include "wine/port.h"
#include
#include "windef.h"
#include "winbase.h"
#include "winternl.h"
#include "wine/winuser16.h"
#include "excpt.h"
#include "wine/debug.h"
#include "kernel16_private.h"
#include "dosexe.h"
#include "wine/exception.h"
WINE_DEFAULT_DEBUG_CHANNEL(int);
WINE_DECLARE_DEBUG_CHANNEL(io);
/* macros to set parts of a DWORD */
#define SET_LOWORD(dw,val) ((dw) = ((dw) & 0xffff0000) | LOWORD(val))
#define SET_LOBYTE(dw,val) ((dw) = ((dw) & 0xffffff00) | LOBYTE(val))
#define ADD_LOWORD(dw,val) ((dw) = ((dw) & 0xffff0000) | LOWORD((DWORD)(dw)+(val)))
#define ISV86(context) ((context)->EFlags & 0x00020000)
static inline void add_stack( CONTEXT *context, int offset )
{
if (ISV86(context) || !IS_SELECTOR_32BIT(context->SegSs))
ADD_LOWORD( context->Esp, offset );
else
context->Esp += offset;
}
static inline void *make_ptr( CONTEXT *context, DWORD seg, DWORD off, int long_addr )
{
if (ISV86(context)) return (void *)((seg << 4) + LOWORD(off));
if (wine_ldt_is_system(seg)) return (void *)off;
if (!long_addr) off = LOWORD(off);
return (char *) MapSL( MAKESEGPTR( seg, 0 ) ) + off;
}
static inline void *get_stack( CONTEXT *context )
{
if (ISV86(context)) return (void *)((context->SegSs << 4) + LOWORD(context->Esp));
return wine_ldt_get_ptr( context->SegSs, context->Esp );
}
#include "pshpack1.h"
struct idtr
{
WORD limit;
BYTE *base;
};
#include "poppack.h"
static LDT_ENTRY idt[256];
static inline struct idtr get_idtr(void)
{
struct idtr ret;
#if defined(__i386__) && defined(__GNUC__)
__asm__( "sidtl %0" : "=m" (ret) );
#else
ret.base = (BYTE *)idt;
ret.limit = sizeof(idt) - 1;
#endif
return ret;
}
/***********************************************************************
* INSTR_ReplaceSelector
*
* Try to replace an invalid selector by a valid one.
* The only selector where it is allowed to do "mov ax,40;mov es,ax"
* is the so called 'bimodal' selector 0x40, which points to the BIOS
* data segment. Used by (at least) Borland products (and programs compiled
* using Borland products).
*
* See Undocumented Windows, Chapter 5, __0040.
*/
static BOOL INSTR_ReplaceSelector( CONTEXT *context, WORD *sel )
{
if (*sel == 0x40)
{
DOSVM_start_bios_timer();
*sel = DOSMEM_BiosDataSeg;
return TRUE;
}
return FALSE; /* Can't replace selector, crashdump */
}
/* store an operand into a register */
static void store_reg_word( CONTEXT *context, BYTE regmodrm, const BYTE *addr, int long_op )
{
switch((regmodrm >> 3) & 7)
{
case 0:
if (long_op) context->Eax = *(const DWORD *)addr;
else SET_LOWORD(context->Eax, *(const WORD *)addr);
break;
case 1:
if (long_op) context->Ecx = *(const DWORD *)addr;
else SET_LOWORD(context->Ecx, *(const WORD *)addr);
break;
case 2:
if (long_op) context->Edx = *(const DWORD *)addr;
else SET_LOWORD(context->Edx, *(const WORD *)addr);
break;
case 3:
if (long_op) context->Ebx = *(const DWORD *)addr;
else SET_LOWORD(context->Ebx, *(const WORD *)addr);
break;
case 4:
if (long_op) context->Esp = *(const DWORD *)addr;
else SET_LOWORD(context->Esp, *(const WORD *)addr);
break;
case 5:
if (long_op) context->Ebp = *(const DWORD *)addr;
else SET_LOWORD(context->Ebp, *(const WORD *)addr);
break;
case 6:
if (long_op) context->Esi = *(const DWORD *)addr;
else SET_LOWORD(context->Esi, *(const WORD *)addr);
break;
case 7:
if (long_op) context->Edi = *(const DWORD *)addr;
else SET_LOWORD(context->Edi, *(const WORD *)addr);
break;
}
}
/* store an operand into a byte register */
static void store_reg_byte( CONTEXT *context, BYTE regmodrm, const BYTE *addr )
{
switch((regmodrm >> 3) & 7)
{
case 0: context->Eax = (context->Eax & 0xffffff00) | *addr; break;
case 1: context->Ecx = (context->Ecx & 0xffffff00) | *addr; break;
case 2: context->Edx = (context->Edx & 0xffffff00) | *addr; break;
case 3: context->Ebx = (context->Ebx & 0xffffff00) | *addr; break;
case 4: context->Eax = (context->Eax & 0xffff00ff) | (*addr << 8); break;
case 5: context->Ecx = (context->Ecx & 0xffff00ff) | (*addr << 8); break;
case 6: context->Edx = (context->Edx & 0xffff00ff) | (*addr << 8); break;
case 7: context->Ebx = (context->Ebx & 0xffff00ff) | (*addr << 8); break;
}
}
/***********************************************************************
* INSTR_GetOperandAddr
*
* Return the address of an instruction operand (from the mod/rm byte).
*/
static BYTE *INSTR_GetOperandAddr( CONTEXT *context, BYTE *instr,
int long_addr, int segprefix, int *len )
{
int mod, rm, base = 0, index = 0, ss = 0, seg = 0, off;
LDT_ENTRY entry;
#define GET_VAL(val,type) \
{ *val = *(type *)instr; instr += sizeof(type); *len += sizeof(type); }
*len = 0;
GET_VAL( &mod, BYTE );
rm = mod & 7;
mod >>= 6;
if (mod == 3)
{
switch(rm)
{
case 0: return (BYTE *)&context->Eax;
case 1: return (BYTE *)&context->Ecx;
case 2: return (BYTE *)&context->Edx;
case 3: return (BYTE *)&context->Ebx;
case 4: return (BYTE *)&context->Esp;
case 5: return (BYTE *)&context->Ebp;
case 6: return (BYTE *)&context->Esi;
case 7: return (BYTE *)&context->Edi;
}
}
if (long_addr)
{
if (rm == 4)
{
BYTE sib;
GET_VAL( &sib, BYTE );
rm = sib & 7;
ss = sib >> 6;
switch((sib >> 3) & 7)
{
case 0: index = context->Eax; break;
case 1: index = context->Ecx; break;
case 2: index = context->Edx; break;
case 3: index = context->Ebx; break;
case 4: index = 0; break;
case 5: index = context->Ebp; break;
case 6: index = context->Esi; break;
case 7: index = context->Edi; break;
}
}
switch(rm)
{
case 0: base = context->Eax; seg = context->SegDs; break;
case 1: base = context->Ecx; seg = context->SegDs; break;
case 2: base = context->Edx; seg = context->SegDs; break;
case 3: base = context->Ebx; seg = context->SegDs; break;
case 4: base = context->Esp; seg = context->SegSs; break;
case 5: base = context->Ebp; seg = context->SegSs; break;
case 6: base = context->Esi; seg = context->SegDs; break;
case 7: base = context->Edi; seg = context->SegDs; break;
}
switch (mod)
{
case 0:
if (rm == 5) /* special case: ds:(disp32) */
{
GET_VAL( &base, DWORD );
seg = context->SegDs;
}
break;
case 1: /* 8-bit disp */
GET_VAL( &off, BYTE );
base += (signed char)off;
break;
case 2: /* 32-bit disp */
GET_VAL( &off, DWORD );
base += (signed long)off;
break;
}
}
else /* short address */
{
switch(rm)
{
case 0: /* ds:(bx,si) */
base = LOWORD(context->Ebx) + LOWORD(context->Esi);
seg = context->SegDs;
break;
case 1: /* ds:(bx,di) */
base = LOWORD(context->Ebx) + LOWORD(context->Edi);
seg = context->SegDs;
break;
case 2: /* ss:(bp,si) */
base = LOWORD(context->Ebp) + LOWORD(context->Esi);
seg = context->SegSs;
break;
case 3: /* ss:(bp,di) */
base = LOWORD(context->Ebp) + LOWORD(context->Edi);
seg = context->SegSs;
break;
case 4: /* ds:(si) */
base = LOWORD(context->Esi);
seg = context->SegDs;
break;
case 5: /* ds:(di) */
base = LOWORD(context->Edi);
seg = context->SegDs;
break;
case 6: /* ss:(bp) */
base = LOWORD(context->Ebp);
seg = context->SegSs;
break;
case 7: /* ds:(bx) */
base = LOWORD(context->Ebx);
seg = context->SegDs;
break;
}
switch(mod)
{
case 0:
if (rm == 6) /* special case: ds:(disp16) */
{
GET_VAL( &base, WORD );
seg = context->SegDs;
}
break;
case 1: /* 8-bit disp */
GET_VAL( &off, BYTE );
base += (signed char)off;
break;
case 2: /* 16-bit disp */
GET_VAL( &off, WORD );
base += (signed short)off;
break;
}
base &= 0xffff;
}
if (segprefix != -1) seg = segprefix;
/* Make sure the segment and offset are valid */
if (wine_ldt_is_system(seg)) return (BYTE *)(base + (index << ss));
if ((seg & 7) != 7) return NULL;
wine_ldt_get_entry( seg, &entry );
if (wine_ldt_is_empty( &entry )) return NULL;
if (wine_ldt_get_limit(&entry) < (base + (index << ss))) return NULL;
return (BYTE *)wine_ldt_get_base(&entry) + base + (index << ss);
#undef GET_VAL
}
/***********************************************************************
* INSTR_EmulateLDS
*
* Emulate the LDS (and LES,LFS,etc.) instruction.
*/
static BOOL INSTR_EmulateLDS( CONTEXT *context, BYTE *instr, int long_op,
int long_addr, int segprefix, int *len )
{
WORD seg;
BYTE *regmodrm = instr + 1 + (*instr == 0x0f);
BYTE *addr = INSTR_GetOperandAddr( context, regmodrm,
long_addr, segprefix, len );
if (!addr)
return FALSE; /* Unable to emulate it */
seg = *(WORD *)(addr + (long_op ? 4 : 2));
if (!INSTR_ReplaceSelector( context, &seg ))
return FALSE; /* Unable to emulate it */
/* Now store the offset in the correct register */
store_reg_word( context, *regmodrm, addr, long_op );
/* Store the correct segment in the segment register */
switch(*instr)
{
case 0xc4: context->SegEs = seg; break; /* les */
case 0xc5: context->SegDs = seg; break; /* lds */
case 0x0f: switch(instr[1])
{
case 0xb2: context->SegSs = seg; break; /* lss */
case 0xb4: context->SegFs = seg; break; /* lfs */
case 0xb5: context->SegGs = seg; break; /* lgs */
}
break;
}
/* Add the opcode size to the total length */
*len += 1 + (*instr == 0x0f);
return TRUE;
}
/***********************************************************************
* INSTR_inport
*
* input on an I/O port
*/
static DWORD INSTR_inport( WORD port, int size, CONTEXT *context )
{
DWORD res = DOSVM_inport( port, size, context );
if (TRACE_ON(io))
{
switch(size)
{
case 1:
TRACE_(io)( "0x%x < %02x @ %04x:%04x\n", port, LOBYTE(res),
(WORD)context->SegCs, LOWORD(context->Eip));
break;
case 2:
TRACE_(io)( "0x%x < %04x @ %04x:%04x\n", port, LOWORD(res),
(WORD)context->SegCs, LOWORD(context->Eip));
break;
case 4:
TRACE_(io)( "0x%x < %08x @ %04x:%04x\n", port, res,
(WORD)context->SegCs, LOWORD(context->Eip));
break;
}
}
return res;
}
/***********************************************************************
* INSTR_outport
*
* output on an I/O port
*/
static void INSTR_outport( WORD port, int size, DWORD val, CONTEXT *context )
{
DOSVM_outport( port, size, val, context );
if (TRACE_ON(io))
{
switch(size)
{
case 1:
TRACE_(io)("0x%x > %02x @ %04x:%04x\n", port, LOBYTE(val),
(WORD)context->SegCs, LOWORD(context->Eip));
break;
case 2:
TRACE_(io)("0x%x > %04x @ %04x:%04x\n", port, LOWORD(val),
(WORD)context->SegCs, LOWORD(context->Eip));
break;
case 4:
TRACE_(io)("0x%x > %08x @ %04x:%04x\n", port, val,
(WORD)context->SegCs, LOWORD(context->Eip));
break;
}
}
}
/***********************************************************************
* __wine_emulate_instruction
*
* Emulate a privileged instruction.
* Returns exception continuation status.
*/
DWORD __wine_emulate_instruction( EXCEPTION_RECORD *rec, CONTEXT *context )
{
int prefix, segprefix, prefixlen, len, repX, long_op, long_addr;
BYTE *instr;
long_op = long_addr = (!ISV86(context) && IS_SELECTOR_32BIT(context->SegCs));
instr = make_ptr( context, context->SegCs, context->Eip, TRUE );
if (!instr) return ExceptionContinueSearch;
/* First handle any possible prefix */
segprefix = -1; /* no prefix */
prefix = 1;
repX = 0;
prefixlen = 0;
while(prefix)
{
switch(*instr)
{
case 0x2e:
segprefix = context->SegCs;
break;
case 0x36:
segprefix = context->SegSs;
break;
case 0x3e:
segprefix = context->SegDs;
break;
case 0x26:
segprefix = context->SegEs;
break;
case 0x64:
segprefix = context->SegFs;
break;
case 0x65:
segprefix = context->SegGs;
break;
case 0x66:
long_op = !long_op; /* opcode size prefix */
break;
case 0x67:
long_addr = !long_addr; /* addr size prefix */
break;
case 0xf0: /* lock */
break;
case 0xf2: /* repne */
repX = 1;
break;
case 0xf3: /* repe */
repX = 2;
break;
default:
prefix = 0; /* no more prefixes */
break;
}
if (prefix)
{
instr++;
prefixlen++;
}
}
/* Now look at the actual instruction */
switch(*instr)
{
case 0x07: /* pop es */
case 0x17: /* pop ss */
case 0x1f: /* pop ds */
{
WORD seg = *(WORD *)get_stack( context );
if (INSTR_ReplaceSelector( context, &seg ))
{
switch(*instr)
{
case 0x07: context->SegEs = seg; break;
case 0x17: context->SegSs = seg; break;
case 0x1f: context->SegDs = seg; break;
}
add_stack(context, long_op ? 4 : 2);
context->Eip += prefixlen + 1;
return ExceptionContinueExecution;
}
}
break; /* Unable to emulate it */
case 0x0f: /* extended instruction */
switch(instr[1])
{
case 0x22: /* mov %eax, %crX */
switch (instr[2])
{
case 0xc0:
FIXME("mov %%eax, %%cr0 at 0x%08x, EAX=0x%08x\n",
context->Eip,context->Eax );
context->Eip += prefixlen+3;
return ExceptionContinueExecution;
default:
break; /* Fallthrough to bad instruction handling */
}
break; /* Fallthrough to bad instruction handling */
case 0x20: /* mov %crX, %eax */
switch (instr[2])
{
case 0xe0: /* mov %cr4, %eax */
/* CR4 register: See linux/arch/i386/mm/init.c, X86_CR4_ defs
* bit 0: VME Virtual Mode Exception ?
* bit 1: PVI Protected mode Virtual Interrupt
* bit 2: TSD Timestamp disable
* bit 3: DE Debugging extensions
* bit 4: PSE Page size extensions
* bit 5: PAE Physical address extension
* bit 6: MCE Machine check enable
* bit 7: PGE Enable global pages
* bit 8: PCE Enable performance counters at IPL3
*/
FIXME("mov %%cr4, %%eax at 0x%08x\n",context->Eip);
context->Eax = 0;
context->Eip += prefixlen+3;
return ExceptionContinueExecution;
case 0xc0: /* mov %cr0, %eax */
FIXME("mov %%cr0, %%eax at 0x%08x\n",context->Eip);
context->Eax = 0x10; /* FIXME: set more bits ? */
context->Eip += prefixlen+3;
return ExceptionContinueExecution;
default: /* Fallthrough to illegal instruction */
break;
}
/* Fallthrough to illegal instruction */
break;
case 0x21: /* mov %drX, %eax */
switch (instr[2])
{
case 0xc8: /* mov %dr1, %eax */
TRACE("mov %%dr1, %%eax at 0x%08x\n",context->Eip);
context->Eax = context->Dr1;
context->Eip += prefixlen+3;
return ExceptionContinueExecution;
case 0xf8: /* mov %dr7, %eax */
TRACE("mov %%dr7, %%eax at 0x%08x\n",context->Eip);
context->Eax = 0x400;
context->Eip += prefixlen+3;
return ExceptionContinueExecution;
}
FIXME("Unsupported DR register, eip+2 is %02x\n", instr[2]);
/* fallthrough to illegal instruction */
break;
case 0x23: /* mov %eax, %drX */
switch (instr[2])
{
case 0xc8: /* mov %eax, %dr1 */
context->Dr1 = context->Eax;
context->Eip += prefixlen+3;
return ExceptionContinueExecution;
}
FIXME("Unsupported DR register, eip+2 is %02x\n", instr[2]);
/* fallthrough to illegal instruction */
break;
case 0xa1: /* pop fs */
{
WORD seg = *(WORD *)get_stack( context );
if (INSTR_ReplaceSelector( context, &seg ))
{
context->SegFs = seg;
add_stack(context, long_op ? 4 : 2);
context->Eip += prefixlen + 2;
return ExceptionContinueExecution;
}
}
break;
case 0xa9: /* pop gs */
{
WORD seg = *(WORD *)get_stack( context );
if (INSTR_ReplaceSelector( context, &seg ))
{
context->SegGs = seg;
add_stack(context, long_op ? 4 : 2);
context->Eip += prefixlen + 2;
return ExceptionContinueExecution;
}
}
break;
case 0xb2: /* lss addr,reg */
case 0xb4: /* lfs addr,reg */
case 0xb5: /* lgs addr,reg */
if (INSTR_EmulateLDS( context, instr, long_op,
long_addr, segprefix, &len ))
{
context->Eip += prefixlen + len;
return ExceptionContinueExecution;
}
break;
}
break; /* Unable to emulate it */
case 0x6c: /* insb */
case 0x6d: /* insw/d */
case 0x6e: /* outsb */
case 0x6f: /* outsw/d */
{
int typ = *instr; /* Just in case it's overwritten. */
int outp = (typ >= 0x6e);
unsigned long count = repX ?
(long_addr ? context->Ecx : LOWORD(context->Ecx)) : 1;
int opsize = (typ & 1) ? (long_op ? 4 : 2) : 1;
int step = (context->EFlags & 0x400) ? -opsize : +opsize;
int seg;
if (outp)
{
/* Check if there is a segment prefix override and honour it */
seg = segprefix == -1 ? context->SegDs : segprefix;
/* FIXME: Check segment is readable. */
}
else
{
seg = context->SegEs;
/* FIXME: Check segment is writable. */
}
if (repX)
{
if (long_addr) context->Ecx = 0;
else SET_LOWORD(context->Ecx,0);
}
while (count-- > 0)
{
void *data;
WORD dx = LOWORD(context->Edx);
if (outp)
{
data = make_ptr( context, seg, context->Esi, long_addr );
if (long_addr) context->Esi += step;
else ADD_LOWORD(context->Esi,step);
}
else
{
data = make_ptr( context, seg, context->Edi, long_addr );
if (long_addr) context->Edi += step;
else ADD_LOWORD(context->Edi,step);
}
switch (typ)
{
case 0x6c:
*(BYTE *)data = INSTR_inport( dx, 1, context );
break;
case 0x6d:
if (long_op)
*(DWORD *)data = INSTR_inport( dx, 4, context );
else
*(WORD *)data = INSTR_inport( dx, 2, context );
break;
case 0x6e:
INSTR_outport( dx, 1, *(BYTE *)data, context );
break;
case 0x6f:
if (long_op)
INSTR_outport( dx, 4, *(DWORD *)data, context );
else
INSTR_outport( dx, 2, *(WORD *)data, context );
break;
}
}
context->Eip += prefixlen + 1;
}
return ExceptionContinueExecution;
case 0x8a: /* mov Eb, Gb */
case 0x8b: /* mov Ev, Gv */
{
BYTE *data = INSTR_GetOperandAddr(context, instr + 1, long_addr,
segprefix, &len);
unsigned int data_size = (*instr == 0x8b) ? (long_op ? 4 : 2) : 1;
struct idtr idtr = get_idtr();
unsigned int offset = data - idtr.base;
if (offset <= idtr.limit + 1 - data_size)
{
idt[1].LimitLow = 0x100; /* FIXME */
idt[2].LimitLow = 0x11E; /* FIXME */
idt[3].LimitLow = 0x500; /* FIXME */
switch (*instr)
{
case 0x8a: store_reg_byte( context, instr[1], (BYTE *)idt + offset ); break;
case 0x8b: store_reg_word( context, instr[1], (BYTE *)idt + offset, long_op ); break;
}
context->Eip += prefixlen + len + 1;
return ExceptionContinueExecution;
}
}
break; /* Unable to emulate it */
case 0x8e: /* mov XX,segment_reg */
{
WORD seg;
BYTE *addr = INSTR_GetOperandAddr(context, instr + 1,
long_addr, segprefix, &len );
if (!addr)
break; /* Unable to emulate it */
seg = *(WORD *)addr;
if (!INSTR_ReplaceSelector( context, &seg ))
break; /* Unable to emulate it */
switch((instr[1] >> 3) & 7)
{
case 0:
context->SegEs = seg;
context->Eip += prefixlen + len + 1;
return ExceptionContinueExecution;
case 1: /* cs */
break;
case 2:
context->SegSs = seg;
context->Eip += prefixlen + len + 1;
return ExceptionContinueExecution;
case 3:
context->SegDs = seg;
context->Eip += prefixlen + len + 1;
return ExceptionContinueExecution;
case 4:
context->SegFs = seg;
context->Eip += prefixlen + len + 1;
return ExceptionContinueExecution;
case 5:
context->SegGs = seg;
context->Eip += prefixlen + len + 1;
return ExceptionContinueExecution;
case 6: /* unused */
case 7: /* unused */
break;
}
}
break; /* Unable to emulate it */
case 0xc4: /* les addr,reg */
case 0xc5: /* lds addr,reg */
if (INSTR_EmulateLDS( context, instr, long_op,
long_addr, segprefix, &len ))
{
context->Eip += prefixlen + len;
return ExceptionContinueExecution;
}
break; /* Unable to emulate it */
case 0xcd: /* int */
context->Eip += prefixlen + 2;
if (DOSVM_EmulateInterruptPM( context, instr[1] )) return ExceptionContinueExecution;
context->Eip -= prefixlen + 2; /* restore eip */
break; /* Unable to emulate it */
case 0xcf: /* iret */
if (wine_ldt_is_system(context->SegCs)) break; /* don't emulate it in 32-bit code */
if (long_op)
{
DWORD *stack = get_stack( context );
context->Eip = *stack++;
context->SegCs = *stack++;
context->EFlags = *stack;
add_stack(context, 3*sizeof(DWORD)); /* Pop the return address and flags */
}
else
{
WORD *stack = get_stack( context );
context->Eip = *stack++;
context->SegCs = *stack++;
SET_LOWORD(context->EFlags,*stack);
add_stack(context, 3*sizeof(WORD)); /* Pop the return address and flags */
}
return ExceptionContinueExecution;
case 0xe4: /* inb al,XX */
SET_LOBYTE(context->Eax,INSTR_inport( instr[1], 1, context ));
context->Eip += prefixlen + 2;
return ExceptionContinueExecution;
case 0xe5: /* in (e)ax,XX */
if (long_op)
context->Eax = INSTR_inport( instr[1], 4, context );
else
SET_LOWORD(context->Eax, INSTR_inport( instr[1], 2, context ));
context->Eip += prefixlen + 2;
return ExceptionContinueExecution;
case 0xe6: /* outb XX,al */
INSTR_outport( instr[1], 1, LOBYTE(context->Eax), context );
context->Eip += prefixlen + 2;
return ExceptionContinueExecution;
case 0xe7: /* out XX,(e)ax */
if (long_op)
INSTR_outport( instr[1], 4, context->Eax, context );
else
INSTR_outport( instr[1], 2, LOWORD(context->Eax), context );
context->Eip += prefixlen + 2;
return ExceptionContinueExecution;
case 0xec: /* inb al,dx */
SET_LOBYTE(context->Eax, INSTR_inport( LOWORD(context->Edx), 1, context ) );
context->Eip += prefixlen + 1;
return ExceptionContinueExecution;
case 0xed: /* in (e)ax,dx */
if (long_op)
context->Eax = INSTR_inport( LOWORD(context->Edx), 4, context );
else
SET_LOWORD(context->Eax, INSTR_inport( LOWORD(context->Edx), 2, context ));
context->Eip += prefixlen + 1;
return ExceptionContinueExecution;
case 0xee: /* outb dx,al */
INSTR_outport( LOWORD(context->Edx), 1, LOBYTE(context->Eax), context );
context->Eip += prefixlen + 1;
return ExceptionContinueExecution;
case 0xef: /* out dx,(e)ax */
if (long_op)
INSTR_outport( LOWORD(context->Edx), 4, context->Eax, context );
else
INSTR_outport( LOWORD(context->Edx), 2, LOWORD(context->Eax), context );
context->Eip += prefixlen + 1;
return ExceptionContinueExecution;
case 0xfa: /* cli */
get_vm86_teb_info()->dpmi_vif = 0;
context->Eip += prefixlen + 1;
return ExceptionContinueExecution;
case 0xfb: /* sti */
get_vm86_teb_info()->dpmi_vif = 1;
context->Eip += prefixlen + 1;
if (get_vm86_teb_info()->vm86_pending)
{
get_vm86_teb_info()->vm86_pending = 0;
rec->ExceptionCode = EXCEPTION_VM86_STI;
break; /* Handle the pending event. */
}
return ExceptionContinueExecution;
}
return ExceptionContinueSearch; /* Unable to emulate it */
}
/***********************************************************************
* INSTR_vectored_handler
*
* Vectored exception handler used to emulate protected instructions
* from 32-bit code.
*/
LONG CALLBACK INSTR_vectored_handler( EXCEPTION_POINTERS *ptrs )
{
EXCEPTION_RECORD *record = ptrs->ExceptionRecord;
CONTEXT *context = ptrs->ContextRecord;
if (wine_ldt_is_system(context->SegCs) &&
(record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION ||
record->ExceptionCode == EXCEPTION_PRIV_INSTRUCTION))
{
if (__wine_emulate_instruction( record, context ) == ExceptionContinueExecution)
return EXCEPTION_CONTINUE_EXECUTION;
}
return EXCEPTION_CONTINUE_SEARCH;
}
/***********************************************************************
* DOS3Call (KERNEL.102)
*/
void WINAPI DOS3Call( CONTEXT *context )
{
__wine_call_int_handler( context, 0x21 );
}
/***********************************************************************
* NetBIOSCall (KERNEL.103)
*/
void WINAPI NetBIOSCall16( CONTEXT *context )
{
__wine_call_int_handler( context, 0x5c );
}
/***********************************************************************
* GetSetKernelDOSProc (KERNEL.311)
*/
FARPROC16 WINAPI GetSetKernelDOSProc16( FARPROC16 DosProc )
{
FIXME("(DosProc=%p): stub\n", DosProc);
return NULL;
}
================================================
FILE: krnl386/int09.c
================================================
/*
* DOS interrupt 09h handler (IRQ1 - KEYBOARD)
*
* Copyright 1999 Ove Kåven
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include